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