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 get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev))
42 struct hdmi_win_data {
45 dma_addr_t chroma_dma_addr;
46 void __iomem *chroma_vaddr;
47 uint32_t pixel_format;
51 unsigned int crtc_width;
52 unsigned int crtc_height;
55 unsigned int fb_width;
56 unsigned int fb_height;
57 unsigned int src_width;
58 unsigned int src_height;
59 unsigned int mode_width;
60 unsigned int mode_height;
61 unsigned int scan_flags;
64 struct mixer_resources {
66 void __iomem *mixer_regs;
67 void __iomem *vp_regs;
71 struct clk *sclk_mixer;
72 struct clk *sclk_hdmi;
76 enum mixer_version_id {
81 struct mixer_context {
89 struct mutex mixer_mutex;
90 struct mixer_resources mixer_res;
91 struct hdmi_win_data win_data[MIXER_WIN_NR];
92 enum mixer_version_id mxr_ver;
95 struct mixer_drv_data {
96 enum mixer_version_id version;
100 static const u8 filter_y_horiz_tap8[] = {
101 0, -1, -1, -1, -1, -1, -1, -1,
102 -1, -1, -1, -1, -1, 0, 0, 0,
103 0, 2, 4, 5, 6, 6, 6, 6,
104 6, 5, 5, 4, 3, 2, 1, 1,
105 0, -6, -12, -16, -18, -20, -21, -20,
106 -20, -18, -16, -13, -10, -8, -5, -2,
107 127, 126, 125, 121, 114, 107, 99, 89,
108 79, 68, 57, 46, 35, 25, 16, 8,
111 static const u8 filter_y_vert_tap4[] = {
112 0, -3, -6, -8, -8, -8, -8, -7,
113 -6, -5, -4, -3, -2, -1, -1, 0,
114 127, 126, 124, 118, 111, 102, 92, 81,
115 70, 59, 48, 37, 27, 19, 11, 5,
116 0, 5, 11, 19, 27, 37, 48, 59,
117 70, 81, 92, 102, 111, 118, 124, 126,
118 0, 0, -1, -1, -2, -3, -4, -5,
119 -6, -7, -8, -8, -8, -8, -6, -3,
122 static const u8 filter_cr_horiz_tap4[] = {
123 0, -3, -6, -8, -8, -8, -8, -7,
124 -6, -5, -4, -3, -2, -1, -1, 0,
125 127, 126, 124, 118, 111, 102, 92, 81,
126 70, 59, 48, 37, 27, 19, 11, 5,
129 static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
131 return readl(res->vp_regs + reg_id);
134 static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
137 writel(val, res->vp_regs + reg_id);
140 static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
143 u32 old = vp_reg_read(res, reg_id);
145 val = (val & mask) | (old & ~mask);
146 writel(val, res->vp_regs + reg_id);
149 static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
151 return readl(res->mixer_regs + reg_id);
154 static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
157 writel(val, res->mixer_regs + reg_id);
160 static inline void mixer_reg_writemask(struct mixer_resources *res,
161 u32 reg_id, u32 val, u32 mask)
163 u32 old = mixer_reg_read(res, reg_id);
165 val = (val & mask) | (old & ~mask);
166 writel(val, res->mixer_regs + reg_id);
169 static void mixer_regs_dump(struct mixer_context *ctx)
171 #define DUMPREG(reg_id) \
173 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
174 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
180 DUMPREG(MXR_INT_STATUS);
182 DUMPREG(MXR_LAYER_CFG);
183 DUMPREG(MXR_VIDEO_CFG);
185 DUMPREG(MXR_GRAPHIC0_CFG);
186 DUMPREG(MXR_GRAPHIC0_BASE);
187 DUMPREG(MXR_GRAPHIC0_SPAN);
188 DUMPREG(MXR_GRAPHIC0_WH);
189 DUMPREG(MXR_GRAPHIC0_SXY);
190 DUMPREG(MXR_GRAPHIC0_DXY);
192 DUMPREG(MXR_GRAPHIC1_CFG);
193 DUMPREG(MXR_GRAPHIC1_BASE);
194 DUMPREG(MXR_GRAPHIC1_SPAN);
195 DUMPREG(MXR_GRAPHIC1_WH);
196 DUMPREG(MXR_GRAPHIC1_SXY);
197 DUMPREG(MXR_GRAPHIC1_DXY);
201 static void vp_regs_dump(struct mixer_context *ctx)
203 #define DUMPREG(reg_id) \
205 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
206 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
211 DUMPREG(VP_SHADOW_UPDATE);
212 DUMPREG(VP_FIELD_ID);
214 DUMPREG(VP_IMG_SIZE_Y);
215 DUMPREG(VP_IMG_SIZE_C);
216 DUMPREG(VP_PER_RATE_CTRL);
217 DUMPREG(VP_TOP_Y_PTR);
218 DUMPREG(VP_BOT_Y_PTR);
219 DUMPREG(VP_TOP_C_PTR);
220 DUMPREG(VP_BOT_C_PTR);
221 DUMPREG(VP_ENDIAN_MODE);
222 DUMPREG(VP_SRC_H_POSITION);
223 DUMPREG(VP_SRC_V_POSITION);
224 DUMPREG(VP_SRC_WIDTH);
225 DUMPREG(VP_SRC_HEIGHT);
226 DUMPREG(VP_DST_H_POSITION);
227 DUMPREG(VP_DST_V_POSITION);
228 DUMPREG(VP_DST_WIDTH);
229 DUMPREG(VP_DST_HEIGHT);
236 static inline void vp_filter_set(struct mixer_resources *res,
237 int reg_id, const u8 *data, unsigned int size)
239 /* assure 4-byte align */
241 for (; size; size -= 4, reg_id += 4, data += 4) {
242 u32 val = (data[0] << 24) | (data[1] << 16) |
243 (data[2] << 8) | data[3];
244 vp_reg_write(res, reg_id, val);
248 static void vp_default_filter(struct mixer_resources *res)
250 vp_filter_set(res, VP_POLY8_Y0_LL,
251 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
252 vp_filter_set(res, VP_POLY4_Y0_LL,
253 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
254 vp_filter_set(res, VP_POLY4_C0_LL,
255 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
258 static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
260 struct mixer_resources *res = &ctx->mixer_res;
262 /* block update on vsync */
263 mixer_reg_writemask(res, MXR_STATUS, enable ?
264 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
267 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
268 VP_SHADOW_UPDATE_ENABLE : 0);
271 static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
273 struct mixer_resources *res = &ctx->mixer_res;
276 /* choosing between interlace and progressive mode */
277 val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
278 MXR_CFG_SCAN_PROGRASSIVE);
280 /* choosing between porper HD and SD mode */
282 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
283 else if (height == 576)
284 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
285 else if (height == 720)
286 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
287 else if (height == 1080)
288 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
290 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
292 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
295 static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
297 struct mixer_resources *res = &ctx->mixer_res;
301 val = MXR_CFG_RGB601_0_255;
302 } else if (height == 576) {
303 val = MXR_CFG_RGB601_0_255;
304 } else if (height == 720) {
305 val = MXR_CFG_RGB709_16_235;
306 mixer_reg_write(res, MXR_CM_COEFF_Y,
307 (1 << 30) | (94 << 20) | (314 << 10) |
309 mixer_reg_write(res, MXR_CM_COEFF_CB,
310 (972 << 20) | (851 << 10) | (225 << 0));
311 mixer_reg_write(res, MXR_CM_COEFF_CR,
312 (225 << 20) | (820 << 10) | (1004 << 0));
313 } else if (height == 1080) {
314 val = MXR_CFG_RGB709_16_235;
315 mixer_reg_write(res, MXR_CM_COEFF_Y,
316 (1 << 30) | (94 << 20) | (314 << 10) |
318 mixer_reg_write(res, MXR_CM_COEFF_CB,
319 (972 << 20) | (851 << 10) | (225 << 0));
320 mixer_reg_write(res, MXR_CM_COEFF_CR,
321 (225 << 20) | (820 << 10) | (1004 << 0));
323 val = MXR_CFG_RGB709_16_235;
324 mixer_reg_write(res, MXR_CM_COEFF_Y,
325 (1 << 30) | (94 << 20) | (314 << 10) |
327 mixer_reg_write(res, MXR_CM_COEFF_CB,
328 (972 << 20) | (851 << 10) | (225 << 0));
329 mixer_reg_write(res, MXR_CM_COEFF_CR,
330 (225 << 20) | (820 << 10) | (1004 << 0));
333 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
336 static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable)
338 struct mixer_resources *res = &ctx->mixer_res;
339 u32 val = enable ? ~0 : 0;
343 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
346 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
349 if (ctx->vp_enabled) {
350 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
351 mixer_reg_writemask(res, MXR_CFG, val,
358 static void mixer_run(struct mixer_context *ctx)
360 struct mixer_resources *res = &ctx->mixer_res;
362 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
364 mixer_regs_dump(ctx);
367 static void vp_video_buffer(struct mixer_context *ctx, int win)
369 struct mixer_resources *res = &ctx->mixer_res;
371 struct hdmi_win_data *win_data;
372 unsigned int x_ratio, y_ratio;
373 unsigned int buf_num;
374 dma_addr_t luma_addr[2], chroma_addr[2];
375 bool tiled_mode = false;
376 bool crcb_mode = false;
379 win_data = &ctx->win_data[win];
381 switch (win_data->pixel_format) {
382 case DRM_FORMAT_NV12MT:
384 case DRM_FORMAT_NV12:
388 /* TODO: single buffer format NV12, NV21 */
390 /* ignore pixel format at disable time */
391 if (!win_data->dma_addr)
394 DRM_ERROR("pixel format for vp is wrong [%d].\n",
395 win_data->pixel_format);
399 /* scaling feature: (src << 16) / dst */
400 x_ratio = (win_data->src_width << 16) / win_data->crtc_width;
401 y_ratio = (win_data->src_height << 16) / win_data->crtc_height;
404 luma_addr[0] = win_data->dma_addr;
405 chroma_addr[0] = win_data->chroma_dma_addr;
407 luma_addr[0] = win_data->dma_addr;
408 chroma_addr[0] = win_data->dma_addr
409 + (win_data->fb_width * win_data->fb_height);
412 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) {
413 ctx->interlace = true;
415 luma_addr[1] = luma_addr[0] + 0x40;
416 chroma_addr[1] = chroma_addr[0] + 0x40;
418 luma_addr[1] = luma_addr[0] + win_data->fb_width;
419 chroma_addr[1] = chroma_addr[0] + win_data->fb_width;
422 ctx->interlace = false;
427 spin_lock_irqsave(&res->reg_slock, flags);
428 mixer_vsync_set_update(ctx, false);
430 /* interlace or progressive scan mode */
431 val = (ctx->interlace ? ~0 : 0);
432 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
435 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
436 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
437 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
439 /* setting size of input image */
440 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_width) |
441 VP_IMG_VSIZE(win_data->fb_height));
442 /* chroma height has to reduced by 2 to avoid chroma distorions */
443 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(win_data->fb_width) |
444 VP_IMG_VSIZE(win_data->fb_height / 2));
446 vp_reg_write(res, VP_SRC_WIDTH, win_data->src_width);
447 vp_reg_write(res, VP_SRC_HEIGHT, win_data->src_height);
448 vp_reg_write(res, VP_SRC_H_POSITION,
449 VP_SRC_H_POSITION_VAL(win_data->fb_x));
450 vp_reg_write(res, VP_SRC_V_POSITION, win_data->fb_y);
452 vp_reg_write(res, VP_DST_WIDTH, win_data->crtc_width);
453 vp_reg_write(res, VP_DST_H_POSITION, win_data->crtc_x);
454 if (ctx->interlace) {
455 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height / 2);
456 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y / 2);
458 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height);
459 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y);
462 vp_reg_write(res, VP_H_RATIO, x_ratio);
463 vp_reg_write(res, VP_V_RATIO, y_ratio);
465 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
467 /* set buffer address to vp */
468 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
469 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
470 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
471 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
473 mixer_cfg_scan(ctx, win_data->mode_height);
474 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
475 mixer_cfg_layer(ctx, win, true);
478 mixer_vsync_set_update(ctx, true);
479 spin_unlock_irqrestore(&res->reg_slock, flags);
484 static void mixer_layer_update(struct mixer_context *ctx)
486 struct mixer_resources *res = &ctx->mixer_res;
489 val = mixer_reg_read(res, MXR_CFG);
491 /* allow one update per vsync only */
492 if (!(val & MXR_CFG_LAYER_UPDATE_COUNT_MASK))
493 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
496 static void mixer_graph_buffer(struct mixer_context *ctx, int win)
498 struct mixer_resources *res = &ctx->mixer_res;
500 struct hdmi_win_data *win_data;
501 unsigned int x_ratio, y_ratio;
502 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
507 win_data = &ctx->win_data[win];
514 switch (win_data->bpp) {
525 /* 2x scaling feature */
529 dst_x_offset = win_data->crtc_x;
530 dst_y_offset = win_data->crtc_y;
532 /* converting dma address base and source offset */
533 dma_addr = win_data->dma_addr
534 + (win_data->fb_x * win_data->bpp >> 3)
535 + (win_data->fb_y * win_data->fb_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), win_data->fb_width);
554 val = MXR_GRP_WH_WIDTH(win_data->crtc_width);
555 val |= MXR_GRP_WH_HEIGHT(win_data->crtc_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, win_data->mode_height);
574 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
575 mixer_cfg_layer(ctx, win, true);
577 /* layer update mandatory for mixer 16.0.33.0 */
578 if (ctx->mxr_ver == MXR_VER_16_0_33_0)
579 mixer_layer_update(ctx);
583 mixer_vsync_set_update(ctx, true);
584 spin_unlock_irqrestore(&res->reg_slock, flags);
587 static void vp_win_reset(struct mixer_context *ctx)
589 struct mixer_resources *res = &ctx->mixer_res;
592 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
593 for (tries = 100; tries; --tries) {
594 /* waiting until VP_SRESET_PROCESSING is 0 */
595 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
599 WARN(tries == 0, "failed to reset Video Processor\n");
602 static void mixer_win_reset(struct mixer_context *ctx)
604 struct mixer_resources *res = &ctx->mixer_res;
606 u32 val; /* value stored to register */
608 spin_lock_irqsave(&res->reg_slock, flags);
609 mixer_vsync_set_update(ctx, false);
611 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
613 /* set output in RGB888 mode */
614 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
616 /* 16 beat burst in DMA */
617 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
618 MXR_STATUS_BURST_MASK);
620 /* setting default layer priority: layer1 > layer0 > video
621 * because typical usage scenario would be
623 * layer0 - framebuffer
624 * video - video overlay
626 val = MXR_LAYER_CFG_GRP1_VAL(3);
627 val |= MXR_LAYER_CFG_GRP0_VAL(2);
629 val |= MXR_LAYER_CFG_VP_VAL(1);
630 mixer_reg_write(res, MXR_LAYER_CFG, val);
632 /* setting background color */
633 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
634 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
635 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
637 /* setting graphical layers */
638 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
639 val |= MXR_GRP_CFG_WIN_BLEND_EN;
640 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
641 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
642 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
644 /* the same configuration for both layers */
645 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
646 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
648 /* setting video layers */
649 val = MXR_GRP_CFG_ALPHA_VAL(0);
650 mixer_reg_write(res, MXR_VIDEO_CFG, val);
652 if (ctx->vp_enabled) {
653 /* configuration of Video Processor Registers */
655 vp_default_filter(res);
658 /* disable all layers */
659 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
660 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
662 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
664 mixer_vsync_set_update(ctx, true);
665 spin_unlock_irqrestore(&res->reg_slock, flags);
668 static void mixer_poweron(struct mixer_context *ctx)
670 struct mixer_resources *res = &ctx->mixer_res;
672 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
674 mutex_lock(&ctx->mixer_mutex);
676 mutex_unlock(&ctx->mixer_mutex);
680 mutex_unlock(&ctx->mixer_mutex);
682 pm_runtime_get_sync(ctx->dev);
684 clk_enable(res->mixer);
685 if (ctx->vp_enabled) {
687 clk_enable(res->sclk_mixer);
690 mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
691 mixer_win_reset(ctx);
694 static void mixer_poweroff(struct mixer_context *ctx)
696 struct mixer_resources *res = &ctx->mixer_res;
698 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
700 mutex_lock(&ctx->mixer_mutex);
703 mutex_unlock(&ctx->mixer_mutex);
705 ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
707 clk_disable(res->mixer);
708 if (ctx->vp_enabled) {
709 clk_disable(res->vp);
710 clk_disable(res->sclk_mixer);
713 pm_runtime_put_sync(ctx->dev);
715 mutex_lock(&ctx->mixer_mutex);
716 ctx->powered = false;
719 mutex_unlock(&ctx->mixer_mutex);
722 static int mixer_enable_vblank(void *ctx, int pipe)
724 struct mixer_context *mixer_ctx = ctx;
725 struct mixer_resources *res = &mixer_ctx->mixer_res;
727 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
729 mixer_ctx->pipe = pipe;
731 /* enable vsync interrupt */
732 mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
738 static void mixer_disable_vblank(void *ctx)
740 struct mixer_context *mixer_ctx = ctx;
741 struct mixer_resources *res = &mixer_ctx->mixer_res;
743 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
745 /* disable vsync interrupt */
746 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
749 static void mixer_dpms(void *ctx, int mode)
751 struct mixer_context *mixer_ctx = ctx;
753 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
756 case DRM_MODE_DPMS_ON:
757 mixer_poweron(mixer_ctx);
759 case DRM_MODE_DPMS_STANDBY:
760 case DRM_MODE_DPMS_SUSPEND:
761 case DRM_MODE_DPMS_OFF:
762 mixer_poweroff(mixer_ctx);
765 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
770 static void mixer_wait_for_vblank(void *ctx)
772 struct mixer_context *mixer_ctx = ctx;
773 struct mixer_resources *res = &mixer_ctx->mixer_res;
776 ret = wait_for((mixer_reg_read(res, MXR_INT_STATUS) &
777 MXR_INT_STATUS_VSYNC), 50);
779 DRM_DEBUG_KMS("vblank wait timed out.\n");
782 static void mixer_win_mode_set(void *ctx,
783 struct exynos_drm_overlay *overlay)
785 struct mixer_context *mixer_ctx = ctx;
786 struct hdmi_win_data *win_data;
789 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
792 DRM_ERROR("overlay is NULL\n");
796 DRM_DEBUG_KMS("set [%d]x[%d] at (%d,%d) to [%d]x[%d] at (%d,%d)\n",
797 overlay->fb_width, overlay->fb_height,
798 overlay->fb_x, overlay->fb_y,
799 overlay->crtc_width, overlay->crtc_height,
800 overlay->crtc_x, overlay->crtc_y);
803 if (win == DEFAULT_ZPOS)
804 win = MIXER_DEFAULT_WIN;
806 if (win < 0 || win > MIXER_WIN_NR) {
807 DRM_ERROR("mixer window[%d] is wrong\n", win);
811 win_data = &mixer_ctx->win_data[win];
813 win_data->dma_addr = overlay->dma_addr[0];
814 win_data->vaddr = overlay->vaddr[0];
815 win_data->chroma_dma_addr = overlay->dma_addr[1];
816 win_data->chroma_vaddr = overlay->vaddr[1];
817 win_data->pixel_format = overlay->pixel_format;
818 win_data->bpp = overlay->bpp;
820 win_data->crtc_x = overlay->crtc_x;
821 win_data->crtc_y = overlay->crtc_y;
822 win_data->crtc_width = overlay->crtc_width;
823 win_data->crtc_height = overlay->crtc_height;
825 win_data->fb_x = overlay->fb_x;
826 win_data->fb_y = overlay->fb_y;
827 win_data->fb_width = overlay->fb_width;
828 win_data->fb_height = overlay->fb_height;
829 win_data->src_width = overlay->src_width;
830 win_data->src_height = overlay->src_height;
832 win_data->mode_width = overlay->mode_width;
833 win_data->mode_height = overlay->mode_height;
835 win_data->scan_flags = overlay->scan_flag;
838 static void mixer_win_commit(void *ctx, int win)
840 struct mixer_context *mixer_ctx = ctx;
842 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
844 if (win > 1 && mixer_ctx->vp_enabled)
845 vp_video_buffer(mixer_ctx, win);
847 mixer_graph_buffer(mixer_ctx, win);
850 static void mixer_win_disable(void *ctx, int win)
852 struct mixer_context *mixer_ctx = ctx;
853 struct mixer_resources *res = &mixer_ctx->mixer_res;
856 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
858 spin_lock_irqsave(&res->reg_slock, flags);
859 mixer_vsync_set_update(mixer_ctx, false);
861 mixer_cfg_layer(mixer_ctx, win, false);
863 mixer_vsync_set_update(mixer_ctx, true);
864 spin_unlock_irqrestore(&res->reg_slock, flags);
867 static struct exynos_mixer_ops mixer_ops = {
869 .enable_vblank = mixer_enable_vblank,
870 .disable_vblank = mixer_disable_vblank,
874 .wait_for_vblank = mixer_wait_for_vblank,
875 .win_mode_set = mixer_win_mode_set,
876 .win_commit = mixer_win_commit,
877 .win_disable = mixer_win_disable,
880 /* for pageflip event */
881 static void mixer_finish_pageflip(struct drm_device *drm_dev, int crtc)
883 struct exynos_drm_private *dev_priv = drm_dev->dev_private;
884 struct drm_pending_vblank_event *e, *t;
888 spin_lock_irqsave(&drm_dev->event_lock, flags);
890 list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
892 /* if event's pipe isn't same as crtc then ignore it. */
896 do_gettimeofday(&now);
897 e->event.sequence = 0;
898 e->event.tv_sec = now.tv_sec;
899 e->event.tv_usec = now.tv_usec;
901 list_move_tail(&e->base.link, &e->base.file_priv->event_list);
902 wake_up_interruptible(&e->base.file_priv->event_wait);
903 drm_vblank_put(drm_dev, crtc);
906 spin_unlock_irqrestore(&drm_dev->event_lock, flags);
909 static irqreturn_t mixer_irq_handler(int irq, void *arg)
911 struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg;
912 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
913 struct mixer_resources *res = &ctx->mixer_res;
914 u32 val, base, shadow;
916 spin_lock(&res->reg_slock);
918 /* read interrupt status for handling and clearing flags for VSYNC */
919 val = mixer_reg_read(res, MXR_INT_STATUS);
922 if (val & MXR_INT_STATUS_VSYNC) {
923 /* interlace scan need to check shadow register */
924 if (ctx->interlace) {
925 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
926 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
930 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
931 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
936 drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe);
937 mixer_finish_pageflip(drm_hdmi_ctx->drm_dev, ctx->pipe);
941 /* clear interrupts */
942 if (~val & MXR_INT_EN_VSYNC) {
943 /* vsync interrupt use different bit for read and clear */
944 val &= ~MXR_INT_EN_VSYNC;
945 val |= MXR_INT_CLEAR_VSYNC;
947 mixer_reg_write(res, MXR_INT_STATUS, val);
949 spin_unlock(&res->reg_slock);
954 static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
955 struct platform_device *pdev)
957 struct mixer_context *mixer_ctx = ctx->ctx;
958 struct device *dev = &pdev->dev;
959 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
960 struct resource *res;
963 spin_lock_init(&mixer_res->reg_slock);
965 mixer_res->mixer = clk_get(dev, "mixer");
966 if (IS_ERR_OR_NULL(mixer_res->mixer)) {
967 dev_err(dev, "failed to get clock 'mixer'\n");
972 mixer_res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
973 if (IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) {
974 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
978 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
980 dev_err(dev, "get memory resource failed.\n");
985 mixer_res->mixer_regs = devm_ioremap(&pdev->dev, res->start,
987 if (mixer_res->mixer_regs == NULL) {
988 dev_err(dev, "register mapping failed.\n");
993 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
995 dev_err(dev, "get interrupt resource failed.\n");
1000 ret = devm_request_irq(&pdev->dev, res->start, mixer_irq_handler,
1001 0, "drm_mixer", ctx);
1003 dev_err(dev, "request interrupt failed.\n");
1006 mixer_res->irq = res->start;
1011 if (!IS_ERR_OR_NULL(mixer_res->sclk_hdmi))
1012 clk_put(mixer_res->sclk_hdmi);
1013 if (!IS_ERR_OR_NULL(mixer_res->mixer))
1014 clk_put(mixer_res->mixer);
1018 static int __devinit vp_resources_init(struct exynos_drm_hdmi_context *ctx,
1019 struct platform_device *pdev)
1021 struct mixer_context *mixer_ctx = ctx->ctx;
1022 struct device *dev = &pdev->dev;
1023 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
1024 struct resource *res;
1027 mixer_res->vp = clk_get(dev, "vp");
1028 if (IS_ERR_OR_NULL(mixer_res->vp)) {
1029 dev_err(dev, "failed to get clock 'vp'\n");
1033 mixer_res->sclk_mixer = clk_get(dev, "sclk_mixer");
1034 if (IS_ERR_OR_NULL(mixer_res->sclk_mixer)) {
1035 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
1039 mixer_res->sclk_dac = clk_get(dev, "sclk_dac");
1040 if (IS_ERR_OR_NULL(mixer_res->sclk_dac)) {
1041 dev_err(dev, "failed to get clock 'sclk_dac'\n");
1046 if (mixer_res->sclk_hdmi)
1047 clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
1049 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
1051 dev_err(dev, "get memory resource failed.\n");
1056 mixer_res->vp_regs = devm_ioremap(&pdev->dev, res->start,
1057 resource_size(res));
1058 if (mixer_res->vp_regs == NULL) {
1059 dev_err(dev, "register mapping failed.\n");
1067 if (!IS_ERR_OR_NULL(mixer_res->sclk_dac))
1068 clk_put(mixer_res->sclk_dac);
1069 if (!IS_ERR_OR_NULL(mixer_res->sclk_mixer))
1070 clk_put(mixer_res->sclk_mixer);
1071 if (!IS_ERR_OR_NULL(mixer_res->vp))
1072 clk_put(mixer_res->vp);
1076 static struct mixer_drv_data exynos5_mxr_drv_data = {
1077 .version = MXR_VER_16_0_33_0,
1081 static struct mixer_drv_data exynos4_mxr_drv_data = {
1082 .version = MXR_VER_0_0_0_16,
1086 static struct platform_device_id mixer_driver_types[] = {
1088 .name = "s5p-mixer",
1089 .driver_data = (unsigned long)&exynos4_mxr_drv_data,
1091 .name = "exynos5-mixer",
1092 .driver_data = (unsigned long)&exynos5_mxr_drv_data,
1098 static struct of_device_id mixer_match_types[] = {
1100 .compatible = "samsung,exynos5-mixer",
1101 .data = &exynos5_mxr_drv_data,
1107 static int __devinit mixer_probe(struct platform_device *pdev)
1109 struct device *dev = &pdev->dev;
1110 struct exynos_drm_hdmi_context *drm_hdmi_ctx;
1111 struct mixer_context *ctx;
1112 struct mixer_drv_data *drv;
1115 dev_info(dev, "probe start\n");
1117 drm_hdmi_ctx = devm_kzalloc(&pdev->dev, sizeof(*drm_hdmi_ctx),
1119 if (!drm_hdmi_ctx) {
1120 DRM_ERROR("failed to allocate common hdmi context.\n");
1124 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1126 DRM_ERROR("failed to alloc mixer context.\n");
1130 mutex_init(&ctx->mixer_mutex);
1133 const struct of_device_id *match;
1134 match = of_match_node(of_match_ptr(mixer_match_types),
1136 drv = (struct mixer_drv_data *)match->data;
1138 drv = (struct mixer_drv_data *)
1139 platform_get_device_id(pdev)->driver_data;
1142 ctx->dev = &pdev->dev;
1143 drm_hdmi_ctx->ctx = (void *)ctx;
1144 ctx->vp_enabled = drv->is_vp_enabled;
1145 ctx->mxr_ver = drv->version;
1147 platform_set_drvdata(pdev, drm_hdmi_ctx);
1149 /* acquire resources: regs, irqs, clocks */
1150 ret = mixer_resources_init(drm_hdmi_ctx, pdev);
1152 DRM_ERROR("mixer_resources_init failed\n");
1156 if (ctx->vp_enabled) {
1157 /* acquire vp resources: regs, irqs, clocks */
1158 ret = vp_resources_init(drm_hdmi_ctx, pdev);
1160 DRM_ERROR("vp_resources_init failed\n");
1165 /* attach mixer driver to common hdmi. */
1166 exynos_mixer_drv_attach(drm_hdmi_ctx);
1168 /* register specific callback point to common hdmi. */
1169 exynos_mixer_ops_register(&mixer_ops);
1171 pm_runtime_enable(dev);
1177 dev_info(dev, "probe failed\n");
1181 static int mixer_remove(struct platform_device *pdev)
1183 dev_info(&pdev->dev, "remove successful\n");
1185 pm_runtime_disable(&pdev->dev);
1190 #ifdef CONFIG_PM_SLEEP
1191 static int mixer_suspend(struct device *dev)
1193 struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
1194 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
1196 mixer_poweroff(ctx);
1202 static SIMPLE_DEV_PM_OPS(mixer_pm_ops, mixer_suspend, NULL);
1204 struct platform_driver mixer_driver = {
1206 .name = "exynos-mixer",
1207 .owner = THIS_MODULE,
1208 .pm = &mixer_pm_ops,
1209 .of_match_table = mixer_match_types,
1211 .probe = mixer_probe,
1212 .remove = __devexit_p(mixer_remove),
1213 .id_table = mixer_driver_types,