blob: c9a137caea41108a18b8c179a39110c3d64e6a5b [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>
33
34#include <drm/exynos_drm.h>
35
36#include "exynos_drm_drv.h"
Rahul Sharma663d8762013-01-03 05:44:04 -050037#include "exynos_drm_crtc.h"
Seung-Woo Kimd8408322011-12-21 17:39:39 +090038#include "exynos_drm_hdmi.h"
Inki Dae1055b392012-10-19 17:37:35 +090039#include "exynos_drm_iommu.h"
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090040
Seung-Woo Kimd8408322011-12-21 17:39:39 +090041#define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev))
42
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090043struct hdmi_win_data {
44 dma_addr_t dma_addr;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090045 dma_addr_t chroma_dma_addr;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090046 uint32_t pixel_format;
47 unsigned int bpp;
48 unsigned int crtc_x;
49 unsigned int crtc_y;
50 unsigned int crtc_width;
51 unsigned int crtc_height;
52 unsigned int fb_x;
53 unsigned int fb_y;
54 unsigned int fb_width;
55 unsigned int fb_height;
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +090056 unsigned int src_width;
57 unsigned int src_height;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090058 unsigned int mode_width;
59 unsigned int mode_height;
60 unsigned int scan_flags;
Prathyush Kdb43fd12012-12-06 20:16:05 +053061 bool enabled;
62 bool resume;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090063};
64
65struct mixer_resources {
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090066 int irq;
67 void __iomem *mixer_regs;
68 void __iomem *vp_regs;
69 spinlock_t reg_slock;
70 struct clk *mixer;
71 struct clk *vp;
72 struct clk *sclk_mixer;
73 struct clk *sclk_hdmi;
74 struct clk *sclk_dac;
75};
76
Rahul Sharma1e123442012-10-04 20:48:51 +053077enum mixer_version_id {
78 MXR_VER_0_0_0_16,
79 MXR_VER_16_0_33_0,
Rahul Sharmadef5e092013-06-19 18:21:08 +053080 MXR_VER_128_0_0_184,
Rahul Sharma1e123442012-10-04 20:48:51 +053081};
82
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090083struct mixer_context {
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090084 struct device *dev;
Inki Dae1055b392012-10-19 17:37:35 +090085 struct drm_device *drm_dev;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090086 int pipe;
87 bool interlace;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090088 bool powered;
Rahul Sharma1b8e5742012-10-04 20:48:52 +053089 bool vp_enabled;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090090 u32 int_en;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090091
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090092 struct mutex mixer_mutex;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090093 struct mixer_resources mixer_res;
Joonyoung Shima634dd52012-04-05 20:49:24 +090094 struct hdmi_win_data win_data[MIXER_WIN_NR];
Rahul Sharma1e123442012-10-04 20:48:51 +053095 enum mixer_version_id mxr_ver;
Inki Dae1055b392012-10-19 17:37:35 +090096 void *parent_ctx;
Prathyush K6e95d5e2012-12-06 20:16:03 +053097 wait_queue_head_t wait_vsync_queue;
98 atomic_t wait_vsync_event;
Rahul Sharma1e123442012-10-04 20:48:51 +053099};
100
101struct mixer_drv_data {
102 enum mixer_version_id version;
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530103 bool is_vp_enabled;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +0900104};
105
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900106static const u8 filter_y_horiz_tap8[] = {
107 0, -1, -1, -1, -1, -1, -1, -1,
108 -1, -1, -1, -1, -1, 0, 0, 0,
109 0, 2, 4, 5, 6, 6, 6, 6,
110 6, 5, 5, 4, 3, 2, 1, 1,
111 0, -6, -12, -16, -18, -20, -21, -20,
112 -20, -18, -16, -13, -10, -8, -5, -2,
113 127, 126, 125, 121, 114, 107, 99, 89,
114 79, 68, 57, 46, 35, 25, 16, 8,
115};
116
117static const u8 filter_y_vert_tap4[] = {
118 0, -3, -6, -8, -8, -8, -8, -7,
119 -6, -5, -4, -3, -2, -1, -1, 0,
120 127, 126, 124, 118, 111, 102, 92, 81,
121 70, 59, 48, 37, 27, 19, 11, 5,
122 0, 5, 11, 19, 27, 37, 48, 59,
123 70, 81, 92, 102, 111, 118, 124, 126,
124 0, 0, -1, -1, -2, -3, -4, -5,
125 -6, -7, -8, -8, -8, -8, -6, -3,
126};
127
128static const u8 filter_cr_horiz_tap4[] = {
129 0, -3, -6, -8, -8, -8, -8, -7,
130 -6, -5, -4, -3, -2, -1, -1, 0,
131 127, 126, 124, 118, 111, 102, 92, 81,
132 70, 59, 48, 37, 27, 19, 11, 5,
133};
134
135static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
136{
137 return readl(res->vp_regs + reg_id);
138}
139
140static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
141 u32 val)
142{
143 writel(val, res->vp_regs + reg_id);
144}
145
146static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
147 u32 val, u32 mask)
148{
149 u32 old = vp_reg_read(res, reg_id);
150
151 val = (val & mask) | (old & ~mask);
152 writel(val, res->vp_regs + reg_id);
153}
154
155static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
156{
157 return readl(res->mixer_regs + reg_id);
158}
159
160static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
161 u32 val)
162{
163 writel(val, res->mixer_regs + reg_id);
164}
165
166static inline void mixer_reg_writemask(struct mixer_resources *res,
167 u32 reg_id, u32 val, u32 mask)
168{
169 u32 old = mixer_reg_read(res, reg_id);
170
171 val = (val & mask) | (old & ~mask);
172 writel(val, res->mixer_regs + reg_id);
173}
174
175static void mixer_regs_dump(struct mixer_context *ctx)
176{
177#define DUMPREG(reg_id) \
178do { \
179 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
180 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
181} while (0)
182
183 DUMPREG(MXR_STATUS);
184 DUMPREG(MXR_CFG);
185 DUMPREG(MXR_INT_EN);
186 DUMPREG(MXR_INT_STATUS);
187
188 DUMPREG(MXR_LAYER_CFG);
189 DUMPREG(MXR_VIDEO_CFG);
190
191 DUMPREG(MXR_GRAPHIC0_CFG);
192 DUMPREG(MXR_GRAPHIC0_BASE);
193 DUMPREG(MXR_GRAPHIC0_SPAN);
194 DUMPREG(MXR_GRAPHIC0_WH);
195 DUMPREG(MXR_GRAPHIC0_SXY);
196 DUMPREG(MXR_GRAPHIC0_DXY);
197
198 DUMPREG(MXR_GRAPHIC1_CFG);
199 DUMPREG(MXR_GRAPHIC1_BASE);
200 DUMPREG(MXR_GRAPHIC1_SPAN);
201 DUMPREG(MXR_GRAPHIC1_WH);
202 DUMPREG(MXR_GRAPHIC1_SXY);
203 DUMPREG(MXR_GRAPHIC1_DXY);
204#undef DUMPREG
205}
206
207static void vp_regs_dump(struct mixer_context *ctx)
208{
209#define DUMPREG(reg_id) \
210do { \
211 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
212 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
213} while (0)
214
215 DUMPREG(VP_ENABLE);
216 DUMPREG(VP_SRESET);
217 DUMPREG(VP_SHADOW_UPDATE);
218 DUMPREG(VP_FIELD_ID);
219 DUMPREG(VP_MODE);
220 DUMPREG(VP_IMG_SIZE_Y);
221 DUMPREG(VP_IMG_SIZE_C);
222 DUMPREG(VP_PER_RATE_CTRL);
223 DUMPREG(VP_TOP_Y_PTR);
224 DUMPREG(VP_BOT_Y_PTR);
225 DUMPREG(VP_TOP_C_PTR);
226 DUMPREG(VP_BOT_C_PTR);
227 DUMPREG(VP_ENDIAN_MODE);
228 DUMPREG(VP_SRC_H_POSITION);
229 DUMPREG(VP_SRC_V_POSITION);
230 DUMPREG(VP_SRC_WIDTH);
231 DUMPREG(VP_SRC_HEIGHT);
232 DUMPREG(VP_DST_H_POSITION);
233 DUMPREG(VP_DST_V_POSITION);
234 DUMPREG(VP_DST_WIDTH);
235 DUMPREG(VP_DST_HEIGHT);
236 DUMPREG(VP_H_RATIO);
237 DUMPREG(VP_V_RATIO);
238
239#undef DUMPREG
240}
241
242static inline void vp_filter_set(struct mixer_resources *res,
243 int reg_id, const u8 *data, unsigned int size)
244{
245 /* assure 4-byte align */
246 BUG_ON(size & 3);
247 for (; size; size -= 4, reg_id += 4, data += 4) {
248 u32 val = (data[0] << 24) | (data[1] << 16) |
249 (data[2] << 8) | data[3];
250 vp_reg_write(res, reg_id, val);
251 }
252}
253
254static void vp_default_filter(struct mixer_resources *res)
255{
256 vp_filter_set(res, VP_POLY8_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530257 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900258 vp_filter_set(res, VP_POLY4_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530259 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900260 vp_filter_set(res, VP_POLY4_C0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530261 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900262}
263
264static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
265{
266 struct mixer_resources *res = &ctx->mixer_res;
267
268 /* block update on vsync */
269 mixer_reg_writemask(res, MXR_STATUS, enable ?
270 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
271
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530272 if (ctx->vp_enabled)
273 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900274 VP_SHADOW_UPDATE_ENABLE : 0);
275}
276
277static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
278{
279 struct mixer_resources *res = &ctx->mixer_res;
280 u32 val;
281
282 /* choosing between interlace and progressive mode */
283 val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
284 MXR_CFG_SCAN_PROGRASSIVE);
285
Rahul Sharmadef5e092013-06-19 18:21:08 +0530286 if (ctx->mxr_ver != MXR_VER_128_0_0_184) {
287 /* choosing between proper HD and SD mode */
288 if (height <= 480)
289 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
290 else if (height <= 576)
291 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
292 else if (height <= 720)
293 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
294 else if (height <= 1080)
295 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
296 else
297 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
298 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900299
300 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
301}
302
303static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
304{
305 struct mixer_resources *res = &ctx->mixer_res;
306 u32 val;
307
308 if (height == 480) {
309 val = MXR_CFG_RGB601_0_255;
310 } else if (height == 576) {
311 val = MXR_CFG_RGB601_0_255;
312 } else if (height == 720) {
313 val = MXR_CFG_RGB709_16_235;
314 mixer_reg_write(res, MXR_CM_COEFF_Y,
315 (1 << 30) | (94 << 20) | (314 << 10) |
316 (32 << 0));
317 mixer_reg_write(res, MXR_CM_COEFF_CB,
318 (972 << 20) | (851 << 10) | (225 << 0));
319 mixer_reg_write(res, MXR_CM_COEFF_CR,
320 (225 << 20) | (820 << 10) | (1004 << 0));
321 } else if (height == 1080) {
322 val = MXR_CFG_RGB709_16_235;
323 mixer_reg_write(res, MXR_CM_COEFF_Y,
324 (1 << 30) | (94 << 20) | (314 << 10) |
325 (32 << 0));
326 mixer_reg_write(res, MXR_CM_COEFF_CB,
327 (972 << 20) | (851 << 10) | (225 << 0));
328 mixer_reg_write(res, MXR_CM_COEFF_CR,
329 (225 << 20) | (820 << 10) | (1004 << 0));
330 } else {
331 val = MXR_CFG_RGB709_16_235;
332 mixer_reg_write(res, MXR_CM_COEFF_Y,
333 (1 << 30) | (94 << 20) | (314 << 10) |
334 (32 << 0));
335 mixer_reg_write(res, MXR_CM_COEFF_CB,
336 (972 << 20) | (851 << 10) | (225 << 0));
337 mixer_reg_write(res, MXR_CM_COEFF_CR,
338 (225 << 20) | (820 << 10) | (1004 << 0));
339 }
340
341 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
342}
343
344static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable)
345{
346 struct mixer_resources *res = &ctx->mixer_res;
347 u32 val = enable ? ~0 : 0;
348
349 switch (win) {
350 case 0:
351 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
352 break;
353 case 1:
354 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
355 break;
356 case 2:
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530357 if (ctx->vp_enabled) {
358 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
359 mixer_reg_writemask(res, MXR_CFG, val,
360 MXR_CFG_VP_ENABLE);
361 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900362 break;
363 }
364}
365
366static void mixer_run(struct mixer_context *ctx)
367{
368 struct mixer_resources *res = &ctx->mixer_res;
369
370 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
371
372 mixer_regs_dump(ctx);
373}
374
375static void vp_video_buffer(struct mixer_context *ctx, int win)
376{
377 struct mixer_resources *res = &ctx->mixer_res;
378 unsigned long flags;
379 struct hdmi_win_data *win_data;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900380 unsigned int x_ratio, y_ratio;
YoungJun Cho782953e2013-07-01 13:04:12 +0900381 unsigned int buf_num = 1;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900382 dma_addr_t luma_addr[2], chroma_addr[2];
383 bool tiled_mode = false;
384 bool crcb_mode = false;
385 u32 val;
386
387 win_data = &ctx->win_data[win];
388
389 switch (win_data->pixel_format) {
390 case DRM_FORMAT_NV12MT:
391 tiled_mode = true;
Ville Syrjälä363b06a2012-05-14 11:08:51 +0900392 case DRM_FORMAT_NV12:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900393 crcb_mode = false;
394 buf_num = 2;
395 break;
396 /* TODO: single buffer format NV12, NV21 */
397 default:
398 /* ignore pixel format at disable time */
399 if (!win_data->dma_addr)
400 break;
401
402 DRM_ERROR("pixel format for vp is wrong [%d].\n",
403 win_data->pixel_format);
404 return;
405 }
406
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900407 /* scaling feature: (src << 16) / dst */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900408 x_ratio = (win_data->src_width << 16) / win_data->crtc_width;
409 y_ratio = (win_data->src_height << 16) / win_data->crtc_height;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900410
411 if (buf_num == 2) {
412 luma_addr[0] = win_data->dma_addr;
413 chroma_addr[0] = win_data->chroma_dma_addr;
414 } else {
415 luma_addr[0] = win_data->dma_addr;
416 chroma_addr[0] = win_data->dma_addr
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900417 + (win_data->fb_width * win_data->fb_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900418 }
419
420 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) {
421 ctx->interlace = true;
422 if (tiled_mode) {
423 luma_addr[1] = luma_addr[0] + 0x40;
424 chroma_addr[1] = chroma_addr[0] + 0x40;
425 } else {
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900426 luma_addr[1] = luma_addr[0] + win_data->fb_width;
427 chroma_addr[1] = chroma_addr[0] + win_data->fb_width;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900428 }
429 } else {
430 ctx->interlace = false;
431 luma_addr[1] = 0;
432 chroma_addr[1] = 0;
433 }
434
435 spin_lock_irqsave(&res->reg_slock, flags);
436 mixer_vsync_set_update(ctx, false);
437
438 /* interlace or progressive scan mode */
439 val = (ctx->interlace ? ~0 : 0);
440 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
441
442 /* setup format */
443 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
444 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
445 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
446
447 /* setting size of input image */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900448 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_width) |
449 VP_IMG_VSIZE(win_data->fb_height));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900450 /* chroma height has to reduced by 2 to avoid chroma distorions */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900451 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(win_data->fb_width) |
452 VP_IMG_VSIZE(win_data->fb_height / 2));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900453
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900454 vp_reg_write(res, VP_SRC_WIDTH, win_data->src_width);
455 vp_reg_write(res, VP_SRC_HEIGHT, win_data->src_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900456 vp_reg_write(res, VP_SRC_H_POSITION,
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900457 VP_SRC_H_POSITION_VAL(win_data->fb_x));
458 vp_reg_write(res, VP_SRC_V_POSITION, win_data->fb_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900459
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900460 vp_reg_write(res, VP_DST_WIDTH, win_data->crtc_width);
461 vp_reg_write(res, VP_DST_H_POSITION, win_data->crtc_x);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900462 if (ctx->interlace) {
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900463 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height / 2);
464 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y / 2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900465 } else {
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900466 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height);
467 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900468 }
469
470 vp_reg_write(res, VP_H_RATIO, x_ratio);
471 vp_reg_write(res, VP_V_RATIO, y_ratio);
472
473 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
474
475 /* set buffer address to vp */
476 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
477 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
478 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
479 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
480
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900481 mixer_cfg_scan(ctx, win_data->mode_height);
482 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900483 mixer_cfg_layer(ctx, win, true);
484 mixer_run(ctx);
485
486 mixer_vsync_set_update(ctx, true);
487 spin_unlock_irqrestore(&res->reg_slock, flags);
488
489 vp_regs_dump(ctx);
490}
491
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530492static void mixer_layer_update(struct mixer_context *ctx)
493{
494 struct mixer_resources *res = &ctx->mixer_res;
495 u32 val;
496
497 val = mixer_reg_read(res, MXR_CFG);
498
499 /* allow one update per vsync only */
500 if (!(val & MXR_CFG_LAYER_UPDATE_COUNT_MASK))
501 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
502}
503
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900504static void mixer_graph_buffer(struct mixer_context *ctx, int win)
505{
506 struct mixer_resources *res = &ctx->mixer_res;
507 unsigned long flags;
508 struct hdmi_win_data *win_data;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900509 unsigned int x_ratio, y_ratio;
510 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900511 dma_addr_t dma_addr;
512 unsigned int fmt;
513 u32 val;
514
515 win_data = &ctx->win_data[win];
516
517 #define RGB565 4
518 #define ARGB1555 5
519 #define ARGB4444 6
520 #define ARGB8888 7
521
522 switch (win_data->bpp) {
523 case 16:
524 fmt = ARGB4444;
525 break;
526 case 32:
527 fmt = ARGB8888;
528 break;
529 default:
530 fmt = ARGB8888;
531 }
532
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900533 /* 2x scaling feature */
534 x_ratio = 0;
535 y_ratio = 0;
536
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900537 dst_x_offset = win_data->crtc_x;
538 dst_y_offset = win_data->crtc_y;
539
540 /* converting dma address base and source offset */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900541 dma_addr = win_data->dma_addr
542 + (win_data->fb_x * win_data->bpp >> 3)
543 + (win_data->fb_y * win_data->fb_width * win_data->bpp >> 3);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900544 src_x_offset = 0;
545 src_y_offset = 0;
546
547 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE)
548 ctx->interlace = true;
549 else
550 ctx->interlace = false;
551
552 spin_lock_irqsave(&res->reg_slock, flags);
553 mixer_vsync_set_update(ctx, false);
554
555 /* setup format */
556 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
557 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
558
559 /* setup geometry */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900560 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), win_data->fb_width);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900561
Rahul Sharmadef5e092013-06-19 18:21:08 +0530562 /* setup display size */
563 if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
564 win == MIXER_DEFAULT_WIN) {
565 val = MXR_MXR_RES_HEIGHT(win_data->fb_height);
566 val |= MXR_MXR_RES_WIDTH(win_data->fb_width);
567 mixer_reg_write(res, MXR_RESOLUTION, val);
568 }
569
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900570 val = MXR_GRP_WH_WIDTH(win_data->crtc_width);
571 val |= MXR_GRP_WH_HEIGHT(win_data->crtc_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900572 val |= MXR_GRP_WH_H_SCALE(x_ratio);
573 val |= MXR_GRP_WH_V_SCALE(y_ratio);
574 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
575
576 /* setup offsets in source image */
577 val = MXR_GRP_SXY_SX(src_x_offset);
578 val |= MXR_GRP_SXY_SY(src_y_offset);
579 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
580
581 /* setup offsets in display image */
582 val = MXR_GRP_DXY_DX(dst_x_offset);
583 val |= MXR_GRP_DXY_DY(dst_y_offset);
584 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
585
586 /* set buffer address to mixer */
587 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
588
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900589 mixer_cfg_scan(ctx, win_data->mode_height);
590 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900591 mixer_cfg_layer(ctx, win, true);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530592
593 /* layer update mandatory for mixer 16.0.33.0 */
Rahul Sharmadef5e092013-06-19 18:21:08 +0530594 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
595 ctx->mxr_ver == MXR_VER_128_0_0_184)
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530596 mixer_layer_update(ctx);
597
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900598 mixer_run(ctx);
599
600 mixer_vsync_set_update(ctx, true);
601 spin_unlock_irqrestore(&res->reg_slock, flags);
602}
603
604static void vp_win_reset(struct mixer_context *ctx)
605{
606 struct mixer_resources *res = &ctx->mixer_res;
607 int tries = 100;
608
609 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
610 for (tries = 100; tries; --tries) {
611 /* waiting until VP_SRESET_PROCESSING is 0 */
612 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
613 break;
Sean Paul09760ea2013-01-14 17:03:20 -0500614 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900615 }
616 WARN(tries == 0, "failed to reset Video Processor\n");
617}
618
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900619static void mixer_win_reset(struct mixer_context *ctx)
620{
621 struct mixer_resources *res = &ctx->mixer_res;
622 unsigned long flags;
623 u32 val; /* value stored to register */
624
625 spin_lock_irqsave(&res->reg_slock, flags);
626 mixer_vsync_set_update(ctx, false);
627
628 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
629
630 /* set output in RGB888 mode */
631 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
632
633 /* 16 beat burst in DMA */
634 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
635 MXR_STATUS_BURST_MASK);
636
637 /* setting default layer priority: layer1 > layer0 > video
638 * because typical usage scenario would be
639 * layer1 - OSD
640 * layer0 - framebuffer
641 * video - video overlay
642 */
643 val = MXR_LAYER_CFG_GRP1_VAL(3);
644 val |= MXR_LAYER_CFG_GRP0_VAL(2);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530645 if (ctx->vp_enabled)
646 val |= MXR_LAYER_CFG_VP_VAL(1);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900647 mixer_reg_write(res, MXR_LAYER_CFG, val);
648
649 /* setting background color */
650 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
651 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
652 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
653
654 /* setting graphical layers */
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900655 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
656 val |= MXR_GRP_CFG_WIN_BLEND_EN;
657 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
658
Sean Paul0377f4e2013-04-25 15:13:26 -0400659 /* Don't blend layer 0 onto the mixer background */
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900660 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
Sean Paul0377f4e2013-04-25 15:13:26 -0400661
662 /* Blend layer 1 into layer 0 */
663 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
664 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900665 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
666
Seung-Woo Kim57366032012-05-15 17:22:08 +0900667 /* setting video layers */
668 val = MXR_GRP_CFG_ALPHA_VAL(0);
669 mixer_reg_write(res, MXR_VIDEO_CFG, val);
670
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530671 if (ctx->vp_enabled) {
672 /* configuration of Video Processor Registers */
673 vp_win_reset(ctx);
674 vp_default_filter(res);
675 }
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900676
677 /* disable all layers */
678 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
679 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530680 if (ctx->vp_enabled)
681 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900682
683 mixer_vsync_set_update(ctx, true);
684 spin_unlock_irqrestore(&res->reg_slock, flags);
685}
686
Inki Dae1055b392012-10-19 17:37:35 +0900687static int mixer_iommu_on(void *ctx, bool enable)
688{
689 struct exynos_drm_hdmi_context *drm_hdmi_ctx;
690 struct mixer_context *mdata = ctx;
691 struct drm_device *drm_dev;
692
693 drm_hdmi_ctx = mdata->parent_ctx;
694 drm_dev = drm_hdmi_ctx->drm_dev;
695
696 if (is_drm_iommu_supported(drm_dev)) {
697 if (enable)
698 return drm_iommu_attach_device(drm_dev, mdata->dev);
699
700 drm_iommu_detach_device(drm_dev, mdata->dev);
701 }
702 return 0;
703}
704
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900705static int mixer_enable_vblank(void *ctx, int pipe)
706{
707 struct mixer_context *mixer_ctx = ctx;
708 struct mixer_resources *res = &mixer_ctx->mixer_res;
709
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900710 mixer_ctx->pipe = pipe;
711
712 /* enable vsync interrupt */
713 mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
714 MXR_INT_EN_VSYNC);
715
716 return 0;
717}
718
719static void mixer_disable_vblank(void *ctx)
720{
721 struct mixer_context *mixer_ctx = ctx;
722 struct mixer_resources *res = &mixer_ctx->mixer_res;
723
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900724 /* disable vsync interrupt */
725 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
726}
727
728static void mixer_win_mode_set(void *ctx,
729 struct exynos_drm_overlay *overlay)
730{
731 struct mixer_context *mixer_ctx = ctx;
732 struct hdmi_win_data *win_data;
733 int win;
734
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900735 if (!overlay) {
736 DRM_ERROR("overlay is NULL\n");
737 return;
738 }
739
740 DRM_DEBUG_KMS("set [%d]x[%d] at (%d,%d) to [%d]x[%d] at (%d,%d)\n",
741 overlay->fb_width, overlay->fb_height,
742 overlay->fb_x, overlay->fb_y,
743 overlay->crtc_width, overlay->crtc_height,
744 overlay->crtc_x, overlay->crtc_y);
745
746 win = overlay->zpos;
747 if (win == DEFAULT_ZPOS)
Joonyoung Shima2ee1512012-04-05 20:49:25 +0900748 win = MIXER_DEFAULT_WIN;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900749
Krzysztof Kozlowski1586d802013-05-27 15:00:43 +0900750 if (win < 0 || win >= MIXER_WIN_NR) {
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900751 DRM_ERROR("mixer window[%d] is wrong\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900752 return;
753 }
754
755 win_data = &mixer_ctx->win_data[win];
756
757 win_data->dma_addr = overlay->dma_addr[0];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900758 win_data->chroma_dma_addr = overlay->dma_addr[1];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900759 win_data->pixel_format = overlay->pixel_format;
760 win_data->bpp = overlay->bpp;
761
762 win_data->crtc_x = overlay->crtc_x;
763 win_data->crtc_y = overlay->crtc_y;
764 win_data->crtc_width = overlay->crtc_width;
765 win_data->crtc_height = overlay->crtc_height;
766
767 win_data->fb_x = overlay->fb_x;
768 win_data->fb_y = overlay->fb_y;
769 win_data->fb_width = overlay->fb_width;
770 win_data->fb_height = overlay->fb_height;
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900771 win_data->src_width = overlay->src_width;
772 win_data->src_height = overlay->src_height;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900773
774 win_data->mode_width = overlay->mode_width;
775 win_data->mode_height = overlay->mode_height;
776
777 win_data->scan_flags = overlay->scan_flag;
778}
779
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900780static void mixer_win_commit(void *ctx, int win)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900781{
782 struct mixer_context *mixer_ctx = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900783
YoungJun Chocbc4c332013-06-12 10:44:40 +0900784 DRM_DEBUG_KMS("win: %d\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900785
Shirish Sdda90122013-01-23 22:03:18 -0500786 mutex_lock(&mixer_ctx->mixer_mutex);
787 if (!mixer_ctx->powered) {
788 mutex_unlock(&mixer_ctx->mixer_mutex);
789 return;
790 }
791 mutex_unlock(&mixer_ctx->mixer_mutex);
792
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530793 if (win > 1 && mixer_ctx->vp_enabled)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900794 vp_video_buffer(mixer_ctx, win);
795 else
796 mixer_graph_buffer(mixer_ctx, win);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530797
798 mixer_ctx->win_data[win].enabled = true;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900799}
800
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900801static void mixer_win_disable(void *ctx, int win)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900802{
803 struct mixer_context *mixer_ctx = ctx;
804 struct mixer_resources *res = &mixer_ctx->mixer_res;
805 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900806
YoungJun Chocbc4c332013-06-12 10:44:40 +0900807 DRM_DEBUG_KMS("win: %d\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900808
Prathyush Kdb43fd12012-12-06 20:16:05 +0530809 mutex_lock(&mixer_ctx->mixer_mutex);
810 if (!mixer_ctx->powered) {
811 mutex_unlock(&mixer_ctx->mixer_mutex);
812 mixer_ctx->win_data[win].resume = false;
813 return;
814 }
815 mutex_unlock(&mixer_ctx->mixer_mutex);
816
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900817 spin_lock_irqsave(&res->reg_slock, flags);
818 mixer_vsync_set_update(mixer_ctx, false);
819
820 mixer_cfg_layer(mixer_ctx, win, false);
821
822 mixer_vsync_set_update(mixer_ctx, true);
823 spin_unlock_irqrestore(&res->reg_slock, flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530824
825 mixer_ctx->win_data[win].enabled = false;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900826}
827
Rahul Sharma16844fb2013-06-10 14:50:00 +0530828static int mixer_check_mode(void *ctx, struct drm_display_mode *mode)
Rahul Sharma0ea68222013-01-15 08:11:06 -0500829{
Rahul Sharmadef5e092013-06-19 18:21:08 +0530830 struct mixer_context *mixer_ctx = ctx;
Rahul Sharma0ea68222013-01-15 08:11:06 -0500831 u32 w, h;
832
Rahul Sharma16844fb2013-06-10 14:50:00 +0530833 w = mode->hdisplay;
834 h = mode->vdisplay;
Rahul Sharma0ea68222013-01-15 08:11:06 -0500835
Rahul Sharma16844fb2013-06-10 14:50:00 +0530836 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
837 mode->hdisplay, mode->vdisplay, mode->vrefresh,
838 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
Rahul Sharma0ea68222013-01-15 08:11:06 -0500839
Rahul Sharmadef5e092013-06-19 18:21:08 +0530840 if (mixer_ctx->mxr_ver == MXR_VER_0_0_0_16 ||
841 mixer_ctx->mxr_ver == MXR_VER_128_0_0_184)
842 return 0;
843
Rahul Sharma0ea68222013-01-15 08:11:06 -0500844 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
845 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
846 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
847 return 0;
848
849 return -EINVAL;
850}
Prathyush K8137a2e2012-12-06 20:16:01 +0530851static void mixer_wait_for_vblank(void *ctx)
852{
853 struct mixer_context *mixer_ctx = ctx;
Prathyush K8137a2e2012-12-06 20:16:01 +0530854
Prathyush K6e95d5e2012-12-06 20:16:03 +0530855 mutex_lock(&mixer_ctx->mixer_mutex);
856 if (!mixer_ctx->powered) {
857 mutex_unlock(&mixer_ctx->mixer_mutex);
858 return;
859 }
860 mutex_unlock(&mixer_ctx->mixer_mutex);
861
862 atomic_set(&mixer_ctx->wait_vsync_event, 1);
863
864 /*
865 * wait for MIXER to signal VSYNC interrupt or return after
866 * timeout which is set to 50ms (refresh rate of 20).
867 */
868 if (!wait_event_timeout(mixer_ctx->wait_vsync_queue,
869 !atomic_read(&mixer_ctx->wait_vsync_event),
870 DRM_HZ/20))
Prathyush K8137a2e2012-12-06 20:16:01 +0530871 DRM_DEBUG_KMS("vblank wait timed out.\n");
872}
873
Prathyush Kdb43fd12012-12-06 20:16:05 +0530874static void mixer_window_suspend(struct mixer_context *ctx)
875{
876 struct hdmi_win_data *win_data;
877 int i;
878
879 for (i = 0; i < MIXER_WIN_NR; i++) {
880 win_data = &ctx->win_data[i];
881 win_data->resume = win_data->enabled;
882 mixer_win_disable(ctx, i);
883 }
884 mixer_wait_for_vblank(ctx);
885}
886
887static void mixer_window_resume(struct mixer_context *ctx)
888{
889 struct hdmi_win_data *win_data;
890 int i;
891
892 for (i = 0; i < MIXER_WIN_NR; i++) {
893 win_data = &ctx->win_data[i];
894 win_data->enabled = win_data->resume;
895 win_data->resume = false;
896 }
897}
898
899static void mixer_poweron(struct mixer_context *ctx)
900{
901 struct mixer_resources *res = &ctx->mixer_res;
902
Prathyush Kdb43fd12012-12-06 20:16:05 +0530903 mutex_lock(&ctx->mixer_mutex);
904 if (ctx->powered) {
905 mutex_unlock(&ctx->mixer_mutex);
906 return;
907 }
908 ctx->powered = true;
909 mutex_unlock(&ctx->mixer_mutex);
910
Sean Paul0bfb1f82013-06-11 12:24:02 +0530911 clk_prepare_enable(res->mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530912 if (ctx->vp_enabled) {
Sean Paul0bfb1f82013-06-11 12:24:02 +0530913 clk_prepare_enable(res->vp);
914 clk_prepare_enable(res->sclk_mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530915 }
916
917 mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
918 mixer_win_reset(ctx);
919
920 mixer_window_resume(ctx);
921}
922
923static void mixer_poweroff(struct mixer_context *ctx)
924{
925 struct mixer_resources *res = &ctx->mixer_res;
926
Prathyush Kdb43fd12012-12-06 20:16:05 +0530927 mutex_lock(&ctx->mixer_mutex);
928 if (!ctx->powered)
929 goto out;
930 mutex_unlock(&ctx->mixer_mutex);
931
932 mixer_window_suspend(ctx);
933
934 ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
935
Sean Paul0bfb1f82013-06-11 12:24:02 +0530936 clk_disable_unprepare(res->mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530937 if (ctx->vp_enabled) {
Sean Paul0bfb1f82013-06-11 12:24:02 +0530938 clk_disable_unprepare(res->vp);
939 clk_disable_unprepare(res->sclk_mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530940 }
941
Prathyush Kdb43fd12012-12-06 20:16:05 +0530942 mutex_lock(&ctx->mixer_mutex);
943 ctx->powered = false;
944
945out:
946 mutex_unlock(&ctx->mixer_mutex);
947}
948
949static void mixer_dpms(void *ctx, int mode)
950{
951 struct mixer_context *mixer_ctx = ctx;
952
Prathyush Kdb43fd12012-12-06 20:16:05 +0530953 switch (mode) {
954 case DRM_MODE_DPMS_ON:
Rahul Sharma000f1302012-11-28 11:30:24 +0530955 if (pm_runtime_suspended(mixer_ctx->dev))
956 pm_runtime_get_sync(mixer_ctx->dev);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530957 break;
958 case DRM_MODE_DPMS_STANDBY:
959 case DRM_MODE_DPMS_SUSPEND:
960 case DRM_MODE_DPMS_OFF:
Rahul Sharma000f1302012-11-28 11:30:24 +0530961 if (!pm_runtime_suspended(mixer_ctx->dev))
962 pm_runtime_put_sync(mixer_ctx->dev);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530963 break;
964 default:
965 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
966 break;
967 }
968}
969
Joonyoung Shim578b6062012-04-05 20:49:26 +0900970static struct exynos_mixer_ops mixer_ops = {
971 /* manager */
Inki Dae1055b392012-10-19 17:37:35 +0900972 .iommu_on = mixer_iommu_on,
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900973 .enable_vblank = mixer_enable_vblank,
974 .disable_vblank = mixer_disable_vblank,
Prathyush K8137a2e2012-12-06 20:16:01 +0530975 .wait_for_vblank = mixer_wait_for_vblank,
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900976 .dpms = mixer_dpms,
Joonyoung Shim578b6062012-04-05 20:49:26 +0900977
978 /* overlay */
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900979 .win_mode_set = mixer_win_mode_set,
980 .win_commit = mixer_win_commit,
981 .win_disable = mixer_win_disable,
Rahul Sharma0ea68222013-01-15 08:11:06 -0500982
983 /* display */
Rahul Sharma16844fb2013-06-10 14:50:00 +0530984 .check_mode = mixer_check_mode,
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900985};
986
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900987static irqreturn_t mixer_irq_handler(int irq, void *arg)
988{
989 struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg;
Joonyoung Shimf9309d12012-04-05 20:49:22 +0900990 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900991 struct mixer_resources *res = &ctx->mixer_res;
Seung-Woo Kim8379e482012-04-23 20:30:13 +0900992 u32 val, base, shadow;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900993
994 spin_lock(&res->reg_slock);
995
996 /* read interrupt status for handling and clearing flags for VSYNC */
997 val = mixer_reg_read(res, MXR_INT_STATUS);
998
999 /* handling VSYNC */
1000 if (val & MXR_INT_STATUS_VSYNC) {
1001 /* interlace scan need to check shadow register */
1002 if (ctx->interlace) {
Seung-Woo Kim8379e482012-04-23 20:30:13 +09001003 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
1004 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
1005 if (base != shadow)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001006 goto out;
1007
Seung-Woo Kim8379e482012-04-23 20:30:13 +09001008 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
1009 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
1010 if (base != shadow)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001011 goto out;
1012 }
1013
1014 drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe);
Rahul Sharma663d8762013-01-03 05:44:04 -05001015 exynos_drm_crtc_finish_pageflip(drm_hdmi_ctx->drm_dev,
1016 ctx->pipe);
Prathyush K6e95d5e2012-12-06 20:16:03 +05301017
1018 /* set wait vsync event to zero and wake up queue. */
1019 if (atomic_read(&ctx->wait_vsync_event)) {
1020 atomic_set(&ctx->wait_vsync_event, 0);
1021 DRM_WAKEUP(&ctx->wait_vsync_queue);
1022 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001023 }
1024
1025out:
1026 /* clear interrupts */
1027 if (~val & MXR_INT_EN_VSYNC) {
1028 /* vsync interrupt use different bit for read and clear */
1029 val &= ~MXR_INT_EN_VSYNC;
1030 val |= MXR_INT_CLEAR_VSYNC;
1031 }
1032 mixer_reg_write(res, MXR_INT_STATUS, val);
1033
1034 spin_unlock(&res->reg_slock);
1035
1036 return IRQ_HANDLED;
1037}
1038
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001039static int mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
1040 struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001041{
Joonyoung Shimf9309d12012-04-05 20:49:22 +09001042 struct mixer_context *mixer_ctx = ctx->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001043 struct device *dev = &pdev->dev;
1044 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
1045 struct resource *res;
1046 int ret;
1047
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001048 spin_lock_init(&mixer_res->reg_slock);
1049
Sachin Kamat37f50862012-11-23 14:13:26 +05301050 mixer_res->mixer = devm_clk_get(dev, "mixer");
Sachin Kamatc11182d2013-03-21 15:33:58 +05301051 if (IS_ERR(mixer_res->mixer)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001052 dev_err(dev, "failed to get clock 'mixer'\n");
Sachin Kamat37f50862012-11-23 14:13:26 +05301053 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001054 }
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301055
Sachin Kamat37f50862012-11-23 14:13:26 +05301056 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatc11182d2013-03-21 15:33:58 +05301057 if (IS_ERR(mixer_res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001058 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
Sachin Kamat37f50862012-11-23 14:13:26 +05301059 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001060 }
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301061 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001062 if (res == NULL) {
1063 dev_err(dev, "get memory resource failed.\n");
Sachin Kamat37f50862012-11-23 14:13:26 +05301064 return -ENXIO;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001065 }
1066
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001067 mixer_res->mixer_regs = devm_ioremap(dev, res->start,
Sachin Kamat9416dfa2012-06-19 11:47:41 +05301068 resource_size(res));
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001069 if (mixer_res->mixer_regs == NULL) {
1070 dev_err(dev, "register mapping failed.\n");
Sachin Kamat37f50862012-11-23 14:13:26 +05301071 return -ENXIO;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001072 }
1073
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301074 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001075 if (res == NULL) {
1076 dev_err(dev, "get interrupt resource failed.\n");
Sachin Kamat37f50862012-11-23 14:13:26 +05301077 return -ENXIO;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001078 }
1079
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001080 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
Sachin Kamat9416dfa2012-06-19 11:47:41 +05301081 0, "drm_mixer", ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001082 if (ret) {
1083 dev_err(dev, "request interrupt failed.\n");
Sachin Kamat37f50862012-11-23 14:13:26 +05301084 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001085 }
1086 mixer_res->irq = res->start;
1087
1088 return 0;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001089}
1090
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001091static int vp_resources_init(struct exynos_drm_hdmi_context *ctx,
1092 struct platform_device *pdev)
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301093{
1094 struct mixer_context *mixer_ctx = ctx->ctx;
1095 struct device *dev = &pdev->dev;
1096 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
1097 struct resource *res;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301098
Sachin Kamat37f50862012-11-23 14:13:26 +05301099 mixer_res->vp = devm_clk_get(dev, "vp");
Sachin Kamatc11182d2013-03-21 15:33:58 +05301100 if (IS_ERR(mixer_res->vp)) {
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301101 dev_err(dev, "failed to get clock 'vp'\n");
Sachin Kamat37f50862012-11-23 14:13:26 +05301102 return -ENODEV;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301103 }
Sachin Kamat37f50862012-11-23 14:13:26 +05301104 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
Sachin Kamatc11182d2013-03-21 15:33:58 +05301105 if (IS_ERR(mixer_res->sclk_mixer)) {
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301106 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
Sachin Kamat37f50862012-11-23 14:13:26 +05301107 return -ENODEV;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301108 }
Sachin Kamat37f50862012-11-23 14:13:26 +05301109 mixer_res->sclk_dac = devm_clk_get(dev, "sclk_dac");
Sachin Kamatc11182d2013-03-21 15:33:58 +05301110 if (IS_ERR(mixer_res->sclk_dac)) {
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301111 dev_err(dev, "failed to get clock 'sclk_dac'\n");
Sachin Kamat37f50862012-11-23 14:13:26 +05301112 return -ENODEV;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301113 }
1114
1115 if (mixer_res->sclk_hdmi)
1116 clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
1117
1118 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
1119 if (res == NULL) {
1120 dev_err(dev, "get memory resource failed.\n");
Sachin Kamat37f50862012-11-23 14:13:26 +05301121 return -ENXIO;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301122 }
1123
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001124 mixer_res->vp_regs = devm_ioremap(dev, res->start,
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301125 resource_size(res));
1126 if (mixer_res->vp_regs == NULL) {
1127 dev_err(dev, "register mapping failed.\n");
Sachin Kamat37f50862012-11-23 14:13:26 +05301128 return -ENXIO;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301129 }
1130
1131 return 0;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301132}
1133
Rahul Sharmadef5e092013-06-19 18:21:08 +05301134static struct mixer_drv_data exynos5420_mxr_drv_data = {
1135 .version = MXR_VER_128_0_0_184,
1136 .is_vp_enabled = 0,
1137};
1138
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301139static struct mixer_drv_data exynos5250_mxr_drv_data = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301140 .version = MXR_VER_16_0_33_0,
1141 .is_vp_enabled = 0,
1142};
1143
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301144static struct mixer_drv_data exynos4210_mxr_drv_data = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301145 .version = MXR_VER_0_0_0_16,
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301146 .is_vp_enabled = 1,
Rahul Sharma1e123442012-10-04 20:48:51 +05301147};
1148
1149static struct platform_device_id mixer_driver_types[] = {
1150 {
1151 .name = "s5p-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301152 .driver_data = (unsigned long)&exynos4210_mxr_drv_data,
Rahul Sharma1e123442012-10-04 20:48:51 +05301153 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301154 .name = "exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301155 .driver_data = (unsigned long)&exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301156 }, {
1157 /* end node */
1158 }
1159};
1160
1161static struct of_device_id mixer_match_types[] = {
1162 {
1163 .compatible = "samsung,exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301164 .data = &exynos5250_mxr_drv_data,
1165 }, {
1166 .compatible = "samsung,exynos5250-mixer",
1167 .data = &exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301168 }, {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301169 .compatible = "samsung,exynos5420-mixer",
1170 .data = &exynos5420_mxr_drv_data,
1171 }, {
Rahul Sharma1e123442012-10-04 20:48:51 +05301172 /* end node */
1173 }
1174};
1175
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001176static int mixer_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001177{
1178 struct device *dev = &pdev->dev;
1179 struct exynos_drm_hdmi_context *drm_hdmi_ctx;
1180 struct mixer_context *ctx;
Rahul Sharma1e123442012-10-04 20:48:51 +05301181 struct mixer_drv_data *drv;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001182 int ret;
1183
1184 dev_info(dev, "probe start\n");
1185
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001186 drm_hdmi_ctx = devm_kzalloc(dev, sizeof(*drm_hdmi_ctx),
Sachin Kamat9416dfa2012-06-19 11:47:41 +05301187 GFP_KERNEL);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001188 if (!drm_hdmi_ctx) {
1189 DRM_ERROR("failed to allocate common hdmi context.\n");
1190 return -ENOMEM;
1191 }
1192
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001193 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001194 if (!ctx) {
1195 DRM_ERROR("failed to alloc mixer context.\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001196 return -ENOMEM;
1197 }
1198
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001199 mutex_init(&ctx->mixer_mutex);
1200
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301201 if (dev->of_node) {
1202 const struct of_device_id *match;
Sachin Kamate436b092013-06-05 16:00:23 +09001203 match = of_match_node(mixer_match_types, dev->of_node);
Rahul Sharma2cdc53b2012-10-31 09:36:26 +05301204 drv = (struct mixer_drv_data *)match->data;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301205 } else {
1206 drv = (struct mixer_drv_data *)
1207 platform_get_device_id(pdev)->driver_data;
1208 }
1209
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001210 ctx->dev = dev;
Inki Dae1055b392012-10-19 17:37:35 +09001211 ctx->parent_ctx = (void *)drm_hdmi_ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001212 drm_hdmi_ctx->ctx = (void *)ctx;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301213 ctx->vp_enabled = drv->is_vp_enabled;
Rahul Sharma1e123442012-10-04 20:48:51 +05301214 ctx->mxr_ver = drv->version;
Prathyush K6e95d5e2012-12-06 20:16:03 +05301215 DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
1216 atomic_set(&ctx->wait_vsync_event, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001217
1218 platform_set_drvdata(pdev, drm_hdmi_ctx);
1219
1220 /* acquire resources: regs, irqs, clocks */
1221 ret = mixer_resources_init(drm_hdmi_ctx, pdev);
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301222 if (ret) {
1223 DRM_ERROR("mixer_resources_init failed\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001224 goto fail;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301225 }
1226
1227 if (ctx->vp_enabled) {
1228 /* acquire vp resources: regs, irqs, clocks */
1229 ret = vp_resources_init(drm_hdmi_ctx, pdev);
1230 if (ret) {
1231 DRM_ERROR("vp_resources_init failed\n");
1232 goto fail;
1233 }
1234 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001235
Rahul Sharma768c3052012-10-04 20:48:56 +05301236 /* attach mixer driver to common hdmi. */
1237 exynos_mixer_drv_attach(drm_hdmi_ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001238
1239 /* register specific callback point to common hdmi. */
Joonyoung Shim578b6062012-04-05 20:49:26 +09001240 exynos_mixer_ops_register(&mixer_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001241
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001242 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001243
1244 return 0;
1245
1246
1247fail:
1248 dev_info(dev, "probe failed\n");
1249 return ret;
1250}
1251
1252static int mixer_remove(struct platform_device *pdev)
1253{
Sachin Kamat9416dfa2012-06-19 11:47:41 +05301254 dev_info(&pdev->dev, "remove successful\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001255
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001256 pm_runtime_disable(&pdev->dev);
1257
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001258 return 0;
1259}
1260
Joonyoung Shimab27af82012-04-23 19:35:51 +09001261#ifdef CONFIG_PM_SLEEP
1262static int mixer_suspend(struct device *dev)
1263{
1264 struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
1265 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
1266
Rahul Sharma000f1302012-11-28 11:30:24 +05301267 if (pm_runtime_suspended(dev)) {
YoungJun Chocbc4c332013-06-12 10:44:40 +09001268 DRM_DEBUG_KMS("Already suspended\n");
Rahul Sharma000f1302012-11-28 11:30:24 +05301269 return 0;
1270 }
1271
Joonyoung Shimab27af82012-04-23 19:35:51 +09001272 mixer_poweroff(ctx);
1273
1274 return 0;
1275}
Rahul Sharma000f1302012-11-28 11:30:24 +05301276
1277static int mixer_resume(struct device *dev)
1278{
1279 struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
1280 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
1281
Rahul Sharma000f1302012-11-28 11:30:24 +05301282 if (!pm_runtime_suspended(dev)) {
YoungJun Chocbc4c332013-06-12 10:44:40 +09001283 DRM_DEBUG_KMS("Already resumed\n");
Rahul Sharma000f1302012-11-28 11:30:24 +05301284 return 0;
1285 }
1286
1287 mixer_poweron(ctx);
1288
1289 return 0;
1290}
Joonyoung Shimab27af82012-04-23 19:35:51 +09001291#endif
1292
Rahul Sharma000f1302012-11-28 11:30:24 +05301293#ifdef CONFIG_PM_RUNTIME
1294static int mixer_runtime_suspend(struct device *dev)
1295{
1296 struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
1297 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
1298
Rahul Sharma000f1302012-11-28 11:30:24 +05301299 mixer_poweroff(ctx);
1300
1301 return 0;
1302}
1303
1304static int mixer_runtime_resume(struct device *dev)
1305{
1306 struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
1307 struct mixer_context *ctx = drm_hdmi_ctx->ctx;
1308
Rahul Sharma000f1302012-11-28 11:30:24 +05301309 mixer_poweron(ctx);
1310
1311 return 0;
1312}
1313#endif
1314
1315static const struct dev_pm_ops mixer_pm_ops = {
1316 SET_SYSTEM_SLEEP_PM_OPS(mixer_suspend, mixer_resume)
1317 SET_RUNTIME_PM_OPS(mixer_runtime_suspend, mixer_runtime_resume, NULL)
1318};
Joonyoung Shimab27af82012-04-23 19:35:51 +09001319
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001320struct platform_driver mixer_driver = {
1321 .driver = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301322 .name = "exynos-mixer",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001323 .owner = THIS_MODULE,
Joonyoung Shimab27af82012-04-23 19:35:51 +09001324 .pm = &mixer_pm_ops,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301325 .of_match_table = mixer_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001326 },
1327 .probe = mixer_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001328 .remove = mixer_remove,
Rahul Sharma1e123442012-10-04 20:48:51 +05301329 .id_table = mixer_driver_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001330};