Drivers: infinband: remove __dev* attributes.
[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;
22b21ae6 45 dma_addr_t chroma_dma_addr;
22b21ae6
JS
46 uint32_t pixel_format;
47 unsigned int bpp;
48 unsigned int crtc_x;
49 unsigned int crtc_y;
50 unsigned int crtc_width;
51 unsigned int crtc_height;
52 unsigned int fb_x;
53 unsigned int fb_y;
54 unsigned int fb_width;
55 unsigned int fb_height;
8dcb96b6
SWK
56 unsigned int src_width;
57 unsigned int src_height;
22b21ae6
JS
58 unsigned int mode_width;
59 unsigned int mode_height;
60 unsigned int scan_flags;
db43fd16
P
61 bool enabled;
62 bool resume;
22b21ae6
JS
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
d8408326
SWK
691static int mixer_enable_vblank(void *ctx, int pipe)
692{
693 struct mixer_context *mixer_ctx = ctx;
694 struct mixer_resources *res = &mixer_ctx->mixer_res;
695
696 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
697
698 mixer_ctx->pipe = pipe;
699
700 /* enable vsync interrupt */
701 mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
702 MXR_INT_EN_VSYNC);
703
704 return 0;
705}
706
707static void mixer_disable_vblank(void *ctx)
708{
709 struct mixer_context *mixer_ctx = ctx;
710 struct mixer_resources *res = &mixer_ctx->mixer_res;
711
712 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
713
714 /* disable vsync interrupt */
715 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
716}
717
718static void mixer_win_mode_set(void *ctx,
719 struct exynos_drm_overlay *overlay)
720{
721 struct mixer_context *mixer_ctx = ctx;
722 struct hdmi_win_data *win_data;
723 int win;
724
725 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
726
727 if (!overlay) {
728 DRM_ERROR("overlay is NULL\n");
729 return;
730 }
731
732 DRM_DEBUG_KMS("set [%d]x[%d] at (%d,%d) to [%d]x[%d] at (%d,%d)\n",
733 overlay->fb_width, overlay->fb_height,
734 overlay->fb_x, overlay->fb_y,
735 overlay->crtc_width, overlay->crtc_height,
736 overlay->crtc_x, overlay->crtc_y);
737
738 win = overlay->zpos;
739 if (win == DEFAULT_ZPOS)
a2ee151b 740 win = MIXER_DEFAULT_WIN;
d8408326 741
a634dd54 742 if (win < 0 || win > MIXER_WIN_NR) {
cf8fc4f1 743 DRM_ERROR("mixer window[%d] is wrong\n", win);
d8408326
SWK
744 return;
745 }
746
747 win_data = &mixer_ctx->win_data[win];
748
749 win_data->dma_addr = overlay->dma_addr[0];
d8408326 750 win_data->chroma_dma_addr = overlay->dma_addr[1];
d8408326
SWK
751 win_data->pixel_format = overlay->pixel_format;
752 win_data->bpp = overlay->bpp;
753
754 win_data->crtc_x = overlay->crtc_x;
755 win_data->crtc_y = overlay->crtc_y;
756 win_data->crtc_width = overlay->crtc_width;
757 win_data->crtc_height = overlay->crtc_height;
758
759 win_data->fb_x = overlay->fb_x;
760 win_data->fb_y = overlay->fb_y;
761 win_data->fb_width = overlay->fb_width;
762 win_data->fb_height = overlay->fb_height;
8dcb96b6
SWK
763 win_data->src_width = overlay->src_width;
764 win_data->src_height = overlay->src_height;
d8408326
SWK
765
766 win_data->mode_width = overlay->mode_width;
767 win_data->mode_height = overlay->mode_height;
768
769 win_data->scan_flags = overlay->scan_flag;
770}
771
cf8fc4f1 772static void mixer_win_commit(void *ctx, int win)
d8408326
SWK
773{
774 struct mixer_context *mixer_ctx = ctx;
d8408326
SWK
775
776 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
777
1b8e5747 778 if (win > 1 && mixer_ctx->vp_enabled)
d8408326
SWK
779 vp_video_buffer(mixer_ctx, win);
780 else
781 mixer_graph_buffer(mixer_ctx, win);
db43fd16
P
782
783 mixer_ctx->win_data[win].enabled = true;
d8408326
SWK
784}
785
cf8fc4f1 786static void mixer_win_disable(void *ctx, int win)
d8408326
SWK
787{
788 struct mixer_context *mixer_ctx = ctx;
789 struct mixer_resources *res = &mixer_ctx->mixer_res;
790 unsigned long flags;
d8408326
SWK
791
792 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
793
db43fd16
P
794 mutex_lock(&mixer_ctx->mixer_mutex);
795 if (!mixer_ctx->powered) {
796 mutex_unlock(&mixer_ctx->mixer_mutex);
797 mixer_ctx->win_data[win].resume = false;
798 return;
799 }
800 mutex_unlock(&mixer_ctx->mixer_mutex);
801
d8408326
SWK
802 spin_lock_irqsave(&res->reg_slock, flags);
803 mixer_vsync_set_update(mixer_ctx, false);
804
805 mixer_cfg_layer(mixer_ctx, win, false);
806
807 mixer_vsync_set_update(mixer_ctx, true);
808 spin_unlock_irqrestore(&res->reg_slock, flags);
db43fd16
P
809
810 mixer_ctx->win_data[win].enabled = false;
d8408326
SWK
811}
812
8137a2e2
P
813static void mixer_wait_for_vblank(void *ctx)
814{
815 struct mixer_context *mixer_ctx = ctx;
8137a2e2 816
6e95d5e6
P
817 mutex_lock(&mixer_ctx->mixer_mutex);
818 if (!mixer_ctx->powered) {
819 mutex_unlock(&mixer_ctx->mixer_mutex);
820 return;
821 }
822 mutex_unlock(&mixer_ctx->mixer_mutex);
823
824 atomic_set(&mixer_ctx->wait_vsync_event, 1);
825
826 /*
827 * wait for MIXER to signal VSYNC interrupt or return after
828 * timeout which is set to 50ms (refresh rate of 20).
829 */
830 if (!wait_event_timeout(mixer_ctx->wait_vsync_queue,
831 !atomic_read(&mixer_ctx->wait_vsync_event),
832 DRM_HZ/20))
8137a2e2
P
833 DRM_DEBUG_KMS("vblank wait timed out.\n");
834}
835
db43fd16
P
836static void mixer_window_suspend(struct mixer_context *ctx)
837{
838 struct hdmi_win_data *win_data;
839 int i;
840
841 for (i = 0; i < MIXER_WIN_NR; i++) {
842 win_data = &ctx->win_data[i];
843 win_data->resume = win_data->enabled;
844 mixer_win_disable(ctx, i);
845 }
846 mixer_wait_for_vblank(ctx);
847}
848
849static void mixer_window_resume(struct mixer_context *ctx)
850{
851 struct hdmi_win_data *win_data;
852 int i;
853
854 for (i = 0; i < MIXER_WIN_NR; i++) {
855 win_data = &ctx->win_data[i];
856 win_data->enabled = win_data->resume;
857 win_data->resume = false;
858 }
859}
860
861static void mixer_poweron(struct mixer_context *ctx)
862{
863 struct mixer_resources *res = &ctx->mixer_res;
864
865 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
866
867 mutex_lock(&ctx->mixer_mutex);
868 if (ctx->powered) {
869 mutex_unlock(&ctx->mixer_mutex);
870 return;
871 }
872 ctx->powered = true;
873 mutex_unlock(&ctx->mixer_mutex);
874
db43fd16
P
875 clk_enable(res->mixer);
876 if (ctx->vp_enabled) {
877 clk_enable(res->vp);
878 clk_enable(res->sclk_mixer);
879 }
880
881 mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
882 mixer_win_reset(ctx);
883
884 mixer_window_resume(ctx);
885}
886
887static void mixer_poweroff(struct mixer_context *ctx)
888{
889 struct mixer_resources *res = &ctx->mixer_res;
890
891 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
892
893 mutex_lock(&ctx->mixer_mutex);
894 if (!ctx->powered)
895 goto out;
896 mutex_unlock(&ctx->mixer_mutex);
897
898 mixer_window_suspend(ctx);
899
900 ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
901
902 clk_disable(res->mixer);
903 if (ctx->vp_enabled) {
904 clk_disable(res->vp);
905 clk_disable(res->sclk_mixer);
906 }
907
db43fd16
P
908 mutex_lock(&ctx->mixer_mutex);
909 ctx->powered = false;
910
911out:
912 mutex_unlock(&ctx->mixer_mutex);
913}
914
915static void mixer_dpms(void *ctx, int mode)
916{
917 struct mixer_context *mixer_ctx = ctx;
918
919 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
920
921 switch (mode) {
922 case DRM_MODE_DPMS_ON:
000f1308
RS
923 if (pm_runtime_suspended(mixer_ctx->dev))
924 pm_runtime_get_sync(mixer_ctx->dev);
db43fd16
P
925 break;
926 case DRM_MODE_DPMS_STANDBY:
927 case DRM_MODE_DPMS_SUSPEND:
928 case DRM_MODE_DPMS_OFF:
000f1308
RS
929 if (!pm_runtime_suspended(mixer_ctx->dev))
930 pm_runtime_put_sync(mixer_ctx->dev);
db43fd16
P
931 break;
932 default:
933 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
934 break;
935 }
936}
937
578b6065
JS
938static struct exynos_mixer_ops mixer_ops = {
939 /* manager */
1055b39f 940 .iommu_on = mixer_iommu_on,
d8408326
SWK
941 .enable_vblank = mixer_enable_vblank,
942 .disable_vblank = mixer_disable_vblank,
8137a2e2 943 .wait_for_vblank = mixer_wait_for_vblank,
cf8fc4f1 944 .dpms = mixer_dpms,
578b6065
JS
945
946 /* overlay */
d8408326
SWK
947 .win_mode_set = mixer_win_mode_set,
948 .win_commit = mixer_win_commit,
949 .win_disable = mixer_win_disable,
950};
951
952/* for pageflip event */
953static void mixer_finish_pageflip(struct drm_device *drm_dev, int crtc)
954{
955 struct exynos_drm_private *dev_priv = drm_dev->dev_private;
956 struct drm_pending_vblank_event *e, *t;
957 struct timeval now;
958 unsigned long flags;
d8408326
SWK
959
960 spin_lock_irqsave(&drm_dev->event_lock, flags);
961
962 list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
963 base.link) {
964 /* if event's pipe isn't same as crtc then ignore it. */
965 if (crtc != e->pipe)
966 continue;
967
d8408326
SWK
968 do_gettimeofday(&now);
969 e->event.sequence = 0;
970 e->event.tv_sec = now.tv_sec;
971 e->event.tv_usec = now.tv_usec;
972
973 list_move_tail(&e->base.link, &e->base.file_priv->event_list);
974 wake_up_interruptible(&e->base.file_priv->event_wait);
e1f48ee5 975 drm_vblank_put(drm_dev, crtc);
d8408326
SWK
976 }
977
d8408326
SWK
978 spin_unlock_irqrestore(&drm_dev->event_lock, flags);
979}
980
981static irqreturn_t mixer_irq_handler(int irq, void *arg)
982{
983 struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg;
f9309d1b 984 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
d8408326 985 struct mixer_resources *res = &ctx->mixer_res;
8379e482 986 u32 val, base, shadow;
d8408326
SWK
987
988 spin_lock(&res->reg_slock);
989
990 /* read interrupt status for handling and clearing flags for VSYNC */
991 val = mixer_reg_read(res, MXR_INT_STATUS);
992
993 /* handling VSYNC */
994 if (val & MXR_INT_STATUS_VSYNC) {
995 /* interlace scan need to check shadow register */
996 if (ctx->interlace) {
8379e482
SWK
997 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
998 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
999 if (base != shadow)
d8408326
SWK
1000 goto out;
1001
8379e482
SWK
1002 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
1003 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
1004 if (base != shadow)
d8408326
SWK
1005 goto out;
1006 }
1007
1008 drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe);
1009 mixer_finish_pageflip(drm_hdmi_ctx->drm_dev, ctx->pipe);
6e95d5e6
P
1010
1011 /* set wait vsync event to zero and wake up queue. */
1012 if (atomic_read(&ctx->wait_vsync_event)) {
1013 atomic_set(&ctx->wait_vsync_event, 0);
1014 DRM_WAKEUP(&ctx->wait_vsync_queue);
1015 }
d8408326
SWK
1016 }
1017
1018out:
1019 /* clear interrupts */
1020 if (~val & MXR_INT_EN_VSYNC) {
1021 /* vsync interrupt use different bit for read and clear */
1022 val &= ~MXR_INT_EN_VSYNC;
1023 val |= MXR_INT_CLEAR_VSYNC;
1024 }
1025 mixer_reg_write(res, MXR_INT_STATUS, val);
1026
1027 spin_unlock(&res->reg_slock);
1028
1029 return IRQ_HANDLED;
1030}
1031
d8408326
SWK
1032static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
1033 struct platform_device *pdev)
1034{
f9309d1b 1035 struct mixer_context *mixer_ctx = ctx->ctx;
d8408326
SWK
1036 struct device *dev = &pdev->dev;
1037 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
1038 struct resource *res;
1039 int ret;
1040
d8408326
SWK
1041 spin_lock_init(&mixer_res->reg_slock);
1042
37f50861 1043 mixer_res->mixer = devm_clk_get(dev, "mixer");
d8408326
SWK
1044 if (IS_ERR_OR_NULL(mixer_res->mixer)) {
1045 dev_err(dev, "failed to get clock 'mixer'\n");
37f50861 1046 return -ENODEV;
d8408326 1047 }
1b8e5747 1048
37f50861 1049 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
d8408326
SWK
1050 if (IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) {
1051 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
37f50861 1052 return -ENODEV;
d8408326 1053 }
1b8e5747 1054 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
d8408326
SWK
1055 if (res == NULL) {
1056 dev_err(dev, "get memory resource failed.\n");
37f50861 1057 return -ENXIO;
d8408326
SWK
1058 }
1059
9416dfa7
SK
1060 mixer_res->mixer_regs = devm_ioremap(&pdev->dev, res->start,
1061 resource_size(res));
d8408326
SWK
1062 if (mixer_res->mixer_regs == NULL) {
1063 dev_err(dev, "register mapping failed.\n");
37f50861 1064 return -ENXIO;
d8408326
SWK
1065 }
1066
1b8e5747 1067 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
d8408326 1068 if (res == NULL) {
1b8e5747 1069 dev_err(dev, "get interrupt resource failed.\n");
37f50861 1070 return -ENXIO;
d8408326
SWK
1071 }
1072
1b8e5747
RS
1073 ret = devm_request_irq(&pdev->dev, res->start, mixer_irq_handler,
1074 0, "drm_mixer", ctx);
1075 if (ret) {
1076 dev_err(dev, "request interrupt failed.\n");
37f50861 1077 return ret;
d8408326 1078 }
1b8e5747 1079 mixer_res->irq = res->start;
d8408326 1080
1b8e5747 1081 return 0;
1b8e5747
RS
1082}
1083
1084static int __devinit vp_resources_init(struct exynos_drm_hdmi_context *ctx,
1085 struct platform_device *pdev)
1086{
1087 struct mixer_context *mixer_ctx = ctx->ctx;
1088 struct device *dev = &pdev->dev;
1089 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
1090 struct resource *res;
1b8e5747 1091
37f50861 1092 mixer_res->vp = devm_clk_get(dev, "vp");
1b8e5747
RS
1093 if (IS_ERR_OR_NULL(mixer_res->vp)) {
1094 dev_err(dev, "failed to get clock 'vp'\n");
37f50861 1095 return -ENODEV;
1b8e5747 1096 }
37f50861 1097 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
1b8e5747
RS
1098 if (IS_ERR_OR_NULL(mixer_res->sclk_mixer)) {
1099 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
37f50861 1100 return -ENODEV;
1b8e5747 1101 }
37f50861 1102 mixer_res->sclk_dac = devm_clk_get(dev, "sclk_dac");
1b8e5747
RS
1103 if (IS_ERR_OR_NULL(mixer_res->sclk_dac)) {
1104 dev_err(dev, "failed to get clock 'sclk_dac'\n");
37f50861 1105 return -ENODEV;
1b8e5747
RS
1106 }
1107
1108 if (mixer_res->sclk_hdmi)
1109 clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
1110
1111 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
d8408326 1112 if (res == NULL) {
1b8e5747 1113 dev_err(dev, "get memory resource failed.\n");
37f50861 1114 return -ENXIO;
d8408326
SWK
1115 }
1116
1b8e5747
RS
1117 mixer_res->vp_regs = devm_ioremap(&pdev->dev, res->start,
1118 resource_size(res));
1119 if (mixer_res->vp_regs == NULL) {
1120 dev_err(dev, "register mapping failed.\n");
37f50861 1121 return -ENXIO;
d8408326 1122 }
d8408326
SWK
1123
1124 return 0;
d8408326
SWK
1125}
1126
aaf8b49e
RS
1127static struct mixer_drv_data exynos5_mxr_drv_data = {
1128 .version = MXR_VER_16_0_33_0,
1129 .is_vp_enabled = 0,
1130};
1131
1e123441
RS
1132static struct mixer_drv_data exynos4_mxr_drv_data = {
1133 .version = MXR_VER_0_0_0_16,
1b8e5747 1134 .is_vp_enabled = 1,
1e123441
RS
1135};
1136
1137static struct platform_device_id mixer_driver_types[] = {
1138 {
1139 .name = "s5p-mixer",
1140 .driver_data = (unsigned long)&exynos4_mxr_drv_data,
aaf8b49e
RS
1141 }, {
1142 .name = "exynos5-mixer",
1143 .driver_data = (unsigned long)&exynos5_mxr_drv_data,
1144 }, {
1145 /* end node */
1146 }
1147};
1148
1149static struct of_device_id mixer_match_types[] = {
1150 {
1151 .compatible = "samsung,exynos5-mixer",
1152 .data = &exynos5_mxr_drv_data,
1e123441
RS
1153 }, {
1154 /* end node */
1155 }
1156};
1157
d8408326
SWK
1158static int __devinit mixer_probe(struct platform_device *pdev)
1159{
1160 struct device *dev = &pdev->dev;
1161 struct exynos_drm_hdmi_context *drm_hdmi_ctx;
1162 struct mixer_context *ctx;
1e123441 1163 struct mixer_drv_data *drv;
d8408326
SWK
1164 int ret;
1165
1166 dev_info(dev, "probe start\n");
1167
9416dfa7
SK
1168 drm_hdmi_ctx = devm_kzalloc(&pdev->dev, sizeof(*drm_hdmi_ctx),
1169 GFP_KERNEL);
d8408326
SWK
1170 if (!drm_hdmi_ctx) {
1171 DRM_ERROR("failed to allocate common hdmi context.\n");
1172 return -ENOMEM;
1173 }
1174
9416dfa7 1175 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
d8408326
SWK
1176 if (!ctx) {
1177 DRM_ERROR("failed to alloc mixer context.\n");
d8408326
SWK
1178 return -ENOMEM;
1179 }
1180
cf8fc4f1
JS
1181 mutex_init(&ctx->mixer_mutex);
1182
aaf8b49e
RS
1183 if (dev->of_node) {
1184 const struct of_device_id *match;
1185 match = of_match_node(of_match_ptr(mixer_match_types),
1186 pdev->dev.of_node);
2cdc53b3 1187 drv = (struct mixer_drv_data *)match->data;
aaf8b49e
RS
1188 } else {
1189 drv = (struct mixer_drv_data *)
1190 platform_get_device_id(pdev)->driver_data;
1191 }
1192
cf8fc4f1 1193 ctx->dev = &pdev->dev;
1055b39f 1194 ctx->parent_ctx = (void *)drm_hdmi_ctx;
d8408326 1195 drm_hdmi_ctx->ctx = (void *)ctx;
1b8e5747 1196 ctx->vp_enabled = drv->is_vp_enabled;
1e123441 1197 ctx->mxr_ver = drv->version;
6e95d5e6
P
1198 DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
1199 atomic_set(&ctx->wait_vsync_event, 0);
d8408326
SWK
1200
1201 platform_set_drvdata(pdev, drm_hdmi_ctx);
1202
1203 /* acquire resources: regs, irqs, clocks */
1204 ret = mixer_resources_init(drm_hdmi_ctx, pdev);
1b8e5747
RS
1205 if (ret) {
1206 DRM_ERROR("mixer_resources_init failed\n");
d8408326 1207 goto fail;
1b8e5747
RS
1208 }
1209
1210 if (ctx->vp_enabled) {
1211 /* acquire vp resources: regs, irqs, clocks */
1212 ret = vp_resources_init(drm_hdmi_ctx, pdev);
1213 if (ret) {
1214 DRM_ERROR("vp_resources_init failed\n");
1215 goto fail;
1216 }
1217 }
d8408326 1218
768c3059
RS
1219 /* attach mixer driver to common hdmi. */
1220 exynos_mixer_drv_attach(drm_hdmi_ctx);
d8408326
SWK
1221
1222 /* register specific callback point to common hdmi. */
578b6065 1223 exynos_mixer_ops_register(&mixer_ops);
d8408326 1224
cf8fc4f1 1225 pm_runtime_enable(dev);
d8408326
SWK
1226
1227 return 0;
1228
1229
1230fail:
1231 dev_info(dev, "probe failed\n");
1232 return ret;
1233}
1234
1235static int mixer_remove(struct platform_device *pdev)
1236{
9416dfa7 1237 dev_info(&pdev->dev, "remove successful\n");
d8408326 1238
cf8fc4f1
JS
1239 pm_runtime_disable(&pdev->dev);
1240
d8408326
SWK
1241 return 0;
1242}
1243
ab27af85
JS
1244#ifdef CONFIG_PM_SLEEP
1245static int mixer_suspend(struct device *dev)
1246{
1247 struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
1248 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
1249
000f1308
RS
1250 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
1251
1252 if (pm_runtime_suspended(dev)) {
1253 DRM_DEBUG_KMS("%s : Already suspended\n", __func__);
1254 return 0;
1255 }
1256
ab27af85
JS
1257 mixer_poweroff(ctx);
1258
1259 return 0;
1260}
000f1308
RS
1261
1262static int mixer_resume(struct device *dev)
1263{
1264 struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
1265 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
1266
1267 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
1268
1269 if (!pm_runtime_suspended(dev)) {
1270 DRM_DEBUG_KMS("%s : Already resumed\n", __func__);
1271 return 0;
1272 }
1273
1274 mixer_poweron(ctx);
1275
1276 return 0;
1277}
ab27af85
JS
1278#endif
1279
000f1308
RS
1280#ifdef CONFIG_PM_RUNTIME
1281static int mixer_runtime_suspend(struct device *dev)
1282{
1283 struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
1284 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
1285
1286 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
1287
1288 mixer_poweroff(ctx);
1289
1290 return 0;
1291}
1292
1293static int mixer_runtime_resume(struct device *dev)
1294{
1295 struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
1296 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
1297
1298 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
1299
1300 mixer_poweron(ctx);
1301
1302 return 0;
1303}
1304#endif
1305
1306static const struct dev_pm_ops mixer_pm_ops = {
1307 SET_SYSTEM_SLEEP_PM_OPS(mixer_suspend, mixer_resume)
1308 SET_RUNTIME_PM_OPS(mixer_runtime_suspend, mixer_runtime_resume, NULL)
1309};
ab27af85 1310
d8408326
SWK
1311struct platform_driver mixer_driver = {
1312 .driver = {
aaf8b49e 1313 .name = "exynos-mixer",
d8408326 1314 .owner = THIS_MODULE,
ab27af85 1315 .pm = &mixer_pm_ops,
aaf8b49e 1316 .of_match_table = mixer_match_types,
d8408326
SWK
1317 },
1318 .probe = mixer_probe,
1319 .remove = __devexit_p(mixer_remove),
1e123441 1320 .id_table = mixer_driver_types,
d8408326 1321};