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 *saved_mixer_regs;
68 void __iomem *vp_regs;
69 void __iomem *saved_vp_regs;
73 struct clk *sclk_mixer;
74 struct clk *sclk_hdmi;
75 struct clk *sclk_pixel;
79 struct mixer_context {
86 struct mutex mixer_mutex;
87 struct mixer_resources mixer_res;
88 struct hdmi_win_data win_data[MIXER_WIN_NR];
91 static const u8 filter_y_horiz_tap8[] = {
92 0, -1, -1, -1, -1, -1, -1, -1,
93 -1, -1, -1, -1, -1, 0, 0, 0,
94 0, 2, 4, 5, 6, 6, 6, 6,
95 6, 5, 5, 4, 3, 2, 1, 1,
96 0, -6, -12, -16, -18, -20, -21, -20,
97 -20, -18, -16, -13, -10, -8, -5, -2,
98 127, 126, 125, 121, 114, 107, 99, 89,
99 79, 68, 57, 46, 35, 25, 16, 8,
102 static const u8 filter_y_vert_tap4[] = {
103 0, -3, -6, -8, -8, -8, -8, -7,
104 -6, -5, -4, -3, -2, -1, -1, 0,
105 127, 126, 124, 118, 111, 102, 92, 81,
106 70, 59, 48, 37, 27, 19, 11, 5,
107 0, 5, 11, 19, 27, 37, 48, 59,
108 70, 81, 92, 102, 111, 118, 124, 126,
109 0, 0, -1, -1, -2, -3, -4, -5,
110 -6, -7, -8, -8, -8, -8, -6, -3,
113 static const u8 filter_cr_horiz_tap4[] = {
114 0, -3, -6, -8, -8, -8, -8, -7,
115 -6, -5, -4, -3, -2, -1, -1, 0,
116 127, 126, 124, 118, 111, 102, 92, 81,
117 70, 59, 48, 37, 27, 19, 11, 5,
120 static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
122 return readl(res->vp_regs + reg_id);
125 static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
128 writel(val, res->vp_regs + reg_id);
131 static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
134 u32 old = vp_reg_read(res, reg_id);
136 val = (val & mask) | (old & ~mask);
137 writel(val, res->vp_regs + reg_id);
140 static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
142 return readl(res->mixer_regs + reg_id);
145 static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
148 writel(val, res->mixer_regs + reg_id);
151 static inline void mixer_reg_writemask(struct mixer_resources *res,
152 u32 reg_id, u32 val, u32 mask)
154 u32 old = mixer_reg_read(res, reg_id);
156 val = (val & mask) | (old & ~mask);
157 writel(val, res->mixer_regs + reg_id);
160 static void mixer_regs_dump(struct mixer_context *ctx)
162 #define DUMPREG(reg_id) \
164 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
165 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
171 DUMPREG(MXR_INT_STATUS);
173 DUMPREG(MXR_LAYER_CFG);
174 DUMPREG(MXR_VIDEO_CFG);
176 DUMPREG(MXR_GRAPHIC0_CFG);
177 DUMPREG(MXR_GRAPHIC0_BASE);
178 DUMPREG(MXR_GRAPHIC0_SPAN);
179 DUMPREG(MXR_GRAPHIC0_WH);
180 DUMPREG(MXR_GRAPHIC0_SXY);
181 DUMPREG(MXR_GRAPHIC0_DXY);
183 DUMPREG(MXR_GRAPHIC1_CFG);
184 DUMPREG(MXR_GRAPHIC1_BASE);
185 DUMPREG(MXR_GRAPHIC1_SPAN);
186 DUMPREG(MXR_GRAPHIC1_WH);
187 DUMPREG(MXR_GRAPHIC1_SXY);
188 DUMPREG(MXR_GRAPHIC1_DXY);
192 static void vp_regs_dump(struct mixer_context *ctx)
194 #define DUMPREG(reg_id) \
196 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
197 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
202 DUMPREG(VP_SHADOW_UPDATE);
203 DUMPREG(VP_FIELD_ID);
205 DUMPREG(VP_IMG_SIZE_Y);
206 DUMPREG(VP_IMG_SIZE_C);
207 DUMPREG(VP_PER_RATE_CTRL);
208 DUMPREG(VP_TOP_Y_PTR);
209 DUMPREG(VP_BOT_Y_PTR);
210 DUMPREG(VP_TOP_C_PTR);
211 DUMPREG(VP_BOT_C_PTR);
212 DUMPREG(VP_ENDIAN_MODE);
213 DUMPREG(VP_SRC_H_POSITION);
214 DUMPREG(VP_SRC_V_POSITION);
215 DUMPREG(VP_SRC_WIDTH);
216 DUMPREG(VP_SRC_HEIGHT);
217 DUMPREG(VP_DST_H_POSITION);
218 DUMPREG(VP_DST_V_POSITION);
219 DUMPREG(VP_DST_WIDTH);
220 DUMPREG(VP_DST_HEIGHT);
227 static inline void vp_filter_set(struct mixer_resources *res,
228 int reg_id, const u8 *data, unsigned int size)
230 /* assure 4-byte align */
232 for (; size; size -= 4, reg_id += 4, data += 4) {
233 u32 val = (data[0] << 24) | (data[1] << 16) |
234 (data[2] << 8) | data[3];
235 vp_reg_write(res, reg_id, val);
239 static void vp_default_filter(struct mixer_resources *res)
241 vp_filter_set(res, VP_POLY8_Y0_LL,
242 filter_y_horiz_tap8, sizeof filter_y_horiz_tap8);
243 vp_filter_set(res, VP_POLY4_Y0_LL,
244 filter_y_vert_tap4, sizeof filter_y_vert_tap4);
245 vp_filter_set(res, VP_POLY4_C0_LL,
246 filter_cr_horiz_tap4, sizeof filter_cr_horiz_tap4);
249 static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
251 struct mixer_resources *res = &ctx->mixer_res;
253 /* block update on vsync */
254 mixer_reg_writemask(res, MXR_STATUS, enable ?
255 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
257 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
258 VP_SHADOW_UPDATE_ENABLE : 0);
261 static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
263 struct mixer_resources *res = &ctx->mixer_res;
266 /* choosing between interlace and progressive mode */
267 val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
268 MXR_CFG_SCAN_PROGRASSIVE);
270 /* choosing between porper HD and SD mode */
272 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
273 else if (height == 576)
274 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
275 else if (height == 720)
276 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
277 else if (height == 1080)
278 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
280 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
282 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
285 static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
287 struct mixer_resources *res = &ctx->mixer_res;
291 val = MXR_CFG_RGB601_0_255;
292 } else if (height == 576) {
293 val = MXR_CFG_RGB601_0_255;
294 } else if (height == 720) {
295 val = MXR_CFG_RGB709_16_235;
296 mixer_reg_write(res, MXR_CM_COEFF_Y,
297 (1 << 30) | (94 << 20) | (314 << 10) |
299 mixer_reg_write(res, MXR_CM_COEFF_CB,
300 (972 << 20) | (851 << 10) | (225 << 0));
301 mixer_reg_write(res, MXR_CM_COEFF_CR,
302 (225 << 20) | (820 << 10) | (1004 << 0));
303 } else if (height == 1080) {
304 val = MXR_CFG_RGB709_16_235;
305 mixer_reg_write(res, MXR_CM_COEFF_Y,
306 (1 << 30) | (94 << 20) | (314 << 10) |
308 mixer_reg_write(res, MXR_CM_COEFF_CB,
309 (972 << 20) | (851 << 10) | (225 << 0));
310 mixer_reg_write(res, MXR_CM_COEFF_CR,
311 (225 << 20) | (820 << 10) | (1004 << 0));
313 val = MXR_CFG_RGB709_16_235;
314 mixer_reg_write(res, MXR_CM_COEFF_Y,
315 (1 << 30) | (94 << 20) | (314 << 10) |
317 mixer_reg_write(res, MXR_CM_COEFF_CB,
318 (972 << 20) | (851 << 10) | (225 << 0));
319 mixer_reg_write(res, MXR_CM_COEFF_CR,
320 (225 << 20) | (820 << 10) | (1004 << 0));
323 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
326 static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable)
328 struct mixer_resources *res = &ctx->mixer_res;
329 u32 val = enable ? ~0 : 0;
333 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
336 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
339 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
340 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_VP_ENABLE);
345 static void mixer_run(struct mixer_context *ctx)
347 struct mixer_resources *res = &ctx->mixer_res;
349 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
351 mixer_regs_dump(ctx);
354 static void vp_video_buffer(struct mixer_context *ctx, int win)
356 struct mixer_resources *res = &ctx->mixer_res;
358 struct hdmi_win_data *win_data;
359 unsigned int x_ratio, y_ratio;
360 unsigned int buf_num;
361 dma_addr_t luma_addr[2], chroma_addr[2];
362 bool tiled_mode = false;
363 bool crcb_mode = false;
366 win_data = &ctx->win_data[win];
368 switch (win_data->pixel_format) {
369 case DRM_FORMAT_NV12MT:
371 case DRM_FORMAT_NV12M:
375 /* TODO: single buffer format NV12, NV21 */
377 /* ignore pixel format at disable time */
378 if (!win_data->dma_addr)
381 DRM_ERROR("pixel format for vp is wrong [%d].\n",
382 win_data->pixel_format);
386 /* scaling feature: (src << 16) / dst */
387 x_ratio = (win_data->src_width << 16) / win_data->crtc_width;
388 y_ratio = (win_data->src_height << 16) / win_data->crtc_height;
391 luma_addr[0] = win_data->dma_addr;
392 chroma_addr[0] = win_data->chroma_dma_addr;
394 luma_addr[0] = win_data->dma_addr;
395 chroma_addr[0] = win_data->dma_addr
396 + (win_data->fb_width * win_data->fb_height);
399 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) {
400 ctx->interlace = true;
402 luma_addr[1] = luma_addr[0] + 0x40;
403 chroma_addr[1] = chroma_addr[0] + 0x40;
405 luma_addr[1] = luma_addr[0] + win_data->fb_width;
406 chroma_addr[1] = chroma_addr[0] + win_data->fb_width;
409 ctx->interlace = false;
414 spin_lock_irqsave(&res->reg_slock, flags);
415 mixer_vsync_set_update(ctx, false);
417 /* interlace or progressive scan mode */
418 val = (ctx->interlace ? ~0 : 0);
419 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
422 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
423 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
424 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
426 /* setting size of input image */
427 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_width) |
428 VP_IMG_VSIZE(win_data->fb_height));
429 /* chroma height has to reduced by 2 to avoid chroma distorions */
430 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(win_data->fb_width) |
431 VP_IMG_VSIZE(win_data->fb_height / 2));
433 vp_reg_write(res, VP_SRC_WIDTH, win_data->src_width);
434 vp_reg_write(res, VP_SRC_HEIGHT, win_data->src_height);
435 vp_reg_write(res, VP_SRC_H_POSITION,
436 VP_SRC_H_POSITION_VAL(win_data->fb_x));
437 vp_reg_write(res, VP_SRC_V_POSITION, win_data->fb_y);
439 vp_reg_write(res, VP_DST_WIDTH, win_data->crtc_width);
440 vp_reg_write(res, VP_DST_H_POSITION, win_data->crtc_x);
441 if (ctx->interlace) {
442 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height / 2);
443 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y / 2);
445 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height);
446 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y);
449 vp_reg_write(res, VP_H_RATIO, x_ratio);
450 vp_reg_write(res, VP_V_RATIO, y_ratio);
452 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
454 /* set buffer address to vp */
455 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
456 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
457 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
458 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
460 mixer_cfg_scan(ctx, win_data->mode_height);
461 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
462 mixer_cfg_layer(ctx, win, true);
465 mixer_vsync_set_update(ctx, true);
466 spin_unlock_irqrestore(&res->reg_slock, flags);
471 static void mixer_graph_buffer(struct mixer_context *ctx, int win)
473 struct mixer_resources *res = &ctx->mixer_res;
475 struct hdmi_win_data *win_data;
476 unsigned int x_ratio, y_ratio;
477 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
482 win_data = &ctx->win_data[win];
489 switch (win_data->bpp) {
500 /* 2x scaling feature */
504 dst_x_offset = win_data->crtc_x;
505 dst_y_offset = win_data->crtc_y;
507 /* converting dma address base and source offset */
508 dma_addr = win_data->dma_addr
509 + (win_data->fb_x * win_data->bpp >> 3)
510 + (win_data->fb_y * win_data->fb_width * win_data->bpp >> 3);
514 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE)
515 ctx->interlace = true;
517 ctx->interlace = false;
519 spin_lock_irqsave(&res->reg_slock, flags);
520 mixer_vsync_set_update(ctx, false);
523 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
524 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
527 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), win_data->fb_width);
529 val = MXR_GRP_WH_WIDTH(win_data->crtc_width);
530 val |= MXR_GRP_WH_HEIGHT(win_data->crtc_height);
531 val |= MXR_GRP_WH_H_SCALE(x_ratio);
532 val |= MXR_GRP_WH_V_SCALE(y_ratio);
533 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
535 /* setup offsets in source image */
536 val = MXR_GRP_SXY_SX(src_x_offset);
537 val |= MXR_GRP_SXY_SY(src_y_offset);
538 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
540 /* setup offsets in display image */
541 val = MXR_GRP_DXY_DX(dst_x_offset);
542 val |= MXR_GRP_DXY_DY(dst_y_offset);
543 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
545 /* set buffer address to mixer */
546 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
548 mixer_cfg_scan(ctx, win_data->mode_height);
549 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
550 mixer_cfg_layer(ctx, win, true);
553 mixer_vsync_set_update(ctx, true);
554 spin_unlock_irqrestore(&res->reg_slock, flags);
557 static void vp_win_reset(struct mixer_context *ctx)
559 struct mixer_resources *res = &ctx->mixer_res;
562 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
563 for (tries = 100; tries; --tries) {
564 /* waiting until VP_SRESET_PROCESSING is 0 */
565 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
569 WARN(tries == 0, "failed to reset Video Processor\n");
572 static void mixer_win_reset(struct mixer_context *ctx)
574 struct mixer_resources *res = &ctx->mixer_res;
576 u32 val; /* value stored to register */
578 spin_lock_irqsave(&res->reg_slock, flags);
579 mixer_vsync_set_update(ctx, false);
581 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
583 /* set output in RGB888 mode */
584 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
586 /* 16 beat burst in DMA */
587 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
588 MXR_STATUS_BURST_MASK);
590 /* setting default layer priority: layer1 > layer0 > video
591 * because typical usage scenario would be
593 * layer0 - framebuffer
594 * video - video overlay
596 val = MXR_LAYER_CFG_GRP1_VAL(3);
597 val |= MXR_LAYER_CFG_GRP0_VAL(2);
598 val |= MXR_LAYER_CFG_VP_VAL(1);
599 mixer_reg_write(res, MXR_LAYER_CFG, val);
601 /* setting background color */
602 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
603 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
604 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
606 /* setting graphical layers */
607 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
608 val |= MXR_GRP_CFG_WIN_BLEND_EN;
609 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
610 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
611 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
613 /* the same configuration for both layers */
614 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
615 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
617 /* setting video layers */
618 val = MXR_GRP_CFG_ALPHA_VAL(0);
619 mixer_reg_write(res, MXR_VIDEO_CFG, val);
621 /* configuration of Video Processor Registers */
623 vp_default_filter(res);
625 /* disable all layers */
626 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
627 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
628 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
630 mixer_vsync_set_update(ctx, true);
631 spin_unlock_irqrestore(&res->reg_slock, flags);
634 static void mixer_poweron(struct mixer_context *ctx)
636 struct mixer_resources *res = &ctx->mixer_res;
638 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
640 mutex_lock(&ctx->mixer_mutex);
642 mutex_unlock(&ctx->mixer_mutex);
646 mutex_unlock(&ctx->mixer_mutex);
648 res->mixer_regs = res->saved_mixer_regs;
649 res->vp_regs = res->saved_vp_regs;
651 pm_runtime_get_sync(ctx->dev);
653 clk_enable(res->mixer);
655 clk_enable(res->sclk_mixer);
657 mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
658 mixer_win_reset(ctx);
661 static void vp_cleanup(struct mixer_context *ctx)
663 struct mixer_resources *res = &ctx->mixer_res;
664 int val, retries = 200;
666 DRM_DEBUG_KMS("%s\n", __func__);
668 vp_reg_writemask(res, VP_ENABLE, 0, VP_ENABLE_ON);
671 val = vp_reg_read(res, VP_ENABLE);
672 } while (!(val & VP_ENABLE_OPERATING) && retries--);
675 DRM_ERROR("vp disable failed.\n");
677 /* clean buffer address to vp */
678 vp_reg_write(res, VP_TOP_Y_PTR, 0);
679 vp_reg_write(res, VP_BOT_Y_PTR, 0);
680 vp_reg_write(res, VP_TOP_C_PTR, 0);
681 vp_reg_write(res, VP_BOT_C_PTR, 0);
684 static void mixer_cleanup(struct mixer_context *ctx)
686 struct mixer_resources *res = &ctx->mixer_res;
687 int val, retries = 200;
689 DRM_DEBUG_KMS("%s\n", __func__);
692 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
695 mixer_reg_writemask(res, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
698 val = mixer_reg_read(res, MXR_STATUS);
699 } while (!(val & MXR_STATUS_IDLE_MODE) && retries--);
702 DRM_ERROR("mixer disable failed.\n");
705 static void mixer_poweroff(struct mixer_context *ctx)
707 struct mixer_resources *res = &ctx->mixer_res;
710 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
712 mutex_lock(&ctx->mixer_mutex);
715 mutex_unlock(&ctx->mixer_mutex);
717 spin_lock_irqsave(&res->reg_slock, flags);
719 ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
720 mixer_vsync_set_update(ctx, false);
725 spin_unlock_irqrestore(&res->reg_slock, flags);
727 /* HDMI changed sclk_hdmi parent clock from pixel to hdmiphy */
728 clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
730 clk_disable(res->mixer);
731 clk_disable(res->vp);
732 clk_disable(res->sclk_mixer);
734 res->mixer_regs = NULL;
737 pm_runtime_put_sync(ctx->dev);
739 mutex_lock(&ctx->mixer_mutex);
740 ctx->powered = false;
743 mutex_unlock(&ctx->mixer_mutex);
746 static int mixer_enable_vblank(void *ctx, int pipe)
748 struct mixer_context *mixer_ctx = ctx;
749 struct mixer_resources *res = &mixer_ctx->mixer_res;
751 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
753 mixer_ctx->pipe = pipe;
755 /* enable vsync interrupt */
756 mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
762 static void mixer_disable_vblank(void *ctx)
764 struct mixer_context *mixer_ctx = ctx;
765 struct mixer_resources *res = &mixer_ctx->mixer_res;
767 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
769 /* disable vsync interrupt */
770 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
773 static void mixer_dpms(void *ctx, int mode)
775 struct mixer_context *mixer_ctx = ctx;
777 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
780 case DRM_MODE_DPMS_ON:
781 mixer_poweron(mixer_ctx);
783 case DRM_MODE_DPMS_STANDBY:
784 case DRM_MODE_DPMS_SUSPEND:
785 case DRM_MODE_DPMS_OFF:
786 mixer_poweroff(mixer_ctx);
789 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
794 static void mixer_wait_for_vblank(void *ctx)
796 struct mixer_context *mixer_ctx = ctx;
797 struct mixer_resources *res = &mixer_ctx->mixer_res;
800 ret = wait_for((mixer_reg_read(res, MXR_INT_STATUS) &
801 MXR_INT_STATUS_VSYNC), 50);
803 DRM_DEBUG_KMS("vblank wait timed out.\n");
806 static void mixer_win_mode_set(void *ctx,
807 struct exynos_drm_overlay *overlay)
809 struct mixer_context *mixer_ctx = ctx;
810 struct hdmi_win_data *win_data;
813 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
816 DRM_ERROR("overlay is NULL\n");
820 DRM_DEBUG_KMS("set [%d]x[%d] at (%d,%d) to [%d]x[%d] at (%d,%d)\n",
821 overlay->fb_width, overlay->fb_height,
822 overlay->fb_x, overlay->fb_y,
823 overlay->crtc_width, overlay->crtc_height,
824 overlay->crtc_x, overlay->crtc_y);
827 if (win == DEFAULT_ZPOS)
828 win = MIXER_DEFAULT_WIN;
830 if (win < 0 || win > MIXER_WIN_NR) {
831 DRM_ERROR("mixer window[%d] is wrong\n", win);
835 win_data = &mixer_ctx->win_data[win];
837 win_data->dma_addr = overlay->dma_addr[0];
838 win_data->vaddr = overlay->vaddr[0];
839 win_data->chroma_dma_addr = overlay->dma_addr[1];
840 win_data->chroma_vaddr = overlay->vaddr[1];
841 win_data->pixel_format = overlay->pixel_format;
842 win_data->bpp = overlay->bpp;
844 win_data->crtc_x = overlay->crtc_x;
845 win_data->crtc_y = overlay->crtc_y;
846 win_data->crtc_width = overlay->crtc_width;
847 win_data->crtc_height = overlay->crtc_height;
849 win_data->fb_x = overlay->fb_x;
850 win_data->fb_y = overlay->fb_y;
851 win_data->fb_width = overlay->fb_width;
852 win_data->fb_height = overlay->fb_height;
853 win_data->src_width = overlay->src_width;
854 win_data->src_height = overlay->src_height;
856 win_data->mode_width = overlay->mode_width;
857 win_data->mode_height = overlay->mode_height;
859 win_data->scan_flags = overlay->scan_flag;
862 static void mixer_win_commit(void *ctx, int win)
864 struct mixer_context *mixer_ctx = ctx;
866 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
869 vp_video_buffer(mixer_ctx, win);
871 mixer_graph_buffer(mixer_ctx, win);
874 static void mixer_win_disable(void *ctx, int win)
876 struct mixer_context *mixer_ctx = ctx;
877 struct mixer_resources *res = &mixer_ctx->mixer_res;
880 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
882 spin_lock_irqsave(&res->reg_slock, flags);
883 mixer_vsync_set_update(mixer_ctx, false);
885 mixer_cfg_layer(mixer_ctx, win, false);
887 mixer_vsync_set_update(mixer_ctx, true);
888 spin_unlock_irqrestore(&res->reg_slock, flags);
891 static struct exynos_mixer_ops mixer_ops = {
893 .enable_vblank = mixer_enable_vblank,
894 .disable_vblank = mixer_disable_vblank,
898 .wait_for_vblank = mixer_wait_for_vblank,
899 .win_mode_set = mixer_win_mode_set,
900 .win_commit = mixer_win_commit,
901 .win_disable = mixer_win_disable,
904 /* for pageflip event */
905 static void mixer_finish_pageflip(struct drm_device *drm_dev, int crtc)
907 struct exynos_drm_private *dev_priv = drm_dev->dev_private;
908 struct drm_pending_vblank_event *e, *t;
911 bool is_checked = false;
913 spin_lock_irqsave(&drm_dev->event_lock, flags);
915 list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
917 /* if event's pipe isn't same as crtc then ignore it. */
922 do_gettimeofday(&now);
923 e->event.sequence = 0;
924 e->event.tv_sec = now.tv_sec;
925 e->event.tv_usec = now.tv_usec;
927 list_move_tail(&e->base.link, &e->base.file_priv->event_list);
928 wake_up_interruptible(&e->base.file_priv->event_wait);
933 * call drm_vblank_put only in case that drm_vblank_get was
936 if (atomic_read(&drm_dev->vblank_refcount[crtc]) > 0)
937 drm_vblank_put(drm_dev, crtc);
939 spin_unlock_irqrestore(&drm_dev->event_lock, flags);
942 static irqreturn_t mixer_irq_handler(int irq, void *arg)
944 struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg;
945 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
946 struct mixer_resources *res = &ctx->mixer_res;
947 u32 val, base, shadow;
949 spin_lock(&res->reg_slock);
952 spin_unlock(&res->reg_slock);
956 /* read interrupt status for handling and clearing flags for VSYNC */
957 val = mixer_reg_read(res, MXR_INT_STATUS);
960 if (val & MXR_INT_STATUS_VSYNC) {
961 /* interlace scan need to check shadow register */
962 if (ctx->interlace) {
963 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
964 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
968 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
969 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
974 drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe);
975 mixer_finish_pageflip(drm_hdmi_ctx->drm_dev, ctx->pipe);
979 /* clear interrupts */
980 if (~val & MXR_INT_EN_VSYNC) {
981 /* vsync interrupt use different bit for read and clear */
982 val &= ~MXR_INT_EN_VSYNC;
983 val |= MXR_INT_CLEAR_VSYNC;
985 mixer_reg_write(res, MXR_INT_STATUS, val);
987 spin_unlock(&res->reg_slock);
992 static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
993 struct platform_device *pdev)
995 struct mixer_context *mixer_ctx = ctx->ctx;
996 struct device *dev = &pdev->dev;
997 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
998 struct resource *res;
1001 spin_lock_init(&mixer_res->reg_slock);
1003 mixer_res->mixer = clk_get(dev, "mixer");
1004 if (IS_ERR_OR_NULL(mixer_res->mixer)) {
1005 dev_err(dev, "failed to get clock 'mixer'\n");
1009 mixer_res->vp = clk_get(dev, "vp");
1010 if (IS_ERR_OR_NULL(mixer_res->vp)) {
1011 dev_err(dev, "failed to get clock 'vp'\n");
1015 mixer_res->sclk_mixer = clk_get(dev, "sclk_mixer");
1016 if (IS_ERR_OR_NULL(mixer_res->sclk_mixer)) {
1017 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
1021 mixer_res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
1022 if (IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) {
1023 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
1027 mixer_res->sclk_pixel = clk_get(dev, "sclk_pixel");
1028 if (IS_ERR_OR_NULL(mixer_res->sclk_pixel)) {
1029 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
1032 mixer_res->sclk_dac = clk_get(dev, "sclk_dac");
1033 if (IS_ERR_OR_NULL(mixer_res->sclk_dac)) {
1034 dev_err(dev, "failed to get clock 'sclk_dac'\n");
1038 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr");
1040 dev_err(dev, "get memory resource failed.\n");
1045 clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
1047 mixer_res->mixer_regs = ioremap(res->start, resource_size(res));
1048 if (mixer_res->mixer_regs == NULL) {
1049 dev_err(dev, "register mapping failed.\n");
1053 mixer_res->saved_mixer_regs = mixer_res->mixer_regs;
1055 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp");
1057 dev_err(dev, "get memory resource failed.\n");
1059 goto fail_mixer_regs;
1062 mixer_res->vp_regs = ioremap(res->start, resource_size(res));
1063 if (mixer_res->vp_regs == NULL) {
1064 dev_err(dev, "register mapping failed.\n");
1066 goto fail_mixer_regs;
1068 mixer_res->saved_vp_regs = mixer_res->vp_regs;
1070 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq");
1072 dev_err(dev, "get interrupt resource failed.\n");
1077 ret = request_irq(res->start, mixer_irq_handler, 0, "drm_mixer", ctx);
1079 dev_err(dev, "request interrupt failed.\n");
1082 mixer_res->irq = res->start;
1087 iounmap(mixer_res->vp_regs);
1090 iounmap(mixer_res->mixer_regs);
1093 if (!IS_ERR_OR_NULL(mixer_res->sclk_dac))
1094 clk_put(mixer_res->sclk_dac);
1095 if (!IS_ERR_OR_NULL(mixer_res->sclk_hdmi))
1096 clk_put(mixer_res->sclk_hdmi);
1097 if (!IS_ERR_OR_NULL(mixer_res->sclk_pixel))
1098 clk_put(mixer_res->sclk_pixel);
1099 if (!IS_ERR_OR_NULL(mixer_res->sclk_mixer))
1100 clk_put(mixer_res->sclk_mixer);
1101 if (!IS_ERR_OR_NULL(mixer_res->vp))
1102 clk_put(mixer_res->vp);
1103 if (!IS_ERR_OR_NULL(mixer_res->mixer))
1104 clk_put(mixer_res->mixer);
1108 static void mixer_resources_cleanup(struct mixer_context *ctx)
1110 struct mixer_resources *res = &ctx->mixer_res;
1112 free_irq(res->irq, ctx);
1114 if (!IS_ERR_OR_NULL(res->sclk_dac))
1115 clk_put(res->sclk_dac);
1116 if (!IS_ERR_OR_NULL(res->sclk_hdmi))
1117 clk_put(res->sclk_hdmi);
1118 if (!IS_ERR_OR_NULL(res->sclk_pixel))
1119 clk_put(res->sclk_pixel);
1120 if (!IS_ERR_OR_NULL(res->sclk_mixer))
1121 clk_put(res->sclk_mixer);
1122 if (!IS_ERR_OR_NULL(res->vp))
1124 if (!IS_ERR_OR_NULL(res->mixer))
1125 clk_put(res->mixer);
1127 iounmap(res->vp_regs);
1128 iounmap(res->mixer_regs);
1131 static int __devinit mixer_probe(struct platform_device *pdev)
1133 struct device *dev = &pdev->dev;
1134 struct exynos_drm_hdmi_context *drm_hdmi_ctx;
1135 struct mixer_context *ctx;
1138 dev_info(dev, "probe start\n");
1140 drm_hdmi_ctx = kzalloc(sizeof(*drm_hdmi_ctx), GFP_KERNEL);
1141 if (!drm_hdmi_ctx) {
1142 DRM_ERROR("failed to allocate common hdmi context.\n");
1146 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
1148 DRM_ERROR("failed to alloc mixer context.\n");
1149 kfree(drm_hdmi_ctx);
1153 mutex_init(&ctx->mixer_mutex);
1155 ctx->dev = &pdev->dev;
1156 drm_hdmi_ctx->ctx = (void *)ctx;
1158 platform_set_drvdata(pdev, drm_hdmi_ctx);
1160 /* acquire resources: regs, irqs, clocks */
1161 ret = mixer_resources_init(drm_hdmi_ctx, pdev);
1165 /* register specific callback point to common hdmi. */
1166 exynos_mixer_ops_register(&mixer_ops);
1168 pm_runtime_enable(dev);
1174 dev_info(dev, "probe failed\n");
1178 static int mixer_remove(struct platform_device *pdev)
1180 struct device *dev = &pdev->dev;
1181 struct exynos_drm_hdmi_context *drm_hdmi_ctx =
1182 platform_get_drvdata(pdev);
1183 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
1185 dev_info(dev, "remove successful\n");
1187 pm_runtime_disable(&pdev->dev);
1189 mixer_resources_cleanup(ctx);
1194 #ifdef CONFIG_PM_SLEEP
1195 static int mixer_suspend(struct device *dev)
1197 struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
1198 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
1200 mixer_poweroff(ctx);
1206 static SIMPLE_DEV_PM_OPS(mixer_pm_ops, mixer_suspend, NULL);
1208 struct platform_driver mixer_driver = {
1210 .name = "s5p-mixer",
1211 .owner = THIS_MODULE,
1212 .pm = &mixer_pm_ops,
1214 .probe = mixer_probe,
1215 .remove = __devexit_p(mixer_remove),