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_device.h>
1562306a36Sopenharmony_ci#include <linux/platform_device.h>
1662306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1762306a36Sopenharmony_ci#include <linux/regmap.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <drm/drm_fourcc.h>
2062306a36Sopenharmony_ci#include <drm/drm_print.h>
2162306a36Sopenharmony_ci#include <drm/exynos_drm.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "exynos_drm_drv.h"
2462306a36Sopenharmony_ci#include "exynos_drm_ipp.h"
2562306a36Sopenharmony_ci#include "regs-gsc.h"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/*
2862306a36Sopenharmony_ci * GSC stands for General SCaler and
2962306a36Sopenharmony_ci * supports image scaler/rotator and input/output DMA operations.
3062306a36Sopenharmony_ci * input DMA reads image data from the memory.
3162306a36Sopenharmony_ci * output DMA writes image data to memory.
3262306a36Sopenharmony_ci * GSC supports image rotation and image effect functions.
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define GSC_MAX_CLOCKS	8
3762306a36Sopenharmony_ci#define GSC_MAX_SRC		4
3862306a36Sopenharmony_ci#define GSC_MAX_DST		16
3962306a36Sopenharmony_ci#define GSC_RESET_TIMEOUT	50
4062306a36Sopenharmony_ci#define GSC_BUF_STOP	1
4162306a36Sopenharmony_ci#define GSC_BUF_START	2
4262306a36Sopenharmony_ci#define GSC_REG_SZ		16
4362306a36Sopenharmony_ci#define GSC_WIDTH_ITU_709	1280
4462306a36Sopenharmony_ci#define GSC_SC_UP_MAX_RATIO		65536
4562306a36Sopenharmony_ci#define GSC_SC_DOWN_RATIO_7_8		74898
4662306a36Sopenharmony_ci#define GSC_SC_DOWN_RATIO_6_8		87381
4762306a36Sopenharmony_ci#define GSC_SC_DOWN_RATIO_5_8		104857
4862306a36Sopenharmony_ci#define GSC_SC_DOWN_RATIO_4_8		131072
4962306a36Sopenharmony_ci#define GSC_SC_DOWN_RATIO_3_8		174762
5062306a36Sopenharmony_ci#define GSC_SC_DOWN_RATIO_2_8		262144
5162306a36Sopenharmony_ci#define GSC_CROP_MAX	8192
5262306a36Sopenharmony_ci#define GSC_CROP_MIN	32
5362306a36Sopenharmony_ci#define GSC_SCALE_MAX	4224
5462306a36Sopenharmony_ci#define GSC_SCALE_MIN	32
5562306a36Sopenharmony_ci#define GSC_COEF_RATIO	7
5662306a36Sopenharmony_ci#define GSC_COEF_PHASE	9
5762306a36Sopenharmony_ci#define GSC_COEF_ATTR	16
5862306a36Sopenharmony_ci#define GSC_COEF_H_8T	8
5962306a36Sopenharmony_ci#define GSC_COEF_V_4T	4
6062306a36Sopenharmony_ci#define GSC_COEF_DEPTH	3
6162306a36Sopenharmony_ci#define GSC_AUTOSUSPEND_DELAY		2000
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define get_gsc_context(dev)	dev_get_drvdata(dev)
6462306a36Sopenharmony_ci#define gsc_read(offset)		readl(ctx->regs + (offset))
6562306a36Sopenharmony_ci#define gsc_write(cfg, offset)	writel(cfg, ctx->regs + (offset))
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/*
6862306a36Sopenharmony_ci * A structure of scaler.
6962306a36Sopenharmony_ci *
7062306a36Sopenharmony_ci * @range: narrow, wide.
7162306a36Sopenharmony_ci * @pre_shfactor: pre sclaer shift factor.
7262306a36Sopenharmony_ci * @pre_hratio: horizontal ratio of the prescaler.
7362306a36Sopenharmony_ci * @pre_vratio: vertical ratio of the prescaler.
7462306a36Sopenharmony_ci * @main_hratio: the main scaler's horizontal ratio.
7562306a36Sopenharmony_ci * @main_vratio: the main scaler's vertical ratio.
7662306a36Sopenharmony_ci */
7762306a36Sopenharmony_cistruct gsc_scaler {
7862306a36Sopenharmony_ci	bool	range;
7962306a36Sopenharmony_ci	u32	pre_shfactor;
8062306a36Sopenharmony_ci	u32	pre_hratio;
8162306a36Sopenharmony_ci	u32	pre_vratio;
8262306a36Sopenharmony_ci	unsigned long main_hratio;
8362306a36Sopenharmony_ci	unsigned long main_vratio;
8462306a36Sopenharmony_ci};
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci/*
8762306a36Sopenharmony_ci * A structure of gsc context.
8862306a36Sopenharmony_ci *
8962306a36Sopenharmony_ci * @regs: memory mapped io registers.
9062306a36Sopenharmony_ci * @gsc_clk: gsc gate clock.
9162306a36Sopenharmony_ci * @sc: scaler infomations.
9262306a36Sopenharmony_ci * @id: gsc id.
9362306a36Sopenharmony_ci * @irq: irq number.
9462306a36Sopenharmony_ci * @rotation: supports rotation of src.
9562306a36Sopenharmony_ci */
9662306a36Sopenharmony_cistruct gsc_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	const char	**clk_names;
10762306a36Sopenharmony_ci	struct clk	*clocks[GSC_MAX_CLOCKS];
10862306a36Sopenharmony_ci	int		num_clocks;
10962306a36Sopenharmony_ci	struct gsc_scaler	sc;
11062306a36Sopenharmony_ci	int	id;
11162306a36Sopenharmony_ci	int	irq;
11262306a36Sopenharmony_ci	bool	rotation;
11362306a36Sopenharmony_ci};
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci/**
11662306a36Sopenharmony_ci * struct gsc_driverdata - per device type driver data for init time.
11762306a36Sopenharmony_ci *
11862306a36Sopenharmony_ci * @limits: picture size limits array
11962306a36Sopenharmony_ci * @num_limits: number of items in the aforementioned array
12062306a36Sopenharmony_ci * @clk_names: names of clocks needed by this variant
12162306a36Sopenharmony_ci * @num_clocks: the number of clocks needed by this variant
12262306a36Sopenharmony_ci */
12362306a36Sopenharmony_cistruct gsc_driverdata {
12462306a36Sopenharmony_ci	const struct drm_exynos_ipp_limit *limits;
12562306a36Sopenharmony_ci	int		num_limits;
12662306a36Sopenharmony_ci	const char	*clk_names[GSC_MAX_CLOCKS];
12762306a36Sopenharmony_ci	int		num_clocks;
12862306a36Sopenharmony_ci};
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci/* 8-tap Filter Coefficient */
13162306a36Sopenharmony_cistatic const int h_coef_8t[GSC_COEF_RATIO][GSC_COEF_ATTR][GSC_COEF_H_8T] = {
13262306a36Sopenharmony_ci	{	/* Ratio <= 65536 (~8:8) */
13362306a36Sopenharmony_ci		{  0,  0,   0, 128,   0,   0,  0,  0 },
13462306a36Sopenharmony_ci		{ -1,  2,  -6, 127,   7,  -2,  1,  0 },
13562306a36Sopenharmony_ci		{ -1,  4, -12, 125,  16,  -5,  1,  0 },
13662306a36Sopenharmony_ci		{ -1,  5, -15, 120,  25,  -8,  2,  0 },
13762306a36Sopenharmony_ci		{ -1,  6, -18, 114,  35, -10,  3, -1 },
13862306a36Sopenharmony_ci		{ -1,  6, -20, 107,  46, -13,  4, -1 },
13962306a36Sopenharmony_ci		{ -2,  7, -21,  99,  57, -16,  5, -1 },
14062306a36Sopenharmony_ci		{ -1,  6, -20,  89,  68, -18,  5, -1 },
14162306a36Sopenharmony_ci		{ -1,  6, -20,  79,  79, -20,  6, -1 },
14262306a36Sopenharmony_ci		{ -1,  5, -18,  68,  89, -20,  6, -1 },
14362306a36Sopenharmony_ci		{ -1,  5, -16,  57,  99, -21,  7, -2 },
14462306a36Sopenharmony_ci		{ -1,  4, -13,  46, 107, -20,  6, -1 },
14562306a36Sopenharmony_ci		{ -1,  3, -10,  35, 114, -18,  6, -1 },
14662306a36Sopenharmony_ci		{  0,  2,  -8,  25, 120, -15,  5, -1 },
14762306a36Sopenharmony_ci		{  0,  1,  -5,  16, 125, -12,  4, -1 },
14862306a36Sopenharmony_ci		{  0,  1,  -2,   7, 127,  -6,  2, -1 }
14962306a36Sopenharmony_ci	}, {	/* 65536 < Ratio <= 74898 (~8:7) */
15062306a36Sopenharmony_ci		{  3, -8,  14, 111,  13,  -8,  3,  0 },
15162306a36Sopenharmony_ci		{  2, -6,   7, 112,  21, -10,  3, -1 },
15262306a36Sopenharmony_ci		{  2, -4,   1, 110,  28, -12,  4, -1 },
15362306a36Sopenharmony_ci		{  1, -2,  -3, 106,  36, -13,  4, -1 },
15462306a36Sopenharmony_ci		{  1, -1,  -7, 103,  44, -15,  4, -1 },
15562306a36Sopenharmony_ci		{  1,  1, -11,  97,  53, -16,  4, -1 },
15662306a36Sopenharmony_ci		{  0,  2, -13,  91,  61, -16,  4, -1 },
15762306a36Sopenharmony_ci		{  0,  3, -15,  85,  69, -17,  4, -1 },
15862306a36Sopenharmony_ci		{  0,  3, -16,  77,  77, -16,  3,  0 },
15962306a36Sopenharmony_ci		{ -1,  4, -17,  69,  85, -15,  3,  0 },
16062306a36Sopenharmony_ci		{ -1,  4, -16,  61,  91, -13,  2,  0 },
16162306a36Sopenharmony_ci		{ -1,  4, -16,  53,  97, -11,  1,  1 },
16262306a36Sopenharmony_ci		{ -1,  4, -15,  44, 103,  -7, -1,  1 },
16362306a36Sopenharmony_ci		{ -1,  4, -13,  36, 106,  -3, -2,  1 },
16462306a36Sopenharmony_ci		{ -1,  4, -12,  28, 110,   1, -4,  2 },
16562306a36Sopenharmony_ci		{ -1,  3, -10,  21, 112,   7, -6,  2 }
16662306a36Sopenharmony_ci	}, {	/* 74898 < Ratio <= 87381 (~8:6) */
16762306a36Sopenharmony_ci		{ 2, -11,  25,  96, 25, -11,   2,  0 },
16862306a36Sopenharmony_ci		{ 2, -10,  19,  96, 31, -12,   2,  0 },
16962306a36Sopenharmony_ci		{ 2,  -9,  14,  94, 37, -12,   2,  0 },
17062306a36Sopenharmony_ci		{ 2,  -8,  10,  92, 43, -12,   1,  0 },
17162306a36Sopenharmony_ci		{ 2,  -7,   5,  90, 49, -12,   1,  0 },
17262306a36Sopenharmony_ci		{ 2,  -5,   1,  86, 55, -12,   0,  1 },
17362306a36Sopenharmony_ci		{ 2,  -4,  -2,  82, 61, -11,  -1,  1 },
17462306a36Sopenharmony_ci		{ 1,  -3,  -5,  77, 67,  -9,  -1,  1 },
17562306a36Sopenharmony_ci		{ 1,  -2,  -7,  72, 72,  -7,  -2,  1 },
17662306a36Sopenharmony_ci		{ 1,  -1,  -9,  67, 77,  -5,  -3,  1 },
17762306a36Sopenharmony_ci		{ 1,  -1, -11,  61, 82,  -2,  -4,  2 },
17862306a36Sopenharmony_ci		{ 1,   0, -12,  55, 86,   1,  -5,  2 },
17962306a36Sopenharmony_ci		{ 0,   1, -12,  49, 90,   5,  -7,  2 },
18062306a36Sopenharmony_ci		{ 0,   1, -12,  43, 92,  10,  -8,  2 },
18162306a36Sopenharmony_ci		{ 0,   2, -12,  37, 94,  14,  -9,  2 },
18262306a36Sopenharmony_ci		{ 0,   2, -12,  31, 96,  19, -10,  2 }
18362306a36Sopenharmony_ci	}, {	/* 87381 < Ratio <= 104857 (~8:5) */
18462306a36Sopenharmony_ci		{ -1,  -8, 33,  80, 33,  -8,  -1,  0 },
18562306a36Sopenharmony_ci		{ -1,  -8, 28,  80, 37,  -7,  -2,  1 },
18662306a36Sopenharmony_ci		{  0,  -8, 24,  79, 41,  -7,  -2,  1 },
18762306a36Sopenharmony_ci		{  0,  -8, 20,  78, 46,  -6,  -3,  1 },
18862306a36Sopenharmony_ci		{  0,  -8, 16,  76, 50,  -4,  -3,  1 },
18962306a36Sopenharmony_ci		{  0,  -7, 13,  74, 54,  -3,  -4,  1 },
19062306a36Sopenharmony_ci		{  1,  -7, 10,  71, 58,  -1,  -5,  1 },
19162306a36Sopenharmony_ci		{  1,  -6,  6,  68, 62,   1,  -5,  1 },
19262306a36Sopenharmony_ci		{  1,  -6,  4,  65, 65,   4,  -6,  1 },
19362306a36Sopenharmony_ci		{  1,  -5,  1,  62, 68,   6,  -6,  1 },
19462306a36Sopenharmony_ci		{  1,  -5, -1,  58, 71,  10,  -7,  1 },
19562306a36Sopenharmony_ci		{  1,  -4, -3,  54, 74,  13,  -7,  0 },
19662306a36Sopenharmony_ci		{  1,  -3, -4,  50, 76,  16,  -8,  0 },
19762306a36Sopenharmony_ci		{  1,  -3, -6,  46, 78,  20,  -8,  0 },
19862306a36Sopenharmony_ci		{  1,  -2, -7,  41, 79,  24,  -8,  0 },
19962306a36Sopenharmony_ci		{  1,  -2, -7,  37, 80,  28,  -8, -1 }
20062306a36Sopenharmony_ci	}, {	/* 104857 < Ratio <= 131072 (~8:4) */
20162306a36Sopenharmony_ci		{ -3,   0, 35,  64, 35,   0,  -3,  0 },
20262306a36Sopenharmony_ci		{ -3,  -1, 32,  64, 38,   1,  -3,  0 },
20362306a36Sopenharmony_ci		{ -2,  -2, 29,  63, 41,   2,  -3,  0 },
20462306a36Sopenharmony_ci		{ -2,  -3, 27,  63, 43,   4,  -4,  0 },
20562306a36Sopenharmony_ci		{ -2,  -3, 24,  61, 46,   6,  -4,  0 },
20662306a36Sopenharmony_ci		{ -2,  -3, 21,  60, 49,   7,  -4,  0 },
20762306a36Sopenharmony_ci		{ -1,  -4, 19,  59, 51,   9,  -4, -1 },
20862306a36Sopenharmony_ci		{ -1,  -4, 16,  57, 53,  12,  -4, -1 },
20962306a36Sopenharmony_ci		{ -1,  -4, 14,  55, 55,  14,  -4, -1 },
21062306a36Sopenharmony_ci		{ -1,  -4, 12,  53, 57,  16,  -4, -1 },
21162306a36Sopenharmony_ci		{ -1,  -4,  9,  51, 59,  19,  -4, -1 },
21262306a36Sopenharmony_ci		{  0,  -4,  7,  49, 60,  21,  -3, -2 },
21362306a36Sopenharmony_ci		{  0,  -4,  6,  46, 61,  24,  -3, -2 },
21462306a36Sopenharmony_ci		{  0,  -4,  4,  43, 63,  27,  -3, -2 },
21562306a36Sopenharmony_ci		{  0,  -3,  2,  41, 63,  29,  -2, -2 },
21662306a36Sopenharmony_ci		{  0,  -3,  1,  38, 64,  32,  -1, -3 }
21762306a36Sopenharmony_ci	}, {	/* 131072 < Ratio <= 174762 (~8:3) */
21862306a36Sopenharmony_ci		{ -1,   8, 33,  48, 33,   8,  -1,  0 },
21962306a36Sopenharmony_ci		{ -1,   7, 31,  49, 35,   9,  -1, -1 },
22062306a36Sopenharmony_ci		{ -1,   6, 30,  49, 36,  10,  -1, -1 },
22162306a36Sopenharmony_ci		{ -1,   5, 28,  48, 38,  12,  -1, -1 },
22262306a36Sopenharmony_ci		{ -1,   4, 26,  48, 39,  13,   0, -1 },
22362306a36Sopenharmony_ci		{ -1,   3, 24,  47, 41,  15,   0, -1 },
22462306a36Sopenharmony_ci		{ -1,   2, 23,  47, 42,  16,   0, -1 },
22562306a36Sopenharmony_ci		{ -1,   2, 21,  45, 43,  18,   1, -1 },
22662306a36Sopenharmony_ci		{ -1,   1, 19,  45, 45,  19,   1, -1 },
22762306a36Sopenharmony_ci		{ -1,   1, 18,  43, 45,  21,   2, -1 },
22862306a36Sopenharmony_ci		{ -1,   0, 16,  42, 47,  23,   2, -1 },
22962306a36Sopenharmony_ci		{ -1,   0, 15,  41, 47,  24,   3, -1 },
23062306a36Sopenharmony_ci		{ -1,   0, 13,  39, 48,  26,   4, -1 },
23162306a36Sopenharmony_ci		{ -1,  -1, 12,  38, 48,  28,   5, -1 },
23262306a36Sopenharmony_ci		{ -1,  -1, 10,  36, 49,  30,   6, -1 },
23362306a36Sopenharmony_ci		{ -1,  -1,  9,  35, 49,  31,   7, -1 }
23462306a36Sopenharmony_ci	}, {	/* 174762 < Ratio <= 262144 (~8:2) */
23562306a36Sopenharmony_ci		{  2,  13, 30,  38, 30,  13,   2,  0 },
23662306a36Sopenharmony_ci		{  2,  12, 29,  38, 30,  14,   3,  0 },
23762306a36Sopenharmony_ci		{  2,  11, 28,  38, 31,  15,   3,  0 },
23862306a36Sopenharmony_ci		{  2,  10, 26,  38, 32,  16,   4,  0 },
23962306a36Sopenharmony_ci		{  1,  10, 26,  37, 33,  17,   4,  0 },
24062306a36Sopenharmony_ci		{  1,   9, 24,  37, 34,  18,   5,  0 },
24162306a36Sopenharmony_ci		{  1,   8, 24,  37, 34,  19,   5,  0 },
24262306a36Sopenharmony_ci		{  1,   7, 22,  36, 35,  20,   6,  1 },
24362306a36Sopenharmony_ci		{  1,   6, 21,  36, 36,  21,   6,  1 },
24462306a36Sopenharmony_ci		{  1,   6, 20,  35, 36,  22,   7,  1 },
24562306a36Sopenharmony_ci		{  0,   5, 19,  34, 37,  24,   8,  1 },
24662306a36Sopenharmony_ci		{  0,   5, 18,  34, 37,  24,   9,  1 },
24762306a36Sopenharmony_ci		{  0,   4, 17,  33, 37,  26,  10,  1 },
24862306a36Sopenharmony_ci		{  0,   4, 16,  32, 38,  26,  10,  2 },
24962306a36Sopenharmony_ci		{  0,   3, 15,  31, 38,  28,  11,  2 },
25062306a36Sopenharmony_ci		{  0,   3, 14,  30, 38,  29,  12,  2 }
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci};
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci/* 4-tap Filter Coefficient */
25562306a36Sopenharmony_cistatic const int v_coef_4t[GSC_COEF_RATIO][GSC_COEF_ATTR][GSC_COEF_V_4T] = {
25662306a36Sopenharmony_ci	{	/* Ratio <= 65536 (~8:8) */
25762306a36Sopenharmony_ci		{  0, 128,   0,  0 },
25862306a36Sopenharmony_ci		{ -4, 127,   5,  0 },
25962306a36Sopenharmony_ci		{ -6, 124,  11, -1 },
26062306a36Sopenharmony_ci		{ -8, 118,  19, -1 },
26162306a36Sopenharmony_ci		{ -8, 111,  27, -2 },
26262306a36Sopenharmony_ci		{ -8, 102,  37, -3 },
26362306a36Sopenharmony_ci		{ -8,  92,  48, -4 },
26462306a36Sopenharmony_ci		{ -7,  81,  59, -5 },
26562306a36Sopenharmony_ci		{ -6,  70,  70, -6 },
26662306a36Sopenharmony_ci		{ -5,  59,  81, -7 },
26762306a36Sopenharmony_ci		{ -4,  48,  92, -8 },
26862306a36Sopenharmony_ci		{ -3,  37, 102, -8 },
26962306a36Sopenharmony_ci		{ -2,  27, 111, -8 },
27062306a36Sopenharmony_ci		{ -1,  19, 118, -8 },
27162306a36Sopenharmony_ci		{ -1,  11, 124, -6 },
27262306a36Sopenharmony_ci		{  0,   5, 127, -4 }
27362306a36Sopenharmony_ci	}, {	/* 65536 < Ratio <= 74898 (~8:7) */
27462306a36Sopenharmony_ci		{  8, 112,   8,  0 },
27562306a36Sopenharmony_ci		{  4, 111,  14, -1 },
27662306a36Sopenharmony_ci		{  1, 109,  20, -2 },
27762306a36Sopenharmony_ci		{ -2, 105,  27, -2 },
27862306a36Sopenharmony_ci		{ -3, 100,  34, -3 },
27962306a36Sopenharmony_ci		{ -5,  93,  43, -3 },
28062306a36Sopenharmony_ci		{ -5,  86,  51, -4 },
28162306a36Sopenharmony_ci		{ -5,  77,  60, -4 },
28262306a36Sopenharmony_ci		{ -5,  69,  69, -5 },
28362306a36Sopenharmony_ci		{ -4,  60,  77, -5 },
28462306a36Sopenharmony_ci		{ -4,  51,  86, -5 },
28562306a36Sopenharmony_ci		{ -3,  43,  93, -5 },
28662306a36Sopenharmony_ci		{ -3,  34, 100, -3 },
28762306a36Sopenharmony_ci		{ -2,  27, 105, -2 },
28862306a36Sopenharmony_ci		{ -2,  20, 109,  1 },
28962306a36Sopenharmony_ci		{ -1,  14, 111,  4 }
29062306a36Sopenharmony_ci	}, {	/* 74898 < Ratio <= 87381 (~8:6) */
29162306a36Sopenharmony_ci		{ 16,  96,  16,  0 },
29262306a36Sopenharmony_ci		{ 12,  97,  21, -2 },
29362306a36Sopenharmony_ci		{  8,  96,  26, -2 },
29462306a36Sopenharmony_ci		{  5,  93,  32, -2 },
29562306a36Sopenharmony_ci		{  2,  89,  39, -2 },
29662306a36Sopenharmony_ci		{  0,  84,  46, -2 },
29762306a36Sopenharmony_ci		{ -1,  79,  53, -3 },
29862306a36Sopenharmony_ci		{ -2,  73,  59, -2 },
29962306a36Sopenharmony_ci		{ -2,  66,  66, -2 },
30062306a36Sopenharmony_ci		{ -2,  59,  73, -2 },
30162306a36Sopenharmony_ci		{ -3,  53,  79, -1 },
30262306a36Sopenharmony_ci		{ -2,  46,  84,  0 },
30362306a36Sopenharmony_ci		{ -2,  39,  89,  2 },
30462306a36Sopenharmony_ci		{ -2,  32,  93,  5 },
30562306a36Sopenharmony_ci		{ -2,  26,  96,  8 },
30662306a36Sopenharmony_ci		{ -2,  21,  97, 12 }
30762306a36Sopenharmony_ci	}, {	/* 87381 < Ratio <= 104857 (~8:5) */
30862306a36Sopenharmony_ci		{ 22,  84,  22,  0 },
30962306a36Sopenharmony_ci		{ 18,  85,  26, -1 },
31062306a36Sopenharmony_ci		{ 14,  84,  31, -1 },
31162306a36Sopenharmony_ci		{ 11,  82,  36, -1 },
31262306a36Sopenharmony_ci		{  8,  79,  42, -1 },
31362306a36Sopenharmony_ci		{  6,  76,  47, -1 },
31462306a36Sopenharmony_ci		{  4,  72,  52,  0 },
31562306a36Sopenharmony_ci		{  2,  68,  58,  0 },
31662306a36Sopenharmony_ci		{  1,  63,  63,  1 },
31762306a36Sopenharmony_ci		{  0,  58,  68,  2 },
31862306a36Sopenharmony_ci		{  0,  52,  72,  4 },
31962306a36Sopenharmony_ci		{ -1,  47,  76,  6 },
32062306a36Sopenharmony_ci		{ -1,  42,  79,  8 },
32162306a36Sopenharmony_ci		{ -1,  36,  82, 11 },
32262306a36Sopenharmony_ci		{ -1,  31,  84, 14 },
32362306a36Sopenharmony_ci		{ -1,  26,  85, 18 }
32462306a36Sopenharmony_ci	}, {	/* 104857 < Ratio <= 131072 (~8:4) */
32562306a36Sopenharmony_ci		{ 26,  76,  26,  0 },
32662306a36Sopenharmony_ci		{ 22,  76,  30,  0 },
32762306a36Sopenharmony_ci		{ 19,  75,  34,  0 },
32862306a36Sopenharmony_ci		{ 16,  73,  38,  1 },
32962306a36Sopenharmony_ci		{ 13,  71,  43,  1 },
33062306a36Sopenharmony_ci		{ 10,  69,  47,  2 },
33162306a36Sopenharmony_ci		{  8,  66,  51,  3 },
33262306a36Sopenharmony_ci		{  6,  63,  55,  4 },
33362306a36Sopenharmony_ci		{  5,  59,  59,  5 },
33462306a36Sopenharmony_ci		{  4,  55,  63,  6 },
33562306a36Sopenharmony_ci		{  3,  51,  66,  8 },
33662306a36Sopenharmony_ci		{  2,  47,  69, 10 },
33762306a36Sopenharmony_ci		{  1,  43,  71, 13 },
33862306a36Sopenharmony_ci		{  1,  38,  73, 16 },
33962306a36Sopenharmony_ci		{  0,  34,  75, 19 },
34062306a36Sopenharmony_ci		{  0,  30,  76, 22 }
34162306a36Sopenharmony_ci	}, {	/* 131072 < Ratio <= 174762 (~8:3) */
34262306a36Sopenharmony_ci		{ 29,  70,  29,  0 },
34362306a36Sopenharmony_ci		{ 26,  68,  32,  2 },
34462306a36Sopenharmony_ci		{ 23,  67,  36,  2 },
34562306a36Sopenharmony_ci		{ 20,  66,  39,  3 },
34662306a36Sopenharmony_ci		{ 17,  65,  43,  3 },
34762306a36Sopenharmony_ci		{ 15,  63,  46,  4 },
34862306a36Sopenharmony_ci		{ 12,  61,  50,  5 },
34962306a36Sopenharmony_ci		{ 10,  58,  53,  7 },
35062306a36Sopenharmony_ci		{  8,  56,  56,  8 },
35162306a36Sopenharmony_ci		{  7,  53,  58, 10 },
35262306a36Sopenharmony_ci		{  5,  50,  61, 12 },
35362306a36Sopenharmony_ci		{  4,  46,  63, 15 },
35462306a36Sopenharmony_ci		{  3,  43,  65, 17 },
35562306a36Sopenharmony_ci		{  3,  39,  66, 20 },
35662306a36Sopenharmony_ci		{  2,  36,  67, 23 },
35762306a36Sopenharmony_ci		{  2,  32,  68, 26 }
35862306a36Sopenharmony_ci	}, {	/* 174762 < Ratio <= 262144 (~8:2) */
35962306a36Sopenharmony_ci		{ 32,  64,  32,  0 },
36062306a36Sopenharmony_ci		{ 28,  63,  34,  3 },
36162306a36Sopenharmony_ci		{ 25,  62,  37,  4 },
36262306a36Sopenharmony_ci		{ 22,  62,  40,  4 },
36362306a36Sopenharmony_ci		{ 19,  61,  43,  5 },
36462306a36Sopenharmony_ci		{ 17,  59,  46,  6 },
36562306a36Sopenharmony_ci		{ 15,  58,  48,  7 },
36662306a36Sopenharmony_ci		{ 13,  55,  51,  9 },
36762306a36Sopenharmony_ci		{ 11,  53,  53, 11 },
36862306a36Sopenharmony_ci		{  9,  51,  55, 13 },
36962306a36Sopenharmony_ci		{  7,  48,  58, 15 },
37062306a36Sopenharmony_ci		{  6,  46,  59, 17 },
37162306a36Sopenharmony_ci		{  5,  43,  61, 19 },
37262306a36Sopenharmony_ci		{  4,  40,  62, 22 },
37362306a36Sopenharmony_ci		{  4,  37,  62, 25 },
37462306a36Sopenharmony_ci		{  3,  34,  63, 28 }
37562306a36Sopenharmony_ci	}
37662306a36Sopenharmony_ci};
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cistatic int gsc_sw_reset(struct gsc_context *ctx)
37962306a36Sopenharmony_ci{
38062306a36Sopenharmony_ci	u32 cfg;
38162306a36Sopenharmony_ci	int count = GSC_RESET_TIMEOUT;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	/* s/w reset */
38462306a36Sopenharmony_ci	cfg = (GSC_SW_RESET_SRESET);
38562306a36Sopenharmony_ci	gsc_write(cfg, GSC_SW_RESET);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	/* wait s/w reset complete */
38862306a36Sopenharmony_ci	while (count--) {
38962306a36Sopenharmony_ci		cfg = gsc_read(GSC_SW_RESET);
39062306a36Sopenharmony_ci		if (!cfg)
39162306a36Sopenharmony_ci			break;
39262306a36Sopenharmony_ci		usleep_range(1000, 2000);
39362306a36Sopenharmony_ci	}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	if (cfg) {
39662306a36Sopenharmony_ci		DRM_DEV_ERROR(ctx->dev, "failed to reset gsc h/w.\n");
39762306a36Sopenharmony_ci		return -EBUSY;
39862306a36Sopenharmony_ci	}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	/* reset sequence */
40162306a36Sopenharmony_ci	cfg = gsc_read(GSC_IN_BASE_ADDR_Y_MASK);
40262306a36Sopenharmony_ci	cfg |= (GSC_IN_BASE_ADDR_MASK |
40362306a36Sopenharmony_ci		GSC_IN_BASE_ADDR_PINGPONG(0));
40462306a36Sopenharmony_ci	gsc_write(cfg, GSC_IN_BASE_ADDR_Y_MASK);
40562306a36Sopenharmony_ci	gsc_write(cfg, GSC_IN_BASE_ADDR_CB_MASK);
40662306a36Sopenharmony_ci	gsc_write(cfg, GSC_IN_BASE_ADDR_CR_MASK);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	cfg = gsc_read(GSC_OUT_BASE_ADDR_Y_MASK);
40962306a36Sopenharmony_ci	cfg |= (GSC_OUT_BASE_ADDR_MASK |
41062306a36Sopenharmony_ci		GSC_OUT_BASE_ADDR_PINGPONG(0));
41162306a36Sopenharmony_ci	gsc_write(cfg, GSC_OUT_BASE_ADDR_Y_MASK);
41262306a36Sopenharmony_ci	gsc_write(cfg, GSC_OUT_BASE_ADDR_CB_MASK);
41362306a36Sopenharmony_ci	gsc_write(cfg, GSC_OUT_BASE_ADDR_CR_MASK);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	return 0;
41662306a36Sopenharmony_ci}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_cistatic void gsc_handle_irq(struct gsc_context *ctx, bool enable,
41962306a36Sopenharmony_ci		bool overflow, bool done)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	u32 cfg;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "enable[%d]overflow[%d]level[%d]\n",
42462306a36Sopenharmony_ci			  enable, overflow, done);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	cfg = gsc_read(GSC_IRQ);
42762306a36Sopenharmony_ci	cfg |= (GSC_IRQ_OR_MASK | GSC_IRQ_FRMDONE_MASK);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	if (enable)
43062306a36Sopenharmony_ci		cfg |= GSC_IRQ_ENABLE;
43162306a36Sopenharmony_ci	else
43262306a36Sopenharmony_ci		cfg &= ~GSC_IRQ_ENABLE;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	if (overflow)
43562306a36Sopenharmony_ci		cfg &= ~GSC_IRQ_OR_MASK;
43662306a36Sopenharmony_ci	else
43762306a36Sopenharmony_ci		cfg |= GSC_IRQ_OR_MASK;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	if (done)
44062306a36Sopenharmony_ci		cfg &= ~GSC_IRQ_FRMDONE_MASK;
44162306a36Sopenharmony_ci	else
44262306a36Sopenharmony_ci		cfg |= GSC_IRQ_FRMDONE_MASK;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	gsc_write(cfg, GSC_IRQ);
44562306a36Sopenharmony_ci}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_cistatic void gsc_src_set_fmt(struct gsc_context *ctx, u32 fmt, bool tiled)
44962306a36Sopenharmony_ci{
45062306a36Sopenharmony_ci	u32 cfg;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "fmt[0x%x]\n", fmt);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	cfg = gsc_read(GSC_IN_CON);
45562306a36Sopenharmony_ci	cfg &= ~(GSC_IN_RGB_TYPE_MASK | GSC_IN_YUV422_1P_ORDER_MASK |
45662306a36Sopenharmony_ci		 GSC_IN_CHROMA_ORDER_MASK | GSC_IN_FORMAT_MASK |
45762306a36Sopenharmony_ci		 GSC_IN_TILE_TYPE_MASK | GSC_IN_TILE_MODE |
45862306a36Sopenharmony_ci		 GSC_IN_CHROM_STRIDE_SEL_MASK | GSC_IN_RB_SWAP_MASK);
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	switch (fmt) {
46162306a36Sopenharmony_ci	case DRM_FORMAT_RGB565:
46262306a36Sopenharmony_ci		cfg |= GSC_IN_RGB565;
46362306a36Sopenharmony_ci		break;
46462306a36Sopenharmony_ci	case DRM_FORMAT_XRGB8888:
46562306a36Sopenharmony_ci	case DRM_FORMAT_ARGB8888:
46662306a36Sopenharmony_ci		cfg |= GSC_IN_XRGB8888;
46762306a36Sopenharmony_ci		break;
46862306a36Sopenharmony_ci	case DRM_FORMAT_BGRX8888:
46962306a36Sopenharmony_ci		cfg |= (GSC_IN_XRGB8888 | GSC_IN_RB_SWAP);
47062306a36Sopenharmony_ci		break;
47162306a36Sopenharmony_ci	case DRM_FORMAT_YUYV:
47262306a36Sopenharmony_ci		cfg |= (GSC_IN_YUV422_1P |
47362306a36Sopenharmony_ci			GSC_IN_YUV422_1P_ORDER_LSB_Y |
47462306a36Sopenharmony_ci			GSC_IN_CHROMA_ORDER_CBCR);
47562306a36Sopenharmony_ci		break;
47662306a36Sopenharmony_ci	case DRM_FORMAT_YVYU:
47762306a36Sopenharmony_ci		cfg |= (GSC_IN_YUV422_1P |
47862306a36Sopenharmony_ci			GSC_IN_YUV422_1P_ORDER_LSB_Y |
47962306a36Sopenharmony_ci			GSC_IN_CHROMA_ORDER_CRCB);
48062306a36Sopenharmony_ci		break;
48162306a36Sopenharmony_ci	case DRM_FORMAT_UYVY:
48262306a36Sopenharmony_ci		cfg |= (GSC_IN_YUV422_1P |
48362306a36Sopenharmony_ci			GSC_IN_YUV422_1P_OEDER_LSB_C |
48462306a36Sopenharmony_ci			GSC_IN_CHROMA_ORDER_CBCR);
48562306a36Sopenharmony_ci		break;
48662306a36Sopenharmony_ci	case DRM_FORMAT_VYUY:
48762306a36Sopenharmony_ci		cfg |= (GSC_IN_YUV422_1P |
48862306a36Sopenharmony_ci			GSC_IN_YUV422_1P_OEDER_LSB_C |
48962306a36Sopenharmony_ci			GSC_IN_CHROMA_ORDER_CRCB);
49062306a36Sopenharmony_ci		break;
49162306a36Sopenharmony_ci	case DRM_FORMAT_NV21:
49262306a36Sopenharmony_ci		cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV420_2P);
49362306a36Sopenharmony_ci		break;
49462306a36Sopenharmony_ci	case DRM_FORMAT_NV61:
49562306a36Sopenharmony_ci		cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV422_2P);
49662306a36Sopenharmony_ci		break;
49762306a36Sopenharmony_ci	case DRM_FORMAT_YUV422:
49862306a36Sopenharmony_ci		cfg |= GSC_IN_YUV422_3P;
49962306a36Sopenharmony_ci		break;
50062306a36Sopenharmony_ci	case DRM_FORMAT_YUV420:
50162306a36Sopenharmony_ci		cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_3P);
50262306a36Sopenharmony_ci		break;
50362306a36Sopenharmony_ci	case DRM_FORMAT_YVU420:
50462306a36Sopenharmony_ci		cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV420_3P);
50562306a36Sopenharmony_ci		break;
50662306a36Sopenharmony_ci	case DRM_FORMAT_NV12:
50762306a36Sopenharmony_ci		cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_2P);
50862306a36Sopenharmony_ci		break;
50962306a36Sopenharmony_ci	case DRM_FORMAT_NV16:
51062306a36Sopenharmony_ci		cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV422_2P);
51162306a36Sopenharmony_ci		break;
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	if (tiled)
51562306a36Sopenharmony_ci		cfg |= (GSC_IN_TILE_C_16x8 | GSC_IN_TILE_MODE);
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	gsc_write(cfg, GSC_IN_CON);
51862306a36Sopenharmony_ci}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_cistatic void gsc_src_set_transf(struct gsc_context *ctx, unsigned int rotation)
52162306a36Sopenharmony_ci{
52262306a36Sopenharmony_ci	unsigned int degree = rotation & DRM_MODE_ROTATE_MASK;
52362306a36Sopenharmony_ci	u32 cfg;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	cfg = gsc_read(GSC_IN_CON);
52662306a36Sopenharmony_ci	cfg &= ~GSC_IN_ROT_MASK;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	switch (degree) {
52962306a36Sopenharmony_ci	case DRM_MODE_ROTATE_0:
53062306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_X)
53162306a36Sopenharmony_ci			cfg |= GSC_IN_ROT_XFLIP;
53262306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_Y)
53362306a36Sopenharmony_ci			cfg |= GSC_IN_ROT_YFLIP;
53462306a36Sopenharmony_ci		break;
53562306a36Sopenharmony_ci	case DRM_MODE_ROTATE_90:
53662306a36Sopenharmony_ci		cfg |= GSC_IN_ROT_90;
53762306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_X)
53862306a36Sopenharmony_ci			cfg |= GSC_IN_ROT_XFLIP;
53962306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_Y)
54062306a36Sopenharmony_ci			cfg |= GSC_IN_ROT_YFLIP;
54162306a36Sopenharmony_ci		break;
54262306a36Sopenharmony_ci	case DRM_MODE_ROTATE_180:
54362306a36Sopenharmony_ci		cfg |= GSC_IN_ROT_180;
54462306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_X)
54562306a36Sopenharmony_ci			cfg &= ~GSC_IN_ROT_XFLIP;
54662306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_Y)
54762306a36Sopenharmony_ci			cfg &= ~GSC_IN_ROT_YFLIP;
54862306a36Sopenharmony_ci		break;
54962306a36Sopenharmony_ci	case DRM_MODE_ROTATE_270:
55062306a36Sopenharmony_ci		cfg |= GSC_IN_ROT_270;
55162306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_X)
55262306a36Sopenharmony_ci			cfg &= ~GSC_IN_ROT_XFLIP;
55362306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_Y)
55462306a36Sopenharmony_ci			cfg &= ~GSC_IN_ROT_YFLIP;
55562306a36Sopenharmony_ci		break;
55662306a36Sopenharmony_ci	}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	gsc_write(cfg, GSC_IN_CON);
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	ctx->rotation = (cfg & GSC_IN_ROT_90) ? 1 : 0;
56162306a36Sopenharmony_ci}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_cistatic void gsc_src_set_size(struct gsc_context *ctx,
56462306a36Sopenharmony_ci			     struct exynos_drm_ipp_buffer *buf)
56562306a36Sopenharmony_ci{
56662306a36Sopenharmony_ci	struct gsc_scaler *sc = &ctx->sc;
56762306a36Sopenharmony_ci	u32 cfg;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	/* pixel offset */
57062306a36Sopenharmony_ci	cfg = (GSC_SRCIMG_OFFSET_X(buf->rect.x) |
57162306a36Sopenharmony_ci		GSC_SRCIMG_OFFSET_Y(buf->rect.y));
57262306a36Sopenharmony_ci	gsc_write(cfg, GSC_SRCIMG_OFFSET);
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	/* cropped size */
57562306a36Sopenharmony_ci	cfg = (GSC_CROPPED_WIDTH(buf->rect.w) |
57662306a36Sopenharmony_ci		GSC_CROPPED_HEIGHT(buf->rect.h));
57762306a36Sopenharmony_ci	gsc_write(cfg, GSC_CROPPED_SIZE);
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	/* original size */
58062306a36Sopenharmony_ci	cfg = gsc_read(GSC_SRCIMG_SIZE);
58162306a36Sopenharmony_ci	cfg &= ~(GSC_SRCIMG_HEIGHT_MASK |
58262306a36Sopenharmony_ci		GSC_SRCIMG_WIDTH_MASK);
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	cfg |= (GSC_SRCIMG_WIDTH(buf->buf.pitch[0] / buf->format->cpp[0]) |
58562306a36Sopenharmony_ci		GSC_SRCIMG_HEIGHT(buf->buf.height));
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	gsc_write(cfg, GSC_SRCIMG_SIZE);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	cfg = gsc_read(GSC_IN_CON);
59062306a36Sopenharmony_ci	cfg &= ~GSC_IN_RGB_TYPE_MASK;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	if (buf->rect.w >= GSC_WIDTH_ITU_709)
59362306a36Sopenharmony_ci		if (sc->range)
59462306a36Sopenharmony_ci			cfg |= GSC_IN_RGB_HD_WIDE;
59562306a36Sopenharmony_ci		else
59662306a36Sopenharmony_ci			cfg |= GSC_IN_RGB_HD_NARROW;
59762306a36Sopenharmony_ci	else
59862306a36Sopenharmony_ci		if (sc->range)
59962306a36Sopenharmony_ci			cfg |= GSC_IN_RGB_SD_WIDE;
60062306a36Sopenharmony_ci		else
60162306a36Sopenharmony_ci			cfg |= GSC_IN_RGB_SD_NARROW;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	gsc_write(cfg, GSC_IN_CON);
60462306a36Sopenharmony_ci}
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_cistatic void gsc_src_set_buf_seq(struct gsc_context *ctx, u32 buf_id,
60762306a36Sopenharmony_ci			       bool enqueue)
60862306a36Sopenharmony_ci{
60962306a36Sopenharmony_ci	bool masked = !enqueue;
61062306a36Sopenharmony_ci	u32 cfg;
61162306a36Sopenharmony_ci	u32 mask = 0x00000001 << buf_id;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	/* mask register set */
61462306a36Sopenharmony_ci	cfg = gsc_read(GSC_IN_BASE_ADDR_Y_MASK);
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	/* sequence id */
61762306a36Sopenharmony_ci	cfg &= ~mask;
61862306a36Sopenharmony_ci	cfg |= masked << buf_id;
61962306a36Sopenharmony_ci	gsc_write(cfg, GSC_IN_BASE_ADDR_Y_MASK);
62062306a36Sopenharmony_ci	gsc_write(cfg, GSC_IN_BASE_ADDR_CB_MASK);
62162306a36Sopenharmony_ci	gsc_write(cfg, GSC_IN_BASE_ADDR_CR_MASK);
62262306a36Sopenharmony_ci}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_cistatic void gsc_src_set_addr(struct gsc_context *ctx, u32 buf_id,
62562306a36Sopenharmony_ci			    struct exynos_drm_ipp_buffer *buf)
62662306a36Sopenharmony_ci{
62762306a36Sopenharmony_ci	/* address register set */
62862306a36Sopenharmony_ci	gsc_write(buf->dma_addr[0], GSC_IN_BASE_ADDR_Y(buf_id));
62962306a36Sopenharmony_ci	gsc_write(buf->dma_addr[1], GSC_IN_BASE_ADDR_CB(buf_id));
63062306a36Sopenharmony_ci	gsc_write(buf->dma_addr[2], GSC_IN_BASE_ADDR_CR(buf_id));
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	gsc_src_set_buf_seq(ctx, buf_id, true);
63362306a36Sopenharmony_ci}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_cistatic void gsc_dst_set_fmt(struct gsc_context *ctx, u32 fmt, bool tiled)
63662306a36Sopenharmony_ci{
63762306a36Sopenharmony_ci	u32 cfg;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "fmt[0x%x]\n", fmt);
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	cfg = gsc_read(GSC_OUT_CON);
64262306a36Sopenharmony_ci	cfg &= ~(GSC_OUT_RGB_TYPE_MASK | GSC_OUT_YUV422_1P_ORDER_MASK |
64362306a36Sopenharmony_ci		 GSC_OUT_CHROMA_ORDER_MASK | GSC_OUT_FORMAT_MASK |
64462306a36Sopenharmony_ci		 GSC_OUT_CHROM_STRIDE_SEL_MASK | GSC_OUT_RB_SWAP_MASK |
64562306a36Sopenharmony_ci		 GSC_OUT_GLOBAL_ALPHA_MASK);
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	switch (fmt) {
64862306a36Sopenharmony_ci	case DRM_FORMAT_RGB565:
64962306a36Sopenharmony_ci		cfg |= GSC_OUT_RGB565;
65062306a36Sopenharmony_ci		break;
65162306a36Sopenharmony_ci	case DRM_FORMAT_ARGB8888:
65262306a36Sopenharmony_ci	case DRM_FORMAT_XRGB8888:
65362306a36Sopenharmony_ci		cfg |= (GSC_OUT_XRGB8888 | GSC_OUT_GLOBAL_ALPHA(0xff));
65462306a36Sopenharmony_ci		break;
65562306a36Sopenharmony_ci	case DRM_FORMAT_BGRX8888:
65662306a36Sopenharmony_ci		cfg |= (GSC_OUT_XRGB8888 | GSC_OUT_RB_SWAP);
65762306a36Sopenharmony_ci		break;
65862306a36Sopenharmony_ci	case DRM_FORMAT_YUYV:
65962306a36Sopenharmony_ci		cfg |= (GSC_OUT_YUV422_1P |
66062306a36Sopenharmony_ci			GSC_OUT_YUV422_1P_ORDER_LSB_Y |
66162306a36Sopenharmony_ci			GSC_OUT_CHROMA_ORDER_CBCR);
66262306a36Sopenharmony_ci		break;
66362306a36Sopenharmony_ci	case DRM_FORMAT_YVYU:
66462306a36Sopenharmony_ci		cfg |= (GSC_OUT_YUV422_1P |
66562306a36Sopenharmony_ci			GSC_OUT_YUV422_1P_ORDER_LSB_Y |
66662306a36Sopenharmony_ci			GSC_OUT_CHROMA_ORDER_CRCB);
66762306a36Sopenharmony_ci		break;
66862306a36Sopenharmony_ci	case DRM_FORMAT_UYVY:
66962306a36Sopenharmony_ci		cfg |= (GSC_OUT_YUV422_1P |
67062306a36Sopenharmony_ci			GSC_OUT_YUV422_1P_OEDER_LSB_C |
67162306a36Sopenharmony_ci			GSC_OUT_CHROMA_ORDER_CBCR);
67262306a36Sopenharmony_ci		break;
67362306a36Sopenharmony_ci	case DRM_FORMAT_VYUY:
67462306a36Sopenharmony_ci		cfg |= (GSC_OUT_YUV422_1P |
67562306a36Sopenharmony_ci			GSC_OUT_YUV422_1P_OEDER_LSB_C |
67662306a36Sopenharmony_ci			GSC_OUT_CHROMA_ORDER_CRCB);
67762306a36Sopenharmony_ci		break;
67862306a36Sopenharmony_ci	case DRM_FORMAT_NV21:
67962306a36Sopenharmony_ci		cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV420_2P);
68062306a36Sopenharmony_ci		break;
68162306a36Sopenharmony_ci	case DRM_FORMAT_NV61:
68262306a36Sopenharmony_ci		cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV422_2P);
68362306a36Sopenharmony_ci		break;
68462306a36Sopenharmony_ci	case DRM_FORMAT_YUV422:
68562306a36Sopenharmony_ci		cfg |= GSC_OUT_YUV422_3P;
68662306a36Sopenharmony_ci		break;
68762306a36Sopenharmony_ci	case DRM_FORMAT_YUV420:
68862306a36Sopenharmony_ci		cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_3P);
68962306a36Sopenharmony_ci		break;
69062306a36Sopenharmony_ci	case DRM_FORMAT_YVU420:
69162306a36Sopenharmony_ci		cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV420_3P);
69262306a36Sopenharmony_ci		break;
69362306a36Sopenharmony_ci	case DRM_FORMAT_NV12:
69462306a36Sopenharmony_ci		cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_2P);
69562306a36Sopenharmony_ci		break;
69662306a36Sopenharmony_ci	case DRM_FORMAT_NV16:
69762306a36Sopenharmony_ci		cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV422_2P);
69862306a36Sopenharmony_ci		break;
69962306a36Sopenharmony_ci	}
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	if (tiled)
70262306a36Sopenharmony_ci		cfg |= (GSC_IN_TILE_C_16x8 | GSC_OUT_TILE_MODE);
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	gsc_write(cfg, GSC_OUT_CON);
70562306a36Sopenharmony_ci}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_cistatic int gsc_get_ratio_shift(struct gsc_context *ctx, u32 src, u32 dst,
70862306a36Sopenharmony_ci			       u32 *ratio)
70962306a36Sopenharmony_ci{
71062306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "src[%d]dst[%d]\n", src, dst);
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	if (src >= dst * 8) {
71362306a36Sopenharmony_ci		DRM_DEV_ERROR(ctx->dev, "failed to make ratio and shift.\n");
71462306a36Sopenharmony_ci		return -EINVAL;
71562306a36Sopenharmony_ci	} else if (src >= dst * 4)
71662306a36Sopenharmony_ci		*ratio = 4;
71762306a36Sopenharmony_ci	else if (src >= dst * 2)
71862306a36Sopenharmony_ci		*ratio = 2;
71962306a36Sopenharmony_ci	else
72062306a36Sopenharmony_ci		*ratio = 1;
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	return 0;
72362306a36Sopenharmony_ci}
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_cistatic void gsc_get_prescaler_shfactor(u32 hratio, u32 vratio, u32 *shfactor)
72662306a36Sopenharmony_ci{
72762306a36Sopenharmony_ci	if (hratio == 4 && vratio == 4)
72862306a36Sopenharmony_ci		*shfactor = 4;
72962306a36Sopenharmony_ci	else if ((hratio == 4 && vratio == 2) ||
73062306a36Sopenharmony_ci		 (hratio == 2 && vratio == 4))
73162306a36Sopenharmony_ci		*shfactor = 3;
73262306a36Sopenharmony_ci	else if ((hratio == 4 && vratio == 1) ||
73362306a36Sopenharmony_ci		 (hratio == 1 && vratio == 4) ||
73462306a36Sopenharmony_ci		 (hratio == 2 && vratio == 2))
73562306a36Sopenharmony_ci		*shfactor = 2;
73662306a36Sopenharmony_ci	else if (hratio == 1 && vratio == 1)
73762306a36Sopenharmony_ci		*shfactor = 0;
73862306a36Sopenharmony_ci	else
73962306a36Sopenharmony_ci		*shfactor = 1;
74062306a36Sopenharmony_ci}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_cistatic int gsc_set_prescaler(struct gsc_context *ctx, struct gsc_scaler *sc,
74362306a36Sopenharmony_ci			     struct drm_exynos_ipp_task_rect *src,
74462306a36Sopenharmony_ci			     struct drm_exynos_ipp_task_rect *dst)
74562306a36Sopenharmony_ci{
74662306a36Sopenharmony_ci	u32 cfg;
74762306a36Sopenharmony_ci	u32 src_w, src_h, dst_w, dst_h;
74862306a36Sopenharmony_ci	int ret = 0;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	src_w = src->w;
75162306a36Sopenharmony_ci	src_h = src->h;
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	if (ctx->rotation) {
75462306a36Sopenharmony_ci		dst_w = dst->h;
75562306a36Sopenharmony_ci		dst_h = dst->w;
75662306a36Sopenharmony_ci	} else {
75762306a36Sopenharmony_ci		dst_w = dst->w;
75862306a36Sopenharmony_ci		dst_h = dst->h;
75962306a36Sopenharmony_ci	}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	ret = gsc_get_ratio_shift(ctx, src_w, dst_w, &sc->pre_hratio);
76262306a36Sopenharmony_ci	if (ret) {
76362306a36Sopenharmony_ci		DRM_DEV_ERROR(ctx->dev, "failed to get ratio horizontal.\n");
76462306a36Sopenharmony_ci		return ret;
76562306a36Sopenharmony_ci	}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	ret = gsc_get_ratio_shift(ctx, src_h, dst_h, &sc->pre_vratio);
76862306a36Sopenharmony_ci	if (ret) {
76962306a36Sopenharmony_ci		DRM_DEV_ERROR(ctx->dev, "failed to get ratio vertical.\n");
77062306a36Sopenharmony_ci		return ret;
77162306a36Sopenharmony_ci	}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "pre_hratio[%d]pre_vratio[%d]\n",
77462306a36Sopenharmony_ci			  sc->pre_hratio, sc->pre_vratio);
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	sc->main_hratio = (src_w << 16) / dst_w;
77762306a36Sopenharmony_ci	sc->main_vratio = (src_h << 16) / dst_h;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "main_hratio[%ld]main_vratio[%ld]\n",
78062306a36Sopenharmony_ci			  sc->main_hratio, sc->main_vratio);
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	gsc_get_prescaler_shfactor(sc->pre_hratio, sc->pre_vratio,
78362306a36Sopenharmony_ci		&sc->pre_shfactor);
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "pre_shfactor[%d]\n", sc->pre_shfactor);
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	cfg = (GSC_PRESC_SHFACTOR(sc->pre_shfactor) |
78862306a36Sopenharmony_ci		GSC_PRESC_H_RATIO(sc->pre_hratio) |
78962306a36Sopenharmony_ci		GSC_PRESC_V_RATIO(sc->pre_vratio));
79062306a36Sopenharmony_ci	gsc_write(cfg, GSC_PRE_SCALE_RATIO);
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	return ret;
79362306a36Sopenharmony_ci}
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_cistatic void gsc_set_h_coef(struct gsc_context *ctx, unsigned long main_hratio)
79662306a36Sopenharmony_ci{
79762306a36Sopenharmony_ci	int i, j, k, sc_ratio;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	if (main_hratio <= GSC_SC_UP_MAX_RATIO)
80062306a36Sopenharmony_ci		sc_ratio = 0;
80162306a36Sopenharmony_ci	else if (main_hratio <= GSC_SC_DOWN_RATIO_7_8)
80262306a36Sopenharmony_ci		sc_ratio = 1;
80362306a36Sopenharmony_ci	else if (main_hratio <= GSC_SC_DOWN_RATIO_6_8)
80462306a36Sopenharmony_ci		sc_ratio = 2;
80562306a36Sopenharmony_ci	else if (main_hratio <= GSC_SC_DOWN_RATIO_5_8)
80662306a36Sopenharmony_ci		sc_ratio = 3;
80762306a36Sopenharmony_ci	else if (main_hratio <= GSC_SC_DOWN_RATIO_4_8)
80862306a36Sopenharmony_ci		sc_ratio = 4;
80962306a36Sopenharmony_ci	else if (main_hratio <= GSC_SC_DOWN_RATIO_3_8)
81062306a36Sopenharmony_ci		sc_ratio = 5;
81162306a36Sopenharmony_ci	else
81262306a36Sopenharmony_ci		sc_ratio = 6;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	for (i = 0; i < GSC_COEF_PHASE; i++)
81562306a36Sopenharmony_ci		for (j = 0; j < GSC_COEF_H_8T; j++)
81662306a36Sopenharmony_ci			for (k = 0; k < GSC_COEF_DEPTH; k++)
81762306a36Sopenharmony_ci				gsc_write(h_coef_8t[sc_ratio][i][j],
81862306a36Sopenharmony_ci					GSC_HCOEF(i, j, k));
81962306a36Sopenharmony_ci}
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_cistatic void gsc_set_v_coef(struct gsc_context *ctx, unsigned long main_vratio)
82262306a36Sopenharmony_ci{
82362306a36Sopenharmony_ci	int i, j, k, sc_ratio;
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	if (main_vratio <= GSC_SC_UP_MAX_RATIO)
82662306a36Sopenharmony_ci		sc_ratio = 0;
82762306a36Sopenharmony_ci	else if (main_vratio <= GSC_SC_DOWN_RATIO_7_8)
82862306a36Sopenharmony_ci		sc_ratio = 1;
82962306a36Sopenharmony_ci	else if (main_vratio <= GSC_SC_DOWN_RATIO_6_8)
83062306a36Sopenharmony_ci		sc_ratio = 2;
83162306a36Sopenharmony_ci	else if (main_vratio <= GSC_SC_DOWN_RATIO_5_8)
83262306a36Sopenharmony_ci		sc_ratio = 3;
83362306a36Sopenharmony_ci	else if (main_vratio <= GSC_SC_DOWN_RATIO_4_8)
83462306a36Sopenharmony_ci		sc_ratio = 4;
83562306a36Sopenharmony_ci	else if (main_vratio <= GSC_SC_DOWN_RATIO_3_8)
83662306a36Sopenharmony_ci		sc_ratio = 5;
83762306a36Sopenharmony_ci	else
83862306a36Sopenharmony_ci		sc_ratio = 6;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	for (i = 0; i < GSC_COEF_PHASE; i++)
84162306a36Sopenharmony_ci		for (j = 0; j < GSC_COEF_V_4T; j++)
84262306a36Sopenharmony_ci			for (k = 0; k < GSC_COEF_DEPTH; k++)
84362306a36Sopenharmony_ci				gsc_write(v_coef_4t[sc_ratio][i][j],
84462306a36Sopenharmony_ci					GSC_VCOEF(i, j, k));
84562306a36Sopenharmony_ci}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_cistatic void gsc_set_scaler(struct gsc_context *ctx, struct gsc_scaler *sc)
84862306a36Sopenharmony_ci{
84962306a36Sopenharmony_ci	u32 cfg;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "main_hratio[%ld]main_vratio[%ld]\n",
85262306a36Sopenharmony_ci			  sc->main_hratio, sc->main_vratio);
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	gsc_set_h_coef(ctx, sc->main_hratio);
85562306a36Sopenharmony_ci	cfg = GSC_MAIN_H_RATIO_VALUE(sc->main_hratio);
85662306a36Sopenharmony_ci	gsc_write(cfg, GSC_MAIN_H_RATIO);
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	gsc_set_v_coef(ctx, sc->main_vratio);
85962306a36Sopenharmony_ci	cfg = GSC_MAIN_V_RATIO_VALUE(sc->main_vratio);
86062306a36Sopenharmony_ci	gsc_write(cfg, GSC_MAIN_V_RATIO);
86162306a36Sopenharmony_ci}
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_cistatic void gsc_dst_set_size(struct gsc_context *ctx,
86462306a36Sopenharmony_ci			     struct exynos_drm_ipp_buffer *buf)
86562306a36Sopenharmony_ci{
86662306a36Sopenharmony_ci	struct gsc_scaler *sc = &ctx->sc;
86762306a36Sopenharmony_ci	u32 cfg;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	/* pixel offset */
87062306a36Sopenharmony_ci	cfg = (GSC_DSTIMG_OFFSET_X(buf->rect.x) |
87162306a36Sopenharmony_ci		GSC_DSTIMG_OFFSET_Y(buf->rect.y));
87262306a36Sopenharmony_ci	gsc_write(cfg, GSC_DSTIMG_OFFSET);
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	/* scaled size */
87562306a36Sopenharmony_ci	if (ctx->rotation)
87662306a36Sopenharmony_ci		cfg = (GSC_SCALED_WIDTH(buf->rect.h) |
87762306a36Sopenharmony_ci		       GSC_SCALED_HEIGHT(buf->rect.w));
87862306a36Sopenharmony_ci	else
87962306a36Sopenharmony_ci		cfg = (GSC_SCALED_WIDTH(buf->rect.w) |
88062306a36Sopenharmony_ci		       GSC_SCALED_HEIGHT(buf->rect.h));
88162306a36Sopenharmony_ci	gsc_write(cfg, GSC_SCALED_SIZE);
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	/* original size */
88462306a36Sopenharmony_ci	cfg = gsc_read(GSC_DSTIMG_SIZE);
88562306a36Sopenharmony_ci	cfg &= ~(GSC_DSTIMG_HEIGHT_MASK | GSC_DSTIMG_WIDTH_MASK);
88662306a36Sopenharmony_ci	cfg |= GSC_DSTIMG_WIDTH(buf->buf.pitch[0] / buf->format->cpp[0]) |
88762306a36Sopenharmony_ci	       GSC_DSTIMG_HEIGHT(buf->buf.height);
88862306a36Sopenharmony_ci	gsc_write(cfg, GSC_DSTIMG_SIZE);
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	cfg = gsc_read(GSC_OUT_CON);
89162306a36Sopenharmony_ci	cfg &= ~GSC_OUT_RGB_TYPE_MASK;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	if (buf->rect.w >= GSC_WIDTH_ITU_709)
89462306a36Sopenharmony_ci		if (sc->range)
89562306a36Sopenharmony_ci			cfg |= GSC_OUT_RGB_HD_WIDE;
89662306a36Sopenharmony_ci		else
89762306a36Sopenharmony_ci			cfg |= GSC_OUT_RGB_HD_NARROW;
89862306a36Sopenharmony_ci	else
89962306a36Sopenharmony_ci		if (sc->range)
90062306a36Sopenharmony_ci			cfg |= GSC_OUT_RGB_SD_WIDE;
90162306a36Sopenharmony_ci		else
90262306a36Sopenharmony_ci			cfg |= GSC_OUT_RGB_SD_NARROW;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	gsc_write(cfg, GSC_OUT_CON);
90562306a36Sopenharmony_ci}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_cistatic int gsc_dst_get_buf_seq(struct gsc_context *ctx)
90862306a36Sopenharmony_ci{
90962306a36Sopenharmony_ci	u32 cfg, i, buf_num = GSC_REG_SZ;
91062306a36Sopenharmony_ci	u32 mask = 0x00000001;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	cfg = gsc_read(GSC_OUT_BASE_ADDR_Y_MASK);
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	for (i = 0; i < GSC_REG_SZ; i++)
91562306a36Sopenharmony_ci		if (cfg & (mask << i))
91662306a36Sopenharmony_ci			buf_num--;
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "buf_num[%d]\n", buf_num);
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	return buf_num;
92162306a36Sopenharmony_ci}
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_cistatic void gsc_dst_set_buf_seq(struct gsc_context *ctx, u32 buf_id,
92462306a36Sopenharmony_ci				bool enqueue)
92562306a36Sopenharmony_ci{
92662306a36Sopenharmony_ci	bool masked = !enqueue;
92762306a36Sopenharmony_ci	u32 cfg;
92862306a36Sopenharmony_ci	u32 mask = 0x00000001 << buf_id;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	/* mask register set */
93162306a36Sopenharmony_ci	cfg = gsc_read(GSC_OUT_BASE_ADDR_Y_MASK);
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	/* sequence id */
93462306a36Sopenharmony_ci	cfg &= ~mask;
93562306a36Sopenharmony_ci	cfg |= masked << buf_id;
93662306a36Sopenharmony_ci	gsc_write(cfg, GSC_OUT_BASE_ADDR_Y_MASK);
93762306a36Sopenharmony_ci	gsc_write(cfg, GSC_OUT_BASE_ADDR_CB_MASK);
93862306a36Sopenharmony_ci	gsc_write(cfg, GSC_OUT_BASE_ADDR_CR_MASK);
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	/* interrupt enable */
94162306a36Sopenharmony_ci	if (enqueue && gsc_dst_get_buf_seq(ctx) >= GSC_BUF_START)
94262306a36Sopenharmony_ci		gsc_handle_irq(ctx, true, false, true);
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	/* interrupt disable */
94562306a36Sopenharmony_ci	if (!enqueue && gsc_dst_get_buf_seq(ctx) <= GSC_BUF_STOP)
94662306a36Sopenharmony_ci		gsc_handle_irq(ctx, false, false, true);
94762306a36Sopenharmony_ci}
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_cistatic void gsc_dst_set_addr(struct gsc_context *ctx,
95062306a36Sopenharmony_ci			     u32 buf_id, struct exynos_drm_ipp_buffer *buf)
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	/* address register set */
95362306a36Sopenharmony_ci	gsc_write(buf->dma_addr[0], GSC_OUT_BASE_ADDR_Y(buf_id));
95462306a36Sopenharmony_ci	gsc_write(buf->dma_addr[1], GSC_OUT_BASE_ADDR_CB(buf_id));
95562306a36Sopenharmony_ci	gsc_write(buf->dma_addr[2], GSC_OUT_BASE_ADDR_CR(buf_id));
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	gsc_dst_set_buf_seq(ctx, buf_id, true);
95862306a36Sopenharmony_ci}
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_cistatic int gsc_get_src_buf_index(struct gsc_context *ctx)
96162306a36Sopenharmony_ci{
96262306a36Sopenharmony_ci	u32 cfg, curr_index, i;
96362306a36Sopenharmony_ci	u32 buf_id = GSC_MAX_SRC;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "gsc id[%d]\n", ctx->id);
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	cfg = gsc_read(GSC_IN_BASE_ADDR_Y_MASK);
96862306a36Sopenharmony_ci	curr_index = GSC_IN_CURR_GET_INDEX(cfg);
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	for (i = curr_index; i < GSC_MAX_SRC; i++) {
97162306a36Sopenharmony_ci		if (!((cfg >> i) & 0x1)) {
97262306a36Sopenharmony_ci			buf_id = i;
97362306a36Sopenharmony_ci			break;
97462306a36Sopenharmony_ci		}
97562306a36Sopenharmony_ci	}
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "cfg[0x%x]curr_index[%d]buf_id[%d]\n", cfg,
97862306a36Sopenharmony_ci			  curr_index, buf_id);
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	if (buf_id == GSC_MAX_SRC) {
98162306a36Sopenharmony_ci		DRM_DEV_ERROR(ctx->dev, "failed to get in buffer index.\n");
98262306a36Sopenharmony_ci		return -EINVAL;
98362306a36Sopenharmony_ci	}
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	gsc_src_set_buf_seq(ctx, buf_id, false);
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	return buf_id;
98862306a36Sopenharmony_ci}
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_cistatic int gsc_get_dst_buf_index(struct gsc_context *ctx)
99162306a36Sopenharmony_ci{
99262306a36Sopenharmony_ci	u32 cfg, curr_index, i;
99362306a36Sopenharmony_ci	u32 buf_id = GSC_MAX_DST;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "gsc id[%d]\n", ctx->id);
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	cfg = gsc_read(GSC_OUT_BASE_ADDR_Y_MASK);
99862306a36Sopenharmony_ci	curr_index = GSC_OUT_CURR_GET_INDEX(cfg);
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	for (i = curr_index; i < GSC_MAX_DST; i++) {
100162306a36Sopenharmony_ci		if (!((cfg >> i) & 0x1)) {
100262306a36Sopenharmony_ci			buf_id = i;
100362306a36Sopenharmony_ci			break;
100462306a36Sopenharmony_ci		}
100562306a36Sopenharmony_ci	}
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	if (buf_id == GSC_MAX_DST) {
100862306a36Sopenharmony_ci		DRM_DEV_ERROR(ctx->dev, "failed to get out buffer index.\n");
100962306a36Sopenharmony_ci		return -EINVAL;
101062306a36Sopenharmony_ci	}
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	gsc_dst_set_buf_seq(ctx, buf_id, false);
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "cfg[0x%x]curr_index[%d]buf_id[%d]\n", cfg,
101562306a36Sopenharmony_ci			  curr_index, buf_id);
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	return buf_id;
101862306a36Sopenharmony_ci}
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_cistatic irqreturn_t gsc_irq_handler(int irq, void *dev_id)
102162306a36Sopenharmony_ci{
102262306a36Sopenharmony_ci	struct gsc_context *ctx = dev_id;
102362306a36Sopenharmony_ci	u32 status;
102462306a36Sopenharmony_ci	int err = 0;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(ctx->dev, "gsc id[%d]\n", ctx->id);
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	status = gsc_read(GSC_IRQ);
102962306a36Sopenharmony_ci	if (status & GSC_IRQ_STATUS_OR_IRQ) {
103062306a36Sopenharmony_ci		dev_err(ctx->dev, "occurred overflow at %d, status 0x%x.\n",
103162306a36Sopenharmony_ci			ctx->id, status);
103262306a36Sopenharmony_ci		err = -EINVAL;
103362306a36Sopenharmony_ci	}
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	if (status & GSC_IRQ_STATUS_OR_FRM_DONE) {
103662306a36Sopenharmony_ci		int src_buf_id, dst_buf_id;
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci		dev_dbg(ctx->dev, "occurred frame done at %d, status 0x%x.\n",
103962306a36Sopenharmony_ci			ctx->id, status);
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci		src_buf_id = gsc_get_src_buf_index(ctx);
104262306a36Sopenharmony_ci		dst_buf_id = gsc_get_dst_buf_index(ctx);
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci		DRM_DEV_DEBUG_KMS(ctx->dev, "buf_id_src[%d]buf_id_dst[%d]\n",
104562306a36Sopenharmony_ci				  src_buf_id, dst_buf_id);
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci		if (src_buf_id < 0 || dst_buf_id < 0)
104862306a36Sopenharmony_ci			err = -EINVAL;
104962306a36Sopenharmony_ci	}
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	if (ctx->task) {
105262306a36Sopenharmony_ci		struct exynos_drm_ipp_task *task = ctx->task;
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci		ctx->task = NULL;
105562306a36Sopenharmony_ci		pm_runtime_mark_last_busy(ctx->dev);
105662306a36Sopenharmony_ci		pm_runtime_put_autosuspend(ctx->dev);
105762306a36Sopenharmony_ci		exynos_drm_ipp_task_done(task, err);
105862306a36Sopenharmony_ci	}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	return IRQ_HANDLED;
106162306a36Sopenharmony_ci}
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_cistatic int gsc_reset(struct gsc_context *ctx)
106462306a36Sopenharmony_ci{
106562306a36Sopenharmony_ci	struct gsc_scaler *sc = &ctx->sc;
106662306a36Sopenharmony_ci	int ret;
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	/* reset h/w block */
106962306a36Sopenharmony_ci	ret = gsc_sw_reset(ctx);
107062306a36Sopenharmony_ci	if (ret < 0) {
107162306a36Sopenharmony_ci		dev_err(ctx->dev, "failed to reset hardware.\n");
107262306a36Sopenharmony_ci		return ret;
107362306a36Sopenharmony_ci	}
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	/* scaler setting */
107662306a36Sopenharmony_ci	memset(&ctx->sc, 0x0, sizeof(ctx->sc));
107762306a36Sopenharmony_ci	sc->range = true;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	return 0;
108062306a36Sopenharmony_ci}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_cistatic void gsc_start(struct gsc_context *ctx)
108362306a36Sopenharmony_ci{
108462306a36Sopenharmony_ci	u32 cfg;
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	gsc_handle_irq(ctx, true, false, true);
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	/* enable one shot */
108962306a36Sopenharmony_ci	cfg = gsc_read(GSC_ENABLE);
109062306a36Sopenharmony_ci	cfg &= ~(GSC_ENABLE_ON_CLEAR_MASK |
109162306a36Sopenharmony_ci		GSC_ENABLE_CLK_GATE_MODE_MASK);
109262306a36Sopenharmony_ci	cfg |= GSC_ENABLE_ON_CLEAR_ONESHOT;
109362306a36Sopenharmony_ci	gsc_write(cfg, GSC_ENABLE);
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	/* src dma memory */
109662306a36Sopenharmony_ci	cfg = gsc_read(GSC_IN_CON);
109762306a36Sopenharmony_ci	cfg &= ~(GSC_IN_PATH_MASK | GSC_IN_LOCAL_SEL_MASK);
109862306a36Sopenharmony_ci	cfg |= GSC_IN_PATH_MEMORY;
109962306a36Sopenharmony_ci	gsc_write(cfg, GSC_IN_CON);
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	/* dst dma memory */
110262306a36Sopenharmony_ci	cfg = gsc_read(GSC_OUT_CON);
110362306a36Sopenharmony_ci	cfg |= GSC_OUT_PATH_MEMORY;
110462306a36Sopenharmony_ci	gsc_write(cfg, GSC_OUT_CON);
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	gsc_set_scaler(ctx, &ctx->sc);
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	cfg = gsc_read(GSC_ENABLE);
110962306a36Sopenharmony_ci	cfg |= GSC_ENABLE_ON;
111062306a36Sopenharmony_ci	gsc_write(cfg, GSC_ENABLE);
111162306a36Sopenharmony_ci}
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_cistatic int gsc_commit(struct exynos_drm_ipp *ipp,
111462306a36Sopenharmony_ci			  struct exynos_drm_ipp_task *task)
111562306a36Sopenharmony_ci{
111662306a36Sopenharmony_ci	struct gsc_context *ctx = container_of(ipp, struct gsc_context, ipp);
111762306a36Sopenharmony_ci	int ret;
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(ctx->dev);
112062306a36Sopenharmony_ci	if (ret < 0) {
112162306a36Sopenharmony_ci		dev_err(ctx->dev, "failed to enable GScaler device.\n");
112262306a36Sopenharmony_ci		return ret;
112362306a36Sopenharmony_ci	}
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	ctx->task = task;
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	ret = gsc_reset(ctx);
112862306a36Sopenharmony_ci	if (ret) {
112962306a36Sopenharmony_ci		pm_runtime_put_autosuspend(ctx->dev);
113062306a36Sopenharmony_ci		ctx->task = NULL;
113162306a36Sopenharmony_ci		return ret;
113262306a36Sopenharmony_ci	}
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	gsc_src_set_fmt(ctx, task->src.buf.fourcc, task->src.buf.modifier);
113562306a36Sopenharmony_ci	gsc_src_set_transf(ctx, task->transform.rotation);
113662306a36Sopenharmony_ci	gsc_src_set_size(ctx, &task->src);
113762306a36Sopenharmony_ci	gsc_src_set_addr(ctx, 0, &task->src);
113862306a36Sopenharmony_ci	gsc_dst_set_fmt(ctx, task->dst.buf.fourcc, task->dst.buf.modifier);
113962306a36Sopenharmony_ci	gsc_dst_set_size(ctx, &task->dst);
114062306a36Sopenharmony_ci	gsc_dst_set_addr(ctx, 0, &task->dst);
114162306a36Sopenharmony_ci	gsc_set_prescaler(ctx, &ctx->sc, &task->src.rect, &task->dst.rect);
114262306a36Sopenharmony_ci	gsc_start(ctx);
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	return 0;
114562306a36Sopenharmony_ci}
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_cistatic void gsc_abort(struct exynos_drm_ipp *ipp,
114862306a36Sopenharmony_ci			  struct exynos_drm_ipp_task *task)
114962306a36Sopenharmony_ci{
115062306a36Sopenharmony_ci	struct gsc_context *ctx =
115162306a36Sopenharmony_ci			container_of(ipp, struct gsc_context, ipp);
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	gsc_reset(ctx);
115462306a36Sopenharmony_ci	if (ctx->task) {
115562306a36Sopenharmony_ci		struct exynos_drm_ipp_task *task = ctx->task;
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci		ctx->task = NULL;
115862306a36Sopenharmony_ci		pm_runtime_mark_last_busy(ctx->dev);
115962306a36Sopenharmony_ci		pm_runtime_put_autosuspend(ctx->dev);
116062306a36Sopenharmony_ci		exynos_drm_ipp_task_done(task, -EIO);
116162306a36Sopenharmony_ci	}
116262306a36Sopenharmony_ci}
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_cistatic struct exynos_drm_ipp_funcs ipp_funcs = {
116562306a36Sopenharmony_ci	.commit = gsc_commit,
116662306a36Sopenharmony_ci	.abort = gsc_abort,
116762306a36Sopenharmony_ci};
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_cistatic int gsc_bind(struct device *dev, struct device *master, void *data)
117062306a36Sopenharmony_ci{
117162306a36Sopenharmony_ci	struct gsc_context *ctx = dev_get_drvdata(dev);
117262306a36Sopenharmony_ci	struct drm_device *drm_dev = data;
117362306a36Sopenharmony_ci	struct exynos_drm_ipp *ipp = &ctx->ipp;
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	ctx->drm_dev = drm_dev;
117662306a36Sopenharmony_ci	ctx->drm_dev = drm_dev;
117762306a36Sopenharmony_ci	exynos_drm_register_dma(drm_dev, dev, &ctx->dma_priv);
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	exynos_drm_ipp_register(dev, ipp, &ipp_funcs,
118062306a36Sopenharmony_ci			DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |
118162306a36Sopenharmony_ci			DRM_EXYNOS_IPP_CAP_SCALE | DRM_EXYNOS_IPP_CAP_CONVERT,
118262306a36Sopenharmony_ci			ctx->formats, ctx->num_formats, "gsc");
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	dev_info(dev, "The exynos gscaler has been probed successfully\n");
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	return 0;
118762306a36Sopenharmony_ci}
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_cistatic void gsc_unbind(struct device *dev, struct device *master,
119062306a36Sopenharmony_ci			void *data)
119162306a36Sopenharmony_ci{
119262306a36Sopenharmony_ci	struct gsc_context *ctx = dev_get_drvdata(dev);
119362306a36Sopenharmony_ci	struct drm_device *drm_dev = data;
119462306a36Sopenharmony_ci	struct exynos_drm_ipp *ipp = &ctx->ipp;
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	exynos_drm_ipp_unregister(dev, ipp);
119762306a36Sopenharmony_ci	exynos_drm_unregister_dma(drm_dev, dev, &ctx->dma_priv);
119862306a36Sopenharmony_ci}
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_cistatic const struct component_ops gsc_component_ops = {
120162306a36Sopenharmony_ci	.bind	= gsc_bind,
120262306a36Sopenharmony_ci	.unbind = gsc_unbind,
120362306a36Sopenharmony_ci};
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_cistatic const unsigned int gsc_formats[] = {
120662306a36Sopenharmony_ci	DRM_FORMAT_ARGB8888,
120762306a36Sopenharmony_ci	DRM_FORMAT_XRGB8888, DRM_FORMAT_RGB565, DRM_FORMAT_BGRX8888,
120862306a36Sopenharmony_ci	DRM_FORMAT_NV12, DRM_FORMAT_NV16, DRM_FORMAT_NV21, DRM_FORMAT_NV61,
120962306a36Sopenharmony_ci	DRM_FORMAT_UYVY, DRM_FORMAT_VYUY, DRM_FORMAT_YUYV, DRM_FORMAT_YVYU,
121062306a36Sopenharmony_ci	DRM_FORMAT_YUV420, DRM_FORMAT_YVU420, DRM_FORMAT_YUV422,
121162306a36Sopenharmony_ci};
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_cistatic const unsigned int gsc_tiled_formats[] = {
121462306a36Sopenharmony_ci	DRM_FORMAT_NV12, DRM_FORMAT_NV21,
121562306a36Sopenharmony_ci};
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_cistatic int gsc_probe(struct platform_device *pdev)
121862306a36Sopenharmony_ci{
121962306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
122062306a36Sopenharmony_ci	struct gsc_driverdata *driver_data;
122162306a36Sopenharmony_ci	struct exynos_drm_ipp_formats *formats;
122262306a36Sopenharmony_ci	struct gsc_context *ctx;
122362306a36Sopenharmony_ci	int num_formats, ret, i, j;
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
122662306a36Sopenharmony_ci	if (!ctx)
122762306a36Sopenharmony_ci		return -ENOMEM;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	driver_data = (struct gsc_driverdata *)of_device_get_match_data(dev);
123062306a36Sopenharmony_ci	ctx->dev = dev;
123162306a36Sopenharmony_ci	ctx->num_clocks = driver_data->num_clocks;
123262306a36Sopenharmony_ci	ctx->clk_names = driver_data->clk_names;
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	/* construct formats/limits array */
123562306a36Sopenharmony_ci	num_formats = ARRAY_SIZE(gsc_formats) + ARRAY_SIZE(gsc_tiled_formats);
123662306a36Sopenharmony_ci	formats = devm_kcalloc(dev, num_formats, sizeof(*formats), GFP_KERNEL);
123762306a36Sopenharmony_ci	if (!formats)
123862306a36Sopenharmony_ci		return -ENOMEM;
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	/* linear formats */
124162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(gsc_formats); i++) {
124262306a36Sopenharmony_ci		formats[i].fourcc = gsc_formats[i];
124362306a36Sopenharmony_ci		formats[i].type = DRM_EXYNOS_IPP_FORMAT_SOURCE |
124462306a36Sopenharmony_ci				  DRM_EXYNOS_IPP_FORMAT_DESTINATION;
124562306a36Sopenharmony_ci		formats[i].limits = driver_data->limits;
124662306a36Sopenharmony_ci		formats[i].num_limits = driver_data->num_limits;
124762306a36Sopenharmony_ci	}
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	/* tiled formats */
125062306a36Sopenharmony_ci	for (j = i, i = 0; i < ARRAY_SIZE(gsc_tiled_formats); j++, i++) {
125162306a36Sopenharmony_ci		formats[j].fourcc = gsc_tiled_formats[i];
125262306a36Sopenharmony_ci		formats[j].modifier = DRM_FORMAT_MOD_SAMSUNG_16_16_TILE;
125362306a36Sopenharmony_ci		formats[j].type = DRM_EXYNOS_IPP_FORMAT_SOURCE |
125462306a36Sopenharmony_ci				  DRM_EXYNOS_IPP_FORMAT_DESTINATION;
125562306a36Sopenharmony_ci		formats[j].limits = driver_data->limits;
125662306a36Sopenharmony_ci		formats[j].num_limits = driver_data->num_limits;
125762306a36Sopenharmony_ci	}
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	ctx->formats = formats;
126062306a36Sopenharmony_ci	ctx->num_formats = num_formats;
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	/* clock control */
126362306a36Sopenharmony_ci	for (i = 0; i < ctx->num_clocks; i++) {
126462306a36Sopenharmony_ci		ctx->clocks[i] = devm_clk_get(dev, ctx->clk_names[i]);
126562306a36Sopenharmony_ci		if (IS_ERR(ctx->clocks[i])) {
126662306a36Sopenharmony_ci			dev_err(dev, "failed to get clock: %s\n",
126762306a36Sopenharmony_ci				ctx->clk_names[i]);
126862306a36Sopenharmony_ci			return PTR_ERR(ctx->clocks[i]);
126962306a36Sopenharmony_ci		}
127062306a36Sopenharmony_ci	}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	ctx->regs = devm_platform_ioremap_resource(pdev, 0);
127362306a36Sopenharmony_ci	if (IS_ERR(ctx->regs))
127462306a36Sopenharmony_ci		return PTR_ERR(ctx->regs);
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	/* resource irq */
127762306a36Sopenharmony_ci	ctx->irq = platform_get_irq(pdev, 0);
127862306a36Sopenharmony_ci	if (ctx->irq < 0)
127962306a36Sopenharmony_ci		return ctx->irq;
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	ret = devm_request_irq(dev, ctx->irq, gsc_irq_handler, 0,
128262306a36Sopenharmony_ci			       dev_name(dev), ctx);
128362306a36Sopenharmony_ci	if (ret < 0) {
128462306a36Sopenharmony_ci		dev_err(dev, "failed to request irq.\n");
128562306a36Sopenharmony_ci		return ret;
128662306a36Sopenharmony_ci	}
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	/* context initailization */
128962306a36Sopenharmony_ci	ctx->id = pdev->id;
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	platform_set_drvdata(pdev, ctx);
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	pm_runtime_use_autosuspend(dev);
129462306a36Sopenharmony_ci	pm_runtime_set_autosuspend_delay(dev, GSC_AUTOSUSPEND_DELAY);
129562306a36Sopenharmony_ci	pm_runtime_enable(dev);
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	ret = component_add(dev, &gsc_component_ops);
129862306a36Sopenharmony_ci	if (ret)
129962306a36Sopenharmony_ci		goto err_pm_dis;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	dev_info(dev, "drm gsc registered successfully.\n");
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	return 0;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_cierr_pm_dis:
130662306a36Sopenharmony_ci	pm_runtime_dont_use_autosuspend(dev);
130762306a36Sopenharmony_ci	pm_runtime_disable(dev);
130862306a36Sopenharmony_ci	return ret;
130962306a36Sopenharmony_ci}
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_cistatic int gsc_remove(struct platform_device *pdev)
131262306a36Sopenharmony_ci{
131362306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	component_del(dev, &gsc_component_ops);
131662306a36Sopenharmony_ci	pm_runtime_dont_use_autosuspend(dev);
131762306a36Sopenharmony_ci	pm_runtime_disable(dev);
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	return 0;
132062306a36Sopenharmony_ci}
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_cistatic int __maybe_unused gsc_runtime_suspend(struct device *dev)
132362306a36Sopenharmony_ci{
132462306a36Sopenharmony_ci	struct gsc_context *ctx = get_gsc_context(dev);
132562306a36Sopenharmony_ci	int i;
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(dev, "id[%d]\n", ctx->id);
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	for (i = ctx->num_clocks - 1; i >= 0; i--)
133062306a36Sopenharmony_ci		clk_disable_unprepare(ctx->clocks[i]);
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	return 0;
133362306a36Sopenharmony_ci}
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_cistatic int __maybe_unused gsc_runtime_resume(struct device *dev)
133662306a36Sopenharmony_ci{
133762306a36Sopenharmony_ci	struct gsc_context *ctx = get_gsc_context(dev);
133862306a36Sopenharmony_ci	int i, ret;
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci	DRM_DEV_DEBUG_KMS(dev, "id[%d]\n", ctx->id);
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	for (i = 0; i < ctx->num_clocks; i++) {
134362306a36Sopenharmony_ci		ret = clk_prepare_enable(ctx->clocks[i]);
134462306a36Sopenharmony_ci		if (ret) {
134562306a36Sopenharmony_ci			while (--i >= 0)
134662306a36Sopenharmony_ci				clk_disable_unprepare(ctx->clocks[i]);
134762306a36Sopenharmony_ci			return ret;
134862306a36Sopenharmony_ci		}
134962306a36Sopenharmony_ci	}
135062306a36Sopenharmony_ci	return 0;
135162306a36Sopenharmony_ci}
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_cistatic const struct dev_pm_ops gsc_pm_ops = {
135462306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
135562306a36Sopenharmony_ci				pm_runtime_force_resume)
135662306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(gsc_runtime_suspend, gsc_runtime_resume, NULL)
135762306a36Sopenharmony_ci};
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_cistatic const struct drm_exynos_ipp_limit gsc_5250_limits[] = {
136062306a36Sopenharmony_ci	{ IPP_SIZE_LIMIT(BUFFER, .h = { 32, 4800, 8 }, .v = { 16, 3344, 8 }) },
136162306a36Sopenharmony_ci	{ IPP_SIZE_LIMIT(AREA, .h = { 16, 4800, 2 }, .v = { 8, 3344, 2 }) },
136262306a36Sopenharmony_ci	{ IPP_SIZE_LIMIT(ROTATED, .h = { 32, 2048 }, .v = { 16, 2048 }) },
136362306a36Sopenharmony_ci	{ IPP_SCALE_LIMIT(.h = { (1 << 16) / 16, (1 << 16) * 8 },
136462306a36Sopenharmony_ci			  .v = { (1 << 16) / 16, (1 << 16) * 8 }) },
136562306a36Sopenharmony_ci};
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_cistatic const struct drm_exynos_ipp_limit gsc_5420_limits[] = {
136862306a36Sopenharmony_ci	{ IPP_SIZE_LIMIT(BUFFER, .h = { 32, 4800, 8 }, .v = { 16, 3344, 8 }) },
136962306a36Sopenharmony_ci	{ IPP_SIZE_LIMIT(AREA, .h = { 16, 4800, 2 }, .v = { 8, 3344, 2 }) },
137062306a36Sopenharmony_ci	{ IPP_SIZE_LIMIT(ROTATED, .h = { 16, 2016 }, .v = { 8, 2016 }) },
137162306a36Sopenharmony_ci	{ IPP_SCALE_LIMIT(.h = { (1 << 16) / 16, (1 << 16) * 8 },
137262306a36Sopenharmony_ci			  .v = { (1 << 16) / 16, (1 << 16) * 8 }) },
137362306a36Sopenharmony_ci};
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_cistatic const struct drm_exynos_ipp_limit gsc_5433_limits[] = {
137662306a36Sopenharmony_ci	{ IPP_SIZE_LIMIT(BUFFER, .h = { 32, 8191, 16 }, .v = { 16, 8191, 2 }) },
137762306a36Sopenharmony_ci	{ IPP_SIZE_LIMIT(AREA, .h = { 16, 4800, 1 }, .v = { 8, 3344, 1 }) },
137862306a36Sopenharmony_ci	{ IPP_SIZE_LIMIT(ROTATED, .h = { 32, 2047 }, .v = { 8, 8191 }) },
137962306a36Sopenharmony_ci	{ IPP_SCALE_LIMIT(.h = { (1 << 16) / 16, (1 << 16) * 8 },
138062306a36Sopenharmony_ci			  .v = { (1 << 16) / 16, (1 << 16) * 8 }) },
138162306a36Sopenharmony_ci};
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_cistatic struct gsc_driverdata gsc_exynos5250_drvdata = {
138462306a36Sopenharmony_ci	.clk_names = {"gscl"},
138562306a36Sopenharmony_ci	.num_clocks = 1,
138662306a36Sopenharmony_ci	.limits = gsc_5250_limits,
138762306a36Sopenharmony_ci	.num_limits = ARRAY_SIZE(gsc_5250_limits),
138862306a36Sopenharmony_ci};
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_cistatic struct gsc_driverdata gsc_exynos5420_drvdata = {
139162306a36Sopenharmony_ci	.clk_names = {"gscl"},
139262306a36Sopenharmony_ci	.num_clocks = 1,
139362306a36Sopenharmony_ci	.limits = gsc_5420_limits,
139462306a36Sopenharmony_ci	.num_limits = ARRAY_SIZE(gsc_5420_limits),
139562306a36Sopenharmony_ci};
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_cistatic struct gsc_driverdata gsc_exynos5433_drvdata = {
139862306a36Sopenharmony_ci	.clk_names = {"pclk", "aclk", "aclk_xiu", "aclk_gsclbend"},
139962306a36Sopenharmony_ci	.num_clocks = 4,
140062306a36Sopenharmony_ci	.limits = gsc_5433_limits,
140162306a36Sopenharmony_ci	.num_limits = ARRAY_SIZE(gsc_5433_limits),
140262306a36Sopenharmony_ci};
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_cistatic const struct of_device_id exynos_drm_gsc_of_match[] = {
140562306a36Sopenharmony_ci	{
140662306a36Sopenharmony_ci		.compatible = "samsung,exynos5-gsc",
140762306a36Sopenharmony_ci		.data = &gsc_exynos5250_drvdata,
140862306a36Sopenharmony_ci	}, {
140962306a36Sopenharmony_ci		.compatible = "samsung,exynos5250-gsc",
141062306a36Sopenharmony_ci		.data = &gsc_exynos5250_drvdata,
141162306a36Sopenharmony_ci	}, {
141262306a36Sopenharmony_ci		.compatible = "samsung,exynos5420-gsc",
141362306a36Sopenharmony_ci		.data = &gsc_exynos5420_drvdata,
141462306a36Sopenharmony_ci	}, {
141562306a36Sopenharmony_ci		.compatible = "samsung,exynos5433-gsc",
141662306a36Sopenharmony_ci		.data = &gsc_exynos5433_drvdata,
141762306a36Sopenharmony_ci	}, {
141862306a36Sopenharmony_ci	},
141962306a36Sopenharmony_ci};
142062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, exynos_drm_gsc_of_match);
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_cistruct platform_driver gsc_driver = {
142362306a36Sopenharmony_ci	.probe		= gsc_probe,
142462306a36Sopenharmony_ci	.remove		= gsc_remove,
142562306a36Sopenharmony_ci	.driver		= {
142662306a36Sopenharmony_ci		.name	= "exynos-drm-gsc",
142762306a36Sopenharmony_ci		.owner	= THIS_MODULE,
142862306a36Sopenharmony_ci		.pm	= &gsc_pm_ops,
142962306a36Sopenharmony_ci		.of_match_table = exynos_drm_gsc_of_match,
143062306a36Sopenharmony_ci	},
143162306a36Sopenharmony_ci};
1432