Merge tag 'drm-amdkfd-next-fixes-2015-02-03' of git://people.freedesktop.org/~gabbayo...
[linux-2.6-block.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>
d8408326
SWK
26#include <linux/platform_device.h>
27#include <linux/interrupt.h>
28#include <linux/irq.h>
29#include <linux/delay.h>
30#include <linux/pm_runtime.h>
31#include <linux/clk.h>
32#include <linux/regulator/consumer.h>
3f1c781d 33#include <linux/of.h>
f37cd5e8 34#include <linux/component.h>
d8408326
SWK
35
36#include <drm/exynos_drm.h>
37
38#include "exynos_drm_drv.h"
663d8766 39#include "exynos_drm_crtc.h"
1055b39f 40#include "exynos_drm_iommu.h"
f041b257 41#include "exynos_mixer.h"
22b21ae6 42
f041b257
SP
43#define MIXER_WIN_NR 3
44#define MIXER_DEFAULT_WIN 0
d8408326 45
22b21ae6
JS
46struct hdmi_win_data {
47 dma_addr_t dma_addr;
22b21ae6 48 dma_addr_t chroma_dma_addr;
22b21ae6
JS
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;
8dcb96b6
SWK
59 unsigned int src_width;
60 unsigned int src_height;
22b21ae6
JS
61 unsigned int mode_width;
62 unsigned int mode_height;
63 unsigned int scan_flags;
db43fd16
P
64 bool enabled;
65 bool resume;
22b21ae6
JS
66};
67
68struct mixer_resources {
22b21ae6
JS
69 int irq;
70 void __iomem *mixer_regs;
71 void __iomem *vp_regs;
72 spinlock_t reg_slock;
73 struct clk *mixer;
74 struct clk *vp;
75 struct clk *sclk_mixer;
76 struct clk *sclk_hdmi;
ff830c96 77 struct clk *mout_mixer;
22b21ae6
JS
78};
79
1e123441
RS
80enum mixer_version_id {
81 MXR_VER_0_0_0_16,
82 MXR_VER_16_0_33_0,
def5e095 83 MXR_VER_128_0_0_184,
1e123441
RS
84};
85
22b21ae6 86struct mixer_context {
4551789f 87 struct platform_device *pdev;
cf8fc4f1 88 struct device *dev;
1055b39f 89 struct drm_device *drm_dev;
93bca243 90 struct exynos_drm_crtc *crtc;
22b21ae6
JS
91 int pipe;
92 bool interlace;
cf8fc4f1 93 bool powered;
1b8e5747 94 bool vp_enabled;
ff830c96 95 bool has_sclk;
cf8fc4f1 96 u32 int_en;
22b21ae6 97
cf8fc4f1 98 struct mutex mixer_mutex;
22b21ae6 99 struct mixer_resources mixer_res;
a634dd54 100 struct hdmi_win_data win_data[MIXER_WIN_NR];
1e123441 101 enum mixer_version_id mxr_ver;
6e95d5e6
P
102 wait_queue_head_t wait_vsync_queue;
103 atomic_t wait_vsync_event;
1e123441
RS
104};
105
106struct mixer_drv_data {
107 enum mixer_version_id version;
1b8e5747 108 bool is_vp_enabled;
ff830c96 109 bool has_sclk;
22b21ae6
JS
110};
111
d8408326
SWK
112static const u8 filter_y_horiz_tap8[] = {
113 0, -1, -1, -1, -1, -1, -1, -1,
114 -1, -1, -1, -1, -1, 0, 0, 0,
115 0, 2, 4, 5, 6, 6, 6, 6,
116 6, 5, 5, 4, 3, 2, 1, 1,
117 0, -6, -12, -16, -18, -20, -21, -20,
118 -20, -18, -16, -13, -10, -8, -5, -2,
119 127, 126, 125, 121, 114, 107, 99, 89,
120 79, 68, 57, 46, 35, 25, 16, 8,
121};
122
123static const u8 filter_y_vert_tap4[] = {
124 0, -3, -6, -8, -8, -8, -8, -7,
125 -6, -5, -4, -3, -2, -1, -1, 0,
126 127, 126, 124, 118, 111, 102, 92, 81,
127 70, 59, 48, 37, 27, 19, 11, 5,
128 0, 5, 11, 19, 27, 37, 48, 59,
129 70, 81, 92, 102, 111, 118, 124, 126,
130 0, 0, -1, -1, -2, -3, -4, -5,
131 -6, -7, -8, -8, -8, -8, -6, -3,
132};
133
134static const u8 filter_cr_horiz_tap4[] = {
135 0, -3, -6, -8, -8, -8, -8, -7,
136 -6, -5, -4, -3, -2, -1, -1, 0,
137 127, 126, 124, 118, 111, 102, 92, 81,
138 70, 59, 48, 37, 27, 19, 11, 5,
139};
140
141static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
142{
143 return readl(res->vp_regs + reg_id);
144}
145
146static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
147 u32 val)
148{
149 writel(val, res->vp_regs + reg_id);
150}
151
152static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
153 u32 val, u32 mask)
154{
155 u32 old = vp_reg_read(res, reg_id);
156
157 val = (val & mask) | (old & ~mask);
158 writel(val, res->vp_regs + reg_id);
159}
160
161static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
162{
163 return readl(res->mixer_regs + reg_id);
164}
165
166static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
167 u32 val)
168{
169 writel(val, res->mixer_regs + reg_id);
170}
171
172static inline void mixer_reg_writemask(struct mixer_resources *res,
173 u32 reg_id, u32 val, u32 mask)
174{
175 u32 old = mixer_reg_read(res, reg_id);
176
177 val = (val & mask) | (old & ~mask);
178 writel(val, res->mixer_regs + reg_id);
179}
180
181static void mixer_regs_dump(struct mixer_context *ctx)
182{
183#define DUMPREG(reg_id) \
184do { \
185 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
186 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
187} while (0)
188
189 DUMPREG(MXR_STATUS);
190 DUMPREG(MXR_CFG);
191 DUMPREG(MXR_INT_EN);
192 DUMPREG(MXR_INT_STATUS);
193
194 DUMPREG(MXR_LAYER_CFG);
195 DUMPREG(MXR_VIDEO_CFG);
196
197 DUMPREG(MXR_GRAPHIC0_CFG);
198 DUMPREG(MXR_GRAPHIC0_BASE);
199 DUMPREG(MXR_GRAPHIC0_SPAN);
200 DUMPREG(MXR_GRAPHIC0_WH);
201 DUMPREG(MXR_GRAPHIC0_SXY);
202 DUMPREG(MXR_GRAPHIC0_DXY);
203
204 DUMPREG(MXR_GRAPHIC1_CFG);
205 DUMPREG(MXR_GRAPHIC1_BASE);
206 DUMPREG(MXR_GRAPHIC1_SPAN);
207 DUMPREG(MXR_GRAPHIC1_WH);
208 DUMPREG(MXR_GRAPHIC1_SXY);
209 DUMPREG(MXR_GRAPHIC1_DXY);
210#undef DUMPREG
211}
212
213static void vp_regs_dump(struct mixer_context *ctx)
214{
215#define DUMPREG(reg_id) \
216do { \
217 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
218 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
219} while (0)
220
221 DUMPREG(VP_ENABLE);
222 DUMPREG(VP_SRESET);
223 DUMPREG(VP_SHADOW_UPDATE);
224 DUMPREG(VP_FIELD_ID);
225 DUMPREG(VP_MODE);
226 DUMPREG(VP_IMG_SIZE_Y);
227 DUMPREG(VP_IMG_SIZE_C);
228 DUMPREG(VP_PER_RATE_CTRL);
229 DUMPREG(VP_TOP_Y_PTR);
230 DUMPREG(VP_BOT_Y_PTR);
231 DUMPREG(VP_TOP_C_PTR);
232 DUMPREG(VP_BOT_C_PTR);
233 DUMPREG(VP_ENDIAN_MODE);
234 DUMPREG(VP_SRC_H_POSITION);
235 DUMPREG(VP_SRC_V_POSITION);
236 DUMPREG(VP_SRC_WIDTH);
237 DUMPREG(VP_SRC_HEIGHT);
238 DUMPREG(VP_DST_H_POSITION);
239 DUMPREG(VP_DST_V_POSITION);
240 DUMPREG(VP_DST_WIDTH);
241 DUMPREG(VP_DST_HEIGHT);
242 DUMPREG(VP_H_RATIO);
243 DUMPREG(VP_V_RATIO);
244
245#undef DUMPREG
246}
247
248static inline void vp_filter_set(struct mixer_resources *res,
249 int reg_id, const u8 *data, unsigned int size)
250{
251 /* assure 4-byte align */
252 BUG_ON(size & 3);
253 for (; size; size -= 4, reg_id += 4, data += 4) {
254 u32 val = (data[0] << 24) | (data[1] << 16) |
255 (data[2] << 8) | data[3];
256 vp_reg_write(res, reg_id, val);
257 }
258}
259
260static void vp_default_filter(struct mixer_resources *res)
261{
262 vp_filter_set(res, VP_POLY8_Y0_LL,
e25e1b66 263 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
d8408326 264 vp_filter_set(res, VP_POLY4_Y0_LL,
e25e1b66 265 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
d8408326 266 vp_filter_set(res, VP_POLY4_C0_LL,
e25e1b66 267 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
d8408326
SWK
268}
269
270static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
271{
272 struct mixer_resources *res = &ctx->mixer_res;
273
274 /* block update on vsync */
275 mixer_reg_writemask(res, MXR_STATUS, enable ?
276 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
277
1b8e5747
RS
278 if (ctx->vp_enabled)
279 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
d8408326
SWK
280 VP_SHADOW_UPDATE_ENABLE : 0);
281}
282
283static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
284{
285 struct mixer_resources *res = &ctx->mixer_res;
286 u32 val;
287
288 /* choosing between interlace and progressive mode */
289 val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
290 MXR_CFG_SCAN_PROGRASSIVE);
291
def5e095
RS
292 if (ctx->mxr_ver != MXR_VER_128_0_0_184) {
293 /* choosing between proper HD and SD mode */
294 if (height <= 480)
295 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
296 else if (height <= 576)
297 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
298 else if (height <= 720)
299 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
300 else if (height <= 1080)
301 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
302 else
303 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
304 }
d8408326
SWK
305
306 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
307}
308
309static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
310{
311 struct mixer_resources *res = &ctx->mixer_res;
312 u32 val;
313
314 if (height == 480) {
315 val = MXR_CFG_RGB601_0_255;
316 } else if (height == 576) {
317 val = MXR_CFG_RGB601_0_255;
318 } else if (height == 720) {
319 val = MXR_CFG_RGB709_16_235;
320 mixer_reg_write(res, MXR_CM_COEFF_Y,
321 (1 << 30) | (94 << 20) | (314 << 10) |
322 (32 << 0));
323 mixer_reg_write(res, MXR_CM_COEFF_CB,
324 (972 << 20) | (851 << 10) | (225 << 0));
325 mixer_reg_write(res, MXR_CM_COEFF_CR,
326 (225 << 20) | (820 << 10) | (1004 << 0));
327 } else if (height == 1080) {
328 val = MXR_CFG_RGB709_16_235;
329 mixer_reg_write(res, MXR_CM_COEFF_Y,
330 (1 << 30) | (94 << 20) | (314 << 10) |
331 (32 << 0));
332 mixer_reg_write(res, MXR_CM_COEFF_CB,
333 (972 << 20) | (851 << 10) | (225 << 0));
334 mixer_reg_write(res, MXR_CM_COEFF_CR,
335 (225 << 20) | (820 << 10) | (1004 << 0));
336 } else {
337 val = MXR_CFG_RGB709_16_235;
338 mixer_reg_write(res, MXR_CM_COEFF_Y,
339 (1 << 30) | (94 << 20) | (314 << 10) |
340 (32 << 0));
341 mixer_reg_write(res, MXR_CM_COEFF_CB,
342 (972 << 20) | (851 << 10) | (225 << 0));
343 mixer_reg_write(res, MXR_CM_COEFF_CR,
344 (225 << 20) | (820 << 10) | (1004 << 0));
345 }
346
347 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
348}
349
350static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable)
351{
352 struct mixer_resources *res = &ctx->mixer_res;
353 u32 val = enable ? ~0 : 0;
354
355 switch (win) {
356 case 0:
357 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
358 break;
359 case 1:
360 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
361 break;
362 case 2:
1b8e5747
RS
363 if (ctx->vp_enabled) {
364 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
365 mixer_reg_writemask(res, MXR_CFG, val,
366 MXR_CFG_VP_ENABLE);
f1e716d8
JS
367
368 /* control blending of graphic layer 0 */
369 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(0), val,
370 MXR_GRP_CFG_BLEND_PRE_MUL |
371 MXR_GRP_CFG_PIXEL_BLEND_EN);
1b8e5747 372 }
d8408326
SWK
373 break;
374 }
375}
376
377static void mixer_run(struct mixer_context *ctx)
378{
379 struct mixer_resources *res = &ctx->mixer_res;
380
381 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
382
383 mixer_regs_dump(ctx);
384}
385
381be025
RS
386static void mixer_stop(struct mixer_context *ctx)
387{
388 struct mixer_resources *res = &ctx->mixer_res;
389 int timeout = 20;
390
391 mixer_reg_writemask(res, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
392
393 while (!(mixer_reg_read(res, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
394 --timeout)
395 usleep_range(10000, 12000);
396
397 mixer_regs_dump(ctx);
398}
399
d8408326
SWK
400static void vp_video_buffer(struct mixer_context *ctx, int win)
401{
402 struct mixer_resources *res = &ctx->mixer_res;
403 unsigned long flags;
404 struct hdmi_win_data *win_data;
d8408326 405 unsigned int x_ratio, y_ratio;
782953ec 406 unsigned int buf_num = 1;
d8408326
SWK
407 dma_addr_t luma_addr[2], chroma_addr[2];
408 bool tiled_mode = false;
409 bool crcb_mode = false;
410 u32 val;
411
412 win_data = &ctx->win_data[win];
413
414 switch (win_data->pixel_format) {
415 case DRM_FORMAT_NV12MT:
416 tiled_mode = true;
363b06aa 417 case DRM_FORMAT_NV12:
d8408326
SWK
418 crcb_mode = false;
419 buf_num = 2;
420 break;
421 /* TODO: single buffer format NV12, NV21 */
422 default:
423 /* ignore pixel format at disable time */
424 if (!win_data->dma_addr)
425 break;
426
427 DRM_ERROR("pixel format for vp is wrong [%d].\n",
428 win_data->pixel_format);
429 return;
430 }
431
d8408326 432 /* scaling feature: (src << 16) / dst */
8dcb96b6
SWK
433 x_ratio = (win_data->src_width << 16) / win_data->crtc_width;
434 y_ratio = (win_data->src_height << 16) / win_data->crtc_height;
d8408326
SWK
435
436 if (buf_num == 2) {
437 luma_addr[0] = win_data->dma_addr;
438 chroma_addr[0] = win_data->chroma_dma_addr;
439 } else {
440 luma_addr[0] = win_data->dma_addr;
441 chroma_addr[0] = win_data->dma_addr
8dcb96b6 442 + (win_data->fb_width * win_data->fb_height);
d8408326
SWK
443 }
444
445 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) {
446 ctx->interlace = true;
447 if (tiled_mode) {
448 luma_addr[1] = luma_addr[0] + 0x40;
449 chroma_addr[1] = chroma_addr[0] + 0x40;
450 } else {
8dcb96b6
SWK
451 luma_addr[1] = luma_addr[0] + win_data->fb_width;
452 chroma_addr[1] = chroma_addr[0] + win_data->fb_width;
d8408326
SWK
453 }
454 } else {
455 ctx->interlace = false;
456 luma_addr[1] = 0;
457 chroma_addr[1] = 0;
458 }
459
460 spin_lock_irqsave(&res->reg_slock, flags);
461 mixer_vsync_set_update(ctx, false);
462
463 /* interlace or progressive scan mode */
464 val = (ctx->interlace ? ~0 : 0);
465 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
466
467 /* setup format */
468 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
469 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
470 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
471
472 /* setting size of input image */
8dcb96b6
SWK
473 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_width) |
474 VP_IMG_VSIZE(win_data->fb_height));
d8408326 475 /* chroma height has to reduced by 2 to avoid chroma distorions */
8dcb96b6
SWK
476 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(win_data->fb_width) |
477 VP_IMG_VSIZE(win_data->fb_height / 2));
d8408326 478
8dcb96b6
SWK
479 vp_reg_write(res, VP_SRC_WIDTH, win_data->src_width);
480 vp_reg_write(res, VP_SRC_HEIGHT, win_data->src_height);
d8408326 481 vp_reg_write(res, VP_SRC_H_POSITION,
8dcb96b6
SWK
482 VP_SRC_H_POSITION_VAL(win_data->fb_x));
483 vp_reg_write(res, VP_SRC_V_POSITION, win_data->fb_y);
d8408326 484
8dcb96b6
SWK
485 vp_reg_write(res, VP_DST_WIDTH, win_data->crtc_width);
486 vp_reg_write(res, VP_DST_H_POSITION, win_data->crtc_x);
d8408326 487 if (ctx->interlace) {
8dcb96b6
SWK
488 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height / 2);
489 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y / 2);
d8408326 490 } else {
8dcb96b6
SWK
491 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height);
492 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y);
d8408326
SWK
493 }
494
495 vp_reg_write(res, VP_H_RATIO, x_ratio);
496 vp_reg_write(res, VP_V_RATIO, y_ratio);
497
498 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
499
500 /* set buffer address to vp */
501 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
502 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
503 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
504 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
505
8dcb96b6
SWK
506 mixer_cfg_scan(ctx, win_data->mode_height);
507 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
d8408326
SWK
508 mixer_cfg_layer(ctx, win, true);
509 mixer_run(ctx);
510
511 mixer_vsync_set_update(ctx, true);
512 spin_unlock_irqrestore(&res->reg_slock, flags);
513
514 vp_regs_dump(ctx);
515}
516
aaf8b49e
RS
517static void mixer_layer_update(struct mixer_context *ctx)
518{
519 struct mixer_resources *res = &ctx->mixer_res;
aaf8b49e 520
5c0f4829 521 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
aaf8b49e
RS
522}
523
d8408326
SWK
524static void mixer_graph_buffer(struct mixer_context *ctx, int win)
525{
526 struct mixer_resources *res = &ctx->mixer_res;
527 unsigned long flags;
528 struct hdmi_win_data *win_data;
d8408326
SWK
529 unsigned int x_ratio, y_ratio;
530 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
d8408326
SWK
531 dma_addr_t dma_addr;
532 unsigned int fmt;
533 u32 val;
534
535 win_data = &ctx->win_data[win];
536
537 #define RGB565 4
538 #define ARGB1555 5
539 #define ARGB4444 6
540 #define ARGB8888 7
541
542 switch (win_data->bpp) {
543 case 16:
544 fmt = ARGB4444;
545 break;
546 case 32:
547 fmt = ARGB8888;
548 break;
549 default:
550 fmt = ARGB8888;
551 }
552
d8408326
SWK
553 /* 2x scaling feature */
554 x_ratio = 0;
555 y_ratio = 0;
556
d8408326
SWK
557 dst_x_offset = win_data->crtc_x;
558 dst_y_offset = win_data->crtc_y;
559
560 /* converting dma address base and source offset */
8dcb96b6
SWK
561 dma_addr = win_data->dma_addr
562 + (win_data->fb_x * win_data->bpp >> 3)
563 + (win_data->fb_y * win_data->fb_width * win_data->bpp >> 3);
d8408326
SWK
564 src_x_offset = 0;
565 src_y_offset = 0;
566
567 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE)
568 ctx->interlace = true;
569 else
570 ctx->interlace = false;
571
572 spin_lock_irqsave(&res->reg_slock, flags);
573 mixer_vsync_set_update(ctx, false);
574
575 /* setup format */
576 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
577 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
578
579 /* setup geometry */
8dcb96b6 580 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), win_data->fb_width);
d8408326 581
def5e095
RS
582 /* setup display size */
583 if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
584 win == MIXER_DEFAULT_WIN) {
585 val = MXR_MXR_RES_HEIGHT(win_data->fb_height);
586 val |= MXR_MXR_RES_WIDTH(win_data->fb_width);
587 mixer_reg_write(res, MXR_RESOLUTION, val);
588 }
589
8dcb96b6
SWK
590 val = MXR_GRP_WH_WIDTH(win_data->crtc_width);
591 val |= MXR_GRP_WH_HEIGHT(win_data->crtc_height);
d8408326
SWK
592 val |= MXR_GRP_WH_H_SCALE(x_ratio);
593 val |= MXR_GRP_WH_V_SCALE(y_ratio);
594 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
595
596 /* setup offsets in source image */
597 val = MXR_GRP_SXY_SX(src_x_offset);
598 val |= MXR_GRP_SXY_SY(src_y_offset);
599 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
600
601 /* setup offsets in display image */
602 val = MXR_GRP_DXY_DX(dst_x_offset);
603 val |= MXR_GRP_DXY_DY(dst_y_offset);
604 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
605
606 /* set buffer address to mixer */
607 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
608
8dcb96b6
SWK
609 mixer_cfg_scan(ctx, win_data->mode_height);
610 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
d8408326 611 mixer_cfg_layer(ctx, win, true);
aaf8b49e
RS
612
613 /* layer update mandatory for mixer 16.0.33.0 */
def5e095
RS
614 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
615 ctx->mxr_ver == MXR_VER_128_0_0_184)
aaf8b49e
RS
616 mixer_layer_update(ctx);
617
d8408326
SWK
618 mixer_run(ctx);
619
620 mixer_vsync_set_update(ctx, true);
621 spin_unlock_irqrestore(&res->reg_slock, flags);
622}
623
624static void vp_win_reset(struct mixer_context *ctx)
625{
626 struct mixer_resources *res = &ctx->mixer_res;
627 int tries = 100;
628
629 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
630 for (tries = 100; tries; --tries) {
631 /* waiting until VP_SRESET_PROCESSING is 0 */
632 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
633 break;
09760ea3 634 usleep_range(10000, 12000);
d8408326
SWK
635 }
636 WARN(tries == 0, "failed to reset Video Processor\n");
637}
638
cf8fc4f1
JS
639static void mixer_win_reset(struct mixer_context *ctx)
640{
641 struct mixer_resources *res = &ctx->mixer_res;
642 unsigned long flags;
643 u32 val; /* value stored to register */
644
645 spin_lock_irqsave(&res->reg_slock, flags);
646 mixer_vsync_set_update(ctx, false);
647
648 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
649
650 /* set output in RGB888 mode */
651 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
652
653 /* 16 beat burst in DMA */
654 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
655 MXR_STATUS_BURST_MASK);
656
657 /* setting default layer priority: layer1 > layer0 > video
658 * because typical usage scenario would be
659 * layer1 - OSD
660 * layer0 - framebuffer
661 * video - video overlay
662 */
663 val = MXR_LAYER_CFG_GRP1_VAL(3);
664 val |= MXR_LAYER_CFG_GRP0_VAL(2);
1b8e5747
RS
665 if (ctx->vp_enabled)
666 val |= MXR_LAYER_CFG_VP_VAL(1);
cf8fc4f1
JS
667 mixer_reg_write(res, MXR_LAYER_CFG, val);
668
669 /* setting background color */
670 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
671 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
672 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
673
674 /* setting graphical layers */
cf8fc4f1
JS
675 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
676 val |= MXR_GRP_CFG_WIN_BLEND_EN;
677 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
678
0377f4ed 679 /* Don't blend layer 0 onto the mixer background */
cf8fc4f1 680 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
0377f4ed
SP
681
682 /* Blend layer 1 into layer 0 */
683 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
684 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
cf8fc4f1
JS
685 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
686
5736603b
SWK
687 /* setting video layers */
688 val = MXR_GRP_CFG_ALPHA_VAL(0);
689 mixer_reg_write(res, MXR_VIDEO_CFG, val);
690
1b8e5747
RS
691 if (ctx->vp_enabled) {
692 /* configuration of Video Processor Registers */
693 vp_win_reset(ctx);
694 vp_default_filter(res);
695 }
cf8fc4f1
JS
696
697 /* disable all layers */
698 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
699 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
1b8e5747
RS
700 if (ctx->vp_enabled)
701 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
cf8fc4f1
JS
702
703 mixer_vsync_set_update(ctx, true);
704 spin_unlock_irqrestore(&res->reg_slock, flags);
705}
706
4551789f
SP
707static irqreturn_t mixer_irq_handler(int irq, void *arg)
708{
709 struct mixer_context *ctx = arg;
710 struct mixer_resources *res = &ctx->mixer_res;
711 u32 val, base, shadow;
712
713 spin_lock(&res->reg_slock);
714
715 /* read interrupt status for handling and clearing flags for VSYNC */
716 val = mixer_reg_read(res, MXR_INT_STATUS);
717
718 /* handling VSYNC */
719 if (val & MXR_INT_STATUS_VSYNC) {
720 /* interlace scan need to check shadow register */
721 if (ctx->interlace) {
722 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
723 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
724 if (base != shadow)
725 goto out;
726
727 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
728 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
729 if (base != shadow)
730 goto out;
731 }
732
733 drm_handle_vblank(ctx->drm_dev, ctx->pipe);
734 exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
735
736 /* set wait vsync event to zero and wake up queue. */
737 if (atomic_read(&ctx->wait_vsync_event)) {
738 atomic_set(&ctx->wait_vsync_event, 0);
739 wake_up(&ctx->wait_vsync_queue);
740 }
741 }
742
743out:
744 /* clear interrupts */
745 if (~val & MXR_INT_EN_VSYNC) {
746 /* vsync interrupt use different bit for read and clear */
747 val &= ~MXR_INT_EN_VSYNC;
748 val |= MXR_INT_CLEAR_VSYNC;
749 }
750 mixer_reg_write(res, MXR_INT_STATUS, val);
751
752 spin_unlock(&res->reg_slock);
753
754 return IRQ_HANDLED;
755}
756
757static int mixer_resources_init(struct mixer_context *mixer_ctx)
758{
759 struct device *dev = &mixer_ctx->pdev->dev;
760 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
761 struct resource *res;
762 int ret;
763
764 spin_lock_init(&mixer_res->reg_slock);
765
766 mixer_res->mixer = devm_clk_get(dev, "mixer");
767 if (IS_ERR(mixer_res->mixer)) {
768 dev_err(dev, "failed to get clock 'mixer'\n");
769 return -ENODEV;
770 }
771
772 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
773 if (IS_ERR(mixer_res->sclk_hdmi)) {
774 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
775 return -ENODEV;
776 }
777 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
778 if (res == NULL) {
779 dev_err(dev, "get memory resource failed.\n");
780 return -ENXIO;
781 }
782
783 mixer_res->mixer_regs = devm_ioremap(dev, res->start,
784 resource_size(res));
785 if (mixer_res->mixer_regs == NULL) {
786 dev_err(dev, "register mapping failed.\n");
787 return -ENXIO;
788 }
789
790 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
791 if (res == NULL) {
792 dev_err(dev, "get interrupt resource failed.\n");
793 return -ENXIO;
794 }
795
796 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
797 0, "drm_mixer", mixer_ctx);
798 if (ret) {
799 dev_err(dev, "request interrupt failed.\n");
800 return ret;
801 }
802 mixer_res->irq = res->start;
803
804 return 0;
805}
806
807static int vp_resources_init(struct mixer_context *mixer_ctx)
808{
809 struct device *dev = &mixer_ctx->pdev->dev;
810 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
811 struct resource *res;
812
813 mixer_res->vp = devm_clk_get(dev, "vp");
814 if (IS_ERR(mixer_res->vp)) {
815 dev_err(dev, "failed to get clock 'vp'\n");
816 return -ENODEV;
817 }
4551789f 818
ff830c96
MS
819 if (mixer_ctx->has_sclk) {
820 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
821 if (IS_ERR(mixer_res->sclk_mixer)) {
822 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
823 return -ENODEV;
824 }
825 mixer_res->mout_mixer = devm_clk_get(dev, "mout_mixer");
826 if (IS_ERR(mixer_res->mout_mixer)) {
827 dev_err(dev, "failed to get clock 'mout_mixer'\n");
828 return -ENODEV;
829 }
830
831 if (mixer_res->sclk_hdmi && mixer_res->mout_mixer)
832 clk_set_parent(mixer_res->mout_mixer,
833 mixer_res->sclk_hdmi);
834 }
4551789f
SP
835
836 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
837 if (res == NULL) {
838 dev_err(dev, "get memory resource failed.\n");
839 return -ENXIO;
840 }
841
842 mixer_res->vp_regs = devm_ioremap(dev, res->start,
843 resource_size(res));
844 if (mixer_res->vp_regs == NULL) {
845 dev_err(dev, "register mapping failed.\n");
846 return -ENXIO;
847 }
848
849 return 0;
850}
851
93bca243 852static int mixer_initialize(struct mixer_context *mixer_ctx,
f37cd5e8 853 struct drm_device *drm_dev)
4551789f
SP
854{
855 int ret;
f37cd5e8
ID
856 struct exynos_drm_private *priv;
857 priv = drm_dev->dev_private;
4551789f 858
eb88e422 859 mixer_ctx->drm_dev = drm_dev;
8a326edd 860 mixer_ctx->pipe = priv->pipe++;
4551789f
SP
861
862 /* acquire resources: regs, irqs, clocks */
863 ret = mixer_resources_init(mixer_ctx);
864 if (ret) {
865 DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
866 return ret;
867 }
868
869 if (mixer_ctx->vp_enabled) {
870 /* acquire vp resources: regs, irqs, clocks */
871 ret = vp_resources_init(mixer_ctx);
872 if (ret) {
873 DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
874 return ret;
875 }
876 }
877
f041b257
SP
878 if (!is_drm_iommu_supported(mixer_ctx->drm_dev))
879 return 0;
880
881 return drm_iommu_attach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
4551789f
SP
882}
883
93bca243 884static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
1055b39f 885{
f041b257
SP
886 if (is_drm_iommu_supported(mixer_ctx->drm_dev))
887 drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
1055b39f
ID
888}
889
93bca243 890static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
d8408326 891{
93bca243 892 struct mixer_context *mixer_ctx = crtc->ctx;
d8408326
SWK
893 struct mixer_resources *res = &mixer_ctx->mixer_res;
894
f041b257
SP
895 if (!mixer_ctx->powered) {
896 mixer_ctx->int_en |= MXR_INT_EN_VSYNC;
897 return 0;
898 }
d8408326
SWK
899
900 /* enable vsync interrupt */
901 mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
902 MXR_INT_EN_VSYNC);
903
904 return 0;
905}
906
93bca243 907static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
d8408326 908{
93bca243 909 struct mixer_context *mixer_ctx = crtc->ctx;
d8408326
SWK
910 struct mixer_resources *res = &mixer_ctx->mixer_res;
911
d8408326
SWK
912 /* disable vsync interrupt */
913 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
914}
915
93bca243 916static void mixer_win_mode_set(struct exynos_drm_crtc *crtc,
8837deea 917 struct exynos_drm_plane *plane)
d8408326 918{
93bca243 919 struct mixer_context *mixer_ctx = crtc->ctx;
d8408326
SWK
920 struct hdmi_win_data *win_data;
921 int win;
922
8837deea
GP
923 if (!plane) {
924 DRM_ERROR("plane is NULL\n");
d8408326
SWK
925 return;
926 }
927
928 DRM_DEBUG_KMS("set [%d]x[%d] at (%d,%d) to [%d]x[%d] at (%d,%d)\n",
8837deea
GP
929 plane->fb_width, plane->fb_height,
930 plane->fb_x, plane->fb_y,
931 plane->crtc_width, plane->crtc_height,
932 plane->crtc_x, plane->crtc_y);
d8408326 933
8837deea 934 win = plane->zpos;
d8408326 935 if (win == DEFAULT_ZPOS)
a2ee151b 936 win = MIXER_DEFAULT_WIN;
d8408326 937
1586d80c 938 if (win < 0 || win >= MIXER_WIN_NR) {
cf8fc4f1 939 DRM_ERROR("mixer window[%d] is wrong\n", win);
d8408326
SWK
940 return;
941 }
942
943 win_data = &mixer_ctx->win_data[win];
944
8837deea
GP
945 win_data->dma_addr = plane->dma_addr[0];
946 win_data->chroma_dma_addr = plane->dma_addr[1];
947 win_data->pixel_format = plane->pixel_format;
948 win_data->bpp = plane->bpp;
d8408326 949
8837deea
GP
950 win_data->crtc_x = plane->crtc_x;
951 win_data->crtc_y = plane->crtc_y;
952 win_data->crtc_width = plane->crtc_width;
953 win_data->crtc_height = plane->crtc_height;
d8408326 954
8837deea
GP
955 win_data->fb_x = plane->fb_x;
956 win_data->fb_y = plane->fb_y;
957 win_data->fb_width = plane->fb_width;
958 win_data->fb_height = plane->fb_height;
959 win_data->src_width = plane->src_width;
960 win_data->src_height = plane->src_height;
d8408326 961
8837deea
GP
962 win_data->mode_width = plane->mode_width;
963 win_data->mode_height = plane->mode_height;
d8408326 964
8837deea 965 win_data->scan_flags = plane->scan_flag;
d8408326
SWK
966}
967
93bca243 968static void mixer_win_commit(struct exynos_drm_crtc *crtc, int zpos)
d8408326 969{
93bca243 970 struct mixer_context *mixer_ctx = crtc->ctx;
f041b257 971 int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
d8408326 972
cbc4c33d 973 DRM_DEBUG_KMS("win: %d\n", win);
d8408326 974
dda9012b
S
975 mutex_lock(&mixer_ctx->mixer_mutex);
976 if (!mixer_ctx->powered) {
977 mutex_unlock(&mixer_ctx->mixer_mutex);
978 return;
979 }
980 mutex_unlock(&mixer_ctx->mixer_mutex);
981
1b8e5747 982 if (win > 1 && mixer_ctx->vp_enabled)
d8408326
SWK
983 vp_video_buffer(mixer_ctx, win);
984 else
985 mixer_graph_buffer(mixer_ctx, win);
db43fd16
P
986
987 mixer_ctx->win_data[win].enabled = true;
d8408326
SWK
988}
989
93bca243 990static void mixer_win_disable(struct exynos_drm_crtc *crtc, int zpos)
d8408326 991{
93bca243 992 struct mixer_context *mixer_ctx = crtc->ctx;
d8408326 993 struct mixer_resources *res = &mixer_ctx->mixer_res;
f041b257 994 int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
d8408326 995 unsigned long flags;
d8408326 996
cbc4c33d 997 DRM_DEBUG_KMS("win: %d\n", win);
d8408326 998
db43fd16
P
999 mutex_lock(&mixer_ctx->mixer_mutex);
1000 if (!mixer_ctx->powered) {
1001 mutex_unlock(&mixer_ctx->mixer_mutex);
1002 mixer_ctx->win_data[win].resume = false;
1003 return;
1004 }
1005 mutex_unlock(&mixer_ctx->mixer_mutex);
1006
d8408326
SWK
1007 spin_lock_irqsave(&res->reg_slock, flags);
1008 mixer_vsync_set_update(mixer_ctx, false);
1009
1010 mixer_cfg_layer(mixer_ctx, win, false);
1011
1012 mixer_vsync_set_update(mixer_ctx, true);
1013 spin_unlock_irqrestore(&res->reg_slock, flags);
db43fd16
P
1014
1015 mixer_ctx->win_data[win].enabled = false;
d8408326
SWK
1016}
1017
93bca243 1018static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
8137a2e2 1019{
93bca243 1020 struct mixer_context *mixer_ctx = crtc->ctx;
7c4c5584 1021 int err;
8137a2e2 1022
6e95d5e6
P
1023 mutex_lock(&mixer_ctx->mixer_mutex);
1024 if (!mixer_ctx->powered) {
1025 mutex_unlock(&mixer_ctx->mixer_mutex);
1026 return;
1027 }
1028 mutex_unlock(&mixer_ctx->mixer_mutex);
1029
93bca243 1030 err = drm_vblank_get(mixer_ctx->drm_dev, mixer_ctx->pipe);
7c4c5584
JS
1031 if (err < 0) {
1032 DRM_DEBUG_KMS("failed to acquire vblank counter\n");
1033 return;
1034 }
5d39b9ee 1035
6e95d5e6
P
1036 atomic_set(&mixer_ctx->wait_vsync_event, 1);
1037
1038 /*
1039 * wait for MIXER to signal VSYNC interrupt or return after
1040 * timeout which is set to 50ms (refresh rate of 20).
1041 */
1042 if (!wait_event_timeout(mixer_ctx->wait_vsync_queue,
1043 !atomic_read(&mixer_ctx->wait_vsync_event),
bfd8303a 1044 HZ/20))
8137a2e2 1045 DRM_DEBUG_KMS("vblank wait timed out.\n");
5d39b9ee 1046
93bca243 1047 drm_vblank_put(mixer_ctx->drm_dev, mixer_ctx->pipe);
8137a2e2
P
1048}
1049
93bca243 1050static void mixer_window_suspend(struct exynos_drm_crtc *crtc)
db43fd16 1051{
93bca243 1052 struct mixer_context *ctx = crtc->ctx;
db43fd16
P
1053 struct hdmi_win_data *win_data;
1054 int i;
1055
1056 for (i = 0; i < MIXER_WIN_NR; i++) {
1057 win_data = &ctx->win_data[i];
1058 win_data->resume = win_data->enabled;
93bca243 1059 mixer_win_disable(crtc, i);
db43fd16 1060 }
93bca243 1061 mixer_wait_for_vblank(crtc);
db43fd16
P
1062}
1063
93bca243 1064static void mixer_window_resume(struct exynos_drm_crtc *crtc)
db43fd16 1065{
93bca243 1066 struct mixer_context *ctx = crtc->ctx;
db43fd16
P
1067 struct hdmi_win_data *win_data;
1068 int i;
1069
1070 for (i = 0; i < MIXER_WIN_NR; i++) {
1071 win_data = &ctx->win_data[i];
1072 win_data->enabled = win_data->resume;
1073 win_data->resume = false;
87244fa6 1074 if (win_data->enabled)
93bca243 1075 mixer_win_commit(crtc, i);
db43fd16
P
1076 }
1077}
1078
93bca243 1079static void mixer_poweron(struct exynos_drm_crtc *crtc)
db43fd16 1080{
93bca243 1081 struct mixer_context *ctx = crtc->ctx;
db43fd16
P
1082 struct mixer_resources *res = &ctx->mixer_res;
1083
db43fd16
P
1084 mutex_lock(&ctx->mixer_mutex);
1085 if (ctx->powered) {
1086 mutex_unlock(&ctx->mixer_mutex);
1087 return;
1088 }
b4bfa3c7 1089
db43fd16
P
1090 mutex_unlock(&ctx->mixer_mutex);
1091
af65c804
SP
1092 pm_runtime_get_sync(ctx->dev);
1093
0bfb1f8b 1094 clk_prepare_enable(res->mixer);
db43fd16 1095 if (ctx->vp_enabled) {
0bfb1f8b 1096 clk_prepare_enable(res->vp);
ff830c96
MS
1097 if (ctx->has_sclk)
1098 clk_prepare_enable(res->sclk_mixer);
db43fd16
P
1099 }
1100
b4bfa3c7
RS
1101 mutex_lock(&ctx->mixer_mutex);
1102 ctx->powered = true;
1103 mutex_unlock(&ctx->mixer_mutex);
1104
d74ed937
RS
1105 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
1106
db43fd16
P
1107 mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
1108 mixer_win_reset(ctx);
1109
93bca243 1110 mixer_window_resume(crtc);
db43fd16
P
1111}
1112
93bca243 1113static void mixer_poweroff(struct exynos_drm_crtc *crtc)
db43fd16 1114{
93bca243 1115 struct mixer_context *ctx = crtc->ctx;
db43fd16
P
1116 struct mixer_resources *res = &ctx->mixer_res;
1117
db43fd16 1118 mutex_lock(&ctx->mixer_mutex);
b4bfa3c7
RS
1119 if (!ctx->powered) {
1120 mutex_unlock(&ctx->mixer_mutex);
1121 return;
1122 }
db43fd16
P
1123 mutex_unlock(&ctx->mixer_mutex);
1124
381be025 1125 mixer_stop(ctx);
93bca243 1126 mixer_window_suspend(crtc);
db43fd16
P
1127
1128 ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
1129
b4bfa3c7
RS
1130 mutex_lock(&ctx->mixer_mutex);
1131 ctx->powered = false;
1132 mutex_unlock(&ctx->mixer_mutex);
1133
0bfb1f8b 1134 clk_disable_unprepare(res->mixer);
db43fd16 1135 if (ctx->vp_enabled) {
0bfb1f8b 1136 clk_disable_unprepare(res->vp);
ff830c96
MS
1137 if (ctx->has_sclk)
1138 clk_disable_unprepare(res->sclk_mixer);
db43fd16
P
1139 }
1140
af65c804 1141 pm_runtime_put_sync(ctx->dev);
db43fd16
P
1142}
1143
93bca243 1144static void mixer_dpms(struct exynos_drm_crtc *crtc, int mode)
db43fd16 1145{
db43fd16
P
1146 switch (mode) {
1147 case DRM_MODE_DPMS_ON:
93bca243 1148 mixer_poweron(crtc);
db43fd16
P
1149 break;
1150 case DRM_MODE_DPMS_STANDBY:
1151 case DRM_MODE_DPMS_SUSPEND:
1152 case DRM_MODE_DPMS_OFF:
93bca243 1153 mixer_poweroff(crtc);
db43fd16
P
1154 break;
1155 default:
1156 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
1157 break;
1158 }
1159}
1160
f041b257
SP
1161/* Only valid for Mixer version 16.0.33.0 */
1162int mixer_check_mode(struct drm_display_mode *mode)
1163{
1164 u32 w, h;
1165
1166 w = mode->hdisplay;
1167 h = mode->vdisplay;
1168
1169 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
1170 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1171 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1172
1173 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
1174 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1175 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1176 return 0;
1177
1178 return -EINVAL;
1179}
1180
93bca243 1181static struct exynos_drm_crtc_ops mixer_crtc_ops = {
f041b257 1182 .dpms = mixer_dpms,
d8408326
SWK
1183 .enable_vblank = mixer_enable_vblank,
1184 .disable_vblank = mixer_disable_vblank,
8137a2e2 1185 .wait_for_vblank = mixer_wait_for_vblank,
d8408326
SWK
1186 .win_mode_set = mixer_win_mode_set,
1187 .win_commit = mixer_win_commit,
1188 .win_disable = mixer_win_disable,
f041b257 1189};
0ea6822f 1190
def5e095
RS
1191static struct mixer_drv_data exynos5420_mxr_drv_data = {
1192 .version = MXR_VER_128_0_0_184,
1193 .is_vp_enabled = 0,
1194};
1195
cc57caf0 1196static struct mixer_drv_data exynos5250_mxr_drv_data = {
aaf8b49e
RS
1197 .version = MXR_VER_16_0_33_0,
1198 .is_vp_enabled = 0,
1199};
1200
ff830c96
MS
1201static struct mixer_drv_data exynos4212_mxr_drv_data = {
1202 .version = MXR_VER_0_0_0_16,
1203 .is_vp_enabled = 1,
1204};
1205
cc57caf0 1206static struct mixer_drv_data exynos4210_mxr_drv_data = {
1e123441 1207 .version = MXR_VER_0_0_0_16,
1b8e5747 1208 .is_vp_enabled = 1,
ff830c96 1209 .has_sclk = 1,
1e123441
RS
1210};
1211
1212static struct platform_device_id mixer_driver_types[] = {
1213 {
1214 .name = "s5p-mixer",
cc57caf0 1215 .driver_data = (unsigned long)&exynos4210_mxr_drv_data,
aaf8b49e
RS
1216 }, {
1217 .name = "exynos5-mixer",
cc57caf0 1218 .driver_data = (unsigned long)&exynos5250_mxr_drv_data,
aaf8b49e
RS
1219 }, {
1220 /* end node */
1221 }
1222};
1223
1224static struct of_device_id mixer_match_types[] = {
1225 {
ff830c96
MS
1226 .compatible = "samsung,exynos4210-mixer",
1227 .data = &exynos4210_mxr_drv_data,
1228 }, {
1229 .compatible = "samsung,exynos4212-mixer",
1230 .data = &exynos4212_mxr_drv_data,
1231 }, {
aaf8b49e 1232 .compatible = "samsung,exynos5-mixer",
cc57caf0
RS
1233 .data = &exynos5250_mxr_drv_data,
1234 }, {
1235 .compatible = "samsung,exynos5250-mixer",
1236 .data = &exynos5250_mxr_drv_data,
def5e095
RS
1237 }, {
1238 .compatible = "samsung,exynos5420-mixer",
1239 .data = &exynos5420_mxr_drv_data,
1e123441
RS
1240 }, {
1241 /* end node */
1242 }
1243};
39b58a39 1244MODULE_DEVICE_TABLE(of, mixer_match_types);
1e123441 1245
f37cd5e8 1246static int mixer_bind(struct device *dev, struct device *manager, void *data)
d8408326 1247{
8103ef1b 1248 struct mixer_context *ctx = dev_get_drvdata(dev);
f37cd5e8 1249 struct drm_device *drm_dev = data;
f37cd5e8 1250 int ret;
d8408326 1251
93bca243
GP
1252 ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
1253 EXYNOS_DISPLAY_TYPE_HDMI,
1254 &mixer_crtc_ops, ctx);
1255 if (IS_ERR(ctx->crtc)) {
1256 ret = PTR_ERR(ctx->crtc);
1257 goto free_ctx;
f37cd5e8 1258 }
d8408326 1259
93bca243
GP
1260 ret = mixer_initialize(ctx, drm_dev);
1261 if (ret)
1262 goto free_ctx;
1263
d8408326 1264 return 0;
93bca243
GP
1265
1266free_ctx:
1267 devm_kfree(dev, ctx);
1268 return ret;
d8408326
SWK
1269}
1270
f37cd5e8 1271static void mixer_unbind(struct device *dev, struct device *master, void *data)
d8408326 1272{
8103ef1b 1273 struct mixer_context *ctx = dev_get_drvdata(dev);
f37cd5e8 1274
93bca243 1275 mixer_ctx_remove(ctx);
f37cd5e8
ID
1276}
1277
1278static const struct component_ops mixer_component_ops = {
1279 .bind = mixer_bind,
1280 .unbind = mixer_unbind,
1281};
1282
1283static int mixer_probe(struct platform_device *pdev)
1284{
8103ef1b
AH
1285 struct device *dev = &pdev->dev;
1286 struct mixer_drv_data *drv;
1287 struct mixer_context *ctx;
df5225bc
ID
1288 int ret;
1289
8103ef1b
AH
1290 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1291 if (!ctx) {
1292 DRM_ERROR("failed to alloc mixer context.\n");
1293 return -ENOMEM;
1294 }
1295
1296 mutex_init(&ctx->mixer_mutex);
1297
8103ef1b
AH
1298 if (dev->of_node) {
1299 const struct of_device_id *match;
1300
1301 match = of_match_node(mixer_match_types, dev->of_node);
1302 drv = (struct mixer_drv_data *)match->data;
1303 } else {
1304 drv = (struct mixer_drv_data *)
1305 platform_get_device_id(pdev)->driver_data;
1306 }
1307
1308 ctx->pdev = pdev;
1309 ctx->dev = dev;
1310 ctx->vp_enabled = drv->is_vp_enabled;
1311 ctx->has_sclk = drv->has_sclk;
1312 ctx->mxr_ver = drv->version;
1313 init_waitqueue_head(&ctx->wait_vsync_queue);
1314 atomic_set(&ctx->wait_vsync_event, 0);
8103ef1b
AH
1315
1316 platform_set_drvdata(pdev, ctx);
1317
df5225bc 1318 ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
5d1741ad 1319 EXYNOS_DISPLAY_TYPE_HDMI);
df5225bc
ID
1320 if (ret)
1321 return ret;
1322
1323 ret = component_add(&pdev->dev, &mixer_component_ops);
8103ef1b 1324 if (ret) {
df5225bc 1325 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
8103ef1b
AH
1326 return ret;
1327 }
1328
1329 pm_runtime_enable(dev);
df5225bc
ID
1330
1331 return ret;
f37cd5e8
ID
1332}
1333
1334static int mixer_remove(struct platform_device *pdev)
1335{
8103ef1b
AH
1336 pm_runtime_disable(&pdev->dev);
1337
df5225bc
ID
1338 component_del(&pdev->dev, &mixer_component_ops);
1339 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
1340
d8408326
SWK
1341 return 0;
1342}
1343
1344struct platform_driver mixer_driver = {
1345 .driver = {
aaf8b49e 1346 .name = "exynos-mixer",
d8408326 1347 .owner = THIS_MODULE,
aaf8b49e 1348 .of_match_table = mixer_match_types,
d8408326
SWK
1349 },
1350 .probe = mixer_probe,
56550d94 1351 .remove = mixer_remove,
1e123441 1352 .id_table = mixer_driver_types,
d8408326 1353};