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