xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/exynos/exynos_mixer.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2011 Samsung Electronics Co.Ltd
4*4882a593Smuzhiyun  * Authors:
5*4882a593Smuzhiyun  * Seung-Woo Kim <sw0312.kim@samsung.com>
6*4882a593Smuzhiyun  *	Inki Dae <inki.dae@samsung.com>
7*4882a593Smuzhiyun  *	Joonyoung Shim <jy0922.shim@samsung.com>
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Based on drivers/media/video/s5p-tv/mixer_reg.c
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <linux/clk.h>
13*4882a593Smuzhiyun #include <linux/component.h>
14*4882a593Smuzhiyun #include <linux/delay.h>
15*4882a593Smuzhiyun #include <linux/i2c.h>
16*4882a593Smuzhiyun #include <linux/interrupt.h>
17*4882a593Smuzhiyun #include <linux/irq.h>
18*4882a593Smuzhiyun #include <linux/kernel.h>
19*4882a593Smuzhiyun #include <linux/ktime.h>
20*4882a593Smuzhiyun #include <linux/of.h>
21*4882a593Smuzhiyun #include <linux/of_device.h>
22*4882a593Smuzhiyun #include <linux/platform_device.h>
23*4882a593Smuzhiyun #include <linux/pm_runtime.h>
24*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
25*4882a593Smuzhiyun #include <linux/spinlock.h>
26*4882a593Smuzhiyun #include <linux/wait.h>
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #include <drm/drm_fourcc.h>
29*4882a593Smuzhiyun #include <drm/drm_vblank.h>
30*4882a593Smuzhiyun #include <drm/exynos_drm.h>
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun #include "exynos_drm_crtc.h"
33*4882a593Smuzhiyun #include "exynos_drm_drv.h"
34*4882a593Smuzhiyun #include "exynos_drm_fb.h"
35*4882a593Smuzhiyun #include "exynos_drm_plane.h"
36*4882a593Smuzhiyun #include "regs-mixer.h"
37*4882a593Smuzhiyun #include "regs-vp.h"
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #define MIXER_WIN_NR		3
40*4882a593Smuzhiyun #define VP_DEFAULT_WIN		2
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun /*
43*4882a593Smuzhiyun  * Mixer color space conversion coefficient triplet.
44*4882a593Smuzhiyun  * Used for CSC from RGB to YCbCr.
45*4882a593Smuzhiyun  * Each coefficient is a 10-bit fixed point number with
46*4882a593Smuzhiyun  * sign and no integer part, i.e.
47*4882a593Smuzhiyun  * [0:8] = fractional part (representing a value y = x / 2^9)
48*4882a593Smuzhiyun  * [9] = sign
49*4882a593Smuzhiyun  * Negative values are encoded with two's complement.
50*4882a593Smuzhiyun  */
51*4882a593Smuzhiyun #define MXR_CSC_C(x) ((int)((x) * 512.0) & 0x3ff)
52*4882a593Smuzhiyun #define MXR_CSC_CT(a0, a1, a2) \
53*4882a593Smuzhiyun   ((MXR_CSC_C(a0) << 20) | (MXR_CSC_C(a1) << 10) | (MXR_CSC_C(a2) << 0))
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun /* YCbCr value, used for mixer background color configuration. */
56*4882a593Smuzhiyun #define MXR_YCBCR_VAL(y, cb, cr) (((y) << 16) | ((cb) << 8) | ((cr) << 0))
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun /* The pixelformats that are natively supported by the mixer. */
59*4882a593Smuzhiyun #define MXR_FORMAT_RGB565	4
60*4882a593Smuzhiyun #define MXR_FORMAT_ARGB1555	5
61*4882a593Smuzhiyun #define MXR_FORMAT_ARGB4444	6
62*4882a593Smuzhiyun #define MXR_FORMAT_ARGB8888	7
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun enum mixer_version_id {
65*4882a593Smuzhiyun 	MXR_VER_0_0_0_16,
66*4882a593Smuzhiyun 	MXR_VER_16_0_33_0,
67*4882a593Smuzhiyun 	MXR_VER_128_0_0_184,
68*4882a593Smuzhiyun };
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun enum mixer_flag_bits {
71*4882a593Smuzhiyun 	MXR_BIT_POWERED,
72*4882a593Smuzhiyun 	MXR_BIT_VSYNC,
73*4882a593Smuzhiyun 	MXR_BIT_INTERLACE,
74*4882a593Smuzhiyun 	MXR_BIT_VP_ENABLED,
75*4882a593Smuzhiyun 	MXR_BIT_HAS_SCLK,
76*4882a593Smuzhiyun };
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun static const uint32_t mixer_formats[] = {
79*4882a593Smuzhiyun 	DRM_FORMAT_XRGB4444,
80*4882a593Smuzhiyun 	DRM_FORMAT_ARGB4444,
81*4882a593Smuzhiyun 	DRM_FORMAT_XRGB1555,
82*4882a593Smuzhiyun 	DRM_FORMAT_ARGB1555,
83*4882a593Smuzhiyun 	DRM_FORMAT_RGB565,
84*4882a593Smuzhiyun 	DRM_FORMAT_XRGB8888,
85*4882a593Smuzhiyun 	DRM_FORMAT_ARGB8888,
86*4882a593Smuzhiyun };
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun static const uint32_t vp_formats[] = {
89*4882a593Smuzhiyun 	DRM_FORMAT_NV12,
90*4882a593Smuzhiyun 	DRM_FORMAT_NV21,
91*4882a593Smuzhiyun };
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun struct mixer_context {
94*4882a593Smuzhiyun 	struct platform_device *pdev;
95*4882a593Smuzhiyun 	struct device		*dev;
96*4882a593Smuzhiyun 	struct drm_device	*drm_dev;
97*4882a593Smuzhiyun 	void			*dma_priv;
98*4882a593Smuzhiyun 	struct exynos_drm_crtc	*crtc;
99*4882a593Smuzhiyun 	struct exynos_drm_plane	planes[MIXER_WIN_NR];
100*4882a593Smuzhiyun 	unsigned long		flags;
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	int			irq;
103*4882a593Smuzhiyun 	void __iomem		*mixer_regs;
104*4882a593Smuzhiyun 	void __iomem		*vp_regs;
105*4882a593Smuzhiyun 	spinlock_t		reg_slock;
106*4882a593Smuzhiyun 	struct clk		*mixer;
107*4882a593Smuzhiyun 	struct clk		*vp;
108*4882a593Smuzhiyun 	struct clk		*hdmi;
109*4882a593Smuzhiyun 	struct clk		*sclk_mixer;
110*4882a593Smuzhiyun 	struct clk		*sclk_hdmi;
111*4882a593Smuzhiyun 	struct clk		*mout_mixer;
112*4882a593Smuzhiyun 	enum mixer_version_id	mxr_ver;
113*4882a593Smuzhiyun 	int			scan_value;
114*4882a593Smuzhiyun };
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun struct mixer_drv_data {
117*4882a593Smuzhiyun 	enum mixer_version_id	version;
118*4882a593Smuzhiyun 	bool					is_vp_enabled;
119*4882a593Smuzhiyun 	bool					has_sclk;
120*4882a593Smuzhiyun };
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun static const struct exynos_drm_plane_config plane_configs[MIXER_WIN_NR] = {
123*4882a593Smuzhiyun 	{
124*4882a593Smuzhiyun 		.zpos = 0,
125*4882a593Smuzhiyun 		.type = DRM_PLANE_TYPE_PRIMARY,
126*4882a593Smuzhiyun 		.pixel_formats = mixer_formats,
127*4882a593Smuzhiyun 		.num_pixel_formats = ARRAY_SIZE(mixer_formats),
128*4882a593Smuzhiyun 		.capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE |
129*4882a593Smuzhiyun 				EXYNOS_DRM_PLANE_CAP_ZPOS |
130*4882a593Smuzhiyun 				EXYNOS_DRM_PLANE_CAP_PIX_BLEND |
131*4882a593Smuzhiyun 				EXYNOS_DRM_PLANE_CAP_WIN_BLEND,
132*4882a593Smuzhiyun 	}, {
133*4882a593Smuzhiyun 		.zpos = 1,
134*4882a593Smuzhiyun 		.type = DRM_PLANE_TYPE_CURSOR,
135*4882a593Smuzhiyun 		.pixel_formats = mixer_formats,
136*4882a593Smuzhiyun 		.num_pixel_formats = ARRAY_SIZE(mixer_formats),
137*4882a593Smuzhiyun 		.capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE |
138*4882a593Smuzhiyun 				EXYNOS_DRM_PLANE_CAP_ZPOS |
139*4882a593Smuzhiyun 				EXYNOS_DRM_PLANE_CAP_PIX_BLEND |
140*4882a593Smuzhiyun 				EXYNOS_DRM_PLANE_CAP_WIN_BLEND,
141*4882a593Smuzhiyun 	}, {
142*4882a593Smuzhiyun 		.zpos = 2,
143*4882a593Smuzhiyun 		.type = DRM_PLANE_TYPE_OVERLAY,
144*4882a593Smuzhiyun 		.pixel_formats = vp_formats,
145*4882a593Smuzhiyun 		.num_pixel_formats = ARRAY_SIZE(vp_formats),
146*4882a593Smuzhiyun 		.capabilities = EXYNOS_DRM_PLANE_CAP_SCALE |
147*4882a593Smuzhiyun 				EXYNOS_DRM_PLANE_CAP_ZPOS |
148*4882a593Smuzhiyun 				EXYNOS_DRM_PLANE_CAP_TILE |
149*4882a593Smuzhiyun 				EXYNOS_DRM_PLANE_CAP_WIN_BLEND,
150*4882a593Smuzhiyun 	},
151*4882a593Smuzhiyun };
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun static const u8 filter_y_horiz_tap8[] = {
154*4882a593Smuzhiyun 	0,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
155*4882a593Smuzhiyun 	-1,	-1,	-1,	-1,	-1,	0,	0,	0,
156*4882a593Smuzhiyun 	0,	2,	4,	5,	6,	6,	6,	6,
157*4882a593Smuzhiyun 	6,	5,	5,	4,	3,	2,	1,	1,
158*4882a593Smuzhiyun 	0,	-6,	-12,	-16,	-18,	-20,	-21,	-20,
159*4882a593Smuzhiyun 	-20,	-18,	-16,	-13,	-10,	-8,	-5,	-2,
160*4882a593Smuzhiyun 	127,	126,	125,	121,	114,	107,	99,	89,
161*4882a593Smuzhiyun 	79,	68,	57,	46,	35,	25,	16,	8,
162*4882a593Smuzhiyun };
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun static const u8 filter_y_vert_tap4[] = {
165*4882a593Smuzhiyun 	0,	-3,	-6,	-8,	-8,	-8,	-8,	-7,
166*4882a593Smuzhiyun 	-6,	-5,	-4,	-3,	-2,	-1,	-1,	0,
167*4882a593Smuzhiyun 	127,	126,	124,	118,	111,	102,	92,	81,
168*4882a593Smuzhiyun 	70,	59,	48,	37,	27,	19,	11,	5,
169*4882a593Smuzhiyun 	0,	5,	11,	19,	27,	37,	48,	59,
170*4882a593Smuzhiyun 	70,	81,	92,	102,	111,	118,	124,	126,
171*4882a593Smuzhiyun 	0,	0,	-1,	-1,	-2,	-3,	-4,	-5,
172*4882a593Smuzhiyun 	-6,	-7,	-8,	-8,	-8,	-8,	-6,	-3,
173*4882a593Smuzhiyun };
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun static const u8 filter_cr_horiz_tap4[] = {
176*4882a593Smuzhiyun 	0,	-3,	-6,	-8,	-8,	-8,	-8,	-7,
177*4882a593Smuzhiyun 	-6,	-5,	-4,	-3,	-2,	-1,	-1,	0,
178*4882a593Smuzhiyun 	127,	126,	124,	118,	111,	102,	92,	81,
179*4882a593Smuzhiyun 	70,	59,	48,	37,	27,	19,	11,	5,
180*4882a593Smuzhiyun };
181*4882a593Smuzhiyun 
vp_reg_read(struct mixer_context * ctx,u32 reg_id)182*4882a593Smuzhiyun static inline u32 vp_reg_read(struct mixer_context *ctx, u32 reg_id)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun 	return readl(ctx->vp_regs + reg_id);
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun 
vp_reg_write(struct mixer_context * ctx,u32 reg_id,u32 val)187*4882a593Smuzhiyun static inline void vp_reg_write(struct mixer_context *ctx, u32 reg_id,
188*4882a593Smuzhiyun 				 u32 val)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun 	writel(val, ctx->vp_regs + reg_id);
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun 
vp_reg_writemask(struct mixer_context * ctx,u32 reg_id,u32 val,u32 mask)193*4882a593Smuzhiyun static inline void vp_reg_writemask(struct mixer_context *ctx, u32 reg_id,
194*4882a593Smuzhiyun 				 u32 val, u32 mask)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun 	u32 old = vp_reg_read(ctx, reg_id);
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	val = (val & mask) | (old & ~mask);
199*4882a593Smuzhiyun 	writel(val, ctx->vp_regs + reg_id);
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun 
mixer_reg_read(struct mixer_context * ctx,u32 reg_id)202*4882a593Smuzhiyun static inline u32 mixer_reg_read(struct mixer_context *ctx, u32 reg_id)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun 	return readl(ctx->mixer_regs + reg_id);
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun 
mixer_reg_write(struct mixer_context * ctx,u32 reg_id,u32 val)207*4882a593Smuzhiyun static inline void mixer_reg_write(struct mixer_context *ctx, u32 reg_id,
208*4882a593Smuzhiyun 				 u32 val)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun 	writel(val, ctx->mixer_regs + reg_id);
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun 
mixer_reg_writemask(struct mixer_context * ctx,u32 reg_id,u32 val,u32 mask)213*4882a593Smuzhiyun static inline void mixer_reg_writemask(struct mixer_context *ctx,
214*4882a593Smuzhiyun 				 u32 reg_id, u32 val, u32 mask)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun 	u32 old = mixer_reg_read(ctx, reg_id);
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	val = (val & mask) | (old & ~mask);
219*4882a593Smuzhiyun 	writel(val, ctx->mixer_regs + reg_id);
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun 
mixer_regs_dump(struct mixer_context * ctx)222*4882a593Smuzhiyun static void mixer_regs_dump(struct mixer_context *ctx)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun #define DUMPREG(reg_id) \
225*4882a593Smuzhiyun do { \
226*4882a593Smuzhiyun 	DRM_DEV_DEBUG_KMS(ctx->dev, #reg_id " = %08x\n", \
227*4882a593Smuzhiyun 			 (u32)readl(ctx->mixer_regs + reg_id)); \
228*4882a593Smuzhiyun } while (0)
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	DUMPREG(MXR_STATUS);
231*4882a593Smuzhiyun 	DUMPREG(MXR_CFG);
232*4882a593Smuzhiyun 	DUMPREG(MXR_INT_EN);
233*4882a593Smuzhiyun 	DUMPREG(MXR_INT_STATUS);
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	DUMPREG(MXR_LAYER_CFG);
236*4882a593Smuzhiyun 	DUMPREG(MXR_VIDEO_CFG);
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	DUMPREG(MXR_GRAPHIC0_CFG);
239*4882a593Smuzhiyun 	DUMPREG(MXR_GRAPHIC0_BASE);
240*4882a593Smuzhiyun 	DUMPREG(MXR_GRAPHIC0_SPAN);
241*4882a593Smuzhiyun 	DUMPREG(MXR_GRAPHIC0_WH);
242*4882a593Smuzhiyun 	DUMPREG(MXR_GRAPHIC0_SXY);
243*4882a593Smuzhiyun 	DUMPREG(MXR_GRAPHIC0_DXY);
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	DUMPREG(MXR_GRAPHIC1_CFG);
246*4882a593Smuzhiyun 	DUMPREG(MXR_GRAPHIC1_BASE);
247*4882a593Smuzhiyun 	DUMPREG(MXR_GRAPHIC1_SPAN);
248*4882a593Smuzhiyun 	DUMPREG(MXR_GRAPHIC1_WH);
249*4882a593Smuzhiyun 	DUMPREG(MXR_GRAPHIC1_SXY);
250*4882a593Smuzhiyun 	DUMPREG(MXR_GRAPHIC1_DXY);
251*4882a593Smuzhiyun #undef DUMPREG
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun 
vp_regs_dump(struct mixer_context * ctx)254*4882a593Smuzhiyun static void vp_regs_dump(struct mixer_context *ctx)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun #define DUMPREG(reg_id) \
257*4882a593Smuzhiyun do { \
258*4882a593Smuzhiyun 	DRM_DEV_DEBUG_KMS(ctx->dev, #reg_id " = %08x\n", \
259*4882a593Smuzhiyun 			 (u32) readl(ctx->vp_regs + reg_id)); \
260*4882a593Smuzhiyun } while (0)
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	DUMPREG(VP_ENABLE);
263*4882a593Smuzhiyun 	DUMPREG(VP_SRESET);
264*4882a593Smuzhiyun 	DUMPREG(VP_SHADOW_UPDATE);
265*4882a593Smuzhiyun 	DUMPREG(VP_FIELD_ID);
266*4882a593Smuzhiyun 	DUMPREG(VP_MODE);
267*4882a593Smuzhiyun 	DUMPREG(VP_IMG_SIZE_Y);
268*4882a593Smuzhiyun 	DUMPREG(VP_IMG_SIZE_C);
269*4882a593Smuzhiyun 	DUMPREG(VP_PER_RATE_CTRL);
270*4882a593Smuzhiyun 	DUMPREG(VP_TOP_Y_PTR);
271*4882a593Smuzhiyun 	DUMPREG(VP_BOT_Y_PTR);
272*4882a593Smuzhiyun 	DUMPREG(VP_TOP_C_PTR);
273*4882a593Smuzhiyun 	DUMPREG(VP_BOT_C_PTR);
274*4882a593Smuzhiyun 	DUMPREG(VP_ENDIAN_MODE);
275*4882a593Smuzhiyun 	DUMPREG(VP_SRC_H_POSITION);
276*4882a593Smuzhiyun 	DUMPREG(VP_SRC_V_POSITION);
277*4882a593Smuzhiyun 	DUMPREG(VP_SRC_WIDTH);
278*4882a593Smuzhiyun 	DUMPREG(VP_SRC_HEIGHT);
279*4882a593Smuzhiyun 	DUMPREG(VP_DST_H_POSITION);
280*4882a593Smuzhiyun 	DUMPREG(VP_DST_V_POSITION);
281*4882a593Smuzhiyun 	DUMPREG(VP_DST_WIDTH);
282*4882a593Smuzhiyun 	DUMPREG(VP_DST_HEIGHT);
283*4882a593Smuzhiyun 	DUMPREG(VP_H_RATIO);
284*4882a593Smuzhiyun 	DUMPREG(VP_V_RATIO);
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun #undef DUMPREG
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun 
vp_filter_set(struct mixer_context * ctx,int reg_id,const u8 * data,unsigned int size)289*4882a593Smuzhiyun static inline void vp_filter_set(struct mixer_context *ctx,
290*4882a593Smuzhiyun 		int reg_id, const u8 *data, unsigned int size)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun 	/* assure 4-byte align */
293*4882a593Smuzhiyun 	BUG_ON(size & 3);
294*4882a593Smuzhiyun 	for (; size; size -= 4, reg_id += 4, data += 4) {
295*4882a593Smuzhiyun 		u32 val = (data[0] << 24) |  (data[1] << 16) |
296*4882a593Smuzhiyun 			(data[2] << 8) | data[3];
297*4882a593Smuzhiyun 		vp_reg_write(ctx, reg_id, val);
298*4882a593Smuzhiyun 	}
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun 
vp_default_filter(struct mixer_context * ctx)301*4882a593Smuzhiyun static void vp_default_filter(struct mixer_context *ctx)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun 	vp_filter_set(ctx, VP_POLY8_Y0_LL,
304*4882a593Smuzhiyun 		filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
305*4882a593Smuzhiyun 	vp_filter_set(ctx, VP_POLY4_Y0_LL,
306*4882a593Smuzhiyun 		filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
307*4882a593Smuzhiyun 	vp_filter_set(ctx, VP_POLY4_C0_LL,
308*4882a593Smuzhiyun 		filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun 
mixer_cfg_gfx_blend(struct mixer_context * ctx,unsigned int win,unsigned int pixel_alpha,unsigned int alpha)311*4882a593Smuzhiyun static void mixer_cfg_gfx_blend(struct mixer_context *ctx, unsigned int win,
312*4882a593Smuzhiyun 				unsigned int pixel_alpha, unsigned int alpha)
313*4882a593Smuzhiyun {
314*4882a593Smuzhiyun 	u32 win_alpha = alpha >> 8;
315*4882a593Smuzhiyun 	u32 val;
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	val  = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
318*4882a593Smuzhiyun 	switch (pixel_alpha) {
319*4882a593Smuzhiyun 	case DRM_MODE_BLEND_PIXEL_NONE:
320*4882a593Smuzhiyun 		break;
321*4882a593Smuzhiyun 	case DRM_MODE_BLEND_COVERAGE:
322*4882a593Smuzhiyun 		val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
323*4882a593Smuzhiyun 		break;
324*4882a593Smuzhiyun 	case DRM_MODE_BLEND_PREMULTI:
325*4882a593Smuzhiyun 	default:
326*4882a593Smuzhiyun 		val |= MXR_GRP_CFG_BLEND_PRE_MUL;
327*4882a593Smuzhiyun 		val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
328*4882a593Smuzhiyun 		break;
329*4882a593Smuzhiyun 	}
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	if (alpha != DRM_BLEND_ALPHA_OPAQUE) {
332*4882a593Smuzhiyun 		val |= MXR_GRP_CFG_WIN_BLEND_EN;
333*4882a593Smuzhiyun 		val |= win_alpha;
334*4882a593Smuzhiyun 	}
335*4882a593Smuzhiyun 	mixer_reg_writemask(ctx, MXR_GRAPHIC_CFG(win),
336*4882a593Smuzhiyun 			    val, MXR_GRP_CFG_MISC_MASK);
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun 
mixer_cfg_vp_blend(struct mixer_context * ctx,unsigned int alpha)339*4882a593Smuzhiyun static void mixer_cfg_vp_blend(struct mixer_context *ctx, unsigned int alpha)
340*4882a593Smuzhiyun {
341*4882a593Smuzhiyun 	u32 win_alpha = alpha >> 8;
342*4882a593Smuzhiyun 	u32 val = 0;
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	if (alpha != DRM_BLEND_ALPHA_OPAQUE) {
345*4882a593Smuzhiyun 		val |= MXR_VID_CFG_BLEND_EN;
346*4882a593Smuzhiyun 		val |= win_alpha;
347*4882a593Smuzhiyun 	}
348*4882a593Smuzhiyun 	mixer_reg_write(ctx, MXR_VIDEO_CFG, val);
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun 
mixer_is_synced(struct mixer_context * ctx)351*4882a593Smuzhiyun static bool mixer_is_synced(struct mixer_context *ctx)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun 	u32 base, shadow;
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
356*4882a593Smuzhiyun 	    ctx->mxr_ver == MXR_VER_128_0_0_184)
357*4882a593Smuzhiyun 		return !(mixer_reg_read(ctx, MXR_CFG) &
358*4882a593Smuzhiyun 			 MXR_CFG_LAYER_UPDATE_COUNT_MASK);
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags) &&
361*4882a593Smuzhiyun 	    vp_reg_read(ctx, VP_SHADOW_UPDATE))
362*4882a593Smuzhiyun 		return false;
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 	base = mixer_reg_read(ctx, MXR_CFG);
365*4882a593Smuzhiyun 	shadow = mixer_reg_read(ctx, MXR_CFG_S);
366*4882a593Smuzhiyun 	if (base != shadow)
367*4882a593Smuzhiyun 		return false;
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(0));
370*4882a593Smuzhiyun 	shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(0));
371*4882a593Smuzhiyun 	if (base != shadow)
372*4882a593Smuzhiyun 		return false;
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(1));
375*4882a593Smuzhiyun 	shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(1));
376*4882a593Smuzhiyun 	if (base != shadow)
377*4882a593Smuzhiyun 		return false;
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	return true;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun 
mixer_wait_for_sync(struct mixer_context * ctx)382*4882a593Smuzhiyun static int mixer_wait_for_sync(struct mixer_context *ctx)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun 	ktime_t timeout = ktime_add_us(ktime_get(), 100000);
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	while (!mixer_is_synced(ctx)) {
387*4882a593Smuzhiyun 		usleep_range(1000, 2000);
388*4882a593Smuzhiyun 		if (ktime_compare(ktime_get(), timeout) > 0)
389*4882a593Smuzhiyun 			return -ETIMEDOUT;
390*4882a593Smuzhiyun 	}
391*4882a593Smuzhiyun 	return 0;
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun 
mixer_disable_sync(struct mixer_context * ctx)394*4882a593Smuzhiyun static void mixer_disable_sync(struct mixer_context *ctx)
395*4882a593Smuzhiyun {
396*4882a593Smuzhiyun 	mixer_reg_writemask(ctx, MXR_STATUS, 0, MXR_STATUS_SYNC_ENABLE);
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun 
mixer_enable_sync(struct mixer_context * ctx)399*4882a593Smuzhiyun static void mixer_enable_sync(struct mixer_context *ctx)
400*4882a593Smuzhiyun {
401*4882a593Smuzhiyun 	if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
402*4882a593Smuzhiyun 	    ctx->mxr_ver == MXR_VER_128_0_0_184)
403*4882a593Smuzhiyun 		mixer_reg_writemask(ctx, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
404*4882a593Smuzhiyun 	mixer_reg_writemask(ctx, MXR_STATUS, ~0, MXR_STATUS_SYNC_ENABLE);
405*4882a593Smuzhiyun 	if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags))
406*4882a593Smuzhiyun 		vp_reg_write(ctx, VP_SHADOW_UPDATE, VP_SHADOW_UPDATE_ENABLE);
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun 
mixer_cfg_scan(struct mixer_context * ctx,int width,int height)409*4882a593Smuzhiyun static void mixer_cfg_scan(struct mixer_context *ctx, int width, int height)
410*4882a593Smuzhiyun {
411*4882a593Smuzhiyun 	u32 val;
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	/* choosing between interlace and progressive mode */
414*4882a593Smuzhiyun 	val = test_bit(MXR_BIT_INTERLACE, &ctx->flags) ?
415*4882a593Smuzhiyun 		MXR_CFG_SCAN_INTERLACE : MXR_CFG_SCAN_PROGRESSIVE;
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	if (ctx->mxr_ver == MXR_VER_128_0_0_184)
418*4882a593Smuzhiyun 		mixer_reg_write(ctx, MXR_RESOLUTION,
419*4882a593Smuzhiyun 			MXR_MXR_RES_HEIGHT(height) | MXR_MXR_RES_WIDTH(width));
420*4882a593Smuzhiyun 	else
421*4882a593Smuzhiyun 		val |= ctx->scan_value;
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	mixer_reg_writemask(ctx, MXR_CFG, val, MXR_CFG_SCAN_MASK);
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun 
mixer_cfg_rgb_fmt(struct mixer_context * ctx,struct drm_display_mode * mode)426*4882a593Smuzhiyun static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, struct drm_display_mode *mode)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun 	enum hdmi_quantization_range range = drm_default_rgb_quant_range(mode);
429*4882a593Smuzhiyun 	u32 val;
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	if (mode->vdisplay < 720) {
432*4882a593Smuzhiyun 		val = MXR_CFG_RGB601;
433*4882a593Smuzhiyun 	} else {
434*4882a593Smuzhiyun 		val = MXR_CFG_RGB709;
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 		/* Configure the BT.709 CSC matrix for full range RGB. */
437*4882a593Smuzhiyun 		mixer_reg_write(ctx, MXR_CM_COEFF_Y,
438*4882a593Smuzhiyun 			MXR_CSC_CT( 0.184,  0.614,  0.063) |
439*4882a593Smuzhiyun 			MXR_CM_COEFF_RGB_FULL);
440*4882a593Smuzhiyun 		mixer_reg_write(ctx, MXR_CM_COEFF_CB,
441*4882a593Smuzhiyun 			MXR_CSC_CT(-0.102, -0.338,  0.440));
442*4882a593Smuzhiyun 		mixer_reg_write(ctx, MXR_CM_COEFF_CR,
443*4882a593Smuzhiyun 			MXR_CSC_CT( 0.440, -0.399, -0.040));
444*4882a593Smuzhiyun 	}
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	if (range == HDMI_QUANTIZATION_RANGE_FULL)
447*4882a593Smuzhiyun 		val |= MXR_CFG_QUANT_RANGE_FULL;
448*4882a593Smuzhiyun 	else
449*4882a593Smuzhiyun 		val |= MXR_CFG_QUANT_RANGE_LIMITED;
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	mixer_reg_writemask(ctx, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun 
mixer_cfg_layer(struct mixer_context * ctx,unsigned int win,unsigned int priority,bool enable)454*4882a593Smuzhiyun static void mixer_cfg_layer(struct mixer_context *ctx, unsigned int win,
455*4882a593Smuzhiyun 			    unsigned int priority, bool enable)
456*4882a593Smuzhiyun {
457*4882a593Smuzhiyun 	u32 val = enable ? ~0 : 0;
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	switch (win) {
460*4882a593Smuzhiyun 	case 0:
461*4882a593Smuzhiyun 		mixer_reg_writemask(ctx, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
462*4882a593Smuzhiyun 		mixer_reg_writemask(ctx, MXR_LAYER_CFG,
463*4882a593Smuzhiyun 				    MXR_LAYER_CFG_GRP0_VAL(priority),
464*4882a593Smuzhiyun 				    MXR_LAYER_CFG_GRP0_MASK);
465*4882a593Smuzhiyun 		break;
466*4882a593Smuzhiyun 	case 1:
467*4882a593Smuzhiyun 		mixer_reg_writemask(ctx, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
468*4882a593Smuzhiyun 		mixer_reg_writemask(ctx, MXR_LAYER_CFG,
469*4882a593Smuzhiyun 				    MXR_LAYER_CFG_GRP1_VAL(priority),
470*4882a593Smuzhiyun 				    MXR_LAYER_CFG_GRP1_MASK);
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 		break;
473*4882a593Smuzhiyun 	case VP_DEFAULT_WIN:
474*4882a593Smuzhiyun 		if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
475*4882a593Smuzhiyun 			vp_reg_writemask(ctx, VP_ENABLE, val, VP_ENABLE_ON);
476*4882a593Smuzhiyun 			mixer_reg_writemask(ctx, MXR_CFG, val,
477*4882a593Smuzhiyun 				MXR_CFG_VP_ENABLE);
478*4882a593Smuzhiyun 			mixer_reg_writemask(ctx, MXR_LAYER_CFG,
479*4882a593Smuzhiyun 					    MXR_LAYER_CFG_VP_VAL(priority),
480*4882a593Smuzhiyun 					    MXR_LAYER_CFG_VP_MASK);
481*4882a593Smuzhiyun 		}
482*4882a593Smuzhiyun 		break;
483*4882a593Smuzhiyun 	}
484*4882a593Smuzhiyun }
485*4882a593Smuzhiyun 
mixer_run(struct mixer_context * ctx)486*4882a593Smuzhiyun static void mixer_run(struct mixer_context *ctx)
487*4882a593Smuzhiyun {
488*4882a593Smuzhiyun 	mixer_reg_writemask(ctx, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun 
mixer_stop(struct mixer_context * ctx)491*4882a593Smuzhiyun static void mixer_stop(struct mixer_context *ctx)
492*4882a593Smuzhiyun {
493*4882a593Smuzhiyun 	int timeout = 20;
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	mixer_reg_writemask(ctx, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun 	while (!(mixer_reg_read(ctx, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
498*4882a593Smuzhiyun 			--timeout)
499*4882a593Smuzhiyun 		usleep_range(10000, 12000);
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun 
mixer_commit(struct mixer_context * ctx)502*4882a593Smuzhiyun static void mixer_commit(struct mixer_context *ctx)
503*4882a593Smuzhiyun {
504*4882a593Smuzhiyun 	struct drm_display_mode *mode = &ctx->crtc->base.state->adjusted_mode;
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	mixer_cfg_scan(ctx, mode->hdisplay, mode->vdisplay);
507*4882a593Smuzhiyun 	mixer_cfg_rgb_fmt(ctx, mode);
508*4882a593Smuzhiyun 	mixer_run(ctx);
509*4882a593Smuzhiyun }
510*4882a593Smuzhiyun 
vp_video_buffer(struct mixer_context * ctx,struct exynos_drm_plane * plane)511*4882a593Smuzhiyun static void vp_video_buffer(struct mixer_context *ctx,
512*4882a593Smuzhiyun 			    struct exynos_drm_plane *plane)
513*4882a593Smuzhiyun {
514*4882a593Smuzhiyun 	struct exynos_drm_plane_state *state =
515*4882a593Smuzhiyun 				to_exynos_plane_state(plane->base.state);
516*4882a593Smuzhiyun 	struct drm_framebuffer *fb = state->base.fb;
517*4882a593Smuzhiyun 	unsigned int priority = state->base.normalized_zpos + 1;
518*4882a593Smuzhiyun 	unsigned long flags;
519*4882a593Smuzhiyun 	dma_addr_t luma_addr[2], chroma_addr[2];
520*4882a593Smuzhiyun 	bool is_tiled, is_nv21;
521*4882a593Smuzhiyun 	u32 val;
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	is_nv21 = (fb->format->format == DRM_FORMAT_NV21);
524*4882a593Smuzhiyun 	is_tiled = (fb->modifier == DRM_FORMAT_MOD_SAMSUNG_64_32_TILE);
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	luma_addr[0] = exynos_drm_fb_dma_addr(fb, 0);
527*4882a593Smuzhiyun 	chroma_addr[0] = exynos_drm_fb_dma_addr(fb, 1);
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
530*4882a593Smuzhiyun 		if (is_tiled) {
531*4882a593Smuzhiyun 			luma_addr[1] = luma_addr[0] + 0x40;
532*4882a593Smuzhiyun 			chroma_addr[1] = chroma_addr[0] + 0x40;
533*4882a593Smuzhiyun 		} else {
534*4882a593Smuzhiyun 			luma_addr[1] = luma_addr[0] + fb->pitches[0];
535*4882a593Smuzhiyun 			chroma_addr[1] = chroma_addr[0] + fb->pitches[1];
536*4882a593Smuzhiyun 		}
537*4882a593Smuzhiyun 	} else {
538*4882a593Smuzhiyun 		luma_addr[1] = 0;
539*4882a593Smuzhiyun 		chroma_addr[1] = 0;
540*4882a593Smuzhiyun 	}
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 	spin_lock_irqsave(&ctx->reg_slock, flags);
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	/* interlace or progressive scan mode */
545*4882a593Smuzhiyun 	val = (test_bit(MXR_BIT_INTERLACE, &ctx->flags) ? ~0 : 0);
546*4882a593Smuzhiyun 	vp_reg_writemask(ctx, VP_MODE, val, VP_MODE_LINE_SKIP);
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	/* setup format */
549*4882a593Smuzhiyun 	val = (is_nv21 ? VP_MODE_NV21 : VP_MODE_NV12);
550*4882a593Smuzhiyun 	val |= (is_tiled ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
551*4882a593Smuzhiyun 	vp_reg_writemask(ctx, VP_MODE, val, VP_MODE_FMT_MASK);
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	/* setting size of input image */
554*4882a593Smuzhiyun 	vp_reg_write(ctx, VP_IMG_SIZE_Y, VP_IMG_HSIZE(fb->pitches[0]) |
555*4882a593Smuzhiyun 		VP_IMG_VSIZE(fb->height));
556*4882a593Smuzhiyun 	/* chroma plane for NV12/NV21 is half the height of the luma plane */
557*4882a593Smuzhiyun 	vp_reg_write(ctx, VP_IMG_SIZE_C, VP_IMG_HSIZE(fb->pitches[1]) |
558*4882a593Smuzhiyun 		VP_IMG_VSIZE(fb->height / 2));
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	vp_reg_write(ctx, VP_SRC_WIDTH, state->src.w);
561*4882a593Smuzhiyun 	vp_reg_write(ctx, VP_SRC_H_POSITION,
562*4882a593Smuzhiyun 			VP_SRC_H_POSITION_VAL(state->src.x));
563*4882a593Smuzhiyun 	vp_reg_write(ctx, VP_DST_WIDTH, state->crtc.w);
564*4882a593Smuzhiyun 	vp_reg_write(ctx, VP_DST_H_POSITION, state->crtc.x);
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
567*4882a593Smuzhiyun 		vp_reg_write(ctx, VP_SRC_HEIGHT, state->src.h / 2);
568*4882a593Smuzhiyun 		vp_reg_write(ctx, VP_SRC_V_POSITION, state->src.y / 2);
569*4882a593Smuzhiyun 		vp_reg_write(ctx, VP_DST_HEIGHT, state->crtc.h / 2);
570*4882a593Smuzhiyun 		vp_reg_write(ctx, VP_DST_V_POSITION, state->crtc.y / 2);
571*4882a593Smuzhiyun 	} else {
572*4882a593Smuzhiyun 		vp_reg_write(ctx, VP_SRC_HEIGHT, state->src.h);
573*4882a593Smuzhiyun 		vp_reg_write(ctx, VP_SRC_V_POSITION, state->src.y);
574*4882a593Smuzhiyun 		vp_reg_write(ctx, VP_DST_HEIGHT, state->crtc.h);
575*4882a593Smuzhiyun 		vp_reg_write(ctx, VP_DST_V_POSITION, state->crtc.y);
576*4882a593Smuzhiyun 	}
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun 	vp_reg_write(ctx, VP_H_RATIO, state->h_ratio);
579*4882a593Smuzhiyun 	vp_reg_write(ctx, VP_V_RATIO, state->v_ratio);
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	vp_reg_write(ctx, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 	/* set buffer address to vp */
584*4882a593Smuzhiyun 	vp_reg_write(ctx, VP_TOP_Y_PTR, luma_addr[0]);
585*4882a593Smuzhiyun 	vp_reg_write(ctx, VP_BOT_Y_PTR, luma_addr[1]);
586*4882a593Smuzhiyun 	vp_reg_write(ctx, VP_TOP_C_PTR, chroma_addr[0]);
587*4882a593Smuzhiyun 	vp_reg_write(ctx, VP_BOT_C_PTR, chroma_addr[1]);
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	mixer_cfg_layer(ctx, plane->index, priority, true);
590*4882a593Smuzhiyun 	mixer_cfg_vp_blend(ctx, state->base.alpha);
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ctx->reg_slock, flags);
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun 	mixer_regs_dump(ctx);
595*4882a593Smuzhiyun 	vp_regs_dump(ctx);
596*4882a593Smuzhiyun }
597*4882a593Smuzhiyun 
mixer_graph_buffer(struct mixer_context * ctx,struct exynos_drm_plane * plane)598*4882a593Smuzhiyun static void mixer_graph_buffer(struct mixer_context *ctx,
599*4882a593Smuzhiyun 			       struct exynos_drm_plane *plane)
600*4882a593Smuzhiyun {
601*4882a593Smuzhiyun 	struct exynos_drm_plane_state *state =
602*4882a593Smuzhiyun 				to_exynos_plane_state(plane->base.state);
603*4882a593Smuzhiyun 	struct drm_framebuffer *fb = state->base.fb;
604*4882a593Smuzhiyun 	unsigned int priority = state->base.normalized_zpos + 1;
605*4882a593Smuzhiyun 	unsigned long flags;
606*4882a593Smuzhiyun 	unsigned int win = plane->index;
607*4882a593Smuzhiyun 	unsigned int x_ratio = 0, y_ratio = 0;
608*4882a593Smuzhiyun 	unsigned int dst_x_offset, dst_y_offset;
609*4882a593Smuzhiyun 	unsigned int pixel_alpha;
610*4882a593Smuzhiyun 	dma_addr_t dma_addr;
611*4882a593Smuzhiyun 	unsigned int fmt;
612*4882a593Smuzhiyun 	u32 val;
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 	if (fb->format->has_alpha)
615*4882a593Smuzhiyun 		pixel_alpha = state->base.pixel_blend_mode;
616*4882a593Smuzhiyun 	else
617*4882a593Smuzhiyun 		pixel_alpha = DRM_MODE_BLEND_PIXEL_NONE;
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun 	switch (fb->format->format) {
620*4882a593Smuzhiyun 	case DRM_FORMAT_XRGB4444:
621*4882a593Smuzhiyun 	case DRM_FORMAT_ARGB4444:
622*4882a593Smuzhiyun 		fmt = MXR_FORMAT_ARGB4444;
623*4882a593Smuzhiyun 		break;
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	case DRM_FORMAT_XRGB1555:
626*4882a593Smuzhiyun 	case DRM_FORMAT_ARGB1555:
627*4882a593Smuzhiyun 		fmt = MXR_FORMAT_ARGB1555;
628*4882a593Smuzhiyun 		break;
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 	case DRM_FORMAT_RGB565:
631*4882a593Smuzhiyun 		fmt = MXR_FORMAT_RGB565;
632*4882a593Smuzhiyun 		break;
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	case DRM_FORMAT_XRGB8888:
635*4882a593Smuzhiyun 	case DRM_FORMAT_ARGB8888:
636*4882a593Smuzhiyun 	default:
637*4882a593Smuzhiyun 		fmt = MXR_FORMAT_ARGB8888;
638*4882a593Smuzhiyun 		break;
639*4882a593Smuzhiyun 	}
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 	/* ratio is already checked by common plane code */
642*4882a593Smuzhiyun 	x_ratio = state->h_ratio == (1 << 15);
643*4882a593Smuzhiyun 	y_ratio = state->v_ratio == (1 << 15);
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 	dst_x_offset = state->crtc.x;
646*4882a593Smuzhiyun 	dst_y_offset = state->crtc.y;
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 	/* translate dma address base s.t. the source image offset is zero */
649*4882a593Smuzhiyun 	dma_addr = exynos_drm_fb_dma_addr(fb, 0)
650*4882a593Smuzhiyun 		+ (state->src.x * fb->format->cpp[0])
651*4882a593Smuzhiyun 		+ (state->src.y * fb->pitches[0]);
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 	spin_lock_irqsave(&ctx->reg_slock, flags);
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	/* setup format */
656*4882a593Smuzhiyun 	mixer_reg_writemask(ctx, MXR_GRAPHIC_CFG(win),
657*4882a593Smuzhiyun 		MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun 	/* setup geometry */
660*4882a593Smuzhiyun 	mixer_reg_write(ctx, MXR_GRAPHIC_SPAN(win),
661*4882a593Smuzhiyun 			fb->pitches[0] / fb->format->cpp[0]);
662*4882a593Smuzhiyun 
663*4882a593Smuzhiyun 	val  = MXR_GRP_WH_WIDTH(state->src.w);
664*4882a593Smuzhiyun 	val |= MXR_GRP_WH_HEIGHT(state->src.h);
665*4882a593Smuzhiyun 	val |= MXR_GRP_WH_H_SCALE(x_ratio);
666*4882a593Smuzhiyun 	val |= MXR_GRP_WH_V_SCALE(y_ratio);
667*4882a593Smuzhiyun 	mixer_reg_write(ctx, MXR_GRAPHIC_WH(win), val);
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 	/* setup offsets in display image */
670*4882a593Smuzhiyun 	val  = MXR_GRP_DXY_DX(dst_x_offset);
671*4882a593Smuzhiyun 	val |= MXR_GRP_DXY_DY(dst_y_offset);
672*4882a593Smuzhiyun 	mixer_reg_write(ctx, MXR_GRAPHIC_DXY(win), val);
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	/* set buffer address to mixer */
675*4882a593Smuzhiyun 	mixer_reg_write(ctx, MXR_GRAPHIC_BASE(win), dma_addr);
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun 	mixer_cfg_layer(ctx, win, priority, true);
678*4882a593Smuzhiyun 	mixer_cfg_gfx_blend(ctx, win, pixel_alpha, state->base.alpha);
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ctx->reg_slock, flags);
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun 	mixer_regs_dump(ctx);
683*4882a593Smuzhiyun }
684*4882a593Smuzhiyun 
vp_win_reset(struct mixer_context * ctx)685*4882a593Smuzhiyun static void vp_win_reset(struct mixer_context *ctx)
686*4882a593Smuzhiyun {
687*4882a593Smuzhiyun 	unsigned int tries = 100;
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun 	vp_reg_write(ctx, VP_SRESET, VP_SRESET_PROCESSING);
690*4882a593Smuzhiyun 	while (--tries) {
691*4882a593Smuzhiyun 		/* waiting until VP_SRESET_PROCESSING is 0 */
692*4882a593Smuzhiyun 		if (~vp_reg_read(ctx, VP_SRESET) & VP_SRESET_PROCESSING)
693*4882a593Smuzhiyun 			break;
694*4882a593Smuzhiyun 		mdelay(10);
695*4882a593Smuzhiyun 	}
696*4882a593Smuzhiyun 	WARN(tries == 0, "failed to reset Video Processor\n");
697*4882a593Smuzhiyun }
698*4882a593Smuzhiyun 
mixer_win_reset(struct mixer_context * ctx)699*4882a593Smuzhiyun static void mixer_win_reset(struct mixer_context *ctx)
700*4882a593Smuzhiyun {
701*4882a593Smuzhiyun 	unsigned long flags;
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	spin_lock_irqsave(&ctx->reg_slock, flags);
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun 	mixer_reg_writemask(ctx, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun 	/* set output in RGB888 mode */
708*4882a593Smuzhiyun 	mixer_reg_writemask(ctx, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	/* 16 beat burst in DMA */
711*4882a593Smuzhiyun 	mixer_reg_writemask(ctx, MXR_STATUS, MXR_STATUS_16_BURST,
712*4882a593Smuzhiyun 		MXR_STATUS_BURST_MASK);
713*4882a593Smuzhiyun 
714*4882a593Smuzhiyun 	/* reset default layer priority */
715*4882a593Smuzhiyun 	mixer_reg_write(ctx, MXR_LAYER_CFG, 0);
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun 	/* set all background colors to RGB (0,0,0) */
718*4882a593Smuzhiyun 	mixer_reg_write(ctx, MXR_BG_COLOR0, MXR_YCBCR_VAL(0, 128, 128));
719*4882a593Smuzhiyun 	mixer_reg_write(ctx, MXR_BG_COLOR1, MXR_YCBCR_VAL(0, 128, 128));
720*4882a593Smuzhiyun 	mixer_reg_write(ctx, MXR_BG_COLOR2, MXR_YCBCR_VAL(0, 128, 128));
721*4882a593Smuzhiyun 
722*4882a593Smuzhiyun 	if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
723*4882a593Smuzhiyun 		/* configuration of Video Processor Registers */
724*4882a593Smuzhiyun 		vp_win_reset(ctx);
725*4882a593Smuzhiyun 		vp_default_filter(ctx);
726*4882a593Smuzhiyun 	}
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun 	/* disable all layers */
729*4882a593Smuzhiyun 	mixer_reg_writemask(ctx, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
730*4882a593Smuzhiyun 	mixer_reg_writemask(ctx, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
731*4882a593Smuzhiyun 	if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags))
732*4882a593Smuzhiyun 		mixer_reg_writemask(ctx, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 	/* set all source image offsets to zero */
735*4882a593Smuzhiyun 	mixer_reg_write(ctx, MXR_GRAPHIC_SXY(0), 0);
736*4882a593Smuzhiyun 	mixer_reg_write(ctx, MXR_GRAPHIC_SXY(1), 0);
737*4882a593Smuzhiyun 
738*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ctx->reg_slock, flags);
739*4882a593Smuzhiyun }
740*4882a593Smuzhiyun 
mixer_irq_handler(int irq,void * arg)741*4882a593Smuzhiyun static irqreturn_t mixer_irq_handler(int irq, void *arg)
742*4882a593Smuzhiyun {
743*4882a593Smuzhiyun 	struct mixer_context *ctx = arg;
744*4882a593Smuzhiyun 	u32 val;
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 	spin_lock(&ctx->reg_slock);
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun 	/* read interrupt status for handling and clearing flags for VSYNC */
749*4882a593Smuzhiyun 	val = mixer_reg_read(ctx, MXR_INT_STATUS);
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun 	/* handling VSYNC */
752*4882a593Smuzhiyun 	if (val & MXR_INT_STATUS_VSYNC) {
753*4882a593Smuzhiyun 		/* vsync interrupt use different bit for read and clear */
754*4882a593Smuzhiyun 		val |= MXR_INT_CLEAR_VSYNC;
755*4882a593Smuzhiyun 		val &= ~MXR_INT_STATUS_VSYNC;
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun 		/* interlace scan need to check shadow register */
758*4882a593Smuzhiyun 		if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)
759*4882a593Smuzhiyun 		    && !mixer_is_synced(ctx))
760*4882a593Smuzhiyun 			goto out;
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun 		drm_crtc_handle_vblank(&ctx->crtc->base);
763*4882a593Smuzhiyun 	}
764*4882a593Smuzhiyun 
765*4882a593Smuzhiyun out:
766*4882a593Smuzhiyun 	/* clear interrupts */
767*4882a593Smuzhiyun 	mixer_reg_write(ctx, MXR_INT_STATUS, val);
768*4882a593Smuzhiyun 
769*4882a593Smuzhiyun 	spin_unlock(&ctx->reg_slock);
770*4882a593Smuzhiyun 
771*4882a593Smuzhiyun 	return IRQ_HANDLED;
772*4882a593Smuzhiyun }
773*4882a593Smuzhiyun 
mixer_resources_init(struct mixer_context * mixer_ctx)774*4882a593Smuzhiyun static int mixer_resources_init(struct mixer_context *mixer_ctx)
775*4882a593Smuzhiyun {
776*4882a593Smuzhiyun 	struct device *dev = &mixer_ctx->pdev->dev;
777*4882a593Smuzhiyun 	struct resource *res;
778*4882a593Smuzhiyun 	int ret;
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun 	spin_lock_init(&mixer_ctx->reg_slock);
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun 	mixer_ctx->mixer = devm_clk_get(dev, "mixer");
783*4882a593Smuzhiyun 	if (IS_ERR(mixer_ctx->mixer)) {
784*4882a593Smuzhiyun 		dev_err(dev, "failed to get clock 'mixer'\n");
785*4882a593Smuzhiyun 		return -ENODEV;
786*4882a593Smuzhiyun 	}
787*4882a593Smuzhiyun 
788*4882a593Smuzhiyun 	mixer_ctx->hdmi = devm_clk_get(dev, "hdmi");
789*4882a593Smuzhiyun 	if (IS_ERR(mixer_ctx->hdmi)) {
790*4882a593Smuzhiyun 		dev_err(dev, "failed to get clock 'hdmi'\n");
791*4882a593Smuzhiyun 		return PTR_ERR(mixer_ctx->hdmi);
792*4882a593Smuzhiyun 	}
793*4882a593Smuzhiyun 
794*4882a593Smuzhiyun 	mixer_ctx->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
795*4882a593Smuzhiyun 	if (IS_ERR(mixer_ctx->sclk_hdmi)) {
796*4882a593Smuzhiyun 		dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
797*4882a593Smuzhiyun 		return -ENODEV;
798*4882a593Smuzhiyun 	}
799*4882a593Smuzhiyun 	res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
800*4882a593Smuzhiyun 	if (res == NULL) {
801*4882a593Smuzhiyun 		dev_err(dev, "get memory resource failed.\n");
802*4882a593Smuzhiyun 		return -ENXIO;
803*4882a593Smuzhiyun 	}
804*4882a593Smuzhiyun 
805*4882a593Smuzhiyun 	mixer_ctx->mixer_regs = devm_ioremap(dev, res->start,
806*4882a593Smuzhiyun 							resource_size(res));
807*4882a593Smuzhiyun 	if (mixer_ctx->mixer_regs == NULL) {
808*4882a593Smuzhiyun 		dev_err(dev, "register mapping failed.\n");
809*4882a593Smuzhiyun 		return -ENXIO;
810*4882a593Smuzhiyun 	}
811*4882a593Smuzhiyun 
812*4882a593Smuzhiyun 	res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
813*4882a593Smuzhiyun 	if (res == NULL) {
814*4882a593Smuzhiyun 		dev_err(dev, "get interrupt resource failed.\n");
815*4882a593Smuzhiyun 		return -ENXIO;
816*4882a593Smuzhiyun 	}
817*4882a593Smuzhiyun 
818*4882a593Smuzhiyun 	ret = devm_request_irq(dev, res->start, mixer_irq_handler,
819*4882a593Smuzhiyun 						0, "drm_mixer", mixer_ctx);
820*4882a593Smuzhiyun 	if (ret) {
821*4882a593Smuzhiyun 		dev_err(dev, "request interrupt failed.\n");
822*4882a593Smuzhiyun 		return ret;
823*4882a593Smuzhiyun 	}
824*4882a593Smuzhiyun 	mixer_ctx->irq = res->start;
825*4882a593Smuzhiyun 
826*4882a593Smuzhiyun 	return 0;
827*4882a593Smuzhiyun }
828*4882a593Smuzhiyun 
vp_resources_init(struct mixer_context * mixer_ctx)829*4882a593Smuzhiyun static int vp_resources_init(struct mixer_context *mixer_ctx)
830*4882a593Smuzhiyun {
831*4882a593Smuzhiyun 	struct device *dev = &mixer_ctx->pdev->dev;
832*4882a593Smuzhiyun 	struct resource *res;
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun 	mixer_ctx->vp = devm_clk_get(dev, "vp");
835*4882a593Smuzhiyun 	if (IS_ERR(mixer_ctx->vp)) {
836*4882a593Smuzhiyun 		dev_err(dev, "failed to get clock 'vp'\n");
837*4882a593Smuzhiyun 		return -ENODEV;
838*4882a593Smuzhiyun 	}
839*4882a593Smuzhiyun 
840*4882a593Smuzhiyun 	if (test_bit(MXR_BIT_HAS_SCLK, &mixer_ctx->flags)) {
841*4882a593Smuzhiyun 		mixer_ctx->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
842*4882a593Smuzhiyun 		if (IS_ERR(mixer_ctx->sclk_mixer)) {
843*4882a593Smuzhiyun 			dev_err(dev, "failed to get clock 'sclk_mixer'\n");
844*4882a593Smuzhiyun 			return -ENODEV;
845*4882a593Smuzhiyun 		}
846*4882a593Smuzhiyun 		mixer_ctx->mout_mixer = devm_clk_get(dev, "mout_mixer");
847*4882a593Smuzhiyun 		if (IS_ERR(mixer_ctx->mout_mixer)) {
848*4882a593Smuzhiyun 			dev_err(dev, "failed to get clock 'mout_mixer'\n");
849*4882a593Smuzhiyun 			return -ENODEV;
850*4882a593Smuzhiyun 		}
851*4882a593Smuzhiyun 
852*4882a593Smuzhiyun 		if (mixer_ctx->sclk_hdmi && mixer_ctx->mout_mixer)
853*4882a593Smuzhiyun 			clk_set_parent(mixer_ctx->mout_mixer,
854*4882a593Smuzhiyun 				       mixer_ctx->sclk_hdmi);
855*4882a593Smuzhiyun 	}
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun 	res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
858*4882a593Smuzhiyun 	if (res == NULL) {
859*4882a593Smuzhiyun 		dev_err(dev, "get memory resource failed.\n");
860*4882a593Smuzhiyun 		return -ENXIO;
861*4882a593Smuzhiyun 	}
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun 	mixer_ctx->vp_regs = devm_ioremap(dev, res->start,
864*4882a593Smuzhiyun 							resource_size(res));
865*4882a593Smuzhiyun 	if (mixer_ctx->vp_regs == NULL) {
866*4882a593Smuzhiyun 		dev_err(dev, "register mapping failed.\n");
867*4882a593Smuzhiyun 		return -ENXIO;
868*4882a593Smuzhiyun 	}
869*4882a593Smuzhiyun 
870*4882a593Smuzhiyun 	return 0;
871*4882a593Smuzhiyun }
872*4882a593Smuzhiyun 
mixer_initialize(struct mixer_context * mixer_ctx,struct drm_device * drm_dev)873*4882a593Smuzhiyun static int mixer_initialize(struct mixer_context *mixer_ctx,
874*4882a593Smuzhiyun 			struct drm_device *drm_dev)
875*4882a593Smuzhiyun {
876*4882a593Smuzhiyun 	int ret;
877*4882a593Smuzhiyun 
878*4882a593Smuzhiyun 	mixer_ctx->drm_dev = drm_dev;
879*4882a593Smuzhiyun 
880*4882a593Smuzhiyun 	/* acquire resources: regs, irqs, clocks */
881*4882a593Smuzhiyun 	ret = mixer_resources_init(mixer_ctx);
882*4882a593Smuzhiyun 	if (ret) {
883*4882a593Smuzhiyun 		DRM_DEV_ERROR(mixer_ctx->dev,
884*4882a593Smuzhiyun 			      "mixer_resources_init failed ret=%d\n", ret);
885*4882a593Smuzhiyun 		return ret;
886*4882a593Smuzhiyun 	}
887*4882a593Smuzhiyun 
888*4882a593Smuzhiyun 	if (test_bit(MXR_BIT_VP_ENABLED, &mixer_ctx->flags)) {
889*4882a593Smuzhiyun 		/* acquire vp resources: regs, irqs, clocks */
890*4882a593Smuzhiyun 		ret = vp_resources_init(mixer_ctx);
891*4882a593Smuzhiyun 		if (ret) {
892*4882a593Smuzhiyun 			DRM_DEV_ERROR(mixer_ctx->dev,
893*4882a593Smuzhiyun 				      "vp_resources_init failed ret=%d\n", ret);
894*4882a593Smuzhiyun 			return ret;
895*4882a593Smuzhiyun 		}
896*4882a593Smuzhiyun 	}
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun 	return exynos_drm_register_dma(drm_dev, mixer_ctx->dev,
899*4882a593Smuzhiyun 				       &mixer_ctx->dma_priv);
900*4882a593Smuzhiyun }
901*4882a593Smuzhiyun 
mixer_ctx_remove(struct mixer_context * mixer_ctx)902*4882a593Smuzhiyun static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
903*4882a593Smuzhiyun {
904*4882a593Smuzhiyun 	exynos_drm_unregister_dma(mixer_ctx->drm_dev, mixer_ctx->dev,
905*4882a593Smuzhiyun 				  &mixer_ctx->dma_priv);
906*4882a593Smuzhiyun }
907*4882a593Smuzhiyun 
mixer_enable_vblank(struct exynos_drm_crtc * crtc)908*4882a593Smuzhiyun static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
909*4882a593Smuzhiyun {
910*4882a593Smuzhiyun 	struct mixer_context *mixer_ctx = crtc->ctx;
911*4882a593Smuzhiyun 
912*4882a593Smuzhiyun 	__set_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
913*4882a593Smuzhiyun 	if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
914*4882a593Smuzhiyun 		return 0;
915*4882a593Smuzhiyun 
916*4882a593Smuzhiyun 	/* enable vsync interrupt */
917*4882a593Smuzhiyun 	mixer_reg_writemask(mixer_ctx, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
918*4882a593Smuzhiyun 	mixer_reg_writemask(mixer_ctx, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
919*4882a593Smuzhiyun 
920*4882a593Smuzhiyun 	return 0;
921*4882a593Smuzhiyun }
922*4882a593Smuzhiyun 
mixer_disable_vblank(struct exynos_drm_crtc * crtc)923*4882a593Smuzhiyun static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
924*4882a593Smuzhiyun {
925*4882a593Smuzhiyun 	struct mixer_context *mixer_ctx = crtc->ctx;
926*4882a593Smuzhiyun 
927*4882a593Smuzhiyun 	__clear_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun 	if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
930*4882a593Smuzhiyun 		return;
931*4882a593Smuzhiyun 
932*4882a593Smuzhiyun 	/* disable vsync interrupt */
933*4882a593Smuzhiyun 	mixer_reg_writemask(mixer_ctx, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
934*4882a593Smuzhiyun 	mixer_reg_writemask(mixer_ctx, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
935*4882a593Smuzhiyun }
936*4882a593Smuzhiyun 
mixer_atomic_begin(struct exynos_drm_crtc * crtc)937*4882a593Smuzhiyun static void mixer_atomic_begin(struct exynos_drm_crtc *crtc)
938*4882a593Smuzhiyun {
939*4882a593Smuzhiyun 	struct mixer_context *ctx = crtc->ctx;
940*4882a593Smuzhiyun 
941*4882a593Smuzhiyun 	if (!test_bit(MXR_BIT_POWERED, &ctx->flags))
942*4882a593Smuzhiyun 		return;
943*4882a593Smuzhiyun 
944*4882a593Smuzhiyun 	if (mixer_wait_for_sync(ctx))
945*4882a593Smuzhiyun 		dev_err(ctx->dev, "timeout waiting for VSYNC\n");
946*4882a593Smuzhiyun 	mixer_disable_sync(ctx);
947*4882a593Smuzhiyun }
948*4882a593Smuzhiyun 
mixer_update_plane(struct exynos_drm_crtc * crtc,struct exynos_drm_plane * plane)949*4882a593Smuzhiyun static void mixer_update_plane(struct exynos_drm_crtc *crtc,
950*4882a593Smuzhiyun 			       struct exynos_drm_plane *plane)
951*4882a593Smuzhiyun {
952*4882a593Smuzhiyun 	struct mixer_context *mixer_ctx = crtc->ctx;
953*4882a593Smuzhiyun 
954*4882a593Smuzhiyun 	DRM_DEV_DEBUG_KMS(mixer_ctx->dev, "win: %d\n", plane->index);
955*4882a593Smuzhiyun 
956*4882a593Smuzhiyun 	if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
957*4882a593Smuzhiyun 		return;
958*4882a593Smuzhiyun 
959*4882a593Smuzhiyun 	if (plane->index == VP_DEFAULT_WIN)
960*4882a593Smuzhiyun 		vp_video_buffer(mixer_ctx, plane);
961*4882a593Smuzhiyun 	else
962*4882a593Smuzhiyun 		mixer_graph_buffer(mixer_ctx, plane);
963*4882a593Smuzhiyun }
964*4882a593Smuzhiyun 
mixer_disable_plane(struct exynos_drm_crtc * crtc,struct exynos_drm_plane * plane)965*4882a593Smuzhiyun static void mixer_disable_plane(struct exynos_drm_crtc *crtc,
966*4882a593Smuzhiyun 				struct exynos_drm_plane *plane)
967*4882a593Smuzhiyun {
968*4882a593Smuzhiyun 	struct mixer_context *mixer_ctx = crtc->ctx;
969*4882a593Smuzhiyun 	unsigned long flags;
970*4882a593Smuzhiyun 
971*4882a593Smuzhiyun 	DRM_DEV_DEBUG_KMS(mixer_ctx->dev, "win: %d\n", plane->index);
972*4882a593Smuzhiyun 
973*4882a593Smuzhiyun 	if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
974*4882a593Smuzhiyun 		return;
975*4882a593Smuzhiyun 
976*4882a593Smuzhiyun 	spin_lock_irqsave(&mixer_ctx->reg_slock, flags);
977*4882a593Smuzhiyun 	mixer_cfg_layer(mixer_ctx, plane->index, 0, false);
978*4882a593Smuzhiyun 	spin_unlock_irqrestore(&mixer_ctx->reg_slock, flags);
979*4882a593Smuzhiyun }
980*4882a593Smuzhiyun 
mixer_atomic_flush(struct exynos_drm_crtc * crtc)981*4882a593Smuzhiyun static void mixer_atomic_flush(struct exynos_drm_crtc *crtc)
982*4882a593Smuzhiyun {
983*4882a593Smuzhiyun 	struct mixer_context *mixer_ctx = crtc->ctx;
984*4882a593Smuzhiyun 
985*4882a593Smuzhiyun 	if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
986*4882a593Smuzhiyun 		return;
987*4882a593Smuzhiyun 
988*4882a593Smuzhiyun 	mixer_enable_sync(mixer_ctx);
989*4882a593Smuzhiyun 	exynos_crtc_handle_event(crtc);
990*4882a593Smuzhiyun }
991*4882a593Smuzhiyun 
mixer_atomic_enable(struct exynos_drm_crtc * crtc)992*4882a593Smuzhiyun static void mixer_atomic_enable(struct exynos_drm_crtc *crtc)
993*4882a593Smuzhiyun {
994*4882a593Smuzhiyun 	struct mixer_context *ctx = crtc->ctx;
995*4882a593Smuzhiyun 
996*4882a593Smuzhiyun 	if (test_bit(MXR_BIT_POWERED, &ctx->flags))
997*4882a593Smuzhiyun 		return;
998*4882a593Smuzhiyun 
999*4882a593Smuzhiyun 	pm_runtime_get_sync(ctx->dev);
1000*4882a593Smuzhiyun 
1001*4882a593Smuzhiyun 	exynos_drm_pipe_clk_enable(crtc, true);
1002*4882a593Smuzhiyun 
1003*4882a593Smuzhiyun 	mixer_disable_sync(ctx);
1004*4882a593Smuzhiyun 
1005*4882a593Smuzhiyun 	mixer_reg_writemask(ctx, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 	if (test_bit(MXR_BIT_VSYNC, &ctx->flags)) {
1008*4882a593Smuzhiyun 		mixer_reg_writemask(ctx, MXR_INT_STATUS, ~0,
1009*4882a593Smuzhiyun 					MXR_INT_CLEAR_VSYNC);
1010*4882a593Smuzhiyun 		mixer_reg_writemask(ctx, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
1011*4882a593Smuzhiyun 	}
1012*4882a593Smuzhiyun 	mixer_win_reset(ctx);
1013*4882a593Smuzhiyun 
1014*4882a593Smuzhiyun 	mixer_commit(ctx);
1015*4882a593Smuzhiyun 
1016*4882a593Smuzhiyun 	mixer_enable_sync(ctx);
1017*4882a593Smuzhiyun 
1018*4882a593Smuzhiyun 	set_bit(MXR_BIT_POWERED, &ctx->flags);
1019*4882a593Smuzhiyun }
1020*4882a593Smuzhiyun 
mixer_atomic_disable(struct exynos_drm_crtc * crtc)1021*4882a593Smuzhiyun static void mixer_atomic_disable(struct exynos_drm_crtc *crtc)
1022*4882a593Smuzhiyun {
1023*4882a593Smuzhiyun 	struct mixer_context *ctx = crtc->ctx;
1024*4882a593Smuzhiyun 	int i;
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun 	if (!test_bit(MXR_BIT_POWERED, &ctx->flags))
1027*4882a593Smuzhiyun 		return;
1028*4882a593Smuzhiyun 
1029*4882a593Smuzhiyun 	mixer_stop(ctx);
1030*4882a593Smuzhiyun 	mixer_regs_dump(ctx);
1031*4882a593Smuzhiyun 
1032*4882a593Smuzhiyun 	for (i = 0; i < MIXER_WIN_NR; i++)
1033*4882a593Smuzhiyun 		mixer_disable_plane(crtc, &ctx->planes[i]);
1034*4882a593Smuzhiyun 
1035*4882a593Smuzhiyun 	exynos_drm_pipe_clk_enable(crtc, false);
1036*4882a593Smuzhiyun 
1037*4882a593Smuzhiyun 	pm_runtime_put(ctx->dev);
1038*4882a593Smuzhiyun 
1039*4882a593Smuzhiyun 	clear_bit(MXR_BIT_POWERED, &ctx->flags);
1040*4882a593Smuzhiyun }
1041*4882a593Smuzhiyun 
mixer_mode_valid(struct exynos_drm_crtc * crtc,const struct drm_display_mode * mode)1042*4882a593Smuzhiyun static int mixer_mode_valid(struct exynos_drm_crtc *crtc,
1043*4882a593Smuzhiyun 		const struct drm_display_mode *mode)
1044*4882a593Smuzhiyun {
1045*4882a593Smuzhiyun 	struct mixer_context *ctx = crtc->ctx;
1046*4882a593Smuzhiyun 	u32 w = mode->hdisplay, h = mode->vdisplay;
1047*4882a593Smuzhiyun 
1048*4882a593Smuzhiyun 	DRM_DEV_DEBUG_KMS(ctx->dev, "xres=%d, yres=%d, refresh=%d, intl=%d\n",
1049*4882a593Smuzhiyun 			  w, h, drm_mode_vrefresh(mode),
1050*4882a593Smuzhiyun 			  !!(mode->flags & DRM_MODE_FLAG_INTERLACE));
1051*4882a593Smuzhiyun 
1052*4882a593Smuzhiyun 	if (ctx->mxr_ver == MXR_VER_128_0_0_184)
1053*4882a593Smuzhiyun 		return MODE_OK;
1054*4882a593Smuzhiyun 
1055*4882a593Smuzhiyun 	if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
1056*4882a593Smuzhiyun 	    (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1057*4882a593Smuzhiyun 	    (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1058*4882a593Smuzhiyun 		return MODE_OK;
1059*4882a593Smuzhiyun 
1060*4882a593Smuzhiyun 	if ((w == 1024 && h == 768) ||
1061*4882a593Smuzhiyun 	    (w == 1366 && h == 768) ||
1062*4882a593Smuzhiyun 	    (w == 1280 && h == 1024))
1063*4882a593Smuzhiyun 		return MODE_OK;
1064*4882a593Smuzhiyun 
1065*4882a593Smuzhiyun 	return MODE_BAD;
1066*4882a593Smuzhiyun }
1067*4882a593Smuzhiyun 
mixer_mode_fixup(struct exynos_drm_crtc * crtc,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)1068*4882a593Smuzhiyun static bool mixer_mode_fixup(struct exynos_drm_crtc *crtc,
1069*4882a593Smuzhiyun 		   const struct drm_display_mode *mode,
1070*4882a593Smuzhiyun 		   struct drm_display_mode *adjusted_mode)
1071*4882a593Smuzhiyun {
1072*4882a593Smuzhiyun 	struct mixer_context *ctx = crtc->ctx;
1073*4882a593Smuzhiyun 	int width = mode->hdisplay, height = mode->vdisplay, i;
1074*4882a593Smuzhiyun 
1075*4882a593Smuzhiyun 	static const struct {
1076*4882a593Smuzhiyun 		int hdisplay, vdisplay, htotal, vtotal, scan_val;
1077*4882a593Smuzhiyun 	} modes[] = {
1078*4882a593Smuzhiyun 		{ 720, 480, 858, 525, MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD },
1079*4882a593Smuzhiyun 		{ 720, 576, 864, 625, MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD },
1080*4882a593Smuzhiyun 		{ 1280, 720, 1650, 750, MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD },
1081*4882a593Smuzhiyun 		{ 1920, 1080, 2200, 1125, MXR_CFG_SCAN_HD_1080 |
1082*4882a593Smuzhiyun 						MXR_CFG_SCAN_HD }
1083*4882a593Smuzhiyun 	};
1084*4882a593Smuzhiyun 
1085*4882a593Smuzhiyun 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
1086*4882a593Smuzhiyun 		__set_bit(MXR_BIT_INTERLACE, &ctx->flags);
1087*4882a593Smuzhiyun 	else
1088*4882a593Smuzhiyun 		__clear_bit(MXR_BIT_INTERLACE, &ctx->flags);
1089*4882a593Smuzhiyun 
1090*4882a593Smuzhiyun 	if (ctx->mxr_ver == MXR_VER_128_0_0_184)
1091*4882a593Smuzhiyun 		return true;
1092*4882a593Smuzhiyun 
1093*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(modes); ++i)
1094*4882a593Smuzhiyun 		if (width <= modes[i].hdisplay && height <= modes[i].vdisplay) {
1095*4882a593Smuzhiyun 			ctx->scan_value = modes[i].scan_val;
1096*4882a593Smuzhiyun 			if (width < modes[i].hdisplay ||
1097*4882a593Smuzhiyun 			    height < modes[i].vdisplay) {
1098*4882a593Smuzhiyun 				adjusted_mode->hdisplay = modes[i].hdisplay;
1099*4882a593Smuzhiyun 				adjusted_mode->hsync_start = modes[i].hdisplay;
1100*4882a593Smuzhiyun 				adjusted_mode->hsync_end = modes[i].htotal;
1101*4882a593Smuzhiyun 				adjusted_mode->htotal = modes[i].htotal;
1102*4882a593Smuzhiyun 				adjusted_mode->vdisplay = modes[i].vdisplay;
1103*4882a593Smuzhiyun 				adjusted_mode->vsync_start = modes[i].vdisplay;
1104*4882a593Smuzhiyun 				adjusted_mode->vsync_end = modes[i].vtotal;
1105*4882a593Smuzhiyun 				adjusted_mode->vtotal = modes[i].vtotal;
1106*4882a593Smuzhiyun 			}
1107*4882a593Smuzhiyun 
1108*4882a593Smuzhiyun 			return true;
1109*4882a593Smuzhiyun 		}
1110*4882a593Smuzhiyun 
1111*4882a593Smuzhiyun 	return false;
1112*4882a593Smuzhiyun }
1113*4882a593Smuzhiyun 
1114*4882a593Smuzhiyun static const struct exynos_drm_crtc_ops mixer_crtc_ops = {
1115*4882a593Smuzhiyun 	.atomic_enable		= mixer_atomic_enable,
1116*4882a593Smuzhiyun 	.atomic_disable		= mixer_atomic_disable,
1117*4882a593Smuzhiyun 	.enable_vblank		= mixer_enable_vblank,
1118*4882a593Smuzhiyun 	.disable_vblank		= mixer_disable_vblank,
1119*4882a593Smuzhiyun 	.atomic_begin		= mixer_atomic_begin,
1120*4882a593Smuzhiyun 	.update_plane		= mixer_update_plane,
1121*4882a593Smuzhiyun 	.disable_plane		= mixer_disable_plane,
1122*4882a593Smuzhiyun 	.atomic_flush		= mixer_atomic_flush,
1123*4882a593Smuzhiyun 	.mode_valid		= mixer_mode_valid,
1124*4882a593Smuzhiyun 	.mode_fixup		= mixer_mode_fixup,
1125*4882a593Smuzhiyun };
1126*4882a593Smuzhiyun 
1127*4882a593Smuzhiyun static const struct mixer_drv_data exynos5420_mxr_drv_data = {
1128*4882a593Smuzhiyun 	.version = MXR_VER_128_0_0_184,
1129*4882a593Smuzhiyun 	.is_vp_enabled = 0,
1130*4882a593Smuzhiyun };
1131*4882a593Smuzhiyun 
1132*4882a593Smuzhiyun static const struct mixer_drv_data exynos5250_mxr_drv_data = {
1133*4882a593Smuzhiyun 	.version = MXR_VER_16_0_33_0,
1134*4882a593Smuzhiyun 	.is_vp_enabled = 0,
1135*4882a593Smuzhiyun };
1136*4882a593Smuzhiyun 
1137*4882a593Smuzhiyun static const struct mixer_drv_data exynos4212_mxr_drv_data = {
1138*4882a593Smuzhiyun 	.version = MXR_VER_0_0_0_16,
1139*4882a593Smuzhiyun 	.is_vp_enabled = 1,
1140*4882a593Smuzhiyun };
1141*4882a593Smuzhiyun 
1142*4882a593Smuzhiyun static const struct mixer_drv_data exynos4210_mxr_drv_data = {
1143*4882a593Smuzhiyun 	.version = MXR_VER_0_0_0_16,
1144*4882a593Smuzhiyun 	.is_vp_enabled = 1,
1145*4882a593Smuzhiyun 	.has_sclk = 1,
1146*4882a593Smuzhiyun };
1147*4882a593Smuzhiyun 
1148*4882a593Smuzhiyun static const struct of_device_id mixer_match_types[] = {
1149*4882a593Smuzhiyun 	{
1150*4882a593Smuzhiyun 		.compatible = "samsung,exynos4210-mixer",
1151*4882a593Smuzhiyun 		.data	= &exynos4210_mxr_drv_data,
1152*4882a593Smuzhiyun 	}, {
1153*4882a593Smuzhiyun 		.compatible = "samsung,exynos4212-mixer",
1154*4882a593Smuzhiyun 		.data	= &exynos4212_mxr_drv_data,
1155*4882a593Smuzhiyun 	}, {
1156*4882a593Smuzhiyun 		.compatible = "samsung,exynos5-mixer",
1157*4882a593Smuzhiyun 		.data	= &exynos5250_mxr_drv_data,
1158*4882a593Smuzhiyun 	}, {
1159*4882a593Smuzhiyun 		.compatible = "samsung,exynos5250-mixer",
1160*4882a593Smuzhiyun 		.data	= &exynos5250_mxr_drv_data,
1161*4882a593Smuzhiyun 	}, {
1162*4882a593Smuzhiyun 		.compatible = "samsung,exynos5420-mixer",
1163*4882a593Smuzhiyun 		.data	= &exynos5420_mxr_drv_data,
1164*4882a593Smuzhiyun 	}, {
1165*4882a593Smuzhiyun 		/* end node */
1166*4882a593Smuzhiyun 	}
1167*4882a593Smuzhiyun };
1168*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, mixer_match_types);
1169*4882a593Smuzhiyun 
mixer_bind(struct device * dev,struct device * manager,void * data)1170*4882a593Smuzhiyun static int mixer_bind(struct device *dev, struct device *manager, void *data)
1171*4882a593Smuzhiyun {
1172*4882a593Smuzhiyun 	struct mixer_context *ctx = dev_get_drvdata(dev);
1173*4882a593Smuzhiyun 	struct drm_device *drm_dev = data;
1174*4882a593Smuzhiyun 	struct exynos_drm_plane *exynos_plane;
1175*4882a593Smuzhiyun 	unsigned int i;
1176*4882a593Smuzhiyun 	int ret;
1177*4882a593Smuzhiyun 
1178*4882a593Smuzhiyun 	ret = mixer_initialize(ctx, drm_dev);
1179*4882a593Smuzhiyun 	if (ret)
1180*4882a593Smuzhiyun 		return ret;
1181*4882a593Smuzhiyun 
1182*4882a593Smuzhiyun 	for (i = 0; i < MIXER_WIN_NR; i++) {
1183*4882a593Smuzhiyun 		if (i == VP_DEFAULT_WIN && !test_bit(MXR_BIT_VP_ENABLED,
1184*4882a593Smuzhiyun 						     &ctx->flags))
1185*4882a593Smuzhiyun 			continue;
1186*4882a593Smuzhiyun 
1187*4882a593Smuzhiyun 		ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
1188*4882a593Smuzhiyun 					&plane_configs[i]);
1189*4882a593Smuzhiyun 		if (ret)
1190*4882a593Smuzhiyun 			return ret;
1191*4882a593Smuzhiyun 	}
1192*4882a593Smuzhiyun 
1193*4882a593Smuzhiyun 	exynos_plane = &ctx->planes[DEFAULT_WIN];
1194*4882a593Smuzhiyun 	ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
1195*4882a593Smuzhiyun 			EXYNOS_DISPLAY_TYPE_HDMI, &mixer_crtc_ops, ctx);
1196*4882a593Smuzhiyun 	if (IS_ERR(ctx->crtc)) {
1197*4882a593Smuzhiyun 		mixer_ctx_remove(ctx);
1198*4882a593Smuzhiyun 		ret = PTR_ERR(ctx->crtc);
1199*4882a593Smuzhiyun 		goto free_ctx;
1200*4882a593Smuzhiyun 	}
1201*4882a593Smuzhiyun 
1202*4882a593Smuzhiyun 	return 0;
1203*4882a593Smuzhiyun 
1204*4882a593Smuzhiyun free_ctx:
1205*4882a593Smuzhiyun 	devm_kfree(dev, ctx);
1206*4882a593Smuzhiyun 	return ret;
1207*4882a593Smuzhiyun }
1208*4882a593Smuzhiyun 
mixer_unbind(struct device * dev,struct device * master,void * data)1209*4882a593Smuzhiyun static void mixer_unbind(struct device *dev, struct device *master, void *data)
1210*4882a593Smuzhiyun {
1211*4882a593Smuzhiyun 	struct mixer_context *ctx = dev_get_drvdata(dev);
1212*4882a593Smuzhiyun 
1213*4882a593Smuzhiyun 	mixer_ctx_remove(ctx);
1214*4882a593Smuzhiyun }
1215*4882a593Smuzhiyun 
1216*4882a593Smuzhiyun static const struct component_ops mixer_component_ops = {
1217*4882a593Smuzhiyun 	.bind	= mixer_bind,
1218*4882a593Smuzhiyun 	.unbind	= mixer_unbind,
1219*4882a593Smuzhiyun };
1220*4882a593Smuzhiyun 
mixer_probe(struct platform_device * pdev)1221*4882a593Smuzhiyun static int mixer_probe(struct platform_device *pdev)
1222*4882a593Smuzhiyun {
1223*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
1224*4882a593Smuzhiyun 	const struct mixer_drv_data *drv;
1225*4882a593Smuzhiyun 	struct mixer_context *ctx;
1226*4882a593Smuzhiyun 	int ret;
1227*4882a593Smuzhiyun 
1228*4882a593Smuzhiyun 	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1229*4882a593Smuzhiyun 	if (!ctx) {
1230*4882a593Smuzhiyun 		DRM_DEV_ERROR(dev, "failed to alloc mixer context.\n");
1231*4882a593Smuzhiyun 		return -ENOMEM;
1232*4882a593Smuzhiyun 	}
1233*4882a593Smuzhiyun 
1234*4882a593Smuzhiyun 	drv = of_device_get_match_data(dev);
1235*4882a593Smuzhiyun 
1236*4882a593Smuzhiyun 	ctx->pdev = pdev;
1237*4882a593Smuzhiyun 	ctx->dev = dev;
1238*4882a593Smuzhiyun 	ctx->mxr_ver = drv->version;
1239*4882a593Smuzhiyun 
1240*4882a593Smuzhiyun 	if (drv->is_vp_enabled)
1241*4882a593Smuzhiyun 		__set_bit(MXR_BIT_VP_ENABLED, &ctx->flags);
1242*4882a593Smuzhiyun 	if (drv->has_sclk)
1243*4882a593Smuzhiyun 		__set_bit(MXR_BIT_HAS_SCLK, &ctx->flags);
1244*4882a593Smuzhiyun 
1245*4882a593Smuzhiyun 	platform_set_drvdata(pdev, ctx);
1246*4882a593Smuzhiyun 
1247*4882a593Smuzhiyun 	pm_runtime_enable(dev);
1248*4882a593Smuzhiyun 
1249*4882a593Smuzhiyun 	ret = component_add(&pdev->dev, &mixer_component_ops);
1250*4882a593Smuzhiyun 	if (ret)
1251*4882a593Smuzhiyun 		pm_runtime_disable(dev);
1252*4882a593Smuzhiyun 
1253*4882a593Smuzhiyun 	return ret;
1254*4882a593Smuzhiyun }
1255*4882a593Smuzhiyun 
mixer_remove(struct platform_device * pdev)1256*4882a593Smuzhiyun static int mixer_remove(struct platform_device *pdev)
1257*4882a593Smuzhiyun {
1258*4882a593Smuzhiyun 	pm_runtime_disable(&pdev->dev);
1259*4882a593Smuzhiyun 
1260*4882a593Smuzhiyun 	component_del(&pdev->dev, &mixer_component_ops);
1261*4882a593Smuzhiyun 
1262*4882a593Smuzhiyun 	return 0;
1263*4882a593Smuzhiyun }
1264*4882a593Smuzhiyun 
exynos_mixer_suspend(struct device * dev)1265*4882a593Smuzhiyun static int __maybe_unused exynos_mixer_suspend(struct device *dev)
1266*4882a593Smuzhiyun {
1267*4882a593Smuzhiyun 	struct mixer_context *ctx = dev_get_drvdata(dev);
1268*4882a593Smuzhiyun 
1269*4882a593Smuzhiyun 	clk_disable_unprepare(ctx->hdmi);
1270*4882a593Smuzhiyun 	clk_disable_unprepare(ctx->mixer);
1271*4882a593Smuzhiyun 	if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
1272*4882a593Smuzhiyun 		clk_disable_unprepare(ctx->vp);
1273*4882a593Smuzhiyun 		if (test_bit(MXR_BIT_HAS_SCLK, &ctx->flags))
1274*4882a593Smuzhiyun 			clk_disable_unprepare(ctx->sclk_mixer);
1275*4882a593Smuzhiyun 	}
1276*4882a593Smuzhiyun 
1277*4882a593Smuzhiyun 	return 0;
1278*4882a593Smuzhiyun }
1279*4882a593Smuzhiyun 
exynos_mixer_resume(struct device * dev)1280*4882a593Smuzhiyun static int __maybe_unused exynos_mixer_resume(struct device *dev)
1281*4882a593Smuzhiyun {
1282*4882a593Smuzhiyun 	struct mixer_context *ctx = dev_get_drvdata(dev);
1283*4882a593Smuzhiyun 	int ret;
1284*4882a593Smuzhiyun 
1285*4882a593Smuzhiyun 	ret = clk_prepare_enable(ctx->mixer);
1286*4882a593Smuzhiyun 	if (ret < 0) {
1287*4882a593Smuzhiyun 		DRM_DEV_ERROR(ctx->dev,
1288*4882a593Smuzhiyun 			      "Failed to prepare_enable the mixer clk [%d]\n",
1289*4882a593Smuzhiyun 			      ret);
1290*4882a593Smuzhiyun 		return ret;
1291*4882a593Smuzhiyun 	}
1292*4882a593Smuzhiyun 	ret = clk_prepare_enable(ctx->hdmi);
1293*4882a593Smuzhiyun 	if (ret < 0) {
1294*4882a593Smuzhiyun 		DRM_DEV_ERROR(dev,
1295*4882a593Smuzhiyun 			      "Failed to prepare_enable the hdmi clk [%d]\n",
1296*4882a593Smuzhiyun 			      ret);
1297*4882a593Smuzhiyun 		return ret;
1298*4882a593Smuzhiyun 	}
1299*4882a593Smuzhiyun 	if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
1300*4882a593Smuzhiyun 		ret = clk_prepare_enable(ctx->vp);
1301*4882a593Smuzhiyun 		if (ret < 0) {
1302*4882a593Smuzhiyun 			DRM_DEV_ERROR(dev,
1303*4882a593Smuzhiyun 				      "Failed to prepare_enable the vp clk [%d]\n",
1304*4882a593Smuzhiyun 				      ret);
1305*4882a593Smuzhiyun 			return ret;
1306*4882a593Smuzhiyun 		}
1307*4882a593Smuzhiyun 		if (test_bit(MXR_BIT_HAS_SCLK, &ctx->flags)) {
1308*4882a593Smuzhiyun 			ret = clk_prepare_enable(ctx->sclk_mixer);
1309*4882a593Smuzhiyun 			if (ret < 0) {
1310*4882a593Smuzhiyun 				DRM_DEV_ERROR(dev,
1311*4882a593Smuzhiyun 					   "Failed to prepare_enable the " \
1312*4882a593Smuzhiyun 					   "sclk_mixer clk [%d]\n",
1313*4882a593Smuzhiyun 					   ret);
1314*4882a593Smuzhiyun 				return ret;
1315*4882a593Smuzhiyun 			}
1316*4882a593Smuzhiyun 		}
1317*4882a593Smuzhiyun 	}
1318*4882a593Smuzhiyun 
1319*4882a593Smuzhiyun 	return 0;
1320*4882a593Smuzhiyun }
1321*4882a593Smuzhiyun 
1322*4882a593Smuzhiyun static const struct dev_pm_ops exynos_mixer_pm_ops = {
1323*4882a593Smuzhiyun 	SET_RUNTIME_PM_OPS(exynos_mixer_suspend, exynos_mixer_resume, NULL)
1324*4882a593Smuzhiyun 	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
1325*4882a593Smuzhiyun 				pm_runtime_force_resume)
1326*4882a593Smuzhiyun };
1327*4882a593Smuzhiyun 
1328*4882a593Smuzhiyun struct platform_driver mixer_driver = {
1329*4882a593Smuzhiyun 	.driver = {
1330*4882a593Smuzhiyun 		.name = "exynos-mixer",
1331*4882a593Smuzhiyun 		.owner = THIS_MODULE,
1332*4882a593Smuzhiyun 		.pm = &exynos_mixer_pm_ops,
1333*4882a593Smuzhiyun 		.of_match_table = mixer_match_types,
1334*4882a593Smuzhiyun 	},
1335*4882a593Smuzhiyun 	.probe = mixer_probe,
1336*4882a593Smuzhiyun 	.remove = mixer_remove,
1337*4882a593Smuzhiyun };
1338