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