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