2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
4 * Seung-Woo Kim <sw0312.kim@samsung.com>
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
8 * Based on drivers/media/video/s5p-tv/mixer_reg.c
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.
19 #include "regs-mixer.h"
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>
35 #include <drm/exynos_drm.h>
37 #include "exynos_drm_drv.h"
38 #include "exynos_drm_hdmi.h"
39 #include "exynos_hdmi.h"
40 #include "exynos_mixer.h"
42 #define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev))
44 static const u8 filter_y_horiz_tap8
[] = {
45 0, -1, -1, -1, -1, -1, -1, -1,
46 -1, -1, -1, -1, -1, 0, 0, 0,
47 0, 2, 4, 5, 6, 6, 6, 6,
48 6, 5, 5, 4, 3, 2, 1, 1,
49 0, -6, -12, -16, -18, -20, -21, -20,
50 -20, -18, -16, -13, -10, -8, -5, -2,
51 127, 126, 125, 121, 114, 107, 99, 89,
52 79, 68, 57, 46, 35, 25, 16, 8,
55 static const u8 filter_y_vert_tap4
[] = {
56 0, -3, -6, -8, -8, -8, -8, -7,
57 -6, -5, -4, -3, -2, -1, -1, 0,
58 127, 126, 124, 118, 111, 102, 92, 81,
59 70, 59, 48, 37, 27, 19, 11, 5,
60 0, 5, 11, 19, 27, 37, 48, 59,
61 70, 81, 92, 102, 111, 118, 124, 126,
62 0, 0, -1, -1, -2, -3, -4, -5,
63 -6, -7, -8, -8, -8, -8, -6, -3,
66 static const u8 filter_cr_horiz_tap4
[] = {
67 0, -3, -6, -8, -8, -8, -8, -7,
68 -6, -5, -4, -3, -2, -1, -1, 0,
69 127, 126, 124, 118, 111, 102, 92, 81,
70 70, 59, 48, 37, 27, 19, 11, 5,
73 static inline u32
vp_reg_read(struct mixer_resources
*res
, u32 reg_id
)
75 return readl(res
->vp_regs
+ reg_id
);
78 static inline void vp_reg_write(struct mixer_resources
*res
, u32 reg_id
,
81 writel(val
, res
->vp_regs
+ reg_id
);
84 static inline void vp_reg_writemask(struct mixer_resources
*res
, u32 reg_id
,
87 u32 old
= vp_reg_read(res
, reg_id
);
89 val
= (val
& mask
) | (old
& ~mask
);
90 writel(val
, res
->vp_regs
+ reg_id
);
93 static inline u32
mixer_reg_read(struct mixer_resources
*res
, u32 reg_id
)
95 return readl(res
->mixer_regs
+ reg_id
);
98 static inline void mixer_reg_write(struct mixer_resources
*res
, u32 reg_id
,
101 writel(val
, res
->mixer_regs
+ reg_id
);
104 static inline void mixer_reg_writemask(struct mixer_resources
*res
,
105 u32 reg_id
, u32 val
, u32 mask
)
107 u32 old
= mixer_reg_read(res
, reg_id
);
109 val
= (val
& mask
) | (old
& ~mask
);
110 writel(val
, res
->mixer_regs
+ reg_id
);
113 static void mixer_regs_dump(struct mixer_context
*ctx
)
115 #define DUMPREG(reg_id) \
117 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
118 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
124 DUMPREG(MXR_INT_STATUS
);
126 DUMPREG(MXR_LAYER_CFG
);
127 DUMPREG(MXR_VIDEO_CFG
);
129 DUMPREG(MXR_GRAPHIC0_CFG
);
130 DUMPREG(MXR_GRAPHIC0_BASE
);
131 DUMPREG(MXR_GRAPHIC0_SPAN
);
132 DUMPREG(MXR_GRAPHIC0_WH
);
133 DUMPREG(MXR_GRAPHIC0_SXY
);
134 DUMPREG(MXR_GRAPHIC0_DXY
);
136 DUMPREG(MXR_GRAPHIC1_CFG
);
137 DUMPREG(MXR_GRAPHIC1_BASE
);
138 DUMPREG(MXR_GRAPHIC1_SPAN
);
139 DUMPREG(MXR_GRAPHIC1_WH
);
140 DUMPREG(MXR_GRAPHIC1_SXY
);
141 DUMPREG(MXR_GRAPHIC1_DXY
);
145 static void vp_regs_dump(struct mixer_context
*ctx
)
147 #define DUMPREG(reg_id) \
149 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
150 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
155 DUMPREG(VP_SHADOW_UPDATE
);
156 DUMPREG(VP_FIELD_ID
);
158 DUMPREG(VP_IMG_SIZE_Y
);
159 DUMPREG(VP_IMG_SIZE_C
);
160 DUMPREG(VP_PER_RATE_CTRL
);
161 DUMPREG(VP_TOP_Y_PTR
);
162 DUMPREG(VP_BOT_Y_PTR
);
163 DUMPREG(VP_TOP_C_PTR
);
164 DUMPREG(VP_BOT_C_PTR
);
165 DUMPREG(VP_ENDIAN_MODE
);
166 DUMPREG(VP_SRC_H_POSITION
);
167 DUMPREG(VP_SRC_V_POSITION
);
168 DUMPREG(VP_SRC_WIDTH
);
169 DUMPREG(VP_SRC_HEIGHT
);
170 DUMPREG(VP_DST_H_POSITION
);
171 DUMPREG(VP_DST_V_POSITION
);
172 DUMPREG(VP_DST_WIDTH
);
173 DUMPREG(VP_DST_HEIGHT
);
180 static inline void vp_filter_set(struct mixer_resources
*res
,
181 int reg_id
, const u8
*data
, unsigned int size
)
183 /* assure 4-byte align */
185 for (; size
; size
-= 4, reg_id
+= 4, data
+= 4) {
186 u32 val
= (data
[0] << 24) | (data
[1] << 16) |
187 (data
[2] << 8) | data
[3];
188 vp_reg_write(res
, reg_id
, val
);
192 static void vp_default_filter(struct mixer_resources
*res
)
194 vp_filter_set(res
, VP_POLY8_Y0_LL
,
195 filter_y_horiz_tap8
, sizeof filter_y_horiz_tap8
);
196 vp_filter_set(res
, VP_POLY4_Y0_LL
,
197 filter_y_vert_tap4
, sizeof filter_y_vert_tap4
);
198 vp_filter_set(res
, VP_POLY4_C0_LL
,
199 filter_cr_horiz_tap4
, sizeof filter_cr_horiz_tap4
);
202 static void mixer_vsync_set_update(struct mixer_context
*ctx
, bool enable
)
204 struct mixer_resources
*res
= &ctx
->mixer_res
;
206 /* block update on vsync */
207 mixer_reg_writemask(res
, MXR_STATUS
, enable
?
208 MXR_STATUS_SYNC_ENABLE
: 0, MXR_STATUS_SYNC_ENABLE
);
210 vp_reg_write(res
, VP_SHADOW_UPDATE
, enable
?
211 VP_SHADOW_UPDATE_ENABLE
: 0);
214 static void mixer_cfg_scan(struct mixer_context
*ctx
, unsigned int height
)
216 struct mixer_resources
*res
= &ctx
->mixer_res
;
219 /* choosing between interlace and progressive mode */
220 val
= (ctx
->interlace
? MXR_CFG_SCAN_INTERLACE
:
221 MXR_CFG_SCAN_PROGRASSIVE
);
223 /* choosing between porper HD and SD mode */
225 val
|= MXR_CFG_SCAN_NTSC
| MXR_CFG_SCAN_SD
;
226 else if (height
== 576)
227 val
|= MXR_CFG_SCAN_PAL
| MXR_CFG_SCAN_SD
;
228 else if (height
== 720)
229 val
|= MXR_CFG_SCAN_HD_720
| MXR_CFG_SCAN_HD
;
230 else if (height
== 1080)
231 val
|= MXR_CFG_SCAN_HD_1080
| MXR_CFG_SCAN_HD
;
233 val
|= MXR_CFG_SCAN_HD_720
| MXR_CFG_SCAN_HD
;
235 mixer_reg_writemask(res
, MXR_CFG
, val
, MXR_CFG_SCAN_MASK
);
238 static void mixer_cfg_rgb_fmt(struct mixer_context
*ctx
, unsigned int height
)
240 struct mixer_resources
*res
= &ctx
->mixer_res
;
244 val
= MXR_CFG_RGB601_0_255
;
245 } else if (height
== 576) {
246 val
= MXR_CFG_RGB601_0_255
;
247 } else if (height
== 720) {
248 val
= MXR_CFG_RGB709_16_235
;
249 mixer_reg_write(res
, MXR_CM_COEFF_Y
,
250 (1 << 30) | (94 << 20) | (314 << 10) |
252 mixer_reg_write(res
, MXR_CM_COEFF_CB
,
253 (972 << 20) | (851 << 10) | (225 << 0));
254 mixer_reg_write(res
, MXR_CM_COEFF_CR
,
255 (225 << 20) | (820 << 10) | (1004 << 0));
256 } else if (height
== 1080) {
257 val
= MXR_CFG_RGB709_16_235
;
258 mixer_reg_write(res
, MXR_CM_COEFF_Y
,
259 (1 << 30) | (94 << 20) | (314 << 10) |
261 mixer_reg_write(res
, MXR_CM_COEFF_CB
,
262 (972 << 20) | (851 << 10) | (225 << 0));
263 mixer_reg_write(res
, MXR_CM_COEFF_CR
,
264 (225 << 20) | (820 << 10) | (1004 << 0));
266 val
= MXR_CFG_RGB709_16_235
;
267 mixer_reg_write(res
, MXR_CM_COEFF_Y
,
268 (1 << 30) | (94 << 20) | (314 << 10) |
270 mixer_reg_write(res
, MXR_CM_COEFF_CB
,
271 (972 << 20) | (851 << 10) | (225 << 0));
272 mixer_reg_write(res
, MXR_CM_COEFF_CR
,
273 (225 << 20) | (820 << 10) | (1004 << 0));
276 mixer_reg_writemask(res
, MXR_CFG
, val
, MXR_CFG_RGB_FMT_MASK
);
279 static void mixer_cfg_layer(struct mixer_context
*ctx
, int win
, bool enable
)
281 struct mixer_resources
*res
= &ctx
->mixer_res
;
282 u32 val
= enable
? ~0 : 0;
286 mixer_reg_writemask(res
, MXR_CFG
, val
, MXR_CFG_GRP0_ENABLE
);
289 mixer_reg_writemask(res
, MXR_CFG
, val
, MXR_CFG_GRP1_ENABLE
);
292 vp_reg_writemask(res
, VP_ENABLE
, val
, VP_ENABLE_ON
);
293 mixer_reg_writemask(res
, MXR_CFG
, val
, MXR_CFG_VP_ENABLE
);
298 static void mixer_run(struct mixer_context
*ctx
)
300 struct mixer_resources
*res
= &ctx
->mixer_res
;
302 mixer_reg_writemask(res
, MXR_STATUS
, ~0, MXR_STATUS_REG_RUN
);
304 mixer_regs_dump(ctx
);
307 static void vp_video_buffer(struct mixer_context
*ctx
, int win
)
309 struct mixer_resources
*res
= &ctx
->mixer_res
;
311 struct hdmi_win_data
*win_data
;
312 unsigned int full_width
, full_height
, width
, height
;
313 unsigned int x_ratio
, y_ratio
;
314 unsigned int src_x_offset
, src_y_offset
, dst_x_offset
, dst_y_offset
;
315 unsigned int mode_width
, mode_height
;
316 unsigned int buf_num
;
317 dma_addr_t luma_addr
[2], chroma_addr
[2];
318 bool tiled_mode
= false;
319 bool crcb_mode
= false;
322 win_data
= &ctx
->win_data
[win
];
324 switch (win_data
->pixel_format
) {
325 case DRM_FORMAT_NV12MT
:
327 case DRM_FORMAT_NV12M
:
331 /* TODO: single buffer format NV12, NV21 */
333 /* ignore pixel format at disable time */
334 if (!win_data
->dma_addr
)
337 DRM_ERROR("pixel format for vp is wrong [%d].\n",
338 win_data
->pixel_format
);
342 full_width
= win_data
->fb_width
;
343 full_height
= win_data
->fb_height
;
344 width
= win_data
->crtc_width
;
345 height
= win_data
->crtc_height
;
346 mode_width
= win_data
->mode_width
;
347 mode_height
= win_data
->mode_height
;
349 /* scaling feature: (src << 16) / dst */
350 x_ratio
= (width
<< 16) / width
;
351 y_ratio
= (height
<< 16) / height
;
353 src_x_offset
= win_data
->fb_x
;
354 src_y_offset
= win_data
->fb_y
;
355 dst_x_offset
= win_data
->crtc_x
;
356 dst_y_offset
= win_data
->crtc_y
;
359 luma_addr
[0] = win_data
->dma_addr
;
360 chroma_addr
[0] = win_data
->chroma_dma_addr
;
362 luma_addr
[0] = win_data
->dma_addr
;
363 chroma_addr
[0] = win_data
->dma_addr
364 + (full_width
* full_height
);
367 if (win_data
->scan_flags
& DRM_MODE_FLAG_INTERLACE
) {
368 ctx
->interlace
= true;
370 luma_addr
[1] = luma_addr
[0] + 0x40;
371 chroma_addr
[1] = chroma_addr
[0] + 0x40;
373 luma_addr
[1] = luma_addr
[0] + full_width
;
374 chroma_addr
[1] = chroma_addr
[0] + full_width
;
377 ctx
->interlace
= false;
382 spin_lock_irqsave(&res
->reg_slock
, flags
);
383 mixer_vsync_set_update(ctx
, false);
385 /* interlace or progressive scan mode */
386 val
= (ctx
->interlace
? ~0 : 0);
387 vp_reg_writemask(res
, VP_MODE
, val
, VP_MODE_LINE_SKIP
);
390 val
= (crcb_mode
? VP_MODE_NV21
: VP_MODE_NV12
);
391 val
|= (tiled_mode
? VP_MODE_MEM_TILED
: VP_MODE_MEM_LINEAR
);
392 vp_reg_writemask(res
, VP_MODE
, val
, VP_MODE_FMT_MASK
);
394 /* setting size of input image */
395 vp_reg_write(res
, VP_IMG_SIZE_Y
, VP_IMG_HSIZE(full_width
) |
396 VP_IMG_VSIZE(full_height
));
397 /* chroma height has to reduced by 2 to avoid chroma distorions */
398 vp_reg_write(res
, VP_IMG_SIZE_C
, VP_IMG_HSIZE(full_width
) |
399 VP_IMG_VSIZE(full_height
/ 2));
401 vp_reg_write(res
, VP_SRC_WIDTH
, width
);
402 vp_reg_write(res
, VP_SRC_HEIGHT
, height
);
403 vp_reg_write(res
, VP_SRC_H_POSITION
,
404 VP_SRC_H_POSITION_VAL(src_x_offset
));
405 vp_reg_write(res
, VP_SRC_V_POSITION
, src_y_offset
);
407 vp_reg_write(res
, VP_DST_WIDTH
, width
);
408 vp_reg_write(res
, VP_DST_H_POSITION
, dst_x_offset
);
409 if (ctx
->interlace
) {
410 vp_reg_write(res
, VP_DST_HEIGHT
, height
/ 2);
411 vp_reg_write(res
, VP_DST_V_POSITION
, dst_y_offset
/ 2);
413 vp_reg_write(res
, VP_DST_HEIGHT
, height
);
414 vp_reg_write(res
, VP_DST_V_POSITION
, dst_y_offset
);
417 vp_reg_write(res
, VP_H_RATIO
, x_ratio
);
418 vp_reg_write(res
, VP_V_RATIO
, y_ratio
);
420 vp_reg_write(res
, VP_ENDIAN_MODE
, VP_ENDIAN_MODE_LITTLE
);
422 /* set buffer address to vp */
423 vp_reg_write(res
, VP_TOP_Y_PTR
, luma_addr
[0]);
424 vp_reg_write(res
, VP_BOT_Y_PTR
, luma_addr
[1]);
425 vp_reg_write(res
, VP_TOP_C_PTR
, chroma_addr
[0]);
426 vp_reg_write(res
, VP_BOT_C_PTR
, chroma_addr
[1]);
428 mixer_cfg_scan(ctx
, mode_height
);
429 mixer_cfg_rgb_fmt(ctx
, mode_height
);
430 mixer_cfg_layer(ctx
, win
, true);
433 mixer_vsync_set_update(ctx
, true);
434 spin_unlock_irqrestore(&res
->reg_slock
, flags
);
439 static void mixer_graph_buffer(struct mixer_context
*ctx
, int win
)
441 struct mixer_resources
*res
= &ctx
->mixer_res
;
443 struct hdmi_win_data
*win_data
;
444 unsigned int full_width
, width
, height
;
445 unsigned int x_ratio
, y_ratio
;
446 unsigned int src_x_offset
, src_y_offset
, dst_x_offset
, dst_y_offset
;
447 unsigned int mode_width
, mode_height
;
452 win_data
= &ctx
->win_data
[win
];
459 switch (win_data
->bpp
) {
470 dma_addr
= win_data
->dma_addr
;
471 full_width
= win_data
->fb_width
;
472 width
= win_data
->crtc_width
;
473 height
= win_data
->crtc_height
;
474 mode_width
= win_data
->mode_width
;
475 mode_height
= win_data
->mode_height
;
477 /* 2x scaling feature */
481 src_x_offset
= win_data
->fb_x
;
482 src_y_offset
= win_data
->fb_y
;
483 dst_x_offset
= win_data
->crtc_x
;
484 dst_y_offset
= win_data
->crtc_y
;
486 /* converting dma address base and source offset */
488 + (src_x_offset
* win_data
->bpp
>> 3)
489 + (src_y_offset
* full_width
* win_data
->bpp
>> 3);
493 if (win_data
->scan_flags
& DRM_MODE_FLAG_INTERLACE
)
494 ctx
->interlace
= true;
496 ctx
->interlace
= false;
498 spin_lock_irqsave(&res
->reg_slock
, flags
);
499 mixer_vsync_set_update(ctx
, false);
502 mixer_reg_writemask(res
, MXR_GRAPHIC_CFG(win
),
503 MXR_GRP_CFG_FORMAT_VAL(fmt
), MXR_GRP_CFG_FORMAT_MASK
);
506 mixer_reg_write(res
, MXR_GRAPHIC_SPAN(win
), full_width
);
508 val
= MXR_GRP_WH_WIDTH(width
);
509 val
|= MXR_GRP_WH_HEIGHT(height
);
510 val
|= MXR_GRP_WH_H_SCALE(x_ratio
);
511 val
|= MXR_GRP_WH_V_SCALE(y_ratio
);
512 mixer_reg_write(res
, MXR_GRAPHIC_WH(win
), val
);
514 /* setup offsets in source image */
515 val
= MXR_GRP_SXY_SX(src_x_offset
);
516 val
|= MXR_GRP_SXY_SY(src_y_offset
);
517 mixer_reg_write(res
, MXR_GRAPHIC_SXY(win
), val
);
519 /* setup offsets in display image */
520 val
= MXR_GRP_DXY_DX(dst_x_offset
);
521 val
|= MXR_GRP_DXY_DY(dst_y_offset
);
522 mixer_reg_write(res
, MXR_GRAPHIC_DXY(win
), val
);
524 /* set buffer address to mixer */
525 mixer_reg_write(res
, MXR_GRAPHIC_BASE(win
), dma_addr
);
527 mixer_cfg_scan(ctx
, mode_height
);
528 mixer_cfg_rgb_fmt(ctx
, mode_height
);
529 mixer_cfg_layer(ctx
, win
, true);
532 mixer_vsync_set_update(ctx
, true);
533 spin_unlock_irqrestore(&res
->reg_slock
, flags
);
536 static void vp_win_reset(struct mixer_context
*ctx
)
538 struct mixer_resources
*res
= &ctx
->mixer_res
;
541 vp_reg_write(res
, VP_SRESET
, VP_SRESET_PROCESSING
);
542 for (tries
= 100; tries
; --tries
) {
543 /* waiting until VP_SRESET_PROCESSING is 0 */
544 if (~vp_reg_read(res
, VP_SRESET
) & VP_SRESET_PROCESSING
)
548 WARN(tries
== 0, "failed to reset Video Processor\n");
551 static int mixer_enable_vblank(void *ctx
, int pipe
)
553 struct mixer_context
*mixer_ctx
= ctx
;
554 struct mixer_resources
*res
= &mixer_ctx
->mixer_res
;
556 DRM_DEBUG_KMS("[%d] %s\n", __LINE__
, __func__
);
558 mixer_ctx
->pipe
= pipe
;
560 /* enable vsync interrupt */
561 mixer_reg_writemask(res
, MXR_INT_EN
, MXR_INT_EN_VSYNC
,
567 static void mixer_disable_vblank(void *ctx
)
569 struct mixer_context
*mixer_ctx
= ctx
;
570 struct mixer_resources
*res
= &mixer_ctx
->mixer_res
;
572 DRM_DEBUG_KMS("[%d] %s\n", __LINE__
, __func__
);
574 /* disable vsync interrupt */
575 mixer_reg_writemask(res
, MXR_INT_EN
, 0, MXR_INT_EN_VSYNC
);
578 static void mixer_win_mode_set(void *ctx
,
579 struct exynos_drm_overlay
*overlay
)
581 struct mixer_context
*mixer_ctx
= ctx
;
582 struct hdmi_win_data
*win_data
;
585 DRM_DEBUG_KMS("[%d] %s\n", __LINE__
, __func__
);
588 DRM_ERROR("overlay is NULL\n");
592 DRM_DEBUG_KMS("set [%d]x[%d] at (%d,%d) to [%d]x[%d] at (%d,%d)\n",
593 overlay
->fb_width
, overlay
->fb_height
,
594 overlay
->fb_x
, overlay
->fb_y
,
595 overlay
->crtc_width
, overlay
->crtc_height
,
596 overlay
->crtc_x
, overlay
->crtc_y
);
599 if (win
== DEFAULT_ZPOS
)
600 win
= mixer_ctx
->default_win
;
602 if (win
< 0 || win
> HDMI_OVERLAY_NUMBER
) {
603 DRM_ERROR("overlay plane[%d] is wrong\n", win
);
607 win_data
= &mixer_ctx
->win_data
[win
];
609 win_data
->dma_addr
= overlay
->dma_addr
[0];
610 win_data
->vaddr
= overlay
->vaddr
[0];
611 win_data
->chroma_dma_addr
= overlay
->dma_addr
[1];
612 win_data
->chroma_vaddr
= overlay
->vaddr
[1];
613 win_data
->pixel_format
= overlay
->pixel_format
;
614 win_data
->bpp
= overlay
->bpp
;
616 win_data
->crtc_x
= overlay
->crtc_x
;
617 win_data
->crtc_y
= overlay
->crtc_y
;
618 win_data
->crtc_width
= overlay
->crtc_width
;
619 win_data
->crtc_height
= overlay
->crtc_height
;
621 win_data
->fb_x
= overlay
->fb_x
;
622 win_data
->fb_y
= overlay
->fb_y
;
623 win_data
->fb_width
= overlay
->fb_width
;
624 win_data
->fb_height
= overlay
->fb_height
;
626 win_data
->mode_width
= overlay
->mode_width
;
627 win_data
->mode_height
= overlay
->mode_height
;
629 win_data
->scan_flags
= overlay
->scan_flag
;
632 static void mixer_win_commit(void *ctx
, int zpos
)
634 struct mixer_context
*mixer_ctx
= ctx
;
637 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__
, __func__
, win
);
639 if (win
== DEFAULT_ZPOS
)
640 win
= mixer_ctx
->default_win
;
642 if (win
< 0 || win
> HDMI_OVERLAY_NUMBER
) {
643 DRM_ERROR("overlay plane[%d] is wrong\n", win
);
648 vp_video_buffer(mixer_ctx
, win
);
650 mixer_graph_buffer(mixer_ctx
, win
);
653 static void mixer_win_disable(void *ctx
, int zpos
)
655 struct mixer_context
*mixer_ctx
= ctx
;
656 struct mixer_resources
*res
= &mixer_ctx
->mixer_res
;
660 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__
, __func__
, win
);
662 if (win
== DEFAULT_ZPOS
)
663 win
= mixer_ctx
->default_win
;
665 if (win
< 0 || win
> HDMI_OVERLAY_NUMBER
) {
666 DRM_ERROR("overlay plane[%d] is wrong\n", win
);
670 spin_lock_irqsave(&res
->reg_slock
, flags
);
671 mixer_vsync_set_update(mixer_ctx
, false);
673 mixer_cfg_layer(mixer_ctx
, win
, false);
675 mixer_vsync_set_update(mixer_ctx
, true);
676 spin_unlock_irqrestore(&res
->reg_slock
, flags
);
679 static struct exynos_hdmi_overlay_ops overlay_ops
= {
680 .enable_vblank
= mixer_enable_vblank
,
681 .disable_vblank
= mixer_disable_vblank
,
682 .win_mode_set
= mixer_win_mode_set
,
683 .win_commit
= mixer_win_commit
,
684 .win_disable
= mixer_win_disable
,
687 /* for pageflip event */
688 static void mixer_finish_pageflip(struct drm_device
*drm_dev
, int crtc
)
690 struct exynos_drm_private
*dev_priv
= drm_dev
->dev_private
;
691 struct drm_pending_vblank_event
*e
, *t
;
694 bool is_checked
= false;
696 spin_lock_irqsave(&drm_dev
->event_lock
, flags
);
698 list_for_each_entry_safe(e
, t
, &dev_priv
->pageflip_event_list
,
700 /* if event's pipe isn't same as crtc then ignore it. */
705 do_gettimeofday(&now
);
706 e
->event
.sequence
= 0;
707 e
->event
.tv_sec
= now
.tv_sec
;
708 e
->event
.tv_usec
= now
.tv_usec
;
710 list_move_tail(&e
->base
.link
, &e
->base
.file_priv
->event_list
);
711 wake_up_interruptible(&e
->base
.file_priv
->event_wait
);
716 * call drm_vblank_put only in case that drm_vblank_get was
719 if (atomic_read(&drm_dev
->vblank_refcount
[crtc
]) > 0)
720 drm_vblank_put(drm_dev
, crtc
);
722 spin_unlock_irqrestore(&drm_dev
->event_lock
, flags
);
725 static irqreturn_t
mixer_irq_handler(int irq
, void *arg
)
727 struct exynos_drm_hdmi_context
*drm_hdmi_ctx
= arg
;
728 struct mixer_context
*ctx
=
729 (struct mixer_context
*)drm_hdmi_ctx
->ctx
;
730 struct mixer_resources
*res
= &ctx
->mixer_res
;
733 spin_lock(&res
->reg_slock
);
735 /* read interrupt status for handling and clearing flags for VSYNC */
736 val
= mixer_reg_read(res
, MXR_INT_STATUS
);
739 if (val
& MXR_INT_STATUS_VSYNC
) {
740 /* interlace scan need to check shadow register */
741 if (ctx
->interlace
) {
742 val_base
= mixer_reg_read(res
, MXR_GRAPHIC_BASE_S(0));
743 if (ctx
->win_data
[0].dma_addr
!= val_base
)
746 val_base
= mixer_reg_read(res
, MXR_GRAPHIC_BASE_S(1));
747 if (ctx
->win_data
[1].dma_addr
!= val_base
)
751 drm_handle_vblank(drm_hdmi_ctx
->drm_dev
, ctx
->pipe
);
752 mixer_finish_pageflip(drm_hdmi_ctx
->drm_dev
, ctx
->pipe
);
756 /* clear interrupts */
757 if (~val
& MXR_INT_EN_VSYNC
) {
758 /* vsync interrupt use different bit for read and clear */
759 val
&= ~MXR_INT_EN_VSYNC
;
760 val
|= MXR_INT_CLEAR_VSYNC
;
762 mixer_reg_write(res
, MXR_INT_STATUS
, val
);
764 spin_unlock(&res
->reg_slock
);
769 static void mixer_win_reset(struct mixer_context
*ctx
)
771 struct mixer_resources
*res
= &ctx
->mixer_res
;
773 u32 val
; /* value stored to register */
775 spin_lock_irqsave(&res
->reg_slock
, flags
);
776 mixer_vsync_set_update(ctx
, false);
778 mixer_reg_writemask(res
, MXR_CFG
, MXR_CFG_DST_HDMI
, MXR_CFG_DST_MASK
);
780 /* set output in RGB888 mode */
781 mixer_reg_writemask(res
, MXR_CFG
, MXR_CFG_OUT_RGB888
, MXR_CFG_OUT_MASK
);
783 /* 16 beat burst in DMA */
784 mixer_reg_writemask(res
, MXR_STATUS
, MXR_STATUS_16_BURST
,
785 MXR_STATUS_BURST_MASK
);
787 /* setting default layer priority: layer1 > layer0 > video
788 * because typical usage scenario would be
790 * layer0 - framebuffer
791 * video - video overlay
793 val
= MXR_LAYER_CFG_GRP1_VAL(3);
794 val
|= MXR_LAYER_CFG_GRP0_VAL(2);
795 val
|= MXR_LAYER_CFG_VP_VAL(1);
796 mixer_reg_write(res
, MXR_LAYER_CFG
, val
);
798 /* setting background color */
799 mixer_reg_write(res
, MXR_BG_COLOR0
, 0x008080);
800 mixer_reg_write(res
, MXR_BG_COLOR1
, 0x008080);
801 mixer_reg_write(res
, MXR_BG_COLOR2
, 0x008080);
803 /* setting graphical layers */
805 val
= MXR_GRP_CFG_COLOR_KEY_DISABLE
; /* no blank key */
806 val
|= MXR_GRP_CFG_WIN_BLEND_EN
;
807 val
|= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
809 /* the same configuration for both layers */
810 mixer_reg_write(res
, MXR_GRAPHIC_CFG(0), val
);
812 val
|= MXR_GRP_CFG_BLEND_PRE_MUL
;
813 val
|= MXR_GRP_CFG_PIXEL_BLEND_EN
;
814 mixer_reg_write(res
, MXR_GRAPHIC_CFG(1), val
);
816 /* configuration of Video Processor Registers */
818 vp_default_filter(res
);
820 /* disable all layers */
821 mixer_reg_writemask(res
, MXR_CFG
, 0, MXR_CFG_GRP0_ENABLE
);
822 mixer_reg_writemask(res
, MXR_CFG
, 0, MXR_CFG_GRP1_ENABLE
);
823 mixer_reg_writemask(res
, MXR_CFG
, 0, MXR_CFG_VP_ENABLE
);
825 mixer_vsync_set_update(ctx
, true);
826 spin_unlock_irqrestore(&res
->reg_slock
, flags
);
829 static void mixer_resource_poweron(struct mixer_context
*ctx
)
831 struct mixer_resources
*res
= &ctx
->mixer_res
;
833 DRM_DEBUG_KMS("[%d] %s\n", __LINE__
, __func__
);
835 clk_enable(res
->mixer
);
837 clk_enable(res
->sclk_mixer
);
839 mixer_win_reset(ctx
);
842 static void mixer_resource_poweroff(struct mixer_context
*ctx
)
844 struct mixer_resources
*res
= &ctx
->mixer_res
;
846 DRM_DEBUG_KMS("[%d] %s\n", __LINE__
, __func__
);
848 clk_disable(res
->mixer
);
849 clk_disable(res
->vp
);
850 clk_disable(res
->sclk_mixer
);
853 static int mixer_runtime_resume(struct device
*dev
)
855 struct exynos_drm_hdmi_context
*ctx
= get_mixer_context(dev
);
857 DRM_DEBUG_KMS("resume - start\n");
859 mixer_resource_poweron((struct mixer_context
*)ctx
->ctx
);
864 static int mixer_runtime_suspend(struct device
*dev
)
866 struct exynos_drm_hdmi_context
*ctx
= get_mixer_context(dev
);
868 DRM_DEBUG_KMS("suspend - start\n");
870 mixer_resource_poweroff((struct mixer_context
*)ctx
->ctx
);
875 static const struct dev_pm_ops mixer_pm_ops
= {
876 .runtime_suspend
= mixer_runtime_suspend
,
877 .runtime_resume
= mixer_runtime_resume
,
880 static int __devinit
mixer_resources_init(struct exynos_drm_hdmi_context
*ctx
,
881 struct platform_device
*pdev
)
883 struct mixer_context
*mixer_ctx
=
884 (struct mixer_context
*)ctx
->ctx
;
885 struct device
*dev
= &pdev
->dev
;
886 struct mixer_resources
*mixer_res
= &mixer_ctx
->mixer_res
;
887 struct resource
*res
;
890 mixer_res
->dev
= dev
;
891 spin_lock_init(&mixer_res
->reg_slock
);
893 mixer_res
->mixer
= clk_get(dev
, "mixer");
894 if (IS_ERR_OR_NULL(mixer_res
->mixer
)) {
895 dev_err(dev
, "failed to get clock 'mixer'\n");
899 mixer_res
->vp
= clk_get(dev
, "vp");
900 if (IS_ERR_OR_NULL(mixer_res
->vp
)) {
901 dev_err(dev
, "failed to get clock 'vp'\n");
905 mixer_res
->sclk_mixer
= clk_get(dev
, "sclk_mixer");
906 if (IS_ERR_OR_NULL(mixer_res
->sclk_mixer
)) {
907 dev_err(dev
, "failed to get clock 'sclk_mixer'\n");
911 mixer_res
->sclk_hdmi
= clk_get(dev
, "sclk_hdmi");
912 if (IS_ERR_OR_NULL(mixer_res
->sclk_hdmi
)) {
913 dev_err(dev
, "failed to get clock 'sclk_hdmi'\n");
917 mixer_res
->sclk_dac
= clk_get(dev
, "sclk_dac");
918 if (IS_ERR_OR_NULL(mixer_res
->sclk_dac
)) {
919 dev_err(dev
, "failed to get clock 'sclk_dac'\n");
923 res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, "mxr");
925 dev_err(dev
, "get memory resource failed.\n");
930 clk_set_parent(mixer_res
->sclk_mixer
, mixer_res
->sclk_hdmi
);
932 mixer_res
->mixer_regs
= ioremap(res
->start
, resource_size(res
));
933 if (mixer_res
->mixer_regs
== NULL
) {
934 dev_err(dev
, "register mapping failed.\n");
939 res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, "vp");
941 dev_err(dev
, "get memory resource failed.\n");
943 goto fail_mixer_regs
;
946 mixer_res
->vp_regs
= ioremap(res
->start
, resource_size(res
));
947 if (mixer_res
->vp_regs
== NULL
) {
948 dev_err(dev
, "register mapping failed.\n");
950 goto fail_mixer_regs
;
953 res
= platform_get_resource_byname(pdev
, IORESOURCE_IRQ
, "irq");
955 dev_err(dev
, "get interrupt resource failed.\n");
960 ret
= request_irq(res
->start
, mixer_irq_handler
, 0, "drm_mixer", ctx
);
962 dev_err(dev
, "request interrupt failed.\n");
965 mixer_res
->irq
= res
->start
;
970 iounmap(mixer_res
->vp_regs
);
973 iounmap(mixer_res
->mixer_regs
);
976 if (!IS_ERR_OR_NULL(mixer_res
->sclk_dac
))
977 clk_put(mixer_res
->sclk_dac
);
978 if (!IS_ERR_OR_NULL(mixer_res
->sclk_hdmi
))
979 clk_put(mixer_res
->sclk_hdmi
);
980 if (!IS_ERR_OR_NULL(mixer_res
->sclk_mixer
))
981 clk_put(mixer_res
->sclk_mixer
);
982 if (!IS_ERR_OR_NULL(mixer_res
->vp
))
983 clk_put(mixer_res
->vp
);
984 if (!IS_ERR_OR_NULL(mixer_res
->mixer
))
985 clk_put(mixer_res
->mixer
);
986 mixer_res
->dev
= NULL
;
990 static void mixer_resources_cleanup(struct mixer_context
*ctx
)
992 struct mixer_resources
*res
= &ctx
->mixer_res
;
994 disable_irq(res
->irq
);
995 free_irq(res
->irq
, ctx
);
997 iounmap(res
->vp_regs
);
998 iounmap(res
->mixer_regs
);
1001 static int __devinit
mixer_probe(struct platform_device
*pdev
)
1003 struct device
*dev
= &pdev
->dev
;
1004 struct exynos_drm_hdmi_context
*drm_hdmi_ctx
;
1005 struct mixer_context
*ctx
;
1008 dev_info(dev
, "probe start\n");
1010 drm_hdmi_ctx
= kzalloc(sizeof(*drm_hdmi_ctx
), GFP_KERNEL
);
1011 if (!drm_hdmi_ctx
) {
1012 DRM_ERROR("failed to allocate common hdmi context.\n");
1016 ctx
= kzalloc(sizeof(*ctx
), GFP_KERNEL
);
1018 DRM_ERROR("failed to alloc mixer context.\n");
1019 kfree(drm_hdmi_ctx
);
1023 drm_hdmi_ctx
->ctx
= (void *)ctx
;
1025 platform_set_drvdata(pdev
, drm_hdmi_ctx
);
1027 /* acquire resources: regs, irqs, clocks */
1028 ret
= mixer_resources_init(drm_hdmi_ctx
, pdev
);
1032 /* register specific callback point to common hdmi. */
1033 exynos_drm_overlay_ops_register(&overlay_ops
);
1035 mixer_resource_poweron(ctx
);
1041 dev_info(dev
, "probe failed\n");
1045 static int mixer_remove(struct platform_device
*pdev
)
1047 struct device
*dev
= &pdev
->dev
;
1048 struct exynos_drm_hdmi_context
*drm_hdmi_ctx
=
1049 platform_get_drvdata(pdev
);
1050 struct mixer_context
*ctx
= (struct mixer_context
*)drm_hdmi_ctx
->ctx
;
1052 dev_info(dev
, "remove successful\n");
1054 mixer_resource_poweroff(ctx
);
1055 mixer_resources_cleanup(ctx
);
1060 struct platform_driver mixer_driver
= {
1062 .name
= "s5p-mixer",
1063 .owner
= THIS_MODULE
,
1064 .pm
= &mixer_pm_ops
,
1066 .probe
= mixer_probe
,
1067 .remove
= __devexit_p(mixer_remove
),
1069 EXPORT_SYMBOL(mixer_driver
);
1071 MODULE_AUTHOR("Seung-Woo Kim, <sw0312.kim@samsung.com>");
1072 MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
1073 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
1074 MODULE_DESCRIPTION("Samsung DRM HDMI mixer Driver");
1075 MODULE_LICENSE("GPL");