]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/gpu/drm/exynos/exynos_mixer.c
Merge remote-tracking branches 'spi/topic/devprop', 'spi/topic/fsl', 'spi/topic/fsl...
[mirror_ubuntu-bionic-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
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,
adeb6f44
TJ
76 MXR_BIT_INTERLACE,
77 MXR_BIT_VP_ENABLED,
78 MXR_BIT_HAS_SCLK,
a44652e8
AH
79};
80
fbbb1e1a
MS
81static const uint32_t mixer_formats[] = {
82 DRM_FORMAT_XRGB4444,
26a7af3e 83 DRM_FORMAT_ARGB4444,
fbbb1e1a 84 DRM_FORMAT_XRGB1555,
26a7af3e 85 DRM_FORMAT_ARGB1555,
fbbb1e1a
MS
86 DRM_FORMAT_RGB565,
87 DRM_FORMAT_XRGB8888,
88 DRM_FORMAT_ARGB8888,
89};
90
91static const uint32_t vp_formats[] = {
92 DRM_FORMAT_NV12,
93 DRM_FORMAT_NV21,
94};
95
22b21ae6 96struct mixer_context {
4551789f 97 struct platform_device *pdev;
cf8fc4f1 98 struct device *dev;
1055b39f 99 struct drm_device *drm_dev;
93bca243 100 struct exynos_drm_crtc *crtc;
7ee14cdc 101 struct exynos_drm_plane planes[MIXER_WIN_NR];
22b21ae6 102 int pipe;
a44652e8 103 unsigned long flags;
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
adeb6f44 349 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags))
1b8e5747 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 */
adeb6f44
TJ
360 val = test_bit(MXR_BIT_INTERLACE, &ctx->flags) ?
361 MXR_CFG_SCAN_INTERLACE : 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);
adeb6f44 439
d8408326 440 break;
5e68fef2 441 case VP_DEFAULT_WIN:
adeb6f44 442 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
1b8e5747
RS
443 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
444 mixer_reg_writemask(res, MXR_CFG, val,
445 MXR_CFG_VP_ENABLE);
a2cb911e
MS
446 mixer_reg_writemask(res, MXR_LAYER_CFG,
447 MXR_LAYER_CFG_VP_VAL(priority),
448 MXR_LAYER_CFG_VP_MASK);
1b8e5747 449 }
d8408326
SWK
450 break;
451 }
452}
453
454static void mixer_run(struct mixer_context *ctx)
455{
456 struct mixer_resources *res = &ctx->mixer_res;
457
458 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
d8408326
SWK
459}
460
381be025
RS
461static void mixer_stop(struct mixer_context *ctx)
462{
463 struct mixer_resources *res = &ctx->mixer_res;
464 int timeout = 20;
465
466 mixer_reg_writemask(res, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
467
468 while (!(mixer_reg_read(res, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
469 --timeout)
470 usleep_range(10000, 12000);
381be025
RS
471}
472
2eeb2e5e
GP
473static void vp_video_buffer(struct mixer_context *ctx,
474 struct exynos_drm_plane *plane)
d8408326 475{
0114f404
MS
476 struct exynos_drm_plane_state *state =
477 to_exynos_plane_state(plane->base.state);
2ee35d8b 478 struct drm_display_mode *mode = &state->base.crtc->state->adjusted_mode;
d8408326 479 struct mixer_resources *res = &ctx->mixer_res;
0114f404 480 struct drm_framebuffer *fb = state->base.fb;
e47726a1 481 unsigned int priority = state->base.normalized_zpos + 1;
d8408326 482 unsigned long flags;
d8408326
SWK
483 dma_addr_t luma_addr[2], chroma_addr[2];
484 bool tiled_mode = false;
485 bool crcb_mode = false;
486 u32 val;
487
438b74a5 488 switch (fb->format->format) {
363b06aa 489 case DRM_FORMAT_NV12:
d8408326 490 crcb_mode = false;
d8408326 491 break;
8f2590f8
TJ
492 case DRM_FORMAT_NV21:
493 crcb_mode = true;
494 break;
d8408326 495 default:
d8408326 496 DRM_ERROR("pixel format for vp is wrong [%d].\n",
438b74a5 497 fb->format->format);
d8408326
SWK
498 return;
499 }
500
0488f50e
MS
501 luma_addr[0] = exynos_drm_fb_dma_addr(fb, 0);
502 chroma_addr[0] = exynos_drm_fb_dma_addr(fb, 1);
d8408326 503
2eeb2e5e 504 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
adeb6f44 505 __set_bit(MXR_BIT_INTERLACE, &ctx->flags);
d8408326
SWK
506 if (tiled_mode) {
507 luma_addr[1] = luma_addr[0] + 0x40;
508 chroma_addr[1] = chroma_addr[0] + 0x40;
509 } else {
2eeb2e5e
GP
510 luma_addr[1] = luma_addr[0] + fb->pitches[0];
511 chroma_addr[1] = chroma_addr[0] + fb->pitches[0];
d8408326
SWK
512 }
513 } else {
adeb6f44 514 __clear_bit(MXR_BIT_INTERLACE, &ctx->flags);
d8408326
SWK
515 luma_addr[1] = 0;
516 chroma_addr[1] = 0;
517 }
518
519 spin_lock_irqsave(&res->reg_slock, flags);
d8408326
SWK
520
521 /* interlace or progressive scan mode */
adeb6f44 522 val = (test_bit(MXR_BIT_INTERLACE, &ctx->flags) ? ~0 : 0);
d8408326
SWK
523 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
524
525 /* setup format */
526 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
527 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
528 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
529
530 /* setting size of input image */
2eeb2e5e
GP
531 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(fb->pitches[0]) |
532 VP_IMG_VSIZE(fb->height));
d8408326 533 /* chroma height has to reduced by 2 to avoid chroma distorions */
2eeb2e5e
GP
534 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(fb->pitches[0]) |
535 VP_IMG_VSIZE(fb->height / 2));
d8408326 536
0114f404
MS
537 vp_reg_write(res, VP_SRC_WIDTH, state->src.w);
538 vp_reg_write(res, VP_SRC_HEIGHT, state->src.h);
d8408326 539 vp_reg_write(res, VP_SRC_H_POSITION,
0114f404
MS
540 VP_SRC_H_POSITION_VAL(state->src.x));
541 vp_reg_write(res, VP_SRC_V_POSITION, state->src.y);
d8408326 542
0114f404
MS
543 vp_reg_write(res, VP_DST_WIDTH, state->crtc.w);
544 vp_reg_write(res, VP_DST_H_POSITION, state->crtc.x);
adeb6f44 545 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
0114f404
MS
546 vp_reg_write(res, VP_DST_HEIGHT, state->crtc.h / 2);
547 vp_reg_write(res, VP_DST_V_POSITION, state->crtc.y / 2);
d8408326 548 } else {
0114f404
MS
549 vp_reg_write(res, VP_DST_HEIGHT, state->crtc.h);
550 vp_reg_write(res, VP_DST_V_POSITION, state->crtc.y);
d8408326
SWK
551 }
552
0114f404
MS
553 vp_reg_write(res, VP_H_RATIO, state->h_ratio);
554 vp_reg_write(res, VP_V_RATIO, state->v_ratio);
d8408326
SWK
555
556 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
557
558 /* set buffer address to vp */
559 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
560 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
561 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
562 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
563
2eeb2e5e
GP
564 mixer_cfg_scan(ctx, mode->vdisplay);
565 mixer_cfg_rgb_fmt(ctx, mode->vdisplay);
e47726a1 566 mixer_cfg_layer(ctx, plane->index, priority, true);
f657a996 567 mixer_cfg_vp_blend(ctx);
d8408326
SWK
568 mixer_run(ctx);
569
d8408326
SWK
570 spin_unlock_irqrestore(&res->reg_slock, flags);
571
c0734fba 572 mixer_regs_dump(ctx);
d8408326
SWK
573 vp_regs_dump(ctx);
574}
575
aaf8b49e
RS
576static void mixer_layer_update(struct mixer_context *ctx)
577{
578 struct mixer_resources *res = &ctx->mixer_res;
aaf8b49e 579
5c0f4829 580 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
aaf8b49e
RS
581}
582
2eeb2e5e
GP
583static void mixer_graph_buffer(struct mixer_context *ctx,
584 struct exynos_drm_plane *plane)
d8408326 585{
0114f404
MS
586 struct exynos_drm_plane_state *state =
587 to_exynos_plane_state(plane->base.state);
2ee35d8b 588 struct drm_display_mode *mode = &state->base.crtc->state->adjusted_mode;
d8408326 589 struct mixer_resources *res = &ctx->mixer_res;
0114f404 590 struct drm_framebuffer *fb = state->base.fb;
e47726a1 591 unsigned int priority = state->base.normalized_zpos + 1;
d8408326 592 unsigned long flags;
40bdfb0a 593 unsigned int win = plane->index;
2611015c 594 unsigned int x_ratio = 0, y_ratio = 0;
d8408326 595 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
d8408326
SWK
596 dma_addr_t dma_addr;
597 unsigned int fmt;
598 u32 val;
599
438b74a5 600 switch (fb->format->format) {
7a57ca7c 601 case DRM_FORMAT_XRGB4444:
26a7af3e 602 case DRM_FORMAT_ARGB4444:
7a57ca7c
TJ
603 fmt = MXR_FORMAT_ARGB4444;
604 break;
605
606 case DRM_FORMAT_XRGB1555:
26a7af3e 607 case DRM_FORMAT_ARGB1555:
7a57ca7c
TJ
608 fmt = MXR_FORMAT_ARGB1555;
609 break;
d8408326 610
7a57ca7c
TJ
611 case DRM_FORMAT_RGB565:
612 fmt = MXR_FORMAT_RGB565;
d8408326 613 break;
7a57ca7c
TJ
614
615 case DRM_FORMAT_XRGB8888:
616 case DRM_FORMAT_ARGB8888:
617 fmt = MXR_FORMAT_ARGB8888;
d8408326 618 break;
7a57ca7c 619
d8408326 620 default:
7a57ca7c
TJ
621 DRM_DEBUG_KMS("pixelformat unsupported by mixer\n");
622 return;
d8408326
SWK
623 }
624
e463b069
MS
625 /* ratio is already checked by common plane code */
626 x_ratio = state->h_ratio == (1 << 15);
627 y_ratio = state->v_ratio == (1 << 15);
d8408326 628
0114f404
MS
629 dst_x_offset = state->crtc.x;
630 dst_y_offset = state->crtc.y;
d8408326
SWK
631
632 /* converting dma address base and source offset */
0488f50e 633 dma_addr = exynos_drm_fb_dma_addr(fb, 0)
272725c7 634 + (state->src.x * fb->format->cpp[0])
0114f404 635 + (state->src.y * fb->pitches[0]);
d8408326
SWK
636 src_x_offset = 0;
637 src_y_offset = 0;
638
2eeb2e5e 639 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
adeb6f44 640 __set_bit(MXR_BIT_INTERLACE, &ctx->flags);
d8408326 641 else
adeb6f44 642 __clear_bit(MXR_BIT_INTERLACE, &ctx->flags);
d8408326
SWK
643
644 spin_lock_irqsave(&res->reg_slock, flags);
d8408326
SWK
645
646 /* setup format */
647 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
648 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
649
650 /* setup geometry */
adacb228 651 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win),
272725c7 652 fb->pitches[0] / fb->format->cpp[0]);
d8408326 653
def5e095
RS
654 /* setup display size */
655 if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
5d3d0995 656 win == DEFAULT_WIN) {
2eeb2e5e
GP
657 val = MXR_MXR_RES_HEIGHT(mode->vdisplay);
658 val |= MXR_MXR_RES_WIDTH(mode->hdisplay);
def5e095
RS
659 mixer_reg_write(res, MXR_RESOLUTION, val);
660 }
661
0114f404
MS
662 val = MXR_GRP_WH_WIDTH(state->src.w);
663 val |= MXR_GRP_WH_HEIGHT(state->src.h);
d8408326
SWK
664 val |= MXR_GRP_WH_H_SCALE(x_ratio);
665 val |= MXR_GRP_WH_V_SCALE(y_ratio);
666 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
667
668 /* setup offsets in source image */
669 val = MXR_GRP_SXY_SX(src_x_offset);
670 val |= MXR_GRP_SXY_SY(src_y_offset);
671 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
672
673 /* setup offsets in display image */
674 val = MXR_GRP_DXY_DX(dst_x_offset);
675 val |= MXR_GRP_DXY_DY(dst_y_offset);
676 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
677
678 /* set buffer address to mixer */
679 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
680
2eeb2e5e
GP
681 mixer_cfg_scan(ctx, mode->vdisplay);
682 mixer_cfg_rgb_fmt(ctx, mode->vdisplay);
e47726a1 683 mixer_cfg_layer(ctx, win, priority, true);
438b74a5 684 mixer_cfg_gfx_blend(ctx, win, is_alpha_format(fb->format->format));
aaf8b49e
RS
685
686 /* layer update mandatory for mixer 16.0.33.0 */
def5e095
RS
687 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
688 ctx->mxr_ver == MXR_VER_128_0_0_184)
aaf8b49e
RS
689 mixer_layer_update(ctx);
690
d8408326
SWK
691 mixer_run(ctx);
692
d8408326 693 spin_unlock_irqrestore(&res->reg_slock, flags);
c0734fba
TJ
694
695 mixer_regs_dump(ctx);
d8408326
SWK
696}
697
698static void vp_win_reset(struct mixer_context *ctx)
699{
700 struct mixer_resources *res = &ctx->mixer_res;
a696394c 701 unsigned int tries = 100;
d8408326
SWK
702
703 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
8646dcb8 704 while (--tries) {
d8408326
SWK
705 /* waiting until VP_SRESET_PROCESSING is 0 */
706 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
707 break;
02b3de43 708 mdelay(10);
d8408326
SWK
709 }
710 WARN(tries == 0, "failed to reset Video Processor\n");
711}
712
cf8fc4f1
JS
713static void mixer_win_reset(struct mixer_context *ctx)
714{
715 struct mixer_resources *res = &ctx->mixer_res;
716 unsigned long flags;
cf8fc4f1
JS
717
718 spin_lock_irqsave(&res->reg_slock, flags);
cf8fc4f1
JS
719
720 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
721
722 /* set output in RGB888 mode */
723 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
724
725 /* 16 beat burst in DMA */
726 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
727 MXR_STATUS_BURST_MASK);
728
a2cb911e
MS
729 /* reset default layer priority */
730 mixer_reg_write(res, MXR_LAYER_CFG, 0);
cf8fc4f1
JS
731
732 /* setting background color */
733 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
734 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
735 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
736
adeb6f44 737 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
1b8e5747
RS
738 /* configuration of Video Processor Registers */
739 vp_win_reset(ctx);
740 vp_default_filter(res);
741 }
cf8fc4f1
JS
742
743 /* disable all layers */
744 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
745 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
adeb6f44 746 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags))
1b8e5747 747 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
cf8fc4f1 748
cf8fc4f1
JS
749 spin_unlock_irqrestore(&res->reg_slock, flags);
750}
751
4551789f
SP
752static irqreturn_t mixer_irq_handler(int irq, void *arg)
753{
754 struct mixer_context *ctx = arg;
755 struct mixer_resources *res = &ctx->mixer_res;
756 u32 val, base, shadow;
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 769 /* interlace scan need to check shadow register */
adeb6f44 770 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
4551789f
SP
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);
4551789f
SP
783 }
784
785out:
786 /* clear interrupts */
4551789f
SP
787 mixer_reg_write(res, MXR_INT_STATUS, val);
788
789 spin_unlock(&res->reg_slock);
790
791 return IRQ_HANDLED;
792}
793
794static int mixer_resources_init(struct mixer_context *mixer_ctx)
795{
796 struct device *dev = &mixer_ctx->pdev->dev;
797 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
798 struct resource *res;
799 int ret;
800
801 spin_lock_init(&mixer_res->reg_slock);
802
803 mixer_res->mixer = devm_clk_get(dev, "mixer");
804 if (IS_ERR(mixer_res->mixer)) {
805 dev_err(dev, "failed to get clock 'mixer'\n");
806 return -ENODEV;
807 }
808
04427ec5
MS
809 mixer_res->hdmi = devm_clk_get(dev, "hdmi");
810 if (IS_ERR(mixer_res->hdmi)) {
811 dev_err(dev, "failed to get clock 'hdmi'\n");
812 return PTR_ERR(mixer_res->hdmi);
813 }
814
4551789f
SP
815 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
816 if (IS_ERR(mixer_res->sclk_hdmi)) {
817 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
818 return -ENODEV;
819 }
820 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
821 if (res == NULL) {
822 dev_err(dev, "get memory resource failed.\n");
823 return -ENXIO;
824 }
825
826 mixer_res->mixer_regs = devm_ioremap(dev, res->start,
827 resource_size(res));
828 if (mixer_res->mixer_regs == NULL) {
829 dev_err(dev, "register mapping failed.\n");
830 return -ENXIO;
831 }
832
833 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
834 if (res == NULL) {
835 dev_err(dev, "get interrupt resource failed.\n");
836 return -ENXIO;
837 }
838
839 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
840 0, "drm_mixer", mixer_ctx);
841 if (ret) {
842 dev_err(dev, "request interrupt failed.\n");
843 return ret;
844 }
845 mixer_res->irq = res->start;
846
847 return 0;
848}
849
850static int vp_resources_init(struct mixer_context *mixer_ctx)
851{
852 struct device *dev = &mixer_ctx->pdev->dev;
853 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
854 struct resource *res;
855
856 mixer_res->vp = devm_clk_get(dev, "vp");
857 if (IS_ERR(mixer_res->vp)) {
858 dev_err(dev, "failed to get clock 'vp'\n");
859 return -ENODEV;
860 }
4551789f 861
adeb6f44 862 if (test_bit(MXR_BIT_HAS_SCLK, &mixer_ctx->flags)) {
ff830c96
MS
863 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
864 if (IS_ERR(mixer_res->sclk_mixer)) {
865 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
866 return -ENODEV;
867 }
868 mixer_res->mout_mixer = devm_clk_get(dev, "mout_mixer");
869 if (IS_ERR(mixer_res->mout_mixer)) {
870 dev_err(dev, "failed to get clock 'mout_mixer'\n");
871 return -ENODEV;
872 }
873
874 if (mixer_res->sclk_hdmi && mixer_res->mout_mixer)
875 clk_set_parent(mixer_res->mout_mixer,
876 mixer_res->sclk_hdmi);
877 }
4551789f
SP
878
879 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
880 if (res == NULL) {
881 dev_err(dev, "get memory resource failed.\n");
882 return -ENXIO;
883 }
884
885 mixer_res->vp_regs = devm_ioremap(dev, res->start,
886 resource_size(res));
887 if (mixer_res->vp_regs == NULL) {
888 dev_err(dev, "register mapping failed.\n");
889 return -ENXIO;
890 }
891
892 return 0;
893}
894
93bca243 895static int mixer_initialize(struct mixer_context *mixer_ctx,
f37cd5e8 896 struct drm_device *drm_dev)
4551789f
SP
897{
898 int ret;
f37cd5e8
ID
899 struct exynos_drm_private *priv;
900 priv = drm_dev->dev_private;
4551789f 901
eb88e422 902 mixer_ctx->drm_dev = drm_dev;
8a326edd 903 mixer_ctx->pipe = priv->pipe++;
4551789f
SP
904
905 /* acquire resources: regs, irqs, clocks */
906 ret = mixer_resources_init(mixer_ctx);
907 if (ret) {
908 DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
909 return ret;
910 }
911
adeb6f44 912 if (test_bit(MXR_BIT_VP_ENABLED, &mixer_ctx->flags)) {
4551789f
SP
913 /* acquire vp resources: regs, irqs, clocks */
914 ret = vp_resources_init(mixer_ctx);
915 if (ret) {
916 DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
917 return ret;
918 }
919 }
920
eb7a3fc7 921 ret = drm_iommu_attach_device(drm_dev, mixer_ctx->dev);
fc2e013f
HH
922 if (ret)
923 priv->pipe--;
f041b257 924
fc2e013f 925 return ret;
4551789f
SP
926}
927
93bca243 928static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
1055b39f 929{
bf56608a 930 drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
1055b39f
ID
931}
932
93bca243 933static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
d8408326 934{
93bca243 935 struct mixer_context *mixer_ctx = crtc->ctx;
d8408326
SWK
936 struct mixer_resources *res = &mixer_ctx->mixer_res;
937
0df5e4ac
AH
938 __set_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
939 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
f041b257 940 return 0;
d8408326
SWK
941
942 /* enable vsync interrupt */
fc073248
AH
943 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
944 mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
d8408326
SWK
945
946 return 0;
947}
948
93bca243 949static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
d8408326 950{
93bca243 951 struct mixer_context *mixer_ctx = crtc->ctx;
d8408326
SWK
952 struct mixer_resources *res = &mixer_ctx->mixer_res;
953
0df5e4ac
AH
954 __clear_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
955
956 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
947710c6 957 return;
947710c6 958
d8408326 959 /* disable vsync interrupt */
fc073248 960 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
d8408326
SWK
961 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
962}
963
3dbaab16
MS
964static void mixer_atomic_begin(struct exynos_drm_crtc *crtc)
965{
966 struct mixer_context *mixer_ctx = crtc->ctx;
967
968 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
969 return;
970
971 mixer_vsync_set_update(mixer_ctx, false);
972}
973
1e1d1393
GP
974static void mixer_update_plane(struct exynos_drm_crtc *crtc,
975 struct exynos_drm_plane *plane)
d8408326 976{
93bca243 977 struct mixer_context *mixer_ctx = crtc->ctx;
d8408326 978
40bdfb0a 979 DRM_DEBUG_KMS("win: %d\n", plane->index);
d8408326 980
a44652e8 981 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
dda9012b 982 return;
dda9012b 983
5e68fef2 984 if (plane->index == VP_DEFAULT_WIN)
2eeb2e5e 985 vp_video_buffer(mixer_ctx, plane);
d8408326 986 else
2eeb2e5e 987 mixer_graph_buffer(mixer_ctx, plane);
d8408326
SWK
988}
989
1e1d1393
GP
990static void mixer_disable_plane(struct exynos_drm_crtc *crtc,
991 struct exynos_drm_plane *plane)
d8408326 992{
93bca243 993 struct mixer_context *mixer_ctx = crtc->ctx;
d8408326
SWK
994 struct mixer_resources *res = &mixer_ctx->mixer_res;
995 unsigned long flags;
d8408326 996
40bdfb0a 997 DRM_DEBUG_KMS("win: %d\n", plane->index);
d8408326 998
a44652e8 999 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
db43fd16 1000 return;
db43fd16 1001
d8408326 1002 spin_lock_irqsave(&res->reg_slock, flags);
a2cb911e 1003 mixer_cfg_layer(mixer_ctx, plane->index, 0, false);
3dbaab16
MS
1004 spin_unlock_irqrestore(&res->reg_slock, flags);
1005}
1006
1007static void mixer_atomic_flush(struct exynos_drm_crtc *crtc)
1008{
1009 struct mixer_context *mixer_ctx = crtc->ctx;
1010
1011 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
1012 return;
d8408326
SWK
1013
1014 mixer_vsync_set_update(mixer_ctx, true);
a392276d 1015 exynos_crtc_handle_event(crtc);
d8408326
SWK
1016}
1017
3cecda03 1018static void mixer_enable(struct exynos_drm_crtc *crtc)
db43fd16 1019{
3cecda03 1020 struct mixer_context *ctx = crtc->ctx;
db43fd16
P
1021 struct mixer_resources *res = &ctx->mixer_res;
1022
a44652e8 1023 if (test_bit(MXR_BIT_POWERED, &ctx->flags))
db43fd16 1024 return;
db43fd16 1025
af65c804
SP
1026 pm_runtime_get_sync(ctx->dev);
1027
a121d179
AH
1028 exynos_drm_pipe_clk_enable(crtc, true);
1029
3dbaab16
MS
1030 mixer_vsync_set_update(ctx, false);
1031
d74ed937
RS
1032 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
1033
0df5e4ac 1034 if (test_bit(MXR_BIT_VSYNC, &ctx->flags)) {
fc073248 1035 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
0df5e4ac
AH
1036 mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
1037 }
db43fd16 1038 mixer_win_reset(ctx);
ccf034a9 1039
3dbaab16
MS
1040 mixer_vsync_set_update(ctx, true);
1041
ccf034a9 1042 set_bit(MXR_BIT_POWERED, &ctx->flags);
db43fd16
P
1043}
1044
3cecda03 1045static void mixer_disable(struct exynos_drm_crtc *crtc)
db43fd16 1046{
3cecda03 1047 struct mixer_context *ctx = crtc->ctx;
c329f667 1048 int i;
db43fd16 1049
a44652e8 1050 if (!test_bit(MXR_BIT_POWERED, &ctx->flags))
b4bfa3c7 1051 return;
db43fd16 1052
381be025 1053 mixer_stop(ctx);
c0734fba 1054 mixer_regs_dump(ctx);
c329f667
JS
1055
1056 for (i = 0; i < MIXER_WIN_NR; i++)
1e1d1393 1057 mixer_disable_plane(crtc, &ctx->planes[i]);
db43fd16 1058
a121d179
AH
1059 exynos_drm_pipe_clk_enable(crtc, false);
1060
ccf034a9 1061 pm_runtime_put(ctx->dev);
b4bfa3c7 1062
ccf034a9 1063 clear_bit(MXR_BIT_POWERED, &ctx->flags);
db43fd16
P
1064}
1065
f041b257 1066/* Only valid for Mixer version 16.0.33.0 */
3ae24362
AH
1067static int mixer_atomic_check(struct exynos_drm_crtc *crtc,
1068 struct drm_crtc_state *state)
f041b257 1069{
3ae24362 1070 struct drm_display_mode *mode = &state->adjusted_mode;
f041b257
SP
1071 u32 w, h;
1072
1073 w = mode->hdisplay;
1074 h = mode->vdisplay;
1075
1076 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
1077 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1078 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1079
1080 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
1081 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1082 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1083 return 0;
1084
1085 return -EINVAL;
1086}
1087
f3aaf762 1088static const struct exynos_drm_crtc_ops mixer_crtc_ops = {
3cecda03
GP
1089 .enable = mixer_enable,
1090 .disable = mixer_disable,
d8408326
SWK
1091 .enable_vblank = mixer_enable_vblank,
1092 .disable_vblank = mixer_disable_vblank,
3dbaab16 1093 .atomic_begin = mixer_atomic_begin,
9cc7610a
GP
1094 .update_plane = mixer_update_plane,
1095 .disable_plane = mixer_disable_plane,
3dbaab16 1096 .atomic_flush = mixer_atomic_flush,
3ae24362 1097 .atomic_check = mixer_atomic_check,
f041b257 1098};
0ea6822f 1099
def5e095
RS
1100static struct mixer_drv_data exynos5420_mxr_drv_data = {
1101 .version = MXR_VER_128_0_0_184,
1102 .is_vp_enabled = 0,
1103};
1104
cc57caf0 1105static struct mixer_drv_data exynos5250_mxr_drv_data = {
aaf8b49e
RS
1106 .version = MXR_VER_16_0_33_0,
1107 .is_vp_enabled = 0,
1108};
1109
ff830c96
MS
1110static struct mixer_drv_data exynos4212_mxr_drv_data = {
1111 .version = MXR_VER_0_0_0_16,
1112 .is_vp_enabled = 1,
1113};
1114
cc57caf0 1115static struct mixer_drv_data exynos4210_mxr_drv_data = {
1e123441 1116 .version = MXR_VER_0_0_0_16,
1b8e5747 1117 .is_vp_enabled = 1,
ff830c96 1118 .has_sclk = 1,
1e123441
RS
1119};
1120
aaf8b49e
RS
1121static struct of_device_id mixer_match_types[] = {
1122 {
ff830c96
MS
1123 .compatible = "samsung,exynos4210-mixer",
1124 .data = &exynos4210_mxr_drv_data,
1125 }, {
1126 .compatible = "samsung,exynos4212-mixer",
1127 .data = &exynos4212_mxr_drv_data,
1128 }, {
aaf8b49e 1129 .compatible = "samsung,exynos5-mixer",
cc57caf0
RS
1130 .data = &exynos5250_mxr_drv_data,
1131 }, {
1132 .compatible = "samsung,exynos5250-mixer",
1133 .data = &exynos5250_mxr_drv_data,
def5e095
RS
1134 }, {
1135 .compatible = "samsung,exynos5420-mixer",
1136 .data = &exynos5420_mxr_drv_data,
1e123441
RS
1137 }, {
1138 /* end node */
1139 }
1140};
39b58a39 1141MODULE_DEVICE_TABLE(of, mixer_match_types);
1e123441 1142
f37cd5e8 1143static int mixer_bind(struct device *dev, struct device *manager, void *data)
d8408326 1144{
8103ef1b 1145 struct mixer_context *ctx = dev_get_drvdata(dev);
f37cd5e8 1146 struct drm_device *drm_dev = data;
7ee14cdc 1147 struct exynos_drm_plane *exynos_plane;
fd2d2fc2 1148 unsigned int i;
6e2a3b66 1149 int ret;
d8408326 1150
e2dc3f72
AB
1151 ret = mixer_initialize(ctx, drm_dev);
1152 if (ret)
1153 return ret;
1154
fd2d2fc2 1155 for (i = 0; i < MIXER_WIN_NR; i++) {
adeb6f44
TJ
1156 if (i == VP_DEFAULT_WIN && !test_bit(MXR_BIT_VP_ENABLED,
1157 &ctx->flags))
ab144201
MS
1158 continue;
1159
40bdfb0a 1160 ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
fd2d2fc2 1161 1 << ctx->pipe, &plane_configs[i]);
7ee14cdc
GP
1162 if (ret)
1163 return ret;
1164 }
1165
5d3d0995 1166 exynos_plane = &ctx->planes[DEFAULT_WIN];
7ee14cdc
GP
1167 ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
1168 ctx->pipe, EXYNOS_DISPLAY_TYPE_HDMI,
1169 &mixer_crtc_ops, ctx);
93bca243 1170 if (IS_ERR(ctx->crtc)) {
e2dc3f72 1171 mixer_ctx_remove(ctx);
93bca243
GP
1172 ret = PTR_ERR(ctx->crtc);
1173 goto free_ctx;
f37cd5e8 1174 }
d8408326 1175
d8408326 1176 return 0;
93bca243
GP
1177
1178free_ctx:
1179 devm_kfree(dev, ctx);
1180 return ret;
d8408326
SWK
1181}
1182
f37cd5e8 1183static void mixer_unbind(struct device *dev, struct device *master, void *data)
d8408326 1184{
8103ef1b 1185 struct mixer_context *ctx = dev_get_drvdata(dev);
f37cd5e8 1186
93bca243 1187 mixer_ctx_remove(ctx);
f37cd5e8
ID
1188}
1189
1190static const struct component_ops mixer_component_ops = {
1191 .bind = mixer_bind,
1192 .unbind = mixer_unbind,
1193};
1194
1195static int mixer_probe(struct platform_device *pdev)
1196{
8103ef1b 1197 struct device *dev = &pdev->dev;
48f6155a 1198 const struct mixer_drv_data *drv;
8103ef1b 1199 struct mixer_context *ctx;
df5225bc
ID
1200 int ret;
1201
8103ef1b
AH
1202 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1203 if (!ctx) {
1204 DRM_ERROR("failed to alloc mixer context.\n");
1205 return -ENOMEM;
1206 }
1207
48f6155a 1208 drv = of_device_get_match_data(dev);
8103ef1b
AH
1209
1210 ctx->pdev = pdev;
1211 ctx->dev = dev;
8103ef1b 1212 ctx->mxr_ver = drv->version;
8103ef1b 1213
adeb6f44
TJ
1214 if (drv->is_vp_enabled)
1215 __set_bit(MXR_BIT_VP_ENABLED, &ctx->flags);
1216 if (drv->has_sclk)
1217 __set_bit(MXR_BIT_HAS_SCLK, &ctx->flags);
1218
8103ef1b
AH
1219 platform_set_drvdata(pdev, ctx);
1220
df5225bc 1221 ret = component_add(&pdev->dev, &mixer_component_ops);
86650408
AH
1222 if (!ret)
1223 pm_runtime_enable(dev);
df5225bc
ID
1224
1225 return ret;
f37cd5e8
ID
1226}
1227
1228static int mixer_remove(struct platform_device *pdev)
1229{
8103ef1b
AH
1230 pm_runtime_disable(&pdev->dev);
1231
df5225bc 1232 component_del(&pdev->dev, &mixer_component_ops);
df5225bc 1233
d8408326
SWK
1234 return 0;
1235}
1236
e0fea7e7 1237static int __maybe_unused exynos_mixer_suspend(struct device *dev)
ccf034a9
GP
1238{
1239 struct mixer_context *ctx = dev_get_drvdata(dev);
1240 struct mixer_resources *res = &ctx->mixer_res;
1241
1242 clk_disable_unprepare(res->hdmi);
1243 clk_disable_unprepare(res->mixer);
adeb6f44 1244 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
ccf034a9 1245 clk_disable_unprepare(res->vp);
adeb6f44 1246 if (test_bit(MXR_BIT_HAS_SCLK, &ctx->flags))
ccf034a9
GP
1247 clk_disable_unprepare(res->sclk_mixer);
1248 }
1249
1250 return 0;
1251}
1252
e0fea7e7 1253static int __maybe_unused exynos_mixer_resume(struct device *dev)
ccf034a9
GP
1254{
1255 struct mixer_context *ctx = dev_get_drvdata(dev);
1256 struct mixer_resources *res = &ctx->mixer_res;
1257 int ret;
1258
1259 ret = clk_prepare_enable(res->mixer);
1260 if (ret < 0) {
1261 DRM_ERROR("Failed to prepare_enable the mixer clk [%d]\n", ret);
1262 return ret;
1263 }
1264 ret = clk_prepare_enable(res->hdmi);
1265 if (ret < 0) {
1266 DRM_ERROR("Failed to prepare_enable the hdmi clk [%d]\n", ret);
1267 return ret;
1268 }
adeb6f44 1269 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
ccf034a9
GP
1270 ret = clk_prepare_enable(res->vp);
1271 if (ret < 0) {
1272 DRM_ERROR("Failed to prepare_enable the vp clk [%d]\n",
1273 ret);
1274 return ret;
1275 }
adeb6f44 1276 if (test_bit(MXR_BIT_HAS_SCLK, &ctx->flags)) {
ccf034a9
GP
1277 ret = clk_prepare_enable(res->sclk_mixer);
1278 if (ret < 0) {
1279 DRM_ERROR("Failed to prepare_enable the " \
1280 "sclk_mixer clk [%d]\n",
1281 ret);
1282 return ret;
1283 }
1284 }
1285 }
1286
1287 return 0;
1288}
ccf034a9
GP
1289
1290static const struct dev_pm_ops exynos_mixer_pm_ops = {
1291 SET_RUNTIME_PM_OPS(exynos_mixer_suspend, exynos_mixer_resume, NULL)
1292};
1293
d8408326
SWK
1294struct platform_driver mixer_driver = {
1295 .driver = {
aaf8b49e 1296 .name = "exynos-mixer",
d8408326 1297 .owner = THIS_MODULE,
ccf034a9 1298 .pm = &exynos_mixer_pm_ops,
aaf8b49e 1299 .of_match_table = mixer_match_types,
d8408326
SWK
1300 },
1301 .probe = mixer_probe,
56550d94 1302 .remove = mixer_remove,
d8408326 1303};