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