drm/exynos: remove exynos_mixer.h
[deliverable/linux.git] / drivers / gpu / drm / exynos / exynos_mixer.c
CommitLineData
d8408326
SWK
1/*
2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
3 * Authors:
4 * Seung-Woo Kim <sw0312.kim@samsung.com>
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 *
8 * Based on drivers/media/video/s5p-tv/mixer_reg.c
9 *
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.
14 *
15 */
16
17#include "drmP.h"
18
19#include "regs-mixer.h"
20#include "regs-vp.h"
21
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>
34
35#include <drm/exynos_drm.h>
36
37#include "exynos_drm_drv.h"
38#include "exynos_drm_hdmi.h"
39#include "exynos_hdmi.h"
22b21ae6
JS
40
41#define HDMI_OVERLAY_NUMBER 3
d8408326
SWK
42
43#define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev))
44
22b21ae6
JS
45struct hdmi_win_data {
46 dma_addr_t dma_addr;
47 void __iomem *vaddr;
48 dma_addr_t chroma_dma_addr;
49 void __iomem *chroma_vaddr;
50 uint32_t pixel_format;
51 unsigned int bpp;
52 unsigned int crtc_x;
53 unsigned int crtc_y;
54 unsigned int crtc_width;
55 unsigned int crtc_height;
56 unsigned int fb_x;
57 unsigned int fb_y;
58 unsigned int fb_width;
59 unsigned int fb_height;
60 unsigned int mode_width;
61 unsigned int mode_height;
62 unsigned int scan_flags;
63};
64
65struct mixer_resources {
66 struct device *dev;
67 int irq;
68 void __iomem *mixer_regs;
69 void __iomem *vp_regs;
70 spinlock_t reg_slock;
71 struct clk *mixer;
72 struct clk *vp;
73 struct clk *sclk_mixer;
74 struct clk *sclk_hdmi;
75 struct clk *sclk_dac;
76};
77
78struct mixer_context {
79 struct fb_videomode *default_timing;
80 unsigned int default_win;
81 unsigned int default_bpp;
82 unsigned int irq;
83 int pipe;
84 bool interlace;
85 bool vp_enabled;
86
87 struct mixer_resources mixer_res;
88 struct hdmi_win_data win_data[HDMI_OVERLAY_NUMBER];
89};
90
d8408326
SWK
91static 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,
100};
101
102static 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,
111};
112
113static 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,
118};
119
120static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
121{
122 return readl(res->vp_regs + reg_id);
123}
124
125static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
126 u32 val)
127{
128 writel(val, res->vp_regs + reg_id);
129}
130
131static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
132 u32 val, u32 mask)
133{
134 u32 old = vp_reg_read(res, reg_id);
135
136 val = (val & mask) | (old & ~mask);
137 writel(val, res->vp_regs + reg_id);
138}
139
140static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
141{
142 return readl(res->mixer_regs + reg_id);
143}
144
145static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
146 u32 val)
147{
148 writel(val, res->mixer_regs + reg_id);
149}
150
151static inline void mixer_reg_writemask(struct mixer_resources *res,
152 u32 reg_id, u32 val, u32 mask)
153{
154 u32 old = mixer_reg_read(res, reg_id);
155
156 val = (val & mask) | (old & ~mask);
157 writel(val, res->mixer_regs + reg_id);
158}
159
160static void mixer_regs_dump(struct mixer_context *ctx)
161{
162#define DUMPREG(reg_id) \
163do { \
164 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
165 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
166} while (0)
167
168 DUMPREG(MXR_STATUS);
169 DUMPREG(MXR_CFG);
170 DUMPREG(MXR_INT_EN);
171 DUMPREG(MXR_INT_STATUS);
172
173 DUMPREG(MXR_LAYER_CFG);
174 DUMPREG(MXR_VIDEO_CFG);
175
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);
182
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);
189#undef DUMPREG
190}
191
192static void vp_regs_dump(struct mixer_context *ctx)
193{
194#define DUMPREG(reg_id) \
195do { \
196 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
197 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
198} while (0)
199
200 DUMPREG(VP_ENABLE);
201 DUMPREG(VP_SRESET);
202 DUMPREG(VP_SHADOW_UPDATE);
203 DUMPREG(VP_FIELD_ID);
204 DUMPREG(VP_MODE);
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);
221 DUMPREG(VP_H_RATIO);
222 DUMPREG(VP_V_RATIO);
223
224#undef DUMPREG
225}
226
227static inline void vp_filter_set(struct mixer_resources *res,
228 int reg_id, const u8 *data, unsigned int size)
229{
230 /* assure 4-byte align */
231 BUG_ON(size & 3);
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);
236 }
237}
238
239static void vp_default_filter(struct mixer_resources *res)
240{
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);
247}
248
249static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
250{
251 struct mixer_resources *res = &ctx->mixer_res;
252
253 /* block update on vsync */
254 mixer_reg_writemask(res, MXR_STATUS, enable ?
255 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
256
257 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
258 VP_SHADOW_UPDATE_ENABLE : 0);
259}
260
261static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
262{
263 struct mixer_resources *res = &ctx->mixer_res;
264 u32 val;
265
266 /* choosing between interlace and progressive mode */
267 val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
268 MXR_CFG_SCAN_PROGRASSIVE);
269
270 /* choosing between porper HD and SD mode */
271 if (height == 480)
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;
279 else
280 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
281
282 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
283}
284
285static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
286{
287 struct mixer_resources *res = &ctx->mixer_res;
288 u32 val;
289
290 if (height == 480) {
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) |
298 (32 << 0));
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) |
307 (32 << 0));
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));
312 } else {
313 val = MXR_CFG_RGB709_16_235;
314 mixer_reg_write(res, MXR_CM_COEFF_Y,
315 (1 << 30) | (94 << 20) | (314 << 10) |
316 (32 << 0));
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));
321 }
322
323 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
324}
325
326static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable)
327{
328 struct mixer_resources *res = &ctx->mixer_res;
329 u32 val = enable ? ~0 : 0;
330
331 switch (win) {
332 case 0:
333 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
334 break;
335 case 1:
336 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
337 break;
338 case 2:
339 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
340 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_VP_ENABLE);
341 break;
342 }
343}
344
345static void mixer_run(struct mixer_context *ctx)
346{
347 struct mixer_resources *res = &ctx->mixer_res;
348
349 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
350
351 mixer_regs_dump(ctx);
352}
353
354static void vp_video_buffer(struct mixer_context *ctx, int win)
355{
356 struct mixer_resources *res = &ctx->mixer_res;
357 unsigned long flags;
358 struct hdmi_win_data *win_data;
359 unsigned int full_width, full_height, width, height;
360 unsigned int x_ratio, y_ratio;
361 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
362 unsigned int mode_width, mode_height;
363 unsigned int buf_num;
364 dma_addr_t luma_addr[2], chroma_addr[2];
365 bool tiled_mode = false;
366 bool crcb_mode = false;
367 u32 val;
368
369 win_data = &ctx->win_data[win];
370
371 switch (win_data->pixel_format) {
372 case DRM_FORMAT_NV12MT:
373 tiled_mode = true;
374 case DRM_FORMAT_NV12M:
375 crcb_mode = false;
376 buf_num = 2;
377 break;
378 /* TODO: single buffer format NV12, NV21 */
379 default:
380 /* ignore pixel format at disable time */
381 if (!win_data->dma_addr)
382 break;
383
384 DRM_ERROR("pixel format for vp is wrong [%d].\n",
385 win_data->pixel_format);
386 return;
387 }
388
389 full_width = win_data->fb_width;
390 full_height = win_data->fb_height;
391 width = win_data->crtc_width;
392 height = win_data->crtc_height;
393 mode_width = win_data->mode_width;
394 mode_height = win_data->mode_height;
395
396 /* scaling feature: (src << 16) / dst */
397 x_ratio = (width << 16) / width;
398 y_ratio = (height << 16) / height;
399
400 src_x_offset = win_data->fb_x;
401 src_y_offset = win_data->fb_y;
402 dst_x_offset = win_data->crtc_x;
403 dst_y_offset = win_data->crtc_y;
404
405 if (buf_num == 2) {
406 luma_addr[0] = win_data->dma_addr;
407 chroma_addr[0] = win_data->chroma_dma_addr;
408 } else {
409 luma_addr[0] = win_data->dma_addr;
410 chroma_addr[0] = win_data->dma_addr
411 + (full_width * full_height);
412 }
413
414 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) {
415 ctx->interlace = true;
416 if (tiled_mode) {
417 luma_addr[1] = luma_addr[0] + 0x40;
418 chroma_addr[1] = chroma_addr[0] + 0x40;
419 } else {
420 luma_addr[1] = luma_addr[0] + full_width;
421 chroma_addr[1] = chroma_addr[0] + full_width;
422 }
423 } else {
424 ctx->interlace = false;
425 luma_addr[1] = 0;
426 chroma_addr[1] = 0;
427 }
428
429 spin_lock_irqsave(&res->reg_slock, flags);
430 mixer_vsync_set_update(ctx, false);
431
432 /* interlace or progressive scan mode */
433 val = (ctx->interlace ? ~0 : 0);
434 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
435
436 /* setup format */
437 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
438 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
439 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
440
441 /* setting size of input image */
442 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(full_width) |
443 VP_IMG_VSIZE(full_height));
444 /* chroma height has to reduced by 2 to avoid chroma distorions */
445 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(full_width) |
446 VP_IMG_VSIZE(full_height / 2));
447
448 vp_reg_write(res, VP_SRC_WIDTH, width);
449 vp_reg_write(res, VP_SRC_HEIGHT, height);
450 vp_reg_write(res, VP_SRC_H_POSITION,
451 VP_SRC_H_POSITION_VAL(src_x_offset));
452 vp_reg_write(res, VP_SRC_V_POSITION, src_y_offset);
453
454 vp_reg_write(res, VP_DST_WIDTH, width);
455 vp_reg_write(res, VP_DST_H_POSITION, dst_x_offset);
456 if (ctx->interlace) {
457 vp_reg_write(res, VP_DST_HEIGHT, height / 2);
458 vp_reg_write(res, VP_DST_V_POSITION, dst_y_offset / 2);
459 } else {
460 vp_reg_write(res, VP_DST_HEIGHT, height);
461 vp_reg_write(res, VP_DST_V_POSITION, dst_y_offset);
462 }
463
464 vp_reg_write(res, VP_H_RATIO, x_ratio);
465 vp_reg_write(res, VP_V_RATIO, y_ratio);
466
467 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
468
469 /* set buffer address to vp */
470 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
471 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
472 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
473 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
474
475 mixer_cfg_scan(ctx, mode_height);
476 mixer_cfg_rgb_fmt(ctx, mode_height);
477 mixer_cfg_layer(ctx, win, true);
478 mixer_run(ctx);
479
480 mixer_vsync_set_update(ctx, true);
481 spin_unlock_irqrestore(&res->reg_slock, flags);
482
483 vp_regs_dump(ctx);
484}
485
486static void mixer_graph_buffer(struct mixer_context *ctx, int win)
487{
488 struct mixer_resources *res = &ctx->mixer_res;
489 unsigned long flags;
490 struct hdmi_win_data *win_data;
491 unsigned int full_width, width, height;
492 unsigned int x_ratio, y_ratio;
493 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
494 unsigned int mode_width, mode_height;
495 dma_addr_t dma_addr;
496 unsigned int fmt;
497 u32 val;
498
499 win_data = &ctx->win_data[win];
500
501 #define RGB565 4
502 #define ARGB1555 5
503 #define ARGB4444 6
504 #define ARGB8888 7
505
506 switch (win_data->bpp) {
507 case 16:
508 fmt = ARGB4444;
509 break;
510 case 32:
511 fmt = ARGB8888;
512 break;
513 default:
514 fmt = ARGB8888;
515 }
516
517 dma_addr = win_data->dma_addr;
518 full_width = win_data->fb_width;
519 width = win_data->crtc_width;
520 height = win_data->crtc_height;
521 mode_width = win_data->mode_width;
522 mode_height = win_data->mode_height;
523
524 /* 2x scaling feature */
525 x_ratio = 0;
526 y_ratio = 0;
527
528 src_x_offset = win_data->fb_x;
529 src_y_offset = win_data->fb_y;
530 dst_x_offset = win_data->crtc_x;
531 dst_y_offset = win_data->crtc_y;
532
533 /* converting dma address base and source offset */
534 dma_addr = dma_addr
535 + (src_x_offset * win_data->bpp >> 3)
536 + (src_y_offset * full_width * win_data->bpp >> 3);
537 src_x_offset = 0;
538 src_y_offset = 0;
539
540 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE)
541 ctx->interlace = true;
542 else
543 ctx->interlace = false;
544
545 spin_lock_irqsave(&res->reg_slock, flags);
546 mixer_vsync_set_update(ctx, false);
547
548 /* setup format */
549 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
550 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
551
552 /* setup geometry */
553 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), full_width);
554
555 val = MXR_GRP_WH_WIDTH(width);
556 val |= MXR_GRP_WH_HEIGHT(height);
557 val |= MXR_GRP_WH_H_SCALE(x_ratio);
558 val |= MXR_GRP_WH_V_SCALE(y_ratio);
559 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
560
561 /* setup offsets in source image */
562 val = MXR_GRP_SXY_SX(src_x_offset);
563 val |= MXR_GRP_SXY_SY(src_y_offset);
564 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
565
566 /* setup offsets in display image */
567 val = MXR_GRP_DXY_DX(dst_x_offset);
568 val |= MXR_GRP_DXY_DY(dst_y_offset);
569 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
570
571 /* set buffer address to mixer */
572 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
573
574 mixer_cfg_scan(ctx, mode_height);
575 mixer_cfg_rgb_fmt(ctx, mode_height);
576 mixer_cfg_layer(ctx, win, true);
577 mixer_run(ctx);
578
579 mixer_vsync_set_update(ctx, true);
580 spin_unlock_irqrestore(&res->reg_slock, flags);
581}
582
583static void vp_win_reset(struct mixer_context *ctx)
584{
585 struct mixer_resources *res = &ctx->mixer_res;
586 int tries = 100;
587
588 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
589 for (tries = 100; tries; --tries) {
590 /* waiting until VP_SRESET_PROCESSING is 0 */
591 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
592 break;
593 mdelay(10);
594 }
595 WARN(tries == 0, "failed to reset Video Processor\n");
596}
597
598static int mixer_enable_vblank(void *ctx, int pipe)
599{
600 struct mixer_context *mixer_ctx = ctx;
601 struct mixer_resources *res = &mixer_ctx->mixer_res;
602
603 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
604
605 mixer_ctx->pipe = pipe;
606
607 /* enable vsync interrupt */
608 mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
609 MXR_INT_EN_VSYNC);
610
611 return 0;
612}
613
614static void mixer_disable_vblank(void *ctx)
615{
616 struct mixer_context *mixer_ctx = ctx;
617 struct mixer_resources *res = &mixer_ctx->mixer_res;
618
619 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
620
621 /* disable vsync interrupt */
622 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
623}
624
625static void mixer_win_mode_set(void *ctx,
626 struct exynos_drm_overlay *overlay)
627{
628 struct mixer_context *mixer_ctx = ctx;
629 struct hdmi_win_data *win_data;
630 int win;
631
632 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
633
634 if (!overlay) {
635 DRM_ERROR("overlay is NULL\n");
636 return;
637 }
638
639 DRM_DEBUG_KMS("set [%d]x[%d] at (%d,%d) to [%d]x[%d] at (%d,%d)\n",
640 overlay->fb_width, overlay->fb_height,
641 overlay->fb_x, overlay->fb_y,
642 overlay->crtc_width, overlay->crtc_height,
643 overlay->crtc_x, overlay->crtc_y);
644
645 win = overlay->zpos;
646 if (win == DEFAULT_ZPOS)
647 win = mixer_ctx->default_win;
648
649 if (win < 0 || win > HDMI_OVERLAY_NUMBER) {
650 DRM_ERROR("overlay plane[%d] is wrong\n", win);
651 return;
652 }
653
654 win_data = &mixer_ctx->win_data[win];
655
656 win_data->dma_addr = overlay->dma_addr[0];
657 win_data->vaddr = overlay->vaddr[0];
658 win_data->chroma_dma_addr = overlay->dma_addr[1];
659 win_data->chroma_vaddr = overlay->vaddr[1];
660 win_data->pixel_format = overlay->pixel_format;
661 win_data->bpp = overlay->bpp;
662
663 win_data->crtc_x = overlay->crtc_x;
664 win_data->crtc_y = overlay->crtc_y;
665 win_data->crtc_width = overlay->crtc_width;
666 win_data->crtc_height = overlay->crtc_height;
667
668 win_data->fb_x = overlay->fb_x;
669 win_data->fb_y = overlay->fb_y;
670 win_data->fb_width = overlay->fb_width;
671 win_data->fb_height = overlay->fb_height;
672
673 win_data->mode_width = overlay->mode_width;
674 win_data->mode_height = overlay->mode_height;
675
676 win_data->scan_flags = overlay->scan_flag;
677}
678
679static void mixer_win_commit(void *ctx, int zpos)
680{
681 struct mixer_context *mixer_ctx = ctx;
682 int win = zpos;
683
684 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
685
686 if (win == DEFAULT_ZPOS)
687 win = mixer_ctx->default_win;
688
689 if (win < 0 || win > HDMI_OVERLAY_NUMBER) {
690 DRM_ERROR("overlay plane[%d] is wrong\n", win);
691 return;
692 }
693
694 if (win > 1)
695 vp_video_buffer(mixer_ctx, win);
696 else
697 mixer_graph_buffer(mixer_ctx, win);
698}
699
700static void mixer_win_disable(void *ctx, int zpos)
701{
702 struct mixer_context *mixer_ctx = ctx;
703 struct mixer_resources *res = &mixer_ctx->mixer_res;
704 unsigned long flags;
705 int win = zpos;
706
707 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
708
709 if (win == DEFAULT_ZPOS)
710 win = mixer_ctx->default_win;
711
712 if (win < 0 || win > HDMI_OVERLAY_NUMBER) {
713 DRM_ERROR("overlay plane[%d] is wrong\n", win);
714 return;
715 }
716
717 spin_lock_irqsave(&res->reg_slock, flags);
718 mixer_vsync_set_update(mixer_ctx, false);
719
720 mixer_cfg_layer(mixer_ctx, win, false);
721
722 mixer_vsync_set_update(mixer_ctx, true);
723 spin_unlock_irqrestore(&res->reg_slock, flags);
724}
725
726static struct exynos_hdmi_overlay_ops overlay_ops = {
727 .enable_vblank = mixer_enable_vblank,
728 .disable_vblank = mixer_disable_vblank,
729 .win_mode_set = mixer_win_mode_set,
730 .win_commit = mixer_win_commit,
731 .win_disable = mixer_win_disable,
732};
733
734/* for pageflip event */
735static void mixer_finish_pageflip(struct drm_device *drm_dev, int crtc)
736{
737 struct exynos_drm_private *dev_priv = drm_dev->dev_private;
738 struct drm_pending_vblank_event *e, *t;
739 struct timeval now;
740 unsigned long flags;
741 bool is_checked = false;
742
743 spin_lock_irqsave(&drm_dev->event_lock, flags);
744
745 list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
746 base.link) {
747 /* if event's pipe isn't same as crtc then ignore it. */
748 if (crtc != e->pipe)
749 continue;
750
751 is_checked = true;
752 do_gettimeofday(&now);
753 e->event.sequence = 0;
754 e->event.tv_sec = now.tv_sec;
755 e->event.tv_usec = now.tv_usec;
756
757 list_move_tail(&e->base.link, &e->base.file_priv->event_list);
758 wake_up_interruptible(&e->base.file_priv->event_wait);
759 }
760
761 if (is_checked)
c5614ae3
ID
762 /*
763 * call drm_vblank_put only in case that drm_vblank_get was
764 * called.
765 */
766 if (atomic_read(&drm_dev->vblank_refcount[crtc]) > 0)
767 drm_vblank_put(drm_dev, crtc);
d8408326
SWK
768
769 spin_unlock_irqrestore(&drm_dev->event_lock, flags);
770}
771
772static irqreturn_t mixer_irq_handler(int irq, void *arg)
773{
774 struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg;
775 struct mixer_context *ctx =
776 (struct mixer_context *)drm_hdmi_ctx->ctx;
777 struct mixer_resources *res = &ctx->mixer_res;
778 u32 val, val_base;
779
780 spin_lock(&res->reg_slock);
781
782 /* read interrupt status for handling and clearing flags for VSYNC */
783 val = mixer_reg_read(res, MXR_INT_STATUS);
784
785 /* handling VSYNC */
786 if (val & MXR_INT_STATUS_VSYNC) {
787 /* interlace scan need to check shadow register */
788 if (ctx->interlace) {
789 val_base = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
790 if (ctx->win_data[0].dma_addr != val_base)
791 goto out;
792
793 val_base = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
794 if (ctx->win_data[1].dma_addr != val_base)
795 goto out;
796 }
797
798 drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe);
799 mixer_finish_pageflip(drm_hdmi_ctx->drm_dev, ctx->pipe);
800 }
801
802out:
803 /* clear interrupts */
804 if (~val & MXR_INT_EN_VSYNC) {
805 /* vsync interrupt use different bit for read and clear */
806 val &= ~MXR_INT_EN_VSYNC;
807 val |= MXR_INT_CLEAR_VSYNC;
808 }
809 mixer_reg_write(res, MXR_INT_STATUS, val);
810
811 spin_unlock(&res->reg_slock);
812
813 return IRQ_HANDLED;
814}
815
816static void mixer_win_reset(struct mixer_context *ctx)
817{
818 struct mixer_resources *res = &ctx->mixer_res;
819 unsigned long flags;
820 u32 val; /* value stored to register */
821
822 spin_lock_irqsave(&res->reg_slock, flags);
823 mixer_vsync_set_update(ctx, false);
824
825 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
826
827 /* set output in RGB888 mode */
828 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
829
830 /* 16 beat burst in DMA */
831 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
832 MXR_STATUS_BURST_MASK);
833
44a0e022 834 /* setting default layer priority: layer1 > layer0 > video
d8408326 835 * because typical usage scenario would be
44a0e022 836 * layer1 - OSD
d8408326
SWK
837 * layer0 - framebuffer
838 * video - video overlay
d8408326 839 */
44a0e022
JS
840 val = MXR_LAYER_CFG_GRP1_VAL(3);
841 val |= MXR_LAYER_CFG_GRP0_VAL(2);
842 val |= MXR_LAYER_CFG_VP_VAL(1);
d8408326
SWK
843 mixer_reg_write(res, MXR_LAYER_CFG, val);
844
845 /* setting background color */
846 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
847 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
848 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
849
850 /* setting graphical layers */
851
852 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
853 val |= MXR_GRP_CFG_WIN_BLEND_EN;
854 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
855
856 /* the same configuration for both layers */
857 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
858
859 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
860 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
861 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
862
863 /* configuration of Video Processor Registers */
864 vp_win_reset(ctx);
865 vp_default_filter(res);
866
867 /* disable all layers */
868 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
869 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
870 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
871
872 mixer_vsync_set_update(ctx, true);
873 spin_unlock_irqrestore(&res->reg_slock, flags);
874}
875
876static void mixer_resource_poweron(struct mixer_context *ctx)
877{
878 struct mixer_resources *res = &ctx->mixer_res;
879
880 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
881
882 clk_enable(res->mixer);
883 clk_enable(res->vp);
884 clk_enable(res->sclk_mixer);
885
886 mixer_win_reset(ctx);
887}
888
889static void mixer_resource_poweroff(struct mixer_context *ctx)
890{
891 struct mixer_resources *res = &ctx->mixer_res;
892
893 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
894
895 clk_disable(res->mixer);
896 clk_disable(res->vp);
897 clk_disable(res->sclk_mixer);
898}
899
900static int mixer_runtime_resume(struct device *dev)
901{
902 struct exynos_drm_hdmi_context *ctx = get_mixer_context(dev);
903
904 DRM_DEBUG_KMS("resume - start\n");
905
906 mixer_resource_poweron((struct mixer_context *)ctx->ctx);
907
908 return 0;
909}
910
911static int mixer_runtime_suspend(struct device *dev)
912{
913 struct exynos_drm_hdmi_context *ctx = get_mixer_context(dev);
914
915 DRM_DEBUG_KMS("suspend - start\n");
916
917 mixer_resource_poweroff((struct mixer_context *)ctx->ctx);
918
919 return 0;
920}
921
922static const struct dev_pm_ops mixer_pm_ops = {
923 .runtime_suspend = mixer_runtime_suspend,
924 .runtime_resume = mixer_runtime_resume,
925};
926
927static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
928 struct platform_device *pdev)
929{
930 struct mixer_context *mixer_ctx =
931 (struct mixer_context *)ctx->ctx;
932 struct device *dev = &pdev->dev;
933 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
934 struct resource *res;
935 int ret;
936
937 mixer_res->dev = dev;
938 spin_lock_init(&mixer_res->reg_slock);
939
940 mixer_res->mixer = clk_get(dev, "mixer");
941 if (IS_ERR_OR_NULL(mixer_res->mixer)) {
942 dev_err(dev, "failed to get clock 'mixer'\n");
943 ret = -ENODEV;
944 goto fail;
945 }
946 mixer_res->vp = clk_get(dev, "vp");
947 if (IS_ERR_OR_NULL(mixer_res->vp)) {
948 dev_err(dev, "failed to get clock 'vp'\n");
949 ret = -ENODEV;
950 goto fail;
951 }
952 mixer_res->sclk_mixer = clk_get(dev, "sclk_mixer");
953 if (IS_ERR_OR_NULL(mixer_res->sclk_mixer)) {
954 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
955 ret = -ENODEV;
956 goto fail;
957 }
958 mixer_res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
959 if (IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) {
960 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
961 ret = -ENODEV;
962 goto fail;
963 }
964 mixer_res->sclk_dac = clk_get(dev, "sclk_dac");
965 if (IS_ERR_OR_NULL(mixer_res->sclk_dac)) {
966 dev_err(dev, "failed to get clock 'sclk_dac'\n");
967 ret = -ENODEV;
968 goto fail;
969 }
970 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr");
971 if (res == NULL) {
972 dev_err(dev, "get memory resource failed.\n");
973 ret = -ENXIO;
974 goto fail;
975 }
976
977 clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
978
979 mixer_res->mixer_regs = ioremap(res->start, resource_size(res));
980 if (mixer_res->mixer_regs == NULL) {
981 dev_err(dev, "register mapping failed.\n");
982 ret = -ENXIO;
983 goto fail;
984 }
985
986 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp");
987 if (res == NULL) {
988 dev_err(dev, "get memory resource failed.\n");
989 ret = -ENXIO;
990 goto fail_mixer_regs;
991 }
992
993 mixer_res->vp_regs = ioremap(res->start, resource_size(res));
994 if (mixer_res->vp_regs == NULL) {
995 dev_err(dev, "register mapping failed.\n");
996 ret = -ENXIO;
997 goto fail_mixer_regs;
998 }
999
1000 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq");
1001 if (res == NULL) {
1002 dev_err(dev, "get interrupt resource failed.\n");
1003 ret = -ENXIO;
1004 goto fail_vp_regs;
1005 }
1006
1007 ret = request_irq(res->start, mixer_irq_handler, 0, "drm_mixer", ctx);
1008 if (ret) {
1009 dev_err(dev, "request interrupt failed.\n");
1010 goto fail_vp_regs;
1011 }
1012 mixer_res->irq = res->start;
1013
1014 return 0;
1015
1016fail_vp_regs:
1017 iounmap(mixer_res->vp_regs);
1018
1019fail_mixer_regs:
1020 iounmap(mixer_res->mixer_regs);
1021
1022fail:
1023 if (!IS_ERR_OR_NULL(mixer_res->sclk_dac))
1024 clk_put(mixer_res->sclk_dac);
1025 if (!IS_ERR_OR_NULL(mixer_res->sclk_hdmi))
1026 clk_put(mixer_res->sclk_hdmi);
1027 if (!IS_ERR_OR_NULL(mixer_res->sclk_mixer))
1028 clk_put(mixer_res->sclk_mixer);
1029 if (!IS_ERR_OR_NULL(mixer_res->vp))
1030 clk_put(mixer_res->vp);
1031 if (!IS_ERR_OR_NULL(mixer_res->mixer))
1032 clk_put(mixer_res->mixer);
1033 mixer_res->dev = NULL;
1034 return ret;
1035}
1036
1037static void mixer_resources_cleanup(struct mixer_context *ctx)
1038{
1039 struct mixer_resources *res = &ctx->mixer_res;
1040
1041 disable_irq(res->irq);
1042 free_irq(res->irq, ctx);
1043
1044 iounmap(res->vp_regs);
1045 iounmap(res->mixer_regs);
1046}
1047
1048static int __devinit mixer_probe(struct platform_device *pdev)
1049{
1050 struct device *dev = &pdev->dev;
1051 struct exynos_drm_hdmi_context *drm_hdmi_ctx;
1052 struct mixer_context *ctx;
1053 int ret;
1054
1055 dev_info(dev, "probe start\n");
1056
1057 drm_hdmi_ctx = kzalloc(sizeof(*drm_hdmi_ctx), GFP_KERNEL);
1058 if (!drm_hdmi_ctx) {
1059 DRM_ERROR("failed to allocate common hdmi context.\n");
1060 return -ENOMEM;
1061 }
1062
1063 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
1064 if (!ctx) {
1065 DRM_ERROR("failed to alloc mixer context.\n");
1066 kfree(drm_hdmi_ctx);
1067 return -ENOMEM;
1068 }
1069
1070 drm_hdmi_ctx->ctx = (void *)ctx;
1071
1072 platform_set_drvdata(pdev, drm_hdmi_ctx);
1073
1074 /* acquire resources: regs, irqs, clocks */
1075 ret = mixer_resources_init(drm_hdmi_ctx, pdev);
1076 if (ret)
1077 goto fail;
1078
1079 /* register specific callback point to common hdmi. */
1080 exynos_drm_overlay_ops_register(&overlay_ops);
1081
1082 mixer_resource_poweron(ctx);
1083
1084 return 0;
1085
1086
1087fail:
1088 dev_info(dev, "probe failed\n");
1089 return ret;
1090}
1091
1092static int mixer_remove(struct platform_device *pdev)
1093{
1094 struct device *dev = &pdev->dev;
1095 struct exynos_drm_hdmi_context *drm_hdmi_ctx =
1096 platform_get_drvdata(pdev);
1097 struct mixer_context *ctx = (struct mixer_context *)drm_hdmi_ctx->ctx;
1098
1109bf8b 1099 dev_info(dev, "remove successful\n");
d8408326
SWK
1100
1101 mixer_resource_poweroff(ctx);
1102 mixer_resources_cleanup(ctx);
1103
1104 return 0;
1105}
1106
1107struct platform_driver mixer_driver = {
1108 .driver = {
1109 .name = "s5p-mixer",
1110 .owner = THIS_MODULE,
1111 .pm = &mixer_pm_ops,
1112 },
1113 .probe = mixer_probe,
1114 .remove = __devexit_p(mixer_remove),
1115};
1116EXPORT_SYMBOL(mixer_driver);
1117
1118MODULE_AUTHOR("Seung-Woo Kim, <sw0312.kim@samsung.com>");
1119MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
1120MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
1121MODULE_DESCRIPTION("Samsung DRM HDMI mixer Driver");
1122MODULE_LICENSE("GPL");
This page took 0.229567 seconds and 5 git commands to generate.