drm/exynos/mixer: correct vsync configuration sequence
[linux-2.6-block.git] / drivers / gpu / drm / exynos / exynos_mixer.c
CommitLineData
d8408326
SWK
1/*
2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
3 * Authors:
4 * Seung-Woo Kim <sw0312.kim@samsung.com>
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 *
8 * Based on drivers/media/video/s5p-tv/mixer_reg.c
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 */
16
760285e7 17#include <drm/drmP.h>
d8408326
SWK
18
19#include "regs-mixer.h"
20#include "regs-vp.h"
21
22#include <linux/kernel.h>
23#include <linux/spinlock.h>
24#include <linux/wait.h>
25#include <linux/i2c.h>
d8408326
SWK
26#include <linux/platform_device.h>
27#include <linux/interrupt.h>
28#include <linux/irq.h>
29#include <linux/delay.h>
30#include <linux/pm_runtime.h>
31#include <linux/clk.h>
32#include <linux/regulator/consumer.h>
3f1c781d 33#include <linux/of.h>
f37cd5e8 34#include <linux/component.h>
d8408326
SWK
35
36#include <drm/exynos_drm.h>
37
38#include "exynos_drm_drv.h"
663d8766 39#include "exynos_drm_crtc.h"
7ee14cdc 40#include "exynos_drm_plane.h"
1055b39f 41#include "exynos_drm_iommu.h"
f041b257 42#include "exynos_mixer.h"
22b21ae6 43
f041b257
SP
44#define MIXER_WIN_NR 3
45#define MIXER_DEFAULT_WIN 0
d8408326 46
7a57ca7c
TJ
47/* The pixelformats that are natively supported by the mixer. */
48#define MXR_FORMAT_RGB565 4
49#define MXR_FORMAT_ARGB1555 5
50#define MXR_FORMAT_ARGB4444 6
51#define MXR_FORMAT_ARGB8888 7
52
22b21ae6 53struct mixer_resources {
22b21ae6
JS
54 int irq;
55 void __iomem *mixer_regs;
56 void __iomem *vp_regs;
57 spinlock_t reg_slock;
58 struct clk *mixer;
59 struct clk *vp;
04427ec5 60 struct clk *hdmi;
22b21ae6
JS
61 struct clk *sclk_mixer;
62 struct clk *sclk_hdmi;
ff830c96 63 struct clk *mout_mixer;
22b21ae6
JS
64};
65
1e123441
RS
66enum mixer_version_id {
67 MXR_VER_0_0_0_16,
68 MXR_VER_16_0_33_0,
def5e095 69 MXR_VER_128_0_0_184,
1e123441
RS
70};
71
22b21ae6 72struct mixer_context {
4551789f 73 struct platform_device *pdev;
cf8fc4f1 74 struct device *dev;
1055b39f 75 struct drm_device *drm_dev;
93bca243 76 struct exynos_drm_crtc *crtc;
7ee14cdc 77 struct exynos_drm_plane planes[MIXER_WIN_NR];
22b21ae6
JS
78 int pipe;
79 bool interlace;
cf8fc4f1 80 bool powered;
1b8e5747 81 bool vp_enabled;
ff830c96 82 bool has_sclk;
cf8fc4f1 83 u32 int_en;
22b21ae6 84
cf8fc4f1 85 struct mutex mixer_mutex;
22b21ae6 86 struct mixer_resources mixer_res;
1e123441 87 enum mixer_version_id mxr_ver;
6e95d5e6
P
88 wait_queue_head_t wait_vsync_queue;
89 atomic_t wait_vsync_event;
1e123441
RS
90};
91
92struct mixer_drv_data {
93 enum mixer_version_id version;
1b8e5747 94 bool is_vp_enabled;
ff830c96 95 bool has_sclk;
22b21ae6
JS
96};
97
d8408326
SWK
98static const u8 filter_y_horiz_tap8[] = {
99 0, -1, -1, -1, -1, -1, -1, -1,
100 -1, -1, -1, -1, -1, 0, 0, 0,
101 0, 2, 4, 5, 6, 6, 6, 6,
102 6, 5, 5, 4, 3, 2, 1, 1,
103 0, -6, -12, -16, -18, -20, -21, -20,
104 -20, -18, -16, -13, -10, -8, -5, -2,
105 127, 126, 125, 121, 114, 107, 99, 89,
106 79, 68, 57, 46, 35, 25, 16, 8,
107};
108
109static const u8 filter_y_vert_tap4[] = {
110 0, -3, -6, -8, -8, -8, -8, -7,
111 -6, -5, -4, -3, -2, -1, -1, 0,
112 127, 126, 124, 118, 111, 102, 92, 81,
113 70, 59, 48, 37, 27, 19, 11, 5,
114 0, 5, 11, 19, 27, 37, 48, 59,
115 70, 81, 92, 102, 111, 118, 124, 126,
116 0, 0, -1, -1, -2, -3, -4, -5,
117 -6, -7, -8, -8, -8, -8, -6, -3,
118};
119
120static const u8 filter_cr_horiz_tap4[] = {
121 0, -3, -6, -8, -8, -8, -8, -7,
122 -6, -5, -4, -3, -2, -1, -1, 0,
123 127, 126, 124, 118, 111, 102, 92, 81,
124 70, 59, 48, 37, 27, 19, 11, 5,
125};
126
127static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
128{
129 return readl(res->vp_regs + reg_id);
130}
131
132static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
133 u32 val)
134{
135 writel(val, res->vp_regs + reg_id);
136}
137
138static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
139 u32 val, u32 mask)
140{
141 u32 old = vp_reg_read(res, reg_id);
142
143 val = (val & mask) | (old & ~mask);
144 writel(val, res->vp_regs + reg_id);
145}
146
147static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
148{
149 return readl(res->mixer_regs + reg_id);
150}
151
152static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
153 u32 val)
154{
155 writel(val, res->mixer_regs + reg_id);
156}
157
158static inline void mixer_reg_writemask(struct mixer_resources *res,
159 u32 reg_id, u32 val, u32 mask)
160{
161 u32 old = mixer_reg_read(res, reg_id);
162
163 val = (val & mask) | (old & ~mask);
164 writel(val, res->mixer_regs + reg_id);
165}
166
167static void mixer_regs_dump(struct mixer_context *ctx)
168{
169#define DUMPREG(reg_id) \
170do { \
171 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
172 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
173} while (0)
174
175 DUMPREG(MXR_STATUS);
176 DUMPREG(MXR_CFG);
177 DUMPREG(MXR_INT_EN);
178 DUMPREG(MXR_INT_STATUS);
179
180 DUMPREG(MXR_LAYER_CFG);
181 DUMPREG(MXR_VIDEO_CFG);
182
183 DUMPREG(MXR_GRAPHIC0_CFG);
184 DUMPREG(MXR_GRAPHIC0_BASE);
185 DUMPREG(MXR_GRAPHIC0_SPAN);
186 DUMPREG(MXR_GRAPHIC0_WH);
187 DUMPREG(MXR_GRAPHIC0_SXY);
188 DUMPREG(MXR_GRAPHIC0_DXY);
189
190 DUMPREG(MXR_GRAPHIC1_CFG);
191 DUMPREG(MXR_GRAPHIC1_BASE);
192 DUMPREG(MXR_GRAPHIC1_SPAN);
193 DUMPREG(MXR_GRAPHIC1_WH);
194 DUMPREG(MXR_GRAPHIC1_SXY);
195 DUMPREG(MXR_GRAPHIC1_DXY);
196#undef DUMPREG
197}
198
199static void vp_regs_dump(struct mixer_context *ctx)
200{
201#define DUMPREG(reg_id) \
202do { \
203 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
204 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
205} while (0)
206
207 DUMPREG(VP_ENABLE);
208 DUMPREG(VP_SRESET);
209 DUMPREG(VP_SHADOW_UPDATE);
210 DUMPREG(VP_FIELD_ID);
211 DUMPREG(VP_MODE);
212 DUMPREG(VP_IMG_SIZE_Y);
213 DUMPREG(VP_IMG_SIZE_C);
214 DUMPREG(VP_PER_RATE_CTRL);
215 DUMPREG(VP_TOP_Y_PTR);
216 DUMPREG(VP_BOT_Y_PTR);
217 DUMPREG(VP_TOP_C_PTR);
218 DUMPREG(VP_BOT_C_PTR);
219 DUMPREG(VP_ENDIAN_MODE);
220 DUMPREG(VP_SRC_H_POSITION);
221 DUMPREG(VP_SRC_V_POSITION);
222 DUMPREG(VP_SRC_WIDTH);
223 DUMPREG(VP_SRC_HEIGHT);
224 DUMPREG(VP_DST_H_POSITION);
225 DUMPREG(VP_DST_V_POSITION);
226 DUMPREG(VP_DST_WIDTH);
227 DUMPREG(VP_DST_HEIGHT);
228 DUMPREG(VP_H_RATIO);
229 DUMPREG(VP_V_RATIO);
230
231#undef DUMPREG
232}
233
234static inline void vp_filter_set(struct mixer_resources *res,
235 int reg_id, const u8 *data, unsigned int size)
236{
237 /* assure 4-byte align */
238 BUG_ON(size & 3);
239 for (; size; size -= 4, reg_id += 4, data += 4) {
240 u32 val = (data[0] << 24) | (data[1] << 16) |
241 (data[2] << 8) | data[3];
242 vp_reg_write(res, reg_id, val);
243 }
244}
245
246static void vp_default_filter(struct mixer_resources *res)
247{
248 vp_filter_set(res, VP_POLY8_Y0_LL,
e25e1b66 249 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
d8408326 250 vp_filter_set(res, VP_POLY4_Y0_LL,
e25e1b66 251 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
d8408326 252 vp_filter_set(res, VP_POLY4_C0_LL,
e25e1b66 253 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
d8408326
SWK
254}
255
256static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
257{
258 struct mixer_resources *res = &ctx->mixer_res;
259
260 /* block update on vsync */
261 mixer_reg_writemask(res, MXR_STATUS, enable ?
262 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
263
1b8e5747
RS
264 if (ctx->vp_enabled)
265 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
d8408326
SWK
266 VP_SHADOW_UPDATE_ENABLE : 0);
267}
268
269static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
270{
271 struct mixer_resources *res = &ctx->mixer_res;
272 u32 val;
273
274 /* choosing between interlace and progressive mode */
275 val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
1e6d459d 276 MXR_CFG_SCAN_PROGRESSIVE);
d8408326 277
def5e095
RS
278 if (ctx->mxr_ver != MXR_VER_128_0_0_184) {
279 /* choosing between proper HD and SD mode */
280 if (height <= 480)
281 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
282 else if (height <= 576)
283 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
284 else if (height <= 720)
285 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
286 else if (height <= 1080)
287 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
288 else
289 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
290 }
d8408326
SWK
291
292 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
293}
294
295static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
296{
297 struct mixer_resources *res = &ctx->mixer_res;
298 u32 val;
299
300 if (height == 480) {
301 val = MXR_CFG_RGB601_0_255;
302 } else if (height == 576) {
303 val = MXR_CFG_RGB601_0_255;
304 } else if (height == 720) {
305 val = MXR_CFG_RGB709_16_235;
306 mixer_reg_write(res, MXR_CM_COEFF_Y,
307 (1 << 30) | (94 << 20) | (314 << 10) |
308 (32 << 0));
309 mixer_reg_write(res, MXR_CM_COEFF_CB,
310 (972 << 20) | (851 << 10) | (225 << 0));
311 mixer_reg_write(res, MXR_CM_COEFF_CR,
312 (225 << 20) | (820 << 10) | (1004 << 0));
313 } else if (height == 1080) {
314 val = MXR_CFG_RGB709_16_235;
315 mixer_reg_write(res, MXR_CM_COEFF_Y,
316 (1 << 30) | (94 << 20) | (314 << 10) |
317 (32 << 0));
318 mixer_reg_write(res, MXR_CM_COEFF_CB,
319 (972 << 20) | (851 << 10) | (225 << 0));
320 mixer_reg_write(res, MXR_CM_COEFF_CR,
321 (225 << 20) | (820 << 10) | (1004 << 0));
322 } else {
323 val = MXR_CFG_RGB709_16_235;
324 mixer_reg_write(res, MXR_CM_COEFF_Y,
325 (1 << 30) | (94 << 20) | (314 << 10) |
326 (32 << 0));
327 mixer_reg_write(res, MXR_CM_COEFF_CB,
328 (972 << 20) | (851 << 10) | (225 << 0));
329 mixer_reg_write(res, MXR_CM_COEFF_CR,
330 (225 << 20) | (820 << 10) | (1004 << 0));
331 }
332
333 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
334}
335
5b1d5bc6
TJ
336static void mixer_cfg_layer(struct mixer_context *ctx, unsigned int win,
337 bool enable)
d8408326
SWK
338{
339 struct mixer_resources *res = &ctx->mixer_res;
340 u32 val = enable ? ~0 : 0;
341
342 switch (win) {
343 case 0:
344 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
345 break;
346 case 1:
347 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
348 break;
349 case 2:
1b8e5747
RS
350 if (ctx->vp_enabled) {
351 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
352 mixer_reg_writemask(res, MXR_CFG, val,
353 MXR_CFG_VP_ENABLE);
f1e716d8
JS
354
355 /* control blending of graphic layer 0 */
356 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(0), val,
357 MXR_GRP_CFG_BLEND_PRE_MUL |
358 MXR_GRP_CFG_PIXEL_BLEND_EN);
1b8e5747 359 }
d8408326
SWK
360 break;
361 }
362}
363
364static void mixer_run(struct mixer_context *ctx)
365{
366 struct mixer_resources *res = &ctx->mixer_res;
367
368 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
d8408326
SWK
369}
370
381be025
RS
371static void mixer_stop(struct mixer_context *ctx)
372{
373 struct mixer_resources *res = &ctx->mixer_res;
374 int timeout = 20;
375
376 mixer_reg_writemask(res, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
377
378 while (!(mixer_reg_read(res, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
379 --timeout)
380 usleep_range(10000, 12000);
381be025
RS
381}
382
5b1d5bc6 383static void vp_video_buffer(struct mixer_context *ctx, unsigned int win)
d8408326
SWK
384{
385 struct mixer_resources *res = &ctx->mixer_res;
386 unsigned long flags;
7ee14cdc 387 struct exynos_drm_plane *plane;
d8408326
SWK
388 dma_addr_t luma_addr[2], chroma_addr[2];
389 bool tiled_mode = false;
390 bool crcb_mode = false;
391 u32 val;
392
7ee14cdc 393 plane = &ctx->planes[win];
d8408326 394
7ee14cdc 395 switch (plane->pixel_format) {
363b06aa 396 case DRM_FORMAT_NV12:
d8408326 397 crcb_mode = false;
d8408326 398 break;
8f2590f8
TJ
399 case DRM_FORMAT_NV21:
400 crcb_mode = true;
401 break;
d8408326 402 default:
d8408326 403 DRM_ERROR("pixel format for vp is wrong [%d].\n",
7ee14cdc 404 plane->pixel_format);
d8408326
SWK
405 return;
406 }
407
fac8a5b2
TJ
408 luma_addr[0] = plane->dma_addr[0];
409 chroma_addr[0] = plane->dma_addr[1];
d8408326 410
7ee14cdc 411 if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE) {
d8408326
SWK
412 ctx->interlace = true;
413 if (tiled_mode) {
414 luma_addr[1] = luma_addr[0] + 0x40;
415 chroma_addr[1] = chroma_addr[0] + 0x40;
416 } else {
7ee14cdc
GP
417 luma_addr[1] = luma_addr[0] + plane->pitch;
418 chroma_addr[1] = chroma_addr[0] + plane->pitch;
d8408326
SWK
419 }
420 } else {
421 ctx->interlace = false;
422 luma_addr[1] = 0;
423 chroma_addr[1] = 0;
424 }
425
426 spin_lock_irqsave(&res->reg_slock, flags);
427 mixer_vsync_set_update(ctx, false);
428
429 /* interlace or progressive scan mode */
430 val = (ctx->interlace ? ~0 : 0);
431 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
432
433 /* setup format */
434 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
435 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
436 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
437
438 /* setting size of input image */
7ee14cdc
GP
439 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(plane->pitch) |
440 VP_IMG_VSIZE(plane->fb_height));
d8408326 441 /* chroma height has to reduced by 2 to avoid chroma distorions */
7ee14cdc
GP
442 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(plane->pitch) |
443 VP_IMG_VSIZE(plane->fb_height / 2));
d8408326 444
7ee14cdc
GP
445 vp_reg_write(res, VP_SRC_WIDTH, plane->src_width);
446 vp_reg_write(res, VP_SRC_HEIGHT, plane->src_height);
d8408326 447 vp_reg_write(res, VP_SRC_H_POSITION,
cb8a3db2
JS
448 VP_SRC_H_POSITION_VAL(plane->src_x));
449 vp_reg_write(res, VP_SRC_V_POSITION, plane->src_y);
d8408326 450
7ee14cdc
GP
451 vp_reg_write(res, VP_DST_WIDTH, plane->crtc_width);
452 vp_reg_write(res, VP_DST_H_POSITION, plane->crtc_x);
d8408326 453 if (ctx->interlace) {
7ee14cdc
GP
454 vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height / 2);
455 vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y / 2);
d8408326 456 } else {
7ee14cdc
GP
457 vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height);
458 vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y);
d8408326
SWK
459 }
460
3cabaf7e
JS
461 vp_reg_write(res, VP_H_RATIO, plane->h_ratio);
462 vp_reg_write(res, VP_V_RATIO, plane->v_ratio);
d8408326
SWK
463
464 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
465
466 /* set buffer address to vp */
467 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
468 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
469 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
470 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
471
7ee14cdc
GP
472 mixer_cfg_scan(ctx, plane->mode_height);
473 mixer_cfg_rgb_fmt(ctx, plane->mode_height);
d8408326
SWK
474 mixer_cfg_layer(ctx, win, true);
475 mixer_run(ctx);
476
477 mixer_vsync_set_update(ctx, true);
478 spin_unlock_irqrestore(&res->reg_slock, flags);
479
c0734fba 480 mixer_regs_dump(ctx);
d8408326
SWK
481 vp_regs_dump(ctx);
482}
483
aaf8b49e
RS
484static void mixer_layer_update(struct mixer_context *ctx)
485{
486 struct mixer_resources *res = &ctx->mixer_res;
aaf8b49e 487
5c0f4829 488 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
aaf8b49e
RS
489}
490
2611015c
TJ
491static int mixer_setup_scale(const struct exynos_drm_plane *plane,
492 unsigned int *x_ratio, unsigned int *y_ratio)
493{
494 if (plane->crtc_width != plane->src_width) {
495 if (plane->crtc_width == 2 * plane->src_width)
496 *x_ratio = 1;
497 else
498 goto fail;
499 }
500
501 if (plane->crtc_height != plane->src_height) {
502 if (plane->crtc_height == 2 * plane->src_height)
503 *y_ratio = 1;
504 else
505 goto fail;
506 }
507
508 return 0;
509
510fail:
511 DRM_DEBUG_KMS("only 2x width/height scaling of plane supported\n");
512 return -ENOTSUPP;
513}
514
5b1d5bc6 515static void mixer_graph_buffer(struct mixer_context *ctx, unsigned int win)
d8408326
SWK
516{
517 struct mixer_resources *res = &ctx->mixer_res;
518 unsigned long flags;
7ee14cdc 519 struct exynos_drm_plane *plane;
2611015c 520 unsigned int x_ratio = 0, y_ratio = 0;
d8408326 521 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
d8408326
SWK
522 dma_addr_t dma_addr;
523 unsigned int fmt;
524 u32 val;
525
7ee14cdc 526 plane = &ctx->planes[win];
d8408326 527
7a57ca7c
TJ
528 switch (plane->pixel_format) {
529 case DRM_FORMAT_XRGB4444:
530 fmt = MXR_FORMAT_ARGB4444;
531 break;
532
533 case DRM_FORMAT_XRGB1555:
534 fmt = MXR_FORMAT_ARGB1555;
535 break;
d8408326 536
7a57ca7c
TJ
537 case DRM_FORMAT_RGB565:
538 fmt = MXR_FORMAT_RGB565;
d8408326 539 break;
7a57ca7c
TJ
540
541 case DRM_FORMAT_XRGB8888:
542 case DRM_FORMAT_ARGB8888:
543 fmt = MXR_FORMAT_ARGB8888;
d8408326 544 break;
7a57ca7c 545
d8408326 546 default:
7a57ca7c
TJ
547 DRM_DEBUG_KMS("pixelformat unsupported by mixer\n");
548 return;
d8408326
SWK
549 }
550
2611015c
TJ
551 /* check if mixer supports requested scaling setup */
552 if (mixer_setup_scale(plane, &x_ratio, &y_ratio))
553 return;
d8408326 554
7ee14cdc
GP
555 dst_x_offset = plane->crtc_x;
556 dst_y_offset = plane->crtc_y;
d8408326
SWK
557
558 /* converting dma address base and source offset */
7ee14cdc 559 dma_addr = plane->dma_addr[0]
cb8a3db2
JS
560 + (plane->src_x * plane->bpp >> 3)
561 + (plane->src_y * plane->pitch);
d8408326
SWK
562 src_x_offset = 0;
563 src_y_offset = 0;
564
7ee14cdc 565 if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE)
d8408326
SWK
566 ctx->interlace = true;
567 else
568 ctx->interlace = false;
569
570 spin_lock_irqsave(&res->reg_slock, flags);
571 mixer_vsync_set_update(ctx, false);
572
573 /* setup format */
574 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
575 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
576
577 /* setup geometry */
adacb228 578 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win),
7ee14cdc 579 plane->pitch / (plane->bpp >> 3));
d8408326 580
def5e095
RS
581 /* setup display size */
582 if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
583 win == MIXER_DEFAULT_WIN) {
7ee14cdc
GP
584 val = MXR_MXR_RES_HEIGHT(plane->mode_height);
585 val |= MXR_MXR_RES_WIDTH(plane->mode_width);
def5e095
RS
586 mixer_reg_write(res, MXR_RESOLUTION, val);
587 }
588
2611015c
TJ
589 val = MXR_GRP_WH_WIDTH(plane->src_width);
590 val |= MXR_GRP_WH_HEIGHT(plane->src_height);
d8408326
SWK
591 val |= MXR_GRP_WH_H_SCALE(x_ratio);
592 val |= MXR_GRP_WH_V_SCALE(y_ratio);
593 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
594
595 /* setup offsets in source image */
596 val = MXR_GRP_SXY_SX(src_x_offset);
597 val |= MXR_GRP_SXY_SY(src_y_offset);
598 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
599
600 /* setup offsets in display image */
601 val = MXR_GRP_DXY_DX(dst_x_offset);
602 val |= MXR_GRP_DXY_DY(dst_y_offset);
603 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
604
605 /* set buffer address to mixer */
606 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
607
7ee14cdc
GP
608 mixer_cfg_scan(ctx, plane->mode_height);
609 mixer_cfg_rgb_fmt(ctx, plane->mode_height);
d8408326 610 mixer_cfg_layer(ctx, win, true);
aaf8b49e
RS
611
612 /* layer update mandatory for mixer 16.0.33.0 */
def5e095
RS
613 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
614 ctx->mxr_ver == MXR_VER_128_0_0_184)
aaf8b49e
RS
615 mixer_layer_update(ctx);
616
d8408326
SWK
617 mixer_run(ctx);
618
619 mixer_vsync_set_update(ctx, true);
620 spin_unlock_irqrestore(&res->reg_slock, flags);
c0734fba
TJ
621
622 mixer_regs_dump(ctx);
d8408326
SWK
623}
624
625static void vp_win_reset(struct mixer_context *ctx)
626{
627 struct mixer_resources *res = &ctx->mixer_res;
628 int tries = 100;
629
630 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
631 for (tries = 100; tries; --tries) {
632 /* waiting until VP_SRESET_PROCESSING is 0 */
633 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
634 break;
09760ea3 635 usleep_range(10000, 12000);
d8408326
SWK
636 }
637 WARN(tries == 0, "failed to reset Video Processor\n");
638}
639
cf8fc4f1
JS
640static void mixer_win_reset(struct mixer_context *ctx)
641{
642 struct mixer_resources *res = &ctx->mixer_res;
643 unsigned long flags;
644 u32 val; /* value stored to register */
645
646 spin_lock_irqsave(&res->reg_slock, flags);
647 mixer_vsync_set_update(ctx, false);
648
649 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
650
651 /* set output in RGB888 mode */
652 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
653
654 /* 16 beat burst in DMA */
655 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
656 MXR_STATUS_BURST_MASK);
657
658 /* setting default layer priority: layer1 > layer0 > video
659 * because typical usage scenario would be
660 * layer1 - OSD
661 * layer0 - framebuffer
662 * video - video overlay
663 */
664 val = MXR_LAYER_CFG_GRP1_VAL(3);
665 val |= MXR_LAYER_CFG_GRP0_VAL(2);
1b8e5747
RS
666 if (ctx->vp_enabled)
667 val |= MXR_LAYER_CFG_VP_VAL(1);
cf8fc4f1
JS
668 mixer_reg_write(res, MXR_LAYER_CFG, val);
669
670 /* setting background color */
671 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
672 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
673 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
674
675 /* setting graphical layers */
cf8fc4f1
JS
676 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
677 val |= MXR_GRP_CFG_WIN_BLEND_EN;
678 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
679
0377f4ed 680 /* Don't blend layer 0 onto the mixer background */
cf8fc4f1 681 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
0377f4ed
SP
682
683 /* Blend layer 1 into layer 0 */
684 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
685 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
cf8fc4f1
JS
686 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
687
5736603b
SWK
688 /* setting video layers */
689 val = MXR_GRP_CFG_ALPHA_VAL(0);
690 mixer_reg_write(res, MXR_VIDEO_CFG, val);
691
1b8e5747
RS
692 if (ctx->vp_enabled) {
693 /* configuration of Video Processor Registers */
694 vp_win_reset(ctx);
695 vp_default_filter(res);
696 }
cf8fc4f1
JS
697
698 /* disable all layers */
699 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
700 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
1b8e5747
RS
701 if (ctx->vp_enabled)
702 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
cf8fc4f1
JS
703
704 mixer_vsync_set_update(ctx, true);
705 spin_unlock_irqrestore(&res->reg_slock, flags);
706}
707
4551789f
SP
708static irqreturn_t mixer_irq_handler(int irq, void *arg)
709{
710 struct mixer_context *ctx = arg;
711 struct mixer_resources *res = &ctx->mixer_res;
712 u32 val, base, shadow;
713
714 spin_lock(&res->reg_slock);
715
716 /* read interrupt status for handling and clearing flags for VSYNC */
717 val = mixer_reg_read(res, MXR_INT_STATUS);
718
719 /* handling VSYNC */
720 if (val & MXR_INT_STATUS_VSYNC) {
9859e203
AH
721 /* vsync interrupt use different bit for read and clear */
722 val |= MXR_INT_CLEAR_VSYNC;
723 val &= ~MXR_INT_STATUS_VSYNC;
724
4551789f
SP
725 /* interlace scan need to check shadow register */
726 if (ctx->interlace) {
727 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
728 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
729 if (base != shadow)
730 goto out;
731
732 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
733 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
734 if (base != shadow)
735 goto out;
736 }
737
738 drm_handle_vblank(ctx->drm_dev, ctx->pipe);
739 exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
740
741 /* set wait vsync event to zero and wake up queue. */
742 if (atomic_read(&ctx->wait_vsync_event)) {
743 atomic_set(&ctx->wait_vsync_event, 0);
744 wake_up(&ctx->wait_vsync_queue);
745 }
746 }
747
748out:
749 /* clear interrupts */
4551789f
SP
750 mixer_reg_write(res, MXR_INT_STATUS, val);
751
752 spin_unlock(&res->reg_slock);
753
754 return IRQ_HANDLED;
755}
756
757static int mixer_resources_init(struct mixer_context *mixer_ctx)
758{
759 struct device *dev = &mixer_ctx->pdev->dev;
760 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
761 struct resource *res;
762 int ret;
763
764 spin_lock_init(&mixer_res->reg_slock);
765
766 mixer_res->mixer = devm_clk_get(dev, "mixer");
767 if (IS_ERR(mixer_res->mixer)) {
768 dev_err(dev, "failed to get clock 'mixer'\n");
769 return -ENODEV;
770 }
771
04427ec5
MS
772 mixer_res->hdmi = devm_clk_get(dev, "hdmi");
773 if (IS_ERR(mixer_res->hdmi)) {
774 dev_err(dev, "failed to get clock 'hdmi'\n");
775 return PTR_ERR(mixer_res->hdmi);
776 }
777
4551789f
SP
778 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
779 if (IS_ERR(mixer_res->sclk_hdmi)) {
780 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
781 return -ENODEV;
782 }
783 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
784 if (res == NULL) {
785 dev_err(dev, "get memory resource failed.\n");
786 return -ENXIO;
787 }
788
789 mixer_res->mixer_regs = devm_ioremap(dev, res->start,
790 resource_size(res));
791 if (mixer_res->mixer_regs == NULL) {
792 dev_err(dev, "register mapping failed.\n");
793 return -ENXIO;
794 }
795
796 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
797 if (res == NULL) {
798 dev_err(dev, "get interrupt resource failed.\n");
799 return -ENXIO;
800 }
801
802 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
803 0, "drm_mixer", mixer_ctx);
804 if (ret) {
805 dev_err(dev, "request interrupt failed.\n");
806 return ret;
807 }
808 mixer_res->irq = res->start;
809
810 return 0;
811}
812
813static int vp_resources_init(struct mixer_context *mixer_ctx)
814{
815 struct device *dev = &mixer_ctx->pdev->dev;
816 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
817 struct resource *res;
818
819 mixer_res->vp = devm_clk_get(dev, "vp");
820 if (IS_ERR(mixer_res->vp)) {
821 dev_err(dev, "failed to get clock 'vp'\n");
822 return -ENODEV;
823 }
4551789f 824
ff830c96
MS
825 if (mixer_ctx->has_sclk) {
826 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
827 if (IS_ERR(mixer_res->sclk_mixer)) {
828 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
829 return -ENODEV;
830 }
831 mixer_res->mout_mixer = devm_clk_get(dev, "mout_mixer");
832 if (IS_ERR(mixer_res->mout_mixer)) {
833 dev_err(dev, "failed to get clock 'mout_mixer'\n");
834 return -ENODEV;
835 }
836
837 if (mixer_res->sclk_hdmi && mixer_res->mout_mixer)
838 clk_set_parent(mixer_res->mout_mixer,
839 mixer_res->sclk_hdmi);
840 }
4551789f
SP
841
842 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
843 if (res == NULL) {
844 dev_err(dev, "get memory resource failed.\n");
845 return -ENXIO;
846 }
847
848 mixer_res->vp_regs = devm_ioremap(dev, res->start,
849 resource_size(res));
850 if (mixer_res->vp_regs == NULL) {
851 dev_err(dev, "register mapping failed.\n");
852 return -ENXIO;
853 }
854
855 return 0;
856}
857
93bca243 858static int mixer_initialize(struct mixer_context *mixer_ctx,
f37cd5e8 859 struct drm_device *drm_dev)
4551789f
SP
860{
861 int ret;
f37cd5e8
ID
862 struct exynos_drm_private *priv;
863 priv = drm_dev->dev_private;
4551789f 864
eb88e422 865 mixer_ctx->drm_dev = drm_dev;
8a326edd 866 mixer_ctx->pipe = priv->pipe++;
4551789f
SP
867
868 /* acquire resources: regs, irqs, clocks */
869 ret = mixer_resources_init(mixer_ctx);
870 if (ret) {
871 DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
872 return ret;
873 }
874
875 if (mixer_ctx->vp_enabled) {
876 /* acquire vp resources: regs, irqs, clocks */
877 ret = vp_resources_init(mixer_ctx);
878 if (ret) {
879 DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
880 return ret;
881 }
882 }
883
fc2e013f
HH
884 ret = drm_iommu_attach_device_if_possible(mixer_ctx->crtc, drm_dev,
885 mixer_ctx->dev);
886 if (ret)
887 priv->pipe--;
f041b257 888
fc2e013f 889 return ret;
4551789f
SP
890}
891
93bca243 892static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
1055b39f 893{
f041b257
SP
894 if (is_drm_iommu_supported(mixer_ctx->drm_dev))
895 drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
1055b39f
ID
896}
897
93bca243 898static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
d8408326 899{
93bca243 900 struct mixer_context *mixer_ctx = crtc->ctx;
d8408326
SWK
901 struct mixer_resources *res = &mixer_ctx->mixer_res;
902
f041b257
SP
903 if (!mixer_ctx->powered) {
904 mixer_ctx->int_en |= MXR_INT_EN_VSYNC;
905 return 0;
906 }
d8408326
SWK
907
908 /* enable vsync interrupt */
4f98f944
AH
909 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
910 mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
d8408326
SWK
911
912 return 0;
913}
914
93bca243 915static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
d8408326 916{
93bca243 917 struct mixer_context *mixer_ctx = crtc->ctx;
d8408326
SWK
918 struct mixer_resources *res = &mixer_ctx->mixer_res;
919
d8408326 920 /* disable vsync interrupt */
4f98f944 921 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
d8408326
SWK
922 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
923}
924
6e2a3b66 925static void mixer_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
d8408326 926{
93bca243 927 struct mixer_context *mixer_ctx = crtc->ctx;
d8408326 928
cbc4c33d 929 DRM_DEBUG_KMS("win: %d\n", win);
d8408326 930
dda9012b
S
931 mutex_lock(&mixer_ctx->mixer_mutex);
932 if (!mixer_ctx->powered) {
933 mutex_unlock(&mixer_ctx->mixer_mutex);
934 return;
935 }
936 mutex_unlock(&mixer_ctx->mixer_mutex);
937
1b8e5747 938 if (win > 1 && mixer_ctx->vp_enabled)
d8408326
SWK
939 vp_video_buffer(mixer_ctx, win);
940 else
941 mixer_graph_buffer(mixer_ctx, win);
942}
943
6e2a3b66 944static void mixer_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
d8408326 945{
93bca243 946 struct mixer_context *mixer_ctx = crtc->ctx;
d8408326
SWK
947 struct mixer_resources *res = &mixer_ctx->mixer_res;
948 unsigned long flags;
d8408326 949
cbc4c33d 950 DRM_DEBUG_KMS("win: %d\n", win);
d8408326 951
db43fd16
P
952 mutex_lock(&mixer_ctx->mixer_mutex);
953 if (!mixer_ctx->powered) {
954 mutex_unlock(&mixer_ctx->mixer_mutex);
db43fd16
P
955 return;
956 }
957 mutex_unlock(&mixer_ctx->mixer_mutex);
958
d8408326
SWK
959 spin_lock_irqsave(&res->reg_slock, flags);
960 mixer_vsync_set_update(mixer_ctx, false);
961
962 mixer_cfg_layer(mixer_ctx, win, false);
963
964 mixer_vsync_set_update(mixer_ctx, true);
965 spin_unlock_irqrestore(&res->reg_slock, flags);
966}
967
93bca243 968static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
8137a2e2 969{
93bca243 970 struct mixer_context *mixer_ctx = crtc->ctx;
7c4c5584 971 int err;
8137a2e2 972
6e95d5e6
P
973 mutex_lock(&mixer_ctx->mixer_mutex);
974 if (!mixer_ctx->powered) {
975 mutex_unlock(&mixer_ctx->mixer_mutex);
976 return;
977 }
978 mutex_unlock(&mixer_ctx->mixer_mutex);
979
93bca243 980 err = drm_vblank_get(mixer_ctx->drm_dev, mixer_ctx->pipe);
7c4c5584
JS
981 if (err < 0) {
982 DRM_DEBUG_KMS("failed to acquire vblank counter\n");
983 return;
984 }
5d39b9ee 985
6e95d5e6
P
986 atomic_set(&mixer_ctx->wait_vsync_event, 1);
987
988 /*
989 * wait for MIXER to signal VSYNC interrupt or return after
990 * timeout which is set to 50ms (refresh rate of 20).
991 */
992 if (!wait_event_timeout(mixer_ctx->wait_vsync_queue,
993 !atomic_read(&mixer_ctx->wait_vsync_event),
bfd8303a 994 HZ/20))
8137a2e2 995 DRM_DEBUG_KMS("vblank wait timed out.\n");
5d39b9ee 996
93bca243 997 drm_vblank_put(mixer_ctx->drm_dev, mixer_ctx->pipe);
8137a2e2
P
998}
999
3cecda03 1000static void mixer_enable(struct exynos_drm_crtc *crtc)
db43fd16 1001{
3cecda03 1002 struct mixer_context *ctx = crtc->ctx;
db43fd16 1003 struct mixer_resources *res = &ctx->mixer_res;
38000dbb 1004 int ret;
db43fd16 1005
db43fd16
P
1006 mutex_lock(&ctx->mixer_mutex);
1007 if (ctx->powered) {
1008 mutex_unlock(&ctx->mixer_mutex);
1009 return;
1010 }
b4bfa3c7 1011
db43fd16
P
1012 mutex_unlock(&ctx->mixer_mutex);
1013
af65c804
SP
1014 pm_runtime_get_sync(ctx->dev);
1015
38000dbb
GP
1016 ret = clk_prepare_enable(res->mixer);
1017 if (ret < 0) {
1018 DRM_ERROR("Failed to prepare_enable the mixer clk [%d]\n", ret);
1019 return;
1020 }
1021 ret = clk_prepare_enable(res->hdmi);
1022 if (ret < 0) {
1023 DRM_ERROR("Failed to prepare_enable the hdmi clk [%d]\n", ret);
1024 return;
1025 }
db43fd16 1026 if (ctx->vp_enabled) {
38000dbb
GP
1027 ret = clk_prepare_enable(res->vp);
1028 if (ret < 0) {
1029 DRM_ERROR("Failed to prepare_enable the vp clk [%d]\n",
1030 ret);
1031 return;
1032 }
1033 if (ctx->has_sclk) {
1034 ret = clk_prepare_enable(res->sclk_mixer);
1035 if (ret < 0) {
1036 DRM_ERROR("Failed to prepare_enable the " \
1037 "sclk_mixer clk [%d]\n",
1038 ret);
1039 return;
1040 }
1041 }
db43fd16
P
1042 }
1043
b4bfa3c7
RS
1044 mutex_lock(&ctx->mixer_mutex);
1045 ctx->powered = true;
1046 mutex_unlock(&ctx->mixer_mutex);
1047
d74ed937
RS
1048 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
1049
4f98f944
AH
1050 if (ctx->int_en & MXR_INT_EN_VSYNC)
1051 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
db43fd16
P
1052 mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
1053 mixer_win_reset(ctx);
db43fd16
P
1054}
1055
3cecda03 1056static void mixer_disable(struct exynos_drm_crtc *crtc)
db43fd16 1057{
3cecda03 1058 struct mixer_context *ctx = crtc->ctx;
db43fd16 1059 struct mixer_resources *res = &ctx->mixer_res;
c329f667 1060 int i;
db43fd16 1061
db43fd16 1062 mutex_lock(&ctx->mixer_mutex);
b4bfa3c7
RS
1063 if (!ctx->powered) {
1064 mutex_unlock(&ctx->mixer_mutex);
1065 return;
1066 }
db43fd16
P
1067 mutex_unlock(&ctx->mixer_mutex);
1068
381be025 1069 mixer_stop(ctx);
c0734fba 1070 mixer_regs_dump(ctx);
c329f667
JS
1071
1072 for (i = 0; i < MIXER_WIN_NR; i++)
1073 mixer_win_disable(crtc, i);
db43fd16
P
1074
1075 ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
1076
b4bfa3c7
RS
1077 mutex_lock(&ctx->mixer_mutex);
1078 ctx->powered = false;
1079 mutex_unlock(&ctx->mixer_mutex);
1080
04427ec5 1081 clk_disable_unprepare(res->hdmi);
0bfb1f8b 1082 clk_disable_unprepare(res->mixer);
db43fd16 1083 if (ctx->vp_enabled) {
0bfb1f8b 1084 clk_disable_unprepare(res->vp);
ff830c96
MS
1085 if (ctx->has_sclk)
1086 clk_disable_unprepare(res->sclk_mixer);
db43fd16
P
1087 }
1088
af65c804 1089 pm_runtime_put_sync(ctx->dev);
db43fd16
P
1090}
1091
f041b257
SP
1092/* Only valid for Mixer version 16.0.33.0 */
1093int mixer_check_mode(struct drm_display_mode *mode)
1094{
1095 u32 w, h;
1096
1097 w = mode->hdisplay;
1098 h = mode->vdisplay;
1099
1100 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
1101 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1102 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1103
1104 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
1105 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1106 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1107 return 0;
1108
1109 return -EINVAL;
1110}
1111
f3aaf762 1112static const struct exynos_drm_crtc_ops mixer_crtc_ops = {
3cecda03
GP
1113 .enable = mixer_enable,
1114 .disable = mixer_disable,
d8408326
SWK
1115 .enable_vblank = mixer_enable_vblank,
1116 .disable_vblank = mixer_disable_vblank,
8137a2e2 1117 .wait_for_vblank = mixer_wait_for_vblank,
d8408326
SWK
1118 .win_commit = mixer_win_commit,
1119 .win_disable = mixer_win_disable,
f041b257 1120};
0ea6822f 1121
def5e095
RS
1122static struct mixer_drv_data exynos5420_mxr_drv_data = {
1123 .version = MXR_VER_128_0_0_184,
1124 .is_vp_enabled = 0,
1125};
1126
cc57caf0 1127static struct mixer_drv_data exynos5250_mxr_drv_data = {
aaf8b49e
RS
1128 .version = MXR_VER_16_0_33_0,
1129 .is_vp_enabled = 0,
1130};
1131
ff830c96
MS
1132static struct mixer_drv_data exynos4212_mxr_drv_data = {
1133 .version = MXR_VER_0_0_0_16,
1134 .is_vp_enabled = 1,
1135};
1136
cc57caf0 1137static struct mixer_drv_data exynos4210_mxr_drv_data = {
1e123441 1138 .version = MXR_VER_0_0_0_16,
1b8e5747 1139 .is_vp_enabled = 1,
ff830c96 1140 .has_sclk = 1,
1e123441
RS
1141};
1142
d6b16302 1143static const struct platform_device_id mixer_driver_types[] = {
1e123441
RS
1144 {
1145 .name = "s5p-mixer",
cc57caf0 1146 .driver_data = (unsigned long)&exynos4210_mxr_drv_data,
aaf8b49e
RS
1147 }, {
1148 .name = "exynos5-mixer",
cc57caf0 1149 .driver_data = (unsigned long)&exynos5250_mxr_drv_data,
aaf8b49e
RS
1150 }, {
1151 /* end node */
1152 }
1153};
1154
1155static struct of_device_id mixer_match_types[] = {
1156 {
ff830c96
MS
1157 .compatible = "samsung,exynos4210-mixer",
1158 .data = &exynos4210_mxr_drv_data,
1159 }, {
1160 .compatible = "samsung,exynos4212-mixer",
1161 .data = &exynos4212_mxr_drv_data,
1162 }, {
aaf8b49e 1163 .compatible = "samsung,exynos5-mixer",
cc57caf0
RS
1164 .data = &exynos5250_mxr_drv_data,
1165 }, {
1166 .compatible = "samsung,exynos5250-mixer",
1167 .data = &exynos5250_mxr_drv_data,
def5e095
RS
1168 }, {
1169 .compatible = "samsung,exynos5420-mixer",
1170 .data = &exynos5420_mxr_drv_data,
1e123441
RS
1171 }, {
1172 /* end node */
1173 }
1174};
39b58a39 1175MODULE_DEVICE_TABLE(of, mixer_match_types);
1e123441 1176
f37cd5e8 1177static int mixer_bind(struct device *dev, struct device *manager, void *data)
d8408326 1178{
8103ef1b 1179 struct mixer_context *ctx = dev_get_drvdata(dev);
f37cd5e8 1180 struct drm_device *drm_dev = data;
7ee14cdc
GP
1181 struct exynos_drm_plane *exynos_plane;
1182 enum drm_plane_type type;
6e2a3b66
GP
1183 unsigned int zpos;
1184 int ret;
d8408326 1185
e2dc3f72
AB
1186 ret = mixer_initialize(ctx, drm_dev);
1187 if (ret)
1188 return ret;
1189
7ee14cdc
GP
1190 for (zpos = 0; zpos < MIXER_WIN_NR; zpos++) {
1191 type = (zpos == MIXER_DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY :
1192 DRM_PLANE_TYPE_OVERLAY;
1193 ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
6e2a3b66 1194 1 << ctx->pipe, type, zpos);
7ee14cdc
GP
1195 if (ret)
1196 return ret;
1197 }
1198
1199 exynos_plane = &ctx->planes[MIXER_DEFAULT_WIN];
1200 ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
1201 ctx->pipe, EXYNOS_DISPLAY_TYPE_HDMI,
1202 &mixer_crtc_ops, ctx);
93bca243 1203 if (IS_ERR(ctx->crtc)) {
e2dc3f72 1204 mixer_ctx_remove(ctx);
93bca243
GP
1205 ret = PTR_ERR(ctx->crtc);
1206 goto free_ctx;
f37cd5e8 1207 }
d8408326 1208
d8408326 1209 return 0;
93bca243
GP
1210
1211free_ctx:
1212 devm_kfree(dev, ctx);
1213 return ret;
d8408326
SWK
1214}
1215
f37cd5e8 1216static void mixer_unbind(struct device *dev, struct device *master, void *data)
d8408326 1217{
8103ef1b 1218 struct mixer_context *ctx = dev_get_drvdata(dev);
f37cd5e8 1219
93bca243 1220 mixer_ctx_remove(ctx);
f37cd5e8
ID
1221}
1222
1223static const struct component_ops mixer_component_ops = {
1224 .bind = mixer_bind,
1225 .unbind = mixer_unbind,
1226};
1227
1228static int mixer_probe(struct platform_device *pdev)
1229{
8103ef1b
AH
1230 struct device *dev = &pdev->dev;
1231 struct mixer_drv_data *drv;
1232 struct mixer_context *ctx;
df5225bc
ID
1233 int ret;
1234
8103ef1b
AH
1235 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1236 if (!ctx) {
1237 DRM_ERROR("failed to alloc mixer context.\n");
1238 return -ENOMEM;
1239 }
1240
1241 mutex_init(&ctx->mixer_mutex);
1242
8103ef1b
AH
1243 if (dev->of_node) {
1244 const struct of_device_id *match;
1245
1246 match = of_match_node(mixer_match_types, dev->of_node);
1247 drv = (struct mixer_drv_data *)match->data;
1248 } else {
1249 drv = (struct mixer_drv_data *)
1250 platform_get_device_id(pdev)->driver_data;
1251 }
1252
1253 ctx->pdev = pdev;
1254 ctx->dev = dev;
1255 ctx->vp_enabled = drv->is_vp_enabled;
1256 ctx->has_sclk = drv->has_sclk;
1257 ctx->mxr_ver = drv->version;
1258 init_waitqueue_head(&ctx->wait_vsync_queue);
1259 atomic_set(&ctx->wait_vsync_event, 0);
8103ef1b
AH
1260
1261 platform_set_drvdata(pdev, ctx);
1262
df5225bc 1263 ret = component_add(&pdev->dev, &mixer_component_ops);
86650408
AH
1264 if (!ret)
1265 pm_runtime_enable(dev);
df5225bc
ID
1266
1267 return ret;
f37cd5e8
ID
1268}
1269
1270static int mixer_remove(struct platform_device *pdev)
1271{
8103ef1b
AH
1272 pm_runtime_disable(&pdev->dev);
1273
df5225bc 1274 component_del(&pdev->dev, &mixer_component_ops);
df5225bc 1275
d8408326
SWK
1276 return 0;
1277}
1278
1279struct platform_driver mixer_driver = {
1280 .driver = {
aaf8b49e 1281 .name = "exynos-mixer",
d8408326 1282 .owner = THIS_MODULE,
aaf8b49e 1283 .of_match_table = mixer_match_types,
d8408326
SWK
1284 },
1285 .probe = mixer_probe,
56550d94 1286 .remove = mixer_remove,
1e123441 1287 .id_table = mixer_driver_types,
d8408326 1288};