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_crtc.h"
39 #include "exynos_drm_display.h"
41 #include "exynos_hdmi.h"
43 #include <plat/map-base.h>
44 #ifdef CONFIG_EXYNOS_IOMMU
45 #include <mach/sysmmu.h>
46 #include <linux/of_platform.h>
50 #define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev))
52 #define MIXER_WIN_NR 3
53 #define MIXER_DEFAULT_WIN 0
55 struct hdmi_win_data {
58 dma_addr_t chroma_dma_addr;
59 void __iomem *chroma_vaddr;
60 uint32_t pixel_format;
64 unsigned int crtc_width;
65 unsigned int crtc_height;
68 unsigned int fb_width;
69 unsigned int fb_height;
70 unsigned int mode_width;
71 unsigned int mode_height;
72 unsigned int scan_flags;
76 struct mixer_resources {
79 void __iomem *mixer_regs;
80 void __iomem *vp_regs;
82 wait_queue_head_t event_queue;
85 struct clk *sclk_mixer;
86 struct clk *sclk_hdmi;
88 unsigned int is_soc_exynos5;
91 struct mixer_context {
93 struct drm_device *drm_dev;
97 bool is_mixer_powered_on;
98 bool enabled[MIXER_WIN_NR];
100 struct mixer_resources mixer_res;
101 struct hdmi_win_data win_data[MIXER_WIN_NR];
102 unsigned long event_flags;
104 bool is_800x600_initialized;
107 /* event flags used */
108 enum mixer_status_flags {
112 static const u8 filter_y_horiz_tap8[] = {
113 0, -1, -1, -1, -1, -1, -1, -1,
114 -1, -1, -1, -1, -1, 0, 0, 0,
115 0, 2, 4, 5, 6, 6, 6, 6,
116 6, 5, 5, 4, 3, 2, 1, 1,
117 0, -6, -12, -16, -18, -20, -21, -20,
118 -20, -18, -16, -13, -10, -8, -5, -2,
119 127, 126, 125, 121, 114, 107, 99, 89,
120 79, 68, 57, 46, 35, 25, 16, 8,
123 static const u8 filter_y_vert_tap4[] = {
124 0, -3, -6, -8, -8, -8, -8, -7,
125 -6, -5, -4, -3, -2, -1, -1, 0,
126 127, 126, 124, 118, 111, 102, 92, 81,
127 70, 59, 48, 37, 27, 19, 11, 5,
128 0, 5, 11, 19, 27, 37, 48, 59,
129 70, 81, 92, 102, 111, 118, 124, 126,
130 0, 0, -1, -1, -2, -3, -4, -5,
131 -6, -7, -8, -8, -8, -8, -6, -3,
134 static const u8 filter_cr_horiz_tap4[] = {
135 0, -3, -6, -8, -8, -8, -8, -7,
136 -6, -5, -4, -3, -2, -1, -1, 0,
137 127, 126, 124, 118, 111, 102, 92, 81,
138 70, 59, 48, 37, 27, 19, 11, 5,
141 static void mixer_win_reset(struct mixer_context *mctx);
143 static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
145 return readl(res->vp_regs + reg_id);
148 static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
151 writel(val, res->vp_regs + reg_id);
154 static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
157 u32 old = vp_reg_read(res, reg_id);
159 val = (val & mask) | (old & ~mask);
160 writel(val, res->vp_regs + reg_id);
163 static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
165 return readl(res->mixer_regs + reg_id);
168 static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
171 writel(val, res->mixer_regs + reg_id);
174 static inline void mixer_reg_writemask(struct mixer_resources *res,
175 u32 reg_id, u32 val, u32 mask)
177 u32 old = mixer_reg_read(res, reg_id);
179 val = (val & mask) | (old & ~mask);
180 writel(val, res->mixer_regs + reg_id);
183 enum exynos_mixer_mode_type exynos_mixer_get_mode_type(int width, int height)
185 if (width >= 464 && width <= 720 && height <= 480)
186 return EXYNOS_MIXER_MODE_SD_NTSC;
187 else if (width >= 464 && width <= 720 && height <= 576)
188 return EXYNOS_MIXER_MODE_SD_PAL;
189 else if (width >= 1024 && width <= 1280 && height <= 720)
190 return EXYNOS_MIXER_MODE_HD_720;
191 else if ((width == 1440 && height == 900) ||
192 (width == 800 && height == 600) ||
193 (width >= 1664 && width <= 1920 && height <= 1080))
194 return EXYNOS_MIXER_MODE_HD_1080;
196 return EXYNOS_MIXER_MODE_INVALID;
199 static void mixer_regs_dump(struct mixer_context *mctx)
201 #define DUMPREG(reg_id) \
203 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
204 (u32)readl(mctx->mixer_res.mixer_regs + reg_id)); \
210 DUMPREG(MXR_INT_STATUS);
212 DUMPREG(MXR_LAYER_CFG);
213 DUMPREG(MXR_VIDEO_CFG);
215 DUMPREG(MXR_GRAPHIC0_CFG);
216 DUMPREG(MXR_GRAPHIC0_BASE);
217 DUMPREG(MXR_GRAPHIC0_SPAN);
218 DUMPREG(MXR_GRAPHIC0_WH);
219 DUMPREG(MXR_GRAPHIC0_SXY);
220 DUMPREG(MXR_GRAPHIC0_DXY);
222 DUMPREG(MXR_GRAPHIC1_CFG);
223 DUMPREG(MXR_GRAPHIC1_BASE);
224 DUMPREG(MXR_GRAPHIC1_SPAN);
225 DUMPREG(MXR_GRAPHIC1_WH);
226 DUMPREG(MXR_GRAPHIC1_SXY);
227 DUMPREG(MXR_GRAPHIC1_DXY);
231 static void vp_regs_dump(struct mixer_context *mctx)
233 #define DUMPREG(reg_id) \
235 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
236 (u32) readl(mctx->mixer_res.vp_regs + reg_id)); \
241 DUMPREG(VP_SHADOW_UPDATE);
242 DUMPREG(VP_FIELD_ID);
244 DUMPREG(VP_IMG_SIZE_Y);
245 DUMPREG(VP_IMG_SIZE_C);
246 DUMPREG(VP_PER_RATE_CTRL);
247 DUMPREG(VP_TOP_Y_PTR);
248 DUMPREG(VP_BOT_Y_PTR);
249 DUMPREG(VP_TOP_C_PTR);
250 DUMPREG(VP_BOT_C_PTR);
251 DUMPREG(VP_ENDIAN_MODE);
252 DUMPREG(VP_SRC_H_POSITION);
253 DUMPREG(VP_SRC_V_POSITION);
254 DUMPREG(VP_SRC_WIDTH);
255 DUMPREG(VP_SRC_HEIGHT);
256 DUMPREG(VP_DST_H_POSITION);
257 DUMPREG(VP_DST_V_POSITION);
258 DUMPREG(VP_DST_WIDTH);
259 DUMPREG(VP_DST_HEIGHT);
266 static inline void vp_filter_set(struct mixer_resources *res,
267 int reg_id, const u8 *data, unsigned int size)
269 /* assure 4-byte align */
271 for (; size; size -= 4, reg_id += 4, data += 4) {
272 u32 val = (data[0] << 24) | (data[1] << 16) |
273 (data[2] << 8) | data[3];
274 vp_reg_write(res, reg_id, val);
278 static void vp_default_filter(struct mixer_resources *res)
280 vp_filter_set(res, VP_POLY8_Y0_LL,
281 filter_y_horiz_tap8, sizeof filter_y_horiz_tap8);
282 vp_filter_set(res, VP_POLY4_Y0_LL,
283 filter_y_vert_tap4, sizeof filter_y_vert_tap4);
284 vp_filter_set(res, VP_POLY4_C0_LL,
285 filter_cr_horiz_tap4, sizeof filter_cr_horiz_tap4);
288 static void mixer_vsync_set_update(struct mixer_context *mctx, bool enable)
290 struct mixer_resources *res = &mctx->mixer_res;
292 /* block update on vsync */
293 mixer_reg_writemask(res, MXR_STATUS, enable ?
294 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
296 if (!(res->is_soc_exynos5))
297 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
298 VP_SHADOW_UPDATE_ENABLE : 0);
301 static void mixer_cfg_scan(struct mixer_context *mctx, u32 width, u32 height)
303 struct mixer_resources *res = &mctx->mixer_res;
304 enum exynos_mixer_mode_type mode_type;
307 /* choosing between interlace and progressive mode */
308 val = (mctx->interlace ? MXR_CFG_SCAN_INTERLACE :
309 MXR_CFG_SCAN_PROGRASSIVE);
311 /* choosing between proper HD and SD mode */
312 mode_type = exynos_mixer_get_mode_type(width, height);
314 case EXYNOS_MIXER_MODE_SD_NTSC:
315 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
317 case EXYNOS_MIXER_MODE_SD_PAL:
318 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
320 case EXYNOS_MIXER_MODE_HD_720:
321 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
323 case EXYNOS_MIXER_MODE_HD_1080:
324 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
327 DRM_ERROR("Invalid mixer config %dx%d\n", width, height);
331 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
334 static void mixer_set_layer_offset(struct mixer_context *mctx, u32 offset)
336 struct mixer_resources *res = &mctx->mixer_res;
337 int current_dxy = mixer_reg_read(res, MXR_GRAPHIC1_DXY);
339 if (mctx->previous_dxy != current_dxy) {
340 current_dxy += MXR_GRP_DXY_DX(offset);
341 mixer_reg_write(res, MXR_GRAPHIC1_DXY, current_dxy);
342 mctx->previous_dxy = current_dxy;
345 mixer_reg_write(res, MXR_GRAPHIC0_DXY, MXR_GRP_DXY_DX(offset));
348 static void mixer_toggle_3d_path(struct mixer_context *mctx)
350 struct mixer_resources *res = &mctx->mixer_res;
352 mixer_reg_write(res, MXR_TVOUT_CFG,
353 mctx->is_800x600_initialized ? 0x13 : 0x17);
355 mctx->is_800x600_initialized = true;
358 static void mixer_cfg_rgb_fmt(struct mixer_context *mctx, unsigned int height)
360 struct mixer_resources *res = &mctx->mixer_res;
364 val = MXR_CFG_RGB601_0_255;
365 } else if (height == 576) {
366 val = MXR_CFG_RGB601_0_255;
367 } else if (height == 720) {
368 val = MXR_CFG_RGB709_16_235;
369 mixer_reg_write(res, MXR_CM_COEFF_Y,
370 (1 << 30) | (94 << 20) | (314 << 10) |
372 mixer_reg_write(res, MXR_CM_COEFF_CB,
373 (972 << 20) | (851 << 10) | (225 << 0));
374 mixer_reg_write(res, MXR_CM_COEFF_CR,
375 (225 << 20) | (820 << 10) | (1004 << 0));
376 } else if (height == 1080) {
377 val = MXR_CFG_RGB709_16_235;
378 mixer_reg_write(res, MXR_CM_COEFF_Y,
379 (1 << 30) | (94 << 20) | (314 << 10) |
381 mixer_reg_write(res, MXR_CM_COEFF_CB,
382 (972 << 20) | (851 << 10) | (225 << 0));
383 mixer_reg_write(res, MXR_CM_COEFF_CR,
384 (225 << 20) | (820 << 10) | (1004 << 0));
386 val = MXR_CFG_RGB709_16_235;
387 mixer_reg_write(res, MXR_CM_COEFF_Y,
388 (1 << 30) | (94 << 20) | (314 << 10) |
390 mixer_reg_write(res, MXR_CM_COEFF_CB,
391 (972 << 20) | (851 << 10) | (225 << 0));
392 mixer_reg_write(res, MXR_CM_COEFF_CR,
393 (225 << 20) | (820 << 10) | (1004 << 0));
396 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
399 static void mixer_cfg_layer(struct mixer_context *mctx, int win, bool enable)
401 struct mixer_resources *res = &mctx->mixer_res;
402 u32 val = enable ? ~0 : 0;
406 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
409 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
412 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
413 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_VP_ENABLE);
418 static void mixer_run(struct mixer_context *mctx)
420 struct mixer_resources *res = &mctx->mixer_res;
422 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
424 mixer_regs_dump(mctx);
427 static int mixer_wait_for_vsync(struct mixer_context *mctx)
431 mctx->event_flags |= MXR_EVENT_VSYNC;
433 ret = wait_event_timeout(mctx->mixer_res.event_queue,
434 ((mctx->event_flags & MXR_EVENT_VSYNC) == 0), msecs_to_jiffies(1000));
441 static int mixer_get_layer_update_count(struct mixer_context *ctx)
443 struct mixer_resources *res = &ctx->mixer_res;
446 if (!res->is_soc_exynos5)
449 val = mixer_reg_read(res, MXR_CFG);
451 return (val & MXR_CFG_LAYER_UPDATE_COUNT_MASK) >>
452 MXR_CFG_LAYER_UPDATE_COUNT0;
455 static void mixer_layer_update(struct mixer_context *ctx)
457 struct mixer_resources *res = &ctx->mixer_res;
459 if (!res->is_soc_exynos5)
462 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
465 static void vp_video_buffer(struct mixer_context *mctx, int win)
467 struct mixer_resources *res = &mctx->mixer_res;
469 struct hdmi_win_data *win_data;
470 unsigned int full_width, full_height, width, height;
471 unsigned int x_ratio, y_ratio;
472 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
473 unsigned int mode_width, mode_height;
474 unsigned int buf_num;
475 dma_addr_t luma_addr[2], chroma_addr[2];
476 bool tiled_mode = false;
477 bool crcb_mode = false;
480 win_data = &mctx->win_data[win];
482 switch (win_data->pixel_format) {
483 case DRM_FORMAT_NV12MT:
485 case DRM_FORMAT_NV12M:
489 /* TODO: single buffer format NV12, NV21 */
491 /* ignore pixel format at disable time */
492 if (!win_data->dma_addr)
495 DRM_ERROR("pixel format for vp is wrong [%d].\n",
496 win_data->pixel_format);
500 full_width = win_data->fb_width;
501 full_height = win_data->fb_height;
502 width = win_data->crtc_width;
503 height = win_data->crtc_height;
504 mode_width = win_data->mode_width;
505 mode_height = win_data->mode_height;
507 /* scaling feature: (src << 16) / dst */
508 x_ratio = (width << 16) / width;
509 y_ratio = (height << 16) / height;
511 src_x_offset = win_data->fb_x;
512 src_y_offset = win_data->fb_y;
513 dst_x_offset = win_data->crtc_x;
514 dst_y_offset = win_data->crtc_y;
517 luma_addr[0] = win_data->dma_addr;
518 chroma_addr[0] = win_data->chroma_dma_addr;
520 luma_addr[0] = win_data->dma_addr;
521 chroma_addr[0] = win_data->dma_addr
522 + (full_width * full_height);
525 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) {
526 mctx->interlace = true;
528 luma_addr[1] = luma_addr[0] + 0x40;
529 chroma_addr[1] = chroma_addr[0] + 0x40;
531 luma_addr[1] = luma_addr[0] + full_width;
532 chroma_addr[1] = chroma_addr[0] + full_width;
535 mctx->interlace = false;
540 spin_lock_irqsave(&res->reg_slock, flags);
541 mixer_vsync_set_update(mctx, false);
543 mctx->enabled[win] = true;
545 /* interlace or progressive scan mode */
546 val = (mctx->interlace ? ~0 : 0);
547 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
550 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
551 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
552 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
554 /* setting size of input image */
555 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(full_width) |
556 VP_IMG_VSIZE(full_height));
557 /* chroma height has to reduced by 2 to avoid chroma distorions */
558 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(full_width) |
559 VP_IMG_VSIZE(full_height / 2));
561 vp_reg_write(res, VP_SRC_WIDTH, width);
562 vp_reg_write(res, VP_SRC_HEIGHT, height);
563 vp_reg_write(res, VP_SRC_H_POSITION,
564 VP_SRC_H_POSITION_VAL(src_x_offset));
565 vp_reg_write(res, VP_SRC_V_POSITION, src_y_offset);
567 vp_reg_write(res, VP_DST_WIDTH, width);
568 vp_reg_write(res, VP_DST_H_POSITION, dst_x_offset);
569 if (mctx->interlace) {
570 vp_reg_write(res, VP_DST_HEIGHT, height / 2);
571 vp_reg_write(res, VP_DST_V_POSITION, dst_y_offset / 2);
573 vp_reg_write(res, VP_DST_HEIGHT, height);
574 vp_reg_write(res, VP_DST_V_POSITION, dst_y_offset);
577 vp_reg_write(res, VP_H_RATIO, x_ratio);
578 vp_reg_write(res, VP_V_RATIO, y_ratio);
580 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
582 /* set buffer address to vp */
583 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
584 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
585 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
586 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
588 mixer_cfg_scan(mctx, mode_width, mode_height);
589 mixer_cfg_rgb_fmt(mctx, mode_height);
590 mixer_cfg_layer(mctx, win, true);
593 mixer_vsync_set_update(mctx, true);
594 spin_unlock_irqrestore(&res->reg_slock, flags);
599 static void mixer_graph_buffer(struct mixer_context *mctx, int win)
601 struct mixer_resources *res = &mctx->mixer_res;
603 struct hdmi_win_data *win_data;
604 unsigned int full_width, width, height;
605 unsigned int x_ratio, y_ratio;
606 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
607 unsigned int mode_width, mode_height;
612 win_data = &mctx->win_data[win];
619 switch (win_data->bpp) {
630 dma_addr = win_data->dma_addr;
631 full_width = win_data->fb_width;
632 width = win_data->crtc_width;
633 height = win_data->crtc_height;
634 mode_width = win_data->mode_width;
635 mode_height = win_data->mode_height;
637 /* 2x scaling feature */
641 src_x_offset = win_data->fb_x;
642 src_y_offset = win_data->fb_y;
643 dst_x_offset = win_data->crtc_x;
644 dst_y_offset = win_data->crtc_y;
646 /* converting dma address base and source offset */
648 + (src_x_offset * win_data->bpp >> 3)
649 + (src_y_offset * full_width * win_data->bpp >> 3);
653 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE)
654 mctx->interlace = true;
656 mctx->interlace = false;
658 spin_lock_irqsave(&res->reg_slock, flags);
659 mixer_vsync_set_update(mctx, false);
661 mctx->enabled[win] = true;
664 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
665 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
668 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), full_width);
670 val = MXR_GRP_WH_WIDTH(width);
671 val |= MXR_GRP_WH_HEIGHT(height);
672 val |= MXR_GRP_WH_H_SCALE(x_ratio);
673 val |= MXR_GRP_WH_V_SCALE(y_ratio);
674 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
676 /* setup offsets in source image */
677 val = MXR_GRP_SXY_SX(src_x_offset);
678 val |= MXR_GRP_SXY_SY(src_y_offset);
679 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
681 /* setup offsets in display image */
682 val = MXR_GRP_DXY_DX(dst_x_offset);
683 val |= MXR_GRP_DXY_DY(dst_y_offset);
684 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
686 /* set buffer address to mixer */
687 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
689 mixer_cfg_scan(mctx, mode_width, mode_height);
691 if (res->is_soc_exynos5) {
692 /* Workaround 4 implementation for 1440x900 resolution support */
693 if (mode_width == 1440 && mode_height == 900)
694 mixer_set_layer_offset(mctx, 224);
696 /* Workaround 3 implementation for 800x600 resolution support */
697 if (mode_width == 800 && mode_height == 600) {
698 mixer_set_layer_offset(mctx, 32);
699 mixer_toggle_3d_path(mctx);
701 mctx->is_800x600_initialized = false;
704 mixer_cfg_rgb_fmt(mctx, mode_height);
705 mixer_cfg_layer(mctx, win, true);
706 mixer_cfg_layer(mctx, MIXER_DEFAULT_WIN, true);
708 /* Only allow one update per vsync */
709 if (!win_data->updated)
710 mixer_layer_update(mctx);
712 win_data->updated = true;
715 mixer_vsync_set_update(mctx, true);
716 spin_unlock_irqrestore(&res->reg_slock, flags);
719 static void vp_win_reset(struct mixer_context *mctx)
721 struct mixer_resources *res = &mctx->mixer_res;
724 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
725 for (tries = 100; tries; --tries) {
726 /* waiting until VP_SRESET_PROCESSING is 0 */
727 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
731 WARN(tries == 0, "failed to reset Video Processor\n");
734 static int mixer_enable_vblank(void *ctx, int pipe)
736 struct mixer_context *mctx = ctx;
737 struct mixer_resources *res = &mctx->mixer_res;
739 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
742 * TODO (seanpaul): Right now, this is an expected code path since we
743 * call enable_vblank in the poweron routine; pipe might not be
744 * initialized the first time we run it. We should refactor things such
745 * that this isn't the case and we can either BUG_ON or DRM_ERROR here.
752 /* enable vsync interrupt */
753 mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
759 static void mixer_disable_vblank(void *ctx)
761 struct mixer_context *mctx = ctx;
762 struct mixer_resources *res = &mctx->mixer_res;
764 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
766 /* disable vsync interrupt */
767 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
770 static void mixer_win_mode_set(void *ctx,
771 struct exynos_drm_overlay *overlay)
773 struct mixer_context *mctx = ctx;
774 struct hdmi_win_data *win_data;
777 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
780 DRM_ERROR("overlay is NULL\n");
784 DRM_DEBUG_KMS("set [%d]x[%d] at (%d,%d) to [%d]x[%d] at (%d,%d)\n",
785 overlay->fb_width, overlay->fb_height,
786 overlay->fb_x, overlay->fb_y,
787 overlay->crtc_width, overlay->crtc_height,
788 overlay->crtc_x, overlay->crtc_y);
791 if (win == DEFAULT_ZPOS)
792 win = MIXER_DEFAULT_WIN;
794 if (win < 0 || win > MIXER_WIN_NR) {
795 DRM_ERROR("overlay plane[%d] is wrong\n", win);
799 win_data = &mctx->win_data[win];
801 win_data->dma_addr = overlay->dma_addr[0];
802 win_data->vaddr = overlay->vaddr[0];
803 win_data->chroma_dma_addr = overlay->dma_addr[1];
804 win_data->chroma_vaddr = overlay->vaddr[1];
805 win_data->pixel_format = overlay->pixel_format;
806 win_data->bpp = overlay->bpp;
808 win_data->crtc_x = overlay->crtc_x;
809 win_data->crtc_y = overlay->crtc_y;
810 win_data->crtc_width = overlay->crtc_width;
811 win_data->crtc_height = overlay->crtc_height;
813 win_data->fb_x = overlay->fb_x;
814 win_data->fb_y = overlay->fb_y;
815 win_data->fb_width = overlay->fb_pitch / (overlay->bpp >> 3);
816 win_data->fb_height = overlay->fb_height;
818 win_data->mode_width = overlay->mode_width;
819 win_data->mode_height = overlay->mode_height;
821 win_data->scan_flags = overlay->scan_flag;
824 static void mixer_win_commit(void *ctx, int zpos)
826 struct mixer_context *mctx = ctx;
827 struct mixer_resources *res = &mctx->mixer_res;
830 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
831 if (win == DEFAULT_ZPOS)
832 win = MIXER_DEFAULT_WIN;
834 if (win < 0 || win > MIXER_WIN_NR) {
835 DRM_ERROR("overlay plane[%d] is wrong\n", win);
839 if (!mctx->is_mixer_powered_on) {
840 DRM_DEBUG_KMS("[%d] %s not powered on\n", __LINE__, __func__);
844 if (!(res->is_soc_exynos5)) {
846 vp_video_buffer(mctx, win);
848 mixer_graph_buffer(mctx, win);
851 mixer_graph_buffer(mctx, win);
854 static void mixer_apply(void *ctx)
856 struct mixer_context *mctx = ctx;
859 for (i = 0; i < MIXER_WIN_NR; i++) {
860 if (!mctx->enabled[i])
863 mixer_win_commit(ctx, i);
867 static void mixer_win_disable(void *ctx, int zpos)
869 struct mixer_context *mctx = ctx;
870 struct mixer_resources *res = &mctx->mixer_res;
874 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
876 if (win == DEFAULT_ZPOS)
877 win = MIXER_DEFAULT_WIN;
879 if (win < 0 || win > MIXER_WIN_NR) {
880 DRM_ERROR("overlay plane[%d] is wrong\n", win);
884 mixer_wait_for_vsync(mctx);
886 spin_lock_irqsave(&res->reg_slock, flags);
887 mixer_vsync_set_update(mctx, false);
889 mctx->enabled[win] = false;
890 mixer_cfg_layer(mctx, win, false);
892 mixer_vsync_set_update(mctx, true);
894 spin_unlock_irqrestore(&res->reg_slock, flags);
896 if (win == MIXER_DEFAULT_WIN) {
897 mixer_win_reset(mctx);
898 mixer_enable_vblank(mctx, mctx->pipe);
902 /* for pageflip event */
903 static irqreturn_t mixer_irq_handler(int irq, void *arg)
905 struct mixer_context *mctx = arg;
906 struct mixer_resources *res = &mctx->mixer_res;
907 u32 val, base, shadow;
910 spin_lock(&res->reg_slock);
912 /* read interrupt status for handling and clearing flags for VSYNC */
913 val = mixer_reg_read(res, MXR_INT_STATUS);
916 if (val & MXR_INT_STATUS_VSYNC) {
917 /* interlace scan need to check shadow register */
918 if (mctx->interlace && !res->is_soc_exynos5) {
919 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
920 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
924 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
925 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
930 drm_handle_vblank(mctx->drm_dev, mctx->pipe);
932 /* Bail out if a layer update is pending */
933 if (mixer_get_layer_update_count(mctx))
936 for (i = 0; i < MIXER_WIN_NR; i++)
937 mctx->win_data[i].updated = false;
939 exynos_drm_crtc_finish_pageflip(mctx->drm_dev, mctx->pipe);
941 if (mctx->event_flags & MXR_EVENT_VSYNC) {
942 DRM_DEBUG_KMS("mctx->event_flags & MXR_EVENT_VSYNC");
944 mctx->event_flags &= ~MXR_EVENT_VSYNC;
945 wake_up(&mctx->mixer_res.event_queue);
950 /* clear interrupts */
951 if (~val & MXR_INT_EN_VSYNC) {
952 /* vsync interrupt use different bit for read and clear */
953 val &= ~MXR_INT_EN_VSYNC;
954 val |= MXR_INT_CLEAR_VSYNC;
956 mixer_reg_write(res, MXR_INT_STATUS, val);
958 spin_unlock(&res->reg_slock);
963 static void mixer_win_reset(struct mixer_context *mctx)
965 struct mixer_resources *res = &mctx->mixer_res;
967 u32 val; /* value stored to register */
969 spin_lock_irqsave(&res->reg_slock, flags);
970 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
971 mixer_vsync_set_update(mctx, false);
973 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
975 /* set output in RGB888 mode */
976 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
978 /* 16 beat burst in DMA */
979 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
980 MXR_STATUS_BURST_MASK);
982 /* setting default layer priority: layer1 > layer0 > video
983 * because typical usage scenario would be
985 * layer0 - framebuffer
986 * video - video overlay
988 val = MXR_LAYER_CFG_GRP1_VAL(3);
989 val |= MXR_LAYER_CFG_GRP0_VAL(2);
990 val |= MXR_LAYER_CFG_VP_VAL(1);
991 mixer_reg_write(res, MXR_LAYER_CFG, val);
993 /* setting background color */
994 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
995 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
996 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
998 /* setting graphical layers */
1000 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
1001 val |= MXR_GRP_CFG_WIN_BLEND_EN;
1002 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
1004 /* the same configuration for both layers */
1005 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
1007 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
1008 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
1009 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
1011 if (!(res->is_soc_exynos5)) {
1012 /* configuration of Video Processor for Exynos4 soc */
1014 vp_default_filter(res);
1017 /* disable all layers */
1018 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
1019 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
1020 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
1022 mixer_vsync_set_update(mctx, true);
1023 spin_unlock_irqrestore(&res->reg_slock, flags);
1026 static void mixer_resource_poweron(struct mixer_context *mctx)
1028 struct mixer_resources *res = &mctx->mixer_res;
1030 if (mctx->is_mixer_powered_on)
1033 clk_enable(res->mixer);
1034 if (!(res->is_soc_exynos5)) {
1035 clk_enable(res->vp);
1036 clk_enable(res->sclk_mixer);
1039 mixer_win_reset(mctx);
1040 mixer_enable_vblank(mctx, mctx->pipe);
1042 mctx->is_mixer_powered_on = true;
1043 mixer_win_commit(mctx, 0);
1046 static void mixer_resource_poweroff(struct mixer_context *mctx)
1048 struct mixer_resources *res = &mctx->mixer_res;
1050 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
1051 if (!mctx->is_mixer_powered_on)
1054 clk_disable(res->mixer);
1055 if (!(res->is_soc_exynos5)) {
1056 clk_disable(res->vp);
1057 clk_disable(res->sclk_mixer);
1059 mctx->is_mixer_powered_on = false;
1062 static int mixer_power(void *ctx, int mode)
1064 struct mixer_context *mctx = ctx;
1066 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
1069 case DRM_MODE_DPMS_ON:
1070 mixer_resource_poweron(mctx);
1072 case DRM_MODE_DPMS_STANDBY:
1073 case DRM_MODE_DPMS_SUSPEND:
1074 case DRM_MODE_DPMS_OFF:
1075 mixer_resource_poweroff(mctx);
1078 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
1085 static int mixer_subdrv_probe(void *ctx, struct drm_device *drm_dev)
1087 struct mixer_context *mctx = ctx;
1089 mctx->drm_dev = drm_dev;
1094 static struct exynos_controller_ops mixer_ops = {
1096 .subdrv_probe = mixer_subdrv_probe,
1097 .enable_vblank = mixer_enable_vblank,
1098 .disable_vblank = mixer_disable_vblank,
1099 .power = mixer_power,
1102 .mode_set = mixer_win_mode_set,
1103 .apply = mixer_apply,
1104 .win_commit = mixer_win_commit,
1105 .win_disable = mixer_win_disable,
1108 #ifdef CONFIG_EXYNOS_IOMMU
1109 static int iommu_init(struct platform_device *pdev)
1111 struct platform_device *pds;
1113 pds = find_sysmmu_dt(pdev, "sysmmu");
1115 printk(KERN_ERR "No sysmmu found :\n");
1119 platform_set_sysmmu(&pds->dev, &pdev->dev);
1121 * The ordering in Makefile warrants that this is initialized after
1122 * FIMD, so only just ensure that it works as expected and we are
1123 * reusing the mapping originally created in exynos_drm_fimd.c.
1125 WARN_ON(!exynos_drm_common_mapping);
1126 exynos_drm_common_mapping = s5p_create_iommu_mapping(&pdev->dev,
1127 0, 0, 0, exynos_drm_common_mapping);
1128 if(exynos_drm_common_mapping == NULL) {
1129 printk(KERN_ERR"Failed to create iommu mapping for Mixer\n");
1137 static int __devinit mixer_resources_init_exynos(
1138 struct mixer_context *mctx,
1139 struct platform_device *pdev,
1142 struct device *dev = &pdev->dev;
1143 struct mixer_resources *mixer_res = &mctx->mixer_res;
1144 struct resource *res;
1147 DRM_DEBUG_KMS("Mixer resources init\n");
1149 mixer_res->is_soc_exynos5 = is_exynos5;
1150 mixer_res->dev = dev;
1151 spin_lock_init(&mixer_res->reg_slock);
1154 init_waitqueue_head(&mixer_res->event_queue);
1156 mixer_res->mixer = clk_get(dev, "mixer");
1157 if (IS_ERR_OR_NULL(mixer_res->mixer)) {
1158 dev_err(dev, "failed to get clock 'mixer'\n");
1163 mixer_res->vp = clk_get(dev, "vp");
1164 if (IS_ERR_OR_NULL(mixer_res->vp)) {
1165 dev_err(dev, "failed to get clock 'vp'\n");
1169 mixer_res->sclk_mixer = clk_get(dev, "sclk_mixer");
1170 if (IS_ERR_OR_NULL(mixer_res->sclk_mixer)) {
1171 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
1176 mixer_res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
1177 if (IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) {
1178 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
1183 mixer_res->sclk_dac = clk_get(dev, "sclk_dac");
1184 if (IS_ERR_OR_NULL(mixer_res->sclk_dac)) {
1185 dev_err(dev, "failed to get clock 'sclk_dac'\n");
1189 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr");
1192 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1195 dev_err(dev, "get memory resource failed.\n");
1201 clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
1203 mixer_res->mixer_regs = ioremap(res->start, resource_size(res));
1204 if (mixer_res->mixer_regs == NULL) {
1205 dev_err(dev, "register mapping failed.\n");
1211 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp");
1213 dev_err(dev, "get memory resource failed.\n");
1218 mixer_res->vp_regs = ioremap(res->start, resource_size(res));
1219 if (mixer_res->vp_regs == NULL) {
1220 dev_err(dev, "register mapping failed.\n");
1225 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq");
1227 dev_err(dev, "get interrupt resource failed.\n");
1232 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
1234 dev_err(dev, "get interrupt resource failed.\n");
1236 goto fail_mixer_regs;
1240 ret = request_irq(res->start, mixer_irq_handler, 0, "drm_mixer", mctx);
1242 dev_err(dev, "request interrupt failed.\n");
1243 goto fail_mixer_regs;
1245 mixer_res->irq = res->start;
1247 #ifdef CONFIG_EXYNOS_IOMMU
1248 ret = iommu_init(pdev);
1250 dev_err(dev, "iommu init failed.\n");
1251 goto fail_mixer_regs;
1257 iounmap(mixer_res->vp_regs);
1260 iounmap(mixer_res->mixer_regs);
1263 if (!IS_ERR_OR_NULL(mixer_res->sclk_dac))
1264 clk_put(mixer_res->sclk_dac);
1265 if (!IS_ERR_OR_NULL(mixer_res->sclk_hdmi))
1266 clk_put(mixer_res->sclk_hdmi);
1267 if (!IS_ERR_OR_NULL(mixer_res->sclk_mixer))
1268 clk_put(mixer_res->sclk_mixer);
1269 if (!IS_ERR_OR_NULL(mixer_res->vp))
1270 clk_put(mixer_res->vp);
1271 if (!IS_ERR_OR_NULL(mixer_res->mixer))
1272 clk_put(mixer_res->mixer);
1273 mixer_res->dev = NULL;
1277 static void mixer_resources_cleanup(struct device *dev,
1278 struct mixer_context *mctx)
1280 struct mixer_resources *res = &mctx->mixer_res;
1282 disable_irq(res->irq);
1283 free_irq(res->irq, dev);
1285 iounmap(res->vp_regs);
1286 iounmap(res->mixer_regs);
1289 static int __devinit mixer_probe(struct platform_device *pdev)
1291 struct device *dev = &pdev->dev;
1292 struct exynos_drm_hdmi_pdata *pdata;
1293 struct mixer_context *mctx;
1296 dev_info(dev, "probe start\n");
1298 mctx = kzalloc(sizeof(*mctx), GFP_KERNEL);
1300 DRM_ERROR("failed to alloc mixer context.\n");
1304 mctx->dev = &pdev->dev;
1307 platform_set_drvdata(pdev, mctx);
1309 /* Get from Platform soc deatils */
1310 pdata = pdev->dev.platform_data;
1312 /* acquire resources: regs, irqs, clocks */
1313 ret = mixer_resources_init_exynos(mctx, pdev, pdata->is_soc_exynos5);
1317 mctx->is_mixer_powered_on = false;
1318 pm_runtime_enable(dev);
1320 exynos_display_attach_controller(EXYNOS_DRM_DISPLAY_TYPE_MIXER,
1327 dev_info(dev, "probe failed\n");
1331 static int mixer_remove(struct platform_device *pdev)
1333 struct device *dev = &pdev->dev;
1334 struct mixer_context *mctx = platform_get_drvdata(pdev);
1336 dev_info(dev, "remove successful\n");
1338 mixer_resource_poweroff(mctx);
1339 mixer_resources_cleanup(dev, mctx);
1346 struct platform_driver mixer_driver = {
1348 .name = "s5p-mixer",
1349 .owner = THIS_MODULE,
1351 .probe = mixer_probe,
1352 .remove = __devexit_p(mixer_remove),