drm/exynos: plane: honor buffer offset for dma_addr
[deliverable/linux.git] / drivers / gpu / drm / exynos / exynos_mixer.c
CommitLineData
d8408326
SWK
1/*
2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
3 * Authors:
4 * Seung-Woo Kim <sw0312.kim@samsung.com>
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 *
8 * Based on drivers/media/video/s5p-tv/mixer_reg.c
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 */
16
760285e7 17#include <drm/drmP.h>
d8408326
SWK
18
19#include "regs-mixer.h"
20#include "regs-vp.h"
21
22#include <linux/kernel.h>
23#include <linux/spinlock.h>
24#include <linux/wait.h>
25#include <linux/i2c.h>
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;
782953ec 385 unsigned int buf_num = 1;
d8408326
SWK
386 dma_addr_t luma_addr[2], chroma_addr[2];
387 bool tiled_mode = false;
388 bool crcb_mode = false;
389 u32 val;
390
7ee14cdc 391 plane = &ctx->planes[win];
d8408326 392
7ee14cdc 393 switch (plane->pixel_format) {
363b06aa 394 case DRM_FORMAT_NV12:
d8408326
SWK
395 crcb_mode = false;
396 buf_num = 2;
397 break;
398 /* TODO: single buffer format NV12, NV21 */
399 default:
400 /* ignore pixel format at disable time */
7ee14cdc 401 if (!plane->dma_addr[0])
d8408326
SWK
402 break;
403
404 DRM_ERROR("pixel format for vp is wrong [%d].\n",
7ee14cdc 405 plane->pixel_format);
d8408326
SWK
406 return;
407 }
408
d8408326 409 if (buf_num == 2) {
7ee14cdc
GP
410 luma_addr[0] = plane->dma_addr[0];
411 chroma_addr[0] = plane->dma_addr[1];
d8408326 412 } else {
7ee14cdc
GP
413 luma_addr[0] = plane->dma_addr[0];
414 chroma_addr[0] = plane->dma_addr[0]
415 + (plane->pitch * plane->fb_height);
d8408326
SWK
416 }
417
7ee14cdc 418 if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE) {
d8408326
SWK
419 ctx->interlace = true;
420 if (tiled_mode) {
421 luma_addr[1] = luma_addr[0] + 0x40;
422 chroma_addr[1] = chroma_addr[0] + 0x40;
423 } else {
7ee14cdc
GP
424 luma_addr[1] = luma_addr[0] + plane->pitch;
425 chroma_addr[1] = chroma_addr[0] + plane->pitch;
d8408326
SWK
426 }
427 } else {
428 ctx->interlace = false;
429 luma_addr[1] = 0;
430 chroma_addr[1] = 0;
431 }
432
433 spin_lock_irqsave(&res->reg_slock, flags);
434 mixer_vsync_set_update(ctx, false);
435
436 /* interlace or progressive scan mode */
437 val = (ctx->interlace ? ~0 : 0);
438 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
439
440 /* setup format */
441 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
442 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
443 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
444
445 /* setting size of input image */
7ee14cdc
GP
446 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(plane->pitch) |
447 VP_IMG_VSIZE(plane->fb_height));
d8408326 448 /* chroma height has to reduced by 2 to avoid chroma distorions */
7ee14cdc
GP
449 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(plane->pitch) |
450 VP_IMG_VSIZE(plane->fb_height / 2));
d8408326 451
7ee14cdc
GP
452 vp_reg_write(res, VP_SRC_WIDTH, plane->src_width);
453 vp_reg_write(res, VP_SRC_HEIGHT, plane->src_height);
d8408326 454 vp_reg_write(res, VP_SRC_H_POSITION,
cb8a3db2
JS
455 VP_SRC_H_POSITION_VAL(plane->src_x));
456 vp_reg_write(res, VP_SRC_V_POSITION, plane->src_y);
d8408326 457
7ee14cdc
GP
458 vp_reg_write(res, VP_DST_WIDTH, plane->crtc_width);
459 vp_reg_write(res, VP_DST_H_POSITION, plane->crtc_x);
d8408326 460 if (ctx->interlace) {
7ee14cdc
GP
461 vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height / 2);
462 vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y / 2);
d8408326 463 } else {
7ee14cdc
GP
464 vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height);
465 vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y);
d8408326
SWK
466 }
467
3cabaf7e
JS
468 vp_reg_write(res, VP_H_RATIO, plane->h_ratio);
469 vp_reg_write(res, VP_V_RATIO, plane->v_ratio);
d8408326
SWK
470
471 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
472
473 /* set buffer address to vp */
474 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
475 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
476 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
477 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
478
7ee14cdc
GP
479 mixer_cfg_scan(ctx, plane->mode_height);
480 mixer_cfg_rgb_fmt(ctx, plane->mode_height);
d8408326
SWK
481 mixer_cfg_layer(ctx, win, true);
482 mixer_run(ctx);
483
484 mixer_vsync_set_update(ctx, true);
485 spin_unlock_irqrestore(&res->reg_slock, flags);
486
487 vp_regs_dump(ctx);
488}
489
aaf8b49e
RS
490static void mixer_layer_update(struct mixer_context *ctx)
491{
492 struct mixer_resources *res = &ctx->mixer_res;
aaf8b49e 493
5c0f4829 494 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
aaf8b49e
RS
495}
496
2611015c
TJ
497static int mixer_setup_scale(const struct exynos_drm_plane *plane,
498 unsigned int *x_ratio, unsigned int *y_ratio)
499{
500 if (plane->crtc_width != plane->src_width) {
501 if (plane->crtc_width == 2 * plane->src_width)
502 *x_ratio = 1;
503 else
504 goto fail;
505 }
506
507 if (plane->crtc_height != plane->src_height) {
508 if (plane->crtc_height == 2 * plane->src_height)
509 *y_ratio = 1;
510 else
511 goto fail;
512 }
513
514 return 0;
515
516fail:
517 DRM_DEBUG_KMS("only 2x width/height scaling of plane supported\n");
518 return -ENOTSUPP;
519}
520
d8408326
SWK
521static void mixer_graph_buffer(struct mixer_context *ctx, int win)
522{
523 struct mixer_resources *res = &ctx->mixer_res;
524 unsigned long flags;
7ee14cdc 525 struct exynos_drm_plane *plane;
2611015c 526 unsigned int x_ratio = 0, y_ratio = 0;
d8408326 527 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
d8408326
SWK
528 dma_addr_t dma_addr;
529 unsigned int fmt;
530 u32 val;
531
7ee14cdc 532 plane = &ctx->planes[win];
d8408326
SWK
533
534 #define RGB565 4
535 #define ARGB1555 5
536 #define ARGB4444 6
537 #define ARGB8888 7
538
7ee14cdc 539 switch (plane->bpp) {
d8408326
SWK
540 case 16:
541 fmt = ARGB4444;
542 break;
543 case 32:
544 fmt = ARGB8888;
545 break;
546 default:
547 fmt = ARGB8888;
548 }
549
2611015c
TJ
550 /* check if mixer supports requested scaling setup */
551 if (mixer_setup_scale(plane, &x_ratio, &y_ratio))
552 return;
d8408326 553
7ee14cdc
GP
554 dst_x_offset = plane->crtc_x;
555 dst_y_offset = plane->crtc_y;
d8408326
SWK
556
557 /* converting dma address base and source offset */
7ee14cdc 558 dma_addr = plane->dma_addr[0]
cb8a3db2
JS
559 + (plane->src_x * plane->bpp >> 3)
560 + (plane->src_y * plane->pitch);
d8408326
SWK
561 src_x_offset = 0;
562 src_y_offset = 0;
563
7ee14cdc 564 if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE)
d8408326
SWK
565 ctx->interlace = true;
566 else
567 ctx->interlace = false;
568
569 spin_lock_irqsave(&res->reg_slock, flags);
570 mixer_vsync_set_update(ctx, false);
571
572 /* setup format */
573 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
574 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
575
576 /* setup geometry */
adacb228 577 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win),
7ee14cdc 578 plane->pitch / (plane->bpp >> 3));
d8408326 579
def5e095
RS
580 /* setup display size */
581 if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
582 win == MIXER_DEFAULT_WIN) {
7ee14cdc
GP
583 val = MXR_MXR_RES_HEIGHT(plane->mode_height);
584 val |= MXR_MXR_RES_WIDTH(plane->mode_width);
def5e095
RS
585 mixer_reg_write(res, MXR_RESOLUTION, val);
586 }
587
2611015c
TJ
588 val = MXR_GRP_WH_WIDTH(plane->src_width);
589 val |= MXR_GRP_WH_HEIGHT(plane->src_height);
d8408326
SWK
590 val |= MXR_GRP_WH_H_SCALE(x_ratio);
591 val |= MXR_GRP_WH_V_SCALE(y_ratio);
592 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
593
594 /* setup offsets in source image */
595 val = MXR_GRP_SXY_SX(src_x_offset);
596 val |= MXR_GRP_SXY_SY(src_y_offset);
597 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
598
599 /* setup offsets in display image */
600 val = MXR_GRP_DXY_DX(dst_x_offset);
601 val |= MXR_GRP_DXY_DY(dst_y_offset);
602 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
603
604 /* set buffer address to mixer */
605 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
606
7ee14cdc
GP
607 mixer_cfg_scan(ctx, plane->mode_height);
608 mixer_cfg_rgb_fmt(ctx, plane->mode_height);
d8408326 609 mixer_cfg_layer(ctx, win, true);
aaf8b49e
RS
610
611 /* layer update mandatory for mixer 16.0.33.0 */
def5e095
RS
612 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
613 ctx->mxr_ver == MXR_VER_128_0_0_184)
aaf8b49e
RS
614 mixer_layer_update(ctx);
615
d8408326
SWK
616 mixer_run(ctx);
617
618 mixer_vsync_set_update(ctx, true);
619 spin_unlock_irqrestore(&res->reg_slock, flags);
620}
621
622static void vp_win_reset(struct mixer_context *ctx)
623{
624 struct mixer_resources *res = &ctx->mixer_res;
625 int tries = 100;
626
627 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
628 for (tries = 100; tries; --tries) {
629 /* waiting until VP_SRESET_PROCESSING is 0 */
630 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
631 break;
09760ea3 632 usleep_range(10000, 12000);
d8408326
SWK
633 }
634 WARN(tries == 0, "failed to reset Video Processor\n");
635}
636
cf8fc4f1
JS
637static void mixer_win_reset(struct mixer_context *ctx)
638{
639 struct mixer_resources *res = &ctx->mixer_res;
640 unsigned long flags;
641 u32 val; /* value stored to register */
642
643 spin_lock_irqsave(&res->reg_slock, flags);
644 mixer_vsync_set_update(ctx, false);
645
646 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
647
648 /* set output in RGB888 mode */
649 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
650
651 /* 16 beat burst in DMA */
652 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
653 MXR_STATUS_BURST_MASK);
654
655 /* setting default layer priority: layer1 > layer0 > video
656 * because typical usage scenario would be
657 * layer1 - OSD
658 * layer0 - framebuffer
659 * video - video overlay
660 */
661 val = MXR_LAYER_CFG_GRP1_VAL(3);
662 val |= MXR_LAYER_CFG_GRP0_VAL(2);
1b8e5747
RS
663 if (ctx->vp_enabled)
664 val |= MXR_LAYER_CFG_VP_VAL(1);
cf8fc4f1
JS
665 mixer_reg_write(res, MXR_LAYER_CFG, val);
666
667 /* setting background color */
668 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
669 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
670 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
671
672 /* setting graphical layers */
cf8fc4f1
JS
673 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
674 val |= MXR_GRP_CFG_WIN_BLEND_EN;
675 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
676
0377f4ed 677 /* Don't blend layer 0 onto the mixer background */
cf8fc4f1 678 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
0377f4ed
SP
679
680 /* Blend layer 1 into layer 0 */
681 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
682 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
cf8fc4f1
JS
683 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
684
5736603b
SWK
685 /* setting video layers */
686 val = MXR_GRP_CFG_ALPHA_VAL(0);
687 mixer_reg_write(res, MXR_VIDEO_CFG, val);
688
1b8e5747
RS
689 if (ctx->vp_enabled) {
690 /* configuration of Video Processor Registers */
691 vp_win_reset(ctx);
692 vp_default_filter(res);
693 }
cf8fc4f1
JS
694
695 /* disable all layers */
696 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
697 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
1b8e5747
RS
698 if (ctx->vp_enabled)
699 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
cf8fc4f1
JS
700
701 mixer_vsync_set_update(ctx, true);
702 spin_unlock_irqrestore(&res->reg_slock, flags);
703}
704
4551789f
SP
705static irqreturn_t mixer_irq_handler(int irq, void *arg)
706{
707 struct mixer_context *ctx = arg;
708 struct mixer_resources *res = &ctx->mixer_res;
709 u32 val, base, shadow;
710
711 spin_lock(&res->reg_slock);
712
713 /* read interrupt status for handling and clearing flags for VSYNC */
714 val = mixer_reg_read(res, MXR_INT_STATUS);
715
716 /* handling VSYNC */
717 if (val & MXR_INT_STATUS_VSYNC) {
718 /* interlace scan need to check shadow register */
719 if (ctx->interlace) {
720 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
721 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
722 if (base != shadow)
723 goto out;
724
725 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
726 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
727 if (base != shadow)
728 goto out;
729 }
730
731 drm_handle_vblank(ctx->drm_dev, ctx->pipe);
732 exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
733
734 /* set wait vsync event to zero and wake up queue. */
735 if (atomic_read(&ctx->wait_vsync_event)) {
736 atomic_set(&ctx->wait_vsync_event, 0);
737 wake_up(&ctx->wait_vsync_queue);
738 }
739 }
740
741out:
742 /* clear interrupts */
743 if (~val & MXR_INT_EN_VSYNC) {
744 /* vsync interrupt use different bit for read and clear */
745 val &= ~MXR_INT_EN_VSYNC;
746 val |= MXR_INT_CLEAR_VSYNC;
747 }
748 mixer_reg_write(res, MXR_INT_STATUS, val);
749
750 spin_unlock(&res->reg_slock);
751
752 return IRQ_HANDLED;
753}
754
755static int mixer_resources_init(struct mixer_context *mixer_ctx)
756{
757 struct device *dev = &mixer_ctx->pdev->dev;
758 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
759 struct resource *res;
760 int ret;
761
762 spin_lock_init(&mixer_res->reg_slock);
763
764 mixer_res->mixer = devm_clk_get(dev, "mixer");
765 if (IS_ERR(mixer_res->mixer)) {
766 dev_err(dev, "failed to get clock 'mixer'\n");
767 return -ENODEV;
768 }
769
04427ec5
MS
770 mixer_res->hdmi = devm_clk_get(dev, "hdmi");
771 if (IS_ERR(mixer_res->hdmi)) {
772 dev_err(dev, "failed to get clock 'hdmi'\n");
773 return PTR_ERR(mixer_res->hdmi);
774 }
775
4551789f
SP
776 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
777 if (IS_ERR(mixer_res->sclk_hdmi)) {
778 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
779 return -ENODEV;
780 }
781 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
782 if (res == NULL) {
783 dev_err(dev, "get memory resource failed.\n");
784 return -ENXIO;
785 }
786
787 mixer_res->mixer_regs = devm_ioremap(dev, res->start,
788 resource_size(res));
789 if (mixer_res->mixer_regs == NULL) {
790 dev_err(dev, "register mapping failed.\n");
791 return -ENXIO;
792 }
793
794 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
795 if (res == NULL) {
796 dev_err(dev, "get interrupt resource failed.\n");
797 return -ENXIO;
798 }
799
800 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
801 0, "drm_mixer", mixer_ctx);
802 if (ret) {
803 dev_err(dev, "request interrupt failed.\n");
804 return ret;
805 }
806 mixer_res->irq = res->start;
807
808 return 0;
809}
810
811static int vp_resources_init(struct mixer_context *mixer_ctx)
812{
813 struct device *dev = &mixer_ctx->pdev->dev;
814 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
815 struct resource *res;
816
817 mixer_res->vp = devm_clk_get(dev, "vp");
818 if (IS_ERR(mixer_res->vp)) {
819 dev_err(dev, "failed to get clock 'vp'\n");
820 return -ENODEV;
821 }
4551789f 822
ff830c96
MS
823 if (mixer_ctx->has_sclk) {
824 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
825 if (IS_ERR(mixer_res->sclk_mixer)) {
826 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
827 return -ENODEV;
828 }
829 mixer_res->mout_mixer = devm_clk_get(dev, "mout_mixer");
830 if (IS_ERR(mixer_res->mout_mixer)) {
831 dev_err(dev, "failed to get clock 'mout_mixer'\n");
832 return -ENODEV;
833 }
834
835 if (mixer_res->sclk_hdmi && mixer_res->mout_mixer)
836 clk_set_parent(mixer_res->mout_mixer,
837 mixer_res->sclk_hdmi);
838 }
4551789f
SP
839
840 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
841 if (res == NULL) {
842 dev_err(dev, "get memory resource failed.\n");
843 return -ENXIO;
844 }
845
846 mixer_res->vp_regs = devm_ioremap(dev, res->start,
847 resource_size(res));
848 if (mixer_res->vp_regs == NULL) {
849 dev_err(dev, "register mapping failed.\n");
850 return -ENXIO;
851 }
852
853 return 0;
854}
855
93bca243 856static int mixer_initialize(struct mixer_context *mixer_ctx,
f37cd5e8 857 struct drm_device *drm_dev)
4551789f
SP
858{
859 int ret;
f37cd5e8
ID
860 struct exynos_drm_private *priv;
861 priv = drm_dev->dev_private;
4551789f 862
eb88e422 863 mixer_ctx->drm_dev = drm_dev;
8a326edd 864 mixer_ctx->pipe = priv->pipe++;
4551789f
SP
865
866 /* acquire resources: regs, irqs, clocks */
867 ret = mixer_resources_init(mixer_ctx);
868 if (ret) {
869 DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
870 return ret;
871 }
872
873 if (mixer_ctx->vp_enabled) {
874 /* acquire vp resources: regs, irqs, clocks */
875 ret = vp_resources_init(mixer_ctx);
876 if (ret) {
877 DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
878 return ret;
879 }
880 }
881
f041b257
SP
882 if (!is_drm_iommu_supported(mixer_ctx->drm_dev))
883 return 0;
884
885 return drm_iommu_attach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
4551789f
SP
886}
887
93bca243 888static void mixer_ctx_remove(struct mixer_context *mixer_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
93bca243 894static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
d8408326 895{
93bca243 896 struct mixer_context *mixer_ctx = crtc->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
93bca243 911static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
d8408326 912{
93bca243 913 struct mixer_context *mixer_ctx = crtc->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
6e2a3b66 920static void mixer_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
d8408326 921{
93bca243 922 struct mixer_context *mixer_ctx = crtc->ctx;
d8408326 923
cbc4c33d 924 DRM_DEBUG_KMS("win: %d\n", win);
d8408326 925
dda9012b
S
926 mutex_lock(&mixer_ctx->mixer_mutex);
927 if (!mixer_ctx->powered) {
928 mutex_unlock(&mixer_ctx->mixer_mutex);
929 return;
930 }
931 mutex_unlock(&mixer_ctx->mixer_mutex);
932
1b8e5747 933 if (win > 1 && mixer_ctx->vp_enabled)
d8408326
SWK
934 vp_video_buffer(mixer_ctx, win);
935 else
936 mixer_graph_buffer(mixer_ctx, win);
db43fd16 937
7ee14cdc 938 mixer_ctx->planes[win].enabled = true;
d8408326
SWK
939}
940
6e2a3b66 941static void mixer_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
d8408326 942{
93bca243 943 struct mixer_context *mixer_ctx = crtc->ctx;
d8408326
SWK
944 struct mixer_resources *res = &mixer_ctx->mixer_res;
945 unsigned long flags;
d8408326 946
cbc4c33d 947 DRM_DEBUG_KMS("win: %d\n", win);
d8408326 948
db43fd16
P
949 mutex_lock(&mixer_ctx->mixer_mutex);
950 if (!mixer_ctx->powered) {
951 mutex_unlock(&mixer_ctx->mixer_mutex);
7ee14cdc 952 mixer_ctx->planes[win].resume = false;
db43fd16
P
953 return;
954 }
955 mutex_unlock(&mixer_ctx->mixer_mutex);
956
d8408326
SWK
957 spin_lock_irqsave(&res->reg_slock, flags);
958 mixer_vsync_set_update(mixer_ctx, false);
959
960 mixer_cfg_layer(mixer_ctx, win, false);
961
962 mixer_vsync_set_update(mixer_ctx, true);
963 spin_unlock_irqrestore(&res->reg_slock, flags);
db43fd16 964
7ee14cdc 965 mixer_ctx->planes[win].enabled = false;
d8408326
SWK
966}
967
93bca243 968static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
8137a2e2 969{
93bca243 970 struct mixer_context *mixer_ctx = crtc->ctx;
7c4c5584 971 int err;
8137a2e2 972
6e95d5e6
P
973 mutex_lock(&mixer_ctx->mixer_mutex);
974 if (!mixer_ctx->powered) {
975 mutex_unlock(&mixer_ctx->mixer_mutex);
976 return;
977 }
978 mutex_unlock(&mixer_ctx->mixer_mutex);
979
93bca243 980 err = drm_vblank_get(mixer_ctx->drm_dev, mixer_ctx->pipe);
7c4c5584
JS
981 if (err < 0) {
982 DRM_DEBUG_KMS("failed to acquire vblank counter\n");
983 return;
984 }
5d39b9ee 985
6e95d5e6
P
986 atomic_set(&mixer_ctx->wait_vsync_event, 1);
987
988 /*
989 * wait for MIXER to signal VSYNC interrupt or return after
990 * timeout which is set to 50ms (refresh rate of 20).
991 */
992 if (!wait_event_timeout(mixer_ctx->wait_vsync_queue,
993 !atomic_read(&mixer_ctx->wait_vsync_event),
bfd8303a 994 HZ/20))
8137a2e2 995 DRM_DEBUG_KMS("vblank wait timed out.\n");
5d39b9ee 996
93bca243 997 drm_vblank_put(mixer_ctx->drm_dev, mixer_ctx->pipe);
8137a2e2
P
998}
999
92dc7a04 1000static void mixer_window_suspend(struct mixer_context *ctx)
db43fd16 1001{
7ee14cdc 1002 struct exynos_drm_plane *plane;
db43fd16
P
1003 int i;
1004
1005 for (i = 0; i < MIXER_WIN_NR; i++) {
7ee14cdc
GP
1006 plane = &ctx->planes[i];
1007 plane->resume = plane->enabled;
92dc7a04 1008 mixer_win_disable(ctx->crtc, i);
db43fd16 1009 }
92dc7a04 1010 mixer_wait_for_vblank(ctx->crtc);
db43fd16
P
1011}
1012
92dc7a04 1013static void mixer_window_resume(struct mixer_context *ctx)
db43fd16 1014{
7ee14cdc 1015 struct exynos_drm_plane *plane;
db43fd16
P
1016 int i;
1017
1018 for (i = 0; i < MIXER_WIN_NR; i++) {
7ee14cdc
GP
1019 plane = &ctx->planes[i];
1020 plane->enabled = plane->resume;
1021 plane->resume = false;
1022 if (plane->enabled)
92dc7a04 1023 mixer_win_commit(ctx->crtc, i);
db43fd16
P
1024 }
1025}
1026
92dc7a04 1027static void mixer_poweron(struct mixer_context *ctx)
db43fd16
P
1028{
1029 struct mixer_resources *res = &ctx->mixer_res;
1030
db43fd16
P
1031 mutex_lock(&ctx->mixer_mutex);
1032 if (ctx->powered) {
1033 mutex_unlock(&ctx->mixer_mutex);
1034 return;
1035 }
b4bfa3c7 1036
db43fd16
P
1037 mutex_unlock(&ctx->mixer_mutex);
1038
af65c804
SP
1039 pm_runtime_get_sync(ctx->dev);
1040
0bfb1f8b 1041 clk_prepare_enable(res->mixer);
04427ec5 1042 clk_prepare_enable(res->hdmi);
db43fd16 1043 if (ctx->vp_enabled) {
0bfb1f8b 1044 clk_prepare_enable(res->vp);
ff830c96
MS
1045 if (ctx->has_sclk)
1046 clk_prepare_enable(res->sclk_mixer);
db43fd16
P
1047 }
1048
b4bfa3c7
RS
1049 mutex_lock(&ctx->mixer_mutex);
1050 ctx->powered = true;
1051 mutex_unlock(&ctx->mixer_mutex);
1052
d74ed937
RS
1053 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
1054
db43fd16
P
1055 mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
1056 mixer_win_reset(ctx);
1057
92dc7a04 1058 mixer_window_resume(ctx);
db43fd16
P
1059}
1060
92dc7a04 1061static void mixer_poweroff(struct mixer_context *ctx)
db43fd16
P
1062{
1063 struct mixer_resources *res = &ctx->mixer_res;
1064
db43fd16 1065 mutex_lock(&ctx->mixer_mutex);
b4bfa3c7
RS
1066 if (!ctx->powered) {
1067 mutex_unlock(&ctx->mixer_mutex);
1068 return;
1069 }
db43fd16
P
1070 mutex_unlock(&ctx->mixer_mutex);
1071
381be025 1072 mixer_stop(ctx);
92dc7a04 1073 mixer_window_suspend(ctx);
db43fd16
P
1074
1075 ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
1076
b4bfa3c7
RS
1077 mutex_lock(&ctx->mixer_mutex);
1078 ctx->powered = false;
1079 mutex_unlock(&ctx->mixer_mutex);
1080
04427ec5 1081 clk_disable_unprepare(res->hdmi);
0bfb1f8b 1082 clk_disable_unprepare(res->mixer);
db43fd16 1083 if (ctx->vp_enabled) {
0bfb1f8b 1084 clk_disable_unprepare(res->vp);
ff830c96
MS
1085 if (ctx->has_sclk)
1086 clk_disable_unprepare(res->sclk_mixer);
db43fd16
P
1087 }
1088
af65c804 1089 pm_runtime_put_sync(ctx->dev);
db43fd16
P
1090}
1091
93bca243 1092static void mixer_dpms(struct exynos_drm_crtc *crtc, int mode)
db43fd16 1093{
db43fd16
P
1094 switch (mode) {
1095 case DRM_MODE_DPMS_ON:
92dc7a04 1096 mixer_poweron(crtc->ctx);
db43fd16
P
1097 break;
1098 case DRM_MODE_DPMS_STANDBY:
1099 case DRM_MODE_DPMS_SUSPEND:
1100 case DRM_MODE_DPMS_OFF:
92dc7a04 1101 mixer_poweroff(crtc->ctx);
db43fd16
P
1102 break;
1103 default:
1104 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
1105 break;
1106 }
1107}
1108
f041b257
SP
1109/* Only valid for Mixer version 16.0.33.0 */
1110int mixer_check_mode(struct drm_display_mode *mode)
1111{
1112 u32 w, h;
1113
1114 w = mode->hdisplay;
1115 h = mode->vdisplay;
1116
1117 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
1118 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1119 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1120
1121 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
1122 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1123 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1124 return 0;
1125
1126 return -EINVAL;
1127}
1128
93bca243 1129static struct exynos_drm_crtc_ops mixer_crtc_ops = {
f041b257 1130 .dpms = mixer_dpms,
d8408326
SWK
1131 .enable_vblank = mixer_enable_vblank,
1132 .disable_vblank = mixer_disable_vblank,
8137a2e2 1133 .wait_for_vblank = mixer_wait_for_vblank,
d8408326
SWK
1134 .win_commit = mixer_win_commit,
1135 .win_disable = mixer_win_disable,
f041b257 1136};
0ea6822f 1137
def5e095
RS
1138static struct mixer_drv_data exynos5420_mxr_drv_data = {
1139 .version = MXR_VER_128_0_0_184,
1140 .is_vp_enabled = 0,
1141};
1142
cc57caf0 1143static struct mixer_drv_data exynos5250_mxr_drv_data = {
aaf8b49e
RS
1144 .version = MXR_VER_16_0_33_0,
1145 .is_vp_enabled = 0,
1146};
1147
ff830c96
MS
1148static struct mixer_drv_data exynos4212_mxr_drv_data = {
1149 .version = MXR_VER_0_0_0_16,
1150 .is_vp_enabled = 1,
1151};
1152
cc57caf0 1153static struct mixer_drv_data exynos4210_mxr_drv_data = {
1e123441 1154 .version = MXR_VER_0_0_0_16,
1b8e5747 1155 .is_vp_enabled = 1,
ff830c96 1156 .has_sclk = 1,
1e123441
RS
1157};
1158
1159static struct platform_device_id mixer_driver_types[] = {
1160 {
1161 .name = "s5p-mixer",
cc57caf0 1162 .driver_data = (unsigned long)&exynos4210_mxr_drv_data,
aaf8b49e
RS
1163 }, {
1164 .name = "exynos5-mixer",
cc57caf0 1165 .driver_data = (unsigned long)&exynos5250_mxr_drv_data,
aaf8b49e
RS
1166 }, {
1167 /* end node */
1168 }
1169};
1170
1171static struct of_device_id mixer_match_types[] = {
1172 {
ff830c96
MS
1173 .compatible = "samsung,exynos4210-mixer",
1174 .data = &exynos4210_mxr_drv_data,
1175 }, {
1176 .compatible = "samsung,exynos4212-mixer",
1177 .data = &exynos4212_mxr_drv_data,
1178 }, {
aaf8b49e 1179 .compatible = "samsung,exynos5-mixer",
cc57caf0
RS
1180 .data = &exynos5250_mxr_drv_data,
1181 }, {
1182 .compatible = "samsung,exynos5250-mixer",
1183 .data = &exynos5250_mxr_drv_data,
def5e095
RS
1184 }, {
1185 .compatible = "samsung,exynos5420-mixer",
1186 .data = &exynos5420_mxr_drv_data,
1e123441
RS
1187 }, {
1188 /* end node */
1189 }
1190};
39b58a39 1191MODULE_DEVICE_TABLE(of, mixer_match_types);
1e123441 1192
f37cd5e8 1193static int mixer_bind(struct device *dev, struct device *manager, void *data)
d8408326 1194{
8103ef1b 1195 struct mixer_context *ctx = dev_get_drvdata(dev);
f37cd5e8 1196 struct drm_device *drm_dev = data;
7ee14cdc
GP
1197 struct exynos_drm_plane *exynos_plane;
1198 enum drm_plane_type type;
6e2a3b66
GP
1199 unsigned int zpos;
1200 int ret;
d8408326 1201
e2dc3f72
AB
1202 ret = mixer_initialize(ctx, drm_dev);
1203 if (ret)
1204 return ret;
1205
7ee14cdc
GP
1206 for (zpos = 0; zpos < MIXER_WIN_NR; zpos++) {
1207 type = (zpos == MIXER_DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY :
1208 DRM_PLANE_TYPE_OVERLAY;
1209 ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
6e2a3b66 1210 1 << ctx->pipe, type, zpos);
7ee14cdc
GP
1211 if (ret)
1212 return ret;
1213 }
1214
1215 exynos_plane = &ctx->planes[MIXER_DEFAULT_WIN];
1216 ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
1217 ctx->pipe, EXYNOS_DISPLAY_TYPE_HDMI,
1218 &mixer_crtc_ops, ctx);
93bca243 1219 if (IS_ERR(ctx->crtc)) {
e2dc3f72 1220 mixer_ctx_remove(ctx);
93bca243
GP
1221 ret = PTR_ERR(ctx->crtc);
1222 goto free_ctx;
f37cd5e8 1223 }
d8408326 1224
d8408326 1225 return 0;
93bca243
GP
1226
1227free_ctx:
1228 devm_kfree(dev, ctx);
1229 return ret;
d8408326
SWK
1230}
1231
f37cd5e8 1232static void mixer_unbind(struct device *dev, struct device *master, void *data)
d8408326 1233{
8103ef1b 1234 struct mixer_context *ctx = dev_get_drvdata(dev);
f37cd5e8 1235
93bca243 1236 mixer_ctx_remove(ctx);
f37cd5e8
ID
1237}
1238
1239static const struct component_ops mixer_component_ops = {
1240 .bind = mixer_bind,
1241 .unbind = mixer_unbind,
1242};
1243
1244static int mixer_probe(struct platform_device *pdev)
1245{
8103ef1b
AH
1246 struct device *dev = &pdev->dev;
1247 struct mixer_drv_data *drv;
1248 struct mixer_context *ctx;
df5225bc
ID
1249 int ret;
1250
8103ef1b
AH
1251 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1252 if (!ctx) {
1253 DRM_ERROR("failed to alloc mixer context.\n");
1254 return -ENOMEM;
1255 }
1256
1257 mutex_init(&ctx->mixer_mutex);
1258
8103ef1b
AH
1259 if (dev->of_node) {
1260 const struct of_device_id *match;
1261
1262 match = of_match_node(mixer_match_types, dev->of_node);
1263 drv = (struct mixer_drv_data *)match->data;
1264 } else {
1265 drv = (struct mixer_drv_data *)
1266 platform_get_device_id(pdev)->driver_data;
1267 }
1268
1269 ctx->pdev = pdev;
1270 ctx->dev = dev;
1271 ctx->vp_enabled = drv->is_vp_enabled;
1272 ctx->has_sclk = drv->has_sclk;
1273 ctx->mxr_ver = drv->version;
1274 init_waitqueue_head(&ctx->wait_vsync_queue);
1275 atomic_set(&ctx->wait_vsync_event, 0);
8103ef1b
AH
1276
1277 platform_set_drvdata(pdev, ctx);
1278
df5225bc 1279 ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
5d1741ad 1280 EXYNOS_DISPLAY_TYPE_HDMI);
df5225bc
ID
1281 if (ret)
1282 return ret;
1283
1284 ret = component_add(&pdev->dev, &mixer_component_ops);
8103ef1b 1285 if (ret) {
df5225bc 1286 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
8103ef1b
AH
1287 return ret;
1288 }
1289
1290 pm_runtime_enable(dev);
df5225bc
ID
1291
1292 return ret;
f37cd5e8
ID
1293}
1294
1295static int mixer_remove(struct platform_device *pdev)
1296{
8103ef1b
AH
1297 pm_runtime_disable(&pdev->dev);
1298
df5225bc
ID
1299 component_del(&pdev->dev, &mixer_component_ops);
1300 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
1301
d8408326
SWK
1302 return 0;
1303}
1304
1305struct platform_driver mixer_driver = {
1306 .driver = {
aaf8b49e 1307 .name = "exynos-mixer",
d8408326 1308 .owner = THIS_MODULE,
aaf8b49e 1309 .of_match_table = mixer_match_types,
d8408326
SWK
1310 },
1311 .probe = mixer_probe,
56550d94 1312 .remove = mixer_remove,
1e123441 1313 .id_table = mixer_driver_types,
d8408326 1314};
This page took 0.378828 seconds and 5 git commands to generate.