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