Version:  2.0.40 2.2.26 2.4.37 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17

Linux/drivers/gpu/drm/exynos/exynos_mixer.c

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

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us