162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2012 Samsung Electronics Co.Ltd
462306a36Sopenharmony_ci * Authors:
562306a36Sopenharmony_ci *	Eunchul Kim <chulspro.kim@samsung.com>
662306a36Sopenharmony_ci *	Jinyoung Jeon <jy0.jeon@samsung.com>
762306a36Sopenharmony_ci *	Sangmin Lee <lsmin.lee@samsung.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/clk.h>
1162306a36Sopenharmony_ci#include <linux/component.h>
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
1462306a36Sopenharmony_ci#include <linux/of.h>
1562306a36Sopenharmony_ci#include <linux/platform_device.h>
1662306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1762306a36Sopenharmony_ci#include <linux/regmap.h>
1862306a36Sopenharmony_ci#include <linux/spinlock.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <drm/drm_fourcc.h>
2162306a36Sopenharmony_ci#include <drm/drm_print.h>
2262306a36Sopenharmony_ci#include <drm/exynos_drm.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include "exynos_drm_drv.h"
2562306a36Sopenharmony_ci#include "exynos_drm_ipp.h"
2662306a36Sopenharmony_ci#include "regs-fimc.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/*
2962306a36Sopenharmony_ci * FIMC stands for Fully Interactive Mobile Camera and
3062306a36Sopenharmony_ci * supports image scaler/rotator and input/output DMA operations.
3162306a36Sopenharmony_ci * input DMA reads image data from the memory.
3262306a36Sopenharmony_ci * output DMA writes image data to memory.
3362306a36Sopenharmony_ci * FIMC supports image rotation and image effect functions.
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define FIMC_MAX_DEVS	4
3762306a36Sopenharmony_ci#define FIMC_MAX_SRC	2
3862306a36Sopenharmony_ci#define FIMC_MAX_DST	32
3962306a36Sopenharmony_ci#define FIMC_SHFACTOR	10
4062306a36Sopenharmony_ci#define FIMC_BUF_STOP	1
4162306a36Sopenharmony_ci#define FIMC_BUF_START	2
4262306a36Sopenharmony_ci#define FIMC_WIDTH_ITU_709	1280
4362306a36Sopenharmony_ci#define FIMC_AUTOSUSPEND_DELAY	2000
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic unsigned int fimc_mask = 0xc;
4662306a36Sopenharmony_cimodule_param_named(fimc_devs, fimc_mask, uint, 0644);
4762306a36Sopenharmony_ciMODULE_PARM_DESC(fimc_devs, "Alias mask for assigning FIMC devices to Exynos DRM");
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#define get_fimc_context(dev)	dev_get_drvdata(dev)
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cienum {
5262306a36Sopenharmony_ci	FIMC_CLK_LCLK,
5362306a36Sopenharmony_ci	FIMC_CLK_GATE,
5462306a36Sopenharmony_ci	FIMC_CLK_WB_A,
5562306a36Sopenharmony_ci	FIMC_CLK_WB_B,
5662306a36Sopenharmony_ci	FIMC_CLKS_MAX
5762306a36Sopenharmony_ci};
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic const char * const fimc_clock_names[] = {
6062306a36Sopenharmony_ci	[FIMC_CLK_LCLK]   = "sclk_fimc",
6162306a36Sopenharmony_ci	[FIMC_CLK_GATE]   = "fimc",
6262306a36Sopenharmony_ci	[FIMC_CLK_WB_A]   = "pxl_async0",
6362306a36Sopenharmony_ci	[FIMC_CLK_WB_B]   = "pxl_async1",
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/*
6762306a36Sopenharmony_ci * A structure of scaler.
6862306a36Sopenharmony_ci *
6962306a36Sopenharmony_ci * @range: narrow, wide.
7062306a36Sopenharmony_ci * @bypass: unused scaler path.
7162306a36Sopenharmony_ci * @up_h: horizontal scale up.
7262306a36Sopenharmony_ci * @up_v: vertical scale up.
7362306a36Sopenharmony_ci * @hratio: horizontal ratio.
7462306a36Sopenharmony_ci * @vratio: vertical ratio.
7562306a36Sopenharmony_ci */
7662306a36Sopenharmony_cistruct fimc_scaler {
7762306a36Sopenharmony_ci	bool range;
7862306a36Sopenharmony_ci	bool bypass;
7962306a36Sopenharmony_ci	bool up_h;
8062306a36Sopenharmony_ci	bool up_v;
8162306a36Sopenharmony_ci	u32 hratio;
8262306a36Sopenharmony_ci	u32 vratio;
8362306a36Sopenharmony_ci};
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci/*
8662306a36Sopenharmony_ci * A structure of fimc context.
8762306a36Sopenharmony_ci *
8862306a36Sopenharmony_ci * @regs: memory mapped io registers.
8962306a36Sopenharmony_ci * @lock: locking of operations.
9062306a36Sopenharmony_ci * @clocks: fimc clocks.
9162306a36Sopenharmony_ci * @sc: scaler infomations.
9262306a36Sopenharmony_ci * @pol: porarity of writeback.
9362306a36Sopenharmony_ci * @id: fimc id.
9462306a36Sopenharmony_ci * @irq: irq number.
9562306a36Sopenharmony_ci */
9662306a36Sopenharmony_cistruct fimc_context {
9762306a36Sopenharmony_ci	struct exynos_drm_ipp ipp;
9862306a36Sopenharmony_ci	struct drm_device *drm_dev;
9962306a36Sopenharmony_ci	void		*dma_priv;
10062306a36Sopenharmony_ci	struct device	*dev;
10162306a36Sopenharmony_ci	struct exynos_drm_ipp_task	*task;
10262306a36Sopenharmony_ci	struct exynos_drm_ipp_formats	*formats;
10362306a36Sopenharmony_ci	unsigned int			num_formats;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	void __iomem	*regs;
10662306a36Sopenharmony_ci	spinlock_t	lock;
10762306a36Sopenharmony_ci	struct clk	*clocks[FIMC_CLKS_MAX];
10862306a36Sopenharmony_ci	struct fimc_scaler	sc;
10962306a36Sopenharmony_ci	int	id;
11062306a36Sopenharmony_ci	int	irq;
11162306a36Sopenharmony_ci};
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic u32 fimc_read(struct fimc_context *ctx, u32 reg)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	return readl(ctx->regs + reg);
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic void fimc_write(struct fimc_context *ctx, u32 val, u32 reg)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	writel(val, ctx->regs + reg);
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic void fimc_set_bits(struct fimc_context *ctx, u32 reg, u32 bits)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	void __iomem *r = ctx->regs + reg;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	writel(readl(r) | bits, r);
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic void fimc_clear_bits(struct fimc_context *ctx, u32 reg, u32 bits)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	void __iomem *r = ctx->regs + reg;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	writel(readl(r) & ~bits, r);
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic void fimc_sw_reset(struct fimc_context *ctx)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	u32 cfg;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	/* stop dma operation */
14262306a36Sopenharmony_ci	cfg = fimc_read(ctx, EXYNOS_CISTATUS);
14362306a36Sopenharmony_ci	if (EXYNOS_CISTATUS_GET_ENVID_STATUS(cfg))
14462306a36Sopenharmony_ci		fimc_clear_bits(ctx, EXYNOS_MSCTRL, EXYNOS_MSCTRL_ENVID);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	fimc_set_bits(ctx, EXYNOS_CISRCFMT, EXYNOS_CISRCFMT_ITU601_8BIT);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	/* disable image capture */
14962306a36Sopenharmony_ci	fimc_clear_bits(ctx, EXYNOS_CIIMGCPT,
15062306a36Sopenharmony_ci		EXYNOS_CIIMGCPT_IMGCPTEN_SC | EXYNOS_CIIMGCPT_IMGCPTEN);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	/* s/w reset */
15362306a36Sopenharmony_ci	fimc_set_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_SWRST);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	/* s/w reset complete */
15662306a36Sopenharmony_ci	fimc_clear_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_SWRST);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	/* reset sequence */
15962306a36Sopenharmony_ci	fimc_write(ctx, 0x0, EXYNOS_CIFCNTSEQ);
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic void fimc_set_type_ctrl(struct fimc_context *ctx)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	u32 cfg;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	cfg = fimc_read(ctx, EXYNOS_CIGCTRL);
16762306a36Sopenharmony_ci	cfg &= ~(EXYNOS_CIGCTRL_TESTPATTERN_MASK |
16862306a36Sopenharmony_ci		EXYNOS_CIGCTRL_SELCAM_ITU_MASK |
16962306a36Sopenharmony_ci		EXYNOS_CIGCTRL_SELCAM_MIPI_MASK |
17062306a36Sopenharmony_ci		EXYNOS_CIGCTRL_SELCAM_FIMC_MASK |
17162306a36Sopenharmony_ci		EXYNOS_CIGCTRL_SELWB_CAMIF_MASK |
17262306a36Sopenharmony_ci		EXYNOS_CIGCTRL_SELWRITEBACK_MASK);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	cfg |= (EXYNOS_CIGCTRL_SELCAM_ITU_A |
17562306a36Sopenharmony_ci		EXYNOS_CIGCTRL_SELWRITEBACK_A |
17662306a36Sopenharmony_ci		EXYNOS_CIGCTRL_SELCAM_MIPI_A |
17762306a36Sopenharmony_ci		EXYNOS_CIGCTRL_SELCAM_FIMC_ITU);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CIGCTRL);
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistatic void fimc_handle_jpeg(struct fimc_context *ctx, bool enable)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	u32 cfg;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "enable[%d]\n", enable);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	cfg = fimc_read(ctx, EXYNOS_CIGCTRL);
18962306a36Sopenharmony_ci	if (enable)
19062306a36Sopenharmony_ci		cfg |= EXYNOS_CIGCTRL_CAM_JPEG;
19162306a36Sopenharmony_ci	else
19262306a36Sopenharmony_ci		cfg &= ~EXYNOS_CIGCTRL_CAM_JPEG;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CIGCTRL);
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic void fimc_mask_irq(struct fimc_context *ctx, bool enable)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	u32 cfg;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "enable[%d]\n", enable);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	cfg = fimc_read(ctx, EXYNOS_CIGCTRL);
20462306a36Sopenharmony_ci	if (enable) {
20562306a36Sopenharmony_ci		cfg &= ~EXYNOS_CIGCTRL_IRQ_OVFEN;
20662306a36Sopenharmony_ci		cfg |= EXYNOS_CIGCTRL_IRQ_ENABLE | EXYNOS_CIGCTRL_IRQ_LEVEL;
20762306a36Sopenharmony_ci	} else
20862306a36Sopenharmony_ci		cfg &= ~EXYNOS_CIGCTRL_IRQ_ENABLE;
20962306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CIGCTRL);
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistatic void fimc_clear_irq(struct fimc_context *ctx)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	fimc_set_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_IRQ_CLR);
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic bool fimc_check_ovf(struct fimc_context *ctx)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	u32 status, flag;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	status = fimc_read(ctx, EXYNOS_CISTATUS);
22262306a36Sopenharmony_ci	flag = EXYNOS_CISTATUS_OVFIY | EXYNOS_CISTATUS_OVFICB |
22362306a36Sopenharmony_ci		EXYNOS_CISTATUS_OVFICR;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "flag[0x%x]\n", flag);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	if (status & flag) {
22862306a36Sopenharmony_ci		fimc_set_bits(ctx, EXYNOS_CIWDOFST,
22962306a36Sopenharmony_ci			EXYNOS_CIWDOFST_CLROVFIY | EXYNOS_CIWDOFST_CLROVFICB |
23062306a36Sopenharmony_ci			EXYNOS_CIWDOFST_CLROVFICR);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci		DRM_DEV_ERROR(ctx->dev,
23362306a36Sopenharmony_ci			      "occurred overflow at %d, status 0x%x.\n",
23462306a36Sopenharmony_ci			      ctx->id, status);
23562306a36Sopenharmony_ci		return true;
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	return false;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic bool fimc_check_frame_end(struct fimc_context *ctx)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	u32 cfg;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	cfg = fimc_read(ctx, EXYNOS_CISTATUS);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "cfg[0x%x]\n", cfg);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	if (!(cfg & EXYNOS_CISTATUS_FRAMEEND))
25062306a36Sopenharmony_ci		return false;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	cfg &= ~(EXYNOS_CISTATUS_FRAMEEND);
25362306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CISTATUS);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	return true;
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistatic int fimc_get_buf_id(struct fimc_context *ctx)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	u32 cfg;
26162306a36Sopenharmony_ci	int frame_cnt, buf_id;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	cfg = fimc_read(ctx, EXYNOS_CISTATUS2);
26462306a36Sopenharmony_ci	frame_cnt = EXYNOS_CISTATUS2_GET_FRAMECOUNT_BEFORE(cfg);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	if (frame_cnt == 0)
26762306a36Sopenharmony_ci		frame_cnt = EXYNOS_CISTATUS2_GET_FRAMECOUNT_PRESENT(cfg);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "present[%d]before[%d]\n",
27062306a36Sopenharmony_ci			  EXYNOS_CISTATUS2_GET_FRAMECOUNT_PRESENT(cfg),
27162306a36Sopenharmony_ci			  EXYNOS_CISTATUS2_GET_FRAMECOUNT_BEFORE(cfg));
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	if (frame_cnt == 0) {
27462306a36Sopenharmony_ci		DRM_DEV_ERROR(ctx->dev, "failed to get frame count.\n");
27562306a36Sopenharmony_ci		return -EIO;
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	buf_id = frame_cnt - 1;
27962306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "buf_id[%d]\n", buf_id);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	return buf_id;
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_cistatic void fimc_handle_lastend(struct fimc_context *ctx, bool enable)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	u32 cfg;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "enable[%d]\n", enable);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	cfg = fimc_read(ctx, EXYNOS_CIOCTRL);
29162306a36Sopenharmony_ci	if (enable)
29262306a36Sopenharmony_ci		cfg |= EXYNOS_CIOCTRL_LASTENDEN;
29362306a36Sopenharmony_ci	else
29462306a36Sopenharmony_ci		cfg &= ~EXYNOS_CIOCTRL_LASTENDEN;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CIOCTRL);
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic void fimc_src_set_fmt_order(struct fimc_context *ctx, u32 fmt)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	u32 cfg;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "fmt[0x%x]\n", fmt);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	/* RGB */
30662306a36Sopenharmony_ci	cfg = fimc_read(ctx, EXYNOS_CISCCTRL);
30762306a36Sopenharmony_ci	cfg &= ~EXYNOS_CISCCTRL_INRGB_FMT_RGB_MASK;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	switch (fmt) {
31062306a36Sopenharmony_ci	case DRM_FORMAT_RGB565:
31162306a36Sopenharmony_ci		cfg |= EXYNOS_CISCCTRL_INRGB_FMT_RGB565;
31262306a36Sopenharmony_ci		fimc_write(ctx, cfg, EXYNOS_CISCCTRL);
31362306a36Sopenharmony_ci		return;
31462306a36Sopenharmony_ci	case DRM_FORMAT_RGB888:
31562306a36Sopenharmony_ci	case DRM_FORMAT_XRGB8888:
31662306a36Sopenharmony_ci		cfg |= EXYNOS_CISCCTRL_INRGB_FMT_RGB888;
31762306a36Sopenharmony_ci		fimc_write(ctx, cfg, EXYNOS_CISCCTRL);
31862306a36Sopenharmony_ci		return;
31962306a36Sopenharmony_ci	default:
32062306a36Sopenharmony_ci		/* bypass */
32162306a36Sopenharmony_ci		break;
32262306a36Sopenharmony_ci	}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	/* YUV */
32562306a36Sopenharmony_ci	cfg = fimc_read(ctx, EXYNOS_MSCTRL);
32662306a36Sopenharmony_ci	cfg &= ~(EXYNOS_MSCTRL_ORDER2P_SHIFT_MASK |
32762306a36Sopenharmony_ci		EXYNOS_MSCTRL_C_INT_IN_2PLANE |
32862306a36Sopenharmony_ci		EXYNOS_MSCTRL_ORDER422_YCBYCR);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	switch (fmt) {
33162306a36Sopenharmony_ci	case DRM_FORMAT_YUYV:
33262306a36Sopenharmony_ci		cfg |= EXYNOS_MSCTRL_ORDER422_YCBYCR;
33362306a36Sopenharmony_ci		break;
33462306a36Sopenharmony_ci	case DRM_FORMAT_YVYU:
33562306a36Sopenharmony_ci		cfg |= EXYNOS_MSCTRL_ORDER422_YCRYCB;
33662306a36Sopenharmony_ci		break;
33762306a36Sopenharmony_ci	case DRM_FORMAT_UYVY:
33862306a36Sopenharmony_ci		cfg |= EXYNOS_MSCTRL_ORDER422_CBYCRY;
33962306a36Sopenharmony_ci		break;
34062306a36Sopenharmony_ci	case DRM_FORMAT_VYUY:
34162306a36Sopenharmony_ci	case DRM_FORMAT_YUV444:
34262306a36Sopenharmony_ci		cfg |= EXYNOS_MSCTRL_ORDER422_CRYCBY;
34362306a36Sopenharmony_ci		break;
34462306a36Sopenharmony_ci	case DRM_FORMAT_NV21:
34562306a36Sopenharmony_ci	case DRM_FORMAT_NV61:
34662306a36Sopenharmony_ci		cfg |= (EXYNOS_MSCTRL_ORDER2P_LSB_CRCB |
34762306a36Sopenharmony_ci			EXYNOS_MSCTRL_C_INT_IN_2PLANE);
34862306a36Sopenharmony_ci		break;
34962306a36Sopenharmony_ci	case DRM_FORMAT_YUV422:
35062306a36Sopenharmony_ci	case DRM_FORMAT_YUV420:
35162306a36Sopenharmony_ci	case DRM_FORMAT_YVU420:
35262306a36Sopenharmony_ci		cfg |= EXYNOS_MSCTRL_C_INT_IN_3PLANE;
35362306a36Sopenharmony_ci		break;
35462306a36Sopenharmony_ci	case DRM_FORMAT_NV12:
35562306a36Sopenharmony_ci	case DRM_FORMAT_NV16:
35662306a36Sopenharmony_ci		cfg |= (EXYNOS_MSCTRL_ORDER2P_LSB_CBCR |
35762306a36Sopenharmony_ci			EXYNOS_MSCTRL_C_INT_IN_2PLANE);
35862306a36Sopenharmony_ci		break;
35962306a36Sopenharmony_ci	}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_MSCTRL);
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic void fimc_src_set_fmt(struct fimc_context *ctx, u32 fmt, bool tiled)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	u32 cfg;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "fmt[0x%x]\n", fmt);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	cfg = fimc_read(ctx, EXYNOS_MSCTRL);
37162306a36Sopenharmony_ci	cfg &= ~EXYNOS_MSCTRL_INFORMAT_RGB;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	switch (fmt) {
37462306a36Sopenharmony_ci	case DRM_FORMAT_RGB565:
37562306a36Sopenharmony_ci	case DRM_FORMAT_RGB888:
37662306a36Sopenharmony_ci	case DRM_FORMAT_XRGB8888:
37762306a36Sopenharmony_ci		cfg |= EXYNOS_MSCTRL_INFORMAT_RGB;
37862306a36Sopenharmony_ci		break;
37962306a36Sopenharmony_ci	case DRM_FORMAT_YUV444:
38062306a36Sopenharmony_ci		cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR420;
38162306a36Sopenharmony_ci		break;
38262306a36Sopenharmony_ci	case DRM_FORMAT_YUYV:
38362306a36Sopenharmony_ci	case DRM_FORMAT_YVYU:
38462306a36Sopenharmony_ci	case DRM_FORMAT_UYVY:
38562306a36Sopenharmony_ci	case DRM_FORMAT_VYUY:
38662306a36Sopenharmony_ci		cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR422_1PLANE;
38762306a36Sopenharmony_ci		break;
38862306a36Sopenharmony_ci	case DRM_FORMAT_NV16:
38962306a36Sopenharmony_ci	case DRM_FORMAT_NV61:
39062306a36Sopenharmony_ci	case DRM_FORMAT_YUV422:
39162306a36Sopenharmony_ci		cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR422;
39262306a36Sopenharmony_ci		break;
39362306a36Sopenharmony_ci	case DRM_FORMAT_YUV420:
39462306a36Sopenharmony_ci	case DRM_FORMAT_YVU420:
39562306a36Sopenharmony_ci	case DRM_FORMAT_NV12:
39662306a36Sopenharmony_ci	case DRM_FORMAT_NV21:
39762306a36Sopenharmony_ci		cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR420;
39862306a36Sopenharmony_ci		break;
39962306a36Sopenharmony_ci	}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_MSCTRL);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	cfg = fimc_read(ctx, EXYNOS_CIDMAPARAM);
40462306a36Sopenharmony_ci	cfg &= ~EXYNOS_CIDMAPARAM_R_MODE_MASK;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	if (tiled)
40762306a36Sopenharmony_ci		cfg |= EXYNOS_CIDMAPARAM_R_MODE_64X32;
40862306a36Sopenharmony_ci	else
40962306a36Sopenharmony_ci		cfg |= EXYNOS_CIDMAPARAM_R_MODE_LINEAR;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CIDMAPARAM);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	fimc_src_set_fmt_order(ctx, fmt);
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_cistatic void fimc_src_set_transf(struct fimc_context *ctx, unsigned int rotation)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	unsigned int degree = rotation & DRM_MODE_ROTATE_MASK;
41962306a36Sopenharmony_ci	u32 cfg1, cfg2;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "rotation[%x]\n", rotation);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	cfg1 = fimc_read(ctx, EXYNOS_MSCTRL);
42462306a36Sopenharmony_ci	cfg1 &= ~(EXYNOS_MSCTRL_FLIP_X_MIRROR |
42562306a36Sopenharmony_ci		EXYNOS_MSCTRL_FLIP_Y_MIRROR);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	cfg2 = fimc_read(ctx, EXYNOS_CITRGFMT);
42862306a36Sopenharmony_ci	cfg2 &= ~EXYNOS_CITRGFMT_INROT90_CLOCKWISE;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	switch (degree) {
43162306a36Sopenharmony_ci	case DRM_MODE_ROTATE_0:
43262306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_X)
43362306a36Sopenharmony_ci			cfg1 |= EXYNOS_MSCTRL_FLIP_X_MIRROR;
43462306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_Y)
43562306a36Sopenharmony_ci			cfg1 |= EXYNOS_MSCTRL_FLIP_Y_MIRROR;
43662306a36Sopenharmony_ci		break;
43762306a36Sopenharmony_ci	case DRM_MODE_ROTATE_90:
43862306a36Sopenharmony_ci		cfg2 |= EXYNOS_CITRGFMT_INROT90_CLOCKWISE;
43962306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_X)
44062306a36Sopenharmony_ci			cfg1 |= EXYNOS_MSCTRL_FLIP_X_MIRROR;
44162306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_Y)
44262306a36Sopenharmony_ci			cfg1 |= EXYNOS_MSCTRL_FLIP_Y_MIRROR;
44362306a36Sopenharmony_ci		break;
44462306a36Sopenharmony_ci	case DRM_MODE_ROTATE_180:
44562306a36Sopenharmony_ci		cfg1 |= (EXYNOS_MSCTRL_FLIP_X_MIRROR |
44662306a36Sopenharmony_ci			EXYNOS_MSCTRL_FLIP_Y_MIRROR);
44762306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_X)
44862306a36Sopenharmony_ci			cfg1 &= ~EXYNOS_MSCTRL_FLIP_X_MIRROR;
44962306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_Y)
45062306a36Sopenharmony_ci			cfg1 &= ~EXYNOS_MSCTRL_FLIP_Y_MIRROR;
45162306a36Sopenharmony_ci		break;
45262306a36Sopenharmony_ci	case DRM_MODE_ROTATE_270:
45362306a36Sopenharmony_ci		cfg1 |= (EXYNOS_MSCTRL_FLIP_X_MIRROR |
45462306a36Sopenharmony_ci			EXYNOS_MSCTRL_FLIP_Y_MIRROR);
45562306a36Sopenharmony_ci		cfg2 |= EXYNOS_CITRGFMT_INROT90_CLOCKWISE;
45662306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_X)
45762306a36Sopenharmony_ci			cfg1 &= ~EXYNOS_MSCTRL_FLIP_X_MIRROR;
45862306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_Y)
45962306a36Sopenharmony_ci			cfg1 &= ~EXYNOS_MSCTRL_FLIP_Y_MIRROR;
46062306a36Sopenharmony_ci		break;
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	fimc_write(ctx, cfg1, EXYNOS_MSCTRL);
46462306a36Sopenharmony_ci	fimc_write(ctx, cfg2, EXYNOS_CITRGFMT);
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_cistatic void fimc_set_window(struct fimc_context *ctx,
46862306a36Sopenharmony_ci			    struct exynos_drm_ipp_buffer *buf)
46962306a36Sopenharmony_ci{
47062306a36Sopenharmony_ci	unsigned int real_width = buf->buf.pitch[0] / buf->format->cpp[0];
47162306a36Sopenharmony_ci	u32 cfg, h1, h2, v1, v2;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	/* cropped image */
47462306a36Sopenharmony_ci	h1 = buf->rect.x;
47562306a36Sopenharmony_ci	h2 = real_width - buf->rect.w - buf->rect.x;
47662306a36Sopenharmony_ci	v1 = buf->rect.y;
47762306a36Sopenharmony_ci	v2 = buf->buf.height - buf->rect.h - buf->rect.y;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "x[%d]y[%d]w[%d]h[%d]hsize[%d]vsize[%d]\n",
48062306a36Sopenharmony_ci			  buf->rect.x, buf->rect.y, buf->rect.w, buf->rect.h,
48162306a36Sopenharmony_ci			  real_width, buf->buf.height);
48262306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "h1[%d]h2[%d]v1[%d]v2[%d]\n", h1, h2, v1,
48362306a36Sopenharmony_ci			  v2);
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	/*
48662306a36Sopenharmony_ci	 * set window offset 1, 2 size
48762306a36Sopenharmony_ci	 * check figure 43-21 in user manual
48862306a36Sopenharmony_ci	 */
48962306a36Sopenharmony_ci	cfg = fimc_read(ctx, EXYNOS_CIWDOFST);
49062306a36Sopenharmony_ci	cfg &= ~(EXYNOS_CIWDOFST_WINHOROFST_MASK |
49162306a36Sopenharmony_ci		EXYNOS_CIWDOFST_WINVEROFST_MASK);
49262306a36Sopenharmony_ci	cfg |= (EXYNOS_CIWDOFST_WINHOROFST(h1) |
49362306a36Sopenharmony_ci		EXYNOS_CIWDOFST_WINVEROFST(v1));
49462306a36Sopenharmony_ci	cfg |= EXYNOS_CIWDOFST_WINOFSEN;
49562306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CIWDOFST);
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	cfg = (EXYNOS_CIWDOFST2_WINHOROFST2(h2) |
49862306a36Sopenharmony_ci		EXYNOS_CIWDOFST2_WINVEROFST2(v2));
49962306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CIWDOFST2);
50062306a36Sopenharmony_ci}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_cistatic void fimc_src_set_size(struct fimc_context *ctx,
50362306a36Sopenharmony_ci			      struct exynos_drm_ipp_buffer *buf)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	unsigned int real_width = buf->buf.pitch[0] / buf->format->cpp[0];
50662306a36Sopenharmony_ci	u32 cfg;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "hsize[%d]vsize[%d]\n", real_width,
50962306a36Sopenharmony_ci			  buf->buf.height);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	/* original size */
51262306a36Sopenharmony_ci	cfg = (EXYNOS_ORGISIZE_HORIZONTAL(real_width) |
51362306a36Sopenharmony_ci		EXYNOS_ORGISIZE_VERTICAL(buf->buf.height));
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_ORGISIZE);
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "x[%d]y[%d]w[%d]h[%d]\n", buf->rect.x,
51862306a36Sopenharmony_ci			  buf->rect.y, buf->rect.w, buf->rect.h);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	/* set input DMA image size */
52162306a36Sopenharmony_ci	cfg = fimc_read(ctx, EXYNOS_CIREAL_ISIZE);
52262306a36Sopenharmony_ci	cfg &= ~(EXYNOS_CIREAL_ISIZE_HEIGHT_MASK |
52362306a36Sopenharmony_ci		EXYNOS_CIREAL_ISIZE_WIDTH_MASK);
52462306a36Sopenharmony_ci	cfg |= (EXYNOS_CIREAL_ISIZE_WIDTH(buf->rect.w) |
52562306a36Sopenharmony_ci		EXYNOS_CIREAL_ISIZE_HEIGHT(buf->rect.h));
52662306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CIREAL_ISIZE);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	/*
52962306a36Sopenharmony_ci	 * set input FIFO image size
53062306a36Sopenharmony_ci	 * for now, we support only ITU601 8 bit mode
53162306a36Sopenharmony_ci	 */
53262306a36Sopenharmony_ci	cfg = (EXYNOS_CISRCFMT_ITU601_8BIT |
53362306a36Sopenharmony_ci		EXYNOS_CISRCFMT_SOURCEHSIZE(real_width) |
53462306a36Sopenharmony_ci		EXYNOS_CISRCFMT_SOURCEVSIZE(buf->buf.height));
53562306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CISRCFMT);
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	/* offset Y(RGB), Cb, Cr */
53862306a36Sopenharmony_ci	cfg = (EXYNOS_CIIYOFF_HORIZONTAL(buf->rect.x) |
53962306a36Sopenharmony_ci		EXYNOS_CIIYOFF_VERTICAL(buf->rect.y));
54062306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CIIYOFF);
54162306a36Sopenharmony_ci	cfg = (EXYNOS_CIICBOFF_HORIZONTAL(buf->rect.x) |
54262306a36Sopenharmony_ci		EXYNOS_CIICBOFF_VERTICAL(buf->rect.y));
54362306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CIICBOFF);
54462306a36Sopenharmony_ci	cfg = (EXYNOS_CIICROFF_HORIZONTAL(buf->rect.x) |
54562306a36Sopenharmony_ci		EXYNOS_CIICROFF_VERTICAL(buf->rect.y));
54662306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CIICROFF);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	fimc_set_window(ctx, buf);
54962306a36Sopenharmony_ci}
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_cistatic void fimc_src_set_addr(struct fimc_context *ctx,
55262306a36Sopenharmony_ci			      struct exynos_drm_ipp_buffer *buf)
55362306a36Sopenharmony_ci{
55462306a36Sopenharmony_ci	fimc_write(ctx, buf->dma_addr[0], EXYNOS_CIIYSA(0));
55562306a36Sopenharmony_ci	fimc_write(ctx, buf->dma_addr[1], EXYNOS_CIICBSA(0));
55662306a36Sopenharmony_ci	fimc_write(ctx, buf->dma_addr[2], EXYNOS_CIICRSA(0));
55762306a36Sopenharmony_ci}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_cistatic void fimc_dst_set_fmt_order(struct fimc_context *ctx, u32 fmt)
56062306a36Sopenharmony_ci{
56162306a36Sopenharmony_ci	u32 cfg;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "fmt[0x%x]\n", fmt);
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	/* RGB */
56662306a36Sopenharmony_ci	cfg = fimc_read(ctx, EXYNOS_CISCCTRL);
56762306a36Sopenharmony_ci	cfg &= ~EXYNOS_CISCCTRL_OUTRGB_FMT_RGB_MASK;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	switch (fmt) {
57062306a36Sopenharmony_ci	case DRM_FORMAT_RGB565:
57162306a36Sopenharmony_ci		cfg |= EXYNOS_CISCCTRL_OUTRGB_FMT_RGB565;
57262306a36Sopenharmony_ci		fimc_write(ctx, cfg, EXYNOS_CISCCTRL);
57362306a36Sopenharmony_ci		return;
57462306a36Sopenharmony_ci	case DRM_FORMAT_RGB888:
57562306a36Sopenharmony_ci		cfg |= EXYNOS_CISCCTRL_OUTRGB_FMT_RGB888;
57662306a36Sopenharmony_ci		fimc_write(ctx, cfg, EXYNOS_CISCCTRL);
57762306a36Sopenharmony_ci		return;
57862306a36Sopenharmony_ci	case DRM_FORMAT_XRGB8888:
57962306a36Sopenharmony_ci		cfg |= (EXYNOS_CISCCTRL_OUTRGB_FMT_RGB888 |
58062306a36Sopenharmony_ci			EXYNOS_CISCCTRL_EXTRGB_EXTENSION);
58162306a36Sopenharmony_ci		fimc_write(ctx, cfg, EXYNOS_CISCCTRL);
58262306a36Sopenharmony_ci		break;
58362306a36Sopenharmony_ci	default:
58462306a36Sopenharmony_ci		/* bypass */
58562306a36Sopenharmony_ci		break;
58662306a36Sopenharmony_ci	}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	/* YUV */
58962306a36Sopenharmony_ci	cfg = fimc_read(ctx, EXYNOS_CIOCTRL);
59062306a36Sopenharmony_ci	cfg &= ~(EXYNOS_CIOCTRL_ORDER2P_MASK |
59162306a36Sopenharmony_ci		EXYNOS_CIOCTRL_ORDER422_MASK |
59262306a36Sopenharmony_ci		EXYNOS_CIOCTRL_YCBCR_PLANE_MASK);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	switch (fmt) {
59562306a36Sopenharmony_ci	case DRM_FORMAT_XRGB8888:
59662306a36Sopenharmony_ci		cfg |= EXYNOS_CIOCTRL_ALPHA_OUT;
59762306a36Sopenharmony_ci		break;
59862306a36Sopenharmony_ci	case DRM_FORMAT_YUYV:
59962306a36Sopenharmony_ci		cfg |= EXYNOS_CIOCTRL_ORDER422_YCBYCR;
60062306a36Sopenharmony_ci		break;
60162306a36Sopenharmony_ci	case DRM_FORMAT_YVYU:
60262306a36Sopenharmony_ci		cfg |= EXYNOS_CIOCTRL_ORDER422_YCRYCB;
60362306a36Sopenharmony_ci		break;
60462306a36Sopenharmony_ci	case DRM_FORMAT_UYVY:
60562306a36Sopenharmony_ci		cfg |= EXYNOS_CIOCTRL_ORDER422_CBYCRY;
60662306a36Sopenharmony_ci		break;
60762306a36Sopenharmony_ci	case DRM_FORMAT_VYUY:
60862306a36Sopenharmony_ci		cfg |= EXYNOS_CIOCTRL_ORDER422_CRYCBY;
60962306a36Sopenharmony_ci		break;
61062306a36Sopenharmony_ci	case DRM_FORMAT_NV21:
61162306a36Sopenharmony_ci	case DRM_FORMAT_NV61:
61262306a36Sopenharmony_ci		cfg |= EXYNOS_CIOCTRL_ORDER2P_LSB_CRCB;
61362306a36Sopenharmony_ci		cfg |= EXYNOS_CIOCTRL_YCBCR_2PLANE;
61462306a36Sopenharmony_ci		break;
61562306a36Sopenharmony_ci	case DRM_FORMAT_YUV422:
61662306a36Sopenharmony_ci	case DRM_FORMAT_YUV420:
61762306a36Sopenharmony_ci	case DRM_FORMAT_YVU420:
61862306a36Sopenharmony_ci		cfg |= EXYNOS_CIOCTRL_YCBCR_3PLANE;
61962306a36Sopenharmony_ci		break;
62062306a36Sopenharmony_ci	case DRM_FORMAT_NV12:
62162306a36Sopenharmony_ci	case DRM_FORMAT_NV16:
62262306a36Sopenharmony_ci		cfg |= EXYNOS_CIOCTRL_ORDER2P_LSB_CBCR;
62362306a36Sopenharmony_ci		cfg |= EXYNOS_CIOCTRL_YCBCR_2PLANE;
62462306a36Sopenharmony_ci		break;
62562306a36Sopenharmony_ci	}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CIOCTRL);
62862306a36Sopenharmony_ci}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_cistatic void fimc_dst_set_fmt(struct fimc_context *ctx, u32 fmt, bool tiled)
63162306a36Sopenharmony_ci{
63262306a36Sopenharmony_ci	u32 cfg;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "fmt[0x%x]\n", fmt);
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	cfg = fimc_read(ctx, EXYNOS_CIEXTEN);
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	if (fmt == DRM_FORMAT_AYUV) {
63962306a36Sopenharmony_ci		cfg |= EXYNOS_CIEXTEN_YUV444_OUT;
64062306a36Sopenharmony_ci		fimc_write(ctx, cfg, EXYNOS_CIEXTEN);
64162306a36Sopenharmony_ci	} else {
64262306a36Sopenharmony_ci		cfg &= ~EXYNOS_CIEXTEN_YUV444_OUT;
64362306a36Sopenharmony_ci		fimc_write(ctx, cfg, EXYNOS_CIEXTEN);
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci		cfg = fimc_read(ctx, EXYNOS_CITRGFMT);
64662306a36Sopenharmony_ci		cfg &= ~EXYNOS_CITRGFMT_OUTFORMAT_MASK;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci		switch (fmt) {
64962306a36Sopenharmony_ci		case DRM_FORMAT_RGB565:
65062306a36Sopenharmony_ci		case DRM_FORMAT_RGB888:
65162306a36Sopenharmony_ci		case DRM_FORMAT_XRGB8888:
65262306a36Sopenharmony_ci			cfg |= EXYNOS_CITRGFMT_OUTFORMAT_RGB;
65362306a36Sopenharmony_ci			break;
65462306a36Sopenharmony_ci		case DRM_FORMAT_YUYV:
65562306a36Sopenharmony_ci		case DRM_FORMAT_YVYU:
65662306a36Sopenharmony_ci		case DRM_FORMAT_UYVY:
65762306a36Sopenharmony_ci		case DRM_FORMAT_VYUY:
65862306a36Sopenharmony_ci			cfg |= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR422_1PLANE;
65962306a36Sopenharmony_ci			break;
66062306a36Sopenharmony_ci		case DRM_FORMAT_NV16:
66162306a36Sopenharmony_ci		case DRM_FORMAT_NV61:
66262306a36Sopenharmony_ci		case DRM_FORMAT_YUV422:
66362306a36Sopenharmony_ci			cfg |= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR422;
66462306a36Sopenharmony_ci			break;
66562306a36Sopenharmony_ci		case DRM_FORMAT_YUV420:
66662306a36Sopenharmony_ci		case DRM_FORMAT_YVU420:
66762306a36Sopenharmony_ci		case DRM_FORMAT_NV12:
66862306a36Sopenharmony_ci		case DRM_FORMAT_NV21:
66962306a36Sopenharmony_ci			cfg |= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR420;
67062306a36Sopenharmony_ci			break;
67162306a36Sopenharmony_ci		}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci		fimc_write(ctx, cfg, EXYNOS_CITRGFMT);
67462306a36Sopenharmony_ci	}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	cfg = fimc_read(ctx, EXYNOS_CIDMAPARAM);
67762306a36Sopenharmony_ci	cfg &= ~EXYNOS_CIDMAPARAM_W_MODE_MASK;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	if (tiled)
68062306a36Sopenharmony_ci		cfg |= EXYNOS_CIDMAPARAM_W_MODE_64X32;
68162306a36Sopenharmony_ci	else
68262306a36Sopenharmony_ci		cfg |= EXYNOS_CIDMAPARAM_W_MODE_LINEAR;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CIDMAPARAM);
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	fimc_dst_set_fmt_order(ctx, fmt);
68762306a36Sopenharmony_ci}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_cistatic void fimc_dst_set_transf(struct fimc_context *ctx, unsigned int rotation)
69062306a36Sopenharmony_ci{
69162306a36Sopenharmony_ci	unsigned int degree = rotation & DRM_MODE_ROTATE_MASK;
69262306a36Sopenharmony_ci	u32 cfg;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "rotation[0x%x]\n", rotation);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	cfg = fimc_read(ctx, EXYNOS_CITRGFMT);
69762306a36Sopenharmony_ci	cfg &= ~EXYNOS_CITRGFMT_FLIP_MASK;
69862306a36Sopenharmony_ci	cfg &= ~EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	switch (degree) {
70162306a36Sopenharmony_ci	case DRM_MODE_ROTATE_0:
70262306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_X)
70362306a36Sopenharmony_ci			cfg |= EXYNOS_CITRGFMT_FLIP_X_MIRROR;
70462306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_Y)
70562306a36Sopenharmony_ci			cfg |= EXYNOS_CITRGFMT_FLIP_Y_MIRROR;
70662306a36Sopenharmony_ci		break;
70762306a36Sopenharmony_ci	case DRM_MODE_ROTATE_90:
70862306a36Sopenharmony_ci		cfg |= EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE;
70962306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_X)
71062306a36Sopenharmony_ci			cfg |= EXYNOS_CITRGFMT_FLIP_X_MIRROR;
71162306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_Y)
71262306a36Sopenharmony_ci			cfg |= EXYNOS_CITRGFMT_FLIP_Y_MIRROR;
71362306a36Sopenharmony_ci		break;
71462306a36Sopenharmony_ci	case DRM_MODE_ROTATE_180:
71562306a36Sopenharmony_ci		cfg |= (EXYNOS_CITRGFMT_FLIP_X_MIRROR |
71662306a36Sopenharmony_ci			EXYNOS_CITRGFMT_FLIP_Y_MIRROR);
71762306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_X)
71862306a36Sopenharmony_ci			cfg &= ~EXYNOS_CITRGFMT_FLIP_X_MIRROR;
71962306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_Y)
72062306a36Sopenharmony_ci			cfg &= ~EXYNOS_CITRGFMT_FLIP_Y_MIRROR;
72162306a36Sopenharmony_ci		break;
72262306a36Sopenharmony_ci	case DRM_MODE_ROTATE_270:
72362306a36Sopenharmony_ci		cfg |= (EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE |
72462306a36Sopenharmony_ci			EXYNOS_CITRGFMT_FLIP_X_MIRROR |
72562306a36Sopenharmony_ci			EXYNOS_CITRGFMT_FLIP_Y_MIRROR);
72662306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_X)
72762306a36Sopenharmony_ci			cfg &= ~EXYNOS_CITRGFMT_FLIP_X_MIRROR;
72862306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_Y)
72962306a36Sopenharmony_ci			cfg &= ~EXYNOS_CITRGFMT_FLIP_Y_MIRROR;
73062306a36Sopenharmony_ci		break;
73162306a36Sopenharmony_ci	}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CITRGFMT);
73462306a36Sopenharmony_ci}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_cistatic int fimc_set_prescaler(struct fimc_context *ctx, struct fimc_scaler *sc,
73762306a36Sopenharmony_ci			      struct drm_exynos_ipp_task_rect *src,
73862306a36Sopenharmony_ci			      struct drm_exynos_ipp_task_rect *dst)
73962306a36Sopenharmony_ci{
74062306a36Sopenharmony_ci	u32 cfg, cfg_ext, shfactor;
74162306a36Sopenharmony_ci	u32 pre_dst_width, pre_dst_height;
74262306a36Sopenharmony_ci	u32 hfactor, vfactor;
74362306a36Sopenharmony_ci	int ret = 0;
74462306a36Sopenharmony_ci	u32 src_w, src_h, dst_w, dst_h;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	cfg_ext = fimc_read(ctx, EXYNOS_CITRGFMT);
74762306a36Sopenharmony_ci	if (cfg_ext & EXYNOS_CITRGFMT_INROT90_CLOCKWISE) {
74862306a36Sopenharmony_ci		src_w = src->h;
74962306a36Sopenharmony_ci		src_h = src->w;
75062306a36Sopenharmony_ci	} else {
75162306a36Sopenharmony_ci		src_w = src->w;
75262306a36Sopenharmony_ci		src_h = src->h;
75362306a36Sopenharmony_ci	}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	if (cfg_ext & EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE) {
75662306a36Sopenharmony_ci		dst_w = dst->h;
75762306a36Sopenharmony_ci		dst_h = dst->w;
75862306a36Sopenharmony_ci	} else {
75962306a36Sopenharmony_ci		dst_w = dst->w;
76062306a36Sopenharmony_ci		dst_h = dst->h;
76162306a36Sopenharmony_ci	}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	/* fimc_ippdrv_check_property assures that dividers are not null */
76462306a36Sopenharmony_ci	hfactor = fls(src_w / dst_w / 2);
76562306a36Sopenharmony_ci	if (hfactor > FIMC_SHFACTOR / 2) {
76662306a36Sopenharmony_ci		dev_err(ctx->dev, "failed to get ratio horizontal.\n");
76762306a36Sopenharmony_ci		return -EINVAL;
76862306a36Sopenharmony_ci	}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	vfactor = fls(src_h / dst_h / 2);
77162306a36Sopenharmony_ci	if (vfactor > FIMC_SHFACTOR / 2) {
77262306a36Sopenharmony_ci		dev_err(ctx->dev, "failed to get ratio vertical.\n");
77362306a36Sopenharmony_ci		return -EINVAL;
77462306a36Sopenharmony_ci	}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	pre_dst_width = src_w >> hfactor;
77762306a36Sopenharmony_ci	pre_dst_height = src_h >> vfactor;
77862306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "pre_dst_width[%d]pre_dst_height[%d]\n",
77962306a36Sopenharmony_ci			  pre_dst_width, pre_dst_height);
78062306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "hfactor[%d]vfactor[%d]\n", hfactor,
78162306a36Sopenharmony_ci			  vfactor);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	sc->hratio = (src_w << 14) / (dst_w << hfactor);
78462306a36Sopenharmony_ci	sc->vratio = (src_h << 14) / (dst_h << vfactor);
78562306a36Sopenharmony_ci	sc->up_h = (dst_w >= src_w);
78662306a36Sopenharmony_ci	sc->up_v = (dst_h >= src_h);
78762306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "hratio[%d]vratio[%d]up_h[%d]up_v[%d]\n",
78862306a36Sopenharmony_ci			  sc->hratio, sc->vratio, sc->up_h, sc->up_v);
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	shfactor = FIMC_SHFACTOR - (hfactor + vfactor);
79162306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "shfactor[%d]\n", shfactor);
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	cfg = (EXYNOS_CISCPRERATIO_SHFACTOR(shfactor) |
79462306a36Sopenharmony_ci		EXYNOS_CISCPRERATIO_PREHORRATIO(1 << hfactor) |
79562306a36Sopenharmony_ci		EXYNOS_CISCPRERATIO_PREVERRATIO(1 << vfactor));
79662306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CISCPRERATIO);
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	cfg = (EXYNOS_CISCPREDST_PREDSTWIDTH(pre_dst_width) |
79962306a36Sopenharmony_ci		EXYNOS_CISCPREDST_PREDSTHEIGHT(pre_dst_height));
80062306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CISCPREDST);
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	return ret;
80362306a36Sopenharmony_ci}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_cistatic void fimc_set_scaler(struct fimc_context *ctx, struct fimc_scaler *sc)
80662306a36Sopenharmony_ci{
80762306a36Sopenharmony_ci	u32 cfg, cfg_ext;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "range[%d]bypass[%d]up_h[%d]up_v[%d]\n",
81062306a36Sopenharmony_ci			  sc->range, sc->bypass, sc->up_h, sc->up_v);
81162306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "hratio[%d]vratio[%d]\n",
81262306a36Sopenharmony_ci			  sc->hratio, sc->vratio);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	cfg = fimc_read(ctx, EXYNOS_CISCCTRL);
81562306a36Sopenharmony_ci	cfg &= ~(EXYNOS_CISCCTRL_SCALERBYPASS |
81662306a36Sopenharmony_ci		EXYNOS_CISCCTRL_SCALEUP_H | EXYNOS_CISCCTRL_SCALEUP_V |
81762306a36Sopenharmony_ci		EXYNOS_CISCCTRL_MAIN_V_RATIO_MASK |
81862306a36Sopenharmony_ci		EXYNOS_CISCCTRL_MAIN_H_RATIO_MASK |
81962306a36Sopenharmony_ci		EXYNOS_CISCCTRL_CSCR2Y_WIDE |
82062306a36Sopenharmony_ci		EXYNOS_CISCCTRL_CSCY2R_WIDE);
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	if (sc->range)
82362306a36Sopenharmony_ci		cfg |= (EXYNOS_CISCCTRL_CSCR2Y_WIDE |
82462306a36Sopenharmony_ci			EXYNOS_CISCCTRL_CSCY2R_WIDE);
82562306a36Sopenharmony_ci	if (sc->bypass)
82662306a36Sopenharmony_ci		cfg |= EXYNOS_CISCCTRL_SCALERBYPASS;
82762306a36Sopenharmony_ci	if (sc->up_h)
82862306a36Sopenharmony_ci		cfg |= EXYNOS_CISCCTRL_SCALEUP_H;
82962306a36Sopenharmony_ci	if (sc->up_v)
83062306a36Sopenharmony_ci		cfg |= EXYNOS_CISCCTRL_SCALEUP_V;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	cfg |= (EXYNOS_CISCCTRL_MAINHORRATIO((sc->hratio >> 6)) |
83362306a36Sopenharmony_ci		EXYNOS_CISCCTRL_MAINVERRATIO((sc->vratio >> 6)));
83462306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CISCCTRL);
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	cfg_ext = fimc_read(ctx, EXYNOS_CIEXTEN);
83762306a36Sopenharmony_ci	cfg_ext &= ~EXYNOS_CIEXTEN_MAINHORRATIO_EXT_MASK;
83862306a36Sopenharmony_ci	cfg_ext &= ~EXYNOS_CIEXTEN_MAINVERRATIO_EXT_MASK;
83962306a36Sopenharmony_ci	cfg_ext |= (EXYNOS_CIEXTEN_MAINHORRATIO_EXT(sc->hratio) |
84062306a36Sopenharmony_ci		EXYNOS_CIEXTEN_MAINVERRATIO_EXT(sc->vratio));
84162306a36Sopenharmony_ci	fimc_write(ctx, cfg_ext, EXYNOS_CIEXTEN);
84262306a36Sopenharmony_ci}
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_cistatic void fimc_dst_set_size(struct fimc_context *ctx,
84562306a36Sopenharmony_ci			     struct exynos_drm_ipp_buffer *buf)
84662306a36Sopenharmony_ci{
84762306a36Sopenharmony_ci	unsigned int real_width = buf->buf.pitch[0] / buf->format->cpp[0];
84862306a36Sopenharmony_ci	u32 cfg, cfg_ext;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "hsize[%d]vsize[%d]\n", real_width,
85162306a36Sopenharmony_ci			  buf->buf.height);
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	/* original size */
85462306a36Sopenharmony_ci	cfg = (EXYNOS_ORGOSIZE_HORIZONTAL(real_width) |
85562306a36Sopenharmony_ci		EXYNOS_ORGOSIZE_VERTICAL(buf->buf.height));
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_ORGOSIZE);
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "x[%d]y[%d]w[%d]h[%d]\n", buf->rect.x,
86062306a36Sopenharmony_ci			  buf->rect.y,
86162306a36Sopenharmony_ci			  buf->rect.w, buf->rect.h);
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	/* CSC ITU */
86462306a36Sopenharmony_ci	cfg = fimc_read(ctx, EXYNOS_CIGCTRL);
86562306a36Sopenharmony_ci	cfg &= ~EXYNOS_CIGCTRL_CSC_MASK;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	if (buf->buf.width >= FIMC_WIDTH_ITU_709)
86862306a36Sopenharmony_ci		cfg |= EXYNOS_CIGCTRL_CSC_ITU709;
86962306a36Sopenharmony_ci	else
87062306a36Sopenharmony_ci		cfg |= EXYNOS_CIGCTRL_CSC_ITU601;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CIGCTRL);
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	cfg_ext = fimc_read(ctx, EXYNOS_CITRGFMT);
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	/* target image size */
87762306a36Sopenharmony_ci	cfg = fimc_read(ctx, EXYNOS_CITRGFMT);
87862306a36Sopenharmony_ci	cfg &= ~(EXYNOS_CITRGFMT_TARGETH_MASK |
87962306a36Sopenharmony_ci		EXYNOS_CITRGFMT_TARGETV_MASK);
88062306a36Sopenharmony_ci	if (cfg_ext & EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE)
88162306a36Sopenharmony_ci		cfg |= (EXYNOS_CITRGFMT_TARGETHSIZE(buf->rect.h) |
88262306a36Sopenharmony_ci			EXYNOS_CITRGFMT_TARGETVSIZE(buf->rect.w));
88362306a36Sopenharmony_ci	else
88462306a36Sopenharmony_ci		cfg |= (EXYNOS_CITRGFMT_TARGETHSIZE(buf->rect.w) |
88562306a36Sopenharmony_ci			EXYNOS_CITRGFMT_TARGETVSIZE(buf->rect.h));
88662306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CITRGFMT);
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	/* target area */
88962306a36Sopenharmony_ci	cfg = EXYNOS_CITAREA_TARGET_AREA(buf->rect.w * buf->rect.h);
89062306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CITAREA);
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	/* offset Y(RGB), Cb, Cr */
89362306a36Sopenharmony_ci	cfg = (EXYNOS_CIOYOFF_HORIZONTAL(buf->rect.x) |
89462306a36Sopenharmony_ci		EXYNOS_CIOYOFF_VERTICAL(buf->rect.y));
89562306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CIOYOFF);
89662306a36Sopenharmony_ci	cfg = (EXYNOS_CIOCBOFF_HORIZONTAL(buf->rect.x) |
89762306a36Sopenharmony_ci		EXYNOS_CIOCBOFF_VERTICAL(buf->rect.y));
89862306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CIOCBOFF);
89962306a36Sopenharmony_ci	cfg = (EXYNOS_CIOCROFF_HORIZONTAL(buf->rect.x) |
90062306a36Sopenharmony_ci		EXYNOS_CIOCROFF_VERTICAL(buf->rect.y));
90162306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CIOCROFF);
90262306a36Sopenharmony_ci}
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_cistatic void fimc_dst_set_buf_seq(struct fimc_context *ctx, u32 buf_id,
90562306a36Sopenharmony_ci		bool enqueue)
90662306a36Sopenharmony_ci{
90762306a36Sopenharmony_ci	unsigned long flags;
90862306a36Sopenharmony_ci	u32 buf_num;
90962306a36Sopenharmony_ci	u32 cfg;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "buf_id[%d]enqueu[%d]\n", buf_id, enqueue);
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	spin_lock_irqsave(&ctx->lock, flags);
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	cfg = fimc_read(ctx, EXYNOS_CIFCNTSEQ);
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	if (enqueue)
91862306a36Sopenharmony_ci		cfg |= (1 << buf_id);
91962306a36Sopenharmony_ci	else
92062306a36Sopenharmony_ci		cfg &= ~(1 << buf_id);
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_CIFCNTSEQ);
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	buf_num = hweight32(cfg);
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	if (enqueue && buf_num >= FIMC_BUF_START)
92762306a36Sopenharmony_ci		fimc_mask_irq(ctx, true);
92862306a36Sopenharmony_ci	else if (!enqueue && buf_num <= FIMC_BUF_STOP)
92962306a36Sopenharmony_ci		fimc_mask_irq(ctx, false);
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	spin_unlock_irqrestore(&ctx->lock, flags);
93262306a36Sopenharmony_ci}
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_cistatic void fimc_dst_set_addr(struct fimc_context *ctx,
93562306a36Sopenharmony_ci			     struct exynos_drm_ipp_buffer *buf)
93662306a36Sopenharmony_ci{
93762306a36Sopenharmony_ci	fimc_write(ctx, buf->dma_addr[0], EXYNOS_CIOYSA(0));
93862306a36Sopenharmony_ci	fimc_write(ctx, buf->dma_addr[1], EXYNOS_CIOCBSA(0));
93962306a36Sopenharmony_ci	fimc_write(ctx, buf->dma_addr[2], EXYNOS_CIOCRSA(0));
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	fimc_dst_set_buf_seq(ctx, 0, true);
94262306a36Sopenharmony_ci}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_cistatic void fimc_stop(struct fimc_context *ctx);
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_cistatic irqreturn_t fimc_irq_handler(int irq, void *dev_id)
94762306a36Sopenharmony_ci{
94862306a36Sopenharmony_ci	struct fimc_context *ctx = dev_id;
94962306a36Sopenharmony_ci	int buf_id;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "fimc id[%d]\n", ctx->id);
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	fimc_clear_irq(ctx);
95462306a36Sopenharmony_ci	if (fimc_check_ovf(ctx))
95562306a36Sopenharmony_ci		return IRQ_NONE;
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	if (!fimc_check_frame_end(ctx))
95862306a36Sopenharmony_ci		return IRQ_NONE;
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	buf_id = fimc_get_buf_id(ctx);
96162306a36Sopenharmony_ci	if (buf_id < 0)
96262306a36Sopenharmony_ci		return IRQ_HANDLED;
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "buf_id[%d]\n", buf_id);
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	if (ctx->task) {
96762306a36Sopenharmony_ci		struct exynos_drm_ipp_task *task = ctx->task;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci		ctx->task = NULL;
97062306a36Sopenharmony_ci		pm_runtime_mark_last_busy(ctx->dev);
97162306a36Sopenharmony_ci		pm_runtime_put_autosuspend(ctx->dev);
97262306a36Sopenharmony_ci		exynos_drm_ipp_task_done(task, 0);
97362306a36Sopenharmony_ci	}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	fimc_dst_set_buf_seq(ctx, buf_id, false);
97662306a36Sopenharmony_ci	fimc_stop(ctx);
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	return IRQ_HANDLED;
97962306a36Sopenharmony_ci}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_cistatic void fimc_clear_addr(struct fimc_context *ctx)
98262306a36Sopenharmony_ci{
98362306a36Sopenharmony_ci	int i;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	for (i = 0; i < FIMC_MAX_SRC; i++) {
98662306a36Sopenharmony_ci		fimc_write(ctx, 0, EXYNOS_CIIYSA(i));
98762306a36Sopenharmony_ci		fimc_write(ctx, 0, EXYNOS_CIICBSA(i));
98862306a36Sopenharmony_ci		fimc_write(ctx, 0, EXYNOS_CIICRSA(i));
98962306a36Sopenharmony_ci	}
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	for (i = 0; i < FIMC_MAX_DST; i++) {
99262306a36Sopenharmony_ci		fimc_write(ctx, 0, EXYNOS_CIOYSA(i));
99362306a36Sopenharmony_ci		fimc_write(ctx, 0, EXYNOS_CIOCBSA(i));
99462306a36Sopenharmony_ci		fimc_write(ctx, 0, EXYNOS_CIOCRSA(i));
99562306a36Sopenharmony_ci	}
99662306a36Sopenharmony_ci}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_cistatic void fimc_reset(struct fimc_context *ctx)
99962306a36Sopenharmony_ci{
100062306a36Sopenharmony_ci	/* reset h/w block */
100162306a36Sopenharmony_ci	fimc_sw_reset(ctx);
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	/* reset scaler capability */
100462306a36Sopenharmony_ci	memset(&ctx->sc, 0x0, sizeof(ctx->sc));
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	fimc_clear_addr(ctx);
100762306a36Sopenharmony_ci}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_cistatic void fimc_start(struct fimc_context *ctx)
101062306a36Sopenharmony_ci{
101162306a36Sopenharmony_ci	u32 cfg0, cfg1;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	fimc_mask_irq(ctx, true);
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	/* If set true, we can save jpeg about screen */
101662306a36Sopenharmony_ci	fimc_handle_jpeg(ctx, false);
101762306a36Sopenharmony_ci	fimc_set_scaler(ctx, &ctx->sc);
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	fimc_set_type_ctrl(ctx);
102062306a36Sopenharmony_ci	fimc_handle_lastend(ctx, false);
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	/* setup dma */
102362306a36Sopenharmony_ci	cfg0 = fimc_read(ctx, EXYNOS_MSCTRL);
102462306a36Sopenharmony_ci	cfg0 &= ~EXYNOS_MSCTRL_INPUT_MASK;
102562306a36Sopenharmony_ci	cfg0 |= EXYNOS_MSCTRL_INPUT_MEMORY;
102662306a36Sopenharmony_ci	fimc_write(ctx, cfg0, EXYNOS_MSCTRL);
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	/* Reset status */
102962306a36Sopenharmony_ci	fimc_write(ctx, 0x0, EXYNOS_CISTATUS);
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	cfg0 = fimc_read(ctx, EXYNOS_CIIMGCPT);
103262306a36Sopenharmony_ci	cfg0 &= ~EXYNOS_CIIMGCPT_IMGCPTEN_SC;
103362306a36Sopenharmony_ci	cfg0 |= EXYNOS_CIIMGCPT_IMGCPTEN_SC;
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	/* Scaler */
103662306a36Sopenharmony_ci	cfg1 = fimc_read(ctx, EXYNOS_CISCCTRL);
103762306a36Sopenharmony_ci	cfg1 &= ~EXYNOS_CISCCTRL_SCAN_MASK;
103862306a36Sopenharmony_ci	cfg1 |= (EXYNOS_CISCCTRL_PROGRESSIVE |
103962306a36Sopenharmony_ci		EXYNOS_CISCCTRL_SCALERSTART);
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	fimc_write(ctx, cfg1, EXYNOS_CISCCTRL);
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	/* Enable image capture*/
104462306a36Sopenharmony_ci	cfg0 |= EXYNOS_CIIMGCPT_IMGCPTEN;
104562306a36Sopenharmony_ci	fimc_write(ctx, cfg0, EXYNOS_CIIMGCPT);
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	/* Disable frame end irq */
104862306a36Sopenharmony_ci	fimc_clear_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_IRQ_END_DISABLE);
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	fimc_clear_bits(ctx, EXYNOS_CIOCTRL, EXYNOS_CIOCTRL_WEAVE_MASK);
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	fimc_set_bits(ctx, EXYNOS_MSCTRL, EXYNOS_MSCTRL_ENVID);
105362306a36Sopenharmony_ci}
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_cistatic void fimc_stop(struct fimc_context *ctx)
105662306a36Sopenharmony_ci{
105762306a36Sopenharmony_ci	u32 cfg;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	/* Source clear */
106062306a36Sopenharmony_ci	cfg = fimc_read(ctx, EXYNOS_MSCTRL);
106162306a36Sopenharmony_ci	cfg &= ~EXYNOS_MSCTRL_INPUT_MASK;
106262306a36Sopenharmony_ci	cfg &= ~EXYNOS_MSCTRL_ENVID;
106362306a36Sopenharmony_ci	fimc_write(ctx, cfg, EXYNOS_MSCTRL);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	fimc_mask_irq(ctx, false);
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	/* reset sequence */
106862306a36Sopenharmony_ci	fimc_write(ctx, 0x0, EXYNOS_CIFCNTSEQ);
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	/* Scaler disable */
107162306a36Sopenharmony_ci	fimc_clear_bits(ctx, EXYNOS_CISCCTRL, EXYNOS_CISCCTRL_SCALERSTART);
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	/* Disable image capture */
107462306a36Sopenharmony_ci	fimc_clear_bits(ctx, EXYNOS_CIIMGCPT,
107562306a36Sopenharmony_ci		EXYNOS_CIIMGCPT_IMGCPTEN_SC | EXYNOS_CIIMGCPT_IMGCPTEN);
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	/* Enable frame end irq */
107862306a36Sopenharmony_ci	fimc_set_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_IRQ_END_DISABLE);
107962306a36Sopenharmony_ci}
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_cistatic int fimc_commit(struct exynos_drm_ipp *ipp,
108262306a36Sopenharmony_ci			  struct exynos_drm_ipp_task *task)
108362306a36Sopenharmony_ci{
108462306a36Sopenharmony_ci	struct fimc_context *ctx =
108562306a36Sopenharmony_ci			container_of(ipp, struct fimc_context, ipp);
108662306a36Sopenharmony_ci	int ret;
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(ctx->dev);
108962306a36Sopenharmony_ci	if (ret < 0) {
109062306a36Sopenharmony_ci		dev_err(ctx->dev, "failed to enable FIMC device.\n");
109162306a36Sopenharmony_ci		return ret;
109262306a36Sopenharmony_ci	}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	ctx->task = task;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	fimc_src_set_fmt(ctx, task->src.buf.fourcc, task->src.buf.modifier);
109762306a36Sopenharmony_ci	fimc_src_set_size(ctx, &task->src);
109862306a36Sopenharmony_ci	fimc_src_set_transf(ctx, DRM_MODE_ROTATE_0);
109962306a36Sopenharmony_ci	fimc_src_set_addr(ctx, &task->src);
110062306a36Sopenharmony_ci	fimc_dst_set_fmt(ctx, task->dst.buf.fourcc, task->dst.buf.modifier);
110162306a36Sopenharmony_ci	fimc_dst_set_transf(ctx, task->transform.rotation);
110262306a36Sopenharmony_ci	fimc_dst_set_size(ctx, &task->dst);
110362306a36Sopenharmony_ci	fimc_dst_set_addr(ctx, &task->dst);
110462306a36Sopenharmony_ci	fimc_set_prescaler(ctx, &ctx->sc, &task->src.rect, &task->dst.rect);
110562306a36Sopenharmony_ci	fimc_start(ctx);
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	return 0;
110862306a36Sopenharmony_ci}
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_cistatic void fimc_abort(struct exynos_drm_ipp *ipp,
111162306a36Sopenharmony_ci			  struct exynos_drm_ipp_task *task)
111262306a36Sopenharmony_ci{
111362306a36Sopenharmony_ci	struct fimc_context *ctx =
111462306a36Sopenharmony_ci			container_of(ipp, struct fimc_context, ipp);
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	fimc_reset(ctx);
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	if (ctx->task) {
111962306a36Sopenharmony_ci		struct exynos_drm_ipp_task *task = ctx->task;
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci		ctx->task = NULL;
112262306a36Sopenharmony_ci		pm_runtime_mark_last_busy(ctx->dev);
112362306a36Sopenharmony_ci		pm_runtime_put_autosuspend(ctx->dev);
112462306a36Sopenharmony_ci		exynos_drm_ipp_task_done(task, -EIO);
112562306a36Sopenharmony_ci	}
112662306a36Sopenharmony_ci}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_cistatic struct exynos_drm_ipp_funcs ipp_funcs = {
112962306a36Sopenharmony_ci	.commit = fimc_commit,
113062306a36Sopenharmony_ci	.abort = fimc_abort,
113162306a36Sopenharmony_ci};
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_cistatic int fimc_bind(struct device *dev, struct device *master, void *data)
113462306a36Sopenharmony_ci{
113562306a36Sopenharmony_ci	struct fimc_context *ctx = dev_get_drvdata(dev);
113662306a36Sopenharmony_ci	struct drm_device *drm_dev = data;
113762306a36Sopenharmony_ci	struct exynos_drm_ipp *ipp = &ctx->ipp;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	ctx->drm_dev = drm_dev;
114062306a36Sopenharmony_ci	ipp->drm_dev = drm_dev;
114162306a36Sopenharmony_ci	exynos_drm_register_dma(drm_dev, dev, &ctx->dma_priv);
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	exynos_drm_ipp_register(dev, ipp, &ipp_funcs,
114462306a36Sopenharmony_ci			DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |
114562306a36Sopenharmony_ci			DRM_EXYNOS_IPP_CAP_SCALE | DRM_EXYNOS_IPP_CAP_CONVERT,
114662306a36Sopenharmony_ci			ctx->formats, ctx->num_formats, "fimc");
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	dev_info(dev, "The exynos fimc has been probed successfully\n");
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	return 0;
115162306a36Sopenharmony_ci}
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_cistatic void fimc_unbind(struct device *dev, struct device *master,
115462306a36Sopenharmony_ci			void *data)
115562306a36Sopenharmony_ci{
115662306a36Sopenharmony_ci	struct fimc_context *ctx = dev_get_drvdata(dev);
115762306a36Sopenharmony_ci	struct drm_device *drm_dev = data;
115862306a36Sopenharmony_ci	struct exynos_drm_ipp *ipp = &ctx->ipp;
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	exynos_drm_ipp_unregister(dev, ipp);
116162306a36Sopenharmony_ci	exynos_drm_unregister_dma(drm_dev, dev, &ctx->dma_priv);
116262306a36Sopenharmony_ci}
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_cistatic const struct component_ops fimc_component_ops = {
116562306a36Sopenharmony_ci	.bind	= fimc_bind,
116662306a36Sopenharmony_ci	.unbind = fimc_unbind,
116762306a36Sopenharmony_ci};
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_cistatic void fimc_put_clocks(struct fimc_context *ctx)
117062306a36Sopenharmony_ci{
117162306a36Sopenharmony_ci	int i;
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	for (i = 0; i < FIMC_CLKS_MAX; i++) {
117462306a36Sopenharmony_ci		if (IS_ERR(ctx->clocks[i]))
117562306a36Sopenharmony_ci			continue;
117662306a36Sopenharmony_ci		clk_put(ctx->clocks[i]);
117762306a36Sopenharmony_ci		ctx->clocks[i] = ERR_PTR(-EINVAL);
117862306a36Sopenharmony_ci	}
117962306a36Sopenharmony_ci}
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_cistatic int fimc_setup_clocks(struct fimc_context *ctx)
118262306a36Sopenharmony_ci{
118362306a36Sopenharmony_ci	struct device *fimc_dev = ctx->dev;
118462306a36Sopenharmony_ci	struct device *dev;
118562306a36Sopenharmony_ci	int ret, i;
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	for (i = 0; i < FIMC_CLKS_MAX; i++)
118862306a36Sopenharmony_ci		ctx->clocks[i] = ERR_PTR(-EINVAL);
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	for (i = 0; i < FIMC_CLKS_MAX; i++) {
119162306a36Sopenharmony_ci		if (i == FIMC_CLK_WB_A || i == FIMC_CLK_WB_B)
119262306a36Sopenharmony_ci			dev = fimc_dev->parent;
119362306a36Sopenharmony_ci		else
119462306a36Sopenharmony_ci			dev = fimc_dev;
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci		ctx->clocks[i] = clk_get(dev, fimc_clock_names[i]);
119762306a36Sopenharmony_ci		if (IS_ERR(ctx->clocks[i])) {
119862306a36Sopenharmony_ci			ret = PTR_ERR(ctx->clocks[i]);
119962306a36Sopenharmony_ci			dev_err(fimc_dev, "failed to get clock: %s\n",
120062306a36Sopenharmony_ci						fimc_clock_names[i]);
120162306a36Sopenharmony_ci			goto e_clk_free;
120262306a36Sopenharmony_ci		}
120362306a36Sopenharmony_ci	}
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	ret = clk_prepare_enable(ctx->clocks[FIMC_CLK_LCLK]);
120662306a36Sopenharmony_ci	if (!ret)
120762306a36Sopenharmony_ci		return ret;
120862306a36Sopenharmony_cie_clk_free:
120962306a36Sopenharmony_ci	fimc_put_clocks(ctx);
121062306a36Sopenharmony_ci	return ret;
121162306a36Sopenharmony_ci}
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ciint exynos_drm_check_fimc_device(struct device *dev)
121462306a36Sopenharmony_ci{
121562306a36Sopenharmony_ci	int id = of_alias_get_id(dev->of_node, "fimc");
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	if (id >= 0 && (BIT(id) & fimc_mask))
121862306a36Sopenharmony_ci		return 0;
121962306a36Sopenharmony_ci	return -ENODEV;
122062306a36Sopenharmony_ci}
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_cistatic const unsigned int fimc_formats[] = {
122362306a36Sopenharmony_ci	DRM_FORMAT_XRGB8888, DRM_FORMAT_RGB565,
122462306a36Sopenharmony_ci	DRM_FORMAT_NV12, DRM_FORMAT_NV16, DRM_FORMAT_NV21, DRM_FORMAT_NV61,
122562306a36Sopenharmony_ci	DRM_FORMAT_UYVY, DRM_FORMAT_VYUY, DRM_FORMAT_YUYV, DRM_FORMAT_YVYU,
122662306a36Sopenharmony_ci	DRM_FORMAT_YUV420, DRM_FORMAT_YVU420, DRM_FORMAT_YUV422,
122762306a36Sopenharmony_ci	DRM_FORMAT_YUV444,
122862306a36Sopenharmony_ci};
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_cistatic const unsigned int fimc_tiled_formats[] = {
123162306a36Sopenharmony_ci	DRM_FORMAT_NV12, DRM_FORMAT_NV21,
123262306a36Sopenharmony_ci};
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_cistatic const struct drm_exynos_ipp_limit fimc_4210_limits_v1[] = {
123562306a36Sopenharmony_ci	{ IPP_SIZE_LIMIT(BUFFER, .h = { 16, 8192, 8 }, .v = { 16, 8192, 2 }) },
123662306a36Sopenharmony_ci	{ IPP_SIZE_LIMIT(AREA, .h = { 16, 4224, 2 }, .v = { 16, 0, 2 }) },
123762306a36Sopenharmony_ci	{ IPP_SIZE_LIMIT(ROTATED, .h = { 128, 1920 }, .v = { 128, 0 }) },
123862306a36Sopenharmony_ci	{ IPP_SCALE_LIMIT(.h = { (1 << 16) / 64, (1 << 16) * 64 },
123962306a36Sopenharmony_ci			  .v = { (1 << 16) / 64, (1 << 16) * 64 }) },
124062306a36Sopenharmony_ci};
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_cistatic const struct drm_exynos_ipp_limit fimc_4210_limits_v2[] = {
124362306a36Sopenharmony_ci	{ IPP_SIZE_LIMIT(BUFFER, .h = { 16, 8192, 8 }, .v = { 16, 8192, 2 }) },
124462306a36Sopenharmony_ci	{ IPP_SIZE_LIMIT(AREA, .h = { 16, 1920, 2 }, .v = { 16, 0, 2 }) },
124562306a36Sopenharmony_ci	{ IPP_SIZE_LIMIT(ROTATED, .h = { 128, 1366 }, .v = { 128, 0 }) },
124662306a36Sopenharmony_ci	{ IPP_SCALE_LIMIT(.h = { (1 << 16) / 64, (1 << 16) * 64 },
124762306a36Sopenharmony_ci			  .v = { (1 << 16) / 64, (1 << 16) * 64 }) },
124862306a36Sopenharmony_ci};
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_cistatic const struct drm_exynos_ipp_limit fimc_4210_limits_tiled_v1[] = {
125162306a36Sopenharmony_ci	{ IPP_SIZE_LIMIT(BUFFER, .h = { 128, 1920, 128 }, .v = { 32, 1920, 32 }) },
125262306a36Sopenharmony_ci	{ IPP_SIZE_LIMIT(AREA, .h = { 128, 1920, 2 }, .v = { 128, 0, 2 }) },
125362306a36Sopenharmony_ci	{ IPP_SCALE_LIMIT(.h = { (1 << 16) / 64, (1 << 16) * 64 },
125462306a36Sopenharmony_ci			  .v = { (1 << 16) / 64, (1 << 16) * 64 }) },
125562306a36Sopenharmony_ci};
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_cistatic const struct drm_exynos_ipp_limit fimc_4210_limits_tiled_v2[] = {
125862306a36Sopenharmony_ci	{ IPP_SIZE_LIMIT(BUFFER, .h = { 128, 1920, 128 }, .v = { 32, 1920, 32 }) },
125962306a36Sopenharmony_ci	{ IPP_SIZE_LIMIT(AREA, .h = { 128, 1366, 2 }, .v = { 128, 0, 2 }) },
126062306a36Sopenharmony_ci	{ IPP_SCALE_LIMIT(.h = { (1 << 16) / 64, (1 << 16) * 64 },
126162306a36Sopenharmony_ci			  .v = { (1 << 16) / 64, (1 << 16) * 64 }) },
126262306a36Sopenharmony_ci};
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_cistatic int fimc_probe(struct platform_device *pdev)
126562306a36Sopenharmony_ci{
126662306a36Sopenharmony_ci	const struct drm_exynos_ipp_limit *limits;
126762306a36Sopenharmony_ci	struct exynos_drm_ipp_formats *formats;
126862306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
126962306a36Sopenharmony_ci	struct fimc_context *ctx;
127062306a36Sopenharmony_ci	int ret;
127162306a36Sopenharmony_ci	int i, j, num_limits, num_formats;
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	if (exynos_drm_check_fimc_device(dev) != 0)
127462306a36Sopenharmony_ci		return -ENODEV;
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
127762306a36Sopenharmony_ci	if (!ctx)
127862306a36Sopenharmony_ci		return -ENOMEM;
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	ctx->dev = dev;
128162306a36Sopenharmony_ci	ctx->id = of_alias_get_id(dev->of_node, "fimc");
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	/* construct formats/limits array */
128462306a36Sopenharmony_ci	num_formats = ARRAY_SIZE(fimc_formats) + ARRAY_SIZE(fimc_tiled_formats);
128562306a36Sopenharmony_ci	formats = devm_kcalloc(dev, num_formats, sizeof(*formats),
128662306a36Sopenharmony_ci			       GFP_KERNEL);
128762306a36Sopenharmony_ci	if (!formats)
128862306a36Sopenharmony_ci		return -ENOMEM;
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	/* linear formats */
129162306a36Sopenharmony_ci	if (ctx->id < 3) {
129262306a36Sopenharmony_ci		limits = fimc_4210_limits_v1;
129362306a36Sopenharmony_ci		num_limits = ARRAY_SIZE(fimc_4210_limits_v1);
129462306a36Sopenharmony_ci	} else {
129562306a36Sopenharmony_ci		limits = fimc_4210_limits_v2;
129662306a36Sopenharmony_ci		num_limits = ARRAY_SIZE(fimc_4210_limits_v2);
129762306a36Sopenharmony_ci	}
129862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(fimc_formats); i++) {
129962306a36Sopenharmony_ci		formats[i].fourcc = fimc_formats[i];
130062306a36Sopenharmony_ci		formats[i].type = DRM_EXYNOS_IPP_FORMAT_SOURCE |
130162306a36Sopenharmony_ci				  DRM_EXYNOS_IPP_FORMAT_DESTINATION;
130262306a36Sopenharmony_ci		formats[i].limits = limits;
130362306a36Sopenharmony_ci		formats[i].num_limits = num_limits;
130462306a36Sopenharmony_ci	}
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	/* tiled formats */
130762306a36Sopenharmony_ci	if (ctx->id < 3) {
130862306a36Sopenharmony_ci		limits = fimc_4210_limits_tiled_v1;
130962306a36Sopenharmony_ci		num_limits = ARRAY_SIZE(fimc_4210_limits_tiled_v1);
131062306a36Sopenharmony_ci	} else {
131162306a36Sopenharmony_ci		limits = fimc_4210_limits_tiled_v2;
131262306a36Sopenharmony_ci		num_limits = ARRAY_SIZE(fimc_4210_limits_tiled_v2);
131362306a36Sopenharmony_ci	}
131462306a36Sopenharmony_ci	for (j = i, i = 0; i < ARRAY_SIZE(fimc_tiled_formats); j++, i++) {
131562306a36Sopenharmony_ci		formats[j].fourcc = fimc_tiled_formats[i];
131662306a36Sopenharmony_ci		formats[j].modifier = DRM_FORMAT_MOD_SAMSUNG_64_32_TILE;
131762306a36Sopenharmony_ci		formats[j].type = DRM_EXYNOS_IPP_FORMAT_SOURCE |
131862306a36Sopenharmony_ci				  DRM_EXYNOS_IPP_FORMAT_DESTINATION;
131962306a36Sopenharmony_ci		formats[j].limits = limits;
132062306a36Sopenharmony_ci		formats[j].num_limits = num_limits;
132162306a36Sopenharmony_ci	}
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	ctx->formats = formats;
132462306a36Sopenharmony_ci	ctx->num_formats = num_formats;
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	/* resource memory */
132762306a36Sopenharmony_ci	ctx->regs = devm_platform_ioremap_resource(pdev, 0);
132862306a36Sopenharmony_ci	if (IS_ERR(ctx->regs))
132962306a36Sopenharmony_ci		return PTR_ERR(ctx->regs);
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	/* resource irq */
133262306a36Sopenharmony_ci	ret = platform_get_irq(pdev, 0);
133362306a36Sopenharmony_ci	if (ret < 0)
133462306a36Sopenharmony_ci		return ret;
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	ret = devm_request_irq(dev, ret, fimc_irq_handler,
133762306a36Sopenharmony_ci			       0, dev_name(dev), ctx);
133862306a36Sopenharmony_ci	if (ret < 0) {
133962306a36Sopenharmony_ci		dev_err(dev, "failed to request irq.\n");
134062306a36Sopenharmony_ci		return ret;
134162306a36Sopenharmony_ci	}
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	ret = fimc_setup_clocks(ctx);
134462306a36Sopenharmony_ci	if (ret < 0)
134562306a36Sopenharmony_ci		return ret;
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	spin_lock_init(&ctx->lock);
134862306a36Sopenharmony_ci	platform_set_drvdata(pdev, ctx);
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	pm_runtime_use_autosuspend(dev);
135162306a36Sopenharmony_ci	pm_runtime_set_autosuspend_delay(dev, FIMC_AUTOSUSPEND_DELAY);
135262306a36Sopenharmony_ci	pm_runtime_enable(dev);
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	ret = component_add(dev, &fimc_component_ops);
135562306a36Sopenharmony_ci	if (ret)
135662306a36Sopenharmony_ci		goto err_pm_dis;
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	dev_info(dev, "drm fimc registered successfully.\n");
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	return 0;
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_cierr_pm_dis:
136362306a36Sopenharmony_ci	pm_runtime_dont_use_autosuspend(dev);
136462306a36Sopenharmony_ci	pm_runtime_disable(dev);
136562306a36Sopenharmony_ci	fimc_put_clocks(ctx);
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	return ret;
136862306a36Sopenharmony_ci}
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_cistatic int fimc_remove(struct platform_device *pdev)
137162306a36Sopenharmony_ci{
137262306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
137362306a36Sopenharmony_ci	struct fimc_context *ctx = get_fimc_context(dev);
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	component_del(dev, &fimc_component_ops);
137662306a36Sopenharmony_ci	pm_runtime_dont_use_autosuspend(dev);
137762306a36Sopenharmony_ci	pm_runtime_disable(dev);
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	fimc_put_clocks(ctx);
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	return 0;
138262306a36Sopenharmony_ci}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_cistatic int fimc_runtime_suspend(struct device *dev)
138562306a36Sopenharmony_ci{
138662306a36Sopenharmony_ci	struct fimc_context *ctx = get_fimc_context(dev);
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(dev, "id[%d]\n", ctx->id);
138962306a36Sopenharmony_ci	clk_disable_unprepare(ctx->clocks[FIMC_CLK_GATE]);
139062306a36Sopenharmony_ci	return 0;
139162306a36Sopenharmony_ci}
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_cistatic int fimc_runtime_resume(struct device *dev)
139462306a36Sopenharmony_ci{
139562306a36Sopenharmony_ci	struct fimc_context *ctx = get_fimc_context(dev);
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(dev, "id[%d]\n", ctx->id);
139862306a36Sopenharmony_ci	return clk_prepare_enable(ctx->clocks[FIMC_CLK_GATE]);
139962306a36Sopenharmony_ci}
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_cistatic DEFINE_RUNTIME_DEV_PM_OPS(fimc_pm_ops, fimc_runtime_suspend,
140262306a36Sopenharmony_ci				 fimc_runtime_resume, NULL);
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_cistatic const struct of_device_id fimc_of_match[] = {
140562306a36Sopenharmony_ci	{ .compatible = "samsung,exynos4210-fimc" },
140662306a36Sopenharmony_ci	{ .compatible = "samsung,exynos4212-fimc" },
140762306a36Sopenharmony_ci	{ },
140862306a36Sopenharmony_ci};
140962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, fimc_of_match);
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_cistruct platform_driver fimc_driver = {
141262306a36Sopenharmony_ci	.probe		= fimc_probe,
141362306a36Sopenharmony_ci	.remove		= fimc_remove,
141462306a36Sopenharmony_ci	.driver		= {
141562306a36Sopenharmony_ci		.of_match_table = fimc_of_match,
141662306a36Sopenharmony_ci		.name	= "exynos-drm-fimc",
141762306a36Sopenharmony_ci		.owner	= THIS_MODULE,
141862306a36Sopenharmony_ci		.pm	= pm_ptr(&fimc_pm_ops),
141962306a36Sopenharmony_ci	},
142062306a36Sopenharmony_ci};
1421