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_plane.h"
41 #include "exynos_drm_iommu.h"
42 #include "exynos_mixer.h"
44 #define MIXER_WIN_NR 3
45 #define MIXER_DEFAULT_WIN 0
47 struct mixer_resources {
49 void __iomem *mixer_regs;
50 void __iomem *vp_regs;
55 struct clk *sclk_mixer;
56 struct clk *sclk_hdmi;
57 struct clk *mout_mixer;
60 enum mixer_version_id {
66 struct mixer_context {
67 struct platform_device *pdev;
69 struct drm_device *drm_dev;
70 struct exynos_drm_crtc *crtc;
71 struct exynos_drm_plane planes[MIXER_WIN_NR];
79 struct mutex mixer_mutex;
80 struct mixer_resources mixer_res;
81 enum mixer_version_id mxr_ver;
82 wait_queue_head_t wait_vsync_queue;
83 atomic_t wait_vsync_event;
86 struct mixer_drv_data {
87 enum mixer_version_id version;
92 static const u8 filter_y_horiz_tap8[] = {
93 0, -1, -1, -1, -1, -1, -1, -1,
94 -1, -1, -1, -1, -1, 0, 0, 0,
95 0, 2, 4, 5, 6, 6, 6, 6,
96 6, 5, 5, 4, 3, 2, 1, 1,
97 0, -6, -12, -16, -18, -20, -21, -20,
98 -20, -18, -16, -13, -10, -8, -5, -2,
99 127, 126, 125, 121, 114, 107, 99, 89,
100 79, 68, 57, 46, 35, 25, 16, 8,
103 static const u8 filter_y_vert_tap4[] = {
104 0, -3, -6, -8, -8, -8, -8, -7,
105 -6, -5, -4, -3, -2, -1, -1, 0,
106 127, 126, 124, 118, 111, 102, 92, 81,
107 70, 59, 48, 37, 27, 19, 11, 5,
108 0, 5, 11, 19, 27, 37, 48, 59,
109 70, 81, 92, 102, 111, 118, 124, 126,
110 0, 0, -1, -1, -2, -3, -4, -5,
111 -6, -7, -8, -8, -8, -8, -6, -3,
114 static const u8 filter_cr_horiz_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,
121 static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
123 return readl(res->vp_regs + reg_id);
126 static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
129 writel(val, res->vp_regs + reg_id);
132 static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
135 u32 old = vp_reg_read(res, reg_id);
137 val = (val & mask) | (old & ~mask);
138 writel(val, res->vp_regs + reg_id);
141 static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
143 return readl(res->mixer_regs + reg_id);
146 static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
149 writel(val, res->mixer_regs + reg_id);
152 static inline void mixer_reg_writemask(struct mixer_resources *res,
153 u32 reg_id, u32 val, u32 mask)
155 u32 old = mixer_reg_read(res, reg_id);
157 val = (val & mask) | (old & ~mask);
158 writel(val, res->mixer_regs + reg_id);
161 static void mixer_regs_dump(struct mixer_context *ctx)
163 #define DUMPREG(reg_id) \
165 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
166 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
172 DUMPREG(MXR_INT_STATUS);
174 DUMPREG(MXR_LAYER_CFG);
175 DUMPREG(MXR_VIDEO_CFG);
177 DUMPREG(MXR_GRAPHIC0_CFG);
178 DUMPREG(MXR_GRAPHIC0_BASE);
179 DUMPREG(MXR_GRAPHIC0_SPAN);
180 DUMPREG(MXR_GRAPHIC0_WH);
181 DUMPREG(MXR_GRAPHIC0_SXY);
182 DUMPREG(MXR_GRAPHIC0_DXY);
184 DUMPREG(MXR_GRAPHIC1_CFG);
185 DUMPREG(MXR_GRAPHIC1_BASE);
186 DUMPREG(MXR_GRAPHIC1_SPAN);
187 DUMPREG(MXR_GRAPHIC1_WH);
188 DUMPREG(MXR_GRAPHIC1_SXY);
189 DUMPREG(MXR_GRAPHIC1_DXY);
193 static void vp_regs_dump(struct mixer_context *ctx)
195 #define DUMPREG(reg_id) \
197 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
198 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
203 DUMPREG(VP_SHADOW_UPDATE);
204 DUMPREG(VP_FIELD_ID);
206 DUMPREG(VP_IMG_SIZE_Y);
207 DUMPREG(VP_IMG_SIZE_C);
208 DUMPREG(VP_PER_RATE_CTRL);
209 DUMPREG(VP_TOP_Y_PTR);
210 DUMPREG(VP_BOT_Y_PTR);
211 DUMPREG(VP_TOP_C_PTR);
212 DUMPREG(VP_BOT_C_PTR);
213 DUMPREG(VP_ENDIAN_MODE);
214 DUMPREG(VP_SRC_H_POSITION);
215 DUMPREG(VP_SRC_V_POSITION);
216 DUMPREG(VP_SRC_WIDTH);
217 DUMPREG(VP_SRC_HEIGHT);
218 DUMPREG(VP_DST_H_POSITION);
219 DUMPREG(VP_DST_V_POSITION);
220 DUMPREG(VP_DST_WIDTH);
221 DUMPREG(VP_DST_HEIGHT);
228 static inline void vp_filter_set(struct mixer_resources *res,
229 int reg_id, const u8 *data, unsigned int size)
231 /* assure 4-byte align */
233 for (; size; size -= 4, reg_id += 4, data += 4) {
234 u32 val = (data[0] << 24) | (data[1] << 16) |
235 (data[2] << 8) | data[3];
236 vp_reg_write(res, reg_id, val);
240 static void vp_default_filter(struct mixer_resources *res)
242 vp_filter_set(res, VP_POLY8_Y0_LL,
243 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
244 vp_filter_set(res, VP_POLY4_Y0_LL,
245 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
246 vp_filter_set(res, VP_POLY4_C0_LL,
247 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
250 static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
252 struct mixer_resources *res = &ctx->mixer_res;
254 /* block update on vsync */
255 mixer_reg_writemask(res, MXR_STATUS, enable ?
256 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
259 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
260 VP_SHADOW_UPDATE_ENABLE : 0);
263 static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
265 struct mixer_resources *res = &ctx->mixer_res;
268 /* choosing between interlace and progressive mode */
269 val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
270 MXR_CFG_SCAN_PROGRASSIVE);
272 if (ctx->mxr_ver != MXR_VER_128_0_0_184) {
273 /* choosing between proper HD and SD mode */
275 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
276 else if (height <= 576)
277 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
278 else if (height <= 720)
279 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
280 else if (height <= 1080)
281 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
283 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
286 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
289 static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
291 struct mixer_resources *res = &ctx->mixer_res;
295 val = MXR_CFG_RGB601_0_255;
296 } else if (height == 576) {
297 val = MXR_CFG_RGB601_0_255;
298 } else if (height == 720) {
299 val = MXR_CFG_RGB709_16_235;
300 mixer_reg_write(res, MXR_CM_COEFF_Y,
301 (1 << 30) | (94 << 20) | (314 << 10) |
303 mixer_reg_write(res, MXR_CM_COEFF_CB,
304 (972 << 20) | (851 << 10) | (225 << 0));
305 mixer_reg_write(res, MXR_CM_COEFF_CR,
306 (225 << 20) | (820 << 10) | (1004 << 0));
307 } else if (height == 1080) {
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));
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));
327 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
330 static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable)
332 struct mixer_resources *res = &ctx->mixer_res;
333 u32 val = enable ? ~0 : 0;
337 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
340 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
343 if (ctx->vp_enabled) {
344 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
345 mixer_reg_writemask(res, MXR_CFG, val,
348 /* control blending of graphic layer 0 */
349 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(0), val,
350 MXR_GRP_CFG_BLEND_PRE_MUL |
351 MXR_GRP_CFG_PIXEL_BLEND_EN);
357 static void mixer_run(struct mixer_context *ctx)
359 struct mixer_resources *res = &ctx->mixer_res;
361 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
363 mixer_regs_dump(ctx);
366 static void mixer_stop(struct mixer_context *ctx)
368 struct mixer_resources *res = &ctx->mixer_res;
371 mixer_reg_writemask(res, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
373 while (!(mixer_reg_read(res, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
375 usleep_range(10000, 12000);
377 mixer_regs_dump(ctx);
380 static void vp_video_buffer(struct mixer_context *ctx, int win)
382 struct mixer_resources *res = &ctx->mixer_res;
384 struct exynos_drm_plane *plane;
385 unsigned int x_ratio, y_ratio;
386 unsigned int buf_num = 1;
387 dma_addr_t luma_addr[2], chroma_addr[2];
388 bool tiled_mode = false;
389 bool crcb_mode = false;
392 plane = &ctx->planes[win];
394 switch (plane->pixel_format) {
395 case DRM_FORMAT_NV12:
399 /* TODO: single buffer format NV12, NV21 */
401 /* ignore pixel format at disable time */
402 if (!plane->dma_addr[0])
405 DRM_ERROR("pixel format for vp is wrong [%d].\n",
406 plane->pixel_format);
410 /* scaling feature: (src << 16) / dst */
411 x_ratio = (plane->src_width << 16) / plane->crtc_width;
412 y_ratio = (plane->src_height << 16) / plane->crtc_height;
415 luma_addr[0] = plane->dma_addr[0];
416 chroma_addr[0] = plane->dma_addr[1];
418 luma_addr[0] = plane->dma_addr[0];
419 chroma_addr[0] = plane->dma_addr[0]
420 + (plane->pitch * plane->fb_height);
423 if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE) {
424 ctx->interlace = true;
426 luma_addr[1] = luma_addr[0] + 0x40;
427 chroma_addr[1] = chroma_addr[0] + 0x40;
429 luma_addr[1] = luma_addr[0] + plane->pitch;
430 chroma_addr[1] = chroma_addr[0] + plane->pitch;
433 ctx->interlace = false;
438 spin_lock_irqsave(&res->reg_slock, flags);
439 mixer_vsync_set_update(ctx, false);
441 /* interlace or progressive scan mode */
442 val = (ctx->interlace ? ~0 : 0);
443 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
446 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
447 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
448 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
450 /* setting size of input image */
451 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(plane->pitch) |
452 VP_IMG_VSIZE(plane->fb_height));
453 /* chroma height has to reduced by 2 to avoid chroma distorions */
454 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(plane->pitch) |
455 VP_IMG_VSIZE(plane->fb_height / 2));
457 vp_reg_write(res, VP_SRC_WIDTH, plane->src_width);
458 vp_reg_write(res, VP_SRC_HEIGHT, plane->src_height);
459 vp_reg_write(res, VP_SRC_H_POSITION,
460 VP_SRC_H_POSITION_VAL(plane->fb_x));
461 vp_reg_write(res, VP_SRC_V_POSITION, plane->fb_y);
463 vp_reg_write(res, VP_DST_WIDTH, plane->crtc_width);
464 vp_reg_write(res, VP_DST_H_POSITION, plane->crtc_x);
465 if (ctx->interlace) {
466 vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height / 2);
467 vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y / 2);
469 vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height);
470 vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y);
473 vp_reg_write(res, VP_H_RATIO, x_ratio);
474 vp_reg_write(res, VP_V_RATIO, y_ratio);
476 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
478 /* set buffer address to vp */
479 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
480 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
481 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
482 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
484 mixer_cfg_scan(ctx, plane->mode_height);
485 mixer_cfg_rgb_fmt(ctx, plane->mode_height);
486 mixer_cfg_layer(ctx, win, true);
489 mixer_vsync_set_update(ctx, true);
490 spin_unlock_irqrestore(&res->reg_slock, flags);
495 static void mixer_layer_update(struct mixer_context *ctx)
497 struct mixer_resources *res = &ctx->mixer_res;
499 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
502 static void mixer_graph_buffer(struct mixer_context *ctx, int win)
504 struct mixer_resources *res = &ctx->mixer_res;
506 struct exynos_drm_plane *plane;
507 unsigned int x_ratio, y_ratio;
508 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
513 plane = &ctx->planes[win];
520 switch (plane->bpp) {
531 /* 2x scaling feature */
535 dst_x_offset = plane->crtc_x;
536 dst_y_offset = plane->crtc_y;
538 /* converting dma address base and source offset */
539 dma_addr = plane->dma_addr[0]
540 + (plane->fb_x * plane->bpp >> 3)
541 + (plane->fb_y * plane->pitch);
545 if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE)
546 ctx->interlace = true;
548 ctx->interlace = false;
550 spin_lock_irqsave(&res->reg_slock, flags);
551 mixer_vsync_set_update(ctx, false);
554 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
555 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
558 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win),
559 plane->pitch / (plane->bpp >> 3));
561 /* setup display size */
562 if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
563 win == MIXER_DEFAULT_WIN) {
564 val = MXR_MXR_RES_HEIGHT(plane->mode_height);
565 val |= MXR_MXR_RES_WIDTH(plane->mode_width);
566 mixer_reg_write(res, MXR_RESOLUTION, val);
569 val = MXR_GRP_WH_WIDTH(plane->crtc_width);
570 val |= MXR_GRP_WH_HEIGHT(plane->crtc_height);
571 val |= MXR_GRP_WH_H_SCALE(x_ratio);
572 val |= MXR_GRP_WH_V_SCALE(y_ratio);
573 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
575 /* setup offsets in source image */
576 val = MXR_GRP_SXY_SX(src_x_offset);
577 val |= MXR_GRP_SXY_SY(src_y_offset);
578 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
580 /* setup offsets in display image */
581 val = MXR_GRP_DXY_DX(dst_x_offset);
582 val |= MXR_GRP_DXY_DY(dst_y_offset);
583 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
585 /* set buffer address to mixer */
586 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
588 mixer_cfg_scan(ctx, plane->mode_height);
589 mixer_cfg_rgb_fmt(ctx, plane->mode_height);
590 mixer_cfg_layer(ctx, win, true);
592 /* layer update mandatory for mixer 16.0.33.0 */
593 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
594 ctx->mxr_ver == MXR_VER_128_0_0_184)
595 mixer_layer_update(ctx);
599 mixer_vsync_set_update(ctx, true);
600 spin_unlock_irqrestore(&res->reg_slock, flags);
603 static void vp_win_reset(struct mixer_context *ctx)
605 struct mixer_resources *res = &ctx->mixer_res;
608 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
609 for (tries = 100; tries; --tries) {
610 /* waiting until VP_SRESET_PROCESSING is 0 */
611 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
613 usleep_range(10000, 12000);
615 WARN(tries == 0, "failed to reset Video Processor\n");
618 static void mixer_win_reset(struct mixer_context *ctx)
620 struct mixer_resources *res = &ctx->mixer_res;
622 u32 val; /* value stored to register */
624 spin_lock_irqsave(&res->reg_slock, flags);
625 mixer_vsync_set_update(ctx, false);
627 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
629 /* set output in RGB888 mode */
630 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
632 /* 16 beat burst in DMA */
633 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
634 MXR_STATUS_BURST_MASK);
636 /* setting default layer priority: layer1 > layer0 > video
637 * because typical usage scenario would be
639 * layer0 - framebuffer
640 * video - video overlay
642 val = MXR_LAYER_CFG_GRP1_VAL(3);
643 val |= MXR_LAYER_CFG_GRP0_VAL(2);
645 val |= MXR_LAYER_CFG_VP_VAL(1);
646 mixer_reg_write(res, MXR_LAYER_CFG, val);
648 /* setting background color */
649 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
650 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
651 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
653 /* setting graphical layers */
654 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
655 val |= MXR_GRP_CFG_WIN_BLEND_EN;
656 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
658 /* Don't blend layer 0 onto the mixer background */
659 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
661 /* Blend layer 1 into layer 0 */
662 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
663 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
664 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
666 /* setting video layers */
667 val = MXR_GRP_CFG_ALPHA_VAL(0);
668 mixer_reg_write(res, MXR_VIDEO_CFG, val);
670 if (ctx->vp_enabled) {
671 /* configuration of Video Processor Registers */
673 vp_default_filter(res);
676 /* disable all layers */
677 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
678 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
680 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
682 mixer_vsync_set_update(ctx, true);
683 spin_unlock_irqrestore(&res->reg_slock, flags);
686 static irqreturn_t mixer_irq_handler(int irq, void *arg)
688 struct mixer_context *ctx = arg;
689 struct mixer_resources *res = &ctx->mixer_res;
690 u32 val, base, shadow;
692 spin_lock(&res->reg_slock);
694 /* read interrupt status for handling and clearing flags for VSYNC */
695 val = mixer_reg_read(res, MXR_INT_STATUS);
698 if (val & MXR_INT_STATUS_VSYNC) {
699 /* interlace scan need to check shadow register */
700 if (ctx->interlace) {
701 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
702 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
706 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
707 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
712 drm_handle_vblank(ctx->drm_dev, ctx->pipe);
713 exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
715 /* set wait vsync event to zero and wake up queue. */
716 if (atomic_read(&ctx->wait_vsync_event)) {
717 atomic_set(&ctx->wait_vsync_event, 0);
718 wake_up(&ctx->wait_vsync_queue);
723 /* clear interrupts */
724 if (~val & MXR_INT_EN_VSYNC) {
725 /* vsync interrupt use different bit for read and clear */
726 val &= ~MXR_INT_EN_VSYNC;
727 val |= MXR_INT_CLEAR_VSYNC;
729 mixer_reg_write(res, MXR_INT_STATUS, val);
731 spin_unlock(&res->reg_slock);
736 static int mixer_resources_init(struct mixer_context *mixer_ctx)
738 struct device *dev = &mixer_ctx->pdev->dev;
739 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
740 struct resource *res;
743 spin_lock_init(&mixer_res->reg_slock);
745 mixer_res->mixer = devm_clk_get(dev, "mixer");
746 if (IS_ERR(mixer_res->mixer)) {
747 dev_err(dev, "failed to get clock 'mixer'\n");
751 mixer_res->hdmi = devm_clk_get(dev, "hdmi");
752 if (IS_ERR(mixer_res->hdmi)) {
753 dev_err(dev, "failed to get clock 'hdmi'\n");
754 return PTR_ERR(mixer_res->hdmi);
757 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
758 if (IS_ERR(mixer_res->sclk_hdmi)) {
759 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
762 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
764 dev_err(dev, "get memory resource failed.\n");
768 mixer_res->mixer_regs = devm_ioremap(dev, res->start,
770 if (mixer_res->mixer_regs == NULL) {
771 dev_err(dev, "register mapping failed.\n");
775 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
777 dev_err(dev, "get interrupt resource failed.\n");
781 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
782 0, "drm_mixer", mixer_ctx);
784 dev_err(dev, "request interrupt failed.\n");
787 mixer_res->irq = res->start;
792 static int vp_resources_init(struct mixer_context *mixer_ctx)
794 struct device *dev = &mixer_ctx->pdev->dev;
795 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
796 struct resource *res;
798 mixer_res->vp = devm_clk_get(dev, "vp");
799 if (IS_ERR(mixer_res->vp)) {
800 dev_err(dev, "failed to get clock 'vp'\n");
804 if (mixer_ctx->has_sclk) {
805 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
806 if (IS_ERR(mixer_res->sclk_mixer)) {
807 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
810 mixer_res->mout_mixer = devm_clk_get(dev, "mout_mixer");
811 if (IS_ERR(mixer_res->mout_mixer)) {
812 dev_err(dev, "failed to get clock 'mout_mixer'\n");
816 if (mixer_res->sclk_hdmi && mixer_res->mout_mixer)
817 clk_set_parent(mixer_res->mout_mixer,
818 mixer_res->sclk_hdmi);
821 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
823 dev_err(dev, "get memory resource failed.\n");
827 mixer_res->vp_regs = devm_ioremap(dev, res->start,
829 if (mixer_res->vp_regs == NULL) {
830 dev_err(dev, "register mapping failed.\n");
837 static int mixer_initialize(struct mixer_context *mixer_ctx,
838 struct drm_device *drm_dev)
841 struct exynos_drm_private *priv;
842 priv = drm_dev->dev_private;
844 mixer_ctx->drm_dev = drm_dev;
845 mixer_ctx->pipe = priv->pipe++;
847 /* acquire resources: regs, irqs, clocks */
848 ret = mixer_resources_init(mixer_ctx);
850 DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
854 if (mixer_ctx->vp_enabled) {
855 /* acquire vp resources: regs, irqs, clocks */
856 ret = vp_resources_init(mixer_ctx);
858 DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
863 if (!is_drm_iommu_supported(mixer_ctx->drm_dev))
866 return drm_iommu_attach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
869 static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
871 if (is_drm_iommu_supported(mixer_ctx->drm_dev))
872 drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
875 static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
877 struct mixer_context *mixer_ctx = crtc->ctx;
878 struct mixer_resources *res = &mixer_ctx->mixer_res;
880 if (!mixer_ctx->powered) {
881 mixer_ctx->int_en |= MXR_INT_EN_VSYNC;
885 /* enable vsync interrupt */
886 mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
892 static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
894 struct mixer_context *mixer_ctx = crtc->ctx;
895 struct mixer_resources *res = &mixer_ctx->mixer_res;
897 /* disable vsync interrupt */
898 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
901 static void mixer_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
903 struct mixer_context *mixer_ctx = crtc->ctx;
905 DRM_DEBUG_KMS("win: %d\n", win);
907 mutex_lock(&mixer_ctx->mixer_mutex);
908 if (!mixer_ctx->powered) {
909 mutex_unlock(&mixer_ctx->mixer_mutex);
912 mutex_unlock(&mixer_ctx->mixer_mutex);
914 if (win > 1 && mixer_ctx->vp_enabled)
915 vp_video_buffer(mixer_ctx, win);
917 mixer_graph_buffer(mixer_ctx, win);
919 mixer_ctx->planes[win].enabled = true;
922 static void mixer_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
924 struct mixer_context *mixer_ctx = crtc->ctx;
925 struct mixer_resources *res = &mixer_ctx->mixer_res;
928 DRM_DEBUG_KMS("win: %d\n", win);
930 mutex_lock(&mixer_ctx->mixer_mutex);
931 if (!mixer_ctx->powered) {
932 mutex_unlock(&mixer_ctx->mixer_mutex);
933 mixer_ctx->planes[win].resume = false;
936 mutex_unlock(&mixer_ctx->mixer_mutex);
938 spin_lock_irqsave(&res->reg_slock, flags);
939 mixer_vsync_set_update(mixer_ctx, false);
941 mixer_cfg_layer(mixer_ctx, win, false);
943 mixer_vsync_set_update(mixer_ctx, true);
944 spin_unlock_irqrestore(&res->reg_slock, flags);
946 mixer_ctx->planes[win].enabled = false;
949 static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
951 struct mixer_context *mixer_ctx = crtc->ctx;
954 mutex_lock(&mixer_ctx->mixer_mutex);
955 if (!mixer_ctx->powered) {
956 mutex_unlock(&mixer_ctx->mixer_mutex);
959 mutex_unlock(&mixer_ctx->mixer_mutex);
961 err = drm_vblank_get(mixer_ctx->drm_dev, mixer_ctx->pipe);
963 DRM_DEBUG_KMS("failed to acquire vblank counter\n");
967 atomic_set(&mixer_ctx->wait_vsync_event, 1);
970 * wait for MIXER to signal VSYNC interrupt or return after
971 * timeout which is set to 50ms (refresh rate of 20).
973 if (!wait_event_timeout(mixer_ctx->wait_vsync_queue,
974 !atomic_read(&mixer_ctx->wait_vsync_event),
976 DRM_DEBUG_KMS("vblank wait timed out.\n");
978 drm_vblank_put(mixer_ctx->drm_dev, mixer_ctx->pipe);
981 static void mixer_window_suspend(struct mixer_context *ctx)
983 struct exynos_drm_plane *plane;
986 for (i = 0; i < MIXER_WIN_NR; i++) {
987 plane = &ctx->planes[i];
988 plane->resume = plane->enabled;
989 mixer_win_disable(ctx->crtc, i);
991 mixer_wait_for_vblank(ctx->crtc);
994 static void mixer_window_resume(struct mixer_context *ctx)
996 struct exynos_drm_plane *plane;
999 for (i = 0; i < MIXER_WIN_NR; i++) {
1000 plane = &ctx->planes[i];
1001 plane->enabled = plane->resume;
1002 plane->resume = false;
1004 mixer_win_commit(ctx->crtc, i);
1008 static void mixer_poweron(struct mixer_context *ctx)
1010 struct mixer_resources *res = &ctx->mixer_res;
1012 mutex_lock(&ctx->mixer_mutex);
1014 mutex_unlock(&ctx->mixer_mutex);
1018 mutex_unlock(&ctx->mixer_mutex);
1020 pm_runtime_get_sync(ctx->dev);
1022 clk_prepare_enable(res->mixer);
1023 clk_prepare_enable(res->hdmi);
1024 if (ctx->vp_enabled) {
1025 clk_prepare_enable(res->vp);
1027 clk_prepare_enable(res->sclk_mixer);
1030 mutex_lock(&ctx->mixer_mutex);
1031 ctx->powered = true;
1032 mutex_unlock(&ctx->mixer_mutex);
1034 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
1036 mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
1037 mixer_win_reset(ctx);
1039 mixer_window_resume(ctx);
1042 static void mixer_poweroff(struct mixer_context *ctx)
1044 struct mixer_resources *res = &ctx->mixer_res;
1046 mutex_lock(&ctx->mixer_mutex);
1047 if (!ctx->powered) {
1048 mutex_unlock(&ctx->mixer_mutex);
1051 mutex_unlock(&ctx->mixer_mutex);
1054 mixer_window_suspend(ctx);
1056 ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
1058 mutex_lock(&ctx->mixer_mutex);
1059 ctx->powered = false;
1060 mutex_unlock(&ctx->mixer_mutex);
1062 clk_disable_unprepare(res->hdmi);
1063 clk_disable_unprepare(res->mixer);
1064 if (ctx->vp_enabled) {
1065 clk_disable_unprepare(res->vp);
1067 clk_disable_unprepare(res->sclk_mixer);
1070 pm_runtime_put_sync(ctx->dev);
1073 static void mixer_dpms(struct exynos_drm_crtc *crtc, int mode)
1076 case DRM_MODE_DPMS_ON:
1077 mixer_poweron(crtc->ctx);
1079 case DRM_MODE_DPMS_STANDBY:
1080 case DRM_MODE_DPMS_SUSPEND:
1081 case DRM_MODE_DPMS_OFF:
1082 mixer_poweroff(crtc->ctx);
1085 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
1090 /* Only valid for Mixer version 16.0.33.0 */
1091 int mixer_check_mode(struct drm_display_mode *mode)
1098 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
1099 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1100 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1102 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
1103 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1104 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1110 static struct exynos_drm_crtc_ops mixer_crtc_ops = {
1112 .enable_vblank = mixer_enable_vblank,
1113 .disable_vblank = mixer_disable_vblank,
1114 .wait_for_vblank = mixer_wait_for_vblank,
1115 .win_commit = mixer_win_commit,
1116 .win_disable = mixer_win_disable,
1119 static struct mixer_drv_data exynos5420_mxr_drv_data = {
1120 .version = MXR_VER_128_0_0_184,
1124 static struct mixer_drv_data exynos5250_mxr_drv_data = {
1125 .version = MXR_VER_16_0_33_0,
1129 static struct mixer_drv_data exynos4212_mxr_drv_data = {
1130 .version = MXR_VER_0_0_0_16,
1134 static struct mixer_drv_data exynos4210_mxr_drv_data = {
1135 .version = MXR_VER_0_0_0_16,
1140 static struct platform_device_id mixer_driver_types[] = {
1142 .name = "s5p-mixer",
1143 .driver_data = (unsigned long)&exynos4210_mxr_drv_data,
1145 .name = "exynos5-mixer",
1146 .driver_data = (unsigned long)&exynos5250_mxr_drv_data,
1152 static struct of_device_id mixer_match_types[] = {
1154 .compatible = "samsung,exynos4210-mixer",
1155 .data = &exynos4210_mxr_drv_data,
1157 .compatible = "samsung,exynos4212-mixer",
1158 .data = &exynos4212_mxr_drv_data,
1160 .compatible = "samsung,exynos5-mixer",
1161 .data = &exynos5250_mxr_drv_data,
1163 .compatible = "samsung,exynos5250-mixer",
1164 .data = &exynos5250_mxr_drv_data,
1166 .compatible = "samsung,exynos5420-mixer",
1167 .data = &exynos5420_mxr_drv_data,
1172 MODULE_DEVICE_TABLE(of, mixer_match_types);
1174 static int mixer_bind(struct device *dev, struct device *manager, void *data)
1176 struct mixer_context *ctx = dev_get_drvdata(dev);
1177 struct drm_device *drm_dev = data;
1178 struct exynos_drm_plane *exynos_plane;
1179 enum drm_plane_type type;
1183 ret = mixer_initialize(ctx, drm_dev);
1187 for (zpos = 0; zpos < MIXER_WIN_NR; zpos++) {
1188 type = (zpos == MIXER_DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY :
1189 DRM_PLANE_TYPE_OVERLAY;
1190 ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
1191 1 << ctx->pipe, type, zpos);
1196 exynos_plane = &ctx->planes[MIXER_DEFAULT_WIN];
1197 ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
1198 ctx->pipe, EXYNOS_DISPLAY_TYPE_HDMI,
1199 &mixer_crtc_ops, ctx);
1200 if (IS_ERR(ctx->crtc)) {
1201 mixer_ctx_remove(ctx);
1202 ret = PTR_ERR(ctx->crtc);
1209 devm_kfree(dev, ctx);
1213 static void mixer_unbind(struct device *dev, struct device *master, void *data)
1215 struct mixer_context *ctx = dev_get_drvdata(dev);
1217 mixer_ctx_remove(ctx);
1220 static const struct component_ops mixer_component_ops = {
1222 .unbind = mixer_unbind,
1225 static int mixer_probe(struct platform_device *pdev)
1227 struct device *dev = &pdev->dev;
1228 struct mixer_drv_data *drv;
1229 struct mixer_context *ctx;
1232 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1234 DRM_ERROR("failed to alloc mixer context.\n");
1238 mutex_init(&ctx->mixer_mutex);
1241 const struct of_device_id *match;
1243 match = of_match_node(mixer_match_types, dev->of_node);
1244 drv = (struct mixer_drv_data *)match->data;
1246 drv = (struct mixer_drv_data *)
1247 platform_get_device_id(pdev)->driver_data;
1252 ctx->vp_enabled = drv->is_vp_enabled;
1253 ctx->has_sclk = drv->has_sclk;
1254 ctx->mxr_ver = drv->version;
1255 init_waitqueue_head(&ctx->wait_vsync_queue);
1256 atomic_set(&ctx->wait_vsync_event, 0);
1258 platform_set_drvdata(pdev, ctx);
1260 ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
1261 EXYNOS_DISPLAY_TYPE_HDMI);
1265 ret = component_add(&pdev->dev, &mixer_component_ops);
1267 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
1271 pm_runtime_enable(dev);
1276 static int mixer_remove(struct platform_device *pdev)
1278 pm_runtime_disable(&pdev->dev);
1280 component_del(&pdev->dev, &mixer_component_ops);
1281 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
1286 struct platform_driver mixer_driver = {
1288 .name = "exynos-mixer",
1289 .owner = THIS_MODULE,
1290 .of_match_table = mixer_match_types,
1292 .probe = mixer_probe,
1293 .remove = mixer_remove,
1294 .id_table = mixer_driver_types,