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"
40 #define HDMI_OVERLAY_NUMBER 3
42 #define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev))
44 struct hdmi_win_data {
47 dma_addr_t chroma_dma_addr;
48 void __iomem *chroma_vaddr;
49 uint32_t pixel_format;
53 unsigned int crtc_width;
54 unsigned int crtc_height;
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;
64 struct mixer_resources {
67 void __iomem *mixer_regs;
68 void __iomem *vp_regs;
72 struct clk *sclk_mixer;
73 struct clk *sclk_hdmi;
77 struct mixer_context {
78 struct fb_videomode *default_timing;
79 unsigned int default_win;
80 unsigned int default_bpp;
86 struct mixer_resources mixer_res;
87 struct hdmi_win_data win_data[HDMI_OVERLAY_NUMBER];
90 static 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,
101 static 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,
112 static 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,
119 static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
121 return readl(res->vp_regs + reg_id);
124 static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
127 writel(val, res->vp_regs + reg_id);
130 static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
133 u32 old = vp_reg_read(res, reg_id);
135 val = (val & mask) | (old & ~mask);
136 writel(val, res->vp_regs + reg_id);
139 static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
141 return readl(res->mixer_regs + reg_id);
144 static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
147 writel(val, res->mixer_regs + reg_id);
150 static inline void mixer_reg_writemask(struct mixer_resources *res,
151 u32 reg_id, u32 val, u32 mask)
153 u32 old = mixer_reg_read(res, reg_id);
155 val = (val & mask) | (old & ~mask);
156 writel(val, res->mixer_regs + reg_id);
159 static void mixer_regs_dump(struct mixer_context *ctx)
161 #define DUMPREG(reg_id) \
163 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
164 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
170 DUMPREG(MXR_INT_STATUS);
172 DUMPREG(MXR_LAYER_CFG);
173 DUMPREG(MXR_VIDEO_CFG);
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);
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);
191 static void vp_regs_dump(struct mixer_context *ctx)
193 #define DUMPREG(reg_id) \
195 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
196 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
201 DUMPREG(VP_SHADOW_UPDATE);
202 DUMPREG(VP_FIELD_ID);
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);
226 static inline void vp_filter_set(struct mixer_resources *res,
227 int reg_id, const u8 *data, unsigned int size)
229 /* assure 4-byte align */
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);
238 static void vp_default_filter(struct mixer_resources *res)
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);
248 static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
250 struct mixer_resources *res = &ctx->mixer_res;
252 /* block update on vsync */
253 mixer_reg_writemask(res, MXR_STATUS, enable ?
254 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
256 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
257 VP_SHADOW_UPDATE_ENABLE : 0);
260 static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
262 struct mixer_resources *res = &ctx->mixer_res;
265 /* choosing between interlace and progressive mode */
266 val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
267 MXR_CFG_SCAN_PROGRASSIVE);
269 /* choosing between porper HD and SD mode */
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;
279 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
281 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
284 static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
286 struct mixer_resources *res = &ctx->mixer_res;
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) |
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) |
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));
312 val = MXR_CFG_RGB709_16_235;
313 mixer_reg_write(res, MXR_CM_COEFF_Y,
314 (1 << 30) | (94 << 20) | (314 << 10) |
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));
322 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
325 static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable)
327 struct mixer_resources *res = &ctx->mixer_res;
328 u32 val = enable ? ~0 : 0;
332 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
335 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
338 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
339 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_VP_ENABLE);
344 static void mixer_run(struct mixer_context *ctx)
346 struct mixer_resources *res = &ctx->mixer_res;
348 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
350 mixer_regs_dump(ctx);
353 static void vp_video_buffer(struct mixer_context *ctx, int win)
355 struct mixer_resources *res = &ctx->mixer_res;
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;
368 win_data = &ctx->win_data[win];
370 switch (win_data->pixel_format) {
371 case DRM_FORMAT_NV12MT:
373 case DRM_FORMAT_NV12M:
377 /* TODO: single buffer format NV12, NV21 */
379 /* ignore pixel format at disable time */
380 if (!win_data->dma_addr)
383 DRM_ERROR("pixel format for vp is wrong [%d].\n",
384 win_data->pixel_format);
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;
395 /* scaling feature: (src << 16) / dst */
396 x_ratio = (width << 16) / width;
397 y_ratio = (height << 16) / height;
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;
405 luma_addr[0] = win_data->dma_addr;
406 chroma_addr[0] = win_data->chroma_dma_addr;
408 luma_addr[0] = win_data->dma_addr;
409 chroma_addr[0] = win_data->dma_addr
410 + (full_width * full_height);
413 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) {
414 ctx->interlace = true;
416 luma_addr[1] = luma_addr[0] + 0x40;
417 chroma_addr[1] = chroma_addr[0] + 0x40;
419 luma_addr[1] = luma_addr[0] + full_width;
420 chroma_addr[1] = chroma_addr[0] + full_width;
423 ctx->interlace = false;
428 spin_lock_irqsave(&res->reg_slock, flags);
429 mixer_vsync_set_update(ctx, false);
431 /* interlace or progressive scan mode */
432 val = (ctx->interlace ? ~0 : 0);
433 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
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);
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));
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);
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);
459 vp_reg_write(res, VP_DST_HEIGHT, height);
460 vp_reg_write(res, VP_DST_V_POSITION, dst_y_offset);
463 vp_reg_write(res, VP_H_RATIO, x_ratio);
464 vp_reg_write(res, VP_V_RATIO, y_ratio);
466 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
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]);
474 mixer_cfg_scan(ctx, mode_height);
475 mixer_cfg_rgb_fmt(ctx, mode_height);
476 mixer_cfg_layer(ctx, win, true);
479 mixer_vsync_set_update(ctx, true);
480 spin_unlock_irqrestore(&res->reg_slock, flags);
485 static void mixer_graph_buffer(struct mixer_context *ctx, int win)
487 struct mixer_resources *res = &ctx->mixer_res;
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;
498 win_data = &ctx->win_data[win];
505 switch (win_data->bpp) {
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;
523 /* 2x scaling feature */
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;
532 /* converting dma address base and source offset */
534 + (src_x_offset * win_data->bpp >> 3)
535 + (src_y_offset * full_width * win_data->bpp >> 3);
539 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE)
540 ctx->interlace = true;
542 ctx->interlace = false;
544 spin_lock_irqsave(&res->reg_slock, flags);
545 mixer_vsync_set_update(ctx, false);
548 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
549 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
552 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), full_width);
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);
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);
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);
570 /* set buffer address to mixer */
571 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
573 mixer_cfg_scan(ctx, mode_height);
574 mixer_cfg_rgb_fmt(ctx, mode_height);
575 mixer_cfg_layer(ctx, win, true);
578 mixer_vsync_set_update(ctx, true);
579 spin_unlock_irqrestore(&res->reg_slock, flags);
582 static void vp_win_reset(struct mixer_context *ctx)
584 struct mixer_resources *res = &ctx->mixer_res;
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)
594 WARN(tries == 0, "failed to reset Video Processor\n");
597 static int mixer_enable_vblank(void *ctx, int pipe)
599 struct mixer_context *mixer_ctx = ctx;
600 struct mixer_resources *res = &mixer_ctx->mixer_res;
602 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
604 mixer_ctx->pipe = pipe;
606 /* enable vsync interrupt */
607 mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
613 static void mixer_disable_vblank(void *ctx)
615 struct mixer_context *mixer_ctx = ctx;
616 struct mixer_resources *res = &mixer_ctx->mixer_res;
618 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
620 /* disable vsync interrupt */
621 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
624 static void mixer_win_mode_set(void *ctx,
625 struct exynos_drm_overlay *overlay)
627 struct mixer_context *mixer_ctx = ctx;
628 struct hdmi_win_data *win_data;
631 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
634 DRM_ERROR("overlay is NULL\n");
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);
645 if (win == DEFAULT_ZPOS)
646 win = mixer_ctx->default_win;
648 if (win < 0 || win > HDMI_OVERLAY_NUMBER) {
649 DRM_ERROR("overlay plane[%d] is wrong\n", win);
653 win_data = &mixer_ctx->win_data[win];
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;
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;
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;
672 win_data->mode_width = overlay->mode_width;
673 win_data->mode_height = overlay->mode_height;
675 win_data->scan_flags = overlay->scan_flag;
678 static void mixer_win_commit(void *ctx, int zpos)
680 struct mixer_context *mixer_ctx = ctx;
683 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
685 if (win == DEFAULT_ZPOS)
686 win = mixer_ctx->default_win;
688 if (win < 0 || win > HDMI_OVERLAY_NUMBER) {
689 DRM_ERROR("overlay plane[%d] is wrong\n", win);
694 vp_video_buffer(mixer_ctx, win);
696 mixer_graph_buffer(mixer_ctx, win);
699 static void mixer_win_disable(void *ctx, int zpos)
701 struct mixer_context *mixer_ctx = ctx;
702 struct mixer_resources *res = &mixer_ctx->mixer_res;
706 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
708 if (win == DEFAULT_ZPOS)
709 win = mixer_ctx->default_win;
711 if (win < 0 || win > HDMI_OVERLAY_NUMBER) {
712 DRM_ERROR("overlay plane[%d] is wrong\n", win);
716 spin_lock_irqsave(&res->reg_slock, flags);
717 mixer_vsync_set_update(mixer_ctx, false);
719 mixer_cfg_layer(mixer_ctx, win, false);
721 mixer_vsync_set_update(mixer_ctx, true);
722 spin_unlock_irqrestore(&res->reg_slock, flags);
725 static 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,
733 /* for pageflip event */
734 static void mixer_finish_pageflip(struct drm_device *drm_dev, int crtc)
736 struct exynos_drm_private *dev_priv = drm_dev->dev_private;
737 struct drm_pending_vblank_event *e, *t;
740 bool is_checked = false;
742 spin_lock_irqsave(&drm_dev->event_lock, flags);
744 list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
746 /* if event's pipe isn't same as crtc then ignore it. */
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;
756 list_move_tail(&e->base.link, &e->base.file_priv->event_list);
757 wake_up_interruptible(&e->base.file_priv->event_wait);
762 * call drm_vblank_put only in case that drm_vblank_get was
765 if (atomic_read(&drm_dev->vblank_refcount[crtc]) > 0)
766 drm_vblank_put(drm_dev, crtc);
768 spin_unlock_irqrestore(&drm_dev->event_lock, flags);
771 static irqreturn_t mixer_irq_handler(int irq, void *arg)
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;
779 spin_lock(&res->reg_slock);
781 /* read interrupt status for handling and clearing flags for VSYNC */
782 val = mixer_reg_read(res, MXR_INT_STATUS);
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)
792 val_base = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
793 if (ctx->win_data[1].dma_addr != val_base)
797 drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe);
798 mixer_finish_pageflip(drm_hdmi_ctx->drm_dev, ctx->pipe);
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;
808 mixer_reg_write(res, MXR_INT_STATUS, val);
810 spin_unlock(&res->reg_slock);
815 static void mixer_win_reset(struct mixer_context *ctx)
817 struct mixer_resources *res = &ctx->mixer_res;
819 u32 val; /* value stored to register */
821 spin_lock_irqsave(&res->reg_slock, flags);
822 mixer_vsync_set_update(ctx, false);
824 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
826 /* set output in RGB888 mode */
827 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
829 /* 16 beat burst in DMA */
830 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
831 MXR_STATUS_BURST_MASK);
833 /* setting default layer priority: layer1 > layer0 > video
834 * because typical usage scenario would be
836 * layer0 - framebuffer
837 * video - video overlay
839 val = MXR_LAYER_CFG_GRP1_VAL(3);
840 val |= MXR_LAYER_CFG_GRP0_VAL(2);
841 val |= MXR_LAYER_CFG_VP_VAL(1);
842 mixer_reg_write(res, MXR_LAYER_CFG, val);
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);
849 /* setting graphical layers */
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 */
855 /* the same configuration for both layers */
856 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
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);
862 /* configuration of Video Processor Registers */
864 vp_default_filter(res);
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);
871 mixer_vsync_set_update(ctx, true);
872 spin_unlock_irqrestore(&res->reg_slock, flags);
875 static void mixer_resource_poweron(struct mixer_context *ctx)
877 struct mixer_resources *res = &ctx->mixer_res;
879 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
881 clk_enable(res->mixer);
883 clk_enable(res->sclk_mixer);
885 mixer_win_reset(ctx);
888 static void mixer_resource_poweroff(struct mixer_context *ctx)
890 struct mixer_resources *res = &ctx->mixer_res;
892 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
894 clk_disable(res->mixer);
895 clk_disable(res->vp);
896 clk_disable(res->sclk_mixer);
899 static int mixer_runtime_resume(struct device *dev)
901 struct exynos_drm_hdmi_context *ctx = get_mixer_context(dev);
903 DRM_DEBUG_KMS("resume - start\n");
905 mixer_resource_poweron((struct mixer_context *)ctx->ctx);
910 static int mixer_runtime_suspend(struct device *dev)
912 struct exynos_drm_hdmi_context *ctx = get_mixer_context(dev);
914 DRM_DEBUG_KMS("suspend - start\n");
916 mixer_resource_poweroff((struct mixer_context *)ctx->ctx);
921 static const struct dev_pm_ops mixer_pm_ops = {
922 .runtime_suspend = mixer_runtime_suspend,
923 .runtime_resume = mixer_runtime_resume,
926 static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
927 struct platform_device *pdev)
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;
936 mixer_res->dev = dev;
937 spin_lock_init(&mixer_res->reg_slock);
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");
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");
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");
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");
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");
969 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr");
971 dev_err(dev, "get memory resource failed.\n");
976 clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
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");
985 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp");
987 dev_err(dev, "get memory resource failed.\n");
989 goto fail_mixer_regs;
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");
996 goto fail_mixer_regs;
999 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq");
1001 dev_err(dev, "get interrupt resource failed.\n");
1006 ret = request_irq(res->start, mixer_irq_handler, 0, "drm_mixer", ctx);
1008 dev_err(dev, "request interrupt failed.\n");
1011 mixer_res->irq = res->start;
1016 iounmap(mixer_res->vp_regs);
1019 iounmap(mixer_res->mixer_regs);
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;
1036 static void mixer_resources_cleanup(struct mixer_context *ctx)
1038 struct mixer_resources *res = &ctx->mixer_res;
1040 disable_irq(res->irq);
1041 free_irq(res->irq, ctx);
1043 iounmap(res->vp_regs);
1044 iounmap(res->mixer_regs);
1047 static int __devinit mixer_probe(struct platform_device *pdev)
1049 struct device *dev = &pdev->dev;
1050 struct exynos_drm_hdmi_context *drm_hdmi_ctx;
1051 struct mixer_context *ctx;
1054 dev_info(dev, "probe start\n");
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");
1062 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
1064 DRM_ERROR("failed to alloc mixer context.\n");
1065 kfree(drm_hdmi_ctx);
1069 drm_hdmi_ctx->ctx = (void *)ctx;
1071 platform_set_drvdata(pdev, drm_hdmi_ctx);
1073 /* acquire resources: regs, irqs, clocks */
1074 ret = mixer_resources_init(drm_hdmi_ctx, pdev);
1078 /* register specific callback point to common hdmi. */
1079 exynos_drm_overlay_ops_register(&overlay_ops);
1081 mixer_resource_poweron(ctx);
1087 dev_info(dev, "probe failed\n");
1091 static int mixer_remove(struct platform_device *pdev)
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;
1098 dev_info(dev, "remove successful\n");
1100 mixer_resource_poweroff(ctx);
1101 mixer_resources_cleanup(ctx);
1106 struct platform_driver mixer_driver = {
1108 .name = "s5p-mixer",
1109 .owner = THIS_MODULE,
1110 .pm = &mixer_pm_ops,
1112 .probe = mixer_probe,
1113 .remove = __devexit_p(mixer_remove),