blob: 16197a627c473deabf3924a556f84da78a50117e [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 {
Andrzej Hajda8103ef12014-11-24 14:12:46 +090087 struct exynos_drm_manager manager;
Sean Paul45517892014-01-30 16:19:05 -050088 struct platform_device *pdev;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090089 struct device *dev;
Inki Dae1055b392012-10-19 17:37:35 +090090 struct drm_device *drm_dev;
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
Andrzej Hajda8f0be832014-11-24 14:14:49 +0900106static inline struct mixer_context *mgr_to_mixer(struct exynos_drm_manager *mgr)
107{
108 return container_of(mgr, struct mixer_context, manager);
109}
110
Rahul Sharma1e123442012-10-04 20:48:51 +0530111struct mixer_drv_data {
112 enum mixer_version_id version;
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530113 bool is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200114 bool has_sclk;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +0900115};
116
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900117static const u8 filter_y_horiz_tap8[] = {
118 0, -1, -1, -1, -1, -1, -1, -1,
119 -1, -1, -1, -1, -1, 0, 0, 0,
120 0, 2, 4, 5, 6, 6, 6, 6,
121 6, 5, 5, 4, 3, 2, 1, 1,
122 0, -6, -12, -16, -18, -20, -21, -20,
123 -20, -18, -16, -13, -10, -8, -5, -2,
124 127, 126, 125, 121, 114, 107, 99, 89,
125 79, 68, 57, 46, 35, 25, 16, 8,
126};
127
128static const u8 filter_y_vert_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 0, 5, 11, 19, 27, 37, 48, 59,
134 70, 81, 92, 102, 111, 118, 124, 126,
135 0, 0, -1, -1, -2, -3, -4, -5,
136 -6, -7, -8, -8, -8, -8, -6, -3,
137};
138
139static const u8 filter_cr_horiz_tap4[] = {
140 0, -3, -6, -8, -8, -8, -8, -7,
141 -6, -5, -4, -3, -2, -1, -1, 0,
142 127, 126, 124, 118, 111, 102, 92, 81,
143 70, 59, 48, 37, 27, 19, 11, 5,
144};
145
146static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
147{
148 return readl(res->vp_regs + reg_id);
149}
150
151static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
152 u32 val)
153{
154 writel(val, res->vp_regs + reg_id);
155}
156
157static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
158 u32 val, u32 mask)
159{
160 u32 old = vp_reg_read(res, reg_id);
161
162 val = (val & mask) | (old & ~mask);
163 writel(val, res->vp_regs + reg_id);
164}
165
166static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
167{
168 return readl(res->mixer_regs + reg_id);
169}
170
171static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
172 u32 val)
173{
174 writel(val, res->mixer_regs + reg_id);
175}
176
177static inline void mixer_reg_writemask(struct mixer_resources *res,
178 u32 reg_id, u32 val, u32 mask)
179{
180 u32 old = mixer_reg_read(res, reg_id);
181
182 val = (val & mask) | (old & ~mask);
183 writel(val, res->mixer_regs + reg_id);
184}
185
186static void mixer_regs_dump(struct mixer_context *ctx)
187{
188#define DUMPREG(reg_id) \
189do { \
190 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
191 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
192} while (0)
193
194 DUMPREG(MXR_STATUS);
195 DUMPREG(MXR_CFG);
196 DUMPREG(MXR_INT_EN);
197 DUMPREG(MXR_INT_STATUS);
198
199 DUMPREG(MXR_LAYER_CFG);
200 DUMPREG(MXR_VIDEO_CFG);
201
202 DUMPREG(MXR_GRAPHIC0_CFG);
203 DUMPREG(MXR_GRAPHIC0_BASE);
204 DUMPREG(MXR_GRAPHIC0_SPAN);
205 DUMPREG(MXR_GRAPHIC0_WH);
206 DUMPREG(MXR_GRAPHIC0_SXY);
207 DUMPREG(MXR_GRAPHIC0_DXY);
208
209 DUMPREG(MXR_GRAPHIC1_CFG);
210 DUMPREG(MXR_GRAPHIC1_BASE);
211 DUMPREG(MXR_GRAPHIC1_SPAN);
212 DUMPREG(MXR_GRAPHIC1_WH);
213 DUMPREG(MXR_GRAPHIC1_SXY);
214 DUMPREG(MXR_GRAPHIC1_DXY);
215#undef DUMPREG
216}
217
218static void vp_regs_dump(struct mixer_context *ctx)
219{
220#define DUMPREG(reg_id) \
221do { \
222 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
223 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
224} while (0)
225
226 DUMPREG(VP_ENABLE);
227 DUMPREG(VP_SRESET);
228 DUMPREG(VP_SHADOW_UPDATE);
229 DUMPREG(VP_FIELD_ID);
230 DUMPREG(VP_MODE);
231 DUMPREG(VP_IMG_SIZE_Y);
232 DUMPREG(VP_IMG_SIZE_C);
233 DUMPREG(VP_PER_RATE_CTRL);
234 DUMPREG(VP_TOP_Y_PTR);
235 DUMPREG(VP_BOT_Y_PTR);
236 DUMPREG(VP_TOP_C_PTR);
237 DUMPREG(VP_BOT_C_PTR);
238 DUMPREG(VP_ENDIAN_MODE);
239 DUMPREG(VP_SRC_H_POSITION);
240 DUMPREG(VP_SRC_V_POSITION);
241 DUMPREG(VP_SRC_WIDTH);
242 DUMPREG(VP_SRC_HEIGHT);
243 DUMPREG(VP_DST_H_POSITION);
244 DUMPREG(VP_DST_V_POSITION);
245 DUMPREG(VP_DST_WIDTH);
246 DUMPREG(VP_DST_HEIGHT);
247 DUMPREG(VP_H_RATIO);
248 DUMPREG(VP_V_RATIO);
249
250#undef DUMPREG
251}
252
253static inline void vp_filter_set(struct mixer_resources *res,
254 int reg_id, const u8 *data, unsigned int size)
255{
256 /* assure 4-byte align */
257 BUG_ON(size & 3);
258 for (; size; size -= 4, reg_id += 4, data += 4) {
259 u32 val = (data[0] << 24) | (data[1] << 16) |
260 (data[2] << 8) | data[3];
261 vp_reg_write(res, reg_id, val);
262 }
263}
264
265static void vp_default_filter(struct mixer_resources *res)
266{
267 vp_filter_set(res, VP_POLY8_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530268 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900269 vp_filter_set(res, VP_POLY4_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530270 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900271 vp_filter_set(res, VP_POLY4_C0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530272 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900273}
274
275static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
276{
277 struct mixer_resources *res = &ctx->mixer_res;
278
279 /* block update on vsync */
280 mixer_reg_writemask(res, MXR_STATUS, enable ?
281 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
282
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530283 if (ctx->vp_enabled)
284 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900285 VP_SHADOW_UPDATE_ENABLE : 0);
286}
287
288static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
289{
290 struct mixer_resources *res = &ctx->mixer_res;
291 u32 val;
292
293 /* choosing between interlace and progressive mode */
294 val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
295 MXR_CFG_SCAN_PROGRASSIVE);
296
Rahul Sharmadef5e092013-06-19 18:21:08 +0530297 if (ctx->mxr_ver != MXR_VER_128_0_0_184) {
298 /* choosing between proper HD and SD mode */
299 if (height <= 480)
300 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
301 else if (height <= 576)
302 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
303 else if (height <= 720)
304 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
305 else if (height <= 1080)
306 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
307 else
308 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
309 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900310
311 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
312}
313
314static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
315{
316 struct mixer_resources *res = &ctx->mixer_res;
317 u32 val;
318
319 if (height == 480) {
320 val = MXR_CFG_RGB601_0_255;
321 } else if (height == 576) {
322 val = MXR_CFG_RGB601_0_255;
323 } else if (height == 720) {
324 val = MXR_CFG_RGB709_16_235;
325 mixer_reg_write(res, MXR_CM_COEFF_Y,
326 (1 << 30) | (94 << 20) | (314 << 10) |
327 (32 << 0));
328 mixer_reg_write(res, MXR_CM_COEFF_CB,
329 (972 << 20) | (851 << 10) | (225 << 0));
330 mixer_reg_write(res, MXR_CM_COEFF_CR,
331 (225 << 20) | (820 << 10) | (1004 << 0));
332 } else if (height == 1080) {
333 val = MXR_CFG_RGB709_16_235;
334 mixer_reg_write(res, MXR_CM_COEFF_Y,
335 (1 << 30) | (94 << 20) | (314 << 10) |
336 (32 << 0));
337 mixer_reg_write(res, MXR_CM_COEFF_CB,
338 (972 << 20) | (851 << 10) | (225 << 0));
339 mixer_reg_write(res, MXR_CM_COEFF_CR,
340 (225 << 20) | (820 << 10) | (1004 << 0));
341 } else {
342 val = MXR_CFG_RGB709_16_235;
343 mixer_reg_write(res, MXR_CM_COEFF_Y,
344 (1 << 30) | (94 << 20) | (314 << 10) |
345 (32 << 0));
346 mixer_reg_write(res, MXR_CM_COEFF_CB,
347 (972 << 20) | (851 << 10) | (225 << 0));
348 mixer_reg_write(res, MXR_CM_COEFF_CR,
349 (225 << 20) | (820 << 10) | (1004 << 0));
350 }
351
352 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
353}
354
355static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable)
356{
357 struct mixer_resources *res = &ctx->mixer_res;
358 u32 val = enable ? ~0 : 0;
359
360 switch (win) {
361 case 0:
362 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
363 break;
364 case 1:
365 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
366 break;
367 case 2:
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530368 if (ctx->vp_enabled) {
369 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
370 mixer_reg_writemask(res, MXR_CFG, val,
371 MXR_CFG_VP_ENABLE);
Joonyoung Shimf1e716d2014-07-25 19:59:10 +0900372
373 /* control blending of graphic layer 0 */
374 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(0), val,
375 MXR_GRP_CFG_BLEND_PRE_MUL |
376 MXR_GRP_CFG_PIXEL_BLEND_EN);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530377 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900378 break;
379 }
380}
381
382static void mixer_run(struct mixer_context *ctx)
383{
384 struct mixer_resources *res = &ctx->mixer_res;
385
386 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
387
388 mixer_regs_dump(ctx);
389}
390
Rahul Sharma381be022014-06-23 11:02:22 +0530391static void mixer_stop(struct mixer_context *ctx)
392{
393 struct mixer_resources *res = &ctx->mixer_res;
394 int timeout = 20;
395
396 mixer_reg_writemask(res, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
397
398 while (!(mixer_reg_read(res, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
399 --timeout)
400 usleep_range(10000, 12000);
401
402 mixer_regs_dump(ctx);
403}
404
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900405static void vp_video_buffer(struct mixer_context *ctx, int win)
406{
407 struct mixer_resources *res = &ctx->mixer_res;
408 unsigned long flags;
409 struct hdmi_win_data *win_data;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900410 unsigned int x_ratio, y_ratio;
YoungJun Cho782953e2013-07-01 13:04:12 +0900411 unsigned int buf_num = 1;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900412 dma_addr_t luma_addr[2], chroma_addr[2];
413 bool tiled_mode = false;
414 bool crcb_mode = false;
415 u32 val;
416
417 win_data = &ctx->win_data[win];
418
419 switch (win_data->pixel_format) {
420 case DRM_FORMAT_NV12MT:
421 tiled_mode = true;
Ville Syrjälä363b06a2012-05-14 11:08:51 +0900422 case DRM_FORMAT_NV12:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900423 crcb_mode = false;
424 buf_num = 2;
425 break;
426 /* TODO: single buffer format NV12, NV21 */
427 default:
428 /* ignore pixel format at disable time */
429 if (!win_data->dma_addr)
430 break;
431
432 DRM_ERROR("pixel format for vp is wrong [%d].\n",
433 win_data->pixel_format);
434 return;
435 }
436
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900437 /* scaling feature: (src << 16) / dst */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900438 x_ratio = (win_data->src_width << 16) / win_data->crtc_width;
439 y_ratio = (win_data->src_height << 16) / win_data->crtc_height;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900440
441 if (buf_num == 2) {
442 luma_addr[0] = win_data->dma_addr;
443 chroma_addr[0] = win_data->chroma_dma_addr;
444 } else {
445 luma_addr[0] = win_data->dma_addr;
446 chroma_addr[0] = win_data->dma_addr
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900447 + (win_data->fb_width * win_data->fb_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900448 }
449
450 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) {
451 ctx->interlace = true;
452 if (tiled_mode) {
453 luma_addr[1] = luma_addr[0] + 0x40;
454 chroma_addr[1] = chroma_addr[0] + 0x40;
455 } else {
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900456 luma_addr[1] = luma_addr[0] + win_data->fb_width;
457 chroma_addr[1] = chroma_addr[0] + win_data->fb_width;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900458 }
459 } else {
460 ctx->interlace = false;
461 luma_addr[1] = 0;
462 chroma_addr[1] = 0;
463 }
464
465 spin_lock_irqsave(&res->reg_slock, flags);
466 mixer_vsync_set_update(ctx, false);
467
468 /* interlace or progressive scan mode */
469 val = (ctx->interlace ? ~0 : 0);
470 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
471
472 /* setup format */
473 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
474 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
475 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
476
477 /* setting size of input image */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900478 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_width) |
479 VP_IMG_VSIZE(win_data->fb_height));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900480 /* chroma height has to reduced by 2 to avoid chroma distorions */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900481 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(win_data->fb_width) |
482 VP_IMG_VSIZE(win_data->fb_height / 2));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900483
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900484 vp_reg_write(res, VP_SRC_WIDTH, win_data->src_width);
485 vp_reg_write(res, VP_SRC_HEIGHT, win_data->src_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900486 vp_reg_write(res, VP_SRC_H_POSITION,
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900487 VP_SRC_H_POSITION_VAL(win_data->fb_x));
488 vp_reg_write(res, VP_SRC_V_POSITION, win_data->fb_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900489
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900490 vp_reg_write(res, VP_DST_WIDTH, win_data->crtc_width);
491 vp_reg_write(res, VP_DST_H_POSITION, win_data->crtc_x);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900492 if (ctx->interlace) {
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900493 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height / 2);
494 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y / 2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900495 } else {
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900496 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height);
497 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900498 }
499
500 vp_reg_write(res, VP_H_RATIO, x_ratio);
501 vp_reg_write(res, VP_V_RATIO, y_ratio);
502
503 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
504
505 /* set buffer address to vp */
506 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
507 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
508 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
509 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
510
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900511 mixer_cfg_scan(ctx, win_data->mode_height);
512 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900513 mixer_cfg_layer(ctx, win, true);
514 mixer_run(ctx);
515
516 mixer_vsync_set_update(ctx, true);
517 spin_unlock_irqrestore(&res->reg_slock, flags);
518
519 vp_regs_dump(ctx);
520}
521
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530522static void mixer_layer_update(struct mixer_context *ctx)
523{
524 struct mixer_resources *res = &ctx->mixer_res;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530525
Rahul Sharma5c0f4822014-06-23 11:02:23 +0530526 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530527}
528
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900529static void mixer_graph_buffer(struct mixer_context *ctx, int win)
530{
531 struct mixer_resources *res = &ctx->mixer_res;
532 unsigned long flags;
533 struct hdmi_win_data *win_data;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900534 unsigned int x_ratio, y_ratio;
535 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900536 dma_addr_t dma_addr;
537 unsigned int fmt;
538 u32 val;
539
540 win_data = &ctx->win_data[win];
541
542 #define RGB565 4
543 #define ARGB1555 5
544 #define ARGB4444 6
545 #define ARGB8888 7
546
547 switch (win_data->bpp) {
548 case 16:
549 fmt = ARGB4444;
550 break;
551 case 32:
552 fmt = ARGB8888;
553 break;
554 default:
555 fmt = ARGB8888;
556 }
557
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900558 /* 2x scaling feature */
559 x_ratio = 0;
560 y_ratio = 0;
561
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900562 dst_x_offset = win_data->crtc_x;
563 dst_y_offset = win_data->crtc_y;
564
565 /* converting dma address base and source offset */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900566 dma_addr = win_data->dma_addr
567 + (win_data->fb_x * win_data->bpp >> 3)
568 + (win_data->fb_y * win_data->fb_width * win_data->bpp >> 3);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900569 src_x_offset = 0;
570 src_y_offset = 0;
571
572 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE)
573 ctx->interlace = true;
574 else
575 ctx->interlace = false;
576
577 spin_lock_irqsave(&res->reg_slock, flags);
578 mixer_vsync_set_update(ctx, false);
579
580 /* setup format */
581 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
582 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
583
584 /* setup geometry */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900585 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), win_data->fb_width);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900586
Rahul Sharmadef5e092013-06-19 18:21:08 +0530587 /* setup display size */
588 if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
589 win == MIXER_DEFAULT_WIN) {
590 val = MXR_MXR_RES_HEIGHT(win_data->fb_height);
591 val |= MXR_MXR_RES_WIDTH(win_data->fb_width);
592 mixer_reg_write(res, MXR_RESOLUTION, val);
593 }
594
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900595 val = MXR_GRP_WH_WIDTH(win_data->crtc_width);
596 val |= MXR_GRP_WH_HEIGHT(win_data->crtc_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900597 val |= MXR_GRP_WH_H_SCALE(x_ratio);
598 val |= MXR_GRP_WH_V_SCALE(y_ratio);
599 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
600
601 /* setup offsets in source image */
602 val = MXR_GRP_SXY_SX(src_x_offset);
603 val |= MXR_GRP_SXY_SY(src_y_offset);
604 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
605
606 /* setup offsets in display image */
607 val = MXR_GRP_DXY_DX(dst_x_offset);
608 val |= MXR_GRP_DXY_DY(dst_y_offset);
609 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
610
611 /* set buffer address to mixer */
612 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
613
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900614 mixer_cfg_scan(ctx, win_data->mode_height);
615 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900616 mixer_cfg_layer(ctx, win, true);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530617
618 /* layer update mandatory for mixer 16.0.33.0 */
Rahul Sharmadef5e092013-06-19 18:21:08 +0530619 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
620 ctx->mxr_ver == MXR_VER_128_0_0_184)
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530621 mixer_layer_update(ctx);
622
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900623 mixer_run(ctx);
624
625 mixer_vsync_set_update(ctx, true);
626 spin_unlock_irqrestore(&res->reg_slock, flags);
627}
628
629static void vp_win_reset(struct mixer_context *ctx)
630{
631 struct mixer_resources *res = &ctx->mixer_res;
632 int tries = 100;
633
634 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
635 for (tries = 100; tries; --tries) {
636 /* waiting until VP_SRESET_PROCESSING is 0 */
637 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
638 break;
Sean Paul09760ea2013-01-14 17:03:20 -0500639 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900640 }
641 WARN(tries == 0, "failed to reset Video Processor\n");
642}
643
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900644static void mixer_win_reset(struct mixer_context *ctx)
645{
646 struct mixer_resources *res = &ctx->mixer_res;
647 unsigned long flags;
648 u32 val; /* value stored to register */
649
650 spin_lock_irqsave(&res->reg_slock, flags);
651 mixer_vsync_set_update(ctx, false);
652
653 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
654
655 /* set output in RGB888 mode */
656 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
657
658 /* 16 beat burst in DMA */
659 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
660 MXR_STATUS_BURST_MASK);
661
662 /* setting default layer priority: layer1 > layer0 > video
663 * because typical usage scenario would be
664 * layer1 - OSD
665 * layer0 - framebuffer
666 * video - video overlay
667 */
668 val = MXR_LAYER_CFG_GRP1_VAL(3);
669 val |= MXR_LAYER_CFG_GRP0_VAL(2);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530670 if (ctx->vp_enabled)
671 val |= MXR_LAYER_CFG_VP_VAL(1);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900672 mixer_reg_write(res, MXR_LAYER_CFG, val);
673
674 /* setting background color */
675 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
676 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
677 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
678
679 /* setting graphical layers */
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900680 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
681 val |= MXR_GRP_CFG_WIN_BLEND_EN;
682 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
683
Sean Paul0377f4e2013-04-25 15:13:26 -0400684 /* Don't blend layer 0 onto the mixer background */
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900685 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
Sean Paul0377f4e2013-04-25 15:13:26 -0400686
687 /* Blend layer 1 into layer 0 */
688 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
689 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900690 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
691
Seung-Woo Kim57366032012-05-15 17:22:08 +0900692 /* setting video layers */
693 val = MXR_GRP_CFG_ALPHA_VAL(0);
694 mixer_reg_write(res, MXR_VIDEO_CFG, val);
695
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530696 if (ctx->vp_enabled) {
697 /* configuration of Video Processor Registers */
698 vp_win_reset(ctx);
699 vp_default_filter(res);
700 }
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900701
702 /* disable all layers */
703 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
704 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530705 if (ctx->vp_enabled)
706 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900707
708 mixer_vsync_set_update(ctx, true);
709 spin_unlock_irqrestore(&res->reg_slock, flags);
710}
711
Sean Paul45517892014-01-30 16:19:05 -0500712static irqreturn_t mixer_irq_handler(int irq, void *arg)
713{
714 struct mixer_context *ctx = arg;
715 struct mixer_resources *res = &ctx->mixer_res;
716 u32 val, base, shadow;
717
718 spin_lock(&res->reg_slock);
719
720 /* read interrupt status for handling and clearing flags for VSYNC */
721 val = mixer_reg_read(res, MXR_INT_STATUS);
722
723 /* handling VSYNC */
724 if (val & MXR_INT_STATUS_VSYNC) {
725 /* interlace scan need to check shadow register */
726 if (ctx->interlace) {
727 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
728 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
729 if (base != shadow)
730 goto out;
731
732 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
733 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
734 if (base != shadow)
735 goto out;
736 }
737
738 drm_handle_vblank(ctx->drm_dev, ctx->pipe);
739 exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
740
741 /* set wait vsync event to zero and wake up queue. */
742 if (atomic_read(&ctx->wait_vsync_event)) {
743 atomic_set(&ctx->wait_vsync_event, 0);
744 wake_up(&ctx->wait_vsync_queue);
745 }
746 }
747
748out:
749 /* clear interrupts */
750 if (~val & MXR_INT_EN_VSYNC) {
751 /* vsync interrupt use different bit for read and clear */
752 val &= ~MXR_INT_EN_VSYNC;
753 val |= MXR_INT_CLEAR_VSYNC;
754 }
755 mixer_reg_write(res, MXR_INT_STATUS, val);
756
757 spin_unlock(&res->reg_slock);
758
759 return IRQ_HANDLED;
760}
761
762static int mixer_resources_init(struct mixer_context *mixer_ctx)
763{
764 struct device *dev = &mixer_ctx->pdev->dev;
765 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
766 struct resource *res;
767 int ret;
768
769 spin_lock_init(&mixer_res->reg_slock);
770
771 mixer_res->mixer = devm_clk_get(dev, "mixer");
772 if (IS_ERR(mixer_res->mixer)) {
773 dev_err(dev, "failed to get clock 'mixer'\n");
774 return -ENODEV;
775 }
776
777 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
778 if (IS_ERR(mixer_res->sclk_hdmi)) {
779 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
780 return -ENODEV;
781 }
782 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
783 if (res == NULL) {
784 dev_err(dev, "get memory resource failed.\n");
785 return -ENXIO;
786 }
787
788 mixer_res->mixer_regs = devm_ioremap(dev, res->start,
789 resource_size(res));
790 if (mixer_res->mixer_regs == NULL) {
791 dev_err(dev, "register mapping failed.\n");
792 return -ENXIO;
793 }
794
795 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
796 if (res == NULL) {
797 dev_err(dev, "get interrupt resource failed.\n");
798 return -ENXIO;
799 }
800
801 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
802 0, "drm_mixer", mixer_ctx);
803 if (ret) {
804 dev_err(dev, "request interrupt failed.\n");
805 return ret;
806 }
807 mixer_res->irq = res->start;
808
809 return 0;
810}
811
812static int vp_resources_init(struct mixer_context *mixer_ctx)
813{
814 struct device *dev = &mixer_ctx->pdev->dev;
815 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
816 struct resource *res;
817
818 mixer_res->vp = devm_clk_get(dev, "vp");
819 if (IS_ERR(mixer_res->vp)) {
820 dev_err(dev, "failed to get clock 'vp'\n");
821 return -ENODEV;
822 }
Sean Paul45517892014-01-30 16:19:05 -0500823
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200824 if (mixer_ctx->has_sclk) {
825 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
826 if (IS_ERR(mixer_res->sclk_mixer)) {
827 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
828 return -ENODEV;
829 }
830 mixer_res->mout_mixer = devm_clk_get(dev, "mout_mixer");
831 if (IS_ERR(mixer_res->mout_mixer)) {
832 dev_err(dev, "failed to get clock 'mout_mixer'\n");
833 return -ENODEV;
834 }
835
836 if (mixer_res->sclk_hdmi && mixer_res->mout_mixer)
837 clk_set_parent(mixer_res->mout_mixer,
838 mixer_res->sclk_hdmi);
839 }
Sean Paul45517892014-01-30 16:19:05 -0500840
841 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
842 if (res == NULL) {
843 dev_err(dev, "get memory resource failed.\n");
844 return -ENXIO;
845 }
846
847 mixer_res->vp_regs = devm_ioremap(dev, res->start,
848 resource_size(res));
849 if (mixer_res->vp_regs == NULL) {
850 dev_err(dev, "register mapping failed.\n");
851 return -ENXIO;
852 }
853
854 return 0;
855}
856
Sean Paulf041b252014-01-30 16:19:15 -0500857static int mixer_initialize(struct exynos_drm_manager *mgr,
Inki Daef37cd5e2014-05-09 14:25:20 +0900858 struct drm_device *drm_dev)
Sean Paul45517892014-01-30 16:19:05 -0500859{
860 int ret;
Andrzej Hajda8f0be832014-11-24 14:14:49 +0900861 struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
Inki Daef37cd5e2014-05-09 14:25:20 +0900862 struct exynos_drm_private *priv;
863 priv = drm_dev->dev_private;
Sean Paul45517892014-01-30 16:19:05 -0500864
Inki Daef37cd5e2014-05-09 14:25:20 +0900865 mgr->drm_dev = mixer_ctx->drm_dev = drm_dev;
866 mgr->pipe = mixer_ctx->pipe = priv->pipe++;
Sean Paul45517892014-01-30 16:19:05 -0500867
868 /* acquire resources: regs, irqs, clocks */
869 ret = mixer_resources_init(mixer_ctx);
870 if (ret) {
871 DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
872 return ret;
873 }
874
875 if (mixer_ctx->vp_enabled) {
876 /* acquire vp resources: regs, irqs, clocks */
877 ret = vp_resources_init(mixer_ctx);
878 if (ret) {
879 DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
880 return ret;
881 }
882 }
883
Sean Paulf041b252014-01-30 16:19:15 -0500884 if (!is_drm_iommu_supported(mixer_ctx->drm_dev))
885 return 0;
886
887 return drm_iommu_attach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Sean Paul45517892014-01-30 16:19:05 -0500888}
889
Sean Paulf041b252014-01-30 16:19:15 -0500890static void mixer_mgr_remove(struct exynos_drm_manager *mgr)
Inki Dae1055b392012-10-19 17:37:35 +0900891{
Andrzej Hajda8f0be832014-11-24 14:14:49 +0900892 struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
Inki Dae1055b392012-10-19 17:37:35 +0900893
Sean Paulf041b252014-01-30 16:19:15 -0500894 if (is_drm_iommu_supported(mixer_ctx->drm_dev))
895 drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Inki Dae1055b392012-10-19 17:37:35 +0900896}
897
Sean Paulf041b252014-01-30 16:19:15 -0500898static int mixer_enable_vblank(struct exynos_drm_manager *mgr)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900899{
Andrzej Hajda8f0be832014-11-24 14:14:49 +0900900 struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900901 struct mixer_resources *res = &mixer_ctx->mixer_res;
902
Sean Paulf041b252014-01-30 16:19:15 -0500903 if (!mixer_ctx->powered) {
904 mixer_ctx->int_en |= MXR_INT_EN_VSYNC;
905 return 0;
906 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900907
908 /* enable vsync interrupt */
909 mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
910 MXR_INT_EN_VSYNC);
911
912 return 0;
913}
914
Sean Paulf041b252014-01-30 16:19:15 -0500915static void mixer_disable_vblank(struct exynos_drm_manager *mgr)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900916{
Andrzej Hajda8f0be832014-11-24 14:14:49 +0900917 struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900918 struct mixer_resources *res = &mixer_ctx->mixer_res;
919
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900920 /* disable vsync interrupt */
921 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
922}
923
Sean Paulf041b252014-01-30 16:19:15 -0500924static void mixer_win_mode_set(struct exynos_drm_manager *mgr,
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200925 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900926{
Andrzej Hajda8f0be832014-11-24 14:14:49 +0900927 struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900928 struct hdmi_win_data *win_data;
929 int win;
930
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200931 if (!plane) {
932 DRM_ERROR("plane is NULL\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900933 return;
934 }
935
936 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 -0200937 plane->fb_width, plane->fb_height,
938 plane->fb_x, plane->fb_y,
939 plane->crtc_width, plane->crtc_height,
940 plane->crtc_x, plane->crtc_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900941
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200942 win = plane->zpos;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900943 if (win == DEFAULT_ZPOS)
Joonyoung Shima2ee1512012-04-05 20:49:25 +0900944 win = MIXER_DEFAULT_WIN;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900945
Krzysztof Kozlowski1586d802013-05-27 15:00:43 +0900946 if (win < 0 || win >= MIXER_WIN_NR) {
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900947 DRM_ERROR("mixer window[%d] is wrong\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900948 return;
949 }
950
951 win_data = &mixer_ctx->win_data[win];
952
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200953 win_data->dma_addr = plane->dma_addr[0];
954 win_data->chroma_dma_addr = plane->dma_addr[1];
955 win_data->pixel_format = plane->pixel_format;
956 win_data->bpp = plane->bpp;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900957
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200958 win_data->crtc_x = plane->crtc_x;
959 win_data->crtc_y = plane->crtc_y;
960 win_data->crtc_width = plane->crtc_width;
961 win_data->crtc_height = plane->crtc_height;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900962
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200963 win_data->fb_x = plane->fb_x;
964 win_data->fb_y = plane->fb_y;
965 win_data->fb_width = plane->fb_width;
966 win_data->fb_height = plane->fb_height;
967 win_data->src_width = plane->src_width;
968 win_data->src_height = plane->src_height;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900969
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200970 win_data->mode_width = plane->mode_width;
971 win_data->mode_height = plane->mode_height;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900972
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200973 win_data->scan_flags = plane->scan_flag;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900974}
975
Sean Paulf041b252014-01-30 16:19:15 -0500976static void mixer_win_commit(struct exynos_drm_manager *mgr, int zpos)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900977{
Andrzej Hajda8f0be832014-11-24 14:14:49 +0900978 struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
Sean Paulf041b252014-01-30 16:19:15 -0500979 int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900980
YoungJun Chocbc4c332013-06-12 10:44:40 +0900981 DRM_DEBUG_KMS("win: %d\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900982
Shirish Sdda90122013-01-23 22:03:18 -0500983 mutex_lock(&mixer_ctx->mixer_mutex);
984 if (!mixer_ctx->powered) {
985 mutex_unlock(&mixer_ctx->mixer_mutex);
986 return;
987 }
988 mutex_unlock(&mixer_ctx->mixer_mutex);
989
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530990 if (win > 1 && mixer_ctx->vp_enabled)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900991 vp_video_buffer(mixer_ctx, win);
992 else
993 mixer_graph_buffer(mixer_ctx, win);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530994
995 mixer_ctx->win_data[win].enabled = true;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900996}
997
Sean Paulf041b252014-01-30 16:19:15 -0500998static void mixer_win_disable(struct exynos_drm_manager *mgr, int zpos)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900999{
Andrzej Hajda8f0be832014-11-24 14:14:49 +09001000 struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001001 struct mixer_resources *res = &mixer_ctx->mixer_res;
Sean Paulf041b252014-01-30 16:19:15 -05001002 int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001003 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001004
YoungJun Chocbc4c332013-06-12 10:44:40 +09001005 DRM_DEBUG_KMS("win: %d\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001006
Prathyush Kdb43fd12012-12-06 20:16:05 +05301007 mutex_lock(&mixer_ctx->mixer_mutex);
1008 if (!mixer_ctx->powered) {
1009 mutex_unlock(&mixer_ctx->mixer_mutex);
1010 mixer_ctx->win_data[win].resume = false;
1011 return;
1012 }
1013 mutex_unlock(&mixer_ctx->mixer_mutex);
1014
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001015 spin_lock_irqsave(&res->reg_slock, flags);
1016 mixer_vsync_set_update(mixer_ctx, false);
1017
1018 mixer_cfg_layer(mixer_ctx, win, false);
1019
1020 mixer_vsync_set_update(mixer_ctx, true);
1021 spin_unlock_irqrestore(&res->reg_slock, flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301022
1023 mixer_ctx->win_data[win].enabled = false;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001024}
1025
Sean Paulf041b252014-01-30 16:19:15 -05001026static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr)
Rahul Sharma0ea68222013-01-15 08:11:06 -05001027{
Andrzej Hajda8f0be832014-11-24 14:14:49 +09001028 struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
Joonyoung Shim7c4c5582015-01-18 17:48:29 +09001029 int err;
Prathyush K8137a2e2012-12-06 20:16:01 +05301030
Prathyush K6e95d5e2012-12-06 20:16:03 +05301031 mutex_lock(&mixer_ctx->mixer_mutex);
1032 if (!mixer_ctx->powered) {
1033 mutex_unlock(&mixer_ctx->mixer_mutex);
1034 return;
1035 }
1036 mutex_unlock(&mixer_ctx->mixer_mutex);
1037
Joonyoung Shim7c4c5582015-01-18 17:48:29 +09001038 err = drm_vblank_get(mgr->crtc->dev, mixer_ctx->pipe);
1039 if (err < 0) {
1040 DRM_DEBUG_KMS("failed to acquire vblank counter\n");
1041 return;
1042 }
Rahul Sharma5d39b9e2014-06-23 11:02:25 +05301043
Prathyush K6e95d5e2012-12-06 20:16:03 +05301044 atomic_set(&mixer_ctx->wait_vsync_event, 1);
1045
1046 /*
1047 * wait for MIXER to signal VSYNC interrupt or return after
1048 * timeout which is set to 50ms (refresh rate of 20).
1049 */
1050 if (!wait_event_timeout(mixer_ctx->wait_vsync_queue,
1051 !atomic_read(&mixer_ctx->wait_vsync_event),
Daniel Vetterbfd83032013-12-11 11:34:41 +01001052 HZ/20))
Prathyush K8137a2e2012-12-06 20:16:01 +05301053 DRM_DEBUG_KMS("vblank wait timed out.\n");
Rahul Sharma5d39b9e2014-06-23 11:02:25 +05301054
1055 drm_vblank_put(mgr->crtc->dev, mixer_ctx->pipe);
Prathyush K8137a2e2012-12-06 20:16:01 +05301056}
1057
Sean Paulf041b252014-01-30 16:19:15 -05001058static void mixer_window_suspend(struct exynos_drm_manager *mgr)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301059{
Andrzej Hajda8f0be832014-11-24 14:14:49 +09001060 struct mixer_context *ctx = mgr_to_mixer(mgr);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301061 struct hdmi_win_data *win_data;
1062 int i;
1063
1064 for (i = 0; i < MIXER_WIN_NR; i++) {
1065 win_data = &ctx->win_data[i];
1066 win_data->resume = win_data->enabled;
Sean Paulf041b252014-01-30 16:19:15 -05001067 mixer_win_disable(mgr, i);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301068 }
Sean Paulf041b252014-01-30 16:19:15 -05001069 mixer_wait_for_vblank(mgr);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301070}
1071
Sean Paulf041b252014-01-30 16:19:15 -05001072static void mixer_window_resume(struct exynos_drm_manager *mgr)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301073{
Andrzej Hajda8f0be832014-11-24 14:14:49 +09001074 struct mixer_context *ctx = mgr_to_mixer(mgr);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301075 struct hdmi_win_data *win_data;
1076 int i;
1077
1078 for (i = 0; i < MIXER_WIN_NR; i++) {
1079 win_data = &ctx->win_data[i];
1080 win_data->enabled = win_data->resume;
1081 win_data->resume = false;
Sean Paul87244fa2014-01-30 16:19:07 -05001082 if (win_data->enabled)
Sean Paulf041b252014-01-30 16:19:15 -05001083 mixer_win_commit(mgr, i);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301084 }
1085}
1086
Sean Paulf041b252014-01-30 16:19:15 -05001087static void mixer_poweron(struct exynos_drm_manager *mgr)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301088{
Andrzej Hajda8f0be832014-11-24 14:14:49 +09001089 struct mixer_context *ctx = mgr_to_mixer(mgr);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301090 struct mixer_resources *res = &ctx->mixer_res;
1091
Prathyush Kdb43fd12012-12-06 20:16:05 +05301092 mutex_lock(&ctx->mixer_mutex);
1093 if (ctx->powered) {
1094 mutex_unlock(&ctx->mixer_mutex);
1095 return;
1096 }
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301097
Prathyush Kdb43fd12012-12-06 20:16:05 +05301098 mutex_unlock(&ctx->mixer_mutex);
1099
Sean Paulaf65c802014-01-30 16:19:27 -05001100 pm_runtime_get_sync(ctx->dev);
1101
Sean Paul0bfb1f82013-06-11 12:24:02 +05301102 clk_prepare_enable(res->mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301103 if (ctx->vp_enabled) {
Sean Paul0bfb1f82013-06-11 12:24:02 +05301104 clk_prepare_enable(res->vp);
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001105 if (ctx->has_sclk)
1106 clk_prepare_enable(res->sclk_mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301107 }
1108
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301109 mutex_lock(&ctx->mixer_mutex);
1110 ctx->powered = true;
1111 mutex_unlock(&ctx->mixer_mutex);
1112
Rahul Sharmad74ed932014-06-23 11:02:24 +05301113 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
1114
Prathyush Kdb43fd12012-12-06 20:16:05 +05301115 mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
1116 mixer_win_reset(ctx);
1117
Sean Paulf041b252014-01-30 16:19:15 -05001118 mixer_window_resume(mgr);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301119}
1120
Sean Paulf041b252014-01-30 16:19:15 -05001121static void mixer_poweroff(struct exynos_drm_manager *mgr)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301122{
Andrzej Hajda8f0be832014-11-24 14:14:49 +09001123 struct mixer_context *ctx = mgr_to_mixer(mgr);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301124 struct mixer_resources *res = &ctx->mixer_res;
1125
Prathyush Kdb43fd12012-12-06 20:16:05 +05301126 mutex_lock(&ctx->mixer_mutex);
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301127 if (!ctx->powered) {
1128 mutex_unlock(&ctx->mixer_mutex);
1129 return;
1130 }
Prathyush Kdb43fd12012-12-06 20:16:05 +05301131 mutex_unlock(&ctx->mixer_mutex);
1132
Rahul Sharma381be022014-06-23 11:02:22 +05301133 mixer_stop(ctx);
Sean Paulf041b252014-01-30 16:19:15 -05001134 mixer_window_suspend(mgr);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301135
1136 ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
1137
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301138 mutex_lock(&ctx->mixer_mutex);
1139 ctx->powered = false;
1140 mutex_unlock(&ctx->mixer_mutex);
1141
Sean Paul0bfb1f82013-06-11 12:24:02 +05301142 clk_disable_unprepare(res->mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301143 if (ctx->vp_enabled) {
Sean Paul0bfb1f82013-06-11 12:24:02 +05301144 clk_disable_unprepare(res->vp);
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001145 if (ctx->has_sclk)
1146 clk_disable_unprepare(res->sclk_mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301147 }
1148
Sean Paulaf65c802014-01-30 16:19:27 -05001149 pm_runtime_put_sync(ctx->dev);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301150}
1151
Sean Paulf041b252014-01-30 16:19:15 -05001152static void mixer_dpms(struct exynos_drm_manager *mgr, int mode)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301153{
Prathyush Kdb43fd12012-12-06 20:16:05 +05301154 switch (mode) {
1155 case DRM_MODE_DPMS_ON:
Sean Paulaf65c802014-01-30 16:19:27 -05001156 mixer_poweron(mgr);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301157 break;
1158 case DRM_MODE_DPMS_STANDBY:
1159 case DRM_MODE_DPMS_SUSPEND:
1160 case DRM_MODE_DPMS_OFF:
Sean Paulaf65c802014-01-30 16:19:27 -05001161 mixer_poweroff(mgr);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301162 break;
1163 default:
1164 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
1165 break;
1166 }
1167}
1168
Sean Paulf041b252014-01-30 16:19:15 -05001169/* Only valid for Mixer version 16.0.33.0 */
1170int mixer_check_mode(struct drm_display_mode *mode)
1171{
1172 u32 w, h;
1173
1174 w = mode->hdisplay;
1175 h = mode->vdisplay;
1176
1177 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
1178 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1179 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1180
1181 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
1182 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1183 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1184 return 0;
1185
1186 return -EINVAL;
1187}
1188
1189static struct exynos_drm_manager_ops mixer_manager_ops = {
Sean Paulf041b252014-01-30 16:19:15 -05001190 .dpms = mixer_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001191 .enable_vblank = mixer_enable_vblank,
1192 .disable_vblank = mixer_disable_vblank,
Prathyush K8137a2e2012-12-06 20:16:01 +05301193 .wait_for_vblank = mixer_wait_for_vblank,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001194 .win_mode_set = mixer_win_mode_set,
1195 .win_commit = mixer_win_commit,
1196 .win_disable = mixer_win_disable,
Sean Paulf041b252014-01-30 16:19:15 -05001197};
Rahul Sharma0ea68222013-01-15 08:11:06 -05001198
Rahul Sharmadef5e092013-06-19 18:21:08 +05301199static struct mixer_drv_data exynos5420_mxr_drv_data = {
1200 .version = MXR_VER_128_0_0_184,
1201 .is_vp_enabled = 0,
1202};
1203
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301204static struct mixer_drv_data exynos5250_mxr_drv_data = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301205 .version = MXR_VER_16_0_33_0,
1206 .is_vp_enabled = 0,
1207};
1208
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001209static struct mixer_drv_data exynos4212_mxr_drv_data = {
1210 .version = MXR_VER_0_0_0_16,
1211 .is_vp_enabled = 1,
1212};
1213
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301214static struct mixer_drv_data exynos4210_mxr_drv_data = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301215 .version = MXR_VER_0_0_0_16,
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301216 .is_vp_enabled = 1,
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001217 .has_sclk = 1,
Rahul Sharma1e123442012-10-04 20:48:51 +05301218};
1219
1220static struct platform_device_id mixer_driver_types[] = {
1221 {
1222 .name = "s5p-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301223 .driver_data = (unsigned long)&exynos4210_mxr_drv_data,
Rahul Sharma1e123442012-10-04 20:48:51 +05301224 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301225 .name = "exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301226 .driver_data = (unsigned long)&exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301227 }, {
1228 /* end node */
1229 }
1230};
1231
1232static struct of_device_id mixer_match_types[] = {
1233 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001234 .compatible = "samsung,exynos4210-mixer",
1235 .data = &exynos4210_mxr_drv_data,
1236 }, {
1237 .compatible = "samsung,exynos4212-mixer",
1238 .data = &exynos4212_mxr_drv_data,
1239 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301240 .compatible = "samsung,exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301241 .data = &exynos5250_mxr_drv_data,
1242 }, {
1243 .compatible = "samsung,exynos5250-mixer",
1244 .data = &exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301245 }, {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301246 .compatible = "samsung,exynos5420-mixer",
1247 .data = &exynos5420_mxr_drv_data,
1248 }, {
Rahul Sharma1e123442012-10-04 20:48:51 +05301249 /* end node */
1250 }
1251};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001252MODULE_DEVICE_TABLE(of, mixer_match_types);
Rahul Sharma1e123442012-10-04 20:48:51 +05301253
Inki Daef37cd5e2014-05-09 14:25:20 +09001254static int mixer_bind(struct device *dev, struct device *manager, void *data)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001255{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001256 struct mixer_context *ctx = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09001257 struct drm_device *drm_dev = data;
Inki Daef37cd5e2014-05-09 14:25:20 +09001258 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001259
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001260 ret = mixer_initialize(&ctx->manager, drm_dev);
1261 if (ret)
1262 return ret;
1263
Gustavo Padovane09f2b02014-11-04 18:25:27 -02001264 ret = exynos_drm_crtc_create(&ctx->manager, ctx->pipe);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001265 if (ret) {
1266 mixer_mgr_remove(&ctx->manager);
1267 return ret;
1268 }
1269
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001270 return 0;
1271}
1272
1273static void mixer_unbind(struct device *dev, struct device *master, void *data)
1274{
1275 struct mixer_context *ctx = dev_get_drvdata(dev);
1276
1277 mixer_mgr_remove(&ctx->manager);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001278}
1279
1280static const struct component_ops mixer_component_ops = {
1281 .bind = mixer_bind,
1282 .unbind = mixer_unbind,
1283};
1284
1285static int mixer_probe(struct platform_device *pdev)
1286{
1287 struct device *dev = &pdev->dev;
1288 struct mixer_drv_data *drv;
1289 struct mixer_context *ctx;
1290 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001291
Sean Paulf041b252014-01-30 16:19:15 -05001292 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1293 if (!ctx) {
1294 DRM_ERROR("failed to alloc mixer context.\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001295 return -ENOMEM;
Sean Paulf041b252014-01-30 16:19:15 -05001296 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001297
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001298 mutex_init(&ctx->mixer_mutex);
1299
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001300 ctx->manager.type = EXYNOS_DISPLAY_TYPE_HDMI;
1301 ctx->manager.ops = &mixer_manager_ops;
1302
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301303 if (dev->of_node) {
1304 const struct of_device_id *match;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001305
Sachin Kamate436b092013-06-05 16:00:23 +09001306 match = of_match_node(mixer_match_types, dev->of_node);
Rahul Sharma2cdc53b2012-10-31 09:36:26 +05301307 drv = (struct mixer_drv_data *)match->data;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301308 } else {
1309 drv = (struct mixer_drv_data *)
1310 platform_get_device_id(pdev)->driver_data;
1311 }
1312
Sean Paul45517892014-01-30 16:19:05 -05001313 ctx->pdev = pdev;
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001314 ctx->dev = dev;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301315 ctx->vp_enabled = drv->is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001316 ctx->has_sclk = drv->has_sclk;
Rahul Sharma1e123442012-10-04 20:48:51 +05301317 ctx->mxr_ver = drv->version;
Daniel Vetter57ed0f72013-12-11 11:34:43 +01001318 init_waitqueue_head(&ctx->wait_vsync_queue);
Prathyush K6e95d5e2012-12-06 20:16:03 +05301319 atomic_set(&ctx->wait_vsync_event, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001320
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001321 platform_set_drvdata(pdev, ctx);
Inki Daedf5225b2014-05-29 18:28:02 +09001322
1323 ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001324 ctx->manager.type);
Inki Daedf5225b2014-05-29 18:28:02 +09001325 if (ret)
1326 return ret;
1327
1328 ret = component_add(&pdev->dev, &mixer_component_ops);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001329 if (ret) {
Inki Daedf5225b2014-05-29 18:28:02 +09001330 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001331 return ret;
1332 }
1333
1334 pm_runtime_enable(dev);
Inki Daedf5225b2014-05-29 18:28:02 +09001335
1336 return ret;
Inki Daef37cd5e2014-05-09 14:25:20 +09001337}
1338
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001339static int mixer_remove(struct platform_device *pdev)
1340{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001341 pm_runtime_disable(&pdev->dev);
1342
Inki Daedf5225b2014-05-29 18:28:02 +09001343 component_del(&pdev->dev, &mixer_component_ops);
1344 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
1345
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001346 return 0;
1347}
1348
1349struct platform_driver mixer_driver = {
1350 .driver = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301351 .name = "exynos-mixer",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001352 .owner = THIS_MODULE,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301353 .of_match_table = mixer_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001354 },
1355 .probe = mixer_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001356 .remove = mixer_remove,
Rahul Sharma1e123442012-10-04 20:48:51 +05301357 .id_table = mixer_driver_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001358};