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