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