blob: ed44cd4f01f7647c79eca3e3b40f79d19a82d8c9 [file] [log] [blame]
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001/*
2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
3 * Authors:
4 * Seung-Woo Kim <sw0312.kim@samsung.com>
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 *
8 * Based on drivers/media/video/s5p-tv/mixer_reg.c
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 */
16
David Howells760285e2012-10-02 18:01:07 +010017#include <drm/drmP.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090018
19#include "regs-mixer.h"
20#include "regs-vp.h"
21
22#include <linux/kernel.h>
23#include <linux/spinlock.h>
24#include <linux/wait.h>
25#include <linux/i2c.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090026#include <linux/platform_device.h>
27#include <linux/interrupt.h>
28#include <linux/irq.h>
29#include <linux/delay.h>
30#include <linux/pm_runtime.h>
31#include <linux/clk.h>
32#include <linux/regulator/consumer.h>
Sachin Kamat3f1c7812013-08-14 16:38:01 +053033#include <linux/of.h>
Inki Daef37cd5e2014-05-09 14:25:20 +090034#include <linux/component.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090035
36#include <drm/exynos_drm.h>
37
38#include "exynos_drm_drv.h"
Rahul Sharma663d8762013-01-03 05:44:04 -050039#include "exynos_drm_crtc.h"
Inki Dae1055b392012-10-19 17:37:35 +090040#include "exynos_drm_iommu.h"
Sean Paulf041b252014-01-30 16:19:15 -050041#include "exynos_mixer.h"
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090042
Sean Paulf041b252014-01-30 16:19:15 -050043#define MIXER_WIN_NR 3
44#define MIXER_DEFAULT_WIN 0
Seung-Woo Kimd8408322011-12-21 17:39:39 +090045
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090046struct hdmi_win_data {
47 dma_addr_t dma_addr;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090048 dma_addr_t chroma_dma_addr;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090049 uint32_t pixel_format;
50 unsigned int bpp;
51 unsigned int crtc_x;
52 unsigned int crtc_y;
53 unsigned int crtc_width;
54 unsigned int crtc_height;
55 unsigned int fb_x;
56 unsigned int fb_y;
57 unsigned int fb_width;
58 unsigned int fb_height;
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +090059 unsigned int src_width;
60 unsigned int src_height;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090061 unsigned int mode_width;
62 unsigned int mode_height;
63 unsigned int scan_flags;
Prathyush Kdb43fd12012-12-06 20:16:05 +053064 bool enabled;
65 bool resume;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090066};
67
68struct mixer_resources {
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090069 int irq;
70 void __iomem *mixer_regs;
71 void __iomem *vp_regs;
72 spinlock_t reg_slock;
73 struct clk *mixer;
74 struct clk *vp;
75 struct clk *sclk_mixer;
76 struct clk *sclk_hdmi;
Marek Szyprowskiff830c92014-07-01 10:10:07 +020077 struct clk *mout_mixer;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090078};
79
Rahul Sharma1e123442012-10-04 20:48:51 +053080enum mixer_version_id {
81 MXR_VER_0_0_0_16,
82 MXR_VER_16_0_33_0,
Rahul Sharmadef5e092013-06-19 18:21:08 +053083 MXR_VER_128_0_0_184,
Rahul Sharma1e123442012-10-04 20:48:51 +053084};
85
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090086struct mixer_context {
Sean Paul45517892014-01-30 16:19:05 -050087 struct platform_device *pdev;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090088 struct device *dev;
Inki Dae1055b392012-10-19 17:37:35 +090089 struct drm_device *drm_dev;
Gustavo Padovan93bca242015-01-18 18:16:23 +090090 struct exynos_drm_crtc *crtc;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090091 int pipe;
92 bool interlace;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090093 bool powered;
Rahul Sharma1b8e5742012-10-04 20:48:52 +053094 bool vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +020095 bool has_sclk;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090096 u32 int_en;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090097
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090098 struct mutex mixer_mutex;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090099 struct mixer_resources mixer_res;
Joonyoung Shima634dd52012-04-05 20:49:24 +0900100 struct hdmi_win_data win_data[MIXER_WIN_NR];
Rahul Sharma1e123442012-10-04 20:48:51 +0530101 enum mixer_version_id mxr_ver;
Prathyush K6e95d5e2012-12-06 20:16:03 +0530102 wait_queue_head_t wait_vsync_queue;
103 atomic_t wait_vsync_event;
Rahul Sharma1e123442012-10-04 20:48:51 +0530104};
105
106struct mixer_drv_data {
107 enum mixer_version_id version;
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530108 bool is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200109 bool has_sclk;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +0900110};
111
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900112static const u8 filter_y_horiz_tap8[] = {
113 0, -1, -1, -1, -1, -1, -1, -1,
114 -1, -1, -1, -1, -1, 0, 0, 0,
115 0, 2, 4, 5, 6, 6, 6, 6,
116 6, 5, 5, 4, 3, 2, 1, 1,
117 0, -6, -12, -16, -18, -20, -21, -20,
118 -20, -18, -16, -13, -10, -8, -5, -2,
119 127, 126, 125, 121, 114, 107, 99, 89,
120 79, 68, 57, 46, 35, 25, 16, 8,
121};
122
123static const u8 filter_y_vert_tap4[] = {
124 0, -3, -6, -8, -8, -8, -8, -7,
125 -6, -5, -4, -3, -2, -1, -1, 0,
126 127, 126, 124, 118, 111, 102, 92, 81,
127 70, 59, 48, 37, 27, 19, 11, 5,
128 0, 5, 11, 19, 27, 37, 48, 59,
129 70, 81, 92, 102, 111, 118, 124, 126,
130 0, 0, -1, -1, -2, -3, -4, -5,
131 -6, -7, -8, -8, -8, -8, -6, -3,
132};
133
134static const u8 filter_cr_horiz_tap4[] = {
135 0, -3, -6, -8, -8, -8, -8, -7,
136 -6, -5, -4, -3, -2, -1, -1, 0,
137 127, 126, 124, 118, 111, 102, 92, 81,
138 70, 59, 48, 37, 27, 19, 11, 5,
139};
140
141static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
142{
143 return readl(res->vp_regs + reg_id);
144}
145
146static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
147 u32 val)
148{
149 writel(val, res->vp_regs + reg_id);
150}
151
152static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
153 u32 val, u32 mask)
154{
155 u32 old = vp_reg_read(res, reg_id);
156
157 val = (val & mask) | (old & ~mask);
158 writel(val, res->vp_regs + reg_id);
159}
160
161static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
162{
163 return readl(res->mixer_regs + reg_id);
164}
165
166static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
167 u32 val)
168{
169 writel(val, res->mixer_regs + reg_id);
170}
171
172static inline void mixer_reg_writemask(struct mixer_resources *res,
173 u32 reg_id, u32 val, u32 mask)
174{
175 u32 old = mixer_reg_read(res, reg_id);
176
177 val = (val & mask) | (old & ~mask);
178 writel(val, res->mixer_regs + reg_id);
179}
180
181static void mixer_regs_dump(struct mixer_context *ctx)
182{
183#define DUMPREG(reg_id) \
184do { \
185 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
186 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
187} while (0)
188
189 DUMPREG(MXR_STATUS);
190 DUMPREG(MXR_CFG);
191 DUMPREG(MXR_INT_EN);
192 DUMPREG(MXR_INT_STATUS);
193
194 DUMPREG(MXR_LAYER_CFG);
195 DUMPREG(MXR_VIDEO_CFG);
196
197 DUMPREG(MXR_GRAPHIC0_CFG);
198 DUMPREG(MXR_GRAPHIC0_BASE);
199 DUMPREG(MXR_GRAPHIC0_SPAN);
200 DUMPREG(MXR_GRAPHIC0_WH);
201 DUMPREG(MXR_GRAPHIC0_SXY);
202 DUMPREG(MXR_GRAPHIC0_DXY);
203
204 DUMPREG(MXR_GRAPHIC1_CFG);
205 DUMPREG(MXR_GRAPHIC1_BASE);
206 DUMPREG(MXR_GRAPHIC1_SPAN);
207 DUMPREG(MXR_GRAPHIC1_WH);
208 DUMPREG(MXR_GRAPHIC1_SXY);
209 DUMPREG(MXR_GRAPHIC1_DXY);
210#undef DUMPREG
211}
212
213static void vp_regs_dump(struct mixer_context *ctx)
214{
215#define DUMPREG(reg_id) \
216do { \
217 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
218 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
219} while (0)
220
221 DUMPREG(VP_ENABLE);
222 DUMPREG(VP_SRESET);
223 DUMPREG(VP_SHADOW_UPDATE);
224 DUMPREG(VP_FIELD_ID);
225 DUMPREG(VP_MODE);
226 DUMPREG(VP_IMG_SIZE_Y);
227 DUMPREG(VP_IMG_SIZE_C);
228 DUMPREG(VP_PER_RATE_CTRL);
229 DUMPREG(VP_TOP_Y_PTR);
230 DUMPREG(VP_BOT_Y_PTR);
231 DUMPREG(VP_TOP_C_PTR);
232 DUMPREG(VP_BOT_C_PTR);
233 DUMPREG(VP_ENDIAN_MODE);
234 DUMPREG(VP_SRC_H_POSITION);
235 DUMPREG(VP_SRC_V_POSITION);
236 DUMPREG(VP_SRC_WIDTH);
237 DUMPREG(VP_SRC_HEIGHT);
238 DUMPREG(VP_DST_H_POSITION);
239 DUMPREG(VP_DST_V_POSITION);
240 DUMPREG(VP_DST_WIDTH);
241 DUMPREG(VP_DST_HEIGHT);
242 DUMPREG(VP_H_RATIO);
243 DUMPREG(VP_V_RATIO);
244
245#undef DUMPREG
246}
247
248static inline void vp_filter_set(struct mixer_resources *res,
249 int reg_id, const u8 *data, unsigned int size)
250{
251 /* assure 4-byte align */
252 BUG_ON(size & 3);
253 for (; size; size -= 4, reg_id += 4, data += 4) {
254 u32 val = (data[0] << 24) | (data[1] << 16) |
255 (data[2] << 8) | data[3];
256 vp_reg_write(res, reg_id, val);
257 }
258}
259
260static void vp_default_filter(struct mixer_resources *res)
261{
262 vp_filter_set(res, VP_POLY8_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530263 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900264 vp_filter_set(res, VP_POLY4_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530265 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900266 vp_filter_set(res, VP_POLY4_C0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530267 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900268}
269
270static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
271{
272 struct mixer_resources *res = &ctx->mixer_res;
273
274 /* block update on vsync */
275 mixer_reg_writemask(res, MXR_STATUS, enable ?
276 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
277
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530278 if (ctx->vp_enabled)
279 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900280 VP_SHADOW_UPDATE_ENABLE : 0);
281}
282
283static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
284{
285 struct mixer_resources *res = &ctx->mixer_res;
286 u32 val;
287
288 /* choosing between interlace and progressive mode */
289 val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
290 MXR_CFG_SCAN_PROGRASSIVE);
291
Rahul Sharmadef5e092013-06-19 18:21:08 +0530292 if (ctx->mxr_ver != MXR_VER_128_0_0_184) {
293 /* choosing between proper HD and SD mode */
294 if (height <= 480)
295 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
296 else if (height <= 576)
297 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
298 else if (height <= 720)
299 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
300 else if (height <= 1080)
301 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
302 else
303 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
304 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900305
306 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
307}
308
309static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
310{
311 struct mixer_resources *res = &ctx->mixer_res;
312 u32 val;
313
314 if (height == 480) {
315 val = MXR_CFG_RGB601_0_255;
316 } else if (height == 576) {
317 val = MXR_CFG_RGB601_0_255;
318 } else if (height == 720) {
319 val = MXR_CFG_RGB709_16_235;
320 mixer_reg_write(res, MXR_CM_COEFF_Y,
321 (1 << 30) | (94 << 20) | (314 << 10) |
322 (32 << 0));
323 mixer_reg_write(res, MXR_CM_COEFF_CB,
324 (972 << 20) | (851 << 10) | (225 << 0));
325 mixer_reg_write(res, MXR_CM_COEFF_CR,
326 (225 << 20) | (820 << 10) | (1004 << 0));
327 } else if (height == 1080) {
328 val = MXR_CFG_RGB709_16_235;
329 mixer_reg_write(res, MXR_CM_COEFF_Y,
330 (1 << 30) | (94 << 20) | (314 << 10) |
331 (32 << 0));
332 mixer_reg_write(res, MXR_CM_COEFF_CB,
333 (972 << 20) | (851 << 10) | (225 << 0));
334 mixer_reg_write(res, MXR_CM_COEFF_CR,
335 (225 << 20) | (820 << 10) | (1004 << 0));
336 } else {
337 val = MXR_CFG_RGB709_16_235;
338 mixer_reg_write(res, MXR_CM_COEFF_Y,
339 (1 << 30) | (94 << 20) | (314 << 10) |
340 (32 << 0));
341 mixer_reg_write(res, MXR_CM_COEFF_CB,
342 (972 << 20) | (851 << 10) | (225 << 0));
343 mixer_reg_write(res, MXR_CM_COEFF_CR,
344 (225 << 20) | (820 << 10) | (1004 << 0));
345 }
346
347 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
348}
349
350static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable)
351{
352 struct mixer_resources *res = &ctx->mixer_res;
353 u32 val = enable ? ~0 : 0;
354
355 switch (win) {
356 case 0:
357 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
358 break;
359 case 1:
360 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
361 break;
362 case 2:
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530363 if (ctx->vp_enabled) {
364 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
365 mixer_reg_writemask(res, MXR_CFG, val,
366 MXR_CFG_VP_ENABLE);
Joonyoung Shimf1e716d2014-07-25 19:59:10 +0900367
368 /* control blending of graphic layer 0 */
369 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(0), val,
370 MXR_GRP_CFG_BLEND_PRE_MUL |
371 MXR_GRP_CFG_PIXEL_BLEND_EN);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530372 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900373 break;
374 }
375}
376
377static void mixer_run(struct mixer_context *ctx)
378{
379 struct mixer_resources *res = &ctx->mixer_res;
380
381 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
382
383 mixer_regs_dump(ctx);
384}
385
Rahul Sharma381be022014-06-23 11:02:22 +0530386static void mixer_stop(struct mixer_context *ctx)
387{
388 struct mixer_resources *res = &ctx->mixer_res;
389 int timeout = 20;
390
391 mixer_reg_writemask(res, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
392
393 while (!(mixer_reg_read(res, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
394 --timeout)
395 usleep_range(10000, 12000);
396
397 mixer_regs_dump(ctx);
398}
399
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900400static void vp_video_buffer(struct mixer_context *ctx, int win)
401{
402 struct mixer_resources *res = &ctx->mixer_res;
403 unsigned long flags;
404 struct hdmi_win_data *win_data;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900405 unsigned int x_ratio, y_ratio;
YoungJun Cho782953e2013-07-01 13:04:12 +0900406 unsigned int buf_num = 1;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900407 dma_addr_t luma_addr[2], chroma_addr[2];
408 bool tiled_mode = false;
409 bool crcb_mode = false;
410 u32 val;
411
412 win_data = &ctx->win_data[win];
413
414 switch (win_data->pixel_format) {
415 case DRM_FORMAT_NV12MT:
416 tiled_mode = true;
Ville Syrjälä363b06a2012-05-14 11:08:51 +0900417 case DRM_FORMAT_NV12:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900418 crcb_mode = false;
419 buf_num = 2;
420 break;
421 /* TODO: single buffer format NV12, NV21 */
422 default:
423 /* ignore pixel format at disable time */
424 if (!win_data->dma_addr)
425 break;
426
427 DRM_ERROR("pixel format for vp is wrong [%d].\n",
428 win_data->pixel_format);
429 return;
430 }
431
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900432 /* scaling feature: (src << 16) / dst */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900433 x_ratio = (win_data->src_width << 16) / win_data->crtc_width;
434 y_ratio = (win_data->src_height << 16) / win_data->crtc_height;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900435
436 if (buf_num == 2) {
437 luma_addr[0] = win_data->dma_addr;
438 chroma_addr[0] = win_data->chroma_dma_addr;
439 } else {
440 luma_addr[0] = win_data->dma_addr;
441 chroma_addr[0] = win_data->dma_addr
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900442 + (win_data->fb_width * win_data->fb_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900443 }
444
445 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) {
446 ctx->interlace = true;
447 if (tiled_mode) {
448 luma_addr[1] = luma_addr[0] + 0x40;
449 chroma_addr[1] = chroma_addr[0] + 0x40;
450 } else {
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900451 luma_addr[1] = luma_addr[0] + win_data->fb_width;
452 chroma_addr[1] = chroma_addr[0] + win_data->fb_width;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900453 }
454 } else {
455 ctx->interlace = false;
456 luma_addr[1] = 0;
457 chroma_addr[1] = 0;
458 }
459
460 spin_lock_irqsave(&res->reg_slock, flags);
461 mixer_vsync_set_update(ctx, false);
462
463 /* interlace or progressive scan mode */
464 val = (ctx->interlace ? ~0 : 0);
465 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
466
467 /* setup format */
468 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
469 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
470 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
471
472 /* setting size of input image */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900473 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_width) |
474 VP_IMG_VSIZE(win_data->fb_height));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900475 /* chroma height has to reduced by 2 to avoid chroma distorions */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900476 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(win_data->fb_width) |
477 VP_IMG_VSIZE(win_data->fb_height / 2));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900478
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900479 vp_reg_write(res, VP_SRC_WIDTH, win_data->src_width);
480 vp_reg_write(res, VP_SRC_HEIGHT, win_data->src_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900481 vp_reg_write(res, VP_SRC_H_POSITION,
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900482 VP_SRC_H_POSITION_VAL(win_data->fb_x));
483 vp_reg_write(res, VP_SRC_V_POSITION, win_data->fb_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900484
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900485 vp_reg_write(res, VP_DST_WIDTH, win_data->crtc_width);
486 vp_reg_write(res, VP_DST_H_POSITION, win_data->crtc_x);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900487 if (ctx->interlace) {
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900488 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height / 2);
489 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y / 2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900490 } else {
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900491 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height);
492 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900493 }
494
495 vp_reg_write(res, VP_H_RATIO, x_ratio);
496 vp_reg_write(res, VP_V_RATIO, y_ratio);
497
498 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
499
500 /* set buffer address to vp */
501 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
502 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
503 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
504 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
505
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900506 mixer_cfg_scan(ctx, win_data->mode_height);
507 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900508 mixer_cfg_layer(ctx, win, true);
509 mixer_run(ctx);
510
511 mixer_vsync_set_update(ctx, true);
512 spin_unlock_irqrestore(&res->reg_slock, flags);
513
514 vp_regs_dump(ctx);
515}
516
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530517static void mixer_layer_update(struct mixer_context *ctx)
518{
519 struct mixer_resources *res = &ctx->mixer_res;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530520
Rahul Sharma5c0f4822014-06-23 11:02:23 +0530521 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530522}
523
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900524static void mixer_graph_buffer(struct mixer_context *ctx, int win)
525{
526 struct mixer_resources *res = &ctx->mixer_res;
527 unsigned long flags;
528 struct hdmi_win_data *win_data;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900529 unsigned int x_ratio, y_ratio;
530 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900531 dma_addr_t dma_addr;
532 unsigned int fmt;
533 u32 val;
534
535 win_data = &ctx->win_data[win];
536
537 #define RGB565 4
538 #define ARGB1555 5
539 #define ARGB4444 6
540 #define ARGB8888 7
541
542 switch (win_data->bpp) {
543 case 16:
544 fmt = ARGB4444;
545 break;
546 case 32:
547 fmt = ARGB8888;
548 break;
549 default:
550 fmt = ARGB8888;
551 }
552
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900553 /* 2x scaling feature */
554 x_ratio = 0;
555 y_ratio = 0;
556
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900557 dst_x_offset = win_data->crtc_x;
558 dst_y_offset = win_data->crtc_y;
559
560 /* converting dma address base and source offset */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900561 dma_addr = win_data->dma_addr
562 + (win_data->fb_x * win_data->bpp >> 3)
563 + (win_data->fb_y * win_data->fb_width * win_data->bpp >> 3);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900564 src_x_offset = 0;
565 src_y_offset = 0;
566
567 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE)
568 ctx->interlace = true;
569 else
570 ctx->interlace = false;
571
572 spin_lock_irqsave(&res->reg_slock, flags);
573 mixer_vsync_set_update(ctx, false);
574
575 /* setup format */
576 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
577 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
578
579 /* setup geometry */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900580 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), win_data->fb_width);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900581
Rahul Sharmadef5e092013-06-19 18:21:08 +0530582 /* setup display size */
583 if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
584 win == MIXER_DEFAULT_WIN) {
585 val = MXR_MXR_RES_HEIGHT(win_data->fb_height);
586 val |= MXR_MXR_RES_WIDTH(win_data->fb_width);
587 mixer_reg_write(res, MXR_RESOLUTION, val);
588 }
589
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900590 val = MXR_GRP_WH_WIDTH(win_data->crtc_width);
591 val |= MXR_GRP_WH_HEIGHT(win_data->crtc_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900592 val |= MXR_GRP_WH_H_SCALE(x_ratio);
593 val |= MXR_GRP_WH_V_SCALE(y_ratio);
594 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
595
596 /* setup offsets in source image */
597 val = MXR_GRP_SXY_SX(src_x_offset);
598 val |= MXR_GRP_SXY_SY(src_y_offset);
599 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
600
601 /* setup offsets in display image */
602 val = MXR_GRP_DXY_DX(dst_x_offset);
603 val |= MXR_GRP_DXY_DY(dst_y_offset);
604 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
605
606 /* set buffer address to mixer */
607 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
608
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900609 mixer_cfg_scan(ctx, win_data->mode_height);
610 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900611 mixer_cfg_layer(ctx, win, true);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530612
613 /* layer update mandatory for mixer 16.0.33.0 */
Rahul Sharmadef5e092013-06-19 18:21:08 +0530614 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
615 ctx->mxr_ver == MXR_VER_128_0_0_184)
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530616 mixer_layer_update(ctx);
617
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900618 mixer_run(ctx);
619
620 mixer_vsync_set_update(ctx, true);
621 spin_unlock_irqrestore(&res->reg_slock, flags);
622}
623
624static void vp_win_reset(struct mixer_context *ctx)
625{
626 struct mixer_resources *res = &ctx->mixer_res;
627 int tries = 100;
628
629 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
630 for (tries = 100; tries; --tries) {
631 /* waiting until VP_SRESET_PROCESSING is 0 */
632 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
633 break;
Sean Paul09760ea2013-01-14 17:03:20 -0500634 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900635 }
636 WARN(tries == 0, "failed to reset Video Processor\n");
637}
638
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900639static void mixer_win_reset(struct mixer_context *ctx)
640{
641 struct mixer_resources *res = &ctx->mixer_res;
642 unsigned long flags;
643 u32 val; /* value stored to register */
644
645 spin_lock_irqsave(&res->reg_slock, flags);
646 mixer_vsync_set_update(ctx, false);
647
648 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
649
650 /* set output in RGB888 mode */
651 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
652
653 /* 16 beat burst in DMA */
654 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
655 MXR_STATUS_BURST_MASK);
656
657 /* setting default layer priority: layer1 > layer0 > video
658 * because typical usage scenario would be
659 * layer1 - OSD
660 * layer0 - framebuffer
661 * video - video overlay
662 */
663 val = MXR_LAYER_CFG_GRP1_VAL(3);
664 val |= MXR_LAYER_CFG_GRP0_VAL(2);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530665 if (ctx->vp_enabled)
666 val |= MXR_LAYER_CFG_VP_VAL(1);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900667 mixer_reg_write(res, MXR_LAYER_CFG, val);
668
669 /* setting background color */
670 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
671 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
672 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
673
674 /* setting graphical layers */
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900675 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
676 val |= MXR_GRP_CFG_WIN_BLEND_EN;
677 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
678
Sean Paul0377f4e2013-04-25 15:13:26 -0400679 /* Don't blend layer 0 onto the mixer background */
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900680 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
Sean Paul0377f4e2013-04-25 15:13:26 -0400681
682 /* Blend layer 1 into layer 0 */
683 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
684 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900685 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
686
Seung-Woo Kim57366032012-05-15 17:22:08 +0900687 /* setting video layers */
688 val = MXR_GRP_CFG_ALPHA_VAL(0);
689 mixer_reg_write(res, MXR_VIDEO_CFG, val);
690
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530691 if (ctx->vp_enabled) {
692 /* configuration of Video Processor Registers */
693 vp_win_reset(ctx);
694 vp_default_filter(res);
695 }
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900696
697 /* disable all layers */
698 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
699 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530700 if (ctx->vp_enabled)
701 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900702
703 mixer_vsync_set_update(ctx, true);
704 spin_unlock_irqrestore(&res->reg_slock, flags);
705}
706
Sean Paul45517892014-01-30 16:19:05 -0500707static irqreturn_t mixer_irq_handler(int irq, void *arg)
708{
709 struct mixer_context *ctx = arg;
710 struct mixer_resources *res = &ctx->mixer_res;
711 u32 val, base, shadow;
712
713 spin_lock(&res->reg_slock);
714
715 /* read interrupt status for handling and clearing flags for VSYNC */
716 val = mixer_reg_read(res, MXR_INT_STATUS);
717
718 /* handling VSYNC */
719 if (val & MXR_INT_STATUS_VSYNC) {
720 /* interlace scan need to check shadow register */
721 if (ctx->interlace) {
722 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
723 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
724 if (base != shadow)
725 goto out;
726
727 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
728 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
729 if (base != shadow)
730 goto out;
731 }
732
733 drm_handle_vblank(ctx->drm_dev, ctx->pipe);
734 exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
735
736 /* set wait vsync event to zero and wake up queue. */
737 if (atomic_read(&ctx->wait_vsync_event)) {
738 atomic_set(&ctx->wait_vsync_event, 0);
739 wake_up(&ctx->wait_vsync_queue);
740 }
741 }
742
743out:
744 /* clear interrupts */
745 if (~val & MXR_INT_EN_VSYNC) {
746 /* vsync interrupt use different bit for read and clear */
747 val &= ~MXR_INT_EN_VSYNC;
748 val |= MXR_INT_CLEAR_VSYNC;
749 }
750 mixer_reg_write(res, MXR_INT_STATUS, val);
751
752 spin_unlock(&res->reg_slock);
753
754 return IRQ_HANDLED;
755}
756
757static int mixer_resources_init(struct mixer_context *mixer_ctx)
758{
759 struct device *dev = &mixer_ctx->pdev->dev;
760 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
761 struct resource *res;
762 int ret;
763
764 spin_lock_init(&mixer_res->reg_slock);
765
766 mixer_res->mixer = devm_clk_get(dev, "mixer");
767 if (IS_ERR(mixer_res->mixer)) {
768 dev_err(dev, "failed to get clock 'mixer'\n");
769 return -ENODEV;
770 }
771
772 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
773 if (IS_ERR(mixer_res->sclk_hdmi)) {
774 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
775 return -ENODEV;
776 }
777 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
778 if (res == NULL) {
779 dev_err(dev, "get memory resource failed.\n");
780 return -ENXIO;
781 }
782
783 mixer_res->mixer_regs = devm_ioremap(dev, res->start,
784 resource_size(res));
785 if (mixer_res->mixer_regs == NULL) {
786 dev_err(dev, "register mapping failed.\n");
787 return -ENXIO;
788 }
789
790 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
791 if (res == NULL) {
792 dev_err(dev, "get interrupt resource failed.\n");
793 return -ENXIO;
794 }
795
796 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
797 0, "drm_mixer", mixer_ctx);
798 if (ret) {
799 dev_err(dev, "request interrupt failed.\n");
800 return ret;
801 }
802 mixer_res->irq = res->start;
803
804 return 0;
805}
806
807static int vp_resources_init(struct mixer_context *mixer_ctx)
808{
809 struct device *dev = &mixer_ctx->pdev->dev;
810 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
811 struct resource *res;
812
813 mixer_res->vp = devm_clk_get(dev, "vp");
814 if (IS_ERR(mixer_res->vp)) {
815 dev_err(dev, "failed to get clock 'vp'\n");
816 return -ENODEV;
817 }
Sean Paul45517892014-01-30 16:19:05 -0500818
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200819 if (mixer_ctx->has_sclk) {
820 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
821 if (IS_ERR(mixer_res->sclk_mixer)) {
822 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
823 return -ENODEV;
824 }
825 mixer_res->mout_mixer = devm_clk_get(dev, "mout_mixer");
826 if (IS_ERR(mixer_res->mout_mixer)) {
827 dev_err(dev, "failed to get clock 'mout_mixer'\n");
828 return -ENODEV;
829 }
830
831 if (mixer_res->sclk_hdmi && mixer_res->mout_mixer)
832 clk_set_parent(mixer_res->mout_mixer,
833 mixer_res->sclk_hdmi);
834 }
Sean Paul45517892014-01-30 16:19:05 -0500835
836 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
837 if (res == NULL) {
838 dev_err(dev, "get memory resource failed.\n");
839 return -ENXIO;
840 }
841
842 mixer_res->vp_regs = devm_ioremap(dev, res->start,
843 resource_size(res));
844 if (mixer_res->vp_regs == NULL) {
845 dev_err(dev, "register mapping failed.\n");
846 return -ENXIO;
847 }
848
849 return 0;
850}
851
Gustavo Padovan93bca242015-01-18 18:16:23 +0900852static int mixer_initialize(struct mixer_context *mixer_ctx,
Inki Daef37cd5e2014-05-09 14:25:20 +0900853 struct drm_device *drm_dev)
Sean Paul45517892014-01-30 16:19:05 -0500854{
855 int ret;
Inki Daef37cd5e2014-05-09 14:25:20 +0900856 struct exynos_drm_private *priv;
857 priv = drm_dev->dev_private;
Sean Paul45517892014-01-30 16:19:05 -0500858
Gustavo Padovaneb88e422014-11-26 16:43:27 -0200859 mixer_ctx->drm_dev = drm_dev;
Gustavo Padovan8a326ed2014-11-04 18:44:47 -0200860 mixer_ctx->pipe = priv->pipe++;
Sean Paul45517892014-01-30 16:19:05 -0500861
862 /* acquire resources: regs, irqs, clocks */
863 ret = mixer_resources_init(mixer_ctx);
864 if (ret) {
865 DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
866 return ret;
867 }
868
869 if (mixer_ctx->vp_enabled) {
870 /* acquire vp resources: regs, irqs, clocks */
871 ret = vp_resources_init(mixer_ctx);
872 if (ret) {
873 DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
874 return ret;
875 }
876 }
877
Sean Paulf041b252014-01-30 16:19:15 -0500878 if (!is_drm_iommu_supported(mixer_ctx->drm_dev))
879 return 0;
880
881 return drm_iommu_attach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Sean Paul45517892014-01-30 16:19:05 -0500882}
883
Gustavo Padovan93bca242015-01-18 18:16:23 +0900884static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
Inki Dae1055b392012-10-19 17:37:35 +0900885{
Sean Paulf041b252014-01-30 16:19:15 -0500886 if (is_drm_iommu_supported(mixer_ctx->drm_dev))
887 drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Inki Dae1055b392012-10-19 17:37:35 +0900888}
889
Gustavo Padovan93bca242015-01-18 18:16:23 +0900890static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900891{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900892 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900893 struct mixer_resources *res = &mixer_ctx->mixer_res;
894
Sean Paulf041b252014-01-30 16:19:15 -0500895 if (!mixer_ctx->powered) {
896 mixer_ctx->int_en |= MXR_INT_EN_VSYNC;
897 return 0;
898 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900899
900 /* enable vsync interrupt */
901 mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
902 MXR_INT_EN_VSYNC);
903
904 return 0;
905}
906
Gustavo Padovan93bca242015-01-18 18:16:23 +0900907static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900908{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900909 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900910 struct mixer_resources *res = &mixer_ctx->mixer_res;
911
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900912 /* disable vsync interrupt */
913 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
914}
915
Gustavo Padovan93bca242015-01-18 18:16:23 +0900916static void mixer_win_mode_set(struct exynos_drm_crtc *crtc,
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200917 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900918{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900919 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900920 struct hdmi_win_data *win_data;
921 int win;
922
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200923 if (!plane) {
924 DRM_ERROR("plane is NULL\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900925 return;
926 }
927
928 DRM_DEBUG_KMS("set [%d]x[%d] at (%d,%d) to [%d]x[%d] at (%d,%d)\n",
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200929 plane->fb_width, plane->fb_height,
930 plane->fb_x, plane->fb_y,
931 plane->crtc_width, plane->crtc_height,
932 plane->crtc_x, plane->crtc_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900933
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200934 win = plane->zpos;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900935 if (win == DEFAULT_ZPOS)
Joonyoung Shima2ee1512012-04-05 20:49:25 +0900936 win = MIXER_DEFAULT_WIN;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900937
Krzysztof Kozlowski1586d802013-05-27 15:00:43 +0900938 if (win < 0 || win >= MIXER_WIN_NR) {
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900939 DRM_ERROR("mixer window[%d] is wrong\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900940 return;
941 }
942
943 win_data = &mixer_ctx->win_data[win];
944
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200945 win_data->dma_addr = plane->dma_addr[0];
946 win_data->chroma_dma_addr = plane->dma_addr[1];
947 win_data->pixel_format = plane->pixel_format;
948 win_data->bpp = plane->bpp;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900949
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200950 win_data->crtc_x = plane->crtc_x;
951 win_data->crtc_y = plane->crtc_y;
952 win_data->crtc_width = plane->crtc_width;
953 win_data->crtc_height = plane->crtc_height;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900954
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200955 win_data->fb_x = plane->fb_x;
956 win_data->fb_y = plane->fb_y;
957 win_data->fb_width = plane->fb_width;
958 win_data->fb_height = plane->fb_height;
959 win_data->src_width = plane->src_width;
960 win_data->src_height = plane->src_height;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900961
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200962 win_data->mode_width = plane->mode_width;
963 win_data->mode_height = plane->mode_height;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900964
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200965 win_data->scan_flags = plane->scan_flag;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900966}
967
Gustavo Padovan93bca242015-01-18 18:16:23 +0900968static void mixer_win_commit(struct exynos_drm_crtc *crtc, int zpos)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900969{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900970 struct mixer_context *mixer_ctx = crtc->ctx;
Sean Paulf041b252014-01-30 16:19:15 -0500971 int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900972
YoungJun Chocbc4c332013-06-12 10:44:40 +0900973 DRM_DEBUG_KMS("win: %d\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900974
Shirish Sdda90122013-01-23 22:03:18 -0500975 mutex_lock(&mixer_ctx->mixer_mutex);
976 if (!mixer_ctx->powered) {
977 mutex_unlock(&mixer_ctx->mixer_mutex);
978 return;
979 }
980 mutex_unlock(&mixer_ctx->mixer_mutex);
981
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530982 if (win > 1 && mixer_ctx->vp_enabled)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900983 vp_video_buffer(mixer_ctx, win);
984 else
985 mixer_graph_buffer(mixer_ctx, win);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530986
987 mixer_ctx->win_data[win].enabled = true;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900988}
989
Gustavo Padovan93bca242015-01-18 18:16:23 +0900990static void mixer_win_disable(struct exynos_drm_crtc *crtc, int zpos)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900991{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900992 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900993 struct mixer_resources *res = &mixer_ctx->mixer_res;
Sean Paulf041b252014-01-30 16:19:15 -0500994 int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900995 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900996
YoungJun Chocbc4c332013-06-12 10:44:40 +0900997 DRM_DEBUG_KMS("win: %d\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900998
Prathyush Kdb43fd12012-12-06 20:16:05 +0530999 mutex_lock(&mixer_ctx->mixer_mutex);
1000 if (!mixer_ctx->powered) {
1001 mutex_unlock(&mixer_ctx->mixer_mutex);
1002 mixer_ctx->win_data[win].resume = false;
1003 return;
1004 }
1005 mutex_unlock(&mixer_ctx->mixer_mutex);
1006
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001007 spin_lock_irqsave(&res->reg_slock, flags);
1008 mixer_vsync_set_update(mixer_ctx, false);
1009
1010 mixer_cfg_layer(mixer_ctx, win, false);
1011
1012 mixer_vsync_set_update(mixer_ctx, true);
1013 spin_unlock_irqrestore(&res->reg_slock, flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301014
1015 mixer_ctx->win_data[win].enabled = false;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001016}
1017
Gustavo Padovan93bca242015-01-18 18:16:23 +09001018static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
Rahul Sharma0ea68222013-01-15 08:11:06 -05001019{
Gustavo Padovan93bca242015-01-18 18:16:23 +09001020 struct mixer_context *mixer_ctx = crtc->ctx;
Joonyoung Shim7c4c5582015-01-18 17:48:29 +09001021 int err;
Prathyush K8137a2e2012-12-06 20:16:01 +05301022
Prathyush K6e95d5e2012-12-06 20:16:03 +05301023 mutex_lock(&mixer_ctx->mixer_mutex);
1024 if (!mixer_ctx->powered) {
1025 mutex_unlock(&mixer_ctx->mixer_mutex);
1026 return;
1027 }
1028 mutex_unlock(&mixer_ctx->mixer_mutex);
1029
Gustavo Padovan93bca242015-01-18 18:16:23 +09001030 err = drm_vblank_get(mixer_ctx->drm_dev, mixer_ctx->pipe);
Joonyoung Shim7c4c5582015-01-18 17:48:29 +09001031 if (err < 0) {
1032 DRM_DEBUG_KMS("failed to acquire vblank counter\n");
1033 return;
1034 }
Rahul Sharma5d39b9e2014-06-23 11:02:25 +05301035
Prathyush K6e95d5e2012-12-06 20:16:03 +05301036 atomic_set(&mixer_ctx->wait_vsync_event, 1);
1037
1038 /*
1039 * wait for MIXER to signal VSYNC interrupt or return after
1040 * timeout which is set to 50ms (refresh rate of 20).
1041 */
1042 if (!wait_event_timeout(mixer_ctx->wait_vsync_queue,
1043 !atomic_read(&mixer_ctx->wait_vsync_event),
Daniel Vetterbfd83032013-12-11 11:34:41 +01001044 HZ/20))
Prathyush K8137a2e2012-12-06 20:16:01 +05301045 DRM_DEBUG_KMS("vblank wait timed out.\n");
Rahul Sharma5d39b9e2014-06-23 11:02:25 +05301046
Gustavo Padovan93bca242015-01-18 18:16:23 +09001047 drm_vblank_put(mixer_ctx->drm_dev, mixer_ctx->pipe);
Prathyush K8137a2e2012-12-06 20:16:01 +05301048}
1049
Gustavo Padovan93bca242015-01-18 18:16:23 +09001050static void mixer_window_suspend(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301051{
Gustavo Padovan93bca242015-01-18 18:16:23 +09001052 struct mixer_context *ctx = crtc->ctx;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301053 struct hdmi_win_data *win_data;
1054 int i;
1055
1056 for (i = 0; i < MIXER_WIN_NR; i++) {
1057 win_data = &ctx->win_data[i];
1058 win_data->resume = win_data->enabled;
Gustavo Padovan93bca242015-01-18 18:16:23 +09001059 mixer_win_disable(crtc, i);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301060 }
Gustavo Padovan93bca242015-01-18 18:16:23 +09001061 mixer_wait_for_vblank(crtc);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301062}
1063
Gustavo Padovan93bca242015-01-18 18:16:23 +09001064static void mixer_window_resume(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301065{
Gustavo Padovan93bca242015-01-18 18:16:23 +09001066 struct mixer_context *ctx = crtc->ctx;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301067 struct hdmi_win_data *win_data;
1068 int i;
1069
1070 for (i = 0; i < MIXER_WIN_NR; i++) {
1071 win_data = &ctx->win_data[i];
1072 win_data->enabled = win_data->resume;
1073 win_data->resume = false;
Sean Paul87244fa2014-01-30 16:19:07 -05001074 if (win_data->enabled)
Gustavo Padovan93bca242015-01-18 18:16:23 +09001075 mixer_win_commit(crtc, i);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301076 }
1077}
1078
Gustavo Padovan93bca242015-01-18 18:16:23 +09001079static void mixer_poweron(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301080{
Gustavo Padovan93bca242015-01-18 18:16:23 +09001081 struct mixer_context *ctx = crtc->ctx;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301082 struct mixer_resources *res = &ctx->mixer_res;
1083
Prathyush Kdb43fd12012-12-06 20:16:05 +05301084 mutex_lock(&ctx->mixer_mutex);
1085 if (ctx->powered) {
1086 mutex_unlock(&ctx->mixer_mutex);
1087 return;
1088 }
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301089
Prathyush Kdb43fd12012-12-06 20:16:05 +05301090 mutex_unlock(&ctx->mixer_mutex);
1091
Sean Paulaf65c802014-01-30 16:19:27 -05001092 pm_runtime_get_sync(ctx->dev);
1093
Sean Paul0bfb1f82013-06-11 12:24:02 +05301094 clk_prepare_enable(res->mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301095 if (ctx->vp_enabled) {
Sean Paul0bfb1f82013-06-11 12:24:02 +05301096 clk_prepare_enable(res->vp);
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001097 if (ctx->has_sclk)
1098 clk_prepare_enable(res->sclk_mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301099 }
1100
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301101 mutex_lock(&ctx->mixer_mutex);
1102 ctx->powered = true;
1103 mutex_unlock(&ctx->mixer_mutex);
1104
Rahul Sharmad74ed932014-06-23 11:02:24 +05301105 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
1106
Prathyush Kdb43fd12012-12-06 20:16:05 +05301107 mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
1108 mixer_win_reset(ctx);
1109
Gustavo Padovan93bca242015-01-18 18:16:23 +09001110 mixer_window_resume(crtc);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301111}
1112
Gustavo Padovan93bca242015-01-18 18:16:23 +09001113static void mixer_poweroff(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301114{
Gustavo Padovan93bca242015-01-18 18:16:23 +09001115 struct mixer_context *ctx = crtc->ctx;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301116 struct mixer_resources *res = &ctx->mixer_res;
1117
Prathyush Kdb43fd12012-12-06 20:16:05 +05301118 mutex_lock(&ctx->mixer_mutex);
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301119 if (!ctx->powered) {
1120 mutex_unlock(&ctx->mixer_mutex);
1121 return;
1122 }
Prathyush Kdb43fd12012-12-06 20:16:05 +05301123 mutex_unlock(&ctx->mixer_mutex);
1124
Rahul Sharma381be022014-06-23 11:02:22 +05301125 mixer_stop(ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001126 mixer_window_suspend(crtc);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301127
1128 ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
1129
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301130 mutex_lock(&ctx->mixer_mutex);
1131 ctx->powered = false;
1132 mutex_unlock(&ctx->mixer_mutex);
1133
Sean Paul0bfb1f82013-06-11 12:24:02 +05301134 clk_disable_unprepare(res->mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301135 if (ctx->vp_enabled) {
Sean Paul0bfb1f82013-06-11 12:24:02 +05301136 clk_disable_unprepare(res->vp);
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001137 if (ctx->has_sclk)
1138 clk_disable_unprepare(res->sclk_mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301139 }
1140
Sean Paulaf65c802014-01-30 16:19:27 -05001141 pm_runtime_put_sync(ctx->dev);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301142}
1143
Gustavo Padovan93bca242015-01-18 18:16:23 +09001144static void mixer_dpms(struct exynos_drm_crtc *crtc, int mode)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301145{
Prathyush Kdb43fd12012-12-06 20:16:05 +05301146 switch (mode) {
1147 case DRM_MODE_DPMS_ON:
Gustavo Padovan93bca242015-01-18 18:16:23 +09001148 mixer_poweron(crtc);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301149 break;
1150 case DRM_MODE_DPMS_STANDBY:
1151 case DRM_MODE_DPMS_SUSPEND:
1152 case DRM_MODE_DPMS_OFF:
Gustavo Padovan93bca242015-01-18 18:16:23 +09001153 mixer_poweroff(crtc);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301154 break;
1155 default:
1156 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
1157 break;
1158 }
1159}
1160
Sean Paulf041b252014-01-30 16:19:15 -05001161/* Only valid for Mixer version 16.0.33.0 */
1162int mixer_check_mode(struct drm_display_mode *mode)
1163{
1164 u32 w, h;
1165
1166 w = mode->hdisplay;
1167 h = mode->vdisplay;
1168
1169 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
1170 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1171 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1172
1173 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
1174 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1175 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1176 return 0;
1177
1178 return -EINVAL;
1179}
1180
Gustavo Padovan93bca242015-01-18 18:16:23 +09001181static struct exynos_drm_crtc_ops mixer_crtc_ops = {
Sean Paulf041b252014-01-30 16:19:15 -05001182 .dpms = mixer_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001183 .enable_vblank = mixer_enable_vblank,
1184 .disable_vblank = mixer_disable_vblank,
Prathyush K8137a2e2012-12-06 20:16:01 +05301185 .wait_for_vblank = mixer_wait_for_vblank,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001186 .win_mode_set = mixer_win_mode_set,
1187 .win_commit = mixer_win_commit,
1188 .win_disable = mixer_win_disable,
Sean Paulf041b252014-01-30 16:19:15 -05001189};
Rahul Sharma0ea68222013-01-15 08:11:06 -05001190
Rahul Sharmadef5e092013-06-19 18:21:08 +05301191static struct mixer_drv_data exynos5420_mxr_drv_data = {
1192 .version = MXR_VER_128_0_0_184,
1193 .is_vp_enabled = 0,
1194};
1195
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301196static struct mixer_drv_data exynos5250_mxr_drv_data = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301197 .version = MXR_VER_16_0_33_0,
1198 .is_vp_enabled = 0,
1199};
1200
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001201static struct mixer_drv_data exynos4212_mxr_drv_data = {
1202 .version = MXR_VER_0_0_0_16,
1203 .is_vp_enabled = 1,
1204};
1205
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301206static struct mixer_drv_data exynos4210_mxr_drv_data = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301207 .version = MXR_VER_0_0_0_16,
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301208 .is_vp_enabled = 1,
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001209 .has_sclk = 1,
Rahul Sharma1e123442012-10-04 20:48:51 +05301210};
1211
1212static struct platform_device_id mixer_driver_types[] = {
1213 {
1214 .name = "s5p-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301215 .driver_data = (unsigned long)&exynos4210_mxr_drv_data,
Rahul Sharma1e123442012-10-04 20:48:51 +05301216 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301217 .name = "exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301218 .driver_data = (unsigned long)&exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301219 }, {
1220 /* end node */
1221 }
1222};
1223
1224static struct of_device_id mixer_match_types[] = {
1225 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001226 .compatible = "samsung,exynos4210-mixer",
1227 .data = &exynos4210_mxr_drv_data,
1228 }, {
1229 .compatible = "samsung,exynos4212-mixer",
1230 .data = &exynos4212_mxr_drv_data,
1231 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301232 .compatible = "samsung,exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301233 .data = &exynos5250_mxr_drv_data,
1234 }, {
1235 .compatible = "samsung,exynos5250-mixer",
1236 .data = &exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301237 }, {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301238 .compatible = "samsung,exynos5420-mixer",
1239 .data = &exynos5420_mxr_drv_data,
1240 }, {
Rahul Sharma1e123442012-10-04 20:48:51 +05301241 /* end node */
1242 }
1243};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001244MODULE_DEVICE_TABLE(of, mixer_match_types);
Rahul Sharma1e123442012-10-04 20:48:51 +05301245
Inki Daef37cd5e2014-05-09 14:25:20 +09001246static int mixer_bind(struct device *dev, struct device *manager, void *data)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001247{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001248 struct mixer_context *ctx = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09001249 struct drm_device *drm_dev = data;
Inki Daef37cd5e2014-05-09 14:25:20 +09001250 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001251
Gustavo Padovan93bca242015-01-18 18:16:23 +09001252 ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
1253 EXYNOS_DISPLAY_TYPE_HDMI,
1254 &mixer_crtc_ops, ctx);
1255 if (IS_ERR(ctx->crtc)) {
1256 ret = PTR_ERR(ctx->crtc);
1257 goto free_ctx;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001258 }
1259
Gustavo Padovan93bca242015-01-18 18:16:23 +09001260 ret = mixer_initialize(ctx, drm_dev);
1261 if (ret)
1262 goto free_ctx;
1263
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001264 return 0;
Gustavo Padovan93bca242015-01-18 18:16:23 +09001265
1266free_ctx:
1267 devm_kfree(dev, ctx);
1268 return ret;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001269}
1270
1271static void mixer_unbind(struct device *dev, struct device *master, void *data)
1272{
1273 struct mixer_context *ctx = dev_get_drvdata(dev);
1274
Gustavo Padovan93bca242015-01-18 18:16:23 +09001275 mixer_ctx_remove(ctx);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001276}
1277
1278static const struct component_ops mixer_component_ops = {
1279 .bind = mixer_bind,
1280 .unbind = mixer_unbind,
1281};
1282
1283static int mixer_probe(struct platform_device *pdev)
1284{
1285 struct device *dev = &pdev->dev;
1286 struct mixer_drv_data *drv;
1287 struct mixer_context *ctx;
1288 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001289
Sean Paulf041b252014-01-30 16:19:15 -05001290 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1291 if (!ctx) {
1292 DRM_ERROR("failed to alloc mixer context.\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001293 return -ENOMEM;
Sean Paulf041b252014-01-30 16:19:15 -05001294 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001295
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001296 mutex_init(&ctx->mixer_mutex);
1297
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301298 if (dev->of_node) {
1299 const struct of_device_id *match;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001300
Sachin Kamate436b092013-06-05 16:00:23 +09001301 match = of_match_node(mixer_match_types, dev->of_node);
Rahul Sharma2cdc53b2012-10-31 09:36:26 +05301302 drv = (struct mixer_drv_data *)match->data;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301303 } else {
1304 drv = (struct mixer_drv_data *)
1305 platform_get_device_id(pdev)->driver_data;
1306 }
1307
Sean Paul45517892014-01-30 16:19:05 -05001308 ctx->pdev = pdev;
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001309 ctx->dev = dev;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301310 ctx->vp_enabled = drv->is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001311 ctx->has_sclk = drv->has_sclk;
Rahul Sharma1e123442012-10-04 20:48:51 +05301312 ctx->mxr_ver = drv->version;
Daniel Vetter57ed0f72013-12-11 11:34:43 +01001313 init_waitqueue_head(&ctx->wait_vsync_queue);
Prathyush K6e95d5e2012-12-06 20:16:03 +05301314 atomic_set(&ctx->wait_vsync_event, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001315
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001316 platform_set_drvdata(pdev, ctx);
Inki Daedf5225b2014-05-29 18:28:02 +09001317
1318 ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
Gustavo Padovan5d1741a2014-11-05 19:51:35 -02001319 EXYNOS_DISPLAY_TYPE_HDMI);
Inki Daedf5225b2014-05-29 18:28:02 +09001320 if (ret)
1321 return ret;
1322
1323 ret = component_add(&pdev->dev, &mixer_component_ops);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001324 if (ret) {
Inki Daedf5225b2014-05-29 18:28:02 +09001325 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001326 return ret;
1327 }
1328
1329 pm_runtime_enable(dev);
Inki Daedf5225b2014-05-29 18:28:02 +09001330
1331 return ret;
Inki Daef37cd5e2014-05-09 14:25:20 +09001332}
1333
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001334static int mixer_remove(struct platform_device *pdev)
1335{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001336 pm_runtime_disable(&pdev->dev);
1337
Inki Daedf5225b2014-05-29 18:28:02 +09001338 component_del(&pdev->dev, &mixer_component_ops);
1339 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
1340
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001341 return 0;
1342}
1343
1344struct platform_driver mixer_driver = {
1345 .driver = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301346 .name = "exynos-mixer",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001347 .owner = THIS_MODULE,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301348 .of_match_table = mixer_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001349 },
1350 .probe = mixer_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001351 .remove = mixer_remove,
Rahul Sharma1e123442012-10-04 20:48:51 +05301352 .id_table = mixer_driver_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001353};