blob: 2e3bc57ea50e594dcdf739042c39169428ecbda1 [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;
Daniel Stoneadacb222015-03-17 13:24:58 +000058 unsigned int fb_pitch;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090059 unsigned int fb_height;
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +090060 unsigned int src_width;
61 unsigned int src_height;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090062 unsigned int mode_width;
63 unsigned int mode_height;
64 unsigned int scan_flags;
Prathyush Kdb43fd12012-12-06 20:16:05 +053065 bool enabled;
66 bool resume;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090067};
68
69struct mixer_resources {
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090070 int irq;
71 void __iomem *mixer_regs;
72 void __iomem *vp_regs;
73 spinlock_t reg_slock;
74 struct clk *mixer;
75 struct clk *vp;
Marek Szyprowski04427ec2015-02-02 14:20:28 +010076 struct clk *hdmi;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090077 struct clk *sclk_mixer;
78 struct clk *sclk_hdmi;
Marek Szyprowskiff830c92014-07-01 10:10:07 +020079 struct clk *mout_mixer;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090080};
81
Rahul Sharma1e123442012-10-04 20:48:51 +053082enum mixer_version_id {
83 MXR_VER_0_0_0_16,
84 MXR_VER_16_0_33_0,
Rahul Sharmadef5e092013-06-19 18:21:08 +053085 MXR_VER_128_0_0_184,
Rahul Sharma1e123442012-10-04 20:48:51 +053086};
87
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090088struct mixer_context {
Sean Paul45517892014-01-30 16:19:05 -050089 struct platform_device *pdev;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090090 struct device *dev;
Inki Dae1055b392012-10-19 17:37:35 +090091 struct drm_device *drm_dev;
Gustavo Padovan93bca242015-01-18 18:16:23 +090092 struct exynos_drm_crtc *crtc;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090093 int pipe;
94 bool interlace;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090095 bool powered;
Rahul Sharma1b8e5742012-10-04 20:48:52 +053096 bool vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +020097 bool has_sclk;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090098 u32 int_en;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090099
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900100 struct mutex mixer_mutex;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +0900101 struct mixer_resources mixer_res;
Joonyoung Shima634dd52012-04-05 20:49:24 +0900102 struct hdmi_win_data win_data[MIXER_WIN_NR];
Rahul Sharma1e123442012-10-04 20:48:51 +0530103 enum mixer_version_id mxr_ver;
Prathyush K6e95d5e2012-12-06 20:16:03 +0530104 wait_queue_head_t wait_vsync_queue;
105 atomic_t wait_vsync_event;
Rahul Sharma1e123442012-10-04 20:48:51 +0530106};
107
108struct mixer_drv_data {
109 enum mixer_version_id version;
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530110 bool is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200111 bool has_sclk;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +0900112};
113
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900114static const u8 filter_y_horiz_tap8[] = {
115 0, -1, -1, -1, -1, -1, -1, -1,
116 -1, -1, -1, -1, -1, 0, 0, 0,
117 0, 2, 4, 5, 6, 6, 6, 6,
118 6, 5, 5, 4, 3, 2, 1, 1,
119 0, -6, -12, -16, -18, -20, -21, -20,
120 -20, -18, -16, -13, -10, -8, -5, -2,
121 127, 126, 125, 121, 114, 107, 99, 89,
122 79, 68, 57, 46, 35, 25, 16, 8,
123};
124
125static const u8 filter_y_vert_tap4[] = {
126 0, -3, -6, -8, -8, -8, -8, -7,
127 -6, -5, -4, -3, -2, -1, -1, 0,
128 127, 126, 124, 118, 111, 102, 92, 81,
129 70, 59, 48, 37, 27, 19, 11, 5,
130 0, 5, 11, 19, 27, 37, 48, 59,
131 70, 81, 92, 102, 111, 118, 124, 126,
132 0, 0, -1, -1, -2, -3, -4, -5,
133 -6, -7, -8, -8, -8, -8, -6, -3,
134};
135
136static const u8 filter_cr_horiz_tap4[] = {
137 0, -3, -6, -8, -8, -8, -8, -7,
138 -6, -5, -4, -3, -2, -1, -1, 0,
139 127, 126, 124, 118, 111, 102, 92, 81,
140 70, 59, 48, 37, 27, 19, 11, 5,
141};
142
143static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
144{
145 return readl(res->vp_regs + reg_id);
146}
147
148static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
149 u32 val)
150{
151 writel(val, res->vp_regs + reg_id);
152}
153
154static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
155 u32 val, u32 mask)
156{
157 u32 old = vp_reg_read(res, reg_id);
158
159 val = (val & mask) | (old & ~mask);
160 writel(val, res->vp_regs + reg_id);
161}
162
163static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
164{
165 return readl(res->mixer_regs + reg_id);
166}
167
168static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
169 u32 val)
170{
171 writel(val, res->mixer_regs + reg_id);
172}
173
174static inline void mixer_reg_writemask(struct mixer_resources *res,
175 u32 reg_id, u32 val, u32 mask)
176{
177 u32 old = mixer_reg_read(res, reg_id);
178
179 val = (val & mask) | (old & ~mask);
180 writel(val, res->mixer_regs + reg_id);
181}
182
183static void mixer_regs_dump(struct mixer_context *ctx)
184{
185#define DUMPREG(reg_id) \
186do { \
187 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
188 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
189} while (0)
190
191 DUMPREG(MXR_STATUS);
192 DUMPREG(MXR_CFG);
193 DUMPREG(MXR_INT_EN);
194 DUMPREG(MXR_INT_STATUS);
195
196 DUMPREG(MXR_LAYER_CFG);
197 DUMPREG(MXR_VIDEO_CFG);
198
199 DUMPREG(MXR_GRAPHIC0_CFG);
200 DUMPREG(MXR_GRAPHIC0_BASE);
201 DUMPREG(MXR_GRAPHIC0_SPAN);
202 DUMPREG(MXR_GRAPHIC0_WH);
203 DUMPREG(MXR_GRAPHIC0_SXY);
204 DUMPREG(MXR_GRAPHIC0_DXY);
205
206 DUMPREG(MXR_GRAPHIC1_CFG);
207 DUMPREG(MXR_GRAPHIC1_BASE);
208 DUMPREG(MXR_GRAPHIC1_SPAN);
209 DUMPREG(MXR_GRAPHIC1_WH);
210 DUMPREG(MXR_GRAPHIC1_SXY);
211 DUMPREG(MXR_GRAPHIC1_DXY);
212#undef DUMPREG
213}
214
215static void vp_regs_dump(struct mixer_context *ctx)
216{
217#define DUMPREG(reg_id) \
218do { \
219 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
220 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
221} while (0)
222
223 DUMPREG(VP_ENABLE);
224 DUMPREG(VP_SRESET);
225 DUMPREG(VP_SHADOW_UPDATE);
226 DUMPREG(VP_FIELD_ID);
227 DUMPREG(VP_MODE);
228 DUMPREG(VP_IMG_SIZE_Y);
229 DUMPREG(VP_IMG_SIZE_C);
230 DUMPREG(VP_PER_RATE_CTRL);
231 DUMPREG(VP_TOP_Y_PTR);
232 DUMPREG(VP_BOT_Y_PTR);
233 DUMPREG(VP_TOP_C_PTR);
234 DUMPREG(VP_BOT_C_PTR);
235 DUMPREG(VP_ENDIAN_MODE);
236 DUMPREG(VP_SRC_H_POSITION);
237 DUMPREG(VP_SRC_V_POSITION);
238 DUMPREG(VP_SRC_WIDTH);
239 DUMPREG(VP_SRC_HEIGHT);
240 DUMPREG(VP_DST_H_POSITION);
241 DUMPREG(VP_DST_V_POSITION);
242 DUMPREG(VP_DST_WIDTH);
243 DUMPREG(VP_DST_HEIGHT);
244 DUMPREG(VP_H_RATIO);
245 DUMPREG(VP_V_RATIO);
246
247#undef DUMPREG
248}
249
250static inline void vp_filter_set(struct mixer_resources *res,
251 int reg_id, const u8 *data, unsigned int size)
252{
253 /* assure 4-byte align */
254 BUG_ON(size & 3);
255 for (; size; size -= 4, reg_id += 4, data += 4) {
256 u32 val = (data[0] << 24) | (data[1] << 16) |
257 (data[2] << 8) | data[3];
258 vp_reg_write(res, reg_id, val);
259 }
260}
261
262static void vp_default_filter(struct mixer_resources *res)
263{
264 vp_filter_set(res, VP_POLY8_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530265 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900266 vp_filter_set(res, VP_POLY4_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530267 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900268 vp_filter_set(res, VP_POLY4_C0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530269 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900270}
271
272static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
273{
274 struct mixer_resources *res = &ctx->mixer_res;
275
276 /* block update on vsync */
277 mixer_reg_writemask(res, MXR_STATUS, enable ?
278 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
279
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530280 if (ctx->vp_enabled)
281 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900282 VP_SHADOW_UPDATE_ENABLE : 0);
283}
284
285static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
286{
287 struct mixer_resources *res = &ctx->mixer_res;
288 u32 val;
289
290 /* choosing between interlace and progressive mode */
291 val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
292 MXR_CFG_SCAN_PROGRASSIVE);
293
Rahul Sharmadef5e092013-06-19 18:21:08 +0530294 if (ctx->mxr_ver != MXR_VER_128_0_0_184) {
295 /* choosing between proper HD and SD mode */
296 if (height <= 480)
297 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
298 else if (height <= 576)
299 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
300 else if (height <= 720)
301 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
302 else if (height <= 1080)
303 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
304 else
305 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
306 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900307
308 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
309}
310
311static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
312{
313 struct mixer_resources *res = &ctx->mixer_res;
314 u32 val;
315
316 if (height == 480) {
317 val = MXR_CFG_RGB601_0_255;
318 } else if (height == 576) {
319 val = MXR_CFG_RGB601_0_255;
320 } else if (height == 720) {
321 val = MXR_CFG_RGB709_16_235;
322 mixer_reg_write(res, MXR_CM_COEFF_Y,
323 (1 << 30) | (94 << 20) | (314 << 10) |
324 (32 << 0));
325 mixer_reg_write(res, MXR_CM_COEFF_CB,
326 (972 << 20) | (851 << 10) | (225 << 0));
327 mixer_reg_write(res, MXR_CM_COEFF_CR,
328 (225 << 20) | (820 << 10) | (1004 << 0));
329 } else if (height == 1080) {
330 val = MXR_CFG_RGB709_16_235;
331 mixer_reg_write(res, MXR_CM_COEFF_Y,
332 (1 << 30) | (94 << 20) | (314 << 10) |
333 (32 << 0));
334 mixer_reg_write(res, MXR_CM_COEFF_CB,
335 (972 << 20) | (851 << 10) | (225 << 0));
336 mixer_reg_write(res, MXR_CM_COEFF_CR,
337 (225 << 20) | (820 << 10) | (1004 << 0));
338 } else {
339 val = MXR_CFG_RGB709_16_235;
340 mixer_reg_write(res, MXR_CM_COEFF_Y,
341 (1 << 30) | (94 << 20) | (314 << 10) |
342 (32 << 0));
343 mixer_reg_write(res, MXR_CM_COEFF_CB,
344 (972 << 20) | (851 << 10) | (225 << 0));
345 mixer_reg_write(res, MXR_CM_COEFF_CR,
346 (225 << 20) | (820 << 10) | (1004 << 0));
347 }
348
349 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
350}
351
352static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable)
353{
354 struct mixer_resources *res = &ctx->mixer_res;
355 u32 val = enable ? ~0 : 0;
356
357 switch (win) {
358 case 0:
359 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
360 break;
361 case 1:
362 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
363 break;
364 case 2:
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530365 if (ctx->vp_enabled) {
366 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
367 mixer_reg_writemask(res, MXR_CFG, val,
368 MXR_CFG_VP_ENABLE);
Joonyoung Shimf1e716d2014-07-25 19:59:10 +0900369
370 /* control blending of graphic layer 0 */
371 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(0), val,
372 MXR_GRP_CFG_BLEND_PRE_MUL |
373 MXR_GRP_CFG_PIXEL_BLEND_EN);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530374 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900375 break;
376 }
377}
378
379static void mixer_run(struct mixer_context *ctx)
380{
381 struct mixer_resources *res = &ctx->mixer_res;
382
383 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
384
385 mixer_regs_dump(ctx);
386}
387
Rahul Sharma381be022014-06-23 11:02:22 +0530388static void mixer_stop(struct mixer_context *ctx)
389{
390 struct mixer_resources *res = &ctx->mixer_res;
391 int timeout = 20;
392
393 mixer_reg_writemask(res, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
394
395 while (!(mixer_reg_read(res, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
396 --timeout)
397 usleep_range(10000, 12000);
398
399 mixer_regs_dump(ctx);
400}
401
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900402static void vp_video_buffer(struct mixer_context *ctx, int win)
403{
404 struct mixer_resources *res = &ctx->mixer_res;
405 unsigned long flags;
406 struct hdmi_win_data *win_data;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900407 unsigned int x_ratio, y_ratio;
YoungJun Cho782953e2013-07-01 13:04:12 +0900408 unsigned int buf_num = 1;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900409 dma_addr_t luma_addr[2], chroma_addr[2];
410 bool tiled_mode = false;
411 bool crcb_mode = false;
412 u32 val;
413
414 win_data = &ctx->win_data[win];
415
416 switch (win_data->pixel_format) {
Ville Syrjälä363b06a2012-05-14 11:08:51 +0900417 case DRM_FORMAT_NV12:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900418 crcb_mode = false;
419 buf_num = 2;
420 break;
421 /* TODO: single buffer format NV12, NV21 */
422 default:
423 /* ignore pixel format at disable time */
424 if (!win_data->dma_addr)
425 break;
426
427 DRM_ERROR("pixel format for vp is wrong [%d].\n",
428 win_data->pixel_format);
429 return;
430 }
431
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900432 /* scaling feature: (src << 16) / dst */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900433 x_ratio = (win_data->src_width << 16) / win_data->crtc_width;
434 y_ratio = (win_data->src_height << 16) / win_data->crtc_height;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900435
436 if (buf_num == 2) {
437 luma_addr[0] = win_data->dma_addr;
438 chroma_addr[0] = win_data->chroma_dma_addr;
439 } else {
440 luma_addr[0] = win_data->dma_addr;
441 chroma_addr[0] = win_data->dma_addr
Daniel Stoneadacb222015-03-17 13:24:58 +0000442 + (win_data->fb_pitch * win_data->fb_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900443 }
444
445 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) {
446 ctx->interlace = true;
447 if (tiled_mode) {
448 luma_addr[1] = luma_addr[0] + 0x40;
449 chroma_addr[1] = chroma_addr[0] + 0x40;
450 } else {
Daniel Stoneadacb222015-03-17 13:24:58 +0000451 luma_addr[1] = luma_addr[0] + win_data->fb_pitch;
452 chroma_addr[1] = chroma_addr[0] + win_data->fb_pitch;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900453 }
454 } else {
455 ctx->interlace = false;
456 luma_addr[1] = 0;
457 chroma_addr[1] = 0;
458 }
459
460 spin_lock_irqsave(&res->reg_slock, flags);
461 mixer_vsync_set_update(ctx, false);
462
463 /* interlace or progressive scan mode */
464 val = (ctx->interlace ? ~0 : 0);
465 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
466
467 /* setup format */
468 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
469 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
470 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
471
472 /* setting size of input image */
Daniel Stoneadacb222015-03-17 13:24:58 +0000473 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_pitch) |
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900474 VP_IMG_VSIZE(win_data->fb_height));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900475 /* chroma height has to reduced by 2 to avoid chroma distorions */
Daniel Stoneadacb222015-03-17 13:24:58 +0000476 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(win_data->fb_pitch) |
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900477 VP_IMG_VSIZE(win_data->fb_height / 2));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900478
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900479 vp_reg_write(res, VP_SRC_WIDTH, win_data->src_width);
480 vp_reg_write(res, VP_SRC_HEIGHT, win_data->src_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900481 vp_reg_write(res, VP_SRC_H_POSITION,
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900482 VP_SRC_H_POSITION_VAL(win_data->fb_x));
483 vp_reg_write(res, VP_SRC_V_POSITION, win_data->fb_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900484
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900485 vp_reg_write(res, VP_DST_WIDTH, win_data->crtc_width);
486 vp_reg_write(res, VP_DST_H_POSITION, win_data->crtc_x);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900487 if (ctx->interlace) {
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900488 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height / 2);
489 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y / 2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900490 } else {
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900491 vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height);
492 vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900493 }
494
495 vp_reg_write(res, VP_H_RATIO, x_ratio);
496 vp_reg_write(res, VP_V_RATIO, y_ratio);
497
498 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
499
500 /* set buffer address to vp */
501 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
502 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
503 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
504 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
505
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900506 mixer_cfg_scan(ctx, win_data->mode_height);
507 mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900508 mixer_cfg_layer(ctx, win, true);
509 mixer_run(ctx);
510
511 mixer_vsync_set_update(ctx, true);
512 spin_unlock_irqrestore(&res->reg_slock, flags);
513
514 vp_regs_dump(ctx);
515}
516
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530517static void mixer_layer_update(struct mixer_context *ctx)
518{
519 struct mixer_resources *res = &ctx->mixer_res;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530520
Rahul Sharma5c0f4822014-06-23 11:02:23 +0530521 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530522}
523
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900524static void mixer_graph_buffer(struct mixer_context *ctx, int win)
525{
526 struct mixer_resources *res = &ctx->mixer_res;
527 unsigned long flags;
528 struct hdmi_win_data *win_data;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900529 unsigned int x_ratio, y_ratio;
530 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900531 dma_addr_t dma_addr;
532 unsigned int fmt;
533 u32 val;
534
535 win_data = &ctx->win_data[win];
536
537 #define RGB565 4
538 #define ARGB1555 5
539 #define ARGB4444 6
540 #define ARGB8888 7
541
542 switch (win_data->bpp) {
543 case 16:
544 fmt = ARGB4444;
545 break;
546 case 32:
547 fmt = ARGB8888;
548 break;
549 default:
550 fmt = ARGB8888;
551 }
552
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900553 /* 2x scaling feature */
554 x_ratio = 0;
555 y_ratio = 0;
556
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900557 dst_x_offset = win_data->crtc_x;
558 dst_y_offset = win_data->crtc_y;
559
560 /* converting dma address base and source offset */
Seung-Woo Kim8dcb96b2012-04-24 18:52:22 +0900561 dma_addr = win_data->dma_addr
562 + (win_data->fb_x * win_data->bpp >> 3)
Daniel Stoneadacb222015-03-17 13:24:58 +0000563 + (win_data->fb_y * win_data->fb_pitch);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900564 src_x_offset = 0;
565 src_y_offset = 0;
566
567 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE)
568 ctx->interlace = true;
569 else
570 ctx->interlace = false;
571
572 spin_lock_irqsave(&res->reg_slock, flags);
573 mixer_vsync_set_update(ctx, false);
574
575 /* setup format */
576 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
577 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
578
579 /* setup geometry */
Daniel Stoneadacb222015-03-17 13:24:58 +0000580 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win),
581 win_data->fb_pitch / (win_data->bpp >> 3));
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) {
Seung-Woo Kim129046c2015-01-30 17:30:45 +0900586 val = MXR_MXR_RES_HEIGHT(win_data->mode_height);
587 val |= MXR_MXR_RES_WIDTH(win_data->mode_width);
Rahul Sharmadef5e092013-06-19 18:21:08 +0530588 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;
Daniel Stoneadacb222015-03-17 13:24:58 +0000966 win_data->fb_pitch = plane->pitch;
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200967 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
Gustavo Padovan93bca242015-01-18 18:16:23 +0900976static void mixer_win_commit(struct exynos_drm_crtc *crtc, int zpos)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900977{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900978 struct mixer_context *mixer_ctx = crtc->ctx;
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
Gustavo Padovan93bca242015-01-18 18:16:23 +0900998static void mixer_win_disable(struct exynos_drm_crtc *crtc, int zpos)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900999{
Gustavo Padovan93bca242015-01-18 18:16:23 +09001000 struct mixer_context *mixer_ctx = crtc->ctx;
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
Gustavo Padovan93bca242015-01-18 18:16:23 +09001026static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
Rahul Sharma0ea68222013-01-15 08:11:06 -05001027{
Gustavo Padovan93bca242015-01-18 18:16:23 +09001028 struct mixer_context *mixer_ctx = crtc->ctx;
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
Gustavo Padovan93bca242015-01-18 18:16:23 +09001038 err = drm_vblank_get(mixer_ctx->drm_dev, mixer_ctx->pipe);
Joonyoung Shim7c4c5582015-01-18 17:48:29 +09001039 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
Gustavo Padovan93bca242015-01-18 18:16:23 +09001055 drm_vblank_put(mixer_ctx->drm_dev, mixer_ctx->pipe);
Prathyush K8137a2e2012-12-06 20:16:01 +05301056}
1057
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001058static void mixer_window_suspend(struct mixer_context *ctx)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301059{
1060 struct hdmi_win_data *win_data;
1061 int i;
1062
1063 for (i = 0; i < MIXER_WIN_NR; i++) {
1064 win_data = &ctx->win_data[i];
1065 win_data->resume = win_data->enabled;
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001066 mixer_win_disable(ctx->crtc, i);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301067 }
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001068 mixer_wait_for_vblank(ctx->crtc);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301069}
1070
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001071static void mixer_window_resume(struct mixer_context *ctx)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301072{
1073 struct hdmi_win_data *win_data;
1074 int i;
1075
1076 for (i = 0; i < MIXER_WIN_NR; i++) {
1077 win_data = &ctx->win_data[i];
1078 win_data->enabled = win_data->resume;
1079 win_data->resume = false;
Sean Paul87244fa2014-01-30 16:19:07 -05001080 if (win_data->enabled)
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001081 mixer_win_commit(ctx->crtc, i);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301082 }
1083}
1084
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001085static void mixer_poweron(struct mixer_context *ctx)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301086{
1087 struct mixer_resources *res = &ctx->mixer_res;
1088
Prathyush Kdb43fd12012-12-06 20:16:05 +05301089 mutex_lock(&ctx->mixer_mutex);
1090 if (ctx->powered) {
1091 mutex_unlock(&ctx->mixer_mutex);
1092 return;
1093 }
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301094
Prathyush Kdb43fd12012-12-06 20:16:05 +05301095 mutex_unlock(&ctx->mixer_mutex);
1096
Sean Paulaf65c802014-01-30 16:19:27 -05001097 pm_runtime_get_sync(ctx->dev);
1098
Sean Paul0bfb1f82013-06-11 12:24:02 +05301099 clk_prepare_enable(res->mixer);
Marek Szyprowski04427ec2015-02-02 14:20:28 +01001100 clk_prepare_enable(res->hdmi);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301101 if (ctx->vp_enabled) {
Sean Paul0bfb1f82013-06-11 12:24:02 +05301102 clk_prepare_enable(res->vp);
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001103 if (ctx->has_sclk)
1104 clk_prepare_enable(res->sclk_mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301105 }
1106
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301107 mutex_lock(&ctx->mixer_mutex);
1108 ctx->powered = true;
1109 mutex_unlock(&ctx->mixer_mutex);
1110
Rahul Sharmad74ed932014-06-23 11:02:24 +05301111 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
1112
Prathyush Kdb43fd12012-12-06 20:16:05 +05301113 mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
1114 mixer_win_reset(ctx);
1115
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001116 mixer_window_resume(ctx);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301117}
1118
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001119static void mixer_poweroff(struct mixer_context *ctx)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301120{
1121 struct mixer_resources *res = &ctx->mixer_res;
1122
Prathyush Kdb43fd12012-12-06 20:16:05 +05301123 mutex_lock(&ctx->mixer_mutex);
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301124 if (!ctx->powered) {
1125 mutex_unlock(&ctx->mixer_mutex);
1126 return;
1127 }
Prathyush Kdb43fd12012-12-06 20:16:05 +05301128 mutex_unlock(&ctx->mixer_mutex);
1129
Rahul Sharma381be022014-06-23 11:02:22 +05301130 mixer_stop(ctx);
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001131 mixer_window_suspend(ctx);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301132
1133 ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
1134
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301135 mutex_lock(&ctx->mixer_mutex);
1136 ctx->powered = false;
1137 mutex_unlock(&ctx->mixer_mutex);
1138
Marek Szyprowski04427ec2015-02-02 14:20:28 +01001139 clk_disable_unprepare(res->hdmi);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301140 clk_disable_unprepare(res->mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301141 if (ctx->vp_enabled) {
Sean Paul0bfb1f82013-06-11 12:24:02 +05301142 clk_disable_unprepare(res->vp);
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001143 if (ctx->has_sclk)
1144 clk_disable_unprepare(res->sclk_mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301145 }
1146
Sean Paulaf65c802014-01-30 16:19:27 -05001147 pm_runtime_put_sync(ctx->dev);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301148}
1149
Gustavo Padovan93bca242015-01-18 18:16:23 +09001150static void mixer_dpms(struct exynos_drm_crtc *crtc, int mode)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301151{
Prathyush Kdb43fd12012-12-06 20:16:05 +05301152 switch (mode) {
1153 case DRM_MODE_DPMS_ON:
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001154 mixer_poweron(crtc->ctx);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301155 break;
1156 case DRM_MODE_DPMS_STANDBY:
1157 case DRM_MODE_DPMS_SUSPEND:
1158 case DRM_MODE_DPMS_OFF:
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001159 mixer_poweroff(crtc->ctx);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301160 break;
1161 default:
1162 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
1163 break;
1164 }
1165}
1166
Sean Paulf041b252014-01-30 16:19:15 -05001167/* Only valid for Mixer version 16.0.33.0 */
1168int mixer_check_mode(struct drm_display_mode *mode)
1169{
1170 u32 w, h;
1171
1172 w = mode->hdisplay;
1173 h = mode->vdisplay;
1174
1175 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
1176 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1177 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1178
1179 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
1180 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1181 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1182 return 0;
1183
1184 return -EINVAL;
1185}
1186
Gustavo Padovan93bca242015-01-18 18:16:23 +09001187static struct exynos_drm_crtc_ops mixer_crtc_ops = {
Sean Paulf041b252014-01-30 16:19:15 -05001188 .dpms = mixer_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001189 .enable_vblank = mixer_enable_vblank,
1190 .disable_vblank = mixer_disable_vblank,
Prathyush K8137a2e2012-12-06 20:16:01 +05301191 .wait_for_vblank = mixer_wait_for_vblank,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001192 .win_mode_set = mixer_win_mode_set,
1193 .win_commit = mixer_win_commit,
1194 .win_disable = mixer_win_disable,
Sean Paulf041b252014-01-30 16:19:15 -05001195};
Rahul Sharma0ea68222013-01-15 08:11:06 -05001196
Rahul Sharmadef5e092013-06-19 18:21:08 +05301197static struct mixer_drv_data exynos5420_mxr_drv_data = {
1198 .version = MXR_VER_128_0_0_184,
1199 .is_vp_enabled = 0,
1200};
1201
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301202static struct mixer_drv_data exynos5250_mxr_drv_data = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301203 .version = MXR_VER_16_0_33_0,
1204 .is_vp_enabled = 0,
1205};
1206
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001207static struct mixer_drv_data exynos4212_mxr_drv_data = {
1208 .version = MXR_VER_0_0_0_16,
1209 .is_vp_enabled = 1,
1210};
1211
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301212static struct mixer_drv_data exynos4210_mxr_drv_data = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301213 .version = MXR_VER_0_0_0_16,
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301214 .is_vp_enabled = 1,
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001215 .has_sclk = 1,
Rahul Sharma1e123442012-10-04 20:48:51 +05301216};
1217
1218static struct platform_device_id mixer_driver_types[] = {
1219 {
1220 .name = "s5p-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301221 .driver_data = (unsigned long)&exynos4210_mxr_drv_data,
Rahul Sharma1e123442012-10-04 20:48:51 +05301222 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301223 .name = "exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301224 .driver_data = (unsigned long)&exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301225 }, {
1226 /* end node */
1227 }
1228};
1229
1230static struct of_device_id mixer_match_types[] = {
1231 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001232 .compatible = "samsung,exynos4210-mixer",
1233 .data = &exynos4210_mxr_drv_data,
1234 }, {
1235 .compatible = "samsung,exynos4212-mixer",
1236 .data = &exynos4212_mxr_drv_data,
1237 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301238 .compatible = "samsung,exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301239 .data = &exynos5250_mxr_drv_data,
1240 }, {
1241 .compatible = "samsung,exynos5250-mixer",
1242 .data = &exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301243 }, {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301244 .compatible = "samsung,exynos5420-mixer",
1245 .data = &exynos5420_mxr_drv_data,
1246 }, {
Rahul Sharma1e123442012-10-04 20:48:51 +05301247 /* end node */
1248 }
1249};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001250MODULE_DEVICE_TABLE(of, mixer_match_types);
Rahul Sharma1e123442012-10-04 20:48:51 +05301251
Inki Daef37cd5e2014-05-09 14:25:20 +09001252static int mixer_bind(struct device *dev, struct device *manager, void *data)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001253{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001254 struct mixer_context *ctx = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09001255 struct drm_device *drm_dev = data;
Inki Daef37cd5e2014-05-09 14:25:20 +09001256 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001257
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001258 ret = mixer_initialize(ctx, drm_dev);
1259 if (ret)
1260 return ret;
1261
Gustavo Padovan93bca242015-01-18 18:16:23 +09001262 ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
1263 EXYNOS_DISPLAY_TYPE_HDMI,
1264 &mixer_crtc_ops, ctx);
1265 if (IS_ERR(ctx->crtc)) {
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001266 mixer_ctx_remove(ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001267 ret = PTR_ERR(ctx->crtc);
1268 goto free_ctx;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001269 }
1270
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001271 return 0;
Gustavo Padovan93bca242015-01-18 18:16:23 +09001272
1273free_ctx:
1274 devm_kfree(dev, ctx);
1275 return ret;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001276}
1277
1278static void mixer_unbind(struct device *dev, struct device *master, void *data)
1279{
1280 struct mixer_context *ctx = dev_get_drvdata(dev);
1281
Gustavo Padovan93bca242015-01-18 18:16:23 +09001282 mixer_ctx_remove(ctx);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001283}
1284
1285static const struct component_ops mixer_component_ops = {
1286 .bind = mixer_bind,
1287 .unbind = mixer_unbind,
1288};
1289
1290static int mixer_probe(struct platform_device *pdev)
1291{
1292 struct device *dev = &pdev->dev;
1293 struct mixer_drv_data *drv;
1294 struct mixer_context *ctx;
1295 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001296
Sean Paulf041b252014-01-30 16:19:15 -05001297 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1298 if (!ctx) {
1299 DRM_ERROR("failed to alloc mixer context.\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001300 return -ENOMEM;
Sean Paulf041b252014-01-30 16:19:15 -05001301 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001302
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001303 mutex_init(&ctx->mixer_mutex);
1304
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301305 if (dev->of_node) {
1306 const struct of_device_id *match;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001307
Sachin Kamate436b092013-06-05 16:00:23 +09001308 match = of_match_node(mixer_match_types, dev->of_node);
Rahul Sharma2cdc53b2012-10-31 09:36:26 +05301309 drv = (struct mixer_drv_data *)match->data;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301310 } else {
1311 drv = (struct mixer_drv_data *)
1312 platform_get_device_id(pdev)->driver_data;
1313 }
1314
Sean Paul45517892014-01-30 16:19:05 -05001315 ctx->pdev = pdev;
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001316 ctx->dev = dev;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301317 ctx->vp_enabled = drv->is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001318 ctx->has_sclk = drv->has_sclk;
Rahul Sharma1e123442012-10-04 20:48:51 +05301319 ctx->mxr_ver = drv->version;
Daniel Vetter57ed0f72013-12-11 11:34:43 +01001320 init_waitqueue_head(&ctx->wait_vsync_queue);
Prathyush K6e95d5e2012-12-06 20:16:03 +05301321 atomic_set(&ctx->wait_vsync_event, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001322
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001323 platform_set_drvdata(pdev, ctx);
Inki Daedf5225b2014-05-29 18:28:02 +09001324
1325 ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
Gustavo Padovan5d1741a2014-11-05 19:51:35 -02001326 EXYNOS_DISPLAY_TYPE_HDMI);
Inki Daedf5225b2014-05-29 18:28:02 +09001327 if (ret)
1328 return ret;
1329
1330 ret = component_add(&pdev->dev, &mixer_component_ops);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001331 if (ret) {
Inki Daedf5225b2014-05-29 18:28:02 +09001332 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001333 return ret;
1334 }
1335
1336 pm_runtime_enable(dev);
Inki Daedf5225b2014-05-29 18:28:02 +09001337
1338 return ret;
Inki Daef37cd5e2014-05-09 14:25:20 +09001339}
1340
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001341static int mixer_remove(struct platform_device *pdev)
1342{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001343 pm_runtime_disable(&pdev->dev);
1344
Inki Daedf5225b2014-05-29 18:28:02 +09001345 component_del(&pdev->dev, &mixer_component_ops);
1346 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
1347
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001348 return 0;
1349}
1350
1351struct platform_driver mixer_driver = {
1352 .driver = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301353 .name = "exynos-mixer",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001354 .owner = THIS_MODULE,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301355 .of_match_table = mixer_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001356 },
1357 .probe = mixer_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001358 .remove = mixer_remove,
Rahul Sharma1e123442012-10-04 20:48:51 +05301359 .id_table = mixer_driver_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001360};