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