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