blob: b7e438fc7fddcd2e04f994a21cf1294d357f9f92 [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
Tobias Jakobi7a57ca72015-04-27 23:11:59 +020047/* The pixelformats that are natively supported by the mixer. */
48#define MXR_FORMAT_RGB565 4
49#define MXR_FORMAT_ARGB1555 5
50#define MXR_FORMAT_ARGB4444 6
51#define MXR_FORMAT_ARGB8888 7
52
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090053struct mixer_resources {
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090054 int irq;
55 void __iomem *mixer_regs;
56 void __iomem *vp_regs;
57 spinlock_t reg_slock;
58 struct clk *mixer;
59 struct clk *vp;
Marek Szyprowski04427ec2015-02-02 14:20:28 +010060 struct clk *hdmi;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090061 struct clk *sclk_mixer;
62 struct clk *sclk_hdmi;
Marek Szyprowskiff830c92014-07-01 10:10:07 +020063 struct clk *mout_mixer;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090064};
65
Rahul Sharma1e123442012-10-04 20:48:51 +053066enum mixer_version_id {
67 MXR_VER_0_0_0_16,
68 MXR_VER_16_0_33_0,
Rahul Sharmadef5e092013-06-19 18:21:08 +053069 MXR_VER_128_0_0_184,
Rahul Sharma1e123442012-10-04 20:48:51 +053070};
71
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090072struct mixer_context {
Sean Paul45517892014-01-30 16:19:05 -050073 struct platform_device *pdev;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090074 struct device *dev;
Inki Dae1055b392012-10-19 17:37:35 +090075 struct drm_device *drm_dev;
Gustavo Padovan93bca242015-01-18 18:16:23 +090076 struct exynos_drm_crtc *crtc;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +090077 struct exynos_drm_plane planes[MIXER_WIN_NR];
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090078 int pipe;
79 bool interlace;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090080 bool powered;
Rahul Sharma1b8e5742012-10-04 20:48:52 +053081 bool vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +020082 bool has_sclk;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090083 u32 int_en;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090084
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090085 struct mutex mixer_mutex;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090086 struct mixer_resources mixer_res;
Rahul Sharma1e123442012-10-04 20:48:51 +053087 enum mixer_version_id mxr_ver;
Prathyush K6e95d5e2012-12-06 20:16:03 +053088 wait_queue_head_t wait_vsync_queue;
89 atomic_t wait_vsync_event;
Rahul Sharma1e123442012-10-04 20:48:51 +053090};
91
92struct mixer_drv_data {
93 enum mixer_version_id version;
Rahul Sharma1b8e5742012-10-04 20:48:52 +053094 bool is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +020095 bool has_sclk;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090096};
97
Seung-Woo Kimd8408322011-12-21 17:39:39 +090098static const u8 filter_y_horiz_tap8[] = {
99 0, -1, -1, -1, -1, -1, -1, -1,
100 -1, -1, -1, -1, -1, 0, 0, 0,
101 0, 2, 4, 5, 6, 6, 6, 6,
102 6, 5, 5, 4, 3, 2, 1, 1,
103 0, -6, -12, -16, -18, -20, -21, -20,
104 -20, -18, -16, -13, -10, -8, -5, -2,
105 127, 126, 125, 121, 114, 107, 99, 89,
106 79, 68, 57, 46, 35, 25, 16, 8,
107};
108
109static const u8 filter_y_vert_tap4[] = {
110 0, -3, -6, -8, -8, -8, -8, -7,
111 -6, -5, -4, -3, -2, -1, -1, 0,
112 127, 126, 124, 118, 111, 102, 92, 81,
113 70, 59, 48, 37, 27, 19, 11, 5,
114 0, 5, 11, 19, 27, 37, 48, 59,
115 70, 81, 92, 102, 111, 118, 124, 126,
116 0, 0, -1, -1, -2, -3, -4, -5,
117 -6, -7, -8, -8, -8, -8, -6, -3,
118};
119
120static const u8 filter_cr_horiz_tap4[] = {
121 0, -3, -6, -8, -8, -8, -8, -7,
122 -6, -5, -4, -3, -2, -1, -1, 0,
123 127, 126, 124, 118, 111, 102, 92, 81,
124 70, 59, 48, 37, 27, 19, 11, 5,
125};
126
127static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
128{
129 return readl(res->vp_regs + reg_id);
130}
131
132static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
133 u32 val)
134{
135 writel(val, res->vp_regs + reg_id);
136}
137
138static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
139 u32 val, u32 mask)
140{
141 u32 old = vp_reg_read(res, reg_id);
142
143 val = (val & mask) | (old & ~mask);
144 writel(val, res->vp_regs + reg_id);
145}
146
147static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
148{
149 return readl(res->mixer_regs + reg_id);
150}
151
152static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
153 u32 val)
154{
155 writel(val, res->mixer_regs + reg_id);
156}
157
158static inline void mixer_reg_writemask(struct mixer_resources *res,
159 u32 reg_id, u32 val, u32 mask)
160{
161 u32 old = mixer_reg_read(res, reg_id);
162
163 val = (val & mask) | (old & ~mask);
164 writel(val, res->mixer_regs + reg_id);
165}
166
167static void mixer_regs_dump(struct mixer_context *ctx)
168{
169#define DUMPREG(reg_id) \
170do { \
171 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
172 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
173} while (0)
174
175 DUMPREG(MXR_STATUS);
176 DUMPREG(MXR_CFG);
177 DUMPREG(MXR_INT_EN);
178 DUMPREG(MXR_INT_STATUS);
179
180 DUMPREG(MXR_LAYER_CFG);
181 DUMPREG(MXR_VIDEO_CFG);
182
183 DUMPREG(MXR_GRAPHIC0_CFG);
184 DUMPREG(MXR_GRAPHIC0_BASE);
185 DUMPREG(MXR_GRAPHIC0_SPAN);
186 DUMPREG(MXR_GRAPHIC0_WH);
187 DUMPREG(MXR_GRAPHIC0_SXY);
188 DUMPREG(MXR_GRAPHIC0_DXY);
189
190 DUMPREG(MXR_GRAPHIC1_CFG);
191 DUMPREG(MXR_GRAPHIC1_BASE);
192 DUMPREG(MXR_GRAPHIC1_SPAN);
193 DUMPREG(MXR_GRAPHIC1_WH);
194 DUMPREG(MXR_GRAPHIC1_SXY);
195 DUMPREG(MXR_GRAPHIC1_DXY);
196#undef DUMPREG
197}
198
199static void vp_regs_dump(struct mixer_context *ctx)
200{
201#define DUMPREG(reg_id) \
202do { \
203 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
204 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
205} while (0)
206
207 DUMPREG(VP_ENABLE);
208 DUMPREG(VP_SRESET);
209 DUMPREG(VP_SHADOW_UPDATE);
210 DUMPREG(VP_FIELD_ID);
211 DUMPREG(VP_MODE);
212 DUMPREG(VP_IMG_SIZE_Y);
213 DUMPREG(VP_IMG_SIZE_C);
214 DUMPREG(VP_PER_RATE_CTRL);
215 DUMPREG(VP_TOP_Y_PTR);
216 DUMPREG(VP_BOT_Y_PTR);
217 DUMPREG(VP_TOP_C_PTR);
218 DUMPREG(VP_BOT_C_PTR);
219 DUMPREG(VP_ENDIAN_MODE);
220 DUMPREG(VP_SRC_H_POSITION);
221 DUMPREG(VP_SRC_V_POSITION);
222 DUMPREG(VP_SRC_WIDTH);
223 DUMPREG(VP_SRC_HEIGHT);
224 DUMPREG(VP_DST_H_POSITION);
225 DUMPREG(VP_DST_V_POSITION);
226 DUMPREG(VP_DST_WIDTH);
227 DUMPREG(VP_DST_HEIGHT);
228 DUMPREG(VP_H_RATIO);
229 DUMPREG(VP_V_RATIO);
230
231#undef DUMPREG
232}
233
234static inline void vp_filter_set(struct mixer_resources *res,
235 int reg_id, const u8 *data, unsigned int size)
236{
237 /* assure 4-byte align */
238 BUG_ON(size & 3);
239 for (; size; size -= 4, reg_id += 4, data += 4) {
240 u32 val = (data[0] << 24) | (data[1] << 16) |
241 (data[2] << 8) | data[3];
242 vp_reg_write(res, reg_id, val);
243 }
244}
245
246static void vp_default_filter(struct mixer_resources *res)
247{
248 vp_filter_set(res, VP_POLY8_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530249 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900250 vp_filter_set(res, VP_POLY4_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530251 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900252 vp_filter_set(res, VP_POLY4_C0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530253 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900254}
255
256static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
257{
258 struct mixer_resources *res = &ctx->mixer_res;
259
260 /* block update on vsync */
261 mixer_reg_writemask(res, MXR_STATUS, enable ?
262 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
263
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530264 if (ctx->vp_enabled)
265 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900266 VP_SHADOW_UPDATE_ENABLE : 0);
267}
268
269static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
270{
271 struct mixer_resources *res = &ctx->mixer_res;
272 u32 val;
273
274 /* choosing between interlace and progressive mode */
275 val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
Tobias Jakobi1e6d4592015-04-07 01:14:50 +0200276 MXR_CFG_SCAN_PROGRESSIVE);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900277
Rahul Sharmadef5e092013-06-19 18:21:08 +0530278 if (ctx->mxr_ver != MXR_VER_128_0_0_184) {
279 /* choosing between proper HD and SD mode */
280 if (height <= 480)
281 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
282 else if (height <= 576)
283 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
284 else if (height <= 720)
285 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
286 else if (height <= 1080)
287 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
288 else
289 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
290 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900291
292 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
293}
294
295static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
296{
297 struct mixer_resources *res = &ctx->mixer_res;
298 u32 val;
299
300 if (height == 480) {
301 val = MXR_CFG_RGB601_0_255;
302 } else if (height == 576) {
303 val = MXR_CFG_RGB601_0_255;
304 } else if (height == 720) {
305 val = MXR_CFG_RGB709_16_235;
306 mixer_reg_write(res, MXR_CM_COEFF_Y,
307 (1 << 30) | (94 << 20) | (314 << 10) |
308 (32 << 0));
309 mixer_reg_write(res, MXR_CM_COEFF_CB,
310 (972 << 20) | (851 << 10) | (225 << 0));
311 mixer_reg_write(res, MXR_CM_COEFF_CR,
312 (225 << 20) | (820 << 10) | (1004 << 0));
313 } else if (height == 1080) {
314 val = MXR_CFG_RGB709_16_235;
315 mixer_reg_write(res, MXR_CM_COEFF_Y,
316 (1 << 30) | (94 << 20) | (314 << 10) |
317 (32 << 0));
318 mixer_reg_write(res, MXR_CM_COEFF_CB,
319 (972 << 20) | (851 << 10) | (225 << 0));
320 mixer_reg_write(res, MXR_CM_COEFF_CR,
321 (225 << 20) | (820 << 10) | (1004 << 0));
322 } else {
323 val = MXR_CFG_RGB709_16_235;
324 mixer_reg_write(res, MXR_CM_COEFF_Y,
325 (1 << 30) | (94 << 20) | (314 << 10) |
326 (32 << 0));
327 mixer_reg_write(res, MXR_CM_COEFF_CB,
328 (972 << 20) | (851 << 10) | (225 << 0));
329 mixer_reg_write(res, MXR_CM_COEFF_CR,
330 (225 << 20) | (820 << 10) | (1004 << 0));
331 }
332
333 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
334}
335
Tobias Jakobi5b1d5bc2015-05-06 14:10:22 +0200336static void mixer_cfg_layer(struct mixer_context *ctx, unsigned int win,
337 bool enable)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900338{
339 struct mixer_resources *res = &ctx->mixer_res;
340 u32 val = enable ? ~0 : 0;
341
342 switch (win) {
343 case 0:
344 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
345 break;
346 case 1:
347 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
348 break;
349 case 2:
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530350 if (ctx->vp_enabled) {
351 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
352 mixer_reg_writemask(res, MXR_CFG, val,
353 MXR_CFG_VP_ENABLE);
Joonyoung Shimf1e716d2014-07-25 19:59:10 +0900354
355 /* control blending of graphic layer 0 */
356 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(0), val,
357 MXR_GRP_CFG_BLEND_PRE_MUL |
358 MXR_GRP_CFG_PIXEL_BLEND_EN);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530359 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900360 break;
361 }
362}
363
364static void mixer_run(struct mixer_context *ctx)
365{
366 struct mixer_resources *res = &ctx->mixer_res;
367
368 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900369}
370
Rahul Sharma381be022014-06-23 11:02:22 +0530371static void mixer_stop(struct mixer_context *ctx)
372{
373 struct mixer_resources *res = &ctx->mixer_res;
374 int timeout = 20;
375
376 mixer_reg_writemask(res, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
377
378 while (!(mixer_reg_read(res, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
379 --timeout)
380 usleep_range(10000, 12000);
Rahul Sharma381be022014-06-23 11:02:22 +0530381}
382
Tobias Jakobi5b1d5bc2015-05-06 14:10:22 +0200383static void vp_video_buffer(struct mixer_context *ctx, unsigned int win)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900384{
385 struct mixer_resources *res = &ctx->mixer_res;
386 unsigned long flags;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900387 struct exynos_drm_plane *plane;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900388 dma_addr_t luma_addr[2], chroma_addr[2];
389 bool tiled_mode = false;
390 bool crcb_mode = false;
391 u32 val;
392
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900393 plane = &ctx->planes[win];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900394
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900395 switch (plane->pixel_format) {
Ville Syrjälä363b06a2012-05-14 11:08:51 +0900396 case DRM_FORMAT_NV12:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900397 crcb_mode = false;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900398 break;
Tobias Jakobi8f2590f2015-04-27 23:10:16 +0200399 case DRM_FORMAT_NV21:
400 crcb_mode = true;
401 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900402 default:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900403 DRM_ERROR("pixel format for vp is wrong [%d].\n",
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900404 plane->pixel_format);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900405 return;
406 }
407
Tobias Jakobifac8a5b2015-04-27 23:10:15 +0200408 luma_addr[0] = plane->dma_addr[0];
409 chroma_addr[0] = plane->dma_addr[1];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900410
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900411 if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900412 ctx->interlace = true;
413 if (tiled_mode) {
414 luma_addr[1] = luma_addr[0] + 0x40;
415 chroma_addr[1] = chroma_addr[0] + 0x40;
416 } else {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900417 luma_addr[1] = luma_addr[0] + plane->pitch;
418 chroma_addr[1] = chroma_addr[0] + plane->pitch;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900419 }
420 } else {
421 ctx->interlace = false;
422 luma_addr[1] = 0;
423 chroma_addr[1] = 0;
424 }
425
426 spin_lock_irqsave(&res->reg_slock, flags);
427 mixer_vsync_set_update(ctx, false);
428
429 /* interlace or progressive scan mode */
430 val = (ctx->interlace ? ~0 : 0);
431 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
432
433 /* setup format */
434 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
435 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
436 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
437
438 /* setting size of input image */
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900439 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(plane->pitch) |
440 VP_IMG_VSIZE(plane->fb_height));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900441 /* chroma height has to reduced by 2 to avoid chroma distorions */
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900442 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(plane->pitch) |
443 VP_IMG_VSIZE(plane->fb_height / 2));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900444
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900445 vp_reg_write(res, VP_SRC_WIDTH, plane->src_width);
446 vp_reg_write(res, VP_SRC_HEIGHT, plane->src_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900447 vp_reg_write(res, VP_SRC_H_POSITION,
Joonyoung Shimcb8a3db2015-04-07 15:59:38 +0900448 VP_SRC_H_POSITION_VAL(plane->src_x));
449 vp_reg_write(res, VP_SRC_V_POSITION, plane->src_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900450
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900451 vp_reg_write(res, VP_DST_WIDTH, plane->crtc_width);
452 vp_reg_write(res, VP_DST_H_POSITION, plane->crtc_x);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900453 if (ctx->interlace) {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900454 vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height / 2);
455 vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y / 2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900456 } else {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900457 vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height);
458 vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900459 }
460
Joonyoung Shim3cabaf72015-04-07 15:59:39 +0900461 vp_reg_write(res, VP_H_RATIO, plane->h_ratio);
462 vp_reg_write(res, VP_V_RATIO, plane->v_ratio);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900463
464 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
465
466 /* set buffer address to vp */
467 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
468 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
469 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
470 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
471
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900472 mixer_cfg_scan(ctx, plane->mode_height);
473 mixer_cfg_rgb_fmt(ctx, plane->mode_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900474 mixer_cfg_layer(ctx, win, true);
475 mixer_run(ctx);
476
477 mixer_vsync_set_update(ctx, true);
478 spin_unlock_irqrestore(&res->reg_slock, flags);
479
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200480 mixer_regs_dump(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900481 vp_regs_dump(ctx);
482}
483
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530484static void mixer_layer_update(struct mixer_context *ctx)
485{
486 struct mixer_resources *res = &ctx->mixer_res;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530487
Rahul Sharma5c0f4822014-06-23 11:02:23 +0530488 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530489}
490
Tobias Jakobi26110152015-04-07 01:14:52 +0200491static int mixer_setup_scale(const struct exynos_drm_plane *plane,
492 unsigned int *x_ratio, unsigned int *y_ratio)
493{
494 if (plane->crtc_width != plane->src_width) {
495 if (plane->crtc_width == 2 * plane->src_width)
496 *x_ratio = 1;
497 else
498 goto fail;
499 }
500
501 if (plane->crtc_height != plane->src_height) {
502 if (plane->crtc_height == 2 * plane->src_height)
503 *y_ratio = 1;
504 else
505 goto fail;
506 }
507
508 return 0;
509
510fail:
511 DRM_DEBUG_KMS("only 2x width/height scaling of plane supported\n");
512 return -ENOTSUPP;
513}
514
Tobias Jakobi5b1d5bc2015-05-06 14:10:22 +0200515static void mixer_graph_buffer(struct mixer_context *ctx, unsigned int win)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900516{
517 struct mixer_resources *res = &ctx->mixer_res;
518 unsigned long flags;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900519 struct exynos_drm_plane *plane;
Tobias Jakobi26110152015-04-07 01:14:52 +0200520 unsigned int x_ratio = 0, y_ratio = 0;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900521 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900522 dma_addr_t dma_addr;
523 unsigned int fmt;
524 u32 val;
525
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900526 plane = &ctx->planes[win];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900527
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200528 switch (plane->pixel_format) {
529 case DRM_FORMAT_XRGB4444:
530 fmt = MXR_FORMAT_ARGB4444;
531 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900532
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200533 case DRM_FORMAT_XRGB1555:
534 fmt = MXR_FORMAT_ARGB1555;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900535 break;
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200536
537 case DRM_FORMAT_RGB565:
538 fmt = MXR_FORMAT_RGB565;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900539 break;
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200540
541 case DRM_FORMAT_XRGB8888:
542 case DRM_FORMAT_ARGB8888:
543 fmt = MXR_FORMAT_ARGB8888;
544 break;
545
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900546 default:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200547 DRM_DEBUG_KMS("pixelformat unsupported by mixer\n");
548 return;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900549 }
550
Tobias Jakobi26110152015-04-07 01:14:52 +0200551 /* check if mixer supports requested scaling setup */
552 if (mixer_setup_scale(plane, &x_ratio, &y_ratio))
553 return;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900554
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900555 dst_x_offset = plane->crtc_x;
556 dst_y_offset = plane->crtc_y;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900557
558 /* converting dma address base and source offset */
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900559 dma_addr = plane->dma_addr[0]
Joonyoung Shimcb8a3db2015-04-07 15:59:38 +0900560 + (plane->src_x * plane->bpp >> 3)
561 + (plane->src_y * plane->pitch);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900562 src_x_offset = 0;
563 src_y_offset = 0;
564
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900565 if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900566 ctx->interlace = true;
567 else
568 ctx->interlace = false;
569
570 spin_lock_irqsave(&res->reg_slock, flags);
571 mixer_vsync_set_update(ctx, false);
572
573 /* setup format */
574 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
575 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
576
577 /* setup geometry */
Daniel Stoneadacb222015-03-17 13:24:58 +0000578 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win),
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900579 plane->pitch / (plane->bpp >> 3));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900580
Rahul Sharmadef5e092013-06-19 18:21:08 +0530581 /* setup display size */
582 if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
583 win == MIXER_DEFAULT_WIN) {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900584 val = MXR_MXR_RES_HEIGHT(plane->mode_height);
585 val |= MXR_MXR_RES_WIDTH(plane->mode_width);
Rahul Sharmadef5e092013-06-19 18:21:08 +0530586 mixer_reg_write(res, MXR_RESOLUTION, val);
587 }
588
Tobias Jakobi26110152015-04-07 01:14:52 +0200589 val = MXR_GRP_WH_WIDTH(plane->src_width);
590 val |= MXR_GRP_WH_HEIGHT(plane->src_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900591 val |= MXR_GRP_WH_H_SCALE(x_ratio);
592 val |= MXR_GRP_WH_V_SCALE(y_ratio);
593 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
594
595 /* setup offsets in source image */
596 val = MXR_GRP_SXY_SX(src_x_offset);
597 val |= MXR_GRP_SXY_SY(src_y_offset);
598 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
599
600 /* setup offsets in display image */
601 val = MXR_GRP_DXY_DX(dst_x_offset);
602 val |= MXR_GRP_DXY_DY(dst_y_offset);
603 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
604
605 /* set buffer address to mixer */
606 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
607
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900608 mixer_cfg_scan(ctx, plane->mode_height);
609 mixer_cfg_rgb_fmt(ctx, plane->mode_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900610 mixer_cfg_layer(ctx, win, true);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530611
612 /* layer update mandatory for mixer 16.0.33.0 */
Rahul Sharmadef5e092013-06-19 18:21:08 +0530613 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
614 ctx->mxr_ver == MXR_VER_128_0_0_184)
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530615 mixer_layer_update(ctx);
616
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900617 mixer_run(ctx);
618
619 mixer_vsync_set_update(ctx, true);
620 spin_unlock_irqrestore(&res->reg_slock, flags);
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200621
622 mixer_regs_dump(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900623}
624
625static void vp_win_reset(struct mixer_context *ctx)
626{
627 struct mixer_resources *res = &ctx->mixer_res;
628 int tries = 100;
629
630 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
631 for (tries = 100; tries; --tries) {
632 /* waiting until VP_SRESET_PROCESSING is 0 */
633 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
634 break;
Sean Paul09760ea2013-01-14 17:03:20 -0500635 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900636 }
637 WARN(tries == 0, "failed to reset Video Processor\n");
638}
639
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900640static void mixer_win_reset(struct mixer_context *ctx)
641{
642 struct mixer_resources *res = &ctx->mixer_res;
643 unsigned long flags;
644 u32 val; /* value stored to register */
645
646 spin_lock_irqsave(&res->reg_slock, flags);
647 mixer_vsync_set_update(ctx, false);
648
649 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
650
651 /* set output in RGB888 mode */
652 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
653
654 /* 16 beat burst in DMA */
655 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
656 MXR_STATUS_BURST_MASK);
657
658 /* setting default layer priority: layer1 > layer0 > video
659 * because typical usage scenario would be
660 * layer1 - OSD
661 * layer0 - framebuffer
662 * video - video overlay
663 */
664 val = MXR_LAYER_CFG_GRP1_VAL(3);
665 val |= MXR_LAYER_CFG_GRP0_VAL(2);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530666 if (ctx->vp_enabled)
667 val |= MXR_LAYER_CFG_VP_VAL(1);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900668 mixer_reg_write(res, MXR_LAYER_CFG, val);
669
670 /* setting background color */
671 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
672 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
673 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
674
675 /* setting graphical layers */
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900676 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
677 val |= MXR_GRP_CFG_WIN_BLEND_EN;
678 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
679
Sean Paul0377f4e2013-04-25 15:13:26 -0400680 /* Don't blend layer 0 onto the mixer background */
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900681 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
Sean Paul0377f4e2013-04-25 15:13:26 -0400682
683 /* Blend layer 1 into layer 0 */
684 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
685 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900686 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
687
Seung-Woo Kim57366032012-05-15 17:22:08 +0900688 /* setting video layers */
689 val = MXR_GRP_CFG_ALPHA_VAL(0);
690 mixer_reg_write(res, MXR_VIDEO_CFG, val);
691
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530692 if (ctx->vp_enabled) {
693 /* configuration of Video Processor Registers */
694 vp_win_reset(ctx);
695 vp_default_filter(res);
696 }
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900697
698 /* disable all layers */
699 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
700 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530701 if (ctx->vp_enabled)
702 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900703
704 mixer_vsync_set_update(ctx, true);
705 spin_unlock_irqrestore(&res->reg_slock, flags);
706}
707
Sean Paul45517892014-01-30 16:19:05 -0500708static irqreturn_t mixer_irq_handler(int irq, void *arg)
709{
710 struct mixer_context *ctx = arg;
711 struct mixer_resources *res = &ctx->mixer_res;
712 u32 val, base, shadow;
713
714 spin_lock(&res->reg_slock);
715
716 /* read interrupt status for handling and clearing flags for VSYNC */
717 val = mixer_reg_read(res, MXR_INT_STATUS);
718
719 /* handling VSYNC */
720 if (val & MXR_INT_STATUS_VSYNC) {
Andrzej Hajda81a464d2015-07-09 10:07:53 +0200721 /* vsync interrupt use different bit for read and clear */
722 val |= MXR_INT_CLEAR_VSYNC;
723 val &= ~MXR_INT_STATUS_VSYNC;
724
Sean Paul45517892014-01-30 16:19:05 -0500725 /* interlace scan need to check shadow register */
726 if (ctx->interlace) {
727 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
728 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
729 if (base != shadow)
730 goto out;
731
732 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
733 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
734 if (base != shadow)
735 goto out;
736 }
737
738 drm_handle_vblank(ctx->drm_dev, ctx->pipe);
739 exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
740
741 /* set wait vsync event to zero and wake up queue. */
742 if (atomic_read(&ctx->wait_vsync_event)) {
743 atomic_set(&ctx->wait_vsync_event, 0);
744 wake_up(&ctx->wait_vsync_queue);
745 }
746 }
747
748out:
749 /* clear interrupts */
Sean Paul45517892014-01-30 16:19:05 -0500750 mixer_reg_write(res, MXR_INT_STATUS, val);
751
752 spin_unlock(&res->reg_slock);
753
754 return IRQ_HANDLED;
755}
756
757static int mixer_resources_init(struct mixer_context *mixer_ctx)
758{
759 struct device *dev = &mixer_ctx->pdev->dev;
760 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
761 struct resource *res;
762 int ret;
763
764 spin_lock_init(&mixer_res->reg_slock);
765
766 mixer_res->mixer = devm_clk_get(dev, "mixer");
767 if (IS_ERR(mixer_res->mixer)) {
768 dev_err(dev, "failed to get clock 'mixer'\n");
769 return -ENODEV;
770 }
771
Marek Szyprowski04427ec2015-02-02 14:20:28 +0100772 mixer_res->hdmi = devm_clk_get(dev, "hdmi");
773 if (IS_ERR(mixer_res->hdmi)) {
774 dev_err(dev, "failed to get clock 'hdmi'\n");
775 return PTR_ERR(mixer_res->hdmi);
776 }
777
Sean Paul45517892014-01-30 16:19:05 -0500778 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
779 if (IS_ERR(mixer_res->sclk_hdmi)) {
780 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
781 return -ENODEV;
782 }
783 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
784 if (res == NULL) {
785 dev_err(dev, "get memory resource failed.\n");
786 return -ENXIO;
787 }
788
789 mixer_res->mixer_regs = devm_ioremap(dev, res->start,
790 resource_size(res));
791 if (mixer_res->mixer_regs == NULL) {
792 dev_err(dev, "register mapping failed.\n");
793 return -ENXIO;
794 }
795
796 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
797 if (res == NULL) {
798 dev_err(dev, "get interrupt resource failed.\n");
799 return -ENXIO;
800 }
801
802 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
803 0, "drm_mixer", mixer_ctx);
804 if (ret) {
805 dev_err(dev, "request interrupt failed.\n");
806 return ret;
807 }
808 mixer_res->irq = res->start;
809
810 return 0;
811}
812
813static int vp_resources_init(struct mixer_context *mixer_ctx)
814{
815 struct device *dev = &mixer_ctx->pdev->dev;
816 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
817 struct resource *res;
818
819 mixer_res->vp = devm_clk_get(dev, "vp");
820 if (IS_ERR(mixer_res->vp)) {
821 dev_err(dev, "failed to get clock 'vp'\n");
822 return -ENODEV;
823 }
Sean Paul45517892014-01-30 16:19:05 -0500824
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200825 if (mixer_ctx->has_sclk) {
826 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
827 if (IS_ERR(mixer_res->sclk_mixer)) {
828 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
829 return -ENODEV;
830 }
831 mixer_res->mout_mixer = devm_clk_get(dev, "mout_mixer");
832 if (IS_ERR(mixer_res->mout_mixer)) {
833 dev_err(dev, "failed to get clock 'mout_mixer'\n");
834 return -ENODEV;
835 }
836
837 if (mixer_res->sclk_hdmi && mixer_res->mout_mixer)
838 clk_set_parent(mixer_res->mout_mixer,
839 mixer_res->sclk_hdmi);
840 }
Sean Paul45517892014-01-30 16:19:05 -0500841
842 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
843 if (res == NULL) {
844 dev_err(dev, "get memory resource failed.\n");
845 return -ENXIO;
846 }
847
848 mixer_res->vp_regs = devm_ioremap(dev, res->start,
849 resource_size(res));
850 if (mixer_res->vp_regs == NULL) {
851 dev_err(dev, "register mapping failed.\n");
852 return -ENXIO;
853 }
854
855 return 0;
856}
857
Gustavo Padovan93bca242015-01-18 18:16:23 +0900858static int mixer_initialize(struct mixer_context *mixer_ctx,
Inki Daef37cd5e2014-05-09 14:25:20 +0900859 struct drm_device *drm_dev)
Sean Paul45517892014-01-30 16:19:05 -0500860{
861 int ret;
Inki Daef37cd5e2014-05-09 14:25:20 +0900862 struct exynos_drm_private *priv;
863 priv = drm_dev->dev_private;
Sean Paul45517892014-01-30 16:19:05 -0500864
Gustavo Padovaneb88e422014-11-26 16:43:27 -0200865 mixer_ctx->drm_dev = drm_dev;
Gustavo Padovan8a326ed2014-11-04 18:44:47 -0200866 mixer_ctx->pipe = priv->pipe++;
Sean Paul45517892014-01-30 16:19:05 -0500867
868 /* acquire resources: regs, irqs, clocks */
869 ret = mixer_resources_init(mixer_ctx);
870 if (ret) {
871 DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
872 return ret;
873 }
874
875 if (mixer_ctx->vp_enabled) {
876 /* acquire vp resources: regs, irqs, clocks */
877 ret = vp_resources_init(mixer_ctx);
878 if (ret) {
879 DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
880 return ret;
881 }
882 }
883
Hyungwon Hwangfc2e0132015-06-22 19:05:04 +0900884 ret = drm_iommu_attach_device_if_possible(mixer_ctx->crtc, drm_dev,
885 mixer_ctx->dev);
886 if (ret)
887 priv->pipe--;
Sean Paulf041b252014-01-30 16:19:15 -0500888
Hyungwon Hwangfc2e0132015-06-22 19:05:04 +0900889 return ret;
Sean Paul45517892014-01-30 16:19:05 -0500890}
891
Gustavo Padovan93bca242015-01-18 18:16:23 +0900892static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
Inki Dae1055b392012-10-19 17:37:35 +0900893{
Joonyoung Shimbf566082015-07-02 21:49:38 +0900894 drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Inki Dae1055b392012-10-19 17:37:35 +0900895}
896
Gustavo Padovan93bca242015-01-18 18:16:23 +0900897static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900898{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900899 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900900 struct mixer_resources *res = &mixer_ctx->mixer_res;
901
Sean Paulf041b252014-01-30 16:19:15 -0500902 if (!mixer_ctx->powered) {
903 mixer_ctx->int_en |= MXR_INT_EN_VSYNC;
904 return 0;
905 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900906
907 /* enable vsync interrupt */
Andrzej Hajdafc0732482015-07-09 08:25:40 +0200908 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
909 mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900910
911 return 0;
912}
913
Gustavo Padovan93bca242015-01-18 18:16:23 +0900914static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900915{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900916 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900917 struct mixer_resources *res = &mixer_ctx->mixer_res;
918
Andrzej Hajda947710c2015-07-09 08:25:41 +0200919 if (!mixer_ctx->powered) {
920 mixer_ctx->int_en &= MXR_INT_EN_VSYNC;
921 return;
922 }
923
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900924 /* disable vsync interrupt */
Andrzej Hajdafc0732482015-07-09 08:25:40 +0200925 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900926 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
927}
928
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +0900929static void mixer_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900930{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900931 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900932
YoungJun Chocbc4c332013-06-12 10:44:40 +0900933 DRM_DEBUG_KMS("win: %d\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900934
Shirish Sdda90122013-01-23 22:03:18 -0500935 mutex_lock(&mixer_ctx->mixer_mutex);
936 if (!mixer_ctx->powered) {
937 mutex_unlock(&mixer_ctx->mixer_mutex);
938 return;
939 }
940 mutex_unlock(&mixer_ctx->mixer_mutex);
941
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530942 if (win > 1 && mixer_ctx->vp_enabled)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900943 vp_video_buffer(mixer_ctx, win);
944 else
945 mixer_graph_buffer(mixer_ctx, win);
946}
947
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +0900948static void mixer_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900949{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900950 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900951 struct mixer_resources *res = &mixer_ctx->mixer_res;
952 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900953
YoungJun Chocbc4c332013-06-12 10:44:40 +0900954 DRM_DEBUG_KMS("win: %d\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900955
Prathyush Kdb43fd12012-12-06 20:16:05 +0530956 mutex_lock(&mixer_ctx->mixer_mutex);
957 if (!mixer_ctx->powered) {
958 mutex_unlock(&mixer_ctx->mixer_mutex);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530959 return;
960 }
961 mutex_unlock(&mixer_ctx->mixer_mutex);
962
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900963 spin_lock_irqsave(&res->reg_slock, flags);
964 mixer_vsync_set_update(mixer_ctx, false);
965
966 mixer_cfg_layer(mixer_ctx, win, false);
967
968 mixer_vsync_set_update(mixer_ctx, true);
969 spin_unlock_irqrestore(&res->reg_slock, flags);
970}
971
Gustavo Padovan93bca242015-01-18 18:16:23 +0900972static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
Rahul Sharma0ea68222013-01-15 08:11:06 -0500973{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900974 struct mixer_context *mixer_ctx = crtc->ctx;
Joonyoung Shim7c4c5582015-01-18 17:48:29 +0900975 int err;
Prathyush K8137a2e2012-12-06 20:16:01 +0530976
Prathyush K6e95d5e2012-12-06 20:16:03 +0530977 mutex_lock(&mixer_ctx->mixer_mutex);
978 if (!mixer_ctx->powered) {
979 mutex_unlock(&mixer_ctx->mixer_mutex);
980 return;
981 }
982 mutex_unlock(&mixer_ctx->mixer_mutex);
983
Gustavo Padovan93bca242015-01-18 18:16:23 +0900984 err = drm_vblank_get(mixer_ctx->drm_dev, mixer_ctx->pipe);
Joonyoung Shim7c4c5582015-01-18 17:48:29 +0900985 if (err < 0) {
986 DRM_DEBUG_KMS("failed to acquire vblank counter\n");
987 return;
988 }
Rahul Sharma5d39b9e2014-06-23 11:02:25 +0530989
Prathyush K6e95d5e2012-12-06 20:16:03 +0530990 atomic_set(&mixer_ctx->wait_vsync_event, 1);
991
992 /*
993 * wait for MIXER to signal VSYNC interrupt or return after
994 * timeout which is set to 50ms (refresh rate of 20).
995 */
996 if (!wait_event_timeout(mixer_ctx->wait_vsync_queue,
997 !atomic_read(&mixer_ctx->wait_vsync_event),
Daniel Vetterbfd83032013-12-11 11:34:41 +0100998 HZ/20))
Prathyush K8137a2e2012-12-06 20:16:01 +0530999 DRM_DEBUG_KMS("vblank wait timed out.\n");
Rahul Sharma5d39b9e2014-06-23 11:02:25 +05301000
Gustavo Padovan93bca242015-01-18 18:16:23 +09001001 drm_vblank_put(mixer_ctx->drm_dev, mixer_ctx->pipe);
Prathyush K8137a2e2012-12-06 20:16:01 +05301002}
1003
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001004static void mixer_enable(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301005{
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001006 struct mixer_context *ctx = crtc->ctx;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301007 struct mixer_resources *res = &ctx->mixer_res;
Gustavo Padovan38000db2015-06-03 17:17:16 -03001008 int ret;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301009
Prathyush Kdb43fd12012-12-06 20:16:05 +05301010 mutex_lock(&ctx->mixer_mutex);
1011 if (ctx->powered) {
1012 mutex_unlock(&ctx->mixer_mutex);
1013 return;
1014 }
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301015
Prathyush Kdb43fd12012-12-06 20:16:05 +05301016 mutex_unlock(&ctx->mixer_mutex);
1017
Sean Paulaf65c802014-01-30 16:19:27 -05001018 pm_runtime_get_sync(ctx->dev);
1019
Gustavo Padovan38000db2015-06-03 17:17:16 -03001020 ret = clk_prepare_enable(res->mixer);
1021 if (ret < 0) {
1022 DRM_ERROR("Failed to prepare_enable the mixer clk [%d]\n", ret);
1023 return;
1024 }
1025 ret = clk_prepare_enable(res->hdmi);
1026 if (ret < 0) {
1027 DRM_ERROR("Failed to prepare_enable the hdmi clk [%d]\n", ret);
1028 return;
1029 }
Prathyush Kdb43fd12012-12-06 20:16:05 +05301030 if (ctx->vp_enabled) {
Gustavo Padovan38000db2015-06-03 17:17:16 -03001031 ret = clk_prepare_enable(res->vp);
1032 if (ret < 0) {
1033 DRM_ERROR("Failed to prepare_enable the vp clk [%d]\n",
1034 ret);
1035 return;
1036 }
1037 if (ctx->has_sclk) {
1038 ret = clk_prepare_enable(res->sclk_mixer);
1039 if (ret < 0) {
1040 DRM_ERROR("Failed to prepare_enable the " \
1041 "sclk_mixer clk [%d]\n",
1042 ret);
1043 return;
1044 }
1045 }
Prathyush Kdb43fd12012-12-06 20:16:05 +05301046 }
1047
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301048 mutex_lock(&ctx->mixer_mutex);
1049 ctx->powered = true;
1050 mutex_unlock(&ctx->mixer_mutex);
1051
Rahul Sharmad74ed932014-06-23 11:02:24 +05301052 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
1053
Andrzej Hajdafc0732482015-07-09 08:25:40 +02001054 if (ctx->int_en & MXR_INT_EN_VSYNC)
1055 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301056 mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
1057 mixer_win_reset(ctx);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301058}
1059
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001060static void mixer_disable(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301061{
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001062 struct mixer_context *ctx = crtc->ctx;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301063 struct mixer_resources *res = &ctx->mixer_res;
Joonyoung Shimc329f662015-06-12 20:34:28 +09001064 int i;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301065
Prathyush Kdb43fd12012-12-06 20:16:05 +05301066 mutex_lock(&ctx->mixer_mutex);
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301067 if (!ctx->powered) {
1068 mutex_unlock(&ctx->mixer_mutex);
1069 return;
1070 }
Prathyush Kdb43fd12012-12-06 20:16:05 +05301071 mutex_unlock(&ctx->mixer_mutex);
1072
Rahul Sharma381be022014-06-23 11:02:22 +05301073 mixer_stop(ctx);
Tobias Jakobic0734fb2015-05-06 14:10:21 +02001074 mixer_regs_dump(ctx);
Joonyoung Shimc329f662015-06-12 20:34:28 +09001075
1076 for (i = 0; i < MIXER_WIN_NR; i++)
1077 mixer_win_disable(crtc, i);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301078
1079 ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
1080
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301081 mutex_lock(&ctx->mixer_mutex);
1082 ctx->powered = false;
1083 mutex_unlock(&ctx->mixer_mutex);
1084
Marek Szyprowski04427ec2015-02-02 14:20:28 +01001085 clk_disable_unprepare(res->hdmi);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301086 clk_disable_unprepare(res->mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301087 if (ctx->vp_enabled) {
Sean Paul0bfb1f82013-06-11 12:24:02 +05301088 clk_disable_unprepare(res->vp);
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001089 if (ctx->has_sclk)
1090 clk_disable_unprepare(res->sclk_mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301091 }
1092
Sean Paulaf65c802014-01-30 16:19:27 -05001093 pm_runtime_put_sync(ctx->dev);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301094}
1095
Sean Paulf041b252014-01-30 16:19:15 -05001096/* Only valid for Mixer version 16.0.33.0 */
1097int mixer_check_mode(struct drm_display_mode *mode)
1098{
1099 u32 w, h;
1100
1101 w = mode->hdisplay;
1102 h = mode->vdisplay;
1103
1104 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
1105 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1106 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1107
1108 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
1109 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1110 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1111 return 0;
1112
1113 return -EINVAL;
1114}
1115
Krzysztof Kozlowskif3aaf762015-05-07 09:04:45 +09001116static const struct exynos_drm_crtc_ops mixer_crtc_ops = {
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001117 .enable = mixer_enable,
1118 .disable = mixer_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001119 .enable_vblank = mixer_enable_vblank,
1120 .disable_vblank = mixer_disable_vblank,
Prathyush K8137a2e2012-12-06 20:16:01 +05301121 .wait_for_vblank = mixer_wait_for_vblank,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001122 .win_commit = mixer_win_commit,
1123 .win_disable = mixer_win_disable,
Sean Paulf041b252014-01-30 16:19:15 -05001124};
Rahul Sharma0ea68222013-01-15 08:11:06 -05001125
Rahul Sharmadef5e092013-06-19 18:21:08 +05301126static struct mixer_drv_data exynos5420_mxr_drv_data = {
1127 .version = MXR_VER_128_0_0_184,
1128 .is_vp_enabled = 0,
1129};
1130
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301131static struct mixer_drv_data exynos5250_mxr_drv_data = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301132 .version = MXR_VER_16_0_33_0,
1133 .is_vp_enabled = 0,
1134};
1135
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001136static struct mixer_drv_data exynos4212_mxr_drv_data = {
1137 .version = MXR_VER_0_0_0_16,
1138 .is_vp_enabled = 1,
1139};
1140
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301141static struct mixer_drv_data exynos4210_mxr_drv_data = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301142 .version = MXR_VER_0_0_0_16,
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301143 .is_vp_enabled = 1,
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001144 .has_sclk = 1,
Rahul Sharma1e123442012-10-04 20:48:51 +05301145};
1146
Krzysztof Kozlowskid6b16302015-05-02 00:56:36 +09001147static const struct platform_device_id mixer_driver_types[] = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301148 {
1149 .name = "s5p-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301150 .driver_data = (unsigned long)&exynos4210_mxr_drv_data,
Rahul Sharma1e123442012-10-04 20:48:51 +05301151 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301152 .name = "exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301153 .driver_data = (unsigned long)&exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301154 }, {
1155 /* end node */
1156 }
1157};
1158
1159static struct of_device_id mixer_match_types[] = {
1160 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001161 .compatible = "samsung,exynos4210-mixer",
1162 .data = &exynos4210_mxr_drv_data,
1163 }, {
1164 .compatible = "samsung,exynos4212-mixer",
1165 .data = &exynos4212_mxr_drv_data,
1166 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301167 .compatible = "samsung,exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301168 .data = &exynos5250_mxr_drv_data,
1169 }, {
1170 .compatible = "samsung,exynos5250-mixer",
1171 .data = &exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301172 }, {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301173 .compatible = "samsung,exynos5420-mixer",
1174 .data = &exynos5420_mxr_drv_data,
1175 }, {
Rahul Sharma1e123442012-10-04 20:48:51 +05301176 /* end node */
1177 }
1178};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001179MODULE_DEVICE_TABLE(of, mixer_match_types);
Rahul Sharma1e123442012-10-04 20:48:51 +05301180
Inki Daef37cd5e2014-05-09 14:25:20 +09001181static int mixer_bind(struct device *dev, struct device *manager, void *data)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001182{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001183 struct mixer_context *ctx = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09001184 struct drm_device *drm_dev = data;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001185 struct exynos_drm_plane *exynos_plane;
1186 enum drm_plane_type type;
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +09001187 unsigned int zpos;
1188 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001189
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001190 ret = mixer_initialize(ctx, drm_dev);
1191 if (ret)
1192 return ret;
1193
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001194 for (zpos = 0; zpos < MIXER_WIN_NR; zpos++) {
1195 type = (zpos == MIXER_DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY :
1196 DRM_PLANE_TYPE_OVERLAY;
1197 ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +09001198 1 << ctx->pipe, type, zpos);
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001199 if (ret)
1200 return ret;
1201 }
1202
1203 exynos_plane = &ctx->planes[MIXER_DEFAULT_WIN];
1204 ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
1205 ctx->pipe, EXYNOS_DISPLAY_TYPE_HDMI,
1206 &mixer_crtc_ops, ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001207 if (IS_ERR(ctx->crtc)) {
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001208 mixer_ctx_remove(ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001209 ret = PTR_ERR(ctx->crtc);
1210 goto free_ctx;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001211 }
1212
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001213 return 0;
Gustavo Padovan93bca242015-01-18 18:16:23 +09001214
1215free_ctx:
1216 devm_kfree(dev, ctx);
1217 return ret;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001218}
1219
1220static void mixer_unbind(struct device *dev, struct device *master, void *data)
1221{
1222 struct mixer_context *ctx = dev_get_drvdata(dev);
1223
Gustavo Padovan93bca242015-01-18 18:16:23 +09001224 mixer_ctx_remove(ctx);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001225}
1226
1227static const struct component_ops mixer_component_ops = {
1228 .bind = mixer_bind,
1229 .unbind = mixer_unbind,
1230};
1231
1232static int mixer_probe(struct platform_device *pdev)
1233{
1234 struct device *dev = &pdev->dev;
1235 struct mixer_drv_data *drv;
1236 struct mixer_context *ctx;
1237 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001238
Sean Paulf041b252014-01-30 16:19:15 -05001239 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1240 if (!ctx) {
1241 DRM_ERROR("failed to alloc mixer context.\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001242 return -ENOMEM;
Sean Paulf041b252014-01-30 16:19:15 -05001243 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001244
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001245 mutex_init(&ctx->mixer_mutex);
1246
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301247 if (dev->of_node) {
1248 const struct of_device_id *match;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001249
Sachin Kamate436b092013-06-05 16:00:23 +09001250 match = of_match_node(mixer_match_types, dev->of_node);
Rahul Sharma2cdc53b2012-10-31 09:36:26 +05301251 drv = (struct mixer_drv_data *)match->data;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301252 } else {
1253 drv = (struct mixer_drv_data *)
1254 platform_get_device_id(pdev)->driver_data;
1255 }
1256
Sean Paul45517892014-01-30 16:19:05 -05001257 ctx->pdev = pdev;
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001258 ctx->dev = dev;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301259 ctx->vp_enabled = drv->is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001260 ctx->has_sclk = drv->has_sclk;
Rahul Sharma1e123442012-10-04 20:48:51 +05301261 ctx->mxr_ver = drv->version;
Daniel Vetter57ed0f72013-12-11 11:34:43 +01001262 init_waitqueue_head(&ctx->wait_vsync_queue);
Prathyush K6e95d5e2012-12-06 20:16:03 +05301263 atomic_set(&ctx->wait_vsync_event, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001264
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001265 platform_set_drvdata(pdev, ctx);
Inki Daedf5225b2014-05-29 18:28:02 +09001266
Inki Daedf5225b2014-05-29 18:28:02 +09001267 ret = component_add(&pdev->dev, &mixer_component_ops);
Andrzej Hajda86650402015-06-11 23:23:37 +09001268 if (!ret)
1269 pm_runtime_enable(dev);
Inki Daedf5225b2014-05-29 18:28:02 +09001270
1271 return ret;
Inki Daef37cd5e2014-05-09 14:25:20 +09001272}
1273
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001274static int mixer_remove(struct platform_device *pdev)
1275{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001276 pm_runtime_disable(&pdev->dev);
1277
Inki Daedf5225b2014-05-29 18:28:02 +09001278 component_del(&pdev->dev, &mixer_component_ops);
Inki Daedf5225b2014-05-29 18:28:02 +09001279
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001280 return 0;
1281}
1282
1283struct platform_driver mixer_driver = {
1284 .driver = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301285 .name = "exynos-mixer",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001286 .owner = THIS_MODULE,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301287 .of_match_table = mixer_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001288 },
1289 .probe = mixer_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001290 .remove = mixer_remove,
Rahul Sharma1e123442012-10-04 20:48:51 +05301291 .id_table = mixer_driver_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001292};