blob: 6756d1ca49233bd17d4a063c9d191036b04f9838 [file] [log] [blame]
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001/*
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
David Howells760285e2012-10-02 18:01:07 +010017#include <drm/drmP.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090018
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>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090026#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>
Sachin Kamat3f1c7812013-08-14 16:38:01 +053033#include <linux/of.h>
Inki Daef37cd5e2014-05-09 14:25:20 +090034#include <linux/component.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090035
36#include <drm/exynos_drm.h>
37
38#include "exynos_drm_drv.h"
Rahul Sharma663d8762013-01-03 05:44:04 -050039#include "exynos_drm_crtc.h"
Inki Dae1055b392012-10-19 17:37:35 +090040#include "exynos_drm_iommu.h"
Sean Paulf041b252014-01-30 16:19:15 -050041#include "exynos_mixer.h"
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090042
Sean Paulf041b252014-01-30 16:19:15 -050043#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
Seung-Woo Kimd8408322011-12-21 17:39:39 +090047
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090048struct hdmi_win_data {
49 dma_addr_t dma_addr;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090050 dma_addr_t chroma_dma_addr;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090051 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;
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +090061 unsigned int src_width;
62 unsigned int src_height;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090063 unsigned int mode_width;
64 unsigned int mode_height;
65 unsigned int scan_flags;
Prathyush Kdb43fd12012-12-06 20:16:05 +053066 bool enabled;
67 bool resume;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090068};
69
70struct mixer_resources {
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090071 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;
Marek Szyprowskiff830c92014-07-01 10:10:07 +020079 struct clk *mout_mixer;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090080};
81
Rahul Sharma1e123442012-10-04 20:48:51 +053082enum mixer_version_id {
83 MXR_VER_0_0_0_16,
84 MXR_VER_16_0_33_0,
Rahul Sharmadef5e092013-06-19 18:21:08 +053085 MXR_VER_128_0_0_184,
Rahul Sharma1e123442012-10-04 20:48:51 +053086};
87
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090088struct mixer_context {
Sean Paul45517892014-01-30 16:19:05 -050089 struct platform_device *pdev;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090090 struct device *dev;
Inki Dae1055b392012-10-19 17:37:35 +090091 struct drm_device *drm_dev;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090092 int pipe;
93 bool interlace;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090094 bool powered;
Rahul Sharma1b8e5742012-10-04 20:48:52 +053095 bool vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +020096 bool has_sclk;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090097 u32 int_en;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090098
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090099 struct mutex mixer_mutex;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +0900100 struct mixer_resources mixer_res;
Joonyoung Shima634dd52012-04-05 20:49:24 +0900101 struct hdmi_win_data win_data[MIXER_WIN_NR];
Rahul Sharma1e123442012-10-04 20:48:51 +0530102 enum mixer_version_id mxr_ver;
Prathyush K6e95d5e2012-12-06 20:16:03 +0530103 wait_queue_head_t wait_vsync_queue;
104 atomic_t wait_vsync_event;
Rahul Sharma1e123442012-10-04 20:48:51 +0530105};
106
107struct mixer_drv_data {
108 enum mixer_version_id version;
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530109 bool is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200110 bool has_sclk;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +0900111};
112
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900113static 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
124static 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
135static 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
142static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
143{
144 return readl(res->vp_regs + reg_id);
145}
146
147static 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
153static 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
162static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
163{
164 return readl(res->mixer_regs + reg_id);
165}
166
167static 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
173static 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
182static void mixer_regs_dump(struct mixer_context *ctx)
183{
184#define DUMPREG(reg_id) \
185do { \
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
214static void vp_regs_dump(struct mixer_context *ctx)
215{
216#define DUMPREG(reg_id) \
217do { \
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
249static 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
261static void vp_default_filter(struct mixer_resources *res)
262{
263 vp_filter_set(res, VP_POLY8_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530264 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900265 vp_filter_set(res, VP_POLY4_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530266 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900267 vp_filter_set(res, VP_POLY4_C0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530268 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900269}
270
271static 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
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530279 if (ctx->vp_enabled)
280 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900281 VP_SHADOW_UPDATE_ENABLE : 0);
282}
283
284static 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
Rahul Sharmadef5e092013-06-19 18:21:08 +0530293 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 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900306
307 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
308}
309
310static 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
351static 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:
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530364 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 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900369 break;
370 }
371}
372
373static void mixer_run(struct mixer_context *ctx)
374{
375 struct mixer_resources *res = &ctx->mixer_res;
376
377 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
378
379 mixer_regs_dump(ctx);
380}
381
Rahul Sharma381be022014-06-23 11:02:22 +0530382static void mixer_stop(struct mixer_context *ctx)
383{
384 struct mixer_resources *res = &ctx->mixer_res;
385 int timeout = 20;
386
387 mixer_reg_writemask(res, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
388
389 while (!(mixer_reg_read(res, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
390 --timeout)
391 usleep_range(10000, 12000);
392
393 mixer_regs_dump(ctx);
394}
395
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900396static void vp_video_buffer(struct mixer_context *ctx, int win)
397{
398 struct mixer_resources *res = &ctx->mixer_res;
399 unsigned long flags;
400 struct hdmi_win_data *win_data;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900401 unsigned int x_ratio, y_ratio;
YoungJun Cho782953e2013-07-01 13:04:12 +0900402 unsigned int buf_num = 1;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900403 dma_addr_t luma_addr[2], chroma_addr[2];
404 bool tiled_mode = false;
405 bool crcb_mode = false;
406 u32 val;
407
408 win_data = &ctx->win_data[win];
409
410 switch (win_data->pixel_format) {
411 case DRM_FORMAT_NV12MT:
412 tiled_mode = true;
Ville Syrjälä363b06a2012-05-14 11:08:51 +0900413 case DRM_FORMAT_NV12:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900414 crcb_mode = false;
415 buf_num = 2;
416 break;
417 /* TODO: single buffer format NV12, NV21 */
418 default:
419 /* ignore pixel format at disable time */
420 if (!win_data->dma_addr)
421 break;
422
423 DRM_ERROR("pixel format for vp is wrong [%d].\n",
424 win_data->pixel_format);
425 return;
426 }
427
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900428 /* scaling feature: (src << 16) / dst */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900429 x_ratio = (win_data->src_width << 16) / win_data->crtc_width;
430 y_ratio = (win_data->src_height << 16) / win_data->crtc_height;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900431
432 if (buf_num == 2) {
433 luma_addr[0] = win_data->dma_addr;
434 chroma_addr[0] = win_data->chroma_dma_addr;
435 } else {
436 luma_addr[0] = win_data->dma_addr;
437 chroma_addr[0] = win_data->dma_addr
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900438 + (win_data->fb_width * win_data->fb_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900439 }
440
441 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) {
442 ctx->interlace = true;
443 if (tiled_mode) {
444 luma_addr[1] = luma_addr[0] + 0x40;
445 chroma_addr[1] = chroma_addr[0] + 0x40;
446 } else {
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900447 luma_addr[1] = luma_addr[0] + win_data->fb_width;
448 chroma_addr[1] = chroma_addr[0] + win_data->fb_width;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900449 }
450 } else {
451 ctx->interlace = false;
452 luma_addr[1] = 0;
453 chroma_addr[1] = 0;
454 }
455
456 spin_lock_irqsave(&res->reg_slock, flags);
457 mixer_vsync_set_update(ctx, false);
458
459 /* interlace or progressive scan mode */
460 val = (ctx->interlace ? ~0 : 0);
461 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
462
463 /* setup format */
464 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
465 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
466 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
467
468 /* setting size of input image */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900469 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_width) |
470 VP_IMG_VSIZE(win_data->fb_height));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900471 /* chroma height has to reduced by 2 to avoid chroma distorions */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900472 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(win_data->fb_width) |
473 VP_IMG_VSIZE(win_data->fb_height / 2));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900474
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900475 vp_reg_write(res, VP_SRC_WIDTH, win_data->src_width);
476 vp_reg_write(res, VP_SRC_HEIGHT, win_data->src_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900477 vp_reg_write(res, VP_SRC_H_POSITION,
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900478 VP_SRC_H_POSITION_VAL(win_data->fb_x));
479 vp_reg_write(res, VP_SRC_V_POSITION, win_data->fb_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900480
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900481 vp_reg_write(res, VP_DST_WIDTH, win_data->crtc_width);
482 vp_reg_write(res, VP_DST_H_POSITION, win_data->crtc_x);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900483 if (ctx->interlace) {
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900484 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height / 2);
485 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y / 2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900486 } else {
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900487 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height);
488 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900489 }
490
491 vp_reg_write(res, VP_H_RATIO, x_ratio);
492 vp_reg_write(res, VP_V_RATIO, y_ratio);
493
494 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
495
496 /* set buffer address to vp */
497 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
498 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
499 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
500 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
501
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900502 mixer_cfg_scan(ctx, win_data->mode_height);
503 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900504 mixer_cfg_layer(ctx, win, true);
505 mixer_run(ctx);
506
507 mixer_vsync_set_update(ctx, true);
508 spin_unlock_irqrestore(&res->reg_slock, flags);
509
510 vp_regs_dump(ctx);
511}
512
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530513static void mixer_layer_update(struct mixer_context *ctx)
514{
515 struct mixer_resources *res = &ctx->mixer_res;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530516
Rahul Sharma5c0f4822014-06-23 11:02:23 +0530517 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530518}
519
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900520static void mixer_graph_buffer(struct mixer_context *ctx, int win)
521{
522 struct mixer_resources *res = &ctx->mixer_res;
523 unsigned long flags;
524 struct hdmi_win_data *win_data;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900525 unsigned int x_ratio, y_ratio;
526 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900527 dma_addr_t dma_addr;
528 unsigned int fmt;
529 u32 val;
530
531 win_data = &ctx->win_data[win];
532
533 #define RGB565 4
534 #define ARGB1555 5
535 #define ARGB4444 6
536 #define ARGB8888 7
537
538 switch (win_data->bpp) {
539 case 16:
540 fmt = ARGB4444;
541 break;
542 case 32:
543 fmt = ARGB8888;
544 break;
545 default:
546 fmt = ARGB8888;
547 }
548
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900549 /* 2x scaling feature */
550 x_ratio = 0;
551 y_ratio = 0;
552
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900553 dst_x_offset = win_data->crtc_x;
554 dst_y_offset = win_data->crtc_y;
555
556 /* converting dma address base and source offset */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900557 dma_addr = win_data->dma_addr
558 + (win_data->fb_x * win_data->bpp >> 3)
559 + (win_data->fb_y * win_data->fb_width * win_data->bpp >> 3);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900560 src_x_offset = 0;
561 src_y_offset = 0;
562
563 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE)
564 ctx->interlace = true;
565 else
566 ctx->interlace = false;
567
568 spin_lock_irqsave(&res->reg_slock, flags);
569 mixer_vsync_set_update(ctx, false);
570
571 /* setup format */
572 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
573 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
574
575 /* setup geometry */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900576 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), win_data->fb_width);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900577
Rahul Sharmadef5e092013-06-19 18:21:08 +0530578 /* setup display size */
579 if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
580 win == MIXER_DEFAULT_WIN) {
581 val = MXR_MXR_RES_HEIGHT(win_data->fb_height);
582 val |= MXR_MXR_RES_WIDTH(win_data->fb_width);
583 mixer_reg_write(res, MXR_RESOLUTION, val);
584 }
585
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900586 val = MXR_GRP_WH_WIDTH(win_data->crtc_width);
587 val |= MXR_GRP_WH_HEIGHT(win_data->crtc_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900588 val |= MXR_GRP_WH_H_SCALE(x_ratio);
589 val |= MXR_GRP_WH_V_SCALE(y_ratio);
590 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
591
592 /* setup offsets in source image */
593 val = MXR_GRP_SXY_SX(src_x_offset);
594 val |= MXR_GRP_SXY_SY(src_y_offset);
595 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
596
597 /* setup offsets in display image */
598 val = MXR_GRP_DXY_DX(dst_x_offset);
599 val |= MXR_GRP_DXY_DY(dst_y_offset);
600 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
601
602 /* set buffer address to mixer */
603 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
604
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900605 mixer_cfg_scan(ctx, win_data->mode_height);
606 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900607 mixer_cfg_layer(ctx, win, true);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530608
609 /* layer update mandatory for mixer 16.0.33.0 */
Rahul Sharmadef5e092013-06-19 18:21:08 +0530610 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
611 ctx->mxr_ver == MXR_VER_128_0_0_184)
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530612 mixer_layer_update(ctx);
613
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900614 mixer_run(ctx);
615
616 mixer_vsync_set_update(ctx, true);
617 spin_unlock_irqrestore(&res->reg_slock, flags);
618}
619
620static void vp_win_reset(struct mixer_context *ctx)
621{
622 struct mixer_resources *res = &ctx->mixer_res;
623 int tries = 100;
624
625 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
626 for (tries = 100; tries; --tries) {
627 /* waiting until VP_SRESET_PROCESSING is 0 */
628 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
629 break;
Sean Paul09760ea2013-01-14 17:03:20 -0500630 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900631 }
632 WARN(tries == 0, "failed to reset Video Processor\n");
633}
634
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900635static void mixer_win_reset(struct mixer_context *ctx)
636{
637 struct mixer_resources *res = &ctx->mixer_res;
638 unsigned long flags;
639 u32 val; /* value stored to register */
640
641 spin_lock_irqsave(&res->reg_slock, flags);
642 mixer_vsync_set_update(ctx, false);
643
644 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
645
646 /* set output in RGB888 mode */
647 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
648
649 /* 16 beat burst in DMA */
650 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
651 MXR_STATUS_BURST_MASK);
652
653 /* setting default layer priority: layer1 > layer0 > video
654 * because typical usage scenario would be
655 * layer1 - OSD
656 * layer0 - framebuffer
657 * video - video overlay
658 */
659 val = MXR_LAYER_CFG_GRP1_VAL(3);
660 val |= MXR_LAYER_CFG_GRP0_VAL(2);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530661 if (ctx->vp_enabled)
662 val |= MXR_LAYER_CFG_VP_VAL(1);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900663 mixer_reg_write(res, MXR_LAYER_CFG, val);
664
665 /* setting background color */
666 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
667 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
668 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
669
670 /* setting graphical layers */
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900671 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
672 val |= MXR_GRP_CFG_WIN_BLEND_EN;
673 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
674
Sean Paul0377f4e2013-04-25 15:13:26 -0400675 /* Don't blend layer 0 onto the mixer background */
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900676 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
Sean Paul0377f4e2013-04-25 15:13:26 -0400677
678 /* Blend layer 1 into layer 0 */
679 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
680 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900681 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
682
Seung-Woo Kim57366032012-05-15 17:22:08 +0900683 /* setting video layers */
684 val = MXR_GRP_CFG_ALPHA_VAL(0);
685 mixer_reg_write(res, MXR_VIDEO_CFG, val);
686
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530687 if (ctx->vp_enabled) {
688 /* configuration of Video Processor Registers */
689 vp_win_reset(ctx);
690 vp_default_filter(res);
691 }
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900692
693 /* disable all layers */
694 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
695 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530696 if (ctx->vp_enabled)
697 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900698
699 mixer_vsync_set_update(ctx, true);
700 spin_unlock_irqrestore(&res->reg_slock, flags);
701}
702
Sean Paul45517892014-01-30 16:19:05 -0500703static irqreturn_t mixer_irq_handler(int irq, void *arg)
704{
705 struct mixer_context *ctx = arg;
706 struct mixer_resources *res = &ctx->mixer_res;
707 u32 val, base, shadow;
708
709 spin_lock(&res->reg_slock);
710
711 /* read interrupt status for handling and clearing flags for VSYNC */
712 val = mixer_reg_read(res, MXR_INT_STATUS);
713
714 /* handling VSYNC */
715 if (val & MXR_INT_STATUS_VSYNC) {
716 /* interlace scan need to check shadow register */
717 if (ctx->interlace) {
718 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
719 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
720 if (base != shadow)
721 goto out;
722
723 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
724 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
725 if (base != shadow)
726 goto out;
727 }
728
729 drm_handle_vblank(ctx->drm_dev, ctx->pipe);
730 exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
731
732 /* set wait vsync event to zero and wake up queue. */
733 if (atomic_read(&ctx->wait_vsync_event)) {
734 atomic_set(&ctx->wait_vsync_event, 0);
735 wake_up(&ctx->wait_vsync_queue);
736 }
737 }
738
739out:
740 /* clear interrupts */
741 if (~val & MXR_INT_EN_VSYNC) {
742 /* vsync interrupt use different bit for read and clear */
743 val &= ~MXR_INT_EN_VSYNC;
744 val |= MXR_INT_CLEAR_VSYNC;
745 }
746 mixer_reg_write(res, MXR_INT_STATUS, val);
747
748 spin_unlock(&res->reg_slock);
749
750 return IRQ_HANDLED;
751}
752
753static int mixer_resources_init(struct mixer_context *mixer_ctx)
754{
755 struct device *dev = &mixer_ctx->pdev->dev;
756 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
757 struct resource *res;
758 int ret;
759
760 spin_lock_init(&mixer_res->reg_slock);
761
762 mixer_res->mixer = devm_clk_get(dev, "mixer");
763 if (IS_ERR(mixer_res->mixer)) {
764 dev_err(dev, "failed to get clock 'mixer'\n");
765 return -ENODEV;
766 }
767
768 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
769 if (IS_ERR(mixer_res->sclk_hdmi)) {
770 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
771 return -ENODEV;
772 }
773 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
774 if (res == NULL) {
775 dev_err(dev, "get memory resource failed.\n");
776 return -ENXIO;
777 }
778
779 mixer_res->mixer_regs = devm_ioremap(dev, res->start,
780 resource_size(res));
781 if (mixer_res->mixer_regs == NULL) {
782 dev_err(dev, "register mapping failed.\n");
783 return -ENXIO;
784 }
785
786 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
787 if (res == NULL) {
788 dev_err(dev, "get interrupt resource failed.\n");
789 return -ENXIO;
790 }
791
792 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
793 0, "drm_mixer", mixer_ctx);
794 if (ret) {
795 dev_err(dev, "request interrupt failed.\n");
796 return ret;
797 }
798 mixer_res->irq = res->start;
799
800 return 0;
801}
802
803static int vp_resources_init(struct mixer_context *mixer_ctx)
804{
805 struct device *dev = &mixer_ctx->pdev->dev;
806 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
807 struct resource *res;
808
809 mixer_res->vp = devm_clk_get(dev, "vp");
810 if (IS_ERR(mixer_res->vp)) {
811 dev_err(dev, "failed to get clock 'vp'\n");
812 return -ENODEV;
813 }
Sean Paul45517892014-01-30 16:19:05 -0500814
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200815 if (mixer_ctx->has_sclk) {
816 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
817 if (IS_ERR(mixer_res->sclk_mixer)) {
818 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
819 return -ENODEV;
820 }
821 mixer_res->mout_mixer = devm_clk_get(dev, "mout_mixer");
822 if (IS_ERR(mixer_res->mout_mixer)) {
823 dev_err(dev, "failed to get clock 'mout_mixer'\n");
824 return -ENODEV;
825 }
826
827 if (mixer_res->sclk_hdmi && mixer_res->mout_mixer)
828 clk_set_parent(mixer_res->mout_mixer,
829 mixer_res->sclk_hdmi);
830 }
Sean Paul45517892014-01-30 16:19:05 -0500831
832 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
833 if (res == NULL) {
834 dev_err(dev, "get memory resource failed.\n");
835 return -ENXIO;
836 }
837
838 mixer_res->vp_regs = devm_ioremap(dev, res->start,
839 resource_size(res));
840 if (mixer_res->vp_regs == NULL) {
841 dev_err(dev, "register mapping failed.\n");
842 return -ENXIO;
843 }
844
845 return 0;
846}
847
Sean Paulf041b252014-01-30 16:19:15 -0500848static int mixer_initialize(struct exynos_drm_manager *mgr,
Inki Daef37cd5e2014-05-09 14:25:20 +0900849 struct drm_device *drm_dev)
Sean Paul45517892014-01-30 16:19:05 -0500850{
851 int ret;
Sean Paulf041b252014-01-30 16:19:15 -0500852 struct mixer_context *mixer_ctx = mgr->ctx;
Inki Daef37cd5e2014-05-09 14:25:20 +0900853 struct exynos_drm_private *priv;
854 priv = drm_dev->dev_private;
Sean Paul45517892014-01-30 16:19:05 -0500855
Inki Daef37cd5e2014-05-09 14:25:20 +0900856 mgr->drm_dev = mixer_ctx->drm_dev = drm_dev;
857 mgr->pipe = mixer_ctx->pipe = priv->pipe++;
Sean Paul45517892014-01-30 16:19:05 -0500858
859 /* acquire resources: regs, irqs, clocks */
860 ret = mixer_resources_init(mixer_ctx);
861 if (ret) {
862 DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
863 return ret;
864 }
865
866 if (mixer_ctx->vp_enabled) {
867 /* acquire vp resources: regs, irqs, clocks */
868 ret = vp_resources_init(mixer_ctx);
869 if (ret) {
870 DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
871 return ret;
872 }
873 }
874
Sean Paulf041b252014-01-30 16:19:15 -0500875 if (!is_drm_iommu_supported(mixer_ctx->drm_dev))
876 return 0;
877
878 return drm_iommu_attach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Sean Paul45517892014-01-30 16:19:05 -0500879}
880
Sean Paulf041b252014-01-30 16:19:15 -0500881static void mixer_mgr_remove(struct exynos_drm_manager *mgr)
Inki Dae1055b392012-10-19 17:37:35 +0900882{
Sean Paulf041b252014-01-30 16:19:15 -0500883 struct mixer_context *mixer_ctx = mgr->ctx;
Inki Dae1055b392012-10-19 17:37:35 +0900884
Sean Paulf041b252014-01-30 16:19:15 -0500885 if (is_drm_iommu_supported(mixer_ctx->drm_dev))
886 drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Inki Dae1055b392012-10-19 17:37:35 +0900887}
888
Sean Paulf041b252014-01-30 16:19:15 -0500889static int mixer_enable_vblank(struct exynos_drm_manager *mgr)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900890{
Sean Paulf041b252014-01-30 16:19:15 -0500891 struct mixer_context *mixer_ctx = mgr->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900892 struct mixer_resources *res = &mixer_ctx->mixer_res;
893
Sean Paulf041b252014-01-30 16:19:15 -0500894 if (!mixer_ctx->powered) {
895 mixer_ctx->int_en |= MXR_INT_EN_VSYNC;
896 return 0;
897 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900898
899 /* enable vsync interrupt */
900 mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
901 MXR_INT_EN_VSYNC);
902
903 return 0;
904}
905
Sean Paulf041b252014-01-30 16:19:15 -0500906static void mixer_disable_vblank(struct exynos_drm_manager *mgr)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900907{
Sean Paulf041b252014-01-30 16:19:15 -0500908 struct mixer_context *mixer_ctx = mgr->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900909 struct mixer_resources *res = &mixer_ctx->mixer_res;
910
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900911 /* disable vsync interrupt */
912 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
913}
914
Sean Paulf041b252014-01-30 16:19:15 -0500915static void mixer_win_mode_set(struct exynos_drm_manager *mgr,
916 struct exynos_drm_overlay *overlay)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900917{
Sean Paulf041b252014-01-30 16:19:15 -0500918 struct mixer_context *mixer_ctx = mgr->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900919 struct hdmi_win_data *win_data;
920 int win;
921
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900922 if (!overlay) {
923 DRM_ERROR("overlay is NULL\n");
924 return;
925 }
926
927 DRM_DEBUG_KMS("set [%d]x[%d] at (%d,%d) to [%d]x[%d] at (%d,%d)\n",
928 overlay->fb_width, overlay->fb_height,
929 overlay->fb_x, overlay->fb_y,
930 overlay->crtc_width, overlay->crtc_height,
931 overlay->crtc_x, overlay->crtc_y);
932
933 win = overlay->zpos;
934 if (win == DEFAULT_ZPOS)
Joonyoung Shima2ee1512012-04-05 20:49:25 +0900935 win = MIXER_DEFAULT_WIN;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900936
Krzysztof Kozlowski1586d802013-05-27 15:00:43 +0900937 if (win < 0 || win >= MIXER_WIN_NR) {
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900938 DRM_ERROR("mixer window[%d] is wrong\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900939 return;
940 }
941
942 win_data = &mixer_ctx->win_data[win];
943
944 win_data->dma_addr = overlay->dma_addr[0];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900945 win_data->chroma_dma_addr = overlay->dma_addr[1];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900946 win_data->pixel_format = overlay->pixel_format;
947 win_data->bpp = overlay->bpp;
948
949 win_data->crtc_x = overlay->crtc_x;
950 win_data->crtc_y = overlay->crtc_y;
951 win_data->crtc_width = overlay->crtc_width;
952 win_data->crtc_height = overlay->crtc_height;
953
954 win_data->fb_x = overlay->fb_x;
955 win_data->fb_y = overlay->fb_y;
956 win_data->fb_width = overlay->fb_width;
957 win_data->fb_height = overlay->fb_height;
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900958 win_data->src_width = overlay->src_width;
959 win_data->src_height = overlay->src_height;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900960
961 win_data->mode_width = overlay->mode_width;
962 win_data->mode_height = overlay->mode_height;
963
964 win_data->scan_flags = overlay->scan_flag;
965}
966
Sean Paulf041b252014-01-30 16:19:15 -0500967static void mixer_win_commit(struct exynos_drm_manager *mgr, int zpos)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900968{
Sean Paulf041b252014-01-30 16:19:15 -0500969 struct mixer_context *mixer_ctx = mgr->ctx;
970 int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900971
YoungJun Chocbc4c332013-06-12 10:44:40 +0900972 DRM_DEBUG_KMS("win: %d\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900973
Shirish Sdda90122013-01-23 22:03:18 -0500974 mutex_lock(&mixer_ctx->mixer_mutex);
975 if (!mixer_ctx->powered) {
976 mutex_unlock(&mixer_ctx->mixer_mutex);
977 return;
978 }
979 mutex_unlock(&mixer_ctx->mixer_mutex);
980
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530981 if (win > 1 && mixer_ctx->vp_enabled)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900982 vp_video_buffer(mixer_ctx, win);
983 else
984 mixer_graph_buffer(mixer_ctx, win);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530985
986 mixer_ctx->win_data[win].enabled = true;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900987}
988
Sean Paulf041b252014-01-30 16:19:15 -0500989static void mixer_win_disable(struct exynos_drm_manager *mgr, int zpos)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900990{
Sean Paulf041b252014-01-30 16:19:15 -0500991 struct mixer_context *mixer_ctx = mgr->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900992 struct mixer_resources *res = &mixer_ctx->mixer_res;
Sean Paulf041b252014-01-30 16:19:15 -0500993 int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900994 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900995
YoungJun Chocbc4c332013-06-12 10:44:40 +0900996 DRM_DEBUG_KMS("win: %d\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900997
Prathyush Kdb43fd12012-12-06 20:16:05 +0530998 mutex_lock(&mixer_ctx->mixer_mutex);
999 if (!mixer_ctx->powered) {
1000 mutex_unlock(&mixer_ctx->mixer_mutex);
1001 mixer_ctx->win_data[win].resume = false;
1002 return;
1003 }
1004 mutex_unlock(&mixer_ctx->mixer_mutex);
1005
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001006 spin_lock_irqsave(&res->reg_slock, flags);
1007 mixer_vsync_set_update(mixer_ctx, false);
1008
1009 mixer_cfg_layer(mixer_ctx, win, false);
1010
1011 mixer_vsync_set_update(mixer_ctx, true);
1012 spin_unlock_irqrestore(&res->reg_slock, flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301013
1014 mixer_ctx->win_data[win].enabled = false;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001015}
1016
Sean Paulf041b252014-01-30 16:19:15 -05001017static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr)
Rahul Sharma0ea68222013-01-15 08:11:06 -05001018{
Sean Paulf041b252014-01-30 16:19:15 -05001019 struct mixer_context *mixer_ctx = mgr->ctx;
Prathyush K8137a2e2012-12-06 20:16:01 +05301020
Prathyush K6e95d5e2012-12-06 20:16:03 +05301021 mutex_lock(&mixer_ctx->mixer_mutex);
1022 if (!mixer_ctx->powered) {
1023 mutex_unlock(&mixer_ctx->mixer_mutex);
1024 return;
1025 }
1026 mutex_unlock(&mixer_ctx->mixer_mutex);
1027
Rahul Sharma5d39b9e2014-06-23 11:02:25 +05301028 drm_vblank_get(mgr->crtc->dev, mixer_ctx->pipe);
1029
Prathyush K6e95d5e2012-12-06 20:16:03 +05301030 atomic_set(&mixer_ctx->wait_vsync_event, 1);
1031
1032 /*
1033 * wait for MIXER to signal VSYNC interrupt or return after
1034 * timeout which is set to 50ms (refresh rate of 20).
1035 */
1036 if (!wait_event_timeout(mixer_ctx->wait_vsync_queue,
1037 !atomic_read(&mixer_ctx->wait_vsync_event),
Daniel Vetterbfd83032013-12-11 11:34:41 +01001038 HZ/20))
Prathyush K8137a2e2012-12-06 20:16:01 +05301039 DRM_DEBUG_KMS("vblank wait timed out.\n");
Rahul Sharma5d39b9e2014-06-23 11:02:25 +05301040
1041 drm_vblank_put(mgr->crtc->dev, mixer_ctx->pipe);
Prathyush K8137a2e2012-12-06 20:16:01 +05301042}
1043
Sean Paulf041b252014-01-30 16:19:15 -05001044static void mixer_window_suspend(struct exynos_drm_manager *mgr)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301045{
Sean Paulf041b252014-01-30 16:19:15 -05001046 struct mixer_context *ctx = mgr->ctx;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301047 struct hdmi_win_data *win_data;
1048 int i;
1049
1050 for (i = 0; i < MIXER_WIN_NR; i++) {
1051 win_data = &ctx->win_data[i];
1052 win_data->resume = win_data->enabled;
Sean Paulf041b252014-01-30 16:19:15 -05001053 mixer_win_disable(mgr, i);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301054 }
Sean Paulf041b252014-01-30 16:19:15 -05001055 mixer_wait_for_vblank(mgr);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301056}
1057
Sean Paulf041b252014-01-30 16:19:15 -05001058static void mixer_window_resume(struct exynos_drm_manager *mgr)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301059{
Sean Paulf041b252014-01-30 16:19:15 -05001060 struct mixer_context *ctx = mgr->ctx;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301061 struct hdmi_win_data *win_data;
1062 int i;
1063
1064 for (i = 0; i < MIXER_WIN_NR; i++) {
1065 win_data = &ctx->win_data[i];
1066 win_data->enabled = win_data->resume;
1067 win_data->resume = false;
Sean Paul87244fa2014-01-30 16:19:07 -05001068 if (win_data->enabled)
Sean Paulf041b252014-01-30 16:19:15 -05001069 mixer_win_commit(mgr, i);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301070 }
1071}
1072
Sean Paulf041b252014-01-30 16:19:15 -05001073static void mixer_poweron(struct exynos_drm_manager *mgr)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301074{
Sean Paulf041b252014-01-30 16:19:15 -05001075 struct mixer_context *ctx = mgr->ctx;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301076 struct mixer_resources *res = &ctx->mixer_res;
1077
Prathyush Kdb43fd12012-12-06 20:16:05 +05301078 mutex_lock(&ctx->mixer_mutex);
1079 if (ctx->powered) {
1080 mutex_unlock(&ctx->mixer_mutex);
1081 return;
1082 }
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301083
Prathyush Kdb43fd12012-12-06 20:16:05 +05301084 mutex_unlock(&ctx->mixer_mutex);
1085
Sean Paulaf65c802014-01-30 16:19:27 -05001086 pm_runtime_get_sync(ctx->dev);
1087
Sean Paul0bfb1f82013-06-11 12:24:02 +05301088 clk_prepare_enable(res->mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301089 if (ctx->vp_enabled) {
Sean Paul0bfb1f82013-06-11 12:24:02 +05301090 clk_prepare_enable(res->vp);
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001091 if (ctx->has_sclk)
1092 clk_prepare_enable(res->sclk_mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301093 }
1094
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301095 mutex_lock(&ctx->mixer_mutex);
1096 ctx->powered = true;
1097 mutex_unlock(&ctx->mixer_mutex);
1098
Rahul Sharmad74ed932014-06-23 11:02:24 +05301099 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
1100
Prathyush Kdb43fd12012-12-06 20:16:05 +05301101 mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
1102 mixer_win_reset(ctx);
1103
Sean Paulf041b252014-01-30 16:19:15 -05001104 mixer_window_resume(mgr);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301105}
1106
Sean Paulf041b252014-01-30 16:19:15 -05001107static void mixer_poweroff(struct exynos_drm_manager *mgr)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301108{
Sean Paulf041b252014-01-30 16:19:15 -05001109 struct mixer_context *ctx = mgr->ctx;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301110 struct mixer_resources *res = &ctx->mixer_res;
1111
Prathyush Kdb43fd12012-12-06 20:16:05 +05301112 mutex_lock(&ctx->mixer_mutex);
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301113 if (!ctx->powered) {
1114 mutex_unlock(&ctx->mixer_mutex);
1115 return;
1116 }
Prathyush Kdb43fd12012-12-06 20:16:05 +05301117 mutex_unlock(&ctx->mixer_mutex);
1118
Rahul Sharma381be022014-06-23 11:02:22 +05301119 mixer_stop(ctx);
Sean Paulf041b252014-01-30 16:19:15 -05001120 mixer_window_suspend(mgr);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301121
1122 ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
1123
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301124 mutex_lock(&ctx->mixer_mutex);
1125 ctx->powered = false;
1126 mutex_unlock(&ctx->mixer_mutex);
1127
Sean Paul0bfb1f82013-06-11 12:24:02 +05301128 clk_disable_unprepare(res->mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301129 if (ctx->vp_enabled) {
Sean Paul0bfb1f82013-06-11 12:24:02 +05301130 clk_disable_unprepare(res->vp);
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001131 if (ctx->has_sclk)
1132 clk_disable_unprepare(res->sclk_mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301133 }
1134
Sean Paulaf65c802014-01-30 16:19:27 -05001135 pm_runtime_put_sync(ctx->dev);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301136}
1137
Sean Paulf041b252014-01-30 16:19:15 -05001138static void mixer_dpms(struct exynos_drm_manager *mgr, int mode)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301139{
Prathyush Kdb43fd12012-12-06 20:16:05 +05301140 switch (mode) {
1141 case DRM_MODE_DPMS_ON:
Sean Paulaf65c802014-01-30 16:19:27 -05001142 mixer_poweron(mgr);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301143 break;
1144 case DRM_MODE_DPMS_STANDBY:
1145 case DRM_MODE_DPMS_SUSPEND:
1146 case DRM_MODE_DPMS_OFF:
Sean Paulaf65c802014-01-30 16:19:27 -05001147 mixer_poweroff(mgr);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301148 break;
1149 default:
1150 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
1151 break;
1152 }
1153}
1154
Sean Paulf041b252014-01-30 16:19:15 -05001155/* Only valid for Mixer version 16.0.33.0 */
1156int mixer_check_mode(struct drm_display_mode *mode)
1157{
1158 u32 w, h;
1159
1160 w = mode->hdisplay;
1161 h = mode->vdisplay;
1162
1163 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
1164 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1165 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1166
1167 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
1168 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1169 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1170 return 0;
1171
1172 return -EINVAL;
1173}
1174
1175static struct exynos_drm_manager_ops mixer_manager_ops = {
Sean Paulf041b252014-01-30 16:19:15 -05001176 .dpms = mixer_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001177 .enable_vblank = mixer_enable_vblank,
1178 .disable_vblank = mixer_disable_vblank,
Prathyush K8137a2e2012-12-06 20:16:01 +05301179 .wait_for_vblank = mixer_wait_for_vblank,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001180 .win_mode_set = mixer_win_mode_set,
1181 .win_commit = mixer_win_commit,
1182 .win_disable = mixer_win_disable,
Sean Paulf041b252014-01-30 16:19:15 -05001183};
Rahul Sharma0ea68222013-01-15 08:11:06 -05001184
Sean Paulf041b252014-01-30 16:19:15 -05001185static struct exynos_drm_manager mixer_manager = {
1186 .type = EXYNOS_DISPLAY_TYPE_HDMI,
1187 .ops = &mixer_manager_ops,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001188};
1189
Rahul Sharmadef5e092013-06-19 18:21:08 +05301190static struct mixer_drv_data exynos5420_mxr_drv_data = {
1191 .version = MXR_VER_128_0_0_184,
1192 .is_vp_enabled = 0,
1193};
1194
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301195static struct mixer_drv_data exynos5250_mxr_drv_data = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301196 .version = MXR_VER_16_0_33_0,
1197 .is_vp_enabled = 0,
1198};
1199
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001200static struct mixer_drv_data exynos4212_mxr_drv_data = {
1201 .version = MXR_VER_0_0_0_16,
1202 .is_vp_enabled = 1,
1203};
1204
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301205static struct mixer_drv_data exynos4210_mxr_drv_data = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301206 .version = MXR_VER_0_0_0_16,
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301207 .is_vp_enabled = 1,
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001208 .has_sclk = 1,
Rahul Sharma1e123442012-10-04 20:48:51 +05301209};
1210
1211static struct platform_device_id mixer_driver_types[] = {
1212 {
1213 .name = "s5p-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301214 .driver_data = (unsigned long)&exynos4210_mxr_drv_data,
Rahul Sharma1e123442012-10-04 20:48:51 +05301215 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301216 .name = "exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301217 .driver_data = (unsigned long)&exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301218 }, {
1219 /* end node */
1220 }
1221};
1222
1223static struct of_device_id mixer_match_types[] = {
1224 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001225 .compatible = "samsung,exynos4210-mixer",
1226 .data = &exynos4210_mxr_drv_data,
1227 }, {
1228 .compatible = "samsung,exynos4212-mixer",
1229 .data = &exynos4212_mxr_drv_data,
1230 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301231 .compatible = "samsung,exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301232 .data = &exynos5250_mxr_drv_data,
1233 }, {
1234 .compatible = "samsung,exynos5250-mixer",
1235 .data = &exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301236 }, {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301237 .compatible = "samsung,exynos5420-mixer",
1238 .data = &exynos5420_mxr_drv_data,
1239 }, {
Rahul Sharma1e123442012-10-04 20:48:51 +05301240 /* end node */
1241 }
1242};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001243MODULE_DEVICE_TABLE(of, mixer_match_types);
Rahul Sharma1e123442012-10-04 20:48:51 +05301244
Inki Daef37cd5e2014-05-09 14:25:20 +09001245static int mixer_bind(struct device *dev, struct device *manager, void *data)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001246{
Inki Daef37cd5e2014-05-09 14:25:20 +09001247 struct platform_device *pdev = to_platform_device(dev);
1248 struct drm_device *drm_dev = data;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001249 struct mixer_context *ctx;
Rahul Sharma1e123442012-10-04 20:48:51 +05301250 struct mixer_drv_data *drv;
Inki Daef37cd5e2014-05-09 14:25:20 +09001251 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001252
1253 dev_info(dev, "probe start\n");
1254
Sean Paulf041b252014-01-30 16:19:15 -05001255 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1256 if (!ctx) {
1257 DRM_ERROR("failed to alloc mixer context.\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001258 return -ENOMEM;
Sean Paulf041b252014-01-30 16:19:15 -05001259 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001260
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001261 mutex_init(&ctx->mixer_mutex);
1262
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301263 if (dev->of_node) {
1264 const struct of_device_id *match;
Sachin Kamate436b092013-06-05 16:00:23 +09001265 match = of_match_node(mixer_match_types, dev->of_node);
Rahul Sharma2cdc53b2012-10-31 09:36:26 +05301266 drv = (struct mixer_drv_data *)match->data;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301267 } else {
1268 drv = (struct mixer_drv_data *)
1269 platform_get_device_id(pdev)->driver_data;
1270 }
1271
Sean Paul45517892014-01-30 16:19:05 -05001272 ctx->pdev = pdev;
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001273 ctx->dev = dev;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301274 ctx->vp_enabled = drv->is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001275 ctx->has_sclk = drv->has_sclk;
Rahul Sharma1e123442012-10-04 20:48:51 +05301276 ctx->mxr_ver = drv->version;
Daniel Vetter57ed0f72013-12-11 11:34:43 +01001277 init_waitqueue_head(&ctx->wait_vsync_queue);
Prathyush K6e95d5e2012-12-06 20:16:03 +05301278 atomic_set(&ctx->wait_vsync_event, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001279
Sean Paulf041b252014-01-30 16:19:15 -05001280 mixer_manager.ctx = ctx;
Inki Daef37cd5e2014-05-09 14:25:20 +09001281 ret = mixer_initialize(&mixer_manager, drm_dev);
1282 if (ret)
1283 return ret;
1284
Sean Paulf041b252014-01-30 16:19:15 -05001285 platform_set_drvdata(pdev, &mixer_manager);
Inki Daef37cd5e2014-05-09 14:25:20 +09001286 ret = exynos_drm_crtc_create(&mixer_manager);
1287 if (ret) {
1288 mixer_mgr_remove(&mixer_manager);
1289 return ret;
1290 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001291
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001292 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001293
1294 return 0;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001295}
1296
Inki Daef37cd5e2014-05-09 14:25:20 +09001297static void mixer_unbind(struct device *dev, struct device *master, void *data)
1298{
1299 struct exynos_drm_manager *mgr = dev_get_drvdata(dev);
1300 struct drm_crtc *crtc = mgr->crtc;
1301
1302 dev_info(dev, "remove successful\n");
1303
1304 mixer_mgr_remove(mgr);
1305
1306 pm_runtime_disable(dev);
1307
1308 crtc->funcs->destroy(crtc);
1309}
1310
1311static const struct component_ops mixer_component_ops = {
1312 .bind = mixer_bind,
1313 .unbind = mixer_unbind,
1314};
1315
1316static int mixer_probe(struct platform_device *pdev)
1317{
Inki Daedf5225b2014-05-29 18:28:02 +09001318 int ret;
1319
1320 ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
1321 mixer_manager.type);
1322 if (ret)
1323 return ret;
1324
1325 ret = component_add(&pdev->dev, &mixer_component_ops);
1326 if (ret)
1327 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
1328
1329 return ret;
Inki Daef37cd5e2014-05-09 14:25:20 +09001330}
1331
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001332static int mixer_remove(struct platform_device *pdev)
1333{
Inki Daedf5225b2014-05-29 18:28:02 +09001334 component_del(&pdev->dev, &mixer_component_ops);
1335 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
1336
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001337 return 0;
1338}
1339
1340struct platform_driver mixer_driver = {
1341 .driver = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301342 .name = "exynos-mixer",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001343 .owner = THIS_MODULE,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301344 .of_match_table = mixer_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001345 },
1346 .probe = mixer_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001347 .remove = mixer_remove,
Rahul Sharma1e123442012-10-04 20:48:51 +05301348 .id_table = mixer_driver_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001349};