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_drm_iommu.h"
41 #define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev))
43 struct hdmi_win_data {
46 dma_addr_t chroma_dma_addr;
47 void __iomem *chroma_vaddr;
48 uint32_t pixel_format;
52 unsigned int crtc_width;
53 unsigned int crtc_height;
56 unsigned int fb_width;
57 unsigned int fb_height;
58 unsigned int src_width;
59 unsigned int src_height;
60 unsigned int mode_width;
61 unsigned int mode_height;
62 unsigned int scan_flags;
65 struct mixer_resources {
67 void __iomem *mixer_regs;
68 void __iomem *vp_regs;
72 struct clk *sclk_mixer;
73 struct clk *sclk_hdmi;
77 enum mixer_version_id {
82 struct mixer_context {
84 struct drm_device *drm_dev;
91 struct mutex mixer_mutex;
92 struct mixer_resources mixer_res;
93 struct hdmi_win_data win_data[MIXER_WIN_NR];
94 enum mixer_version_id mxr_ver;
98 struct mixer_drv_data {
99 enum mixer_version_id version;
103 static const u8 filter_y_horiz_tap8[] = {
104 0, -1, -1, -1, -1, -1, -1, -1,
105 -1, -1, -1, -1, -1, 0, 0, 0,
106 0, 2, 4, 5, 6, 6, 6, 6,
107 6, 5, 5, 4, 3, 2, 1, 1,
108 0, -6, -12, -16, -18, -20, -21, -20,
109 -20, -18, -16, -13, -10, -8, -5, -2,
110 127, 126, 125, 121, 114, 107, 99, 89,
111 79, 68, 57, 46, 35, 25, 16, 8,
114 static const u8 filter_y_vert_tap4[] = {
115 0, -3, -6, -8, -8, -8, -8, -7,
116 -6, -5, -4, -3, -2, -1, -1, 0,
117 127, 126, 124, 118, 111, 102, 92, 81,
118 70, 59, 48, 37, 27, 19, 11, 5,
119 0, 5, 11, 19, 27, 37, 48, 59,
120 70, 81, 92, 102, 111, 118, 124, 126,
121 0, 0, -1, -1, -2, -3, -4, -5,
122 -6, -7, -8, -8, -8, -8, -6, -3,
125 static const u8 filter_cr_horiz_tap4[] = {
126 0, -3, -6, -8, -8, -8, -8, -7,
127 -6, -5, -4, -3, -2, -1, -1, 0,
128 127, 126, 124, 118, 111, 102, 92, 81,
129 70, 59, 48, 37, 27, 19, 11, 5,
132 static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
134 return readl(res->vp_regs + reg_id);
137 static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
140 writel(val, res->vp_regs + reg_id);
143 static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
146 u32 old = vp_reg_read(res, reg_id);
148 val = (val & mask) | (old & ~mask);
149 writel(val, res->vp_regs + reg_id);
152 static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
154 return readl(res->mixer_regs + reg_id);
157 static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
160 writel(val, res->mixer_regs + reg_id);
163 static inline void mixer_reg_writemask(struct mixer_resources *res,
164 u32 reg_id, u32 val, u32 mask)
166 u32 old = mixer_reg_read(res, reg_id);
168 val = (val & mask) | (old & ~mask);
169 writel(val, res->mixer_regs + reg_id);
172 static void mixer_regs_dump(struct mixer_context *ctx)
174 #define DUMPREG(reg_id) \
176 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
177 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
183 DUMPREG(MXR_INT_STATUS);
185 DUMPREG(MXR_LAYER_CFG);
186 DUMPREG(MXR_VIDEO_CFG);
188 DUMPREG(MXR_GRAPHIC0_CFG);
189 DUMPREG(MXR_GRAPHIC0_BASE);
190 DUMPREG(MXR_GRAPHIC0_SPAN);
191 DUMPREG(MXR_GRAPHIC0_WH);
192 DUMPREG(MXR_GRAPHIC0_SXY);
193 DUMPREG(MXR_GRAPHIC0_DXY);
195 DUMPREG(MXR_GRAPHIC1_CFG);
196 DUMPREG(MXR_GRAPHIC1_BASE);
197 DUMPREG(MXR_GRAPHIC1_SPAN);
198 DUMPREG(MXR_GRAPHIC1_WH);
199 DUMPREG(MXR_GRAPHIC1_SXY);
200 DUMPREG(MXR_GRAPHIC1_DXY);
204 static void vp_regs_dump(struct mixer_context *ctx)
206 #define DUMPREG(reg_id) \
208 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
209 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
214 DUMPREG(VP_SHADOW_UPDATE);
215 DUMPREG(VP_FIELD_ID);
217 DUMPREG(VP_IMG_SIZE_Y);
218 DUMPREG(VP_IMG_SIZE_C);
219 DUMPREG(VP_PER_RATE_CTRL);
220 DUMPREG(VP_TOP_Y_PTR);
221 DUMPREG(VP_BOT_Y_PTR);
222 DUMPREG(VP_TOP_C_PTR);
223 DUMPREG(VP_BOT_C_PTR);
224 DUMPREG(VP_ENDIAN_MODE);
225 DUMPREG(VP_SRC_H_POSITION);
226 DUMPREG(VP_SRC_V_POSITION);
227 DUMPREG(VP_SRC_WIDTH);
228 DUMPREG(VP_SRC_HEIGHT);
229 DUMPREG(VP_DST_H_POSITION);
230 DUMPREG(VP_DST_V_POSITION);
231 DUMPREG(VP_DST_WIDTH);
232 DUMPREG(VP_DST_HEIGHT);
239 static inline void vp_filter_set(struct mixer_resources *res,
240 int reg_id, const u8 *data, unsigned int size)
242 /* assure 4-byte align */
244 for (; size; size -= 4, reg_id += 4, data += 4) {
245 u32 val = (data[0] << 24) | (data[1] << 16) |
246 (data[2] << 8) | data[3];
247 vp_reg_write(res, reg_id, val);
251 static void vp_default_filter(struct mixer_resources *res)
253 vp_filter_set(res, VP_POLY8_Y0_LL,
254 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
255 vp_filter_set(res, VP_POLY4_Y0_LL,
256 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
257 vp_filter_set(res, VP_POLY4_C0_LL,
258 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
261 static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
263 struct mixer_resources *res = &ctx->mixer_res;
265 /* block update on vsync */
266 mixer_reg_writemask(res, MXR_STATUS, enable ?
267 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
270 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
271 VP_SHADOW_UPDATE_ENABLE : 0);
274 static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
276 struct mixer_resources *res = &ctx->mixer_res;
279 /* choosing between interlace and progressive mode */
280 val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
281 MXR_CFG_SCAN_PROGRASSIVE);
283 /* choosing between porper HD and SD mode */
285 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
286 else if (height == 576)
287 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
288 else if (height == 720)
289 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
290 else if (height == 1080)
291 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
293 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
295 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
298 static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
300 struct mixer_resources *res = &ctx->mixer_res;
304 val = MXR_CFG_RGB601_0_255;
305 } else if (height == 576) {
306 val = MXR_CFG_RGB601_0_255;
307 } else if (height == 720) {
308 val = MXR_CFG_RGB709_16_235;
309 mixer_reg_write(res, MXR_CM_COEFF_Y,
310 (1 << 30) | (94 << 20) | (314 << 10) |
312 mixer_reg_write(res, MXR_CM_COEFF_CB,
313 (972 << 20) | (851 << 10) | (225 << 0));
314 mixer_reg_write(res, MXR_CM_COEFF_CR,
315 (225 << 20) | (820 << 10) | (1004 << 0));
316 } else if (height == 1080) {
317 val = MXR_CFG_RGB709_16_235;
318 mixer_reg_write(res, MXR_CM_COEFF_Y,
319 (1 << 30) | (94 << 20) | (314 << 10) |
321 mixer_reg_write(res, MXR_CM_COEFF_CB,
322 (972 << 20) | (851 << 10) | (225 << 0));
323 mixer_reg_write(res, MXR_CM_COEFF_CR,
324 (225 << 20) | (820 << 10) | (1004 << 0));
326 val = MXR_CFG_RGB709_16_235;
327 mixer_reg_write(res, MXR_CM_COEFF_Y,
328 (1 << 30) | (94 << 20) | (314 << 10) |
330 mixer_reg_write(res, MXR_CM_COEFF_CB,
331 (972 << 20) | (851 << 10) | (225 << 0));
332 mixer_reg_write(res, MXR_CM_COEFF_CR,
333 (225 << 20) | (820 << 10) | (1004 << 0));
336 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
339 static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable)
341 struct mixer_resources *res = &ctx->mixer_res;
342 u32 val = enable ? ~0 : 0;
346 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
349 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
352 if (ctx->vp_enabled) {
353 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
354 mixer_reg_writemask(res, MXR_CFG, val,
361 static void mixer_run(struct mixer_context *ctx)
363 struct mixer_resources *res = &ctx->mixer_res;
365 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
367 mixer_regs_dump(ctx);
370 static void vp_video_buffer(struct mixer_context *ctx, int win)
372 struct mixer_resources *res = &ctx->mixer_res;
374 struct hdmi_win_data *win_data;
375 unsigned int x_ratio, y_ratio;
376 unsigned int buf_num;
377 dma_addr_t luma_addr[2], chroma_addr[2];
378 bool tiled_mode = false;
379 bool crcb_mode = false;
382 win_data = &ctx->win_data[win];
384 switch (win_data->pixel_format) {
385 case DRM_FORMAT_NV12MT:
387 case DRM_FORMAT_NV12:
391 /* TODO: single buffer format NV12, NV21 */
393 /* ignore pixel format at disable time */
394 if (!win_data->dma_addr)
397 DRM_ERROR("pixel format for vp is wrong [%d].\n",
398 win_data->pixel_format);
402 /* scaling feature: (src << 16) / dst */
403 x_ratio = (win_data->src_width << 16) / win_data->crtc_width;
404 y_ratio = (win_data->src_height << 16) / win_data->crtc_height;
407 luma_addr[0] = win_data->dma_addr;
408 chroma_addr[0] = win_data->chroma_dma_addr;
410 luma_addr[0] = win_data->dma_addr;
411 chroma_addr[0] = win_data->dma_addr
412 + (win_data->fb_width * win_data->fb_height);
415 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) {
416 ctx->interlace = true;
418 luma_addr[1] = luma_addr[0] + 0x40;
419 chroma_addr[1] = chroma_addr[0] + 0x40;
421 luma_addr[1] = luma_addr[0] + win_data->fb_width;
422 chroma_addr[1] = chroma_addr[0] + win_data->fb_width;
425 ctx->interlace = false;
430 spin_lock_irqsave(&res->reg_slock, flags);
431 mixer_vsync_set_update(ctx, false);
433 /* interlace or progressive scan mode */
434 val = (ctx->interlace ? ~0 : 0);
435 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
438 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
439 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
440 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
442 /* setting size of input image */
443 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_width) |
444 VP_IMG_VSIZE(win_data->fb_height));
445 /* chroma height has to reduced by 2 to avoid chroma distorions */
446 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(win_data->fb_width) |
447 VP_IMG_VSIZE(win_data->fb_height / 2));
449 vp_reg_write(res, VP_SRC_WIDTH, win_data->src_width);
450 vp_reg_write(res, VP_SRC_HEIGHT, win_data->src_height);
451 vp_reg_write(res, VP_SRC_H_POSITION,
452 VP_SRC_H_POSITION_VAL(win_data->fb_x));
453 vp_reg_write(res, VP_SRC_V_POSITION, win_data->fb_y);
455 vp_reg_write(res, VP_DST_WIDTH, win_data->crtc_width);
456 vp_reg_write(res, VP_DST_H_POSITION, win_data->crtc_x);
457 if (ctx->interlace) {
458 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height / 2);
459 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y / 2);
461 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height);
462 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y);
465 vp_reg_write(res, VP_H_RATIO, x_ratio);
466 vp_reg_write(res, VP_V_RATIO, y_ratio);
468 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
470 /* set buffer address to vp */
471 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
472 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
473 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
474 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
476 mixer_cfg_scan(ctx, win_data->mode_height);
477 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
478 mixer_cfg_layer(ctx, win, true);
481 mixer_vsync_set_update(ctx, true);
482 spin_unlock_irqrestore(&res->reg_slock, flags);
487 static void mixer_layer_update(struct mixer_context *ctx)
489 struct mixer_resources *res = &ctx->mixer_res;
492 val = mixer_reg_read(res, MXR_CFG);
494 /* allow one update per vsync only */
495 if (!(val & MXR_CFG_LAYER_UPDATE_COUNT_MASK))
496 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
499 static void mixer_graph_buffer(struct mixer_context *ctx, int win)
501 struct mixer_resources *res = &ctx->mixer_res;
503 struct hdmi_win_data *win_data;
504 unsigned int x_ratio, y_ratio;
505 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
510 win_data = &ctx->win_data[win];
517 switch (win_data->bpp) {
528 /* 2x scaling feature */
532 dst_x_offset = win_data->crtc_x;
533 dst_y_offset = win_data->crtc_y;
535 /* converting dma address base and source offset */
536 dma_addr = win_data->dma_addr
537 + (win_data->fb_x * win_data->bpp >> 3)
538 + (win_data->fb_y * win_data->fb_width * win_data->bpp >> 3);
542 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE)
543 ctx->interlace = true;
545 ctx->interlace = false;
547 spin_lock_irqsave(&res->reg_slock, flags);
548 mixer_vsync_set_update(ctx, false);
551 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
552 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
555 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), win_data->fb_width);
557 val = MXR_GRP_WH_WIDTH(win_data->crtc_width);
558 val |= MXR_GRP_WH_HEIGHT(win_data->crtc_height);
559 val |= MXR_GRP_WH_H_SCALE(x_ratio);
560 val |= MXR_GRP_WH_V_SCALE(y_ratio);
561 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
563 /* setup offsets in source image */
564 val = MXR_GRP_SXY_SX(src_x_offset);
565 val |= MXR_GRP_SXY_SY(src_y_offset);
566 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
568 /* setup offsets in display image */
569 val = MXR_GRP_DXY_DX(dst_x_offset);
570 val |= MXR_GRP_DXY_DY(dst_y_offset);
571 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
573 /* set buffer address to mixer */
574 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
576 mixer_cfg_scan(ctx, win_data->mode_height);
577 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
578 mixer_cfg_layer(ctx, win, true);
580 /* layer update mandatory for mixer 16.0.33.0 */
581 if (ctx->mxr_ver == MXR_VER_16_0_33_0)
582 mixer_layer_update(ctx);
586 mixer_vsync_set_update(ctx, true);
587 spin_unlock_irqrestore(&res->reg_slock, flags);
590 static void vp_win_reset(struct mixer_context *ctx)
592 struct mixer_resources *res = &ctx->mixer_res;
595 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
596 for (tries = 100; tries; --tries) {
597 /* waiting until VP_SRESET_PROCESSING is 0 */
598 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
602 WARN(tries == 0, "failed to reset Video Processor\n");
605 static void mixer_win_reset(struct mixer_context *ctx)
607 struct mixer_resources *res = &ctx->mixer_res;
609 u32 val; /* value stored to register */
611 spin_lock_irqsave(&res->reg_slock, flags);
612 mixer_vsync_set_update(ctx, false);
614 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
616 /* set output in RGB888 mode */
617 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
619 /* 16 beat burst in DMA */
620 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
621 MXR_STATUS_BURST_MASK);
623 /* setting default layer priority: layer1 > layer0 > video
624 * because typical usage scenario would be
626 * layer0 - framebuffer
627 * video - video overlay
629 val = MXR_LAYER_CFG_GRP1_VAL(3);
630 val |= MXR_LAYER_CFG_GRP0_VAL(2);
632 val |= MXR_LAYER_CFG_VP_VAL(1);
633 mixer_reg_write(res, MXR_LAYER_CFG, val);
635 /* setting background color */
636 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
637 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
638 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
640 /* setting graphical layers */
641 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
642 val |= MXR_GRP_CFG_WIN_BLEND_EN;
643 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
644 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
645 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
647 /* the same configuration for both layers */
648 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
649 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
651 /* setting video layers */
652 val = MXR_GRP_CFG_ALPHA_VAL(0);
653 mixer_reg_write(res, MXR_VIDEO_CFG, val);
655 if (ctx->vp_enabled) {
656 /* configuration of Video Processor Registers */
658 vp_default_filter(res);
661 /* disable all layers */
662 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
663 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
665 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
667 mixer_vsync_set_update(ctx, true);
668 spin_unlock_irqrestore(&res->reg_slock, flags);
671 static int mixer_iommu_on(void *ctx, bool enable)
673 struct exynos_drm_hdmi_context *drm_hdmi_ctx;
674 struct mixer_context *mdata = ctx;
675 struct drm_device *drm_dev;
677 drm_hdmi_ctx = mdata->parent_ctx;
678 drm_dev = drm_hdmi_ctx->drm_dev;
680 if (is_drm_iommu_supported(drm_dev)) {
682 return drm_iommu_attach_device(drm_dev, mdata->dev);
684 drm_iommu_detach_device(drm_dev, mdata->dev);
689 static void mixer_poweron(struct mixer_context *ctx)
691 struct mixer_resources *res = &ctx->mixer_res;
693 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
695 mutex_lock(&ctx->mixer_mutex);
697 mutex_unlock(&ctx->mixer_mutex);
701 mutex_unlock(&ctx->mixer_mutex);
703 pm_runtime_get_sync(ctx->dev);
705 clk_enable(res->mixer);
706 if (ctx->vp_enabled) {
708 clk_enable(res->sclk_mixer);
711 mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
712 mixer_win_reset(ctx);
715 static void mixer_poweroff(struct mixer_context *ctx)
717 struct mixer_resources *res = &ctx->mixer_res;
719 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
721 mutex_lock(&ctx->mixer_mutex);
724 mutex_unlock(&ctx->mixer_mutex);
726 ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
728 clk_disable(res->mixer);
729 if (ctx->vp_enabled) {
730 clk_disable(res->vp);
731 clk_disable(res->sclk_mixer);
734 pm_runtime_put_sync(ctx->dev);
736 mutex_lock(&ctx->mixer_mutex);
737 ctx->powered = false;
740 mutex_unlock(&ctx->mixer_mutex);
743 static int mixer_enable_vblank(void *ctx, int pipe)
745 struct mixer_context *mixer_ctx = ctx;
746 struct mixer_resources *res = &mixer_ctx->mixer_res;
748 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
750 mixer_ctx->pipe = pipe;
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 *mixer_ctx = ctx;
762 struct mixer_resources *res = &mixer_ctx->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_dpms(void *ctx, int mode)
772 struct mixer_context *mixer_ctx = ctx;
774 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
777 case DRM_MODE_DPMS_ON:
778 mixer_poweron(mixer_ctx);
780 case DRM_MODE_DPMS_STANDBY:
781 case DRM_MODE_DPMS_SUSPEND:
782 case DRM_MODE_DPMS_OFF:
783 mixer_poweroff(mixer_ctx);
786 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
791 static void mixer_wait_for_vblank(void *ctx)
793 struct mixer_context *mixer_ctx = ctx;
794 struct mixer_resources *res = &mixer_ctx->mixer_res;
797 ret = wait_for((mixer_reg_read(res, MXR_INT_STATUS) &
798 MXR_INT_STATUS_VSYNC), 50);
800 DRM_DEBUG_KMS("vblank wait timed out.\n");
803 static void mixer_win_mode_set(void *ctx,
804 struct exynos_drm_overlay *overlay)
806 struct mixer_context *mixer_ctx = ctx;
807 struct hdmi_win_data *win_data;
810 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
813 DRM_ERROR("overlay is NULL\n");
817 DRM_DEBUG_KMS("set [%d]x[%d] at (%d,%d) to [%d]x[%d] at (%d,%d)\n",
818 overlay->fb_width, overlay->fb_height,
819 overlay->fb_x, overlay->fb_y,
820 overlay->crtc_width, overlay->crtc_height,
821 overlay->crtc_x, overlay->crtc_y);
824 if (win == DEFAULT_ZPOS)
825 win = MIXER_DEFAULT_WIN;
827 if (win < 0 || win > MIXER_WIN_NR) {
828 DRM_ERROR("mixer window[%d] is wrong\n", win);
832 win_data = &mixer_ctx->win_data[win];
834 win_data->dma_addr = overlay->dma_addr[0];
835 win_data->vaddr = overlay->vaddr[0];
836 win_data->chroma_dma_addr = overlay->dma_addr[1];
837 win_data->chroma_vaddr = overlay->vaddr[1];
838 win_data->pixel_format = overlay->pixel_format;
839 win_data->bpp = overlay->bpp;
841 win_data->crtc_x = overlay->crtc_x;
842 win_data->crtc_y = overlay->crtc_y;
843 win_data->crtc_width = overlay->crtc_width;
844 win_data->crtc_height = overlay->crtc_height;
846 win_data->fb_x = overlay->fb_x;
847 win_data->fb_y = overlay->fb_y;
848 win_data->fb_width = overlay->fb_width;
849 win_data->fb_height = overlay->fb_height;
850 win_data->src_width = overlay->src_width;
851 win_data->src_height = overlay->src_height;
853 win_data->mode_width = overlay->mode_width;
854 win_data->mode_height = overlay->mode_height;
856 win_data->scan_flags = overlay->scan_flag;
859 static void mixer_win_commit(void *ctx, int win)
861 struct mixer_context *mixer_ctx = ctx;
863 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
865 if (win > 1 && mixer_ctx->vp_enabled)
866 vp_video_buffer(mixer_ctx, win);
868 mixer_graph_buffer(mixer_ctx, win);
871 static void mixer_win_disable(void *ctx, int win)
873 struct mixer_context *mixer_ctx = ctx;
874 struct mixer_resources *res = &mixer_ctx->mixer_res;
877 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
879 spin_lock_irqsave(&res->reg_slock, flags);
880 mixer_vsync_set_update(mixer_ctx, false);
882 mixer_cfg_layer(mixer_ctx, win, false);
884 mixer_vsync_set_update(mixer_ctx, true);
885 spin_unlock_irqrestore(&res->reg_slock, flags);
888 static struct exynos_mixer_ops mixer_ops = {
890 .iommu_on = mixer_iommu_on,
891 .enable_vblank = mixer_enable_vblank,
892 .disable_vblank = mixer_disable_vblank,
896 .wait_for_vblank = mixer_wait_for_vblank,
897 .win_mode_set = mixer_win_mode_set,
898 .win_commit = mixer_win_commit,
899 .win_disable = mixer_win_disable,
902 /* for pageflip event */
903 static void mixer_finish_pageflip(struct drm_device *drm_dev, int crtc)
905 struct exynos_drm_private *dev_priv = drm_dev->dev_private;
906 struct drm_pending_vblank_event *e, *t;
910 spin_lock_irqsave(&drm_dev->event_lock, flags);
912 list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
914 /* if event's pipe isn't same as crtc then ignore it. */
918 do_gettimeofday(&now);
919 e->event.sequence = 0;
920 e->event.tv_sec = now.tv_sec;
921 e->event.tv_usec = now.tv_usec;
923 list_move_tail(&e->base.link, &e->base.file_priv->event_list);
924 wake_up_interruptible(&e->base.file_priv->event_wait);
925 drm_vblank_put(drm_dev, crtc);
928 spin_unlock_irqrestore(&drm_dev->event_lock, flags);
931 static irqreturn_t mixer_irq_handler(int irq, void *arg)
933 struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg;
934 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
935 struct mixer_resources *res = &ctx->mixer_res;
936 u32 val, base, shadow;
938 spin_lock(&res->reg_slock);
940 /* read interrupt status for handling and clearing flags for VSYNC */
941 val = mixer_reg_read(res, MXR_INT_STATUS);
944 if (val & MXR_INT_STATUS_VSYNC) {
945 /* interlace scan need to check shadow register */
946 if (ctx->interlace) {
947 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
948 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
952 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
953 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
958 drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe);
959 mixer_finish_pageflip(drm_hdmi_ctx->drm_dev, ctx->pipe);
963 /* clear interrupts */
964 if (~val & MXR_INT_EN_VSYNC) {
965 /* vsync interrupt use different bit for read and clear */
966 val &= ~MXR_INT_EN_VSYNC;
967 val |= MXR_INT_CLEAR_VSYNC;
969 mixer_reg_write(res, MXR_INT_STATUS, val);
971 spin_unlock(&res->reg_slock);
976 static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
977 struct platform_device *pdev)
979 struct mixer_context *mixer_ctx = ctx->ctx;
980 struct device *dev = &pdev->dev;
981 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
982 struct resource *res;
985 spin_lock_init(&mixer_res->reg_slock);
987 mixer_res->mixer = devm_clk_get(dev, "mixer");
988 if (IS_ERR_OR_NULL(mixer_res->mixer)) {
989 dev_err(dev, "failed to get clock 'mixer'\n");
993 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
994 if (IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) {
995 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
998 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1000 dev_err(dev, "get memory resource failed.\n");
1004 mixer_res->mixer_regs = devm_ioremap(&pdev->dev, res->start,
1005 resource_size(res));
1006 if (mixer_res->mixer_regs == NULL) {
1007 dev_err(dev, "register mapping failed.\n");
1011 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
1013 dev_err(dev, "get interrupt resource failed.\n");
1017 ret = devm_request_irq(&pdev->dev, res->start, mixer_irq_handler,
1018 0, "drm_mixer", ctx);
1020 dev_err(dev, "request interrupt failed.\n");
1023 mixer_res->irq = res->start;
1028 static int __devinit vp_resources_init(struct exynos_drm_hdmi_context *ctx,
1029 struct platform_device *pdev)
1031 struct mixer_context *mixer_ctx = ctx->ctx;
1032 struct device *dev = &pdev->dev;
1033 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
1034 struct resource *res;
1036 mixer_res->vp = devm_clk_get(dev, "vp");
1037 if (IS_ERR_OR_NULL(mixer_res->vp)) {
1038 dev_err(dev, "failed to get clock 'vp'\n");
1041 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
1042 if (IS_ERR_OR_NULL(mixer_res->sclk_mixer)) {
1043 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
1046 mixer_res->sclk_dac = devm_clk_get(dev, "sclk_dac");
1047 if (IS_ERR_OR_NULL(mixer_res->sclk_dac)) {
1048 dev_err(dev, "failed to get clock 'sclk_dac'\n");
1052 if (mixer_res->sclk_hdmi)
1053 clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
1055 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
1057 dev_err(dev, "get memory resource failed.\n");
1061 mixer_res->vp_regs = devm_ioremap(&pdev->dev, res->start,
1062 resource_size(res));
1063 if (mixer_res->vp_regs == NULL) {
1064 dev_err(dev, "register mapping failed.\n");
1071 static struct mixer_drv_data exynos5_mxr_drv_data = {
1072 .version = MXR_VER_16_0_33_0,
1076 static struct mixer_drv_data exynos4_mxr_drv_data = {
1077 .version = MXR_VER_0_0_0_16,
1081 static struct platform_device_id mixer_driver_types[] = {
1083 .name = "s5p-mixer",
1084 .driver_data = (unsigned long)&exynos4_mxr_drv_data,
1086 .name = "exynos5-mixer",
1087 .driver_data = (unsigned long)&exynos5_mxr_drv_data,
1093 static struct of_device_id mixer_match_types[] = {
1095 .compatible = "samsung,exynos5-mixer",
1096 .data = &exynos5_mxr_drv_data,
1102 static int __devinit mixer_probe(struct platform_device *pdev)
1104 struct device *dev = &pdev->dev;
1105 struct exynos_drm_hdmi_context *drm_hdmi_ctx;
1106 struct mixer_context *ctx;
1107 struct mixer_drv_data *drv;
1110 dev_info(dev, "probe start\n");
1112 drm_hdmi_ctx = devm_kzalloc(&pdev->dev, sizeof(*drm_hdmi_ctx),
1114 if (!drm_hdmi_ctx) {
1115 DRM_ERROR("failed to allocate common hdmi context.\n");
1119 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1121 DRM_ERROR("failed to alloc mixer context.\n");
1125 mutex_init(&ctx->mixer_mutex);
1128 const struct of_device_id *match;
1129 match = of_match_node(of_match_ptr(mixer_match_types),
1131 drv = (struct mixer_drv_data *)match->data;
1133 drv = (struct mixer_drv_data *)
1134 platform_get_device_id(pdev)->driver_data;
1137 ctx->dev = &pdev->dev;
1138 ctx->parent_ctx = (void *)drm_hdmi_ctx;
1139 drm_hdmi_ctx->ctx = (void *)ctx;
1140 ctx->vp_enabled = drv->is_vp_enabled;
1141 ctx->mxr_ver = drv->version;
1143 platform_set_drvdata(pdev, drm_hdmi_ctx);
1145 /* acquire resources: regs, irqs, clocks */
1146 ret = mixer_resources_init(drm_hdmi_ctx, pdev);
1148 DRM_ERROR("mixer_resources_init failed\n");
1152 if (ctx->vp_enabled) {
1153 /* acquire vp resources: regs, irqs, clocks */
1154 ret = vp_resources_init(drm_hdmi_ctx, pdev);
1156 DRM_ERROR("vp_resources_init failed\n");
1161 /* attach mixer driver to common hdmi. */
1162 exynos_mixer_drv_attach(drm_hdmi_ctx);
1164 /* register specific callback point to common hdmi. */
1165 exynos_mixer_ops_register(&mixer_ops);
1167 pm_runtime_enable(dev);
1173 dev_info(dev, "probe failed\n");
1177 static int mixer_remove(struct platform_device *pdev)
1179 dev_info(&pdev->dev, "remove successful\n");
1181 pm_runtime_disable(&pdev->dev);
1186 #ifdef CONFIG_PM_SLEEP
1187 static int mixer_suspend(struct device *dev)
1189 struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
1190 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
1192 mixer_poweroff(ctx);
1198 static SIMPLE_DEV_PM_OPS(mixer_pm_ops, mixer_suspend, NULL);
1200 struct platform_driver mixer_driver = {
1202 .name = "exynos-mixer",
1203 .owner = THIS_MODULE,
1204 .pm = &mixer_pm_ops,
1205 .of_match_table = mixer_match_types,
1207 .probe = mixer_probe,
1208 .remove = __devexit_p(mixer_remove),
1209 .id_table = mixer_driver_types,