blob: f6cb1205a2fd56b235afbc3a186f96af56e77301 [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>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090034
35#include <drm/exynos_drm.h>
36
37#include "exynos_drm_drv.h"
Rahul Sharma663d8762013-01-03 05:44:04 -050038#include "exynos_drm_crtc.h"
Seung-Woo Kimd8408322011-12-21 17:39:39 +090039#include "exynos_drm_hdmi.h"
Inki Dae1055b392012-10-19 17:37:35 +090040#include "exynos_drm_iommu.h"
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090041
Seung-Woo Kimd8408322011-12-21 17:39:39 +090042#define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev))
43
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090044struct hdmi_win_data {
45 dma_addr_t dma_addr;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090046 dma_addr_t chroma_dma_addr;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090047 uint32_t pixel_format;
48 unsigned int bpp;
49 unsigned int crtc_x;
50 unsigned int crtc_y;
51 unsigned int crtc_width;
52 unsigned int crtc_height;
53 unsigned int fb_x;
54 unsigned int fb_y;
55 unsigned int fb_width;
56 unsigned int fb_height;
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +090057 unsigned int src_width;
58 unsigned int src_height;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090059 unsigned int mode_width;
60 unsigned int mode_height;
61 unsigned int scan_flags;
Prathyush Kdb43fd12012-12-06 20:16:05 +053062 bool enabled;
63 bool resume;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090064};
65
66struct mixer_resources {
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090067 int irq;
68 void __iomem *mixer_regs;
69 void __iomem *vp_regs;
70 spinlock_t reg_slock;
71 struct clk *mixer;
72 struct clk *vp;
73 struct clk *sclk_mixer;
74 struct clk *sclk_hdmi;
75 struct clk *sclk_dac;
76};
77
Rahul Sharma1e123442012-10-04 20:48:51 +053078enum mixer_version_id {
79 MXR_VER_0_0_0_16,
80 MXR_VER_16_0_33_0,
Rahul Sharmadef5e092013-06-19 18:21:08 +053081 MXR_VER_128_0_0_184,
Rahul Sharma1e123442012-10-04 20:48:51 +053082};
83
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090084struct mixer_context {
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090085 struct device *dev;
Inki Dae1055b392012-10-19 17:37:35 +090086 struct drm_device *drm_dev;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090087 int pipe;
88 bool interlace;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090089 bool powered;
Rahul Sharma1b8e5742012-10-04 20:48:52 +053090 bool vp_enabled;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090091 u32 int_en;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090092
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090093 struct mutex mixer_mutex;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090094 struct mixer_resources mixer_res;
Joonyoung Shima634dd52012-04-05 20:49:24 +090095 struct hdmi_win_data win_data[MIXER_WIN_NR];
Rahul Sharma1e123442012-10-04 20:48:51 +053096 enum mixer_version_id mxr_ver;
Inki Dae1055b392012-10-19 17:37:35 +090097 void *parent_ctx;
Prathyush K6e95d5e2012-12-06 20:16:03 +053098 wait_queue_head_t wait_vsync_queue;
99 atomic_t wait_vsync_event;
Rahul Sharma1e123442012-10-04 20:48:51 +0530100};
101
102struct mixer_drv_data {
103 enum mixer_version_id version;
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530104 bool is_vp_enabled;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +0900105};
106
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900107static const u8 filter_y_horiz_tap8[] = {
108 0, -1, -1, -1, -1, -1, -1, -1,
109 -1, -1, -1, -1, -1, 0, 0, 0,
110 0, 2, 4, 5, 6, 6, 6, 6,
111 6, 5, 5, 4, 3, 2, 1, 1,
112 0, -6, -12, -16, -18, -20, -21, -20,
113 -20, -18, -16, -13, -10, -8, -5, -2,
114 127, 126, 125, 121, 114, 107, 99, 89,
115 79, 68, 57, 46, 35, 25, 16, 8,
116};
117
118static const u8 filter_y_vert_tap4[] = {
119 0, -3, -6, -8, -8, -8, -8, -7,
120 -6, -5, -4, -3, -2, -1, -1, 0,
121 127, 126, 124, 118, 111, 102, 92, 81,
122 70, 59, 48, 37, 27, 19, 11, 5,
123 0, 5, 11, 19, 27, 37, 48, 59,
124 70, 81, 92, 102, 111, 118, 124, 126,
125 0, 0, -1, -1, -2, -3, -4, -5,
126 -6, -7, -8, -8, -8, -8, -6, -3,
127};
128
129static const u8 filter_cr_horiz_tap4[] = {
130 0, -3, -6, -8, -8, -8, -8, -7,
131 -6, -5, -4, -3, -2, -1, -1, 0,
132 127, 126, 124, 118, 111, 102, 92, 81,
133 70, 59, 48, 37, 27, 19, 11, 5,
134};
135
136static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
137{
138 return readl(res->vp_regs + reg_id);
139}
140
141static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
142 u32 val)
143{
144 writel(val, res->vp_regs + reg_id);
145}
146
147static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
148 u32 val, u32 mask)
149{
150 u32 old = vp_reg_read(res, reg_id);
151
152 val = (val & mask) | (old & ~mask);
153 writel(val, res->vp_regs + reg_id);
154}
155
156static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
157{
158 return readl(res->mixer_regs + reg_id);
159}
160
161static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
162 u32 val)
163{
164 writel(val, res->mixer_regs + reg_id);
165}
166
167static inline void mixer_reg_writemask(struct mixer_resources *res,
168 u32 reg_id, u32 val, u32 mask)
169{
170 u32 old = mixer_reg_read(res, reg_id);
171
172 val = (val & mask) | (old & ~mask);
173 writel(val, res->mixer_regs + reg_id);
174}
175
176static void mixer_regs_dump(struct mixer_context *ctx)
177{
178#define DUMPREG(reg_id) \
179do { \
180 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
181 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
182} while (0)
183
184 DUMPREG(MXR_STATUS);
185 DUMPREG(MXR_CFG);
186 DUMPREG(MXR_INT_EN);
187 DUMPREG(MXR_INT_STATUS);
188
189 DUMPREG(MXR_LAYER_CFG);
190 DUMPREG(MXR_VIDEO_CFG);
191
192 DUMPREG(MXR_GRAPHIC0_CFG);
193 DUMPREG(MXR_GRAPHIC0_BASE);
194 DUMPREG(MXR_GRAPHIC0_SPAN);
195 DUMPREG(MXR_GRAPHIC0_WH);
196 DUMPREG(MXR_GRAPHIC0_SXY);
197 DUMPREG(MXR_GRAPHIC0_DXY);
198
199 DUMPREG(MXR_GRAPHIC1_CFG);
200 DUMPREG(MXR_GRAPHIC1_BASE);
201 DUMPREG(MXR_GRAPHIC1_SPAN);
202 DUMPREG(MXR_GRAPHIC1_WH);
203 DUMPREG(MXR_GRAPHIC1_SXY);
204 DUMPREG(MXR_GRAPHIC1_DXY);
205#undef DUMPREG
206}
207
208static void vp_regs_dump(struct mixer_context *ctx)
209{
210#define DUMPREG(reg_id) \
211do { \
212 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
213 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
214} while (0)
215
216 DUMPREG(VP_ENABLE);
217 DUMPREG(VP_SRESET);
218 DUMPREG(VP_SHADOW_UPDATE);
219 DUMPREG(VP_FIELD_ID);
220 DUMPREG(VP_MODE);
221 DUMPREG(VP_IMG_SIZE_Y);
222 DUMPREG(VP_IMG_SIZE_C);
223 DUMPREG(VP_PER_RATE_CTRL);
224 DUMPREG(VP_TOP_Y_PTR);
225 DUMPREG(VP_BOT_Y_PTR);
226 DUMPREG(VP_TOP_C_PTR);
227 DUMPREG(VP_BOT_C_PTR);
228 DUMPREG(VP_ENDIAN_MODE);
229 DUMPREG(VP_SRC_H_POSITION);
230 DUMPREG(VP_SRC_V_POSITION);
231 DUMPREG(VP_SRC_WIDTH);
232 DUMPREG(VP_SRC_HEIGHT);
233 DUMPREG(VP_DST_H_POSITION);
234 DUMPREG(VP_DST_V_POSITION);
235 DUMPREG(VP_DST_WIDTH);
236 DUMPREG(VP_DST_HEIGHT);
237 DUMPREG(VP_H_RATIO);
238 DUMPREG(VP_V_RATIO);
239
240#undef DUMPREG
241}
242
243static inline void vp_filter_set(struct mixer_resources *res,
244 int reg_id, const u8 *data, unsigned int size)
245{
246 /* assure 4-byte align */
247 BUG_ON(size & 3);
248 for (; size; size -= 4, reg_id += 4, data += 4) {
249 u32 val = (data[0] << 24) | (data[1] << 16) |
250 (data[2] << 8) | data[3];
251 vp_reg_write(res, reg_id, val);
252 }
253}
254
255static void vp_default_filter(struct mixer_resources *res)
256{
257 vp_filter_set(res, VP_POLY8_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530258 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900259 vp_filter_set(res, VP_POLY4_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530260 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900261 vp_filter_set(res, VP_POLY4_C0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530262 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900263}
264
265static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
266{
267 struct mixer_resources *res = &ctx->mixer_res;
268
269 /* block update on vsync */
270 mixer_reg_writemask(res, MXR_STATUS, enable ?
271 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
272
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530273 if (ctx->vp_enabled)
274 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900275 VP_SHADOW_UPDATE_ENABLE : 0);
276}
277
278static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
279{
280 struct mixer_resources *res = &ctx->mixer_res;
281 u32 val;
282
283 /* choosing between interlace and progressive mode */
284 val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
285 MXR_CFG_SCAN_PROGRASSIVE);
286
Rahul Sharmadef5e092013-06-19 18:21:08 +0530287 if (ctx->mxr_ver != MXR_VER_128_0_0_184) {
288 /* choosing between proper HD and SD mode */
289 if (height <= 480)
290 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
291 else if (height <= 576)
292 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
293 else if (height <= 720)
294 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
295 else if (height <= 1080)
296 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
297 else
298 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
299 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900300
301 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
302}
303
304static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
305{
306 struct mixer_resources *res = &ctx->mixer_res;
307 u32 val;
308
309 if (height == 480) {
310 val = MXR_CFG_RGB601_0_255;
311 } else if (height == 576) {
312 val = MXR_CFG_RGB601_0_255;
313 } else if (height == 720) {
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 if (height == 1080) {
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 } else {
332 val = MXR_CFG_RGB709_16_235;
333 mixer_reg_write(res, MXR_CM_COEFF_Y,
334 (1 << 30) | (94 << 20) | (314 << 10) |
335 (32 << 0));
336 mixer_reg_write(res, MXR_CM_COEFF_CB,
337 (972 << 20) | (851 << 10) | (225 << 0));
338 mixer_reg_write(res, MXR_CM_COEFF_CR,
339 (225 << 20) | (820 << 10) | (1004 << 0));
340 }
341
342 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
343}
344
345static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable)
346{
347 struct mixer_resources *res = &ctx->mixer_res;
348 u32 val = enable ? ~0 : 0;
349
350 switch (win) {
351 case 0:
352 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
353 break;
354 case 1:
355 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
356 break;
357 case 2:
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530358 if (ctx->vp_enabled) {
359 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
360 mixer_reg_writemask(res, MXR_CFG, val,
361 MXR_CFG_VP_ENABLE);
362 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900363 break;
364 }
365}
366
367static void mixer_run(struct mixer_context *ctx)
368{
369 struct mixer_resources *res = &ctx->mixer_res;
370
371 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
372
373 mixer_regs_dump(ctx);
374}
375
376static void vp_video_buffer(struct mixer_context *ctx, int win)
377{
378 struct mixer_resources *res = &ctx->mixer_res;
379 unsigned long flags;
380 struct hdmi_win_data *win_data;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900381 unsigned int x_ratio, y_ratio;
YoungJun Cho782953e2013-07-01 13:04:12 +0900382 unsigned int buf_num = 1;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900383 dma_addr_t luma_addr[2], chroma_addr[2];
384 bool tiled_mode = false;
385 bool crcb_mode = false;
386 u32 val;
387
388 win_data = &ctx->win_data[win];
389
390 switch (win_data->pixel_format) {
391 case DRM_FORMAT_NV12MT:
392 tiled_mode = true;
Ville Syrjälä363b06a2012-05-14 11:08:51 +0900393 case DRM_FORMAT_NV12:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900394 crcb_mode = false;
395 buf_num = 2;
396 break;
397 /* TODO: single buffer format NV12, NV21 */
398 default:
399 /* ignore pixel format at disable time */
400 if (!win_data->dma_addr)
401 break;
402
403 DRM_ERROR("pixel format for vp is wrong [%d].\n",
404 win_data->pixel_format);
405 return;
406 }
407
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900408 /* scaling feature: (src << 16) / dst */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900409 x_ratio = (win_data->src_width << 16) / win_data->crtc_width;
410 y_ratio = (win_data->src_height << 16) / win_data->crtc_height;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900411
412 if (buf_num == 2) {
413 luma_addr[0] = win_data->dma_addr;
414 chroma_addr[0] = win_data->chroma_dma_addr;
415 } else {
416 luma_addr[0] = win_data->dma_addr;
417 chroma_addr[0] = win_data->dma_addr
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900418 + (win_data->fb_width * win_data->fb_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900419 }
420
421 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) {
422 ctx->interlace = true;
423 if (tiled_mode) {
424 luma_addr[1] = luma_addr[0] + 0x40;
425 chroma_addr[1] = chroma_addr[0] + 0x40;
426 } else {
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900427 luma_addr[1] = luma_addr[0] + win_data->fb_width;
428 chroma_addr[1] = chroma_addr[0] + win_data->fb_width;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900429 }
430 } else {
431 ctx->interlace = false;
432 luma_addr[1] = 0;
433 chroma_addr[1] = 0;
434 }
435
436 spin_lock_irqsave(&res->reg_slock, flags);
437 mixer_vsync_set_update(ctx, false);
438
439 /* interlace or progressive scan mode */
440 val = (ctx->interlace ? ~0 : 0);
441 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
442
443 /* setup format */
444 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
445 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
446 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
447
448 /* setting size of input image */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900449 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_width) |
450 VP_IMG_VSIZE(win_data->fb_height));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900451 /* chroma height has to reduced by 2 to avoid chroma distorions */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900452 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(win_data->fb_width) |
453 VP_IMG_VSIZE(win_data->fb_height / 2));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900454
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900455 vp_reg_write(res, VP_SRC_WIDTH, win_data->src_width);
456 vp_reg_write(res, VP_SRC_HEIGHT, win_data->src_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900457 vp_reg_write(res, VP_SRC_H_POSITION,
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900458 VP_SRC_H_POSITION_VAL(win_data->fb_x));
459 vp_reg_write(res, VP_SRC_V_POSITION, win_data->fb_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900460
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900461 vp_reg_write(res, VP_DST_WIDTH, win_data->crtc_width);
462 vp_reg_write(res, VP_DST_H_POSITION, win_data->crtc_x);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900463 if (ctx->interlace) {
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900464 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height / 2);
465 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y / 2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900466 } else {
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900467 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height);
468 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900469 }
470
471 vp_reg_write(res, VP_H_RATIO, x_ratio);
472 vp_reg_write(res, VP_V_RATIO, y_ratio);
473
474 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
475
476 /* set buffer address to vp */
477 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
478 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
479 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
480 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
481
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900482 mixer_cfg_scan(ctx, win_data->mode_height);
483 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900484 mixer_cfg_layer(ctx, win, true);
485 mixer_run(ctx);
486
487 mixer_vsync_set_update(ctx, true);
488 spin_unlock_irqrestore(&res->reg_slock, flags);
489
490 vp_regs_dump(ctx);
491}
492
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530493static void mixer_layer_update(struct mixer_context *ctx)
494{
495 struct mixer_resources *res = &ctx->mixer_res;
496 u32 val;
497
498 val = mixer_reg_read(res, MXR_CFG);
499
500 /* allow one update per vsync only */
501 if (!(val & MXR_CFG_LAYER_UPDATE_COUNT_MASK))
502 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
503}
504
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900505static void mixer_graph_buffer(struct mixer_context *ctx, int win)
506{
507 struct mixer_resources *res = &ctx->mixer_res;
508 unsigned long flags;
509 struct hdmi_win_data *win_data;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900510 unsigned int x_ratio, y_ratio;
511 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900512 dma_addr_t dma_addr;
513 unsigned int fmt;
514 u32 val;
515
516 win_data = &ctx->win_data[win];
517
518 #define RGB565 4
519 #define ARGB1555 5
520 #define ARGB4444 6
521 #define ARGB8888 7
522
523 switch (win_data->bpp) {
524 case 16:
525 fmt = ARGB4444;
526 break;
527 case 32:
528 fmt = ARGB8888;
529 break;
530 default:
531 fmt = ARGB8888;
532 }
533
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900534 /* 2x scaling feature */
535 x_ratio = 0;
536 y_ratio = 0;
537
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900538 dst_x_offset = win_data->crtc_x;
539 dst_y_offset = win_data->crtc_y;
540
541 /* converting dma address base and source offset */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900542 dma_addr = win_data->dma_addr
543 + (win_data->fb_x * win_data->bpp >> 3)
544 + (win_data->fb_y * win_data->fb_width * win_data->bpp >> 3);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900545 src_x_offset = 0;
546 src_y_offset = 0;
547
548 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE)
549 ctx->interlace = true;
550 else
551 ctx->interlace = false;
552
553 spin_lock_irqsave(&res->reg_slock, flags);
554 mixer_vsync_set_update(ctx, false);
555
556 /* setup format */
557 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
558 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
559
560 /* setup geometry */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900561 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), win_data->fb_width);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900562
Rahul Sharmadef5e092013-06-19 18:21:08 +0530563 /* setup display size */
564 if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
565 win == MIXER_DEFAULT_WIN) {
566 val = MXR_MXR_RES_HEIGHT(win_data->fb_height);
567 val |= MXR_MXR_RES_WIDTH(win_data->fb_width);
568 mixer_reg_write(res, MXR_RESOLUTION, val);
569 }
570
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900571 val = MXR_GRP_WH_WIDTH(win_data->crtc_width);
572 val |= MXR_GRP_WH_HEIGHT(win_data->crtc_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900573 val |= MXR_GRP_WH_H_SCALE(x_ratio);
574 val |= MXR_GRP_WH_V_SCALE(y_ratio);
575 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
576
577 /* setup offsets in source image */
578 val = MXR_GRP_SXY_SX(src_x_offset);
579 val |= MXR_GRP_SXY_SY(src_y_offset);
580 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
581
582 /* setup offsets in display image */
583 val = MXR_GRP_DXY_DX(dst_x_offset);
584 val |= MXR_GRP_DXY_DY(dst_y_offset);
585 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
586
587 /* set buffer address to mixer */
588 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
589
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900590 mixer_cfg_scan(ctx, win_data->mode_height);
591 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900592 mixer_cfg_layer(ctx, win, true);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530593
594 /* layer update mandatory for mixer 16.0.33.0 */
Rahul Sharmadef5e092013-06-19 18:21:08 +0530595 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
596 ctx->mxr_ver == MXR_VER_128_0_0_184)
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530597 mixer_layer_update(ctx);
598
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900599 mixer_run(ctx);
600
601 mixer_vsync_set_update(ctx, true);
602 spin_unlock_irqrestore(&res->reg_slock, flags);
603}
604
605static void vp_win_reset(struct mixer_context *ctx)
606{
607 struct mixer_resources *res = &ctx->mixer_res;
608 int tries = 100;
609
610 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
611 for (tries = 100; tries; --tries) {
612 /* waiting until VP_SRESET_PROCESSING is 0 */
613 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
614 break;
Sean Paul09760ea2013-01-14 17:03:20 -0500615 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900616 }
617 WARN(tries == 0, "failed to reset Video Processor\n");
618}
619
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900620static void mixer_win_reset(struct mixer_context *ctx)
621{
622 struct mixer_resources *res = &ctx->mixer_res;
623 unsigned long flags;
624 u32 val; /* value stored to register */
625
626 spin_lock_irqsave(&res->reg_slock, flags);
627 mixer_vsync_set_update(ctx, false);
628
629 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
630
631 /* set output in RGB888 mode */
632 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
633
634 /* 16 beat burst in DMA */
635 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
636 MXR_STATUS_BURST_MASK);
637
638 /* setting default layer priority: layer1 > layer0 > video
639 * because typical usage scenario would be
640 * layer1 - OSD
641 * layer0 - framebuffer
642 * video - video overlay
643 */
644 val = MXR_LAYER_CFG_GRP1_VAL(3);
645 val |= MXR_LAYER_CFG_GRP0_VAL(2);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530646 if (ctx->vp_enabled)
647 val |= MXR_LAYER_CFG_VP_VAL(1);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900648 mixer_reg_write(res, MXR_LAYER_CFG, val);
649
650 /* setting background color */
651 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
652 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
653 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
654
655 /* setting graphical layers */
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900656 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
657 val |= MXR_GRP_CFG_WIN_BLEND_EN;
658 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
659
Sean Paul0377f4e2013-04-25 15:13:26 -0400660 /* Don't blend layer 0 onto the mixer background */
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900661 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
Sean Paul0377f4e2013-04-25 15:13:26 -0400662
663 /* Blend layer 1 into layer 0 */
664 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
665 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900666 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
667
Seung-Woo Kim57366032012-05-15 17:22:08 +0900668 /* setting video layers */
669 val = MXR_GRP_CFG_ALPHA_VAL(0);
670 mixer_reg_write(res, MXR_VIDEO_CFG, val);
671
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530672 if (ctx->vp_enabled) {
673 /* configuration of Video Processor Registers */
674 vp_win_reset(ctx);
675 vp_default_filter(res);
676 }
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900677
678 /* disable all layers */
679 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
680 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530681 if (ctx->vp_enabled)
682 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900683
684 mixer_vsync_set_update(ctx, true);
685 spin_unlock_irqrestore(&res->reg_slock, flags);
686}
687
Inki Dae1055b392012-10-19 17:37:35 +0900688static int mixer_iommu_on(void *ctx, bool enable)
689{
690 struct exynos_drm_hdmi_context *drm_hdmi_ctx;
691 struct mixer_context *mdata = ctx;
692 struct drm_device *drm_dev;
693
694 drm_hdmi_ctx = mdata->parent_ctx;
695 drm_dev = drm_hdmi_ctx->drm_dev;
696
697 if (is_drm_iommu_supported(drm_dev)) {
698 if (enable)
699 return drm_iommu_attach_device(drm_dev, mdata->dev);
700
701 drm_iommu_detach_device(drm_dev, mdata->dev);
702 }
703 return 0;
704}
705
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900706static int mixer_enable_vblank(void *ctx, int pipe)
707{
708 struct mixer_context *mixer_ctx = ctx;
709 struct mixer_resources *res = &mixer_ctx->mixer_res;
710
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900711 mixer_ctx->pipe = pipe;
712
713 /* enable vsync interrupt */
714 mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
715 MXR_INT_EN_VSYNC);
716
717 return 0;
718}
719
720static void mixer_disable_vblank(void *ctx)
721{
722 struct mixer_context *mixer_ctx = ctx;
723 struct mixer_resources *res = &mixer_ctx->mixer_res;
724
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900725 /* disable vsync interrupt */
726 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
727}
728
729static void mixer_win_mode_set(void *ctx,
730 struct exynos_drm_overlay *overlay)
731{
732 struct mixer_context *mixer_ctx = ctx;
733 struct hdmi_win_data *win_data;
734 int win;
735
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900736 if (!overlay) {
737 DRM_ERROR("overlay is NULL\n");
738 return;
739 }
740
741 DRM_DEBUG_KMS("set [%d]x[%d] at (%d,%d) to [%d]x[%d] at (%d,%d)\n",
742 overlay->fb_width, overlay->fb_height,
743 overlay->fb_x, overlay->fb_y,
744 overlay->crtc_width, overlay->crtc_height,
745 overlay->crtc_x, overlay->crtc_y);
746
747 win = overlay->zpos;
748 if (win == DEFAULT_ZPOS)
Joonyoung Shima2ee1512012-04-05 20:49:25 +0900749 win = MIXER_DEFAULT_WIN;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900750
Krzysztof Kozlowski1586d802013-05-27 15:00:43 +0900751 if (win < 0 || win >= MIXER_WIN_NR) {
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900752 DRM_ERROR("mixer window[%d] is wrong\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900753 return;
754 }
755
756 win_data = &mixer_ctx->win_data[win];
757
758 win_data->dma_addr = overlay->dma_addr[0];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900759 win_data->chroma_dma_addr = overlay->dma_addr[1];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900760 win_data->pixel_format = overlay->pixel_format;
761 win_data->bpp = overlay->bpp;
762
763 win_data->crtc_x = overlay->crtc_x;
764 win_data->crtc_y = overlay->crtc_y;
765 win_data->crtc_width = overlay->crtc_width;
766 win_data->crtc_height = overlay->crtc_height;
767
768 win_data->fb_x = overlay->fb_x;
769 win_data->fb_y = overlay->fb_y;
770 win_data->fb_width = overlay->fb_width;
771 win_data->fb_height = overlay->fb_height;
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900772 win_data->src_width = overlay->src_width;
773 win_data->src_height = overlay->src_height;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900774
775 win_data->mode_width = overlay->mode_width;
776 win_data->mode_height = overlay->mode_height;
777
778 win_data->scan_flags = overlay->scan_flag;
779}
780
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900781static void mixer_win_commit(void *ctx, int win)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900782{
783 struct mixer_context *mixer_ctx = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900784
YoungJun Chocbc4c332013-06-12 10:44:40 +0900785 DRM_DEBUG_KMS("win: %d\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900786
Shirish Sdda90122013-01-23 22:03:18 -0500787 mutex_lock(&mixer_ctx->mixer_mutex);
788 if (!mixer_ctx->powered) {
789 mutex_unlock(&mixer_ctx->mixer_mutex);
790 return;
791 }
792 mutex_unlock(&mixer_ctx->mixer_mutex);
793
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530794 if (win > 1 && mixer_ctx->vp_enabled)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900795 vp_video_buffer(mixer_ctx, win);
796 else
797 mixer_graph_buffer(mixer_ctx, win);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530798
799 mixer_ctx->win_data[win].enabled = true;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900800}
801
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900802static void mixer_win_disable(void *ctx, int win)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900803{
804 struct mixer_context *mixer_ctx = ctx;
805 struct mixer_resources *res = &mixer_ctx->mixer_res;
806 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900807
YoungJun Chocbc4c332013-06-12 10:44:40 +0900808 DRM_DEBUG_KMS("win: %d\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900809
Prathyush Kdb43fd12012-12-06 20:16:05 +0530810 mutex_lock(&mixer_ctx->mixer_mutex);
811 if (!mixer_ctx->powered) {
812 mutex_unlock(&mixer_ctx->mixer_mutex);
813 mixer_ctx->win_data[win].resume = false;
814 return;
815 }
816 mutex_unlock(&mixer_ctx->mixer_mutex);
817
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900818 spin_lock_irqsave(&res->reg_slock, flags);
819 mixer_vsync_set_update(mixer_ctx, false);
820
821 mixer_cfg_layer(mixer_ctx, win, false);
822
823 mixer_vsync_set_update(mixer_ctx, true);
824 spin_unlock_irqrestore(&res->reg_slock, flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530825
826 mixer_ctx->win_data[win].enabled = false;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900827}
828
Rahul Sharma16844fb2013-06-10 14:50:00 +0530829static int mixer_check_mode(void *ctx, struct drm_display_mode *mode)
Rahul Sharma0ea68222013-01-15 08:11:06 -0500830{
Rahul Sharmadef5e092013-06-19 18:21:08 +0530831 struct mixer_context *mixer_ctx = ctx;
Rahul Sharma0ea68222013-01-15 08:11:06 -0500832 u32 w, h;
833
Rahul Sharma16844fb2013-06-10 14:50:00 +0530834 w = mode->hdisplay;
835 h = mode->vdisplay;
Rahul Sharma0ea68222013-01-15 08:11:06 -0500836
Rahul Sharma16844fb2013-06-10 14:50:00 +0530837 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
838 mode->hdisplay, mode->vdisplay, mode->vrefresh,
839 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
Rahul Sharma0ea68222013-01-15 08:11:06 -0500840
Rahul Sharmadef5e092013-06-19 18:21:08 +0530841 if (mixer_ctx->mxr_ver == MXR_VER_0_0_0_16 ||
842 mixer_ctx->mxr_ver == MXR_VER_128_0_0_184)
843 return 0;
844
Rahul Sharma0ea68222013-01-15 08:11:06 -0500845 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
846 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
847 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
848 return 0;
849
850 return -EINVAL;
851}
Prathyush K8137a2e2012-12-06 20:16:01 +0530852static void mixer_wait_for_vblank(void *ctx)
853{
854 struct mixer_context *mixer_ctx = ctx;
Prathyush K8137a2e2012-12-06 20:16:01 +0530855
Prathyush K6e95d5e2012-12-06 20:16:03 +0530856 mutex_lock(&mixer_ctx->mixer_mutex);
857 if (!mixer_ctx->powered) {
858 mutex_unlock(&mixer_ctx->mixer_mutex);
859 return;
860 }
861 mutex_unlock(&mixer_ctx->mixer_mutex);
862
863 atomic_set(&mixer_ctx->wait_vsync_event, 1);
864
865 /*
866 * wait for MIXER to signal VSYNC interrupt or return after
867 * timeout which is set to 50ms (refresh rate of 20).
868 */
869 if (!wait_event_timeout(mixer_ctx->wait_vsync_queue,
870 !atomic_read(&mixer_ctx->wait_vsync_event),
871 DRM_HZ/20))
Prathyush K8137a2e2012-12-06 20:16:01 +0530872 DRM_DEBUG_KMS("vblank wait timed out.\n");
873}
874
Prathyush Kdb43fd12012-12-06 20:16:05 +0530875static void mixer_window_suspend(struct mixer_context *ctx)
876{
877 struct hdmi_win_data *win_data;
878 int i;
879
880 for (i = 0; i < MIXER_WIN_NR; i++) {
881 win_data = &ctx->win_data[i];
882 win_data->resume = win_data->enabled;
883 mixer_win_disable(ctx, i);
884 }
885 mixer_wait_for_vblank(ctx);
886}
887
888static void mixer_window_resume(struct mixer_context *ctx)
889{
890 struct hdmi_win_data *win_data;
891 int i;
892
893 for (i = 0; i < MIXER_WIN_NR; i++) {
894 win_data = &ctx->win_data[i];
895 win_data->enabled = win_data->resume;
896 win_data->resume = false;
897 }
898}
899
900static void mixer_poweron(struct mixer_context *ctx)
901{
902 struct mixer_resources *res = &ctx->mixer_res;
903
Prathyush Kdb43fd12012-12-06 20:16:05 +0530904 mutex_lock(&ctx->mixer_mutex);
905 if (ctx->powered) {
906 mutex_unlock(&ctx->mixer_mutex);
907 return;
908 }
909 ctx->powered = true;
910 mutex_unlock(&ctx->mixer_mutex);
911
Sean Paul0bfb1f82013-06-11 12:24:02 +0530912 clk_prepare_enable(res->mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530913 if (ctx->vp_enabled) {
Sean Paul0bfb1f82013-06-11 12:24:02 +0530914 clk_prepare_enable(res->vp);
915 clk_prepare_enable(res->sclk_mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530916 }
917
918 mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
919 mixer_win_reset(ctx);
920
921 mixer_window_resume(ctx);
922}
923
924static void mixer_poweroff(struct mixer_context *ctx)
925{
926 struct mixer_resources *res = &ctx->mixer_res;
927
Prathyush Kdb43fd12012-12-06 20:16:05 +0530928 mutex_lock(&ctx->mixer_mutex);
929 if (!ctx->powered)
930 goto out;
931 mutex_unlock(&ctx->mixer_mutex);
932
933 mixer_window_suspend(ctx);
934
935 ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
936
Sean Paul0bfb1f82013-06-11 12:24:02 +0530937 clk_disable_unprepare(res->mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530938 if (ctx->vp_enabled) {
Sean Paul0bfb1f82013-06-11 12:24:02 +0530939 clk_disable_unprepare(res->vp);
940 clk_disable_unprepare(res->sclk_mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530941 }
942
Prathyush Kdb43fd12012-12-06 20:16:05 +0530943 mutex_lock(&ctx->mixer_mutex);
944 ctx->powered = false;
945
946out:
947 mutex_unlock(&ctx->mixer_mutex);
948}
949
950static void mixer_dpms(void *ctx, int mode)
951{
952 struct mixer_context *mixer_ctx = ctx;
953
Prathyush Kdb43fd12012-12-06 20:16:05 +0530954 switch (mode) {
955 case DRM_MODE_DPMS_ON:
Rahul Sharma000f1302012-11-28 11:30:24 +0530956 if (pm_runtime_suspended(mixer_ctx->dev))
957 pm_runtime_get_sync(mixer_ctx->dev);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530958 break;
959 case DRM_MODE_DPMS_STANDBY:
960 case DRM_MODE_DPMS_SUSPEND:
961 case DRM_MODE_DPMS_OFF:
Rahul Sharma000f1302012-11-28 11:30:24 +0530962 if (!pm_runtime_suspended(mixer_ctx->dev))
963 pm_runtime_put_sync(mixer_ctx->dev);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530964 break;
965 default:
966 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
967 break;
968 }
969}
970
Joonyoung Shim578b6062012-04-05 20:49:26 +0900971static struct exynos_mixer_ops mixer_ops = {
972 /* manager */
Inki Dae1055b392012-10-19 17:37:35 +0900973 .iommu_on = mixer_iommu_on,
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900974 .enable_vblank = mixer_enable_vblank,
975 .disable_vblank = mixer_disable_vblank,
Prathyush K8137a2e2012-12-06 20:16:01 +0530976 .wait_for_vblank = mixer_wait_for_vblank,
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900977 .dpms = mixer_dpms,
Joonyoung Shim578b6062012-04-05 20:49:26 +0900978
979 /* overlay */
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900980 .win_mode_set = mixer_win_mode_set,
981 .win_commit = mixer_win_commit,
982 .win_disable = mixer_win_disable,
Rahul Sharma0ea68222013-01-15 08:11:06 -0500983
984 /* display */
Rahul Sharma16844fb2013-06-10 14:50:00 +0530985 .check_mode = mixer_check_mode,
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900986};
987
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900988static irqreturn_t mixer_irq_handler(int irq, void *arg)
989{
990 struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg;
Joonyoung Shimf9309d12012-04-05 20:49:22 +0900991 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900992 struct mixer_resources *res = &ctx->mixer_res;
Seung-Woo Kim8379e482012-04-23 20:30:13 +0900993 u32 val, base, shadow;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900994
995 spin_lock(&res->reg_slock);
996
997 /* read interrupt status for handling and clearing flags for VSYNC */
998 val = mixer_reg_read(res, MXR_INT_STATUS);
999
1000 /* handling VSYNC */
1001 if (val & MXR_INT_STATUS_VSYNC) {
1002 /* interlace scan need to check shadow register */
1003 if (ctx->interlace) {
Seung-Woo Kim8379e482012-04-23 20:30:13 +09001004 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
1005 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
1006 if (base != shadow)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001007 goto out;
1008
Seung-Woo Kim8379e482012-04-23 20:30:13 +09001009 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
1010 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
1011 if (base != shadow)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001012 goto out;
1013 }
1014
1015 drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe);
Rahul Sharma663d8762013-01-03 05:44:04 -05001016 exynos_drm_crtc_finish_pageflip(drm_hdmi_ctx->drm_dev,
1017 ctx->pipe);
Prathyush K6e95d5e2012-12-06 20:16:03 +05301018
1019 /* set wait vsync event to zero and wake up queue. */
1020 if (atomic_read(&ctx->wait_vsync_event)) {
1021 atomic_set(&ctx->wait_vsync_event, 0);
1022 DRM_WAKEUP(&ctx->wait_vsync_queue);
1023 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001024 }
1025
1026out:
1027 /* clear interrupts */
1028 if (~val & MXR_INT_EN_VSYNC) {
1029 /* vsync interrupt use different bit for read and clear */
1030 val &= ~MXR_INT_EN_VSYNC;
1031 val |= MXR_INT_CLEAR_VSYNC;
1032 }
1033 mixer_reg_write(res, MXR_INT_STATUS, val);
1034
1035 spin_unlock(&res->reg_slock);
1036
1037 return IRQ_HANDLED;
1038}
1039
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001040static int mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
1041 struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001042{
Joonyoung Shimf9309d12012-04-05 20:49:22 +09001043 struct mixer_context *mixer_ctx = ctx->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001044 struct device *dev = &pdev->dev;
1045 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
1046 struct resource *res;
1047 int ret;
1048
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001049 spin_lock_init(&mixer_res->reg_slock);
1050
Sachin Kamat37f50862012-11-23 14:13:26 +05301051 mixer_res->mixer = devm_clk_get(dev, "mixer");
Sachin Kamatc11182d2013-03-21 15:33:58 +05301052 if (IS_ERR(mixer_res->mixer)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001053 dev_err(dev, "failed to get clock 'mixer'\n");
Sachin Kamat37f50862012-11-23 14:13:26 +05301054 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001055 }
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301056
Sachin Kamat37f50862012-11-23 14:13:26 +05301057 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatc11182d2013-03-21 15:33:58 +05301058 if (IS_ERR(mixer_res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001059 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
Sachin Kamat37f50862012-11-23 14:13:26 +05301060 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001061 }
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301062 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001063 if (res == NULL) {
1064 dev_err(dev, "get memory resource failed.\n");
Sachin Kamat37f50862012-11-23 14:13:26 +05301065 return -ENXIO;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001066 }
1067
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001068 mixer_res->mixer_regs = devm_ioremap(dev, res->start,
Sachin Kamat9416dfa2012-06-19 11:47:41 +05301069 resource_size(res));
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001070 if (mixer_res->mixer_regs == NULL) {
1071 dev_err(dev, "register mapping failed.\n");
Sachin Kamat37f50862012-11-23 14:13:26 +05301072 return -ENXIO;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001073 }
1074
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301075 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001076 if (res == NULL) {
1077 dev_err(dev, "get interrupt resource failed.\n");
Sachin Kamat37f50862012-11-23 14:13:26 +05301078 return -ENXIO;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001079 }
1080
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001081 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
Sachin Kamat9416dfa2012-06-19 11:47:41 +05301082 0, "drm_mixer", ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001083 if (ret) {
1084 dev_err(dev, "request interrupt failed.\n");
Sachin Kamat37f50862012-11-23 14:13:26 +05301085 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001086 }
1087 mixer_res->irq = res->start;
1088
1089 return 0;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001090}
1091
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001092static int vp_resources_init(struct exynos_drm_hdmi_context *ctx,
1093 struct platform_device *pdev)
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301094{
1095 struct mixer_context *mixer_ctx = ctx->ctx;
1096 struct device *dev = &pdev->dev;
1097 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
1098 struct resource *res;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301099
Sachin Kamat37f50862012-11-23 14:13:26 +05301100 mixer_res->vp = devm_clk_get(dev, "vp");
Sachin Kamatc11182d2013-03-21 15:33:58 +05301101 if (IS_ERR(mixer_res->vp)) {
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301102 dev_err(dev, "failed to get clock 'vp'\n");
Sachin Kamat37f50862012-11-23 14:13:26 +05301103 return -ENODEV;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301104 }
Sachin Kamat37f50862012-11-23 14:13:26 +05301105 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
Sachin Kamatc11182d2013-03-21 15:33:58 +05301106 if (IS_ERR(mixer_res->sclk_mixer)) {
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301107 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
Sachin Kamat37f50862012-11-23 14:13:26 +05301108 return -ENODEV;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301109 }
Sachin Kamat37f50862012-11-23 14:13:26 +05301110 mixer_res->sclk_dac = devm_clk_get(dev, "sclk_dac");
Sachin Kamatc11182d2013-03-21 15:33:58 +05301111 if (IS_ERR(mixer_res->sclk_dac)) {
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301112 dev_err(dev, "failed to get clock 'sclk_dac'\n");
Sachin Kamat37f50862012-11-23 14:13:26 +05301113 return -ENODEV;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301114 }
1115
1116 if (mixer_res->sclk_hdmi)
1117 clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
1118
1119 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
1120 if (res == NULL) {
1121 dev_err(dev, "get memory resource failed.\n");
Sachin Kamat37f50862012-11-23 14:13:26 +05301122 return -ENXIO;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301123 }
1124
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001125 mixer_res->vp_regs = devm_ioremap(dev, res->start,
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301126 resource_size(res));
1127 if (mixer_res->vp_regs == NULL) {
1128 dev_err(dev, "register mapping failed.\n");
Sachin Kamat37f50862012-11-23 14:13:26 +05301129 return -ENXIO;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301130 }
1131
1132 return 0;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301133}
1134
Rahul Sharmadef5e092013-06-19 18:21:08 +05301135static struct mixer_drv_data exynos5420_mxr_drv_data = {
1136 .version = MXR_VER_128_0_0_184,
1137 .is_vp_enabled = 0,
1138};
1139
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301140static struct mixer_drv_data exynos5250_mxr_drv_data = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301141 .version = MXR_VER_16_0_33_0,
1142 .is_vp_enabled = 0,
1143};
1144
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301145static struct mixer_drv_data exynos4210_mxr_drv_data = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301146 .version = MXR_VER_0_0_0_16,
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301147 .is_vp_enabled = 1,
Rahul Sharma1e123442012-10-04 20:48:51 +05301148};
1149
1150static struct platform_device_id mixer_driver_types[] = {
1151 {
1152 .name = "s5p-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301153 .driver_data = (unsigned long)&exynos4210_mxr_drv_data,
Rahul Sharma1e123442012-10-04 20:48:51 +05301154 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301155 .name = "exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301156 .driver_data = (unsigned long)&exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301157 }, {
1158 /* end node */
1159 }
1160};
1161
1162static struct of_device_id mixer_match_types[] = {
1163 {
1164 .compatible = "samsung,exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301165 .data = &exynos5250_mxr_drv_data,
1166 }, {
1167 .compatible = "samsung,exynos5250-mixer",
1168 .data = &exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301169 }, {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301170 .compatible = "samsung,exynos5420-mixer",
1171 .data = &exynos5420_mxr_drv_data,
1172 }, {
Rahul Sharma1e123442012-10-04 20:48:51 +05301173 /* end node */
1174 }
1175};
1176
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001177static int mixer_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001178{
1179 struct device *dev = &pdev->dev;
1180 struct exynos_drm_hdmi_context *drm_hdmi_ctx;
1181 struct mixer_context *ctx;
Rahul Sharma1e123442012-10-04 20:48:51 +05301182 struct mixer_drv_data *drv;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001183 int ret;
1184
1185 dev_info(dev, "probe start\n");
1186
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001187 drm_hdmi_ctx = devm_kzalloc(dev, sizeof(*drm_hdmi_ctx),
Sachin Kamat9416dfa2012-06-19 11:47:41 +05301188 GFP_KERNEL);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001189 if (!drm_hdmi_ctx) {
1190 DRM_ERROR("failed to allocate common hdmi context.\n");
1191 return -ENOMEM;
1192 }
1193
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001194 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001195 if (!ctx) {
1196 DRM_ERROR("failed to alloc mixer context.\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001197 return -ENOMEM;
1198 }
1199
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001200 mutex_init(&ctx->mixer_mutex);
1201
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301202 if (dev->of_node) {
1203 const struct of_device_id *match;
Sachin Kamate436b092013-06-05 16:00:23 +09001204 match = of_match_node(mixer_match_types, dev->of_node);
Rahul Sharma2cdc53b2012-10-31 09:36:26 +05301205 drv = (struct mixer_drv_data *)match->data;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301206 } else {
1207 drv = (struct mixer_drv_data *)
1208 platform_get_device_id(pdev)->driver_data;
1209 }
1210
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001211 ctx->dev = dev;
Inki Dae1055b392012-10-19 17:37:35 +09001212 ctx->parent_ctx = (void *)drm_hdmi_ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001213 drm_hdmi_ctx->ctx = (void *)ctx;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301214 ctx->vp_enabled = drv->is_vp_enabled;
Rahul Sharma1e123442012-10-04 20:48:51 +05301215 ctx->mxr_ver = drv->version;
Prathyush K6e95d5e2012-12-06 20:16:03 +05301216 DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
1217 atomic_set(&ctx->wait_vsync_event, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001218
1219 platform_set_drvdata(pdev, drm_hdmi_ctx);
1220
1221 /* acquire resources: regs, irqs, clocks */
1222 ret = mixer_resources_init(drm_hdmi_ctx, pdev);
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301223 if (ret) {
1224 DRM_ERROR("mixer_resources_init failed\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001225 goto fail;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301226 }
1227
1228 if (ctx->vp_enabled) {
1229 /* acquire vp resources: regs, irqs, clocks */
1230 ret = vp_resources_init(drm_hdmi_ctx, pdev);
1231 if (ret) {
1232 DRM_ERROR("vp_resources_init failed\n");
1233 goto fail;
1234 }
1235 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001236
Rahul Sharma768c3052012-10-04 20:48:56 +05301237 /* attach mixer driver to common hdmi. */
1238 exynos_mixer_drv_attach(drm_hdmi_ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001239
1240 /* register specific callback point to common hdmi. */
Joonyoung Shim578b6062012-04-05 20:49:26 +09001241 exynos_mixer_ops_register(&mixer_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001242
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001243 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001244
1245 return 0;
1246
1247
1248fail:
1249 dev_info(dev, "probe failed\n");
1250 return ret;
1251}
1252
1253static int mixer_remove(struct platform_device *pdev)
1254{
Sachin Kamat9416dfa2012-06-19 11:47:41 +05301255 dev_info(&pdev->dev, "remove successful\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001256
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001257 pm_runtime_disable(&pdev->dev);
1258
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001259 return 0;
1260}
1261
Joonyoung Shimab27af82012-04-23 19:35:51 +09001262#ifdef CONFIG_PM_SLEEP
1263static int mixer_suspend(struct device *dev)
1264{
1265 struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
1266 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
1267
Rahul Sharma000f1302012-11-28 11:30:24 +05301268 if (pm_runtime_suspended(dev)) {
YoungJun Chocbc4c332013-06-12 10:44:40 +09001269 DRM_DEBUG_KMS("Already suspended\n");
Rahul Sharma000f1302012-11-28 11:30:24 +05301270 return 0;
1271 }
1272
Joonyoung Shimab27af82012-04-23 19:35:51 +09001273 mixer_poweroff(ctx);
1274
1275 return 0;
1276}
Rahul Sharma000f1302012-11-28 11:30:24 +05301277
1278static int mixer_resume(struct device *dev)
1279{
1280 struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
1281 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
1282
Rahul Sharma000f1302012-11-28 11:30:24 +05301283 if (!pm_runtime_suspended(dev)) {
YoungJun Chocbc4c332013-06-12 10:44:40 +09001284 DRM_DEBUG_KMS("Already resumed\n");
Rahul Sharma000f1302012-11-28 11:30:24 +05301285 return 0;
1286 }
1287
1288 mixer_poweron(ctx);
1289
1290 return 0;
1291}
Joonyoung Shimab27af82012-04-23 19:35:51 +09001292#endif
1293
Rahul Sharma000f1302012-11-28 11:30:24 +05301294#ifdef CONFIG_PM_RUNTIME
1295static int mixer_runtime_suspend(struct device *dev)
1296{
1297 struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
1298 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
1299
Rahul Sharma000f1302012-11-28 11:30:24 +05301300 mixer_poweroff(ctx);
1301
1302 return 0;
1303}
1304
1305static int mixer_runtime_resume(struct device *dev)
1306{
1307 struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
1308 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
1309
Rahul Sharma000f1302012-11-28 11:30:24 +05301310 mixer_poweron(ctx);
1311
1312 return 0;
1313}
1314#endif
1315
1316static const struct dev_pm_ops mixer_pm_ops = {
1317 SET_SYSTEM_SLEEP_PM_OPS(mixer_suspend, mixer_resume)
1318 SET_RUNTIME_PM_OPS(mixer_runtime_suspend, mixer_runtime_resume, NULL)
1319};
Joonyoung Shimab27af82012-04-23 19:35:51 +09001320
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001321struct platform_driver mixer_driver = {
1322 .driver = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301323 .name = "exynos-mixer",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001324 .owner = THIS_MODULE,
Joonyoung Shimab27af82012-04-23 19:35:51 +09001325 .pm = &mixer_pm_ops,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301326 .of_match_table = mixer_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001327 },
1328 .probe = mixer_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001329 .remove = mixer_remove,
Rahul Sharma1e123442012-10-04 20:48:51 +05301330 .id_table = mixer_driver_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001331};