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