blob: fbec750574e64a3158b232d15ef309b29ed5340c [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"
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +090040#include "exynos_drm_plane.h"
Inki Dae1055b392012-10-19 17:37:35 +090041#include "exynos_drm_iommu.h"
Sean Paulf041b252014-01-30 16:19:15 -050042#include "exynos_mixer.h"
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090043
Sean Paulf041b252014-01-30 16:19:15 -050044#define MIXER_WIN_NR 3
45#define MIXER_DEFAULT_WIN 0
Seung-Woo Kimd8408322011-12-21 17:39:39 +090046
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090047struct mixer_resources {
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090048 int irq;
49 void __iomem *mixer_regs;
50 void __iomem *vp_regs;
51 spinlock_t reg_slock;
52 struct clk *mixer;
53 struct clk *vp;
Marek Szyprowski04427ec2015-02-02 14:20:28 +010054 struct clk *hdmi;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090055 struct clk *sclk_mixer;
56 struct clk *sclk_hdmi;
Marek Szyprowskiff830c92014-07-01 10:10:07 +020057 struct clk *mout_mixer;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090058};
59
Rahul Sharma1e123442012-10-04 20:48:51 +053060enum mixer_version_id {
61 MXR_VER_0_0_0_16,
62 MXR_VER_16_0_33_0,
Rahul Sharmadef5e092013-06-19 18:21:08 +053063 MXR_VER_128_0_0_184,
Rahul Sharma1e123442012-10-04 20:48:51 +053064};
65
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090066struct mixer_context {
Sean Paul45517892014-01-30 16:19:05 -050067 struct platform_device *pdev;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090068 struct device *dev;
Inki Dae1055b392012-10-19 17:37:35 +090069 struct drm_device *drm_dev;
Gustavo Padovan93bca242015-01-18 18:16:23 +090070 struct exynos_drm_crtc *crtc;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +090071 struct exynos_drm_plane planes[MIXER_WIN_NR];
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090072 int pipe;
73 bool interlace;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090074 bool powered;
Rahul Sharma1b8e5742012-10-04 20:48:52 +053075 bool vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +020076 bool has_sclk;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090077 u32 int_en;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090078
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090079 struct mutex mixer_mutex;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090080 struct mixer_resources mixer_res;
Rahul Sharma1e123442012-10-04 20:48:51 +053081 enum mixer_version_id mxr_ver;
Prathyush K6e95d5e2012-12-06 20:16:03 +053082 wait_queue_head_t wait_vsync_queue;
83 atomic_t wait_vsync_event;
Rahul Sharma1e123442012-10-04 20:48:51 +053084};
85
86struct mixer_drv_data {
87 enum mixer_version_id version;
Rahul Sharma1b8e5742012-10-04 20:48:52 +053088 bool is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +020089 bool has_sclk;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090090};
91
Seung-Woo Kimd8408322011-12-21 17:39:39 +090092static const u8 filter_y_horiz_tap8[] = {
93 0, -1, -1, -1, -1, -1, -1, -1,
94 -1, -1, -1, -1, -1, 0, 0, 0,
95 0, 2, 4, 5, 6, 6, 6, 6,
96 6, 5, 5, 4, 3, 2, 1, 1,
97 0, -6, -12, -16, -18, -20, -21, -20,
98 -20, -18, -16, -13, -10, -8, -5, -2,
99 127, 126, 125, 121, 114, 107, 99, 89,
100 79, 68, 57, 46, 35, 25, 16, 8,
101};
102
103static const u8 filter_y_vert_tap4[] = {
104 0, -3, -6, -8, -8, -8, -8, -7,
105 -6, -5, -4, -3, -2, -1, -1, 0,
106 127, 126, 124, 118, 111, 102, 92, 81,
107 70, 59, 48, 37, 27, 19, 11, 5,
108 0, 5, 11, 19, 27, 37, 48, 59,
109 70, 81, 92, 102, 111, 118, 124, 126,
110 0, 0, -1, -1, -2, -3, -4, -5,
111 -6, -7, -8, -8, -8, -8, -6, -3,
112};
113
114static const u8 filter_cr_horiz_tap4[] = {
115 0, -3, -6, -8, -8, -8, -8, -7,
116 -6, -5, -4, -3, -2, -1, -1, 0,
117 127, 126, 124, 118, 111, 102, 92, 81,
118 70, 59, 48, 37, 27, 19, 11, 5,
119};
120
121static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
122{
123 return readl(res->vp_regs + reg_id);
124}
125
126static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
127 u32 val)
128{
129 writel(val, res->vp_regs + reg_id);
130}
131
132static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
133 u32 val, u32 mask)
134{
135 u32 old = vp_reg_read(res, reg_id);
136
137 val = (val & mask) | (old & ~mask);
138 writel(val, res->vp_regs + reg_id);
139}
140
141static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
142{
143 return readl(res->mixer_regs + reg_id);
144}
145
146static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
147 u32 val)
148{
149 writel(val, res->mixer_regs + reg_id);
150}
151
152static inline void mixer_reg_writemask(struct mixer_resources *res,
153 u32 reg_id, u32 val, u32 mask)
154{
155 u32 old = mixer_reg_read(res, reg_id);
156
157 val = (val & mask) | (old & ~mask);
158 writel(val, res->mixer_regs + reg_id);
159}
160
161static void mixer_regs_dump(struct mixer_context *ctx)
162{
163#define DUMPREG(reg_id) \
164do { \
165 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
166 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
167} while (0)
168
169 DUMPREG(MXR_STATUS);
170 DUMPREG(MXR_CFG);
171 DUMPREG(MXR_INT_EN);
172 DUMPREG(MXR_INT_STATUS);
173
174 DUMPREG(MXR_LAYER_CFG);
175 DUMPREG(MXR_VIDEO_CFG);
176
177 DUMPREG(MXR_GRAPHIC0_CFG);
178 DUMPREG(MXR_GRAPHIC0_BASE);
179 DUMPREG(MXR_GRAPHIC0_SPAN);
180 DUMPREG(MXR_GRAPHIC0_WH);
181 DUMPREG(MXR_GRAPHIC0_SXY);
182 DUMPREG(MXR_GRAPHIC0_DXY);
183
184 DUMPREG(MXR_GRAPHIC1_CFG);
185 DUMPREG(MXR_GRAPHIC1_BASE);
186 DUMPREG(MXR_GRAPHIC1_SPAN);
187 DUMPREG(MXR_GRAPHIC1_WH);
188 DUMPREG(MXR_GRAPHIC1_SXY);
189 DUMPREG(MXR_GRAPHIC1_DXY);
190#undef DUMPREG
191}
192
193static void vp_regs_dump(struct mixer_context *ctx)
194{
195#define DUMPREG(reg_id) \
196do { \
197 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
198 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
199} while (0)
200
201 DUMPREG(VP_ENABLE);
202 DUMPREG(VP_SRESET);
203 DUMPREG(VP_SHADOW_UPDATE);
204 DUMPREG(VP_FIELD_ID);
205 DUMPREG(VP_MODE);
206 DUMPREG(VP_IMG_SIZE_Y);
207 DUMPREG(VP_IMG_SIZE_C);
208 DUMPREG(VP_PER_RATE_CTRL);
209 DUMPREG(VP_TOP_Y_PTR);
210 DUMPREG(VP_BOT_Y_PTR);
211 DUMPREG(VP_TOP_C_PTR);
212 DUMPREG(VP_BOT_C_PTR);
213 DUMPREG(VP_ENDIAN_MODE);
214 DUMPREG(VP_SRC_H_POSITION);
215 DUMPREG(VP_SRC_V_POSITION);
216 DUMPREG(VP_SRC_WIDTH);
217 DUMPREG(VP_SRC_HEIGHT);
218 DUMPREG(VP_DST_H_POSITION);
219 DUMPREG(VP_DST_V_POSITION);
220 DUMPREG(VP_DST_WIDTH);
221 DUMPREG(VP_DST_HEIGHT);
222 DUMPREG(VP_H_RATIO);
223 DUMPREG(VP_V_RATIO);
224
225#undef DUMPREG
226}
227
228static inline void vp_filter_set(struct mixer_resources *res,
229 int reg_id, const u8 *data, unsigned int size)
230{
231 /* assure 4-byte align */
232 BUG_ON(size & 3);
233 for (; size; size -= 4, reg_id += 4, data += 4) {
234 u32 val = (data[0] << 24) | (data[1] << 16) |
235 (data[2] << 8) | data[3];
236 vp_reg_write(res, reg_id, val);
237 }
238}
239
240static void vp_default_filter(struct mixer_resources *res)
241{
242 vp_filter_set(res, VP_POLY8_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530243 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900244 vp_filter_set(res, VP_POLY4_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530245 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900246 vp_filter_set(res, VP_POLY4_C0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530247 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900248}
249
250static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
251{
252 struct mixer_resources *res = &ctx->mixer_res;
253
254 /* block update on vsync */
255 mixer_reg_writemask(res, MXR_STATUS, enable ?
256 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
257
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530258 if (ctx->vp_enabled)
259 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900260 VP_SHADOW_UPDATE_ENABLE : 0);
261}
262
263static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
264{
265 struct mixer_resources *res = &ctx->mixer_res;
266 u32 val;
267
268 /* choosing between interlace and progressive mode */
269 val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
Tobias Jakobi1e6d4592015-04-07 01:14:50 +0200270 MXR_CFG_SCAN_PROGRESSIVE);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900271
Rahul Sharmadef5e092013-06-19 18:21:08 +0530272 if (ctx->mxr_ver != MXR_VER_128_0_0_184) {
273 /* choosing between proper HD and SD mode */
274 if (height <= 480)
275 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
276 else if (height <= 576)
277 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
278 else if (height <= 720)
279 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
280 else if (height <= 1080)
281 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
282 else
283 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
284 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900285
286 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
287}
288
289static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
290{
291 struct mixer_resources *res = &ctx->mixer_res;
292 u32 val;
293
294 if (height == 480) {
295 val = MXR_CFG_RGB601_0_255;
296 } else if (height == 576) {
297 val = MXR_CFG_RGB601_0_255;
298 } else if (height == 720) {
299 val = MXR_CFG_RGB709_16_235;
300 mixer_reg_write(res, MXR_CM_COEFF_Y,
301 (1 << 30) | (94 << 20) | (314 << 10) |
302 (32 << 0));
303 mixer_reg_write(res, MXR_CM_COEFF_CB,
304 (972 << 20) | (851 << 10) | (225 << 0));
305 mixer_reg_write(res, MXR_CM_COEFF_CR,
306 (225 << 20) | (820 << 10) | (1004 << 0));
307 } else if (height == 1080) {
308 val = MXR_CFG_RGB709_16_235;
309 mixer_reg_write(res, MXR_CM_COEFF_Y,
310 (1 << 30) | (94 << 20) | (314 << 10) |
311 (32 << 0));
312 mixer_reg_write(res, MXR_CM_COEFF_CB,
313 (972 << 20) | (851 << 10) | (225 << 0));
314 mixer_reg_write(res, MXR_CM_COEFF_CR,
315 (225 << 20) | (820 << 10) | (1004 << 0));
316 } else {
317 val = MXR_CFG_RGB709_16_235;
318 mixer_reg_write(res, MXR_CM_COEFF_Y,
319 (1 << 30) | (94 << 20) | (314 << 10) |
320 (32 << 0));
321 mixer_reg_write(res, MXR_CM_COEFF_CB,
322 (972 << 20) | (851 << 10) | (225 << 0));
323 mixer_reg_write(res, MXR_CM_COEFF_CR,
324 (225 << 20) | (820 << 10) | (1004 << 0));
325 }
326
327 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
328}
329
330static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable)
331{
332 struct mixer_resources *res = &ctx->mixer_res;
333 u32 val = enable ? ~0 : 0;
334
335 switch (win) {
336 case 0:
337 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
338 break;
339 case 1:
340 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
341 break;
342 case 2:
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530343 if (ctx->vp_enabled) {
344 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
345 mixer_reg_writemask(res, MXR_CFG, val,
346 MXR_CFG_VP_ENABLE);
Joonyoung Shimf1e716d2014-07-25 19:59:10 +0900347
348 /* control blending of graphic layer 0 */
349 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(0), val,
350 MXR_GRP_CFG_BLEND_PRE_MUL |
351 MXR_GRP_CFG_PIXEL_BLEND_EN);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530352 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900353 break;
354 }
355}
356
357static void mixer_run(struct mixer_context *ctx)
358{
359 struct mixer_resources *res = &ctx->mixer_res;
360
361 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
362
363 mixer_regs_dump(ctx);
364}
365
Rahul Sharma381be022014-06-23 11:02:22 +0530366static void mixer_stop(struct mixer_context *ctx)
367{
368 struct mixer_resources *res = &ctx->mixer_res;
369 int timeout = 20;
370
371 mixer_reg_writemask(res, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
372
373 while (!(mixer_reg_read(res, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
374 --timeout)
375 usleep_range(10000, 12000);
376
377 mixer_regs_dump(ctx);
378}
379
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900380static void vp_video_buffer(struct mixer_context *ctx, int win)
381{
382 struct mixer_resources *res = &ctx->mixer_res;
383 unsigned long flags;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900384 struct exynos_drm_plane *plane;
YoungJun Cho782953e2013-07-01 13:04:12 +0900385 unsigned int buf_num = 1;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900386 dma_addr_t luma_addr[2], chroma_addr[2];
387 bool tiled_mode = false;
388 bool crcb_mode = false;
389 u32 val;
390
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900391 plane = &ctx->planes[win];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900392
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900393 switch (plane->pixel_format) {
Ville Syrjälä363b06a2012-05-14 11:08:51 +0900394 case DRM_FORMAT_NV12:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900395 crcb_mode = false;
396 buf_num = 2;
397 break;
398 /* TODO: single buffer format NV12, NV21 */
399 default:
400 /* ignore pixel format at disable time */
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900401 if (!plane->dma_addr[0])
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900402 break;
403
404 DRM_ERROR("pixel format for vp is wrong [%d].\n",
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900405 plane->pixel_format);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900406 return;
407 }
408
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900409 if (buf_num == 2) {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900410 luma_addr[0] = plane->dma_addr[0];
411 chroma_addr[0] = plane->dma_addr[1];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900412 } else {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900413 luma_addr[0] = plane->dma_addr[0];
414 chroma_addr[0] = plane->dma_addr[0]
415 + (plane->pitch * plane->fb_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900416 }
417
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900418 if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900419 ctx->interlace = true;
420 if (tiled_mode) {
421 luma_addr[1] = luma_addr[0] + 0x40;
422 chroma_addr[1] = chroma_addr[0] + 0x40;
423 } else {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900424 luma_addr[1] = luma_addr[0] + plane->pitch;
425 chroma_addr[1] = chroma_addr[0] + plane->pitch;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900426 }
427 } else {
428 ctx->interlace = false;
429 luma_addr[1] = 0;
430 chroma_addr[1] = 0;
431 }
432
433 spin_lock_irqsave(&res->reg_slock, flags);
434 mixer_vsync_set_update(ctx, false);
435
436 /* interlace or progressive scan mode */
437 val = (ctx->interlace ? ~0 : 0);
438 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
439
440 /* setup format */
441 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
442 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
443 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
444
445 /* setting size of input image */
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900446 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(plane->pitch) |
447 VP_IMG_VSIZE(plane->fb_height));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900448 /* chroma height has to reduced by 2 to avoid chroma distorions */
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900449 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(plane->pitch) |
450 VP_IMG_VSIZE(plane->fb_height / 2));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900451
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900452 vp_reg_write(res, VP_SRC_WIDTH, plane->src_width);
453 vp_reg_write(res, VP_SRC_HEIGHT, plane->src_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900454 vp_reg_write(res, VP_SRC_H_POSITION,
Joonyoung Shimcb8a3db2015-04-07 15:59:38 +0900455 VP_SRC_H_POSITION_VAL(plane->src_x));
456 vp_reg_write(res, VP_SRC_V_POSITION, plane->src_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900457
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900458 vp_reg_write(res, VP_DST_WIDTH, plane->crtc_width);
459 vp_reg_write(res, VP_DST_H_POSITION, plane->crtc_x);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900460 if (ctx->interlace) {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900461 vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height / 2);
462 vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y / 2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900463 } else {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900464 vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height);
465 vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900466 }
467
Joonyoung Shim3cabaf72015-04-07 15:59:39 +0900468 vp_reg_write(res, VP_H_RATIO, plane->h_ratio);
469 vp_reg_write(res, VP_V_RATIO, plane->v_ratio);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900470
471 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
472
473 /* set buffer address to vp */
474 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
475 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
476 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
477 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
478
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900479 mixer_cfg_scan(ctx, plane->mode_height);
480 mixer_cfg_rgb_fmt(ctx, plane->mode_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900481 mixer_cfg_layer(ctx, win, true);
482 mixer_run(ctx);
483
484 mixer_vsync_set_update(ctx, true);
485 spin_unlock_irqrestore(&res->reg_slock, flags);
486
487 vp_regs_dump(ctx);
488}
489
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530490static void mixer_layer_update(struct mixer_context *ctx)
491{
492 struct mixer_resources *res = &ctx->mixer_res;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530493
Rahul Sharma5c0f4822014-06-23 11:02:23 +0530494 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530495}
496
Tobias Jakobi26110152015-04-07 01:14:52 +0200497static int mixer_setup_scale(const struct exynos_drm_plane *plane,
498 unsigned int *x_ratio, unsigned int *y_ratio)
499{
500 if (plane->crtc_width != plane->src_width) {
501 if (plane->crtc_width == 2 * plane->src_width)
502 *x_ratio = 1;
503 else
504 goto fail;
505 }
506
507 if (plane->crtc_height != plane->src_height) {
508 if (plane->crtc_height == 2 * plane->src_height)
509 *y_ratio = 1;
510 else
511 goto fail;
512 }
513
514 return 0;
515
516fail:
517 DRM_DEBUG_KMS("only 2x width/height scaling of plane supported\n");
518 return -ENOTSUPP;
519}
520
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900521static void mixer_graph_buffer(struct mixer_context *ctx, int win)
522{
523 struct mixer_resources *res = &ctx->mixer_res;
524 unsigned long flags;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900525 struct exynos_drm_plane *plane;
Tobias Jakobi26110152015-04-07 01:14:52 +0200526 unsigned int x_ratio = 0, y_ratio = 0;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900527 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900528 dma_addr_t dma_addr;
529 unsigned int fmt;
530 u32 val;
531
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900532 plane = &ctx->planes[win];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900533
534 #define RGB565 4
535 #define ARGB1555 5
536 #define ARGB4444 6
537 #define ARGB8888 7
538
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900539 switch (plane->bpp) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900540 case 16:
541 fmt = ARGB4444;
542 break;
543 case 32:
544 fmt = ARGB8888;
545 break;
546 default:
547 fmt = ARGB8888;
548 }
549
Tobias Jakobi26110152015-04-07 01:14:52 +0200550 /* check if mixer supports requested scaling setup */
551 if (mixer_setup_scale(plane, &x_ratio, &y_ratio))
552 return;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900553
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900554 dst_x_offset = plane->crtc_x;
555 dst_y_offset = plane->crtc_y;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900556
557 /* converting dma address base and source offset */
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900558 dma_addr = plane->dma_addr[0]
Joonyoung Shimcb8a3db2015-04-07 15:59:38 +0900559 + (plane->src_x * plane->bpp >> 3)
560 + (plane->src_y * plane->pitch);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900561 src_x_offset = 0;
562 src_y_offset = 0;
563
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900564 if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900565 ctx->interlace = true;
566 else
567 ctx->interlace = false;
568
569 spin_lock_irqsave(&res->reg_slock, flags);
570 mixer_vsync_set_update(ctx, false);
571
572 /* setup format */
573 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
574 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
575
576 /* setup geometry */
Daniel Stoneadacb222015-03-17 13:24:58 +0000577 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win),
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900578 plane->pitch / (plane->bpp >> 3));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900579
Rahul Sharmadef5e092013-06-19 18:21:08 +0530580 /* setup display size */
581 if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
582 win == MIXER_DEFAULT_WIN) {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900583 val = MXR_MXR_RES_HEIGHT(plane->mode_height);
584 val |= MXR_MXR_RES_WIDTH(plane->mode_width);
Rahul Sharmadef5e092013-06-19 18:21:08 +0530585 mixer_reg_write(res, MXR_RESOLUTION, val);
586 }
587
Tobias Jakobi26110152015-04-07 01:14:52 +0200588 val = MXR_GRP_WH_WIDTH(plane->src_width);
589 val |= MXR_GRP_WH_HEIGHT(plane->src_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900590 val |= MXR_GRP_WH_H_SCALE(x_ratio);
591 val |= MXR_GRP_WH_V_SCALE(y_ratio);
592 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
593
594 /* setup offsets in source image */
595 val = MXR_GRP_SXY_SX(src_x_offset);
596 val |= MXR_GRP_SXY_SY(src_y_offset);
597 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
598
599 /* setup offsets in display image */
600 val = MXR_GRP_DXY_DX(dst_x_offset);
601 val |= MXR_GRP_DXY_DY(dst_y_offset);
602 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
603
604 /* set buffer address to mixer */
605 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
606
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900607 mixer_cfg_scan(ctx, plane->mode_height);
608 mixer_cfg_rgb_fmt(ctx, plane->mode_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900609 mixer_cfg_layer(ctx, win, true);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530610
611 /* layer update mandatory for mixer 16.0.33.0 */
Rahul Sharmadef5e092013-06-19 18:21:08 +0530612 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
613 ctx->mxr_ver == MXR_VER_128_0_0_184)
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530614 mixer_layer_update(ctx);
615
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900616 mixer_run(ctx);
617
618 mixer_vsync_set_update(ctx, true);
619 spin_unlock_irqrestore(&res->reg_slock, flags);
620}
621
622static void vp_win_reset(struct mixer_context *ctx)
623{
624 struct mixer_resources *res = &ctx->mixer_res;
625 int tries = 100;
626
627 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
628 for (tries = 100; tries; --tries) {
629 /* waiting until VP_SRESET_PROCESSING is 0 */
630 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
631 break;
Sean Paul09760ea2013-01-14 17:03:20 -0500632 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900633 }
634 WARN(tries == 0, "failed to reset Video Processor\n");
635}
636
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900637static void mixer_win_reset(struct mixer_context *ctx)
638{
639 struct mixer_resources *res = &ctx->mixer_res;
640 unsigned long flags;
641 u32 val; /* value stored to register */
642
643 spin_lock_irqsave(&res->reg_slock, flags);
644 mixer_vsync_set_update(ctx, false);
645
646 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
647
648 /* set output in RGB888 mode */
649 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
650
651 /* 16 beat burst in DMA */
652 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
653 MXR_STATUS_BURST_MASK);
654
655 /* setting default layer priority: layer1 > layer0 > video
656 * because typical usage scenario would be
657 * layer1 - OSD
658 * layer0 - framebuffer
659 * video - video overlay
660 */
661 val = MXR_LAYER_CFG_GRP1_VAL(3);
662 val |= MXR_LAYER_CFG_GRP0_VAL(2);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530663 if (ctx->vp_enabled)
664 val |= MXR_LAYER_CFG_VP_VAL(1);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900665 mixer_reg_write(res, MXR_LAYER_CFG, val);
666
667 /* setting background color */
668 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
669 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
670 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
671
672 /* setting graphical layers */
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900673 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
674 val |= MXR_GRP_CFG_WIN_BLEND_EN;
675 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
676
Sean Paul0377f4e2013-04-25 15:13:26 -0400677 /* Don't blend layer 0 onto the mixer background */
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900678 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
Sean Paul0377f4e2013-04-25 15:13:26 -0400679
680 /* Blend layer 1 into layer 0 */
681 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
682 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900683 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
684
Seung-Woo Kim57366032012-05-15 17:22:08 +0900685 /* setting video layers */
686 val = MXR_GRP_CFG_ALPHA_VAL(0);
687 mixer_reg_write(res, MXR_VIDEO_CFG, val);
688
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530689 if (ctx->vp_enabled) {
690 /* configuration of Video Processor Registers */
691 vp_win_reset(ctx);
692 vp_default_filter(res);
693 }
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900694
695 /* disable all layers */
696 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
697 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530698 if (ctx->vp_enabled)
699 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900700
701 mixer_vsync_set_update(ctx, true);
702 spin_unlock_irqrestore(&res->reg_slock, flags);
703}
704
Sean Paul45517892014-01-30 16:19:05 -0500705static irqreturn_t mixer_irq_handler(int irq, void *arg)
706{
707 struct mixer_context *ctx = arg;
708 struct mixer_resources *res = &ctx->mixer_res;
709 u32 val, base, shadow;
710
711 spin_lock(&res->reg_slock);
712
713 /* read interrupt status for handling and clearing flags for VSYNC */
714 val = mixer_reg_read(res, MXR_INT_STATUS);
715
716 /* handling VSYNC */
717 if (val & MXR_INT_STATUS_VSYNC) {
718 /* interlace scan need to check shadow register */
719 if (ctx->interlace) {
720 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
721 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
722 if (base != shadow)
723 goto out;
724
725 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
726 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
727 if (base != shadow)
728 goto out;
729 }
730
731 drm_handle_vblank(ctx->drm_dev, ctx->pipe);
732 exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
733
734 /* set wait vsync event to zero and wake up queue. */
735 if (atomic_read(&ctx->wait_vsync_event)) {
736 atomic_set(&ctx->wait_vsync_event, 0);
737 wake_up(&ctx->wait_vsync_queue);
738 }
739 }
740
741out:
742 /* clear interrupts */
743 if (~val & MXR_INT_EN_VSYNC) {
744 /* vsync interrupt use different bit for read and clear */
745 val &= ~MXR_INT_EN_VSYNC;
746 val |= MXR_INT_CLEAR_VSYNC;
747 }
748 mixer_reg_write(res, MXR_INT_STATUS, val);
749
750 spin_unlock(&res->reg_slock);
751
752 return IRQ_HANDLED;
753}
754
755static int mixer_resources_init(struct mixer_context *mixer_ctx)
756{
757 struct device *dev = &mixer_ctx->pdev->dev;
758 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
759 struct resource *res;
760 int ret;
761
762 spin_lock_init(&mixer_res->reg_slock);
763
764 mixer_res->mixer = devm_clk_get(dev, "mixer");
765 if (IS_ERR(mixer_res->mixer)) {
766 dev_err(dev, "failed to get clock 'mixer'\n");
767 return -ENODEV;
768 }
769
Marek Szyprowski04427ec2015-02-02 14:20:28 +0100770 mixer_res->hdmi = devm_clk_get(dev, "hdmi");
771 if (IS_ERR(mixer_res->hdmi)) {
772 dev_err(dev, "failed to get clock 'hdmi'\n");
773 return PTR_ERR(mixer_res->hdmi);
774 }
775
Sean Paul45517892014-01-30 16:19:05 -0500776 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
777 if (IS_ERR(mixer_res->sclk_hdmi)) {
778 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
779 return -ENODEV;
780 }
781 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
782 if (res == NULL) {
783 dev_err(dev, "get memory resource failed.\n");
784 return -ENXIO;
785 }
786
787 mixer_res->mixer_regs = devm_ioremap(dev, res->start,
788 resource_size(res));
789 if (mixer_res->mixer_regs == NULL) {
790 dev_err(dev, "register mapping failed.\n");
791 return -ENXIO;
792 }
793
794 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
795 if (res == NULL) {
796 dev_err(dev, "get interrupt resource failed.\n");
797 return -ENXIO;
798 }
799
800 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
801 0, "drm_mixer", mixer_ctx);
802 if (ret) {
803 dev_err(dev, "request interrupt failed.\n");
804 return ret;
805 }
806 mixer_res->irq = res->start;
807
808 return 0;
809}
810
811static int vp_resources_init(struct mixer_context *mixer_ctx)
812{
813 struct device *dev = &mixer_ctx->pdev->dev;
814 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
815 struct resource *res;
816
817 mixer_res->vp = devm_clk_get(dev, "vp");
818 if (IS_ERR(mixer_res->vp)) {
819 dev_err(dev, "failed to get clock 'vp'\n");
820 return -ENODEV;
821 }
Sean Paul45517892014-01-30 16:19:05 -0500822
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200823 if (mixer_ctx->has_sclk) {
824 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
825 if (IS_ERR(mixer_res->sclk_mixer)) {
826 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
827 return -ENODEV;
828 }
829 mixer_res->mout_mixer = devm_clk_get(dev, "mout_mixer");
830 if (IS_ERR(mixer_res->mout_mixer)) {
831 dev_err(dev, "failed to get clock 'mout_mixer'\n");
832 return -ENODEV;
833 }
834
835 if (mixer_res->sclk_hdmi && mixer_res->mout_mixer)
836 clk_set_parent(mixer_res->mout_mixer,
837 mixer_res->sclk_hdmi);
838 }
Sean Paul45517892014-01-30 16:19:05 -0500839
840 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
841 if (res == NULL) {
842 dev_err(dev, "get memory resource failed.\n");
843 return -ENXIO;
844 }
845
846 mixer_res->vp_regs = devm_ioremap(dev, res->start,
847 resource_size(res));
848 if (mixer_res->vp_regs == NULL) {
849 dev_err(dev, "register mapping failed.\n");
850 return -ENXIO;
851 }
852
853 return 0;
854}
855
Gustavo Padovan93bca242015-01-18 18:16:23 +0900856static int mixer_initialize(struct mixer_context *mixer_ctx,
Inki Daef37cd5e2014-05-09 14:25:20 +0900857 struct drm_device *drm_dev)
Sean Paul45517892014-01-30 16:19:05 -0500858{
859 int ret;
Inki Daef37cd5e2014-05-09 14:25:20 +0900860 struct exynos_drm_private *priv;
861 priv = drm_dev->dev_private;
Sean Paul45517892014-01-30 16:19:05 -0500862
Gustavo Padovaneb88e422014-11-26 16:43:27 -0200863 mixer_ctx->drm_dev = drm_dev;
Gustavo Padovan8a326ed2014-11-04 18:44:47 -0200864 mixer_ctx->pipe = priv->pipe++;
Sean Paul45517892014-01-30 16:19:05 -0500865
866 /* acquire resources: regs, irqs, clocks */
867 ret = mixer_resources_init(mixer_ctx);
868 if (ret) {
869 DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
870 return ret;
871 }
872
873 if (mixer_ctx->vp_enabled) {
874 /* acquire vp resources: regs, irqs, clocks */
875 ret = vp_resources_init(mixer_ctx);
876 if (ret) {
877 DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
878 return ret;
879 }
880 }
881
Sean Paulf041b252014-01-30 16:19:15 -0500882 if (!is_drm_iommu_supported(mixer_ctx->drm_dev))
883 return 0;
884
885 return drm_iommu_attach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Sean Paul45517892014-01-30 16:19:05 -0500886}
887
Gustavo Padovan93bca242015-01-18 18:16:23 +0900888static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
Inki Dae1055b392012-10-19 17:37:35 +0900889{
Sean Paulf041b252014-01-30 16:19:15 -0500890 if (is_drm_iommu_supported(mixer_ctx->drm_dev))
891 drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Inki Dae1055b392012-10-19 17:37:35 +0900892}
893
Gustavo Padovan93bca242015-01-18 18:16:23 +0900894static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900895{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900896 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900897 struct mixer_resources *res = &mixer_ctx->mixer_res;
898
Sean Paulf041b252014-01-30 16:19:15 -0500899 if (!mixer_ctx->powered) {
900 mixer_ctx->int_en |= MXR_INT_EN_VSYNC;
901 return 0;
902 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900903
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
Gustavo Padovan93bca242015-01-18 18:16:23 +0900911static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900912{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900913 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900914 struct mixer_resources *res = &mixer_ctx->mixer_res;
915
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900916 /* disable vsync interrupt */
917 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
918}
919
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +0900920static void mixer_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900921{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900922 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900923
YoungJun Chocbc4c332013-06-12 10:44:40 +0900924 DRM_DEBUG_KMS("win: %d\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900925
Shirish Sdda90122013-01-23 22:03:18 -0500926 mutex_lock(&mixer_ctx->mixer_mutex);
927 if (!mixer_ctx->powered) {
928 mutex_unlock(&mixer_ctx->mixer_mutex);
929 return;
930 }
931 mutex_unlock(&mixer_ctx->mixer_mutex);
932
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530933 if (win > 1 && mixer_ctx->vp_enabled)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900934 vp_video_buffer(mixer_ctx, win);
935 else
936 mixer_graph_buffer(mixer_ctx, win);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530937
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900938 mixer_ctx->planes[win].enabled = true;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900939}
940
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +0900941static void mixer_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900942{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900943 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900944 struct mixer_resources *res = &mixer_ctx->mixer_res;
945 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900946
YoungJun Chocbc4c332013-06-12 10:44:40 +0900947 DRM_DEBUG_KMS("win: %d\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900948
Prathyush Kdb43fd12012-12-06 20:16:05 +0530949 mutex_lock(&mixer_ctx->mixer_mutex);
950 if (!mixer_ctx->powered) {
951 mutex_unlock(&mixer_ctx->mixer_mutex);
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900952 mixer_ctx->planes[win].resume = false;
Prathyush Kdb43fd12012-12-06 20:16:05 +0530953 return;
954 }
955 mutex_unlock(&mixer_ctx->mixer_mutex);
956
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900957 spin_lock_irqsave(&res->reg_slock, flags);
958 mixer_vsync_set_update(mixer_ctx, false);
959
960 mixer_cfg_layer(mixer_ctx, win, false);
961
962 mixer_vsync_set_update(mixer_ctx, true);
963 spin_unlock_irqrestore(&res->reg_slock, flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530964
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900965 mixer_ctx->planes[win].enabled = false;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900966}
967
Gustavo Padovan93bca242015-01-18 18:16:23 +0900968static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
Rahul Sharma0ea68222013-01-15 08:11:06 -0500969{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900970 struct mixer_context *mixer_ctx = crtc->ctx;
Joonyoung Shim7c4c5582015-01-18 17:48:29 +0900971 int err;
Prathyush K8137a2e2012-12-06 20:16:01 +0530972
Prathyush K6e95d5e2012-12-06 20:16:03 +0530973 mutex_lock(&mixer_ctx->mixer_mutex);
974 if (!mixer_ctx->powered) {
975 mutex_unlock(&mixer_ctx->mixer_mutex);
976 return;
977 }
978 mutex_unlock(&mixer_ctx->mixer_mutex);
979
Gustavo Padovan93bca242015-01-18 18:16:23 +0900980 err = drm_vblank_get(mixer_ctx->drm_dev, mixer_ctx->pipe);
Joonyoung Shim7c4c5582015-01-18 17:48:29 +0900981 if (err < 0) {
982 DRM_DEBUG_KMS("failed to acquire vblank counter\n");
983 return;
984 }
Rahul Sharma5d39b9e2014-06-23 11:02:25 +0530985
Prathyush K6e95d5e2012-12-06 20:16:03 +0530986 atomic_set(&mixer_ctx->wait_vsync_event, 1);
987
988 /*
989 * wait for MIXER to signal VSYNC interrupt or return after
990 * timeout which is set to 50ms (refresh rate of 20).
991 */
992 if (!wait_event_timeout(mixer_ctx->wait_vsync_queue,
993 !atomic_read(&mixer_ctx->wait_vsync_event),
Daniel Vetterbfd83032013-12-11 11:34:41 +0100994 HZ/20))
Prathyush K8137a2e2012-12-06 20:16:01 +0530995 DRM_DEBUG_KMS("vblank wait timed out.\n");
Rahul Sharma5d39b9e2014-06-23 11:02:25 +0530996
Gustavo Padovan93bca242015-01-18 18:16:23 +0900997 drm_vblank_put(mixer_ctx->drm_dev, mixer_ctx->pipe);
Prathyush K8137a2e2012-12-06 20:16:01 +0530998}
999
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001000static void mixer_window_suspend(struct mixer_context *ctx)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301001{
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001002 struct exynos_drm_plane *plane;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301003 int i;
1004
1005 for (i = 0; i < MIXER_WIN_NR; i++) {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001006 plane = &ctx->planes[i];
1007 plane->resume = plane->enabled;
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001008 mixer_win_disable(ctx->crtc, i);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301009 }
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001010 mixer_wait_for_vblank(ctx->crtc);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301011}
1012
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001013static void mixer_window_resume(struct mixer_context *ctx)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301014{
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001015 struct exynos_drm_plane *plane;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301016 int i;
1017
1018 for (i = 0; i < MIXER_WIN_NR; i++) {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001019 plane = &ctx->planes[i];
1020 plane->enabled = plane->resume;
1021 plane->resume = false;
1022 if (plane->enabled)
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001023 mixer_win_commit(ctx->crtc, i);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301024 }
1025}
1026
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001027static void mixer_poweron(struct mixer_context *ctx)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301028{
1029 struct mixer_resources *res = &ctx->mixer_res;
1030
Prathyush Kdb43fd12012-12-06 20:16:05 +05301031 mutex_lock(&ctx->mixer_mutex);
1032 if (ctx->powered) {
1033 mutex_unlock(&ctx->mixer_mutex);
1034 return;
1035 }
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301036
Prathyush Kdb43fd12012-12-06 20:16:05 +05301037 mutex_unlock(&ctx->mixer_mutex);
1038
Sean Paulaf65c802014-01-30 16:19:27 -05001039 pm_runtime_get_sync(ctx->dev);
1040
Sean Paul0bfb1f82013-06-11 12:24:02 +05301041 clk_prepare_enable(res->mixer);
Marek Szyprowski04427ec2015-02-02 14:20:28 +01001042 clk_prepare_enable(res->hdmi);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301043 if (ctx->vp_enabled) {
Sean Paul0bfb1f82013-06-11 12:24:02 +05301044 clk_prepare_enable(res->vp);
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001045 if (ctx->has_sclk)
1046 clk_prepare_enable(res->sclk_mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301047 }
1048
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301049 mutex_lock(&ctx->mixer_mutex);
1050 ctx->powered = true;
1051 mutex_unlock(&ctx->mixer_mutex);
1052
Rahul Sharmad74ed932014-06-23 11:02:24 +05301053 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
1054
Prathyush Kdb43fd12012-12-06 20:16:05 +05301055 mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
1056 mixer_win_reset(ctx);
1057
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001058 mixer_window_resume(ctx);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301059}
1060
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001061static void mixer_poweroff(struct mixer_context *ctx)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301062{
1063 struct mixer_resources *res = &ctx->mixer_res;
1064
Prathyush Kdb43fd12012-12-06 20:16:05 +05301065 mutex_lock(&ctx->mixer_mutex);
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301066 if (!ctx->powered) {
1067 mutex_unlock(&ctx->mixer_mutex);
1068 return;
1069 }
Prathyush Kdb43fd12012-12-06 20:16:05 +05301070 mutex_unlock(&ctx->mixer_mutex);
1071
Rahul Sharma381be022014-06-23 11:02:22 +05301072 mixer_stop(ctx);
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001073 mixer_window_suspend(ctx);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301074
1075 ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
1076
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301077 mutex_lock(&ctx->mixer_mutex);
1078 ctx->powered = false;
1079 mutex_unlock(&ctx->mixer_mutex);
1080
Marek Szyprowski04427ec2015-02-02 14:20:28 +01001081 clk_disable_unprepare(res->hdmi);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301082 clk_disable_unprepare(res->mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301083 if (ctx->vp_enabled) {
Sean Paul0bfb1f82013-06-11 12:24:02 +05301084 clk_disable_unprepare(res->vp);
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001085 if (ctx->has_sclk)
1086 clk_disable_unprepare(res->sclk_mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301087 }
1088
Sean Paulaf65c802014-01-30 16:19:27 -05001089 pm_runtime_put_sync(ctx->dev);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301090}
1091
Gustavo Padovan93bca242015-01-18 18:16:23 +09001092static void mixer_dpms(struct exynos_drm_crtc *crtc, int mode)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301093{
Prathyush Kdb43fd12012-12-06 20:16:05 +05301094 switch (mode) {
1095 case DRM_MODE_DPMS_ON:
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001096 mixer_poweron(crtc->ctx);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301097 break;
1098 case DRM_MODE_DPMS_STANDBY:
1099 case DRM_MODE_DPMS_SUSPEND:
1100 case DRM_MODE_DPMS_OFF:
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001101 mixer_poweroff(crtc->ctx);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301102 break;
1103 default:
1104 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
1105 break;
1106 }
1107}
1108
Sean Paulf041b252014-01-30 16:19:15 -05001109/* Only valid for Mixer version 16.0.33.0 */
1110int mixer_check_mode(struct drm_display_mode *mode)
1111{
1112 u32 w, h;
1113
1114 w = mode->hdisplay;
1115 h = mode->vdisplay;
1116
1117 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
1118 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1119 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1120
1121 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
1122 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1123 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1124 return 0;
1125
1126 return -EINVAL;
1127}
1128
Gustavo Padovan93bca242015-01-18 18:16:23 +09001129static struct exynos_drm_crtc_ops mixer_crtc_ops = {
Sean Paulf041b252014-01-30 16:19:15 -05001130 .dpms = mixer_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001131 .enable_vblank = mixer_enable_vblank,
1132 .disable_vblank = mixer_disable_vblank,
Prathyush K8137a2e2012-12-06 20:16:01 +05301133 .wait_for_vblank = mixer_wait_for_vblank,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001134 .win_commit = mixer_win_commit,
1135 .win_disable = mixer_win_disable,
Sean Paulf041b252014-01-30 16:19:15 -05001136};
Rahul Sharma0ea68222013-01-15 08:11:06 -05001137
Rahul Sharmadef5e092013-06-19 18:21:08 +05301138static struct mixer_drv_data exynos5420_mxr_drv_data = {
1139 .version = MXR_VER_128_0_0_184,
1140 .is_vp_enabled = 0,
1141};
1142
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301143static struct mixer_drv_data exynos5250_mxr_drv_data = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301144 .version = MXR_VER_16_0_33_0,
1145 .is_vp_enabled = 0,
1146};
1147
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001148static struct mixer_drv_data exynos4212_mxr_drv_data = {
1149 .version = MXR_VER_0_0_0_16,
1150 .is_vp_enabled = 1,
1151};
1152
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301153static struct mixer_drv_data exynos4210_mxr_drv_data = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301154 .version = MXR_VER_0_0_0_16,
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301155 .is_vp_enabled = 1,
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001156 .has_sclk = 1,
Rahul Sharma1e123442012-10-04 20:48:51 +05301157};
1158
1159static struct platform_device_id mixer_driver_types[] = {
1160 {
1161 .name = "s5p-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301162 .driver_data = (unsigned long)&exynos4210_mxr_drv_data,
Rahul Sharma1e123442012-10-04 20:48:51 +05301163 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301164 .name = "exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301165 .driver_data = (unsigned long)&exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301166 }, {
1167 /* end node */
1168 }
1169};
1170
1171static struct of_device_id mixer_match_types[] = {
1172 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001173 .compatible = "samsung,exynos4210-mixer",
1174 .data = &exynos4210_mxr_drv_data,
1175 }, {
1176 .compatible = "samsung,exynos4212-mixer",
1177 .data = &exynos4212_mxr_drv_data,
1178 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301179 .compatible = "samsung,exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301180 .data = &exynos5250_mxr_drv_data,
1181 }, {
1182 .compatible = "samsung,exynos5250-mixer",
1183 .data = &exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301184 }, {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301185 .compatible = "samsung,exynos5420-mixer",
1186 .data = &exynos5420_mxr_drv_data,
1187 }, {
Rahul Sharma1e123442012-10-04 20:48:51 +05301188 /* end node */
1189 }
1190};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001191MODULE_DEVICE_TABLE(of, mixer_match_types);
Rahul Sharma1e123442012-10-04 20:48:51 +05301192
Inki Daef37cd5e2014-05-09 14:25:20 +09001193static int mixer_bind(struct device *dev, struct device *manager, void *data)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001194{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001195 struct mixer_context *ctx = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09001196 struct drm_device *drm_dev = data;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001197 struct exynos_drm_plane *exynos_plane;
1198 enum drm_plane_type type;
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +09001199 unsigned int zpos;
1200 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001201
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001202 ret = mixer_initialize(ctx, drm_dev);
1203 if (ret)
1204 return ret;
1205
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001206 for (zpos = 0; zpos < MIXER_WIN_NR; zpos++) {
1207 type = (zpos == MIXER_DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY :
1208 DRM_PLANE_TYPE_OVERLAY;
1209 ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +09001210 1 << ctx->pipe, type, zpos);
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001211 if (ret)
1212 return ret;
1213 }
1214
1215 exynos_plane = &ctx->planes[MIXER_DEFAULT_WIN];
1216 ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
1217 ctx->pipe, EXYNOS_DISPLAY_TYPE_HDMI,
1218 &mixer_crtc_ops, ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001219 if (IS_ERR(ctx->crtc)) {
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001220 mixer_ctx_remove(ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001221 ret = PTR_ERR(ctx->crtc);
1222 goto free_ctx;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001223 }
1224
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001225 return 0;
Gustavo Padovan93bca242015-01-18 18:16:23 +09001226
1227free_ctx:
1228 devm_kfree(dev, ctx);
1229 return ret;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001230}
1231
1232static void mixer_unbind(struct device *dev, struct device *master, void *data)
1233{
1234 struct mixer_context *ctx = dev_get_drvdata(dev);
1235
Gustavo Padovan93bca242015-01-18 18:16:23 +09001236 mixer_ctx_remove(ctx);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001237}
1238
1239static const struct component_ops mixer_component_ops = {
1240 .bind = mixer_bind,
1241 .unbind = mixer_unbind,
1242};
1243
1244static int mixer_probe(struct platform_device *pdev)
1245{
1246 struct device *dev = &pdev->dev;
1247 struct mixer_drv_data *drv;
1248 struct mixer_context *ctx;
1249 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001250
Sean Paulf041b252014-01-30 16:19:15 -05001251 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1252 if (!ctx) {
1253 DRM_ERROR("failed to alloc mixer context.\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001254 return -ENOMEM;
Sean Paulf041b252014-01-30 16:19:15 -05001255 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001256
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001257 mutex_init(&ctx->mixer_mutex);
1258
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301259 if (dev->of_node) {
1260 const struct of_device_id *match;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001261
Sachin Kamate436b092013-06-05 16:00:23 +09001262 match = of_match_node(mixer_match_types, dev->of_node);
Rahul Sharma2cdc53b2012-10-31 09:36:26 +05301263 drv = (struct mixer_drv_data *)match->data;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301264 } else {
1265 drv = (struct mixer_drv_data *)
1266 platform_get_device_id(pdev)->driver_data;
1267 }
1268
Sean Paul45517892014-01-30 16:19:05 -05001269 ctx->pdev = pdev;
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001270 ctx->dev = dev;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301271 ctx->vp_enabled = drv->is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001272 ctx->has_sclk = drv->has_sclk;
Rahul Sharma1e123442012-10-04 20:48:51 +05301273 ctx->mxr_ver = drv->version;
Daniel Vetter57ed0f72013-12-11 11:34:43 +01001274 init_waitqueue_head(&ctx->wait_vsync_queue);
Prathyush K6e95d5e2012-12-06 20:16:03 +05301275 atomic_set(&ctx->wait_vsync_event, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001276
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001277 platform_set_drvdata(pdev, ctx);
Inki Daedf5225b2014-05-29 18:28:02 +09001278
1279 ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
Gustavo Padovan5d1741a2014-11-05 19:51:35 -02001280 EXYNOS_DISPLAY_TYPE_HDMI);
Inki Daedf5225b2014-05-29 18:28:02 +09001281 if (ret)
1282 return ret;
1283
1284 ret = component_add(&pdev->dev, &mixer_component_ops);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001285 if (ret) {
Inki Daedf5225b2014-05-29 18:28:02 +09001286 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001287 return ret;
1288 }
1289
1290 pm_runtime_enable(dev);
Inki Daedf5225b2014-05-29 18:28:02 +09001291
1292 return ret;
Inki Daef37cd5e2014-05-09 14:25:20 +09001293}
1294
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001295static int mixer_remove(struct platform_device *pdev)
1296{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001297 pm_runtime_disable(&pdev->dev);
1298
Inki Daedf5225b2014-05-29 18:28:02 +09001299 component_del(&pdev->dev, &mixer_component_ops);
1300 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
1301
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001302 return 0;
1303}
1304
1305struct platform_driver mixer_driver = {
1306 .driver = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301307 .name = "exynos-mixer",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001308 .owner = THIS_MODULE,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301309 .of_match_table = mixer_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001310 },
1311 .probe = mixer_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001312 .remove = mixer_remove,
Rahul Sharma1e123442012-10-04 20:48:51 +05301313 .id_table = mixer_driver_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001314};