drm/exynos: Fix potential NULL pointer dereference
[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
760285e7 17#include <drm/drmP.h>
d8408326
SWK
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"
1055b39f 39#include "exynos_drm_iommu.h"
22b21ae6 40
d8408326
SWK
41#define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev))
42
22b21ae6
JS
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;
8dcb96b6
SWK
58 unsigned int src_width;
59 unsigned int src_height;
22b21ae6
JS
60 unsigned int mode_width;
61 unsigned int mode_height;
62 unsigned int scan_flags;
63};
64
65struct mixer_resources {
22b21ae6
JS
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
1e123441
RS
77enum mixer_version_id {
78 MXR_VER_0_0_0_16,
79 MXR_VER_16_0_33_0,
80};
81
22b21ae6 82struct mixer_context {
cf8fc4f1 83 struct device *dev;
1055b39f 84 struct drm_device *drm_dev;
22b21ae6
JS
85 int pipe;
86 bool interlace;
cf8fc4f1 87 bool powered;
1b8e5747 88 bool vp_enabled;
cf8fc4f1 89 u32 int_en;
22b21ae6 90
cf8fc4f1 91 struct mutex mixer_mutex;
22b21ae6 92 struct mixer_resources mixer_res;
a634dd54 93 struct hdmi_win_data win_data[MIXER_WIN_NR];
1e123441 94 enum mixer_version_id mxr_ver;
1055b39f 95 void *parent_ctx;
1e123441
RS
96};
97
98struct mixer_drv_data {
99 enum mixer_version_id version;
1b8e5747 100 bool is_vp_enabled;
22b21ae6
JS
101};
102
d8408326
SWK
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,
e25e1b66 254 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
d8408326 255 vp_filter_set(res, VP_POLY4_Y0_LL,
e25e1b66 256 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
d8408326 257 vp_filter_set(res, VP_POLY4_C0_LL,
e25e1b66 258 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
d8408326
SWK
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
1b8e5747
RS
269 if (ctx->vp_enabled)
270 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
d8408326
SWK
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:
1b8e5747
RS
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 }
d8408326
SWK
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;
d8408326 375 unsigned int x_ratio, y_ratio;
d8408326
SWK
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;
363b06aa 387 case DRM_FORMAT_NV12:
d8408326
SWK
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
d8408326 402 /* scaling feature: (src << 16) / dst */
8dcb96b6
SWK
403 x_ratio = (win_data->src_width << 16) / win_data->crtc_width;
404 y_ratio = (win_data->src_height << 16) / win_data->crtc_height;
d8408326
SWK
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
8dcb96b6 412 + (win_data->fb_width * win_data->fb_height);
d8408326
SWK
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 {
8dcb96b6
SWK
421 luma_addr[1] = luma_addr[0] + win_data->fb_width;
422 chroma_addr[1] = chroma_addr[0] + win_data->fb_width;
d8408326
SWK
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 */
8dcb96b6
SWK
443 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_width) |
444 VP_IMG_VSIZE(win_data->fb_height));
d8408326 445 /* chroma height has to reduced by 2 to avoid chroma distorions */
8dcb96b6
SWK
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));
d8408326 448
8dcb96b6
SWK
449 vp_reg_write(res, VP_SRC_WIDTH, win_data->src_width);
450 vp_reg_write(res, VP_SRC_HEIGHT, win_data->src_height);
d8408326 451 vp_reg_write(res, VP_SRC_H_POSITION,
8dcb96b6
SWK
452 VP_SRC_H_POSITION_VAL(win_data->fb_x));
453 vp_reg_write(res, VP_SRC_V_POSITION, win_data->fb_y);
d8408326 454
8dcb96b6
SWK
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);
d8408326 457 if (ctx->interlace) {
8dcb96b6
SWK
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);
d8408326 460 } else {
8dcb96b6
SWK
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);
d8408326
SWK
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
8dcb96b6
SWK
476 mixer_cfg_scan(ctx, win_data->mode_height);
477 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
d8408326
SWK
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
aaf8b49e
RS
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
d8408326
SWK
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;
d8408326
SWK
504 unsigned int x_ratio, y_ratio;
505 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
d8408326
SWK
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
d8408326
SWK
528 /* 2x scaling feature */
529 x_ratio = 0;
530 y_ratio = 0;
531
d8408326
SWK
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 */
8dcb96b6
SWK
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);
d8408326
SWK
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 */
8dcb96b6 555 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), win_data->fb_width);
d8408326 556
8dcb96b6
SWK
557 val = MXR_GRP_WH_WIDTH(win_data->crtc_width);
558 val |= MXR_GRP_WH_HEIGHT(win_data->crtc_height);
d8408326
SWK
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
8dcb96b6
SWK
576 mixer_cfg_scan(ctx, win_data->mode_height);
577 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
d8408326 578 mixer_cfg_layer(ctx, win, true);
aaf8b49e
RS
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
d8408326
SWK
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
cf8fc4f1
JS
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);
1b8e5747
RS
631 if (ctx->vp_enabled)
632 val |= MXR_LAYER_CFG_VP_VAL(1);
cf8fc4f1
JS
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 */
cf8fc4f1
JS
641 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
642 val |= MXR_GRP_CFG_WIN_BLEND_EN;
5736603b
SWK
643 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
644 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
cf8fc4f1
JS
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);
cf8fc4f1
JS
649 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
650
5736603b
SWK
651 /* setting video layers */
652 val = MXR_GRP_CFG_ALPHA_VAL(0);
653 mixer_reg_write(res, MXR_VIDEO_CFG, val);
654
1b8e5747
RS
655 if (ctx->vp_enabled) {
656 /* configuration of Video Processor Registers */
657 vp_win_reset(ctx);
658 vp_default_filter(res);
659 }
cf8fc4f1
JS
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);
1b8e5747
RS
664 if (ctx->vp_enabled)
665 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
cf8fc4f1
JS
666
667 mixer_vsync_set_update(ctx, true);
668 spin_unlock_irqrestore(&res->reg_slock, flags);
669}
670
1055b39f
ID
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
cf8fc4f1
JS
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);
1b8e5747
RS
706 if (ctx->vp_enabled) {
707 clk_enable(res->vp);
708 clk_enable(res->sclk_mixer);
709 }
cf8fc4f1
JS
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);
1b8e5747
RS
729 if (ctx->vp_enabled) {
730 clk_disable(res->vp);
731 clk_disable(res->sclk_mixer);
732 }
cf8fc4f1
JS
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
d8408326
SWK
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
cf8fc4f1
JS
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
3d05859f
ID
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
d8408326
SWK
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)
a2ee151b 825 win = MIXER_DEFAULT_WIN;
d8408326 826
a634dd54 827 if (win < 0 || win > MIXER_WIN_NR) {
cf8fc4f1 828 DRM_ERROR("mixer window[%d] is wrong\n", win);
d8408326
SWK
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;
8dcb96b6
SWK
850 win_data->src_width = overlay->src_width;
851 win_data->src_height = overlay->src_height;
d8408326
SWK
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
cf8fc4f1 859static void mixer_win_commit(void *ctx, int win)
d8408326
SWK
860{
861 struct mixer_context *mixer_ctx = ctx;
d8408326
SWK
862
863 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
864
1b8e5747 865 if (win > 1 && mixer_ctx->vp_enabled)
d8408326
SWK
866 vp_video_buffer(mixer_ctx, win);
867 else
868 mixer_graph_buffer(mixer_ctx, win);
869}
870
cf8fc4f1 871static void mixer_win_disable(void *ctx, int win)
d8408326
SWK
872{
873 struct mixer_context *mixer_ctx = ctx;
874 struct mixer_resources *res = &mixer_ctx->mixer_res;
875 unsigned long flags;
d8408326
SWK
876
877 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
878
d8408326
SWK
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
578b6065
JS
888static struct exynos_mixer_ops mixer_ops = {
889 /* manager */
1055b39f 890 .iommu_on = mixer_iommu_on,
d8408326
SWK
891 .enable_vblank = mixer_enable_vblank,
892 .disable_vblank = mixer_disable_vblank,
cf8fc4f1 893 .dpms = mixer_dpms,
578b6065
JS
894
895 /* overlay */
3d05859f 896 .wait_for_vblank = mixer_wait_for_vblank,
d8408326
SWK
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;
d8408326
SWK
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
d8408326
SWK
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);
e1f48ee5 925 drm_vblank_put(drm_dev, crtc);
d8408326
SWK
926 }
927
d8408326
SWK
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;
f9309d1b 934 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
d8408326 935 struct mixer_resources *res = &ctx->mixer_res;
8379e482 936 u32 val, base, shadow;
d8408326
SWK
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) {
8379e482
SWK
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)
d8408326
SWK
950 goto out;
951
8379e482
SWK
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)
d8408326
SWK
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
d8408326
SWK
976static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
977 struct platform_device *pdev)
978{
f9309d1b 979 struct mixer_context *mixer_ctx = ctx->ctx;
d8408326
SWK
980 struct device *dev = &pdev->dev;
981 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
982 struct resource *res;
983 int ret;
984
d8408326
SWK
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 }
1b8e5747 993
d8408326
SWK
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 }
1b8e5747 1000 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
d8408326
SWK
1001 if (res == NULL) {
1002 dev_err(dev, "get memory resource failed.\n");
1003 ret = -ENXIO;
1004 goto fail;
1005 }
1006
9416dfa7
SK
1007 mixer_res->mixer_regs = devm_ioremap(&pdev->dev, res->start,
1008 resource_size(res));
d8408326
SWK
1009 if (mixer_res->mixer_regs == NULL) {
1010 dev_err(dev, "register mapping failed.\n");
1011 ret = -ENXIO;
1012 goto fail;
1013 }
1014
1b8e5747 1015 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
d8408326 1016 if (res == NULL) {
1b8e5747 1017 dev_err(dev, "get interrupt resource failed.\n");
d8408326 1018 ret = -ENXIO;
9416dfa7 1019 goto fail;
d8408326
SWK
1020 }
1021
1b8e5747
RS
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");
9416dfa7 1026 goto fail;
d8408326 1027 }
1b8e5747 1028 mixer_res->irq = res->start;
d8408326 1029
1b8e5747 1030 return 0;
d8408326 1031
1b8e5747
RS
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);
d8408326 1072 if (res == NULL) {
1b8e5747 1073 dev_err(dev, "get memory resource failed.\n");
d8408326 1074 ret = -ENXIO;
9416dfa7 1075 goto fail;
d8408326
SWK
1076 }
1077
1b8e5747
RS
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;
9416dfa7 1083 goto fail;
d8408326 1084 }
d8408326
SWK
1085
1086 return 0;
1087
d8408326
SWK
1088fail:
1089 if (!IS_ERR_OR_NULL(mixer_res->sclk_dac))
1090 clk_put(mixer_res->sclk_dac);
d8408326
SWK
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);
d8408326
SWK
1095 return ret;
1096}
1097
aaf8b49e
RS
1098static struct mixer_drv_data exynos5_mxr_drv_data = {
1099 .version = MXR_VER_16_0_33_0,
1100 .is_vp_enabled = 0,
1101};
1102
1e123441
RS
1103static struct mixer_drv_data exynos4_mxr_drv_data = {
1104 .version = MXR_VER_0_0_0_16,
1b8e5747 1105 .is_vp_enabled = 1,
1e123441
RS
1106};
1107
1108static struct platform_device_id mixer_driver_types[] = {
1109 {
1110 .name = "s5p-mixer",
1111 .driver_data = (unsigned long)&exynos4_mxr_drv_data,
aaf8b49e
RS
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,
1e123441
RS
1124 }, {
1125 /* end node */
1126 }
1127};
1128
d8408326
SWK
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;
1e123441 1134 struct mixer_drv_data *drv;
d8408326
SWK
1135 int ret;
1136
1137 dev_info(dev, "probe start\n");
1138
9416dfa7
SK
1139 drm_hdmi_ctx = devm_kzalloc(&pdev->dev, sizeof(*drm_hdmi_ctx),
1140 GFP_KERNEL);
d8408326
SWK
1141 if (!drm_hdmi_ctx) {
1142 DRM_ERROR("failed to allocate common hdmi context.\n");
1143 return -ENOMEM;
1144 }
1145
9416dfa7 1146 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
d8408326
SWK
1147 if (!ctx) {
1148 DRM_ERROR("failed to alloc mixer context.\n");
d8408326
SWK
1149 return -ENOMEM;
1150 }
1151
cf8fc4f1
JS
1152 mutex_init(&ctx->mixer_mutex);
1153
aaf8b49e
RS
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);
2cdc53b3 1158 drv = (struct mixer_drv_data *)match->data;
aaf8b49e
RS
1159 } else {
1160 drv = (struct mixer_drv_data *)
1161 platform_get_device_id(pdev)->driver_data;
1162 }
1163
cf8fc4f1 1164 ctx->dev = &pdev->dev;
1055b39f 1165 ctx->parent_ctx = (void *)drm_hdmi_ctx;
d8408326 1166 drm_hdmi_ctx->ctx = (void *)ctx;
1b8e5747 1167 ctx->vp_enabled = drv->is_vp_enabled;
1e123441 1168 ctx->mxr_ver = drv->version;
d8408326
SWK
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);
1b8e5747
RS
1174 if (ret) {
1175 DRM_ERROR("mixer_resources_init failed\n");
d8408326 1176 goto fail;
1b8e5747
RS
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 }
d8408326 1187
768c3059
RS
1188 /* attach mixer driver to common hdmi. */
1189 exynos_mixer_drv_attach(drm_hdmi_ctx);
d8408326
SWK
1190
1191 /* register specific callback point to common hdmi. */
578b6065 1192 exynos_mixer_ops_register(&mixer_ops);
d8408326 1193
cf8fc4f1 1194 pm_runtime_enable(dev);
d8408326
SWK
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{
9416dfa7 1206 dev_info(&pdev->dev, "remove successful\n");
d8408326 1207
cf8fc4f1
JS
1208 pm_runtime_disable(&pdev->dev);
1209
d8408326
SWK
1210 return 0;
1211}
1212
ab27af85
JS
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
d8408326
SWK
1227struct platform_driver mixer_driver = {
1228 .driver = {
aaf8b49e 1229 .name = "exynos-mixer",
d8408326 1230 .owner = THIS_MODULE,
ab27af85 1231 .pm = &mixer_pm_ops,
aaf8b49e 1232 .of_match_table = mixer_match_types,
d8408326
SWK
1233 },
1234 .probe = mixer_probe,
1235 .remove = __devexit_p(mixer_remove),
1e123441 1236 .id_table = mixer_driver_types,
d8408326 1237};
This page took 0.195287 seconds and 5 git commands to generate.