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