blob: 75b47da6c66c496cba9bcf0f96f36f02b38419ce [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;
Marek Szyprowski04427ec2015-02-02 14:20:28 +010075 struct clk *hdmi;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090076 struct clk *sclk_mixer;
77 struct clk *sclk_hdmi;
Marek Szyprowskiff830c92014-07-01 10:10:07 +020078 struct clk *mout_mixer;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090079};
80
Rahul Sharma1e123442012-10-04 20:48:51 +053081enum mixer_version_id {
82 MXR_VER_0_0_0_16,
83 MXR_VER_16_0_33_0,
Rahul Sharmadef5e092013-06-19 18:21:08 +053084 MXR_VER_128_0_0_184,
Rahul Sharma1e123442012-10-04 20:48:51 +053085};
86
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090087struct mixer_context {
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;
Gustavo Padovan93bca242015-01-18 18:16:23 +090091 struct exynos_drm_crtc *crtc;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090092 int pipe;
93 bool interlace;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090094 bool powered;
Rahul Sharma1b8e5742012-10-04 20:48:52 +053095 bool vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +020096 bool has_sclk;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090097 u32 int_en;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090098
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090099 struct mutex mixer_mutex;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +0900100 struct mixer_resources mixer_res;
Joonyoung Shima634dd52012-04-05 20:49:24 +0900101 struct hdmi_win_data win_data[MIXER_WIN_NR];
Rahul Sharma1e123442012-10-04 20:48:51 +0530102 enum mixer_version_id mxr_ver;
Prathyush K6e95d5e2012-12-06 20:16:03 +0530103 wait_queue_head_t wait_vsync_queue;
104 atomic_t wait_vsync_event;
Rahul Sharma1e123442012-10-04 20:48:51 +0530105};
106
107struct mixer_drv_data {
108 enum mixer_version_id version;
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530109 bool is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200110 bool has_sclk;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +0900111};
112
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900113static const u8 filter_y_horiz_tap8[] = {
114 0, -1, -1, -1, -1, -1, -1, -1,
115 -1, -1, -1, -1, -1, 0, 0, 0,
116 0, 2, 4, 5, 6, 6, 6, 6,
117 6, 5, 5, 4, 3, 2, 1, 1,
118 0, -6, -12, -16, -18, -20, -21, -20,
119 -20, -18, -16, -13, -10, -8, -5, -2,
120 127, 126, 125, 121, 114, 107, 99, 89,
121 79, 68, 57, 46, 35, 25, 16, 8,
122};
123
124static const u8 filter_y_vert_tap4[] = {
125 0, -3, -6, -8, -8, -8, -8, -7,
126 -6, -5, -4, -3, -2, -1, -1, 0,
127 127, 126, 124, 118, 111, 102, 92, 81,
128 70, 59, 48, 37, 27, 19, 11, 5,
129 0, 5, 11, 19, 27, 37, 48, 59,
130 70, 81, 92, 102, 111, 118, 124, 126,
131 0, 0, -1, -1, -2, -3, -4, -5,
132 -6, -7, -8, -8, -8, -8, -6, -3,
133};
134
135static const u8 filter_cr_horiz_tap4[] = {
136 0, -3, -6, -8, -8, -8, -8, -7,
137 -6, -5, -4, -3, -2, -1, -1, 0,
138 127, 126, 124, 118, 111, 102, 92, 81,
139 70, 59, 48, 37, 27, 19, 11, 5,
140};
141
142static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
143{
144 return readl(res->vp_regs + reg_id);
145}
146
147static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
148 u32 val)
149{
150 writel(val, res->vp_regs + reg_id);
151}
152
153static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
154 u32 val, u32 mask)
155{
156 u32 old = vp_reg_read(res, reg_id);
157
158 val = (val & mask) | (old & ~mask);
159 writel(val, res->vp_regs + reg_id);
160}
161
162static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
163{
164 return readl(res->mixer_regs + reg_id);
165}
166
167static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
168 u32 val)
169{
170 writel(val, res->mixer_regs + reg_id);
171}
172
173static inline void mixer_reg_writemask(struct mixer_resources *res,
174 u32 reg_id, u32 val, u32 mask)
175{
176 u32 old = mixer_reg_read(res, reg_id);
177
178 val = (val & mask) | (old & ~mask);
179 writel(val, res->mixer_regs + reg_id);
180}
181
182static void mixer_regs_dump(struct mixer_context *ctx)
183{
184#define DUMPREG(reg_id) \
185do { \
186 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
187 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
188} while (0)
189
190 DUMPREG(MXR_STATUS);
191 DUMPREG(MXR_CFG);
192 DUMPREG(MXR_INT_EN);
193 DUMPREG(MXR_INT_STATUS);
194
195 DUMPREG(MXR_LAYER_CFG);
196 DUMPREG(MXR_VIDEO_CFG);
197
198 DUMPREG(MXR_GRAPHIC0_CFG);
199 DUMPREG(MXR_GRAPHIC0_BASE);
200 DUMPREG(MXR_GRAPHIC0_SPAN);
201 DUMPREG(MXR_GRAPHIC0_WH);
202 DUMPREG(MXR_GRAPHIC0_SXY);
203 DUMPREG(MXR_GRAPHIC0_DXY);
204
205 DUMPREG(MXR_GRAPHIC1_CFG);
206 DUMPREG(MXR_GRAPHIC1_BASE);
207 DUMPREG(MXR_GRAPHIC1_SPAN);
208 DUMPREG(MXR_GRAPHIC1_WH);
209 DUMPREG(MXR_GRAPHIC1_SXY);
210 DUMPREG(MXR_GRAPHIC1_DXY);
211#undef DUMPREG
212}
213
214static void vp_regs_dump(struct mixer_context *ctx)
215{
216#define DUMPREG(reg_id) \
217do { \
218 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
219 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
220} while (0)
221
222 DUMPREG(VP_ENABLE);
223 DUMPREG(VP_SRESET);
224 DUMPREG(VP_SHADOW_UPDATE);
225 DUMPREG(VP_FIELD_ID);
226 DUMPREG(VP_MODE);
227 DUMPREG(VP_IMG_SIZE_Y);
228 DUMPREG(VP_IMG_SIZE_C);
229 DUMPREG(VP_PER_RATE_CTRL);
230 DUMPREG(VP_TOP_Y_PTR);
231 DUMPREG(VP_BOT_Y_PTR);
232 DUMPREG(VP_TOP_C_PTR);
233 DUMPREG(VP_BOT_C_PTR);
234 DUMPREG(VP_ENDIAN_MODE);
235 DUMPREG(VP_SRC_H_POSITION);
236 DUMPREG(VP_SRC_V_POSITION);
237 DUMPREG(VP_SRC_WIDTH);
238 DUMPREG(VP_SRC_HEIGHT);
239 DUMPREG(VP_DST_H_POSITION);
240 DUMPREG(VP_DST_V_POSITION);
241 DUMPREG(VP_DST_WIDTH);
242 DUMPREG(VP_DST_HEIGHT);
243 DUMPREG(VP_H_RATIO);
244 DUMPREG(VP_V_RATIO);
245
246#undef DUMPREG
247}
248
249static inline void vp_filter_set(struct mixer_resources *res,
250 int reg_id, const u8 *data, unsigned int size)
251{
252 /* assure 4-byte align */
253 BUG_ON(size & 3);
254 for (; size; size -= 4, reg_id += 4, data += 4) {
255 u32 val = (data[0] << 24) | (data[1] << 16) |
256 (data[2] << 8) | data[3];
257 vp_reg_write(res, reg_id, val);
258 }
259}
260
261static void vp_default_filter(struct mixer_resources *res)
262{
263 vp_filter_set(res, VP_POLY8_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530264 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900265 vp_filter_set(res, VP_POLY4_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530266 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900267 vp_filter_set(res, VP_POLY4_C0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530268 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900269}
270
271static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
272{
273 struct mixer_resources *res = &ctx->mixer_res;
274
275 /* block update on vsync */
276 mixer_reg_writemask(res, MXR_STATUS, enable ?
277 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
278
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530279 if (ctx->vp_enabled)
280 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900281 VP_SHADOW_UPDATE_ENABLE : 0);
282}
283
284static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
285{
286 struct mixer_resources *res = &ctx->mixer_res;
287 u32 val;
288
289 /* choosing between interlace and progressive mode */
290 val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
291 MXR_CFG_SCAN_PROGRASSIVE);
292
Rahul Sharmadef5e092013-06-19 18:21:08 +0530293 if (ctx->mxr_ver != MXR_VER_128_0_0_184) {
294 /* choosing between proper HD and SD mode */
295 if (height <= 480)
296 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
297 else if (height <= 576)
298 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
299 else if (height <= 720)
300 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
301 else if (height <= 1080)
302 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
303 else
304 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
305 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900306
307 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
308}
309
310static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
311{
312 struct mixer_resources *res = &ctx->mixer_res;
313 u32 val;
314
315 if (height == 480) {
316 val = MXR_CFG_RGB601_0_255;
317 } else if (height == 576) {
318 val = MXR_CFG_RGB601_0_255;
319 } else if (height == 720) {
320 val = MXR_CFG_RGB709_16_235;
321 mixer_reg_write(res, MXR_CM_COEFF_Y,
322 (1 << 30) | (94 << 20) | (314 << 10) |
323 (32 << 0));
324 mixer_reg_write(res, MXR_CM_COEFF_CB,
325 (972 << 20) | (851 << 10) | (225 << 0));
326 mixer_reg_write(res, MXR_CM_COEFF_CR,
327 (225 << 20) | (820 << 10) | (1004 << 0));
328 } else if (height == 1080) {
329 val = MXR_CFG_RGB709_16_235;
330 mixer_reg_write(res, MXR_CM_COEFF_Y,
331 (1 << 30) | (94 << 20) | (314 << 10) |
332 (32 << 0));
333 mixer_reg_write(res, MXR_CM_COEFF_CB,
334 (972 << 20) | (851 << 10) | (225 << 0));
335 mixer_reg_write(res, MXR_CM_COEFF_CR,
336 (225 << 20) | (820 << 10) | (1004 << 0));
337 } else {
338 val = MXR_CFG_RGB709_16_235;
339 mixer_reg_write(res, MXR_CM_COEFF_Y,
340 (1 << 30) | (94 << 20) | (314 << 10) |
341 (32 << 0));
342 mixer_reg_write(res, MXR_CM_COEFF_CB,
343 (972 << 20) | (851 << 10) | (225 << 0));
344 mixer_reg_write(res, MXR_CM_COEFF_CR,
345 (225 << 20) | (820 << 10) | (1004 << 0));
346 }
347
348 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
349}
350
351static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable)
352{
353 struct mixer_resources *res = &ctx->mixer_res;
354 u32 val = enable ? ~0 : 0;
355
356 switch (win) {
357 case 0:
358 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
359 break;
360 case 1:
361 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
362 break;
363 case 2:
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530364 if (ctx->vp_enabled) {
365 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
366 mixer_reg_writemask(res, MXR_CFG, val,
367 MXR_CFG_VP_ENABLE);
Joonyoung Shimf1e716d2014-07-25 19:59:10 +0900368
369 /* control blending of graphic layer 0 */
370 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(0), val,
371 MXR_GRP_CFG_BLEND_PRE_MUL |
372 MXR_GRP_CFG_PIXEL_BLEND_EN);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530373 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900374 break;
375 }
376}
377
378static void mixer_run(struct mixer_context *ctx)
379{
380 struct mixer_resources *res = &ctx->mixer_res;
381
382 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
383
384 mixer_regs_dump(ctx);
385}
386
Rahul Sharma381be022014-06-23 11:02:22 +0530387static void mixer_stop(struct mixer_context *ctx)
388{
389 struct mixer_resources *res = &ctx->mixer_res;
390 int timeout = 20;
391
392 mixer_reg_writemask(res, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
393
394 while (!(mixer_reg_read(res, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
395 --timeout)
396 usleep_range(10000, 12000);
397
398 mixer_regs_dump(ctx);
399}
400
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900401static void vp_video_buffer(struct mixer_context *ctx, int win)
402{
403 struct mixer_resources *res = &ctx->mixer_res;
404 unsigned long flags;
405 struct hdmi_win_data *win_data;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900406 unsigned int x_ratio, y_ratio;
YoungJun Cho782953e2013-07-01 13:04:12 +0900407 unsigned int buf_num = 1;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900408 dma_addr_t luma_addr[2], chroma_addr[2];
409 bool tiled_mode = false;
410 bool crcb_mode = false;
411 u32 val;
412
413 win_data = &ctx->win_data[win];
414
415 switch (win_data->pixel_format) {
416 case DRM_FORMAT_NV12MT:
417 tiled_mode = true;
Ville Syrjälä363b06a2012-05-14 11:08:51 +0900418 case DRM_FORMAT_NV12:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900419 crcb_mode = false;
420 buf_num = 2;
421 break;
422 /* TODO: single buffer format NV12, NV21 */
423 default:
424 /* ignore pixel format at disable time */
425 if (!win_data->dma_addr)
426 break;
427
428 DRM_ERROR("pixel format for vp is wrong [%d].\n",
429 win_data->pixel_format);
430 return;
431 }
432
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900433 /* scaling feature: (src << 16) / dst */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900434 x_ratio = (win_data->src_width << 16) / win_data->crtc_width;
435 y_ratio = (win_data->src_height << 16) / win_data->crtc_height;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900436
437 if (buf_num == 2) {
438 luma_addr[0] = win_data->dma_addr;
439 chroma_addr[0] = win_data->chroma_dma_addr;
440 } else {
441 luma_addr[0] = win_data->dma_addr;
442 chroma_addr[0] = win_data->dma_addr
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900443 + (win_data->fb_width * win_data->fb_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900444 }
445
446 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) {
447 ctx->interlace = true;
448 if (tiled_mode) {
449 luma_addr[1] = luma_addr[0] + 0x40;
450 chroma_addr[1] = chroma_addr[0] + 0x40;
451 } else {
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900452 luma_addr[1] = luma_addr[0] + win_data->fb_width;
453 chroma_addr[1] = chroma_addr[0] + win_data->fb_width;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900454 }
455 } else {
456 ctx->interlace = false;
457 luma_addr[1] = 0;
458 chroma_addr[1] = 0;
459 }
460
461 spin_lock_irqsave(&res->reg_slock, flags);
462 mixer_vsync_set_update(ctx, false);
463
464 /* interlace or progressive scan mode */
465 val = (ctx->interlace ? ~0 : 0);
466 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
467
468 /* setup format */
469 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
470 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
471 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
472
473 /* setting size of input image */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900474 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_width) |
475 VP_IMG_VSIZE(win_data->fb_height));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900476 /* chroma height has to reduced by 2 to avoid chroma distorions */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900477 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(win_data->fb_width) |
478 VP_IMG_VSIZE(win_data->fb_height / 2));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900479
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900480 vp_reg_write(res, VP_SRC_WIDTH, win_data->src_width);
481 vp_reg_write(res, VP_SRC_HEIGHT, win_data->src_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900482 vp_reg_write(res, VP_SRC_H_POSITION,
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900483 VP_SRC_H_POSITION_VAL(win_data->fb_x));
484 vp_reg_write(res, VP_SRC_V_POSITION, win_data->fb_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900485
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900486 vp_reg_write(res, VP_DST_WIDTH, win_data->crtc_width);
487 vp_reg_write(res, VP_DST_H_POSITION, win_data->crtc_x);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900488 if (ctx->interlace) {
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900489 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height / 2);
490 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y / 2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900491 } else {
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900492 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height);
493 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900494 }
495
496 vp_reg_write(res, VP_H_RATIO, x_ratio);
497 vp_reg_write(res, VP_V_RATIO, y_ratio);
498
499 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
500
501 /* set buffer address to vp */
502 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
503 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
504 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
505 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
506
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900507 mixer_cfg_scan(ctx, win_data->mode_height);
508 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900509 mixer_cfg_layer(ctx, win, true);
510 mixer_run(ctx);
511
512 mixer_vsync_set_update(ctx, true);
513 spin_unlock_irqrestore(&res->reg_slock, flags);
514
515 vp_regs_dump(ctx);
516}
517
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530518static void mixer_layer_update(struct mixer_context *ctx)
519{
520 struct mixer_resources *res = &ctx->mixer_res;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530521
Rahul Sharma5c0f4822014-06-23 11:02:23 +0530522 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530523}
524
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900525static void mixer_graph_buffer(struct mixer_context *ctx, int win)
526{
527 struct mixer_resources *res = &ctx->mixer_res;
528 unsigned long flags;
529 struct hdmi_win_data *win_data;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900530 unsigned int x_ratio, y_ratio;
531 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900532 dma_addr_t dma_addr;
533 unsigned int fmt;
534 u32 val;
535
536 win_data = &ctx->win_data[win];
537
538 #define RGB565 4
539 #define ARGB1555 5
540 #define ARGB4444 6
541 #define ARGB8888 7
542
543 switch (win_data->bpp) {
544 case 16:
545 fmt = ARGB4444;
546 break;
547 case 32:
548 fmt = ARGB8888;
549 break;
550 default:
551 fmt = ARGB8888;
552 }
553
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900554 /* 2x scaling feature */
555 x_ratio = 0;
556 y_ratio = 0;
557
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900558 dst_x_offset = win_data->crtc_x;
559 dst_y_offset = win_data->crtc_y;
560
561 /* converting dma address base and source offset */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900562 dma_addr = win_data->dma_addr
563 + (win_data->fb_x * win_data->bpp >> 3)
564 + (win_data->fb_y * win_data->fb_width * win_data->bpp >> 3);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900565 src_x_offset = 0;
566 src_y_offset = 0;
567
568 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE)
569 ctx->interlace = true;
570 else
571 ctx->interlace = false;
572
573 spin_lock_irqsave(&res->reg_slock, flags);
574 mixer_vsync_set_update(ctx, false);
575
576 /* setup format */
577 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
578 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
579
580 /* setup geometry */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900581 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), win_data->fb_width);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900582
Rahul Sharmadef5e092013-06-19 18:21:08 +0530583 /* setup display size */
584 if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
585 win == MIXER_DEFAULT_WIN) {
586 val = MXR_MXR_RES_HEIGHT(win_data->fb_height);
587 val |= MXR_MXR_RES_WIDTH(win_data->fb_width);
588 mixer_reg_write(res, MXR_RESOLUTION, val);
589 }
590
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900591 val = MXR_GRP_WH_WIDTH(win_data->crtc_width);
592 val |= MXR_GRP_WH_HEIGHT(win_data->crtc_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900593 val |= MXR_GRP_WH_H_SCALE(x_ratio);
594 val |= MXR_GRP_WH_V_SCALE(y_ratio);
595 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
596
597 /* setup offsets in source image */
598 val = MXR_GRP_SXY_SX(src_x_offset);
599 val |= MXR_GRP_SXY_SY(src_y_offset);
600 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
601
602 /* setup offsets in display image */
603 val = MXR_GRP_DXY_DX(dst_x_offset);
604 val |= MXR_GRP_DXY_DY(dst_y_offset);
605 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
606
607 /* set buffer address to mixer */
608 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
609
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900610 mixer_cfg_scan(ctx, win_data->mode_height);
611 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900612 mixer_cfg_layer(ctx, win, true);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530613
614 /* layer update mandatory for mixer 16.0.33.0 */
Rahul Sharmadef5e092013-06-19 18:21:08 +0530615 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
616 ctx->mxr_ver == MXR_VER_128_0_0_184)
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530617 mixer_layer_update(ctx);
618
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900619 mixer_run(ctx);
620
621 mixer_vsync_set_update(ctx, true);
622 spin_unlock_irqrestore(&res->reg_slock, flags);
623}
624
625static void vp_win_reset(struct mixer_context *ctx)
626{
627 struct mixer_resources *res = &ctx->mixer_res;
628 int tries = 100;
629
630 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
631 for (tries = 100; tries; --tries) {
632 /* waiting until VP_SRESET_PROCESSING is 0 */
633 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
634 break;
Sean Paul09760ea2013-01-14 17:03:20 -0500635 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900636 }
637 WARN(tries == 0, "failed to reset Video Processor\n");
638}
639
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900640static void mixer_win_reset(struct mixer_context *ctx)
641{
642 struct mixer_resources *res = &ctx->mixer_res;
643 unsigned long flags;
644 u32 val; /* value stored to register */
645
646 spin_lock_irqsave(&res->reg_slock, flags);
647 mixer_vsync_set_update(ctx, false);
648
649 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
650
651 /* set output in RGB888 mode */
652 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
653
654 /* 16 beat burst in DMA */
655 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
656 MXR_STATUS_BURST_MASK);
657
658 /* setting default layer priority: layer1 > layer0 > video
659 * because typical usage scenario would be
660 * layer1 - OSD
661 * layer0 - framebuffer
662 * video - video overlay
663 */
664 val = MXR_LAYER_CFG_GRP1_VAL(3);
665 val |= MXR_LAYER_CFG_GRP0_VAL(2);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530666 if (ctx->vp_enabled)
667 val |= MXR_LAYER_CFG_VP_VAL(1);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900668 mixer_reg_write(res, MXR_LAYER_CFG, val);
669
670 /* setting background color */
671 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
672 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
673 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
674
675 /* setting graphical layers */
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900676 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
677 val |= MXR_GRP_CFG_WIN_BLEND_EN;
678 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
679
Sean Paul0377f4e2013-04-25 15:13:26 -0400680 /* Don't blend layer 0 onto the mixer background */
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900681 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
Sean Paul0377f4e2013-04-25 15:13:26 -0400682
683 /* Blend layer 1 into layer 0 */
684 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
685 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900686 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
687
Seung-Woo Kim57366032012-05-15 17:22:08 +0900688 /* setting video layers */
689 val = MXR_GRP_CFG_ALPHA_VAL(0);
690 mixer_reg_write(res, MXR_VIDEO_CFG, val);
691
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530692 if (ctx->vp_enabled) {
693 /* configuration of Video Processor Registers */
694 vp_win_reset(ctx);
695 vp_default_filter(res);
696 }
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900697
698 /* disable all layers */
699 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
700 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530701 if (ctx->vp_enabled)
702 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900703
704 mixer_vsync_set_update(ctx, true);
705 spin_unlock_irqrestore(&res->reg_slock, flags);
706}
707
Sean Paul45517892014-01-30 16:19:05 -0500708static irqreturn_t mixer_irq_handler(int irq, void *arg)
709{
710 struct mixer_context *ctx = arg;
711 struct mixer_resources *res = &ctx->mixer_res;
712 u32 val, base, shadow;
713
714 spin_lock(&res->reg_slock);
715
716 /* read interrupt status for handling and clearing flags for VSYNC */
717 val = mixer_reg_read(res, MXR_INT_STATUS);
718
719 /* handling VSYNC */
720 if (val & MXR_INT_STATUS_VSYNC) {
721 /* interlace scan need to check shadow register */
722 if (ctx->interlace) {
723 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
724 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
725 if (base != shadow)
726 goto out;
727
728 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
729 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
730 if (base != shadow)
731 goto out;
732 }
733
734 drm_handle_vblank(ctx->drm_dev, ctx->pipe);
735 exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
736
737 /* set wait vsync event to zero and wake up queue. */
738 if (atomic_read(&ctx->wait_vsync_event)) {
739 atomic_set(&ctx->wait_vsync_event, 0);
740 wake_up(&ctx->wait_vsync_queue);
741 }
742 }
743
744out:
745 /* clear interrupts */
746 if (~val & MXR_INT_EN_VSYNC) {
747 /* vsync interrupt use different bit for read and clear */
748 val &= ~MXR_INT_EN_VSYNC;
749 val |= MXR_INT_CLEAR_VSYNC;
750 }
751 mixer_reg_write(res, MXR_INT_STATUS, val);
752
753 spin_unlock(&res->reg_slock);
754
755 return IRQ_HANDLED;
756}
757
758static int mixer_resources_init(struct mixer_context *mixer_ctx)
759{
760 struct device *dev = &mixer_ctx->pdev->dev;
761 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
762 struct resource *res;
763 int ret;
764
765 spin_lock_init(&mixer_res->reg_slock);
766
767 mixer_res->mixer = devm_clk_get(dev, "mixer");
768 if (IS_ERR(mixer_res->mixer)) {
769 dev_err(dev, "failed to get clock 'mixer'\n");
770 return -ENODEV;
771 }
772
Marek Szyprowski04427ec2015-02-02 14:20:28 +0100773 mixer_res->hdmi = devm_clk_get(dev, "hdmi");
774 if (IS_ERR(mixer_res->hdmi)) {
775 dev_err(dev, "failed to get clock 'hdmi'\n");
776 return PTR_ERR(mixer_res->hdmi);
777 }
778
Sean Paul45517892014-01-30 16:19:05 -0500779 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
780 if (IS_ERR(mixer_res->sclk_hdmi)) {
781 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
782 return -ENODEV;
783 }
784 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
785 if (res == NULL) {
786 dev_err(dev, "get memory resource failed.\n");
787 return -ENXIO;
788 }
789
790 mixer_res->mixer_regs = devm_ioremap(dev, res->start,
791 resource_size(res));
792 if (mixer_res->mixer_regs == NULL) {
793 dev_err(dev, "register mapping failed.\n");
794 return -ENXIO;
795 }
796
797 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
798 if (res == NULL) {
799 dev_err(dev, "get interrupt resource failed.\n");
800 return -ENXIO;
801 }
802
803 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
804 0, "drm_mixer", mixer_ctx);
805 if (ret) {
806 dev_err(dev, "request interrupt failed.\n");
807 return ret;
808 }
809 mixer_res->irq = res->start;
810
811 return 0;
812}
813
814static int vp_resources_init(struct mixer_context *mixer_ctx)
815{
816 struct device *dev = &mixer_ctx->pdev->dev;
817 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
818 struct resource *res;
819
820 mixer_res->vp = devm_clk_get(dev, "vp");
821 if (IS_ERR(mixer_res->vp)) {
822 dev_err(dev, "failed to get clock 'vp'\n");
823 return -ENODEV;
824 }
Sean Paul45517892014-01-30 16:19:05 -0500825
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200826 if (mixer_ctx->has_sclk) {
827 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
828 if (IS_ERR(mixer_res->sclk_mixer)) {
829 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
830 return -ENODEV;
831 }
832 mixer_res->mout_mixer = devm_clk_get(dev, "mout_mixer");
833 if (IS_ERR(mixer_res->mout_mixer)) {
834 dev_err(dev, "failed to get clock 'mout_mixer'\n");
835 return -ENODEV;
836 }
837
838 if (mixer_res->sclk_hdmi && mixer_res->mout_mixer)
839 clk_set_parent(mixer_res->mout_mixer,
840 mixer_res->sclk_hdmi);
841 }
Sean Paul45517892014-01-30 16:19:05 -0500842
843 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
844 if (res == NULL) {
845 dev_err(dev, "get memory resource failed.\n");
846 return -ENXIO;
847 }
848
849 mixer_res->vp_regs = devm_ioremap(dev, res->start,
850 resource_size(res));
851 if (mixer_res->vp_regs == NULL) {
852 dev_err(dev, "register mapping failed.\n");
853 return -ENXIO;
854 }
855
856 return 0;
857}
858
Gustavo Padovan93bca242015-01-18 18:16:23 +0900859static int mixer_initialize(struct mixer_context *mixer_ctx,
Inki Daef37cd5e2014-05-09 14:25:20 +0900860 struct drm_device *drm_dev)
Sean Paul45517892014-01-30 16:19:05 -0500861{
862 int ret;
Inki Daef37cd5e2014-05-09 14:25:20 +0900863 struct exynos_drm_private *priv;
864 priv = drm_dev->dev_private;
Sean Paul45517892014-01-30 16:19:05 -0500865
Gustavo Padovaneb88e422014-11-26 16:43:27 -0200866 mixer_ctx->drm_dev = drm_dev;
Gustavo Padovan8a326ed2014-11-04 18:44:47 -0200867 mixer_ctx->pipe = priv->pipe++;
Sean Paul45517892014-01-30 16:19:05 -0500868
869 /* acquire resources: regs, irqs, clocks */
870 ret = mixer_resources_init(mixer_ctx);
871 if (ret) {
872 DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
873 return ret;
874 }
875
876 if (mixer_ctx->vp_enabled) {
877 /* acquire vp resources: regs, irqs, clocks */
878 ret = vp_resources_init(mixer_ctx);
879 if (ret) {
880 DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
881 return ret;
882 }
883 }
884
Sean Paulf041b252014-01-30 16:19:15 -0500885 if (!is_drm_iommu_supported(mixer_ctx->drm_dev))
886 return 0;
887
888 return drm_iommu_attach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Sean Paul45517892014-01-30 16:19:05 -0500889}
890
Gustavo Padovan93bca242015-01-18 18:16:23 +0900891static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
Inki Dae1055b392012-10-19 17:37:35 +0900892{
Sean Paulf041b252014-01-30 16:19:15 -0500893 if (is_drm_iommu_supported(mixer_ctx->drm_dev))
894 drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Inki Dae1055b392012-10-19 17:37:35 +0900895}
896
Gustavo Padovan93bca242015-01-18 18:16:23 +0900897static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900898{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900899 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900900 struct mixer_resources *res = &mixer_ctx->mixer_res;
901
Sean Paulf041b252014-01-30 16:19:15 -0500902 if (!mixer_ctx->powered) {
903 mixer_ctx->int_en |= MXR_INT_EN_VSYNC;
904 return 0;
905 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900906
907 /* enable vsync interrupt */
908 mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
909 MXR_INT_EN_VSYNC);
910
911 return 0;
912}
913
Gustavo Padovan93bca242015-01-18 18:16:23 +0900914static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900915{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900916 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900917 struct mixer_resources *res = &mixer_ctx->mixer_res;
918
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900919 /* disable vsync interrupt */
920 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
921}
922
Gustavo Padovan93bca242015-01-18 18:16:23 +0900923static void mixer_win_mode_set(struct exynos_drm_crtc *crtc,
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200924 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900925{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900926 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900927 struct hdmi_win_data *win_data;
928 int win;
929
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200930 if (!plane) {
931 DRM_ERROR("plane is NULL\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900932 return;
933 }
934
935 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 -0200936 plane->fb_width, plane->fb_height,
937 plane->fb_x, plane->fb_y,
938 plane->crtc_width, plane->crtc_height,
939 plane->crtc_x, plane->crtc_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900940
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200941 win = plane->zpos;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900942 if (win == DEFAULT_ZPOS)
Joonyoung Shima2ee1512012-04-05 20:49:25 +0900943 win = MIXER_DEFAULT_WIN;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900944
Krzysztof Kozlowski1586d802013-05-27 15:00:43 +0900945 if (win < 0 || win >= MIXER_WIN_NR) {
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900946 DRM_ERROR("mixer window[%d] is wrong\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900947 return;
948 }
949
950 win_data = &mixer_ctx->win_data[win];
951
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200952 win_data->dma_addr = plane->dma_addr[0];
953 win_data->chroma_dma_addr = plane->dma_addr[1];
954 win_data->pixel_format = plane->pixel_format;
955 win_data->bpp = plane->bpp;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900956
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200957 win_data->crtc_x = plane->crtc_x;
958 win_data->crtc_y = plane->crtc_y;
959 win_data->crtc_width = plane->crtc_width;
960 win_data->crtc_height = plane->crtc_height;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900961
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200962 win_data->fb_x = plane->fb_x;
963 win_data->fb_y = plane->fb_y;
964 win_data->fb_width = plane->fb_width;
965 win_data->fb_height = plane->fb_height;
966 win_data->src_width = plane->src_width;
967 win_data->src_height = plane->src_height;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900968
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200969 win_data->mode_width = plane->mode_width;
970 win_data->mode_height = plane->mode_height;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900971
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200972 win_data->scan_flags = plane->scan_flag;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900973}
974
Gustavo Padovan93bca242015-01-18 18:16:23 +0900975static void mixer_win_commit(struct exynos_drm_crtc *crtc, int zpos)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900976{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900977 struct mixer_context *mixer_ctx = crtc->ctx;
Sean Paulf041b252014-01-30 16:19:15 -0500978 int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900979
YoungJun Chocbc4c332013-06-12 10:44:40 +0900980 DRM_DEBUG_KMS("win: %d\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900981
Shirish Sdda90122013-01-23 22:03:18 -0500982 mutex_lock(&mixer_ctx->mixer_mutex);
983 if (!mixer_ctx->powered) {
984 mutex_unlock(&mixer_ctx->mixer_mutex);
985 return;
986 }
987 mutex_unlock(&mixer_ctx->mixer_mutex);
988
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530989 if (win > 1 && mixer_ctx->vp_enabled)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900990 vp_video_buffer(mixer_ctx, win);
991 else
992 mixer_graph_buffer(mixer_ctx, win);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530993
994 mixer_ctx->win_data[win].enabled = true;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900995}
996
Gustavo Padovan93bca242015-01-18 18:16:23 +0900997static void mixer_win_disable(struct exynos_drm_crtc *crtc, int zpos)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900998{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900999 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001000 struct mixer_resources *res = &mixer_ctx->mixer_res;
Sean Paulf041b252014-01-30 16:19:15 -05001001 int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001002 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001003
YoungJun Chocbc4c332013-06-12 10:44:40 +09001004 DRM_DEBUG_KMS("win: %d\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001005
Prathyush Kdb43fd12012-12-06 20:16:05 +05301006 mutex_lock(&mixer_ctx->mixer_mutex);
1007 if (!mixer_ctx->powered) {
1008 mutex_unlock(&mixer_ctx->mixer_mutex);
1009 mixer_ctx->win_data[win].resume = false;
1010 return;
1011 }
1012 mutex_unlock(&mixer_ctx->mixer_mutex);
1013
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001014 spin_lock_irqsave(&res->reg_slock, flags);
1015 mixer_vsync_set_update(mixer_ctx, false);
1016
1017 mixer_cfg_layer(mixer_ctx, win, false);
1018
1019 mixer_vsync_set_update(mixer_ctx, true);
1020 spin_unlock_irqrestore(&res->reg_slock, flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301021
1022 mixer_ctx->win_data[win].enabled = false;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001023}
1024
Gustavo Padovan93bca242015-01-18 18:16:23 +09001025static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
Rahul Sharma0ea68222013-01-15 08:11:06 -05001026{
Gustavo Padovan93bca242015-01-18 18:16:23 +09001027 struct mixer_context *mixer_ctx = crtc->ctx;
Joonyoung Shim7c4c5582015-01-18 17:48:29 +09001028 int err;
Prathyush K8137a2e2012-12-06 20:16:01 +05301029
Prathyush K6e95d5e2012-12-06 20:16:03 +05301030 mutex_lock(&mixer_ctx->mixer_mutex);
1031 if (!mixer_ctx->powered) {
1032 mutex_unlock(&mixer_ctx->mixer_mutex);
1033 return;
1034 }
1035 mutex_unlock(&mixer_ctx->mixer_mutex);
1036
Gustavo Padovan93bca242015-01-18 18:16:23 +09001037 err = drm_vblank_get(mixer_ctx->drm_dev, mixer_ctx->pipe);
Joonyoung Shim7c4c5582015-01-18 17:48:29 +09001038 if (err < 0) {
1039 DRM_DEBUG_KMS("failed to acquire vblank counter\n");
1040 return;
1041 }
Rahul Sharma5d39b9e2014-06-23 11:02:25 +05301042
Prathyush K6e95d5e2012-12-06 20:16:03 +05301043 atomic_set(&mixer_ctx->wait_vsync_event, 1);
1044
1045 /*
1046 * wait for MIXER to signal VSYNC interrupt or return after
1047 * timeout which is set to 50ms (refresh rate of 20).
1048 */
1049 if (!wait_event_timeout(mixer_ctx->wait_vsync_queue,
1050 !atomic_read(&mixer_ctx->wait_vsync_event),
Daniel Vetterbfd83032013-12-11 11:34:41 +01001051 HZ/20))
Prathyush K8137a2e2012-12-06 20:16:01 +05301052 DRM_DEBUG_KMS("vblank wait timed out.\n");
Rahul Sharma5d39b9e2014-06-23 11:02:25 +05301053
Gustavo Padovan93bca242015-01-18 18:16:23 +09001054 drm_vblank_put(mixer_ctx->drm_dev, mixer_ctx->pipe);
Prathyush K8137a2e2012-12-06 20:16:01 +05301055}
1056
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001057static void mixer_window_suspend(struct mixer_context *ctx)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301058{
1059 struct hdmi_win_data *win_data;
1060 int i;
1061
1062 for (i = 0; i < MIXER_WIN_NR; i++) {
1063 win_data = &ctx->win_data[i];
1064 win_data->resume = win_data->enabled;
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001065 mixer_win_disable(ctx->crtc, i);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301066 }
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001067 mixer_wait_for_vblank(ctx->crtc);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301068}
1069
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001070static void mixer_window_resume(struct mixer_context *ctx)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301071{
1072 struct hdmi_win_data *win_data;
1073 int i;
1074
1075 for (i = 0; i < MIXER_WIN_NR; i++) {
1076 win_data = &ctx->win_data[i];
1077 win_data->enabled = win_data->resume;
1078 win_data->resume = false;
Sean Paul87244fa2014-01-30 16:19:07 -05001079 if (win_data->enabled)
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001080 mixer_win_commit(ctx->crtc, i);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301081 }
1082}
1083
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001084static void mixer_poweron(struct mixer_context *ctx)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301085{
1086 struct mixer_resources *res = &ctx->mixer_res;
1087
Prathyush Kdb43fd12012-12-06 20:16:05 +05301088 mutex_lock(&ctx->mixer_mutex);
1089 if (ctx->powered) {
1090 mutex_unlock(&ctx->mixer_mutex);
1091 return;
1092 }
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301093
Prathyush Kdb43fd12012-12-06 20:16:05 +05301094 mutex_unlock(&ctx->mixer_mutex);
1095
Sean Paulaf65c802014-01-30 16:19:27 -05001096 pm_runtime_get_sync(ctx->dev);
1097
Sean Paul0bfb1f82013-06-11 12:24:02 +05301098 clk_prepare_enable(res->mixer);
Marek Szyprowski04427ec2015-02-02 14:20:28 +01001099 clk_prepare_enable(res->hdmi);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301100 if (ctx->vp_enabled) {
Sean Paul0bfb1f82013-06-11 12:24:02 +05301101 clk_prepare_enable(res->vp);
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001102 if (ctx->has_sclk)
1103 clk_prepare_enable(res->sclk_mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301104 }
1105
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301106 mutex_lock(&ctx->mixer_mutex);
1107 ctx->powered = true;
1108 mutex_unlock(&ctx->mixer_mutex);
1109
Rahul Sharmad74ed932014-06-23 11:02:24 +05301110 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
1111
Prathyush Kdb43fd12012-12-06 20:16:05 +05301112 mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
1113 mixer_win_reset(ctx);
1114
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001115 mixer_window_resume(ctx);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301116}
1117
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001118static void mixer_poweroff(struct mixer_context *ctx)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301119{
1120 struct mixer_resources *res = &ctx->mixer_res;
1121
Prathyush Kdb43fd12012-12-06 20:16:05 +05301122 mutex_lock(&ctx->mixer_mutex);
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301123 if (!ctx->powered) {
1124 mutex_unlock(&ctx->mixer_mutex);
1125 return;
1126 }
Prathyush Kdb43fd12012-12-06 20:16:05 +05301127 mutex_unlock(&ctx->mixer_mutex);
1128
Rahul Sharma381be022014-06-23 11:02:22 +05301129 mixer_stop(ctx);
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001130 mixer_window_suspend(ctx);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301131
1132 ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
1133
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301134 mutex_lock(&ctx->mixer_mutex);
1135 ctx->powered = false;
1136 mutex_unlock(&ctx->mixer_mutex);
1137
Marek Szyprowski04427ec2015-02-02 14:20:28 +01001138 clk_disable_unprepare(res->hdmi);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301139 clk_disable_unprepare(res->mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301140 if (ctx->vp_enabled) {
Sean Paul0bfb1f82013-06-11 12:24:02 +05301141 clk_disable_unprepare(res->vp);
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001142 if (ctx->has_sclk)
1143 clk_disable_unprepare(res->sclk_mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301144 }
1145
Sean Paulaf65c802014-01-30 16:19:27 -05001146 pm_runtime_put_sync(ctx->dev);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301147}
1148
Gustavo Padovan93bca242015-01-18 18:16:23 +09001149static void mixer_dpms(struct exynos_drm_crtc *crtc, int mode)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301150{
Prathyush Kdb43fd12012-12-06 20:16:05 +05301151 switch (mode) {
1152 case DRM_MODE_DPMS_ON:
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001153 mixer_poweron(crtc->ctx);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301154 break;
1155 case DRM_MODE_DPMS_STANDBY:
1156 case DRM_MODE_DPMS_SUSPEND:
1157 case DRM_MODE_DPMS_OFF:
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001158 mixer_poweroff(crtc->ctx);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301159 break;
1160 default:
1161 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
1162 break;
1163 }
1164}
1165
Sean Paulf041b252014-01-30 16:19:15 -05001166/* Only valid for Mixer version 16.0.33.0 */
1167int mixer_check_mode(struct drm_display_mode *mode)
1168{
1169 u32 w, h;
1170
1171 w = mode->hdisplay;
1172 h = mode->vdisplay;
1173
1174 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
1175 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1176 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1177
1178 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
1179 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1180 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1181 return 0;
1182
1183 return -EINVAL;
1184}
1185
Gustavo Padovan93bca242015-01-18 18:16:23 +09001186static struct exynos_drm_crtc_ops mixer_crtc_ops = {
Sean Paulf041b252014-01-30 16:19:15 -05001187 .dpms = mixer_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001188 .enable_vblank = mixer_enable_vblank,
1189 .disable_vblank = mixer_disable_vblank,
Prathyush K8137a2e2012-12-06 20:16:01 +05301190 .wait_for_vblank = mixer_wait_for_vblank,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001191 .win_mode_set = mixer_win_mode_set,
1192 .win_commit = mixer_win_commit,
1193 .win_disable = mixer_win_disable,
Sean Paulf041b252014-01-30 16:19:15 -05001194};
Rahul Sharma0ea68222013-01-15 08:11:06 -05001195
Rahul Sharmadef5e092013-06-19 18:21:08 +05301196static struct mixer_drv_data exynos5420_mxr_drv_data = {
1197 .version = MXR_VER_128_0_0_184,
1198 .is_vp_enabled = 0,
1199};
1200
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301201static struct mixer_drv_data exynos5250_mxr_drv_data = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301202 .version = MXR_VER_16_0_33_0,
1203 .is_vp_enabled = 0,
1204};
1205
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001206static struct mixer_drv_data exynos4212_mxr_drv_data = {
1207 .version = MXR_VER_0_0_0_16,
1208 .is_vp_enabled = 1,
1209};
1210
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301211static struct mixer_drv_data exynos4210_mxr_drv_data = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301212 .version = MXR_VER_0_0_0_16,
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301213 .is_vp_enabled = 1,
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001214 .has_sclk = 1,
Rahul Sharma1e123442012-10-04 20:48:51 +05301215};
1216
1217static struct platform_device_id mixer_driver_types[] = {
1218 {
1219 .name = "s5p-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301220 .driver_data = (unsigned long)&exynos4210_mxr_drv_data,
Rahul Sharma1e123442012-10-04 20:48:51 +05301221 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301222 .name = "exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301223 .driver_data = (unsigned long)&exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301224 }, {
1225 /* end node */
1226 }
1227};
1228
1229static struct of_device_id mixer_match_types[] = {
1230 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001231 .compatible = "samsung,exynos4210-mixer",
1232 .data = &exynos4210_mxr_drv_data,
1233 }, {
1234 .compatible = "samsung,exynos4212-mixer",
1235 .data = &exynos4212_mxr_drv_data,
1236 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301237 .compatible = "samsung,exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301238 .data = &exynos5250_mxr_drv_data,
1239 }, {
1240 .compatible = "samsung,exynos5250-mixer",
1241 .data = &exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301242 }, {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301243 .compatible = "samsung,exynos5420-mixer",
1244 .data = &exynos5420_mxr_drv_data,
1245 }, {
Rahul Sharma1e123442012-10-04 20:48:51 +05301246 /* end node */
1247 }
1248};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001249MODULE_DEVICE_TABLE(of, mixer_match_types);
Rahul Sharma1e123442012-10-04 20:48:51 +05301250
Inki Daef37cd5e2014-05-09 14:25:20 +09001251static int mixer_bind(struct device *dev, struct device *manager, void *data)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001252{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001253 struct mixer_context *ctx = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09001254 struct drm_device *drm_dev = data;
Inki Daef37cd5e2014-05-09 14:25:20 +09001255 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001256
Gustavo Padovan93bca242015-01-18 18:16:23 +09001257 ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
1258 EXYNOS_DISPLAY_TYPE_HDMI,
1259 &mixer_crtc_ops, ctx);
1260 if (IS_ERR(ctx->crtc)) {
1261 ret = PTR_ERR(ctx->crtc);
1262 goto free_ctx;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001263 }
1264
Gustavo Padovan93bca242015-01-18 18:16:23 +09001265 ret = mixer_initialize(ctx, drm_dev);
1266 if (ret)
1267 goto free_ctx;
1268
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001269 return 0;
Gustavo Padovan93bca242015-01-18 18:16:23 +09001270
1271free_ctx:
1272 devm_kfree(dev, ctx);
1273 return ret;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001274}
1275
1276static void mixer_unbind(struct device *dev, struct device *master, void *data)
1277{
1278 struct mixer_context *ctx = dev_get_drvdata(dev);
1279
Gustavo Padovan93bca242015-01-18 18:16:23 +09001280 mixer_ctx_remove(ctx);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001281}
1282
1283static const struct component_ops mixer_component_ops = {
1284 .bind = mixer_bind,
1285 .unbind = mixer_unbind,
1286};
1287
1288static int mixer_probe(struct platform_device *pdev)
1289{
1290 struct device *dev = &pdev->dev;
1291 struct mixer_drv_data *drv;
1292 struct mixer_context *ctx;
1293 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001294
Sean Paulf041b252014-01-30 16:19:15 -05001295 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1296 if (!ctx) {
1297 DRM_ERROR("failed to alloc mixer context.\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001298 return -ENOMEM;
Sean Paulf041b252014-01-30 16:19:15 -05001299 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001300
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001301 mutex_init(&ctx->mixer_mutex);
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,
Gustavo Padovan5d1741a2014-11-05 19:51:35 -02001324 EXYNOS_DISPLAY_TYPE_HDMI);
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};