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