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/platform_device.h>
27 #include <linux/interrupt.h>
28 #include <linux/irq.h>
29 #include <linux/delay.h>
30 #include <linux/pm_runtime.h>
31 #include <linux/clk.h>
32 #include <linux/regulator/consumer.h>
34 #include <linux/component.h>
36 #include <drm/exynos_drm.h>
38 #include "exynos_drm_drv.h"
39 #include "exynos_drm_crtc.h"
40 #include "exynos_drm_iommu.h"
41 #include "exynos_mixer.h"
43 #define MIXER_WIN_NR 3
44 #define MIXER_DEFAULT_WIN 0
46 struct hdmi_win_data {
48 dma_addr_t chroma_dma_addr;
49 uint32_t pixel_format;
53 unsigned int crtc_width;
54 unsigned int crtc_height;
57 unsigned int fb_width;
58 unsigned int fb_pitch;
59 unsigned int fb_height;
60 unsigned int src_width;
61 unsigned int src_height;
62 unsigned int mode_width;
63 unsigned int mode_height;
64 unsigned int scan_flags;
69 struct mixer_resources {
71 void __iomem *mixer_regs;
72 void __iomem *vp_regs;
77 struct clk *sclk_mixer;
78 struct clk *sclk_hdmi;
79 struct clk *mout_mixer;
82 enum mixer_version_id {
88 struct mixer_context {
89 struct platform_device *pdev;
91 struct drm_device *drm_dev;
92 struct exynos_drm_crtc *crtc;
100 struct mutex mixer_mutex;
101 struct mixer_resources mixer_res;
102 struct hdmi_win_data win_data[MIXER_WIN_NR];
103 enum mixer_version_id mxr_ver;
104 wait_queue_head_t wait_vsync_queue;
105 atomic_t wait_vsync_event;
108 struct mixer_drv_data {
109 enum mixer_version_id version;
114 static const u8 filter_y_horiz_tap8[] = {
115 0, -1, -1, -1, -1, -1, -1, -1,
116 -1, -1, -1, -1, -1, 0, 0, 0,
117 0, 2, 4, 5, 6, 6, 6, 6,
118 6, 5, 5, 4, 3, 2, 1, 1,
119 0, -6, -12, -16, -18, -20, -21, -20,
120 -20, -18, -16, -13, -10, -8, -5, -2,
121 127, 126, 125, 121, 114, 107, 99, 89,
122 79, 68, 57, 46, 35, 25, 16, 8,
125 static const u8 filter_y_vert_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,
130 0, 5, 11, 19, 27, 37, 48, 59,
131 70, 81, 92, 102, 111, 118, 124, 126,
132 0, 0, -1, -1, -2, -3, -4, -5,
133 -6, -7, -8, -8, -8, -8, -6, -3,
136 static const u8 filter_cr_horiz_tap4[] = {
137 0, -3, -6, -8, -8, -8, -8, -7,
138 -6, -5, -4, -3, -2, -1, -1, 0,
139 127, 126, 124, 118, 111, 102, 92, 81,
140 70, 59, 48, 37, 27, 19, 11, 5,
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 static void mixer_regs_dump(struct mixer_context *ctx)
185 #define DUMPREG(reg_id) \
187 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
188 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
194 DUMPREG(MXR_INT_STATUS);
196 DUMPREG(MXR_LAYER_CFG);
197 DUMPREG(MXR_VIDEO_CFG);
199 DUMPREG(MXR_GRAPHIC0_CFG);
200 DUMPREG(MXR_GRAPHIC0_BASE);
201 DUMPREG(MXR_GRAPHIC0_SPAN);
202 DUMPREG(MXR_GRAPHIC0_WH);
203 DUMPREG(MXR_GRAPHIC0_SXY);
204 DUMPREG(MXR_GRAPHIC0_DXY);
206 DUMPREG(MXR_GRAPHIC1_CFG);
207 DUMPREG(MXR_GRAPHIC1_BASE);
208 DUMPREG(MXR_GRAPHIC1_SPAN);
209 DUMPREG(MXR_GRAPHIC1_WH);
210 DUMPREG(MXR_GRAPHIC1_SXY);
211 DUMPREG(MXR_GRAPHIC1_DXY);
215 static void vp_regs_dump(struct mixer_context *ctx)
217 #define DUMPREG(reg_id) \
219 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
220 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
225 DUMPREG(VP_SHADOW_UPDATE);
226 DUMPREG(VP_FIELD_ID);
228 DUMPREG(VP_IMG_SIZE_Y);
229 DUMPREG(VP_IMG_SIZE_C);
230 DUMPREG(VP_PER_RATE_CTRL);
231 DUMPREG(VP_TOP_Y_PTR);
232 DUMPREG(VP_BOT_Y_PTR);
233 DUMPREG(VP_TOP_C_PTR);
234 DUMPREG(VP_BOT_C_PTR);
235 DUMPREG(VP_ENDIAN_MODE);
236 DUMPREG(VP_SRC_H_POSITION);
237 DUMPREG(VP_SRC_V_POSITION);
238 DUMPREG(VP_SRC_WIDTH);
239 DUMPREG(VP_SRC_HEIGHT);
240 DUMPREG(VP_DST_H_POSITION);
241 DUMPREG(VP_DST_V_POSITION);
242 DUMPREG(VP_DST_WIDTH);
243 DUMPREG(VP_DST_HEIGHT);
250 static inline void vp_filter_set(struct mixer_resources *res,
251 int reg_id, const u8 *data, unsigned int size)
253 /* assure 4-byte align */
255 for (; size; size -= 4, reg_id += 4, data += 4) {
256 u32 val = (data[0] << 24) | (data[1] << 16) |
257 (data[2] << 8) | data[3];
258 vp_reg_write(res, reg_id, val);
262 static void vp_default_filter(struct mixer_resources *res)
264 vp_filter_set(res, VP_POLY8_Y0_LL,
265 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
266 vp_filter_set(res, VP_POLY4_Y0_LL,
267 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
268 vp_filter_set(res, VP_POLY4_C0_LL,
269 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
272 static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
274 struct mixer_resources *res = &ctx->mixer_res;
276 /* block update on vsync */
277 mixer_reg_writemask(res, MXR_STATUS, enable ?
278 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
281 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
282 VP_SHADOW_UPDATE_ENABLE : 0);
285 static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
287 struct mixer_resources *res = &ctx->mixer_res;
290 /* choosing between interlace and progressive mode */
291 val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
292 MXR_CFG_SCAN_PROGRASSIVE);
294 if (ctx->mxr_ver != MXR_VER_128_0_0_184) {
295 /* choosing between proper HD and SD mode */
297 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
298 else if (height <= 576)
299 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
300 else if (height <= 720)
301 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
302 else if (height <= 1080)
303 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
305 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
308 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
311 static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
313 struct mixer_resources *res = &ctx->mixer_res;
317 val = MXR_CFG_RGB601_0_255;
318 } else if (height == 576) {
319 val = MXR_CFG_RGB601_0_255;
320 } else if (height == 720) {
321 val = MXR_CFG_RGB709_16_235;
322 mixer_reg_write(res, MXR_CM_COEFF_Y,
323 (1 << 30) | (94 << 20) | (314 << 10) |
325 mixer_reg_write(res, MXR_CM_COEFF_CB,
326 (972 << 20) | (851 << 10) | (225 << 0));
327 mixer_reg_write(res, MXR_CM_COEFF_CR,
328 (225 << 20) | (820 << 10) | (1004 << 0));
329 } else if (height == 1080) {
330 val = MXR_CFG_RGB709_16_235;
331 mixer_reg_write(res, MXR_CM_COEFF_Y,
332 (1 << 30) | (94 << 20) | (314 << 10) |
334 mixer_reg_write(res, MXR_CM_COEFF_CB,
335 (972 << 20) | (851 << 10) | (225 << 0));
336 mixer_reg_write(res, MXR_CM_COEFF_CR,
337 (225 << 20) | (820 << 10) | (1004 << 0));
339 val = MXR_CFG_RGB709_16_235;
340 mixer_reg_write(res, MXR_CM_COEFF_Y,
341 (1 << 30) | (94 << 20) | (314 << 10) |
343 mixer_reg_write(res, MXR_CM_COEFF_CB,
344 (972 << 20) | (851 << 10) | (225 << 0));
345 mixer_reg_write(res, MXR_CM_COEFF_CR,
346 (225 << 20) | (820 << 10) | (1004 << 0));
349 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
352 static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable)
354 struct mixer_resources *res = &ctx->mixer_res;
355 u32 val = enable ? ~0 : 0;
359 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
362 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
365 if (ctx->vp_enabled) {
366 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
367 mixer_reg_writemask(res, MXR_CFG, val,
370 /* control blending of graphic layer 0 */
371 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(0), val,
372 MXR_GRP_CFG_BLEND_PRE_MUL |
373 MXR_GRP_CFG_PIXEL_BLEND_EN);
379 static void mixer_run(struct mixer_context *ctx)
381 struct mixer_resources *res = &ctx->mixer_res;
383 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
385 mixer_regs_dump(ctx);
388 static void mixer_stop(struct mixer_context *ctx)
390 struct mixer_resources *res = &ctx->mixer_res;
393 mixer_reg_writemask(res, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
395 while (!(mixer_reg_read(res, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
397 usleep_range(10000, 12000);
399 mixer_regs_dump(ctx);
402 static void vp_video_buffer(struct mixer_context *ctx, int win)
404 struct mixer_resources *res = &ctx->mixer_res;
406 struct hdmi_win_data *win_data;
407 unsigned int x_ratio, y_ratio;
408 unsigned int buf_num = 1;
409 dma_addr_t luma_addr[2], chroma_addr[2];
410 bool tiled_mode = false;
411 bool crcb_mode = false;
414 win_data = &ctx->win_data[win];
416 switch (win_data->pixel_format) {
417 case DRM_FORMAT_NV12:
421 /* TODO: single buffer format NV12, NV21 */
423 /* ignore pixel format at disable time */
424 if (!win_data->dma_addr)
427 DRM_ERROR("pixel format for vp is wrong [%d].\n",
428 win_data->pixel_format);
432 /* scaling feature: (src << 16) / dst */
433 x_ratio = (win_data->src_width << 16) / win_data->crtc_width;
434 y_ratio = (win_data->src_height << 16) / win_data->crtc_height;
437 luma_addr[0] = win_data->dma_addr;
438 chroma_addr[0] = win_data->chroma_dma_addr;
440 luma_addr[0] = win_data->dma_addr;
441 chroma_addr[0] = win_data->dma_addr
442 + (win_data->fb_pitch * win_data->fb_height);
445 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) {
446 ctx->interlace = true;
448 luma_addr[1] = luma_addr[0] + 0x40;
449 chroma_addr[1] = chroma_addr[0] + 0x40;
451 luma_addr[1] = luma_addr[0] + win_data->fb_pitch;
452 chroma_addr[1] = chroma_addr[0] + win_data->fb_pitch;
455 ctx->interlace = false;
460 spin_lock_irqsave(&res->reg_slock, flags);
461 mixer_vsync_set_update(ctx, false);
463 /* interlace or progressive scan mode */
464 val = (ctx->interlace ? ~0 : 0);
465 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
468 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
469 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
470 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
472 /* setting size of input image */
473 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_pitch) |
474 VP_IMG_VSIZE(win_data->fb_height));
475 /* chroma height has to reduced by 2 to avoid chroma distorions */
476 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(win_data->fb_pitch) |
477 VP_IMG_VSIZE(win_data->fb_height / 2));
479 vp_reg_write(res, VP_SRC_WIDTH, win_data->src_width);
480 vp_reg_write(res, VP_SRC_HEIGHT, win_data->src_height);
481 vp_reg_write(res, VP_SRC_H_POSITION,
482 VP_SRC_H_POSITION_VAL(win_data->fb_x));
483 vp_reg_write(res, VP_SRC_V_POSITION, win_data->fb_y);
485 vp_reg_write(res, VP_DST_WIDTH, win_data->crtc_width);
486 vp_reg_write(res, VP_DST_H_POSITION, win_data->crtc_x);
487 if (ctx->interlace) {
488 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height / 2);
489 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y / 2);
491 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height);
492 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y);
495 vp_reg_write(res, VP_H_RATIO, x_ratio);
496 vp_reg_write(res, VP_V_RATIO, y_ratio);
498 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
500 /* set buffer address to vp */
501 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
502 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
503 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
504 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
506 mixer_cfg_scan(ctx, win_data->mode_height);
507 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
508 mixer_cfg_layer(ctx, win, true);
511 mixer_vsync_set_update(ctx, true);
512 spin_unlock_irqrestore(&res->reg_slock, flags);
517 static void mixer_layer_update(struct mixer_context *ctx)
519 struct mixer_resources *res = &ctx->mixer_res;
521 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
524 static void mixer_graph_buffer(struct mixer_context *ctx, int win)
526 struct mixer_resources *res = &ctx->mixer_res;
528 struct hdmi_win_data *win_data;
529 unsigned int x_ratio, y_ratio;
530 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
535 win_data = &ctx->win_data[win];
542 switch (win_data->bpp) {
553 /* 2x scaling feature */
557 dst_x_offset = win_data->crtc_x;
558 dst_y_offset = win_data->crtc_y;
560 /* converting dma address base and source offset */
561 dma_addr = win_data->dma_addr
562 + (win_data->fb_x * win_data->bpp >> 3)
563 + (win_data->fb_y * win_data->fb_pitch);
567 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE)
568 ctx->interlace = true;
570 ctx->interlace = false;
572 spin_lock_irqsave(&res->reg_slock, flags);
573 mixer_vsync_set_update(ctx, false);
576 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
577 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
580 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win),
581 win_data->fb_pitch / (win_data->bpp >> 3));
583 /* setup display size */
584 if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
585 win == MIXER_DEFAULT_WIN) {
586 val = MXR_MXR_RES_HEIGHT(win_data->mode_height);
587 val |= MXR_MXR_RES_WIDTH(win_data->mode_width);
588 mixer_reg_write(res, MXR_RESOLUTION, val);
591 val = MXR_GRP_WH_WIDTH(win_data->crtc_width);
592 val |= MXR_GRP_WH_HEIGHT(win_data->crtc_height);
593 val |= MXR_GRP_WH_H_SCALE(x_ratio);
594 val |= MXR_GRP_WH_V_SCALE(y_ratio);
595 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
597 /* setup offsets in source image */
598 val = MXR_GRP_SXY_SX(src_x_offset);
599 val |= MXR_GRP_SXY_SY(src_y_offset);
600 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
602 /* setup offsets in display image */
603 val = MXR_GRP_DXY_DX(dst_x_offset);
604 val |= MXR_GRP_DXY_DY(dst_y_offset);
605 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
607 /* set buffer address to mixer */
608 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
610 mixer_cfg_scan(ctx, win_data->mode_height);
611 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
612 mixer_cfg_layer(ctx, win, true);
614 /* layer update mandatory for mixer 16.0.33.0 */
615 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
616 ctx->mxr_ver == MXR_VER_128_0_0_184)
617 mixer_layer_update(ctx);
621 mixer_vsync_set_update(ctx, true);
622 spin_unlock_irqrestore(&res->reg_slock, flags);
625 static void vp_win_reset(struct mixer_context *ctx)
627 struct mixer_resources *res = &ctx->mixer_res;
630 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
631 for (tries = 100; tries; --tries) {
632 /* waiting until VP_SRESET_PROCESSING is 0 */
633 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
635 usleep_range(10000, 12000);
637 WARN(tries == 0, "failed to reset Video Processor\n");
640 static void mixer_win_reset(struct mixer_context *ctx)
642 struct mixer_resources *res = &ctx->mixer_res;
644 u32 val; /* value stored to register */
646 spin_lock_irqsave(&res->reg_slock, flags);
647 mixer_vsync_set_update(ctx, false);
649 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
651 /* set output in RGB888 mode */
652 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
654 /* 16 beat burst in DMA */
655 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
656 MXR_STATUS_BURST_MASK);
658 /* setting default layer priority: layer1 > layer0 > video
659 * because typical usage scenario would be
661 * layer0 - framebuffer
662 * video - video overlay
664 val = MXR_LAYER_CFG_GRP1_VAL(3);
665 val |= MXR_LAYER_CFG_GRP0_VAL(2);
667 val |= MXR_LAYER_CFG_VP_VAL(1);
668 mixer_reg_write(res, MXR_LAYER_CFG, val);
670 /* setting background color */
671 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
672 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
673 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
675 /* setting graphical layers */
676 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
677 val |= MXR_GRP_CFG_WIN_BLEND_EN;
678 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
680 /* Don't blend layer 0 onto the mixer background */
681 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
683 /* Blend layer 1 into layer 0 */
684 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
685 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
686 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
688 /* setting video layers */
689 val = MXR_GRP_CFG_ALPHA_VAL(0);
690 mixer_reg_write(res, MXR_VIDEO_CFG, val);
692 if (ctx->vp_enabled) {
693 /* configuration of Video Processor Registers */
695 vp_default_filter(res);
698 /* disable all layers */
699 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
700 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
702 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
704 mixer_vsync_set_update(ctx, true);
705 spin_unlock_irqrestore(&res->reg_slock, flags);
708 static irqreturn_t mixer_irq_handler(int irq, void *arg)
710 struct mixer_context *ctx = arg;
711 struct mixer_resources *res = &ctx->mixer_res;
712 u32 val, base, shadow;
714 spin_lock(&res->reg_slock);
716 /* read interrupt status for handling and clearing flags for VSYNC */
717 val = mixer_reg_read(res, MXR_INT_STATUS);
720 if (val & MXR_INT_STATUS_VSYNC) {
721 /* interlace scan need to check shadow register */
722 if (ctx->interlace) {
723 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
724 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
728 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
729 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
734 drm_handle_vblank(ctx->drm_dev, ctx->pipe);
735 exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
737 /* set wait vsync event to zero and wake up queue. */
738 if (atomic_read(&ctx->wait_vsync_event)) {
739 atomic_set(&ctx->wait_vsync_event, 0);
740 wake_up(&ctx->wait_vsync_queue);
745 /* clear interrupts */
746 if (~val & MXR_INT_EN_VSYNC) {
747 /* vsync interrupt use different bit for read and clear */
748 val &= ~MXR_INT_EN_VSYNC;
749 val |= MXR_INT_CLEAR_VSYNC;
751 mixer_reg_write(res, MXR_INT_STATUS, val);
753 spin_unlock(&res->reg_slock);
758 static int mixer_resources_init(struct mixer_context *mixer_ctx)
760 struct device *dev = &mixer_ctx->pdev->dev;
761 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
762 struct resource *res;
765 spin_lock_init(&mixer_res->reg_slock);
767 mixer_res->mixer = devm_clk_get(dev, "mixer");
768 if (IS_ERR(mixer_res->mixer)) {
769 dev_err(dev, "failed to get clock 'mixer'\n");
773 mixer_res->hdmi = devm_clk_get(dev, "hdmi");
774 if (IS_ERR(mixer_res->hdmi)) {
775 dev_err(dev, "failed to get clock 'hdmi'\n");
776 return PTR_ERR(mixer_res->hdmi);
779 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
780 if (IS_ERR(mixer_res->sclk_hdmi)) {
781 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
784 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
786 dev_err(dev, "get memory resource failed.\n");
790 mixer_res->mixer_regs = devm_ioremap(dev, res->start,
792 if (mixer_res->mixer_regs == NULL) {
793 dev_err(dev, "register mapping failed.\n");
797 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
799 dev_err(dev, "get interrupt resource failed.\n");
803 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
804 0, "drm_mixer", mixer_ctx);
806 dev_err(dev, "request interrupt failed.\n");
809 mixer_res->irq = res->start;
814 static int vp_resources_init(struct mixer_context *mixer_ctx)
816 struct device *dev = &mixer_ctx->pdev->dev;
817 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
818 struct resource *res;
820 mixer_res->vp = devm_clk_get(dev, "vp");
821 if (IS_ERR(mixer_res->vp)) {
822 dev_err(dev, "failed to get clock 'vp'\n");
826 if (mixer_ctx->has_sclk) {
827 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
828 if (IS_ERR(mixer_res->sclk_mixer)) {
829 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
832 mixer_res->mout_mixer = devm_clk_get(dev, "mout_mixer");
833 if (IS_ERR(mixer_res->mout_mixer)) {
834 dev_err(dev, "failed to get clock 'mout_mixer'\n");
838 if (mixer_res->sclk_hdmi && mixer_res->mout_mixer)
839 clk_set_parent(mixer_res->mout_mixer,
840 mixer_res->sclk_hdmi);
843 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
845 dev_err(dev, "get memory resource failed.\n");
849 mixer_res->vp_regs = devm_ioremap(dev, res->start,
851 if (mixer_res->vp_regs == NULL) {
852 dev_err(dev, "register mapping failed.\n");
859 static int mixer_initialize(struct mixer_context *mixer_ctx,
860 struct drm_device *drm_dev)
863 struct exynos_drm_private *priv;
864 priv = drm_dev->dev_private;
866 mixer_ctx->drm_dev = drm_dev;
867 mixer_ctx->pipe = priv->pipe++;
869 /* acquire resources: regs, irqs, clocks */
870 ret = mixer_resources_init(mixer_ctx);
872 DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
876 if (mixer_ctx->vp_enabled) {
877 /* acquire vp resources: regs, irqs, clocks */
878 ret = vp_resources_init(mixer_ctx);
880 DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
885 if (!is_drm_iommu_supported(mixer_ctx->drm_dev))
888 return drm_iommu_attach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
891 static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
893 if (is_drm_iommu_supported(mixer_ctx->drm_dev))
894 drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
897 static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
899 struct mixer_context *mixer_ctx = crtc->ctx;
900 struct mixer_resources *res = &mixer_ctx->mixer_res;
902 if (!mixer_ctx->powered) {
903 mixer_ctx->int_en |= MXR_INT_EN_VSYNC;
907 /* enable vsync interrupt */
908 mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
914 static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
916 struct mixer_context *mixer_ctx = crtc->ctx;
917 struct mixer_resources *res = &mixer_ctx->mixer_res;
919 /* disable vsync interrupt */
920 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
923 static void mixer_win_mode_set(struct exynos_drm_crtc *crtc,
924 struct exynos_drm_plane *plane)
926 struct mixer_context *mixer_ctx = crtc->ctx;
927 struct hdmi_win_data *win_data;
931 DRM_ERROR("plane is NULL\n");
935 DRM_DEBUG_KMS("set [%d]x[%d] at (%d,%d) to [%d]x[%d] at (%d,%d)\n",
936 plane->fb_width, plane->fb_height,
937 plane->fb_x, plane->fb_y,
938 plane->crtc_width, plane->crtc_height,
939 plane->crtc_x, plane->crtc_y);
942 if (win == DEFAULT_ZPOS)
943 win = MIXER_DEFAULT_WIN;
945 if (win < 0 || win >= MIXER_WIN_NR) {
946 DRM_ERROR("mixer window[%d] is wrong\n", win);
950 win_data = &mixer_ctx->win_data[win];
952 win_data->dma_addr = plane->dma_addr[0];
953 win_data->chroma_dma_addr = plane->dma_addr[1];
954 win_data->pixel_format = plane->pixel_format;
955 win_data->bpp = plane->bpp;
957 win_data->crtc_x = plane->crtc_x;
958 win_data->crtc_y = plane->crtc_y;
959 win_data->crtc_width = plane->crtc_width;
960 win_data->crtc_height = plane->crtc_height;
962 win_data->fb_x = plane->fb_x;
963 win_data->fb_y = plane->fb_y;
964 win_data->fb_width = plane->fb_width;
965 win_data->fb_height = plane->fb_height;
966 win_data->fb_pitch = plane->pitch;
967 win_data->src_width = plane->src_width;
968 win_data->src_height = plane->src_height;
970 win_data->mode_width = plane->mode_width;
971 win_data->mode_height = plane->mode_height;
973 win_data->scan_flags = plane->scan_flag;
976 static void mixer_win_commit(struct exynos_drm_crtc *crtc, int zpos)
978 struct mixer_context *mixer_ctx = crtc->ctx;
979 int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
981 DRM_DEBUG_KMS("win: %d\n", win);
983 mutex_lock(&mixer_ctx->mixer_mutex);
984 if (!mixer_ctx->powered) {
985 mutex_unlock(&mixer_ctx->mixer_mutex);
988 mutex_unlock(&mixer_ctx->mixer_mutex);
990 if (win > 1 && mixer_ctx->vp_enabled)
991 vp_video_buffer(mixer_ctx, win);
993 mixer_graph_buffer(mixer_ctx, win);
995 mixer_ctx->win_data[win].enabled = true;
998 static void mixer_win_disable(struct exynos_drm_crtc *crtc, int zpos)
1000 struct mixer_context *mixer_ctx = crtc->ctx;
1001 struct mixer_resources *res = &mixer_ctx->mixer_res;
1002 int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
1003 unsigned long flags;
1005 DRM_DEBUG_KMS("win: %d\n", win);
1007 mutex_lock(&mixer_ctx->mixer_mutex);
1008 if (!mixer_ctx->powered) {
1009 mutex_unlock(&mixer_ctx->mixer_mutex);
1010 mixer_ctx->win_data[win].resume = false;
1013 mutex_unlock(&mixer_ctx->mixer_mutex);
1015 spin_lock_irqsave(&res->reg_slock, flags);
1016 mixer_vsync_set_update(mixer_ctx, false);
1018 mixer_cfg_layer(mixer_ctx, win, false);
1020 mixer_vsync_set_update(mixer_ctx, true);
1021 spin_unlock_irqrestore(&res->reg_slock, flags);
1023 mixer_ctx->win_data[win].enabled = false;
1026 static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
1028 struct mixer_context *mixer_ctx = crtc->ctx;
1031 mutex_lock(&mixer_ctx->mixer_mutex);
1032 if (!mixer_ctx->powered) {
1033 mutex_unlock(&mixer_ctx->mixer_mutex);
1036 mutex_unlock(&mixer_ctx->mixer_mutex);
1038 err = drm_vblank_get(mixer_ctx->drm_dev, mixer_ctx->pipe);
1040 DRM_DEBUG_KMS("failed to acquire vblank counter\n");
1044 atomic_set(&mixer_ctx->wait_vsync_event, 1);
1047 * wait for MIXER to signal VSYNC interrupt or return after
1048 * timeout which is set to 50ms (refresh rate of 20).
1050 if (!wait_event_timeout(mixer_ctx->wait_vsync_queue,
1051 !atomic_read(&mixer_ctx->wait_vsync_event),
1053 DRM_DEBUG_KMS("vblank wait timed out.\n");
1055 drm_vblank_put(mixer_ctx->drm_dev, mixer_ctx->pipe);
1058 static void mixer_window_suspend(struct mixer_context *ctx)
1060 struct hdmi_win_data *win_data;
1063 for (i = 0; i < MIXER_WIN_NR; i++) {
1064 win_data = &ctx->win_data[i];
1065 win_data->resume = win_data->enabled;
1066 mixer_win_disable(ctx->crtc, i);
1068 mixer_wait_for_vblank(ctx->crtc);
1071 static void mixer_window_resume(struct mixer_context *ctx)
1073 struct hdmi_win_data *win_data;
1076 for (i = 0; i < MIXER_WIN_NR; i++) {
1077 win_data = &ctx->win_data[i];
1078 win_data->enabled = win_data->resume;
1079 win_data->resume = false;
1080 if (win_data->enabled)
1081 mixer_win_commit(ctx->crtc, i);
1085 static void mixer_poweron(struct mixer_context *ctx)
1087 struct mixer_resources *res = &ctx->mixer_res;
1089 mutex_lock(&ctx->mixer_mutex);
1091 mutex_unlock(&ctx->mixer_mutex);
1095 mutex_unlock(&ctx->mixer_mutex);
1097 pm_runtime_get_sync(ctx->dev);
1099 clk_prepare_enable(res->mixer);
1100 clk_prepare_enable(res->hdmi);
1101 if (ctx->vp_enabled) {
1102 clk_prepare_enable(res->vp);
1104 clk_prepare_enable(res->sclk_mixer);
1107 mutex_lock(&ctx->mixer_mutex);
1108 ctx->powered = true;
1109 mutex_unlock(&ctx->mixer_mutex);
1111 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
1113 mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
1114 mixer_win_reset(ctx);
1116 mixer_window_resume(ctx);
1119 static void mixer_poweroff(struct mixer_context *ctx)
1121 struct mixer_resources *res = &ctx->mixer_res;
1123 mutex_lock(&ctx->mixer_mutex);
1124 if (!ctx->powered) {
1125 mutex_unlock(&ctx->mixer_mutex);
1128 mutex_unlock(&ctx->mixer_mutex);
1131 mixer_window_suspend(ctx);
1133 ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
1135 mutex_lock(&ctx->mixer_mutex);
1136 ctx->powered = false;
1137 mutex_unlock(&ctx->mixer_mutex);
1139 clk_disable_unprepare(res->hdmi);
1140 clk_disable_unprepare(res->mixer);
1141 if (ctx->vp_enabled) {
1142 clk_disable_unprepare(res->vp);
1144 clk_disable_unprepare(res->sclk_mixer);
1147 pm_runtime_put_sync(ctx->dev);
1150 static void mixer_dpms(struct exynos_drm_crtc *crtc, int mode)
1153 case DRM_MODE_DPMS_ON:
1154 mixer_poweron(crtc->ctx);
1156 case DRM_MODE_DPMS_STANDBY:
1157 case DRM_MODE_DPMS_SUSPEND:
1158 case DRM_MODE_DPMS_OFF:
1159 mixer_poweroff(crtc->ctx);
1162 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
1167 /* Only valid for Mixer version 16.0.33.0 */
1168 int mixer_check_mode(struct drm_display_mode *mode)
1175 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
1176 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1177 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1179 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
1180 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1181 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1187 static struct exynos_drm_crtc_ops mixer_crtc_ops = {
1189 .enable_vblank = mixer_enable_vblank,
1190 .disable_vblank = mixer_disable_vblank,
1191 .wait_for_vblank = mixer_wait_for_vblank,
1192 .win_mode_set = mixer_win_mode_set,
1193 .win_commit = mixer_win_commit,
1194 .win_disable = mixer_win_disable,
1197 static struct mixer_drv_data exynos5420_mxr_drv_data = {
1198 .version = MXR_VER_128_0_0_184,
1202 static struct mixer_drv_data exynos5250_mxr_drv_data = {
1203 .version = MXR_VER_16_0_33_0,
1207 static struct mixer_drv_data exynos4212_mxr_drv_data = {
1208 .version = MXR_VER_0_0_0_16,
1212 static struct mixer_drv_data exynos4210_mxr_drv_data = {
1213 .version = MXR_VER_0_0_0_16,
1218 static struct platform_device_id mixer_driver_types[] = {
1220 .name = "s5p-mixer",
1221 .driver_data = (unsigned long)&exynos4210_mxr_drv_data,
1223 .name = "exynos5-mixer",
1224 .driver_data = (unsigned long)&exynos5250_mxr_drv_data,
1230 static struct of_device_id mixer_match_types[] = {
1232 .compatible = "samsung,exynos4210-mixer",
1233 .data = &exynos4210_mxr_drv_data,
1235 .compatible = "samsung,exynos4212-mixer",
1236 .data = &exynos4212_mxr_drv_data,
1238 .compatible = "samsung,exynos5-mixer",
1239 .data = &exynos5250_mxr_drv_data,
1241 .compatible = "samsung,exynos5250-mixer",
1242 .data = &exynos5250_mxr_drv_data,
1244 .compatible = "samsung,exynos5420-mixer",
1245 .data = &exynos5420_mxr_drv_data,
1250 MODULE_DEVICE_TABLE(of, mixer_match_types);
1252 static int mixer_bind(struct device *dev, struct device *manager, void *data)
1254 struct mixer_context *ctx = dev_get_drvdata(dev);
1255 struct drm_device *drm_dev = data;
1258 ret = mixer_initialize(ctx, drm_dev);
1262 ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
1263 EXYNOS_DISPLAY_TYPE_HDMI,
1264 &mixer_crtc_ops, ctx);
1265 if (IS_ERR(ctx->crtc)) {
1266 mixer_ctx_remove(ctx);
1267 ret = PTR_ERR(ctx->crtc);
1274 devm_kfree(dev, ctx);
1278 static void mixer_unbind(struct device *dev, struct device *master, void *data)
1280 struct mixer_context *ctx = dev_get_drvdata(dev);
1282 mixer_ctx_remove(ctx);
1285 static const struct component_ops mixer_component_ops = {
1287 .unbind = mixer_unbind,
1290 static int mixer_probe(struct platform_device *pdev)
1292 struct device *dev = &pdev->dev;
1293 struct mixer_drv_data *drv;
1294 struct mixer_context *ctx;
1297 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1299 DRM_ERROR("failed to alloc mixer context.\n");
1303 mutex_init(&ctx->mixer_mutex);
1306 const struct of_device_id *match;
1308 match = of_match_node(mixer_match_types, dev->of_node);
1309 drv = (struct mixer_drv_data *)match->data;
1311 drv = (struct mixer_drv_data *)
1312 platform_get_device_id(pdev)->driver_data;
1317 ctx->vp_enabled = drv->is_vp_enabled;
1318 ctx->has_sclk = drv->has_sclk;
1319 ctx->mxr_ver = drv->version;
1320 init_waitqueue_head(&ctx->wait_vsync_queue);
1321 atomic_set(&ctx->wait_vsync_event, 0);
1323 platform_set_drvdata(pdev, ctx);
1325 ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
1326 EXYNOS_DISPLAY_TYPE_HDMI);
1330 ret = component_add(&pdev->dev, &mixer_component_ops);
1332 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
1336 pm_runtime_enable(dev);
1341 static int mixer_remove(struct platform_device *pdev)
1343 pm_runtime_disable(&pdev->dev);
1345 component_del(&pdev->dev, &mixer_component_ops);
1346 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
1351 struct platform_driver mixer_driver = {
1353 .name = "exynos-mixer",
1354 .owner = THIS_MODULE,
1355 .of_match_table = mixer_match_types,
1357 .probe = mixer_probe,
1358 .remove = mixer_remove,
1359 .id_table = mixer_driver_types,