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