drm/exynos: modify wait_for_vblank of fimd
[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>
26#include <linux/module.h>
27#include <linux/platform_device.h>
28#include <linux/interrupt.h>
29#include <linux/irq.h>
30#include <linux/delay.h>
31#include <linux/pm_runtime.h>
32#include <linux/clk.h>
33#include <linux/regulator/consumer.h>
34
35#include <drm/exynos_drm.h>
36
37#include "exynos_drm_drv.h"
38#include "exynos_drm_hdmi.h"
1055b39f 39#include "exynos_drm_iommu.h"
22b21ae6 40
d8408326
SWK
41#define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev))
42
22b21ae6
JS
43struct hdmi_win_data {
44 dma_addr_t dma_addr;
45 void __iomem *vaddr;
46 dma_addr_t chroma_dma_addr;
47 void __iomem *chroma_vaddr;
48 uint32_t pixel_format;
49 unsigned int bpp;
50 unsigned int crtc_x;
51 unsigned int crtc_y;
52 unsigned int crtc_width;
53 unsigned int crtc_height;
54 unsigned int fb_x;
55 unsigned int fb_y;
56 unsigned int fb_width;
57 unsigned int fb_height;
8dcb96b6
SWK
58 unsigned int src_width;
59 unsigned int src_height;
22b21ae6
JS
60 unsigned int mode_width;
61 unsigned int mode_height;
62 unsigned int scan_flags;
63};
64
65struct mixer_resources {
22b21ae6
JS
66 int irq;
67 void __iomem *mixer_regs;
68 void __iomem *vp_regs;
69 spinlock_t reg_slock;
70 struct clk *mixer;
71 struct clk *vp;
72 struct clk *sclk_mixer;
73 struct clk *sclk_hdmi;
74 struct clk *sclk_dac;
75};
76
1e123441
RS
77enum mixer_version_id {
78 MXR_VER_0_0_0_16,
79 MXR_VER_16_0_33_0,
80};
81
22b21ae6 82struct mixer_context {
cf8fc4f1 83 struct device *dev;
1055b39f 84 struct drm_device *drm_dev;
22b21ae6
JS
85 int pipe;
86 bool interlace;
cf8fc4f1 87 bool powered;
1b8e5747 88 bool vp_enabled;
cf8fc4f1 89 u32 int_en;
22b21ae6 90
cf8fc4f1 91 struct mutex mixer_mutex;
22b21ae6 92 struct mixer_resources mixer_res;
a634dd54 93 struct hdmi_win_data win_data[MIXER_WIN_NR];
1e123441 94 enum mixer_version_id mxr_ver;
1055b39f 95 void *parent_ctx;
6e95d5e6
P
96 wait_queue_head_t wait_vsync_queue;
97 atomic_t wait_vsync_event;
1e123441
RS
98};
99
100struct mixer_drv_data {
101 enum mixer_version_id version;
1b8e5747 102 bool is_vp_enabled;
22b21ae6
JS
103};
104
d8408326
SWK
105static const u8 filter_y_horiz_tap8[] = {
106 0, -1, -1, -1, -1, -1, -1, -1,
107 -1, -1, -1, -1, -1, 0, 0, 0,
108 0, 2, 4, 5, 6, 6, 6, 6,
109 6, 5, 5, 4, 3, 2, 1, 1,
110 0, -6, -12, -16, -18, -20, -21, -20,
111 -20, -18, -16, -13, -10, -8, -5, -2,
112 127, 126, 125, 121, 114, 107, 99, 89,
113 79, 68, 57, 46, 35, 25, 16, 8,
114};
115
116static const u8 filter_y_vert_tap4[] = {
117 0, -3, -6, -8, -8, -8, -8, -7,
118 -6, -5, -4, -3, -2, -1, -1, 0,
119 127, 126, 124, 118, 111, 102, 92, 81,
120 70, 59, 48, 37, 27, 19, 11, 5,
121 0, 5, 11, 19, 27, 37, 48, 59,
122 70, 81, 92, 102, 111, 118, 124, 126,
123 0, 0, -1, -1, -2, -3, -4, -5,
124 -6, -7, -8, -8, -8, -8, -6, -3,
125};
126
127static const u8 filter_cr_horiz_tap4[] = {
128 0, -3, -6, -8, -8, -8, -8, -7,
129 -6, -5, -4, -3, -2, -1, -1, 0,
130 127, 126, 124, 118, 111, 102, 92, 81,
131 70, 59, 48, 37, 27, 19, 11, 5,
132};
133
134static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
135{
136 return readl(res->vp_regs + reg_id);
137}
138
139static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
140 u32 val)
141{
142 writel(val, res->vp_regs + reg_id);
143}
144
145static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
146 u32 val, u32 mask)
147{
148 u32 old = vp_reg_read(res, reg_id);
149
150 val = (val & mask) | (old & ~mask);
151 writel(val, res->vp_regs + reg_id);
152}
153
154static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
155{
156 return readl(res->mixer_regs + reg_id);
157}
158
159static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
160 u32 val)
161{
162 writel(val, res->mixer_regs + reg_id);
163}
164
165static inline void mixer_reg_writemask(struct mixer_resources *res,
166 u32 reg_id, u32 val, u32 mask)
167{
168 u32 old = mixer_reg_read(res, reg_id);
169
170 val = (val & mask) | (old & ~mask);
171 writel(val, res->mixer_regs + reg_id);
172}
173
174static void mixer_regs_dump(struct mixer_context *ctx)
175{
176#define DUMPREG(reg_id) \
177do { \
178 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
179 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
180} while (0)
181
182 DUMPREG(MXR_STATUS);
183 DUMPREG(MXR_CFG);
184 DUMPREG(MXR_INT_EN);
185 DUMPREG(MXR_INT_STATUS);
186
187 DUMPREG(MXR_LAYER_CFG);
188 DUMPREG(MXR_VIDEO_CFG);
189
190 DUMPREG(MXR_GRAPHIC0_CFG);
191 DUMPREG(MXR_GRAPHIC0_BASE);
192 DUMPREG(MXR_GRAPHIC0_SPAN);
193 DUMPREG(MXR_GRAPHIC0_WH);
194 DUMPREG(MXR_GRAPHIC0_SXY);
195 DUMPREG(MXR_GRAPHIC0_DXY);
196
197 DUMPREG(MXR_GRAPHIC1_CFG);
198 DUMPREG(MXR_GRAPHIC1_BASE);
199 DUMPREG(MXR_GRAPHIC1_SPAN);
200 DUMPREG(MXR_GRAPHIC1_WH);
201 DUMPREG(MXR_GRAPHIC1_SXY);
202 DUMPREG(MXR_GRAPHIC1_DXY);
203#undef DUMPREG
204}
205
206static void vp_regs_dump(struct mixer_context *ctx)
207{
208#define DUMPREG(reg_id) \
209do { \
210 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
211 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
212} while (0)
213
214 DUMPREG(VP_ENABLE);
215 DUMPREG(VP_SRESET);
216 DUMPREG(VP_SHADOW_UPDATE);
217 DUMPREG(VP_FIELD_ID);
218 DUMPREG(VP_MODE);
219 DUMPREG(VP_IMG_SIZE_Y);
220 DUMPREG(VP_IMG_SIZE_C);
221 DUMPREG(VP_PER_RATE_CTRL);
222 DUMPREG(VP_TOP_Y_PTR);
223 DUMPREG(VP_BOT_Y_PTR);
224 DUMPREG(VP_TOP_C_PTR);
225 DUMPREG(VP_BOT_C_PTR);
226 DUMPREG(VP_ENDIAN_MODE);
227 DUMPREG(VP_SRC_H_POSITION);
228 DUMPREG(VP_SRC_V_POSITION);
229 DUMPREG(VP_SRC_WIDTH);
230 DUMPREG(VP_SRC_HEIGHT);
231 DUMPREG(VP_DST_H_POSITION);
232 DUMPREG(VP_DST_V_POSITION);
233 DUMPREG(VP_DST_WIDTH);
234 DUMPREG(VP_DST_HEIGHT);
235 DUMPREG(VP_H_RATIO);
236 DUMPREG(VP_V_RATIO);
237
238#undef DUMPREG
239}
240
241static inline void vp_filter_set(struct mixer_resources *res,
242 int reg_id, const u8 *data, unsigned int size)
243{
244 /* assure 4-byte align */
245 BUG_ON(size & 3);
246 for (; size; size -= 4, reg_id += 4, data += 4) {
247 u32 val = (data[0] << 24) | (data[1] << 16) |
248 (data[2] << 8) | data[3];
249 vp_reg_write(res, reg_id, val);
250 }
251}
252
253static void vp_default_filter(struct mixer_resources *res)
254{
255 vp_filter_set(res, VP_POLY8_Y0_LL,
e25e1b66 256 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
d8408326 257 vp_filter_set(res, VP_POLY4_Y0_LL,
e25e1b66 258 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
d8408326 259 vp_filter_set(res, VP_POLY4_C0_LL,
e25e1b66 260 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
d8408326
SWK
261}
262
263static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
264{
265 struct mixer_resources *res = &ctx->mixer_res;
266
267 /* block update on vsync */
268 mixer_reg_writemask(res, MXR_STATUS, enable ?
269 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
270
1b8e5747
RS
271 if (ctx->vp_enabled)
272 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
d8408326
SWK
273 VP_SHADOW_UPDATE_ENABLE : 0);
274}
275
276static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
277{
278 struct mixer_resources *res = &ctx->mixer_res;
279 u32 val;
280
281 /* choosing between interlace and progressive mode */
282 val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
283 MXR_CFG_SCAN_PROGRASSIVE);
284
285 /* choosing between porper HD and SD mode */
286 if (height == 480)
287 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
288 else if (height == 576)
289 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
290 else if (height == 720)
291 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
292 else if (height == 1080)
293 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
294 else
295 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
296
297 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
298}
299
300static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
301{
302 struct mixer_resources *res = &ctx->mixer_res;
303 u32 val;
304
305 if (height == 480) {
306 val = MXR_CFG_RGB601_0_255;
307 } else if (height == 576) {
308 val = MXR_CFG_RGB601_0_255;
309 } else if (height == 720) {
310 val = MXR_CFG_RGB709_16_235;
311 mixer_reg_write(res, MXR_CM_COEFF_Y,
312 (1 << 30) | (94 << 20) | (314 << 10) |
313 (32 << 0));
314 mixer_reg_write(res, MXR_CM_COEFF_CB,
315 (972 << 20) | (851 << 10) | (225 << 0));
316 mixer_reg_write(res, MXR_CM_COEFF_CR,
317 (225 << 20) | (820 << 10) | (1004 << 0));
318 } else if (height == 1080) {
319 val = MXR_CFG_RGB709_16_235;
320 mixer_reg_write(res, MXR_CM_COEFF_Y,
321 (1 << 30) | (94 << 20) | (314 << 10) |
322 (32 << 0));
323 mixer_reg_write(res, MXR_CM_COEFF_CB,
324 (972 << 20) | (851 << 10) | (225 << 0));
325 mixer_reg_write(res, MXR_CM_COEFF_CR,
326 (225 << 20) | (820 << 10) | (1004 << 0));
327 } else {
328 val = MXR_CFG_RGB709_16_235;
329 mixer_reg_write(res, MXR_CM_COEFF_Y,
330 (1 << 30) | (94 << 20) | (314 << 10) |
331 (32 << 0));
332 mixer_reg_write(res, MXR_CM_COEFF_CB,
333 (972 << 20) | (851 << 10) | (225 << 0));
334 mixer_reg_write(res, MXR_CM_COEFF_CR,
335 (225 << 20) | (820 << 10) | (1004 << 0));
336 }
337
338 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
339}
340
341static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable)
342{
343 struct mixer_resources *res = &ctx->mixer_res;
344 u32 val = enable ? ~0 : 0;
345
346 switch (win) {
347 case 0:
348 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
349 break;
350 case 1:
351 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
352 break;
353 case 2:
1b8e5747
RS
354 if (ctx->vp_enabled) {
355 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
356 mixer_reg_writemask(res, MXR_CFG, val,
357 MXR_CFG_VP_ENABLE);
358 }
d8408326
SWK
359 break;
360 }
361}
362
363static void mixer_run(struct mixer_context *ctx)
364{
365 struct mixer_resources *res = &ctx->mixer_res;
366
367 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
368
369 mixer_regs_dump(ctx);
370}
371
372static void vp_video_buffer(struct mixer_context *ctx, int win)
373{
374 struct mixer_resources *res = &ctx->mixer_res;
375 unsigned long flags;
376 struct hdmi_win_data *win_data;
d8408326 377 unsigned int x_ratio, y_ratio;
d8408326
SWK
378 unsigned int buf_num;
379 dma_addr_t luma_addr[2], chroma_addr[2];
380 bool tiled_mode = false;
381 bool crcb_mode = false;
382 u32 val;
383
384 win_data = &ctx->win_data[win];
385
386 switch (win_data->pixel_format) {
387 case DRM_FORMAT_NV12MT:
388 tiled_mode = true;
363b06aa 389 case DRM_FORMAT_NV12:
d8408326
SWK
390 crcb_mode = false;
391 buf_num = 2;
392 break;
393 /* TODO: single buffer format NV12, NV21 */
394 default:
395 /* ignore pixel format at disable time */
396 if (!win_data->dma_addr)
397 break;
398
399 DRM_ERROR("pixel format for vp is wrong [%d].\n",
400 win_data->pixel_format);
401 return;
402 }
403
d8408326 404 /* scaling feature: (src << 16) / dst */
8dcb96b6
SWK
405 x_ratio = (win_data->src_width << 16) / win_data->crtc_width;
406 y_ratio = (win_data->src_height << 16) / win_data->crtc_height;
d8408326
SWK
407
408 if (buf_num == 2) {
409 luma_addr[0] = win_data->dma_addr;
410 chroma_addr[0] = win_data->chroma_dma_addr;
411 } else {
412 luma_addr[0] = win_data->dma_addr;
413 chroma_addr[0] = win_data->dma_addr
8dcb96b6 414 + (win_data->fb_width * win_data->fb_height);
d8408326
SWK
415 }
416
417 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) {
418 ctx->interlace = true;
419 if (tiled_mode) {
420 luma_addr[1] = luma_addr[0] + 0x40;
421 chroma_addr[1] = chroma_addr[0] + 0x40;
422 } else {
8dcb96b6
SWK
423 luma_addr[1] = luma_addr[0] + win_data->fb_width;
424 chroma_addr[1] = chroma_addr[0] + win_data->fb_width;
d8408326
SWK
425 }
426 } else {
427 ctx->interlace = false;
428 luma_addr[1] = 0;
429 chroma_addr[1] = 0;
430 }
431
432 spin_lock_irqsave(&res->reg_slock, flags);
433 mixer_vsync_set_update(ctx, false);
434
435 /* interlace or progressive scan mode */
436 val = (ctx->interlace ? ~0 : 0);
437 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
438
439 /* setup format */
440 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
441 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
442 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
443
444 /* setting size of input image */
8dcb96b6
SWK
445 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_width) |
446 VP_IMG_VSIZE(win_data->fb_height));
d8408326 447 /* chroma height has to reduced by 2 to avoid chroma distorions */
8dcb96b6
SWK
448 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(win_data->fb_width) |
449 VP_IMG_VSIZE(win_data->fb_height / 2));
d8408326 450
8dcb96b6
SWK
451 vp_reg_write(res, VP_SRC_WIDTH, win_data->src_width);
452 vp_reg_write(res, VP_SRC_HEIGHT, win_data->src_height);
d8408326 453 vp_reg_write(res, VP_SRC_H_POSITION,
8dcb96b6
SWK
454 VP_SRC_H_POSITION_VAL(win_data->fb_x));
455 vp_reg_write(res, VP_SRC_V_POSITION, win_data->fb_y);
d8408326 456
8dcb96b6
SWK
457 vp_reg_write(res, VP_DST_WIDTH, win_data->crtc_width);
458 vp_reg_write(res, VP_DST_H_POSITION, win_data->crtc_x);
d8408326 459 if (ctx->interlace) {
8dcb96b6
SWK
460 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height / 2);
461 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y / 2);
d8408326 462 } else {
8dcb96b6
SWK
463 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height);
464 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y);
d8408326
SWK
465 }
466
467 vp_reg_write(res, VP_H_RATIO, x_ratio);
468 vp_reg_write(res, VP_V_RATIO, y_ratio);
469
470 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
471
472 /* set buffer address to vp */
473 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
474 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
475 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
476 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
477
8dcb96b6
SWK
478 mixer_cfg_scan(ctx, win_data->mode_height);
479 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
d8408326
SWK
480 mixer_cfg_layer(ctx, win, true);
481 mixer_run(ctx);
482
483 mixer_vsync_set_update(ctx, true);
484 spin_unlock_irqrestore(&res->reg_slock, flags);
485
486 vp_regs_dump(ctx);
487}
488
aaf8b49e
RS
489static void mixer_layer_update(struct mixer_context *ctx)
490{
491 struct mixer_resources *res = &ctx->mixer_res;
492 u32 val;
493
494 val = mixer_reg_read(res, MXR_CFG);
495
496 /* allow one update per vsync only */
497 if (!(val & MXR_CFG_LAYER_UPDATE_COUNT_MASK))
498 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
499}
500
d8408326
SWK
501static void mixer_graph_buffer(struct mixer_context *ctx, int win)
502{
503 struct mixer_resources *res = &ctx->mixer_res;
504 unsigned long flags;
505 struct hdmi_win_data *win_data;
d8408326
SWK
506 unsigned int x_ratio, y_ratio;
507 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
d8408326
SWK
508 dma_addr_t dma_addr;
509 unsigned int fmt;
510 u32 val;
511
512 win_data = &ctx->win_data[win];
513
514 #define RGB565 4
515 #define ARGB1555 5
516 #define ARGB4444 6
517 #define ARGB8888 7
518
519 switch (win_data->bpp) {
520 case 16:
521 fmt = ARGB4444;
522 break;
523 case 32:
524 fmt = ARGB8888;
525 break;
526 default:
527 fmt = ARGB8888;
528 }
529
d8408326
SWK
530 /* 2x scaling feature */
531 x_ratio = 0;
532 y_ratio = 0;
533
d8408326
SWK
534 dst_x_offset = win_data->crtc_x;
535 dst_y_offset = win_data->crtc_y;
536
537 /* converting dma address base and source offset */
8dcb96b6
SWK
538 dma_addr = win_data->dma_addr
539 + (win_data->fb_x * win_data->bpp >> 3)
540 + (win_data->fb_y * win_data->fb_width * win_data->bpp >> 3);
d8408326
SWK
541 src_x_offset = 0;
542 src_y_offset = 0;
543
544 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE)
545 ctx->interlace = true;
546 else
547 ctx->interlace = false;
548
549 spin_lock_irqsave(&res->reg_slock, flags);
550 mixer_vsync_set_update(ctx, false);
551
552 /* setup format */
553 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
554 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
555
556 /* setup geometry */
8dcb96b6 557 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), win_data->fb_width);
d8408326 558
8dcb96b6
SWK
559 val = MXR_GRP_WH_WIDTH(win_data->crtc_width);
560 val |= MXR_GRP_WH_HEIGHT(win_data->crtc_height);
d8408326
SWK
561 val |= MXR_GRP_WH_H_SCALE(x_ratio);
562 val |= MXR_GRP_WH_V_SCALE(y_ratio);
563 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
564
565 /* setup offsets in source image */
566 val = MXR_GRP_SXY_SX(src_x_offset);
567 val |= MXR_GRP_SXY_SY(src_y_offset);
568 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
569
570 /* setup offsets in display image */
571 val = MXR_GRP_DXY_DX(dst_x_offset);
572 val |= MXR_GRP_DXY_DY(dst_y_offset);
573 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
574
575 /* set buffer address to mixer */
576 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
577
8dcb96b6
SWK
578 mixer_cfg_scan(ctx, win_data->mode_height);
579 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
d8408326 580 mixer_cfg_layer(ctx, win, true);
aaf8b49e
RS
581
582 /* layer update mandatory for mixer 16.0.33.0 */
583 if (ctx->mxr_ver == MXR_VER_16_0_33_0)
584 mixer_layer_update(ctx);
585
d8408326
SWK
586 mixer_run(ctx);
587
588 mixer_vsync_set_update(ctx, true);
589 spin_unlock_irqrestore(&res->reg_slock, flags);
590}
591
592static void vp_win_reset(struct mixer_context *ctx)
593{
594 struct mixer_resources *res = &ctx->mixer_res;
595 int tries = 100;
596
597 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
598 for (tries = 100; tries; --tries) {
599 /* waiting until VP_SRESET_PROCESSING is 0 */
600 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
601 break;
602 mdelay(10);
603 }
604 WARN(tries == 0, "failed to reset Video Processor\n");
605}
606
cf8fc4f1
JS
607static void mixer_win_reset(struct mixer_context *ctx)
608{
609 struct mixer_resources *res = &ctx->mixer_res;
610 unsigned long flags;
611 u32 val; /* value stored to register */
612
613 spin_lock_irqsave(&res->reg_slock, flags);
614 mixer_vsync_set_update(ctx, false);
615
616 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
617
618 /* set output in RGB888 mode */
619 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
620
621 /* 16 beat burst in DMA */
622 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
623 MXR_STATUS_BURST_MASK);
624
625 /* setting default layer priority: layer1 > layer0 > video
626 * because typical usage scenario would be
627 * layer1 - OSD
628 * layer0 - framebuffer
629 * video - video overlay
630 */
631 val = MXR_LAYER_CFG_GRP1_VAL(3);
632 val |= MXR_LAYER_CFG_GRP0_VAL(2);
1b8e5747
RS
633 if (ctx->vp_enabled)
634 val |= MXR_LAYER_CFG_VP_VAL(1);
cf8fc4f1
JS
635 mixer_reg_write(res, MXR_LAYER_CFG, val);
636
637 /* setting background color */
638 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
639 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
640 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
641
642 /* setting graphical layers */
cf8fc4f1
JS
643 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
644 val |= MXR_GRP_CFG_WIN_BLEND_EN;
5736603b
SWK
645 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
646 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
cf8fc4f1
JS
647 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
648
649 /* the same configuration for both layers */
650 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
cf8fc4f1
JS
651 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
652
5736603b
SWK
653 /* setting video layers */
654 val = MXR_GRP_CFG_ALPHA_VAL(0);
655 mixer_reg_write(res, MXR_VIDEO_CFG, val);
656
1b8e5747
RS
657 if (ctx->vp_enabled) {
658 /* configuration of Video Processor Registers */
659 vp_win_reset(ctx);
660 vp_default_filter(res);
661 }
cf8fc4f1
JS
662
663 /* disable all layers */
664 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
665 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
1b8e5747
RS
666 if (ctx->vp_enabled)
667 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
cf8fc4f1
JS
668
669 mixer_vsync_set_update(ctx, true);
670 spin_unlock_irqrestore(&res->reg_slock, flags);
671}
672
1055b39f
ID
673static int mixer_iommu_on(void *ctx, bool enable)
674{
675 struct exynos_drm_hdmi_context *drm_hdmi_ctx;
676 struct mixer_context *mdata = ctx;
677 struct drm_device *drm_dev;
678
679 drm_hdmi_ctx = mdata->parent_ctx;
680 drm_dev = drm_hdmi_ctx->drm_dev;
681
682 if (is_drm_iommu_supported(drm_dev)) {
683 if (enable)
684 return drm_iommu_attach_device(drm_dev, mdata->dev);
685
686 drm_iommu_detach_device(drm_dev, mdata->dev);
687 }
688 return 0;
689}
690
cf8fc4f1
JS
691static void mixer_poweron(struct mixer_context *ctx)
692{
693 struct mixer_resources *res = &ctx->mixer_res;
694
695 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
696
697 mutex_lock(&ctx->mixer_mutex);
698 if (ctx->powered) {
699 mutex_unlock(&ctx->mixer_mutex);
700 return;
701 }
702 ctx->powered = true;
703 mutex_unlock(&ctx->mixer_mutex);
704
705 pm_runtime_get_sync(ctx->dev);
706
707 clk_enable(res->mixer);
1b8e5747
RS
708 if (ctx->vp_enabled) {
709 clk_enable(res->vp);
710 clk_enable(res->sclk_mixer);
711 }
cf8fc4f1
JS
712
713 mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
714 mixer_win_reset(ctx);
715}
716
717static void mixer_poweroff(struct mixer_context *ctx)
718{
719 struct mixer_resources *res = &ctx->mixer_res;
720
721 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
722
723 mutex_lock(&ctx->mixer_mutex);
724 if (!ctx->powered)
725 goto out;
726 mutex_unlock(&ctx->mixer_mutex);
727
728 ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
729
730 clk_disable(res->mixer);
1b8e5747
RS
731 if (ctx->vp_enabled) {
732 clk_disable(res->vp);
733 clk_disable(res->sclk_mixer);
734 }
cf8fc4f1
JS
735
736 pm_runtime_put_sync(ctx->dev);
737
738 mutex_lock(&ctx->mixer_mutex);
739 ctx->powered = false;
740
741out:
742 mutex_unlock(&ctx->mixer_mutex);
743}
744
d8408326
SWK
745static int mixer_enable_vblank(void *ctx, int pipe)
746{
747 struct mixer_context *mixer_ctx = ctx;
748 struct mixer_resources *res = &mixer_ctx->mixer_res;
749
750 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
751
752 mixer_ctx->pipe = pipe;
753
754 /* enable vsync interrupt */
755 mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
756 MXR_INT_EN_VSYNC);
757
758 return 0;
759}
760
761static void mixer_disable_vblank(void *ctx)
762{
763 struct mixer_context *mixer_ctx = ctx;
764 struct mixer_resources *res = &mixer_ctx->mixer_res;
765
766 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
767
768 /* disable vsync interrupt */
769 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
770}
771
cf8fc4f1
JS
772static void mixer_dpms(void *ctx, int mode)
773{
774 struct mixer_context *mixer_ctx = ctx;
775
776 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
777
778 switch (mode) {
779 case DRM_MODE_DPMS_ON:
780 mixer_poweron(mixer_ctx);
781 break;
782 case DRM_MODE_DPMS_STANDBY:
783 case DRM_MODE_DPMS_SUSPEND:
784 case DRM_MODE_DPMS_OFF:
785 mixer_poweroff(mixer_ctx);
786 break;
787 default:
788 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
789 break;
790 }
791}
792
d8408326
SWK
793static void mixer_win_mode_set(void *ctx,
794 struct exynos_drm_overlay *overlay)
795{
796 struct mixer_context *mixer_ctx = ctx;
797 struct hdmi_win_data *win_data;
798 int win;
799
800 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
801
802 if (!overlay) {
803 DRM_ERROR("overlay is NULL\n");
804 return;
805 }
806
807 DRM_DEBUG_KMS("set [%d]x[%d] at (%d,%d) to [%d]x[%d] at (%d,%d)\n",
808 overlay->fb_width, overlay->fb_height,
809 overlay->fb_x, overlay->fb_y,
810 overlay->crtc_width, overlay->crtc_height,
811 overlay->crtc_x, overlay->crtc_y);
812
813 win = overlay->zpos;
814 if (win == DEFAULT_ZPOS)
a2ee151b 815 win = MIXER_DEFAULT_WIN;
d8408326 816
a634dd54 817 if (win < 0 || win > MIXER_WIN_NR) {
cf8fc4f1 818 DRM_ERROR("mixer window[%d] is wrong\n", win);
d8408326
SWK
819 return;
820 }
821
822 win_data = &mixer_ctx->win_data[win];
823
824 win_data->dma_addr = overlay->dma_addr[0];
825 win_data->vaddr = overlay->vaddr[0];
826 win_data->chroma_dma_addr = overlay->dma_addr[1];
827 win_data->chroma_vaddr = overlay->vaddr[1];
828 win_data->pixel_format = overlay->pixel_format;
829 win_data->bpp = overlay->bpp;
830
831 win_data->crtc_x = overlay->crtc_x;
832 win_data->crtc_y = overlay->crtc_y;
833 win_data->crtc_width = overlay->crtc_width;
834 win_data->crtc_height = overlay->crtc_height;
835
836 win_data->fb_x = overlay->fb_x;
837 win_data->fb_y = overlay->fb_y;
838 win_data->fb_width = overlay->fb_width;
839 win_data->fb_height = overlay->fb_height;
8dcb96b6
SWK
840 win_data->src_width = overlay->src_width;
841 win_data->src_height = overlay->src_height;
d8408326
SWK
842
843 win_data->mode_width = overlay->mode_width;
844 win_data->mode_height = overlay->mode_height;
845
846 win_data->scan_flags = overlay->scan_flag;
847}
848
cf8fc4f1 849static void mixer_win_commit(void *ctx, int win)
d8408326
SWK
850{
851 struct mixer_context *mixer_ctx = ctx;
d8408326
SWK
852
853 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
854
1b8e5747 855 if (win > 1 && mixer_ctx->vp_enabled)
d8408326
SWK
856 vp_video_buffer(mixer_ctx, win);
857 else
858 mixer_graph_buffer(mixer_ctx, win);
859}
860
cf8fc4f1 861static void mixer_win_disable(void *ctx, int win)
d8408326
SWK
862{
863 struct mixer_context *mixer_ctx = ctx;
864 struct mixer_resources *res = &mixer_ctx->mixer_res;
865 unsigned long flags;
d8408326
SWK
866
867 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
868
d8408326
SWK
869 spin_lock_irqsave(&res->reg_slock, flags);
870 mixer_vsync_set_update(mixer_ctx, false);
871
872 mixer_cfg_layer(mixer_ctx, win, false);
873
874 mixer_vsync_set_update(mixer_ctx, true);
875 spin_unlock_irqrestore(&res->reg_slock, flags);
876}
877
8137a2e2
P
878static void mixer_wait_for_vblank(void *ctx)
879{
880 struct mixer_context *mixer_ctx = ctx;
8137a2e2 881
6e95d5e6
P
882 mutex_lock(&mixer_ctx->mixer_mutex);
883 if (!mixer_ctx->powered) {
884 mutex_unlock(&mixer_ctx->mixer_mutex);
885 return;
886 }
887 mutex_unlock(&mixer_ctx->mixer_mutex);
888
889 atomic_set(&mixer_ctx->wait_vsync_event, 1);
890
891 /*
892 * wait for MIXER to signal VSYNC interrupt or return after
893 * timeout which is set to 50ms (refresh rate of 20).
894 */
895 if (!wait_event_timeout(mixer_ctx->wait_vsync_queue,
896 !atomic_read(&mixer_ctx->wait_vsync_event),
897 DRM_HZ/20))
8137a2e2
P
898 DRM_DEBUG_KMS("vblank wait timed out.\n");
899}
900
578b6065
JS
901static struct exynos_mixer_ops mixer_ops = {
902 /* manager */
1055b39f 903 .iommu_on = mixer_iommu_on,
d8408326
SWK
904 .enable_vblank = mixer_enable_vblank,
905 .disable_vblank = mixer_disable_vblank,
8137a2e2 906 .wait_for_vblank = mixer_wait_for_vblank,
cf8fc4f1 907 .dpms = mixer_dpms,
578b6065
JS
908
909 /* overlay */
d8408326
SWK
910 .win_mode_set = mixer_win_mode_set,
911 .win_commit = mixer_win_commit,
912 .win_disable = mixer_win_disable,
913};
914
915/* for pageflip event */
916static void mixer_finish_pageflip(struct drm_device *drm_dev, int crtc)
917{
918 struct exynos_drm_private *dev_priv = drm_dev->dev_private;
919 struct drm_pending_vblank_event *e, *t;
920 struct timeval now;
921 unsigned long flags;
d8408326
SWK
922
923 spin_lock_irqsave(&drm_dev->event_lock, flags);
924
925 list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
926 base.link) {
927 /* if event's pipe isn't same as crtc then ignore it. */
928 if (crtc != e->pipe)
929 continue;
930
d8408326
SWK
931 do_gettimeofday(&now);
932 e->event.sequence = 0;
933 e->event.tv_sec = now.tv_sec;
934 e->event.tv_usec = now.tv_usec;
935
936 list_move_tail(&e->base.link, &e->base.file_priv->event_list);
937 wake_up_interruptible(&e->base.file_priv->event_wait);
e1f48ee5 938 drm_vblank_put(drm_dev, crtc);
d8408326
SWK
939 }
940
d8408326
SWK
941 spin_unlock_irqrestore(&drm_dev->event_lock, flags);
942}
943
944static irqreturn_t mixer_irq_handler(int irq, void *arg)
945{
946 struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg;
f9309d1b 947 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
d8408326 948 struct mixer_resources *res = &ctx->mixer_res;
8379e482 949 u32 val, base, shadow;
d8408326
SWK
950
951 spin_lock(&res->reg_slock);
952
953 /* read interrupt status for handling and clearing flags for VSYNC */
954 val = mixer_reg_read(res, MXR_INT_STATUS);
955
956 /* handling VSYNC */
957 if (val & MXR_INT_STATUS_VSYNC) {
958 /* interlace scan need to check shadow register */
959 if (ctx->interlace) {
8379e482
SWK
960 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
961 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
962 if (base != shadow)
d8408326
SWK
963 goto out;
964
8379e482
SWK
965 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
966 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
967 if (base != shadow)
d8408326
SWK
968 goto out;
969 }
970
971 drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe);
972 mixer_finish_pageflip(drm_hdmi_ctx->drm_dev, ctx->pipe);
6e95d5e6
P
973
974 /* set wait vsync event to zero and wake up queue. */
975 if (atomic_read(&ctx->wait_vsync_event)) {
976 atomic_set(&ctx->wait_vsync_event, 0);
977 DRM_WAKEUP(&ctx->wait_vsync_queue);
978 }
d8408326
SWK
979 }
980
981out:
982 /* clear interrupts */
983 if (~val & MXR_INT_EN_VSYNC) {
984 /* vsync interrupt use different bit for read and clear */
985 val &= ~MXR_INT_EN_VSYNC;
986 val |= MXR_INT_CLEAR_VSYNC;
987 }
988 mixer_reg_write(res, MXR_INT_STATUS, val);
989
990 spin_unlock(&res->reg_slock);
991
992 return IRQ_HANDLED;
993}
994
d8408326
SWK
995static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
996 struct platform_device *pdev)
997{
f9309d1b 998 struct mixer_context *mixer_ctx = ctx->ctx;
d8408326
SWK
999 struct device *dev = &pdev->dev;
1000 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
1001 struct resource *res;
1002 int ret;
1003
d8408326
SWK
1004 spin_lock_init(&mixer_res->reg_slock);
1005
37f50861 1006 mixer_res->mixer = devm_clk_get(dev, "mixer");
d8408326
SWK
1007 if (IS_ERR_OR_NULL(mixer_res->mixer)) {
1008 dev_err(dev, "failed to get clock 'mixer'\n");
37f50861 1009 return -ENODEV;
d8408326 1010 }
1b8e5747 1011
37f50861 1012 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
d8408326
SWK
1013 if (IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) {
1014 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
37f50861 1015 return -ENODEV;
d8408326 1016 }
1b8e5747 1017 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
d8408326
SWK
1018 if (res == NULL) {
1019 dev_err(dev, "get memory resource failed.\n");
37f50861 1020 return -ENXIO;
d8408326
SWK
1021 }
1022
9416dfa7
SK
1023 mixer_res->mixer_regs = devm_ioremap(&pdev->dev, res->start,
1024 resource_size(res));
d8408326
SWK
1025 if (mixer_res->mixer_regs == NULL) {
1026 dev_err(dev, "register mapping failed.\n");
37f50861 1027 return -ENXIO;
d8408326
SWK
1028 }
1029
1b8e5747 1030 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
d8408326 1031 if (res == NULL) {
1b8e5747 1032 dev_err(dev, "get interrupt resource failed.\n");
37f50861 1033 return -ENXIO;
d8408326
SWK
1034 }
1035
1b8e5747
RS
1036 ret = devm_request_irq(&pdev->dev, res->start, mixer_irq_handler,
1037 0, "drm_mixer", ctx);
1038 if (ret) {
1039 dev_err(dev, "request interrupt failed.\n");
37f50861 1040 return ret;
d8408326 1041 }
1b8e5747 1042 mixer_res->irq = res->start;
d8408326 1043
1b8e5747 1044 return 0;
1b8e5747
RS
1045}
1046
1047static int __devinit vp_resources_init(struct exynos_drm_hdmi_context *ctx,
1048 struct platform_device *pdev)
1049{
1050 struct mixer_context *mixer_ctx = ctx->ctx;
1051 struct device *dev = &pdev->dev;
1052 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
1053 struct resource *res;
1b8e5747 1054
37f50861 1055 mixer_res->vp = devm_clk_get(dev, "vp");
1b8e5747
RS
1056 if (IS_ERR_OR_NULL(mixer_res->vp)) {
1057 dev_err(dev, "failed to get clock 'vp'\n");
37f50861 1058 return -ENODEV;
1b8e5747 1059 }
37f50861 1060 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
1b8e5747
RS
1061 if (IS_ERR_OR_NULL(mixer_res->sclk_mixer)) {
1062 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
37f50861 1063 return -ENODEV;
1b8e5747 1064 }
37f50861 1065 mixer_res->sclk_dac = devm_clk_get(dev, "sclk_dac");
1b8e5747
RS
1066 if (IS_ERR_OR_NULL(mixer_res->sclk_dac)) {
1067 dev_err(dev, "failed to get clock 'sclk_dac'\n");
37f50861 1068 return -ENODEV;
1b8e5747
RS
1069 }
1070
1071 if (mixer_res->sclk_hdmi)
1072 clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
1073
1074 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
d8408326 1075 if (res == NULL) {
1b8e5747 1076 dev_err(dev, "get memory resource failed.\n");
37f50861 1077 return -ENXIO;
d8408326
SWK
1078 }
1079
1b8e5747
RS
1080 mixer_res->vp_regs = devm_ioremap(&pdev->dev, res->start,
1081 resource_size(res));
1082 if (mixer_res->vp_regs == NULL) {
1083 dev_err(dev, "register mapping failed.\n");
37f50861 1084 return -ENXIO;
d8408326 1085 }
d8408326
SWK
1086
1087 return 0;
d8408326
SWK
1088}
1089
aaf8b49e
RS
1090static struct mixer_drv_data exynos5_mxr_drv_data = {
1091 .version = MXR_VER_16_0_33_0,
1092 .is_vp_enabled = 0,
1093};
1094
1e123441
RS
1095static struct mixer_drv_data exynos4_mxr_drv_data = {
1096 .version = MXR_VER_0_0_0_16,
1b8e5747 1097 .is_vp_enabled = 1,
1e123441
RS
1098};
1099
1100static struct platform_device_id mixer_driver_types[] = {
1101 {
1102 .name = "s5p-mixer",
1103 .driver_data = (unsigned long)&exynos4_mxr_drv_data,
aaf8b49e
RS
1104 }, {
1105 .name = "exynos5-mixer",
1106 .driver_data = (unsigned long)&exynos5_mxr_drv_data,
1107 }, {
1108 /* end node */
1109 }
1110};
1111
1112static struct of_device_id mixer_match_types[] = {
1113 {
1114 .compatible = "samsung,exynos5-mixer",
1115 .data = &exynos5_mxr_drv_data,
1e123441
RS
1116 }, {
1117 /* end node */
1118 }
1119};
1120
d8408326
SWK
1121static int __devinit mixer_probe(struct platform_device *pdev)
1122{
1123 struct device *dev = &pdev->dev;
1124 struct exynos_drm_hdmi_context *drm_hdmi_ctx;
1125 struct mixer_context *ctx;
1e123441 1126 struct mixer_drv_data *drv;
d8408326
SWK
1127 int ret;
1128
1129 dev_info(dev, "probe start\n");
1130
9416dfa7
SK
1131 drm_hdmi_ctx = devm_kzalloc(&pdev->dev, sizeof(*drm_hdmi_ctx),
1132 GFP_KERNEL);
d8408326
SWK
1133 if (!drm_hdmi_ctx) {
1134 DRM_ERROR("failed to allocate common hdmi context.\n");
1135 return -ENOMEM;
1136 }
1137
9416dfa7 1138 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
d8408326
SWK
1139 if (!ctx) {
1140 DRM_ERROR("failed to alloc mixer context.\n");
d8408326
SWK
1141 return -ENOMEM;
1142 }
1143
cf8fc4f1
JS
1144 mutex_init(&ctx->mixer_mutex);
1145
aaf8b49e
RS
1146 if (dev->of_node) {
1147 const struct of_device_id *match;
1148 match = of_match_node(of_match_ptr(mixer_match_types),
1149 pdev->dev.of_node);
2cdc53b3 1150 drv = (struct mixer_drv_data *)match->data;
aaf8b49e
RS
1151 } else {
1152 drv = (struct mixer_drv_data *)
1153 platform_get_device_id(pdev)->driver_data;
1154 }
1155
cf8fc4f1 1156 ctx->dev = &pdev->dev;
1055b39f 1157 ctx->parent_ctx = (void *)drm_hdmi_ctx;
d8408326 1158 drm_hdmi_ctx->ctx = (void *)ctx;
1b8e5747 1159 ctx->vp_enabled = drv->is_vp_enabled;
1e123441 1160 ctx->mxr_ver = drv->version;
6e95d5e6
P
1161 DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
1162 atomic_set(&ctx->wait_vsync_event, 0);
d8408326
SWK
1163
1164 platform_set_drvdata(pdev, drm_hdmi_ctx);
1165
1166 /* acquire resources: regs, irqs, clocks */
1167 ret = mixer_resources_init(drm_hdmi_ctx, pdev);
1b8e5747
RS
1168 if (ret) {
1169 DRM_ERROR("mixer_resources_init failed\n");
d8408326 1170 goto fail;
1b8e5747
RS
1171 }
1172
1173 if (ctx->vp_enabled) {
1174 /* acquire vp resources: regs, irqs, clocks */
1175 ret = vp_resources_init(drm_hdmi_ctx, pdev);
1176 if (ret) {
1177 DRM_ERROR("vp_resources_init failed\n");
1178 goto fail;
1179 }
1180 }
d8408326 1181
768c3059
RS
1182 /* attach mixer driver to common hdmi. */
1183 exynos_mixer_drv_attach(drm_hdmi_ctx);
d8408326
SWK
1184
1185 /* register specific callback point to common hdmi. */
578b6065 1186 exynos_mixer_ops_register(&mixer_ops);
d8408326 1187
cf8fc4f1 1188 pm_runtime_enable(dev);
d8408326
SWK
1189
1190 return 0;
1191
1192
1193fail:
1194 dev_info(dev, "probe failed\n");
1195 return ret;
1196}
1197
1198static int mixer_remove(struct platform_device *pdev)
1199{
9416dfa7 1200 dev_info(&pdev->dev, "remove successful\n");
d8408326 1201
cf8fc4f1
JS
1202 pm_runtime_disable(&pdev->dev);
1203
d8408326
SWK
1204 return 0;
1205}
1206
ab27af85
JS
1207#ifdef CONFIG_PM_SLEEP
1208static int mixer_suspend(struct device *dev)
1209{
1210 struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
1211 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
1212
1213 mixer_poweroff(ctx);
1214
1215 return 0;
1216}
1217#endif
1218
1219static SIMPLE_DEV_PM_OPS(mixer_pm_ops, mixer_suspend, NULL);
1220
d8408326
SWK
1221struct platform_driver mixer_driver = {
1222 .driver = {
aaf8b49e 1223 .name = "exynos-mixer",
d8408326 1224 .owner = THIS_MODULE,
ab27af85 1225 .pm = &mixer_pm_ops,
aaf8b49e 1226 .of_match_table = mixer_match_types,
d8408326
SWK
1227 },
1228 .probe = mixer_probe,
1229 .remove = __devexit_p(mixer_remove),
1e123441 1230 .id_table = mixer_driver_types,
d8408326 1231};