blob: 285e1569e6ade31102b8672028bc335d7b02714d [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"
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +090040#include "exynos_drm_plane.h"
Inki Dae1055b392012-10-19 17:37:35 +090041#include "exynos_drm_iommu.h"
Sean Paulf041b252014-01-30 16:19:15 -050042#include "exynos_mixer.h"
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090043
Sean Paulf041b252014-01-30 16:19:15 -050044#define MIXER_WIN_NR 3
45#define MIXER_DEFAULT_WIN 0
Seung-Woo Kimd8408322011-12-21 17:39:39 +090046
Tobias Jakobi7a57ca72015-04-27 23:11:59 +020047/* The pixelformats that are natively supported by the mixer. */
48#define MXR_FORMAT_RGB565 4
49#define MXR_FORMAT_ARGB1555 5
50#define MXR_FORMAT_ARGB4444 6
51#define MXR_FORMAT_ARGB8888 7
52
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090053struct mixer_resources {
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090054 int irq;
55 void __iomem *mixer_regs;
56 void __iomem *vp_regs;
57 spinlock_t reg_slock;
58 struct clk *mixer;
59 struct clk *vp;
Marek Szyprowski04427ec2015-02-02 14:20:28 +010060 struct clk *hdmi;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090061 struct clk *sclk_mixer;
62 struct clk *sclk_hdmi;
Marek Szyprowskiff830c92014-07-01 10:10:07 +020063 struct clk *mout_mixer;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090064};
65
Rahul Sharma1e123442012-10-04 20:48:51 +053066enum mixer_version_id {
67 MXR_VER_0_0_0_16,
68 MXR_VER_16_0_33_0,
Rahul Sharmadef5e092013-06-19 18:21:08 +053069 MXR_VER_128_0_0_184,
Rahul Sharma1e123442012-10-04 20:48:51 +053070};
71
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090072struct mixer_context {
Sean Paul45517892014-01-30 16:19:05 -050073 struct platform_device *pdev;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090074 struct device *dev;
Inki Dae1055b392012-10-19 17:37:35 +090075 struct drm_device *drm_dev;
Gustavo Padovan93bca242015-01-18 18:16:23 +090076 struct exynos_drm_crtc *crtc;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +090077 struct exynos_drm_plane planes[MIXER_WIN_NR];
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090078 int pipe;
79 bool interlace;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090080 bool powered;
Rahul Sharma1b8e5742012-10-04 20:48:52 +053081 bool vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +020082 bool has_sclk;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090083 u32 int_en;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090084
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090085 struct mutex mixer_mutex;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090086 struct mixer_resources mixer_res;
Rahul Sharma1e123442012-10-04 20:48:51 +053087 enum mixer_version_id mxr_ver;
Prathyush K6e95d5e2012-12-06 20:16:03 +053088 wait_queue_head_t wait_vsync_queue;
89 atomic_t wait_vsync_event;
Rahul Sharma1e123442012-10-04 20:48:51 +053090};
91
92struct mixer_drv_data {
93 enum mixer_version_id version;
Rahul Sharma1b8e5742012-10-04 20:48:52 +053094 bool is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +020095 bool has_sclk;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090096};
97
Seung-Woo Kimd8408322011-12-21 17:39:39 +090098static const u8 filter_y_horiz_tap8[] = {
99 0, -1, -1, -1, -1, -1, -1, -1,
100 -1, -1, -1, -1, -1, 0, 0, 0,
101 0, 2, 4, 5, 6, 6, 6, 6,
102 6, 5, 5, 4, 3, 2, 1, 1,
103 0, -6, -12, -16, -18, -20, -21, -20,
104 -20, -18, -16, -13, -10, -8, -5, -2,
105 127, 126, 125, 121, 114, 107, 99, 89,
106 79, 68, 57, 46, 35, 25, 16, 8,
107};
108
109static const u8 filter_y_vert_tap4[] = {
110 0, -3, -6, -8, -8, -8, -8, -7,
111 -6, -5, -4, -3, -2, -1, -1, 0,
112 127, 126, 124, 118, 111, 102, 92, 81,
113 70, 59, 48, 37, 27, 19, 11, 5,
114 0, 5, 11, 19, 27, 37, 48, 59,
115 70, 81, 92, 102, 111, 118, 124, 126,
116 0, 0, -1, -1, -2, -3, -4, -5,
117 -6, -7, -8, -8, -8, -8, -6, -3,
118};
119
120static const u8 filter_cr_horiz_tap4[] = {
121 0, -3, -6, -8, -8, -8, -8, -7,
122 -6, -5, -4, -3, -2, -1, -1, 0,
123 127, 126, 124, 118, 111, 102, 92, 81,
124 70, 59, 48, 37, 27, 19, 11, 5,
125};
126
127static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
128{
129 return readl(res->vp_regs + reg_id);
130}
131
132static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
133 u32 val)
134{
135 writel(val, res->vp_regs + reg_id);
136}
137
138static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
139 u32 val, u32 mask)
140{
141 u32 old = vp_reg_read(res, reg_id);
142
143 val = (val & mask) | (old & ~mask);
144 writel(val, res->vp_regs + reg_id);
145}
146
147static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
148{
149 return readl(res->mixer_regs + reg_id);
150}
151
152static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
153 u32 val)
154{
155 writel(val, res->mixer_regs + reg_id);
156}
157
158static inline void mixer_reg_writemask(struct mixer_resources *res,
159 u32 reg_id, u32 val, u32 mask)
160{
161 u32 old = mixer_reg_read(res, reg_id);
162
163 val = (val & mask) | (old & ~mask);
164 writel(val, res->mixer_regs + reg_id);
165}
166
167static void mixer_regs_dump(struct mixer_context *ctx)
168{
169#define DUMPREG(reg_id) \
170do { \
171 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
172 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
173} while (0)
174
175 DUMPREG(MXR_STATUS);
176 DUMPREG(MXR_CFG);
177 DUMPREG(MXR_INT_EN);
178 DUMPREG(MXR_INT_STATUS);
179
180 DUMPREG(MXR_LAYER_CFG);
181 DUMPREG(MXR_VIDEO_CFG);
182
183 DUMPREG(MXR_GRAPHIC0_CFG);
184 DUMPREG(MXR_GRAPHIC0_BASE);
185 DUMPREG(MXR_GRAPHIC0_SPAN);
186 DUMPREG(MXR_GRAPHIC0_WH);
187 DUMPREG(MXR_GRAPHIC0_SXY);
188 DUMPREG(MXR_GRAPHIC0_DXY);
189
190 DUMPREG(MXR_GRAPHIC1_CFG);
191 DUMPREG(MXR_GRAPHIC1_BASE);
192 DUMPREG(MXR_GRAPHIC1_SPAN);
193 DUMPREG(MXR_GRAPHIC1_WH);
194 DUMPREG(MXR_GRAPHIC1_SXY);
195 DUMPREG(MXR_GRAPHIC1_DXY);
196#undef DUMPREG
197}
198
199static void vp_regs_dump(struct mixer_context *ctx)
200{
201#define DUMPREG(reg_id) \
202do { \
203 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
204 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
205} while (0)
206
207 DUMPREG(VP_ENABLE);
208 DUMPREG(VP_SRESET);
209 DUMPREG(VP_SHADOW_UPDATE);
210 DUMPREG(VP_FIELD_ID);
211 DUMPREG(VP_MODE);
212 DUMPREG(VP_IMG_SIZE_Y);
213 DUMPREG(VP_IMG_SIZE_C);
214 DUMPREG(VP_PER_RATE_CTRL);
215 DUMPREG(VP_TOP_Y_PTR);
216 DUMPREG(VP_BOT_Y_PTR);
217 DUMPREG(VP_TOP_C_PTR);
218 DUMPREG(VP_BOT_C_PTR);
219 DUMPREG(VP_ENDIAN_MODE);
220 DUMPREG(VP_SRC_H_POSITION);
221 DUMPREG(VP_SRC_V_POSITION);
222 DUMPREG(VP_SRC_WIDTH);
223 DUMPREG(VP_SRC_HEIGHT);
224 DUMPREG(VP_DST_H_POSITION);
225 DUMPREG(VP_DST_V_POSITION);
226 DUMPREG(VP_DST_WIDTH);
227 DUMPREG(VP_DST_HEIGHT);
228 DUMPREG(VP_H_RATIO);
229 DUMPREG(VP_V_RATIO);
230
231#undef DUMPREG
232}
233
234static inline void vp_filter_set(struct mixer_resources *res,
235 int reg_id, const u8 *data, unsigned int size)
236{
237 /* assure 4-byte align */
238 BUG_ON(size & 3);
239 for (; size; size -= 4, reg_id += 4, data += 4) {
240 u32 val = (data[0] << 24) | (data[1] << 16) |
241 (data[2] << 8) | data[3];
242 vp_reg_write(res, reg_id, val);
243 }
244}
245
246static void vp_default_filter(struct mixer_resources *res)
247{
248 vp_filter_set(res, VP_POLY8_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530249 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900250 vp_filter_set(res, VP_POLY4_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530251 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900252 vp_filter_set(res, VP_POLY4_C0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530253 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900254}
255
256static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
257{
258 struct mixer_resources *res = &ctx->mixer_res;
259
260 /* block update on vsync */
261 mixer_reg_writemask(res, MXR_STATUS, enable ?
262 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
263
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530264 if (ctx->vp_enabled)
265 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900266 VP_SHADOW_UPDATE_ENABLE : 0);
267}
268
269static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
270{
271 struct mixer_resources *res = &ctx->mixer_res;
272 u32 val;
273
274 /* choosing between interlace and progressive mode */
275 val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
Tobias Jakobi1e6d4592015-04-07 01:14:50 +0200276 MXR_CFG_SCAN_PROGRESSIVE);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900277
Rahul Sharmadef5e092013-06-19 18:21:08 +0530278 if (ctx->mxr_ver != MXR_VER_128_0_0_184) {
279 /* choosing between proper HD and SD mode */
280 if (height <= 480)
281 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
282 else if (height <= 576)
283 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
284 else if (height <= 720)
285 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
286 else if (height <= 1080)
287 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
288 else
289 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
290 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900291
292 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
293}
294
295static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
296{
297 struct mixer_resources *res = &ctx->mixer_res;
298 u32 val;
299
300 if (height == 480) {
301 val = MXR_CFG_RGB601_0_255;
302 } else if (height == 576) {
303 val = MXR_CFG_RGB601_0_255;
304 } else if (height == 720) {
305 val = MXR_CFG_RGB709_16_235;
306 mixer_reg_write(res, MXR_CM_COEFF_Y,
307 (1 << 30) | (94 << 20) | (314 << 10) |
308 (32 << 0));
309 mixer_reg_write(res, MXR_CM_COEFF_CB,
310 (972 << 20) | (851 << 10) | (225 << 0));
311 mixer_reg_write(res, MXR_CM_COEFF_CR,
312 (225 << 20) | (820 << 10) | (1004 << 0));
313 } else if (height == 1080) {
314 val = MXR_CFG_RGB709_16_235;
315 mixer_reg_write(res, MXR_CM_COEFF_Y,
316 (1 << 30) | (94 << 20) | (314 << 10) |
317 (32 << 0));
318 mixer_reg_write(res, MXR_CM_COEFF_CB,
319 (972 << 20) | (851 << 10) | (225 << 0));
320 mixer_reg_write(res, MXR_CM_COEFF_CR,
321 (225 << 20) | (820 << 10) | (1004 << 0));
322 } else {
323 val = MXR_CFG_RGB709_16_235;
324 mixer_reg_write(res, MXR_CM_COEFF_Y,
325 (1 << 30) | (94 << 20) | (314 << 10) |
326 (32 << 0));
327 mixer_reg_write(res, MXR_CM_COEFF_CB,
328 (972 << 20) | (851 << 10) | (225 << 0));
329 mixer_reg_write(res, MXR_CM_COEFF_CR,
330 (225 << 20) | (820 << 10) | (1004 << 0));
331 }
332
333 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
334}
335
336static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable)
337{
338 struct mixer_resources *res = &ctx->mixer_res;
339 u32 val = enable ? ~0 : 0;
340
341 switch (win) {
342 case 0:
343 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
344 break;
345 case 1:
346 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
347 break;
348 case 2:
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530349 if (ctx->vp_enabled) {
350 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
351 mixer_reg_writemask(res, MXR_CFG, val,
352 MXR_CFG_VP_ENABLE);
Joonyoung Shimf1e716d2014-07-25 19:59:10 +0900353
354 /* control blending of graphic layer 0 */
355 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(0), val,
356 MXR_GRP_CFG_BLEND_PRE_MUL |
357 MXR_GRP_CFG_PIXEL_BLEND_EN);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530358 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900359 break;
360 }
361}
362
363static void mixer_run(struct mixer_context *ctx)
364{
365 struct mixer_resources *res = &ctx->mixer_res;
366
367 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900368}
369
Rahul Sharma381be022014-06-23 11:02:22 +0530370static void mixer_stop(struct mixer_context *ctx)
371{
372 struct mixer_resources *res = &ctx->mixer_res;
373 int timeout = 20;
374
375 mixer_reg_writemask(res, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
376
377 while (!(mixer_reg_read(res, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
378 --timeout)
379 usleep_range(10000, 12000);
Rahul Sharma381be022014-06-23 11:02:22 +0530380}
381
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900382static void vp_video_buffer(struct mixer_context *ctx, int win)
383{
384 struct mixer_resources *res = &ctx->mixer_res;
385 unsigned long flags;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900386 struct exynos_drm_plane *plane;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900387 dma_addr_t luma_addr[2], chroma_addr[2];
388 bool tiled_mode = false;
389 bool crcb_mode = false;
390 u32 val;
391
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900392 plane = &ctx->planes[win];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900393
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900394 switch (plane->pixel_format) {
Ville Syrjälä363b06a2012-05-14 11:08:51 +0900395 case DRM_FORMAT_NV12:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900396 crcb_mode = false;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900397 break;
Tobias Jakobi8f2590f2015-04-27 23:10:16 +0200398 case DRM_FORMAT_NV21:
399 crcb_mode = true;
400 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900401 default:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900402 DRM_ERROR("pixel format for vp is wrong [%d].\n",
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900403 plane->pixel_format);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900404 return;
405 }
406
Tobias Jakobifac8a5b2015-04-27 23:10:15 +0200407 luma_addr[0] = plane->dma_addr[0];
408 chroma_addr[0] = plane->dma_addr[1];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900409
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900410 if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900411 ctx->interlace = true;
412 if (tiled_mode) {
413 luma_addr[1] = luma_addr[0] + 0x40;
414 chroma_addr[1] = chroma_addr[0] + 0x40;
415 } else {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900416 luma_addr[1] = luma_addr[0] + plane->pitch;
417 chroma_addr[1] = chroma_addr[0] + plane->pitch;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900418 }
419 } else {
420 ctx->interlace = false;
421 luma_addr[1] = 0;
422 chroma_addr[1] = 0;
423 }
424
425 spin_lock_irqsave(&res->reg_slock, flags);
426 mixer_vsync_set_update(ctx, false);
427
428 /* interlace or progressive scan mode */
429 val = (ctx->interlace ? ~0 : 0);
430 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
431
432 /* setup format */
433 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
434 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
435 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
436
437 /* setting size of input image */
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900438 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(plane->pitch) |
439 VP_IMG_VSIZE(plane->fb_height));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900440 /* chroma height has to reduced by 2 to avoid chroma distorions */
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900441 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(plane->pitch) |
442 VP_IMG_VSIZE(plane->fb_height / 2));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900443
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900444 vp_reg_write(res, VP_SRC_WIDTH, plane->src_width);
445 vp_reg_write(res, VP_SRC_HEIGHT, plane->src_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900446 vp_reg_write(res, VP_SRC_H_POSITION,
Joonyoung Shimcb8a3db2015-04-07 15:59:38 +0900447 VP_SRC_H_POSITION_VAL(plane->src_x));
448 vp_reg_write(res, VP_SRC_V_POSITION, plane->src_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900449
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900450 vp_reg_write(res, VP_DST_WIDTH, plane->crtc_width);
451 vp_reg_write(res, VP_DST_H_POSITION, plane->crtc_x);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900452 if (ctx->interlace) {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900453 vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height / 2);
454 vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y / 2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900455 } else {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900456 vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height);
457 vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900458 }
459
Joonyoung Shim3cabaf72015-04-07 15:59:39 +0900460 vp_reg_write(res, VP_H_RATIO, plane->h_ratio);
461 vp_reg_write(res, VP_V_RATIO, plane->v_ratio);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900462
463 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
464
465 /* set buffer address to vp */
466 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
467 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
468 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
469 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
470
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900471 mixer_cfg_scan(ctx, plane->mode_height);
472 mixer_cfg_rgb_fmt(ctx, plane->mode_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900473 mixer_cfg_layer(ctx, win, true);
474 mixer_run(ctx);
475
476 mixer_vsync_set_update(ctx, true);
477 spin_unlock_irqrestore(&res->reg_slock, flags);
478
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200479 mixer_regs_dump(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900480 vp_regs_dump(ctx);
481}
482
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530483static void mixer_layer_update(struct mixer_context *ctx)
484{
485 struct mixer_resources *res = &ctx->mixer_res;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530486
Rahul Sharma5c0f4822014-06-23 11:02:23 +0530487 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530488}
489
Tobias Jakobi26110152015-04-07 01:14:52 +0200490static int mixer_setup_scale(const struct exynos_drm_plane *plane,
491 unsigned int *x_ratio, unsigned int *y_ratio)
492{
493 if (plane->crtc_width != plane->src_width) {
494 if (plane->crtc_width == 2 * plane->src_width)
495 *x_ratio = 1;
496 else
497 goto fail;
498 }
499
500 if (plane->crtc_height != plane->src_height) {
501 if (plane->crtc_height == 2 * plane->src_height)
502 *y_ratio = 1;
503 else
504 goto fail;
505 }
506
507 return 0;
508
509fail:
510 DRM_DEBUG_KMS("only 2x width/height scaling of plane supported\n");
511 return -ENOTSUPP;
512}
513
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900514static void mixer_graph_buffer(struct mixer_context *ctx, int win)
515{
516 struct mixer_resources *res = &ctx->mixer_res;
517 unsigned long flags;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900518 struct exynos_drm_plane *plane;
Tobias Jakobi26110152015-04-07 01:14:52 +0200519 unsigned int x_ratio = 0, y_ratio = 0;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900520 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900521 dma_addr_t dma_addr;
522 unsigned int fmt;
523 u32 val;
524
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900525 plane = &ctx->planes[win];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900526
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200527 switch (plane->pixel_format) {
528 case DRM_FORMAT_XRGB4444:
529 fmt = MXR_FORMAT_ARGB4444;
530 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900531
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200532 case DRM_FORMAT_XRGB1555:
533 fmt = MXR_FORMAT_ARGB1555;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900534 break;
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200535
536 case DRM_FORMAT_RGB565:
537 fmt = MXR_FORMAT_RGB565;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900538 break;
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200539
540 case DRM_FORMAT_XRGB8888:
541 case DRM_FORMAT_ARGB8888:
542 fmt = MXR_FORMAT_ARGB8888;
543 break;
544
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900545 default:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200546 DRM_DEBUG_KMS("pixelformat unsupported by mixer\n");
547 return;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900548 }
549
Tobias Jakobi26110152015-04-07 01:14:52 +0200550 /* check if mixer supports requested scaling setup */
551 if (mixer_setup_scale(plane, &x_ratio, &y_ratio))
552 return;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900553
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900554 dst_x_offset = plane->crtc_x;
555 dst_y_offset = plane->crtc_y;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900556
557 /* converting dma address base and source offset */
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900558 dma_addr = plane->dma_addr[0]
Joonyoung Shimcb8a3db2015-04-07 15:59:38 +0900559 + (plane->src_x * plane->bpp >> 3)
560 + (plane->src_y * plane->pitch);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900561 src_x_offset = 0;
562 src_y_offset = 0;
563
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900564 if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900565 ctx->interlace = true;
566 else
567 ctx->interlace = false;
568
569 spin_lock_irqsave(&res->reg_slock, flags);
570 mixer_vsync_set_update(ctx, false);
571
572 /* setup format */
573 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
574 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
575
576 /* setup geometry */
Daniel Stoneadacb222015-03-17 13:24:58 +0000577 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win),
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900578 plane->pitch / (plane->bpp >> 3));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900579
Rahul Sharmadef5e092013-06-19 18:21:08 +0530580 /* setup display size */
581 if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
582 win == MIXER_DEFAULT_WIN) {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900583 val = MXR_MXR_RES_HEIGHT(plane->mode_height);
584 val |= MXR_MXR_RES_WIDTH(plane->mode_width);
Rahul Sharmadef5e092013-06-19 18:21:08 +0530585 mixer_reg_write(res, MXR_RESOLUTION, val);
586 }
587
Tobias Jakobi26110152015-04-07 01:14:52 +0200588 val = MXR_GRP_WH_WIDTH(plane->src_width);
589 val |= MXR_GRP_WH_HEIGHT(plane->src_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900590 val |= MXR_GRP_WH_H_SCALE(x_ratio);
591 val |= MXR_GRP_WH_V_SCALE(y_ratio);
592 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
593
594 /* setup offsets in source image */
595 val = MXR_GRP_SXY_SX(src_x_offset);
596 val |= MXR_GRP_SXY_SY(src_y_offset);
597 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
598
599 /* setup offsets in display image */
600 val = MXR_GRP_DXY_DX(dst_x_offset);
601 val |= MXR_GRP_DXY_DY(dst_y_offset);
602 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
603
604 /* set buffer address to mixer */
605 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
606
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900607 mixer_cfg_scan(ctx, plane->mode_height);
608 mixer_cfg_rgb_fmt(ctx, plane->mode_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900609 mixer_cfg_layer(ctx, win, true);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530610
611 /* layer update mandatory for mixer 16.0.33.0 */
Rahul Sharmadef5e092013-06-19 18:21:08 +0530612 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
613 ctx->mxr_ver == MXR_VER_128_0_0_184)
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530614 mixer_layer_update(ctx);
615
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900616 mixer_run(ctx);
617
618 mixer_vsync_set_update(ctx, true);
619 spin_unlock_irqrestore(&res->reg_slock, flags);
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200620
621 mixer_regs_dump(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900622}
623
624static void vp_win_reset(struct mixer_context *ctx)
625{
626 struct mixer_resources *res = &ctx->mixer_res;
627 int tries = 100;
628
629 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
630 for (tries = 100; tries; --tries) {
631 /* waiting until VP_SRESET_PROCESSING is 0 */
632 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
633 break;
Sean Paul09760ea2013-01-14 17:03:20 -0500634 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900635 }
636 WARN(tries == 0, "failed to reset Video Processor\n");
637}
638
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900639static void mixer_win_reset(struct mixer_context *ctx)
640{
641 struct mixer_resources *res = &ctx->mixer_res;
642 unsigned long flags;
643 u32 val; /* value stored to register */
644
645 spin_lock_irqsave(&res->reg_slock, flags);
646 mixer_vsync_set_update(ctx, false);
647
648 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
649
650 /* set output in RGB888 mode */
651 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
652
653 /* 16 beat burst in DMA */
654 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
655 MXR_STATUS_BURST_MASK);
656
657 /* setting default layer priority: layer1 > layer0 > video
658 * because typical usage scenario would be
659 * layer1 - OSD
660 * layer0 - framebuffer
661 * video - video overlay
662 */
663 val = MXR_LAYER_CFG_GRP1_VAL(3);
664 val |= MXR_LAYER_CFG_GRP0_VAL(2);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530665 if (ctx->vp_enabled)
666 val |= MXR_LAYER_CFG_VP_VAL(1);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900667 mixer_reg_write(res, MXR_LAYER_CFG, val);
668
669 /* setting background color */
670 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
671 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
672 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
673
674 /* setting graphical layers */
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900675 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
676 val |= MXR_GRP_CFG_WIN_BLEND_EN;
677 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
678
Sean Paul0377f4e2013-04-25 15:13:26 -0400679 /* Don't blend layer 0 onto the mixer background */
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900680 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
Sean Paul0377f4e2013-04-25 15:13:26 -0400681
682 /* Blend layer 1 into layer 0 */
683 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
684 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900685 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
686
Seung-Woo Kim57366032012-05-15 17:22:08 +0900687 /* setting video layers */
688 val = MXR_GRP_CFG_ALPHA_VAL(0);
689 mixer_reg_write(res, MXR_VIDEO_CFG, val);
690
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530691 if (ctx->vp_enabled) {
692 /* configuration of Video Processor Registers */
693 vp_win_reset(ctx);
694 vp_default_filter(res);
695 }
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900696
697 /* disable all layers */
698 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
699 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530700 if (ctx->vp_enabled)
701 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900702
703 mixer_vsync_set_update(ctx, true);
704 spin_unlock_irqrestore(&res->reg_slock, flags);
705}
706
Sean Paul45517892014-01-30 16:19:05 -0500707static irqreturn_t mixer_irq_handler(int irq, void *arg)
708{
709 struct mixer_context *ctx = arg;
710 struct mixer_resources *res = &ctx->mixer_res;
711 u32 val, base, shadow;
712
713 spin_lock(&res->reg_slock);
714
715 /* read interrupt status for handling and clearing flags for VSYNC */
716 val = mixer_reg_read(res, MXR_INT_STATUS);
717
718 /* handling VSYNC */
719 if (val & MXR_INT_STATUS_VSYNC) {
720 /* interlace scan need to check shadow register */
721 if (ctx->interlace) {
722 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
723 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
724 if (base != shadow)
725 goto out;
726
727 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
728 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
729 if (base != shadow)
730 goto out;
731 }
732
733 drm_handle_vblank(ctx->drm_dev, ctx->pipe);
734 exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
735
736 /* set wait vsync event to zero and wake up queue. */
737 if (atomic_read(&ctx->wait_vsync_event)) {
738 atomic_set(&ctx->wait_vsync_event, 0);
739 wake_up(&ctx->wait_vsync_queue);
740 }
741 }
742
743out:
744 /* clear interrupts */
745 if (~val & MXR_INT_EN_VSYNC) {
746 /* vsync interrupt use different bit for read and clear */
747 val &= ~MXR_INT_EN_VSYNC;
748 val |= MXR_INT_CLEAR_VSYNC;
749 }
750 mixer_reg_write(res, MXR_INT_STATUS, val);
751
752 spin_unlock(&res->reg_slock);
753
754 return IRQ_HANDLED;
755}
756
757static int mixer_resources_init(struct mixer_context *mixer_ctx)
758{
759 struct device *dev = &mixer_ctx->pdev->dev;
760 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
761 struct resource *res;
762 int ret;
763
764 spin_lock_init(&mixer_res->reg_slock);
765
766 mixer_res->mixer = devm_clk_get(dev, "mixer");
767 if (IS_ERR(mixer_res->mixer)) {
768 dev_err(dev, "failed to get clock 'mixer'\n");
769 return -ENODEV;
770 }
771
Marek Szyprowski04427ec2015-02-02 14:20:28 +0100772 mixer_res->hdmi = devm_clk_get(dev, "hdmi");
773 if (IS_ERR(mixer_res->hdmi)) {
774 dev_err(dev, "failed to get clock 'hdmi'\n");
775 return PTR_ERR(mixer_res->hdmi);
776 }
777
Sean Paul45517892014-01-30 16:19:05 -0500778 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
779 if (IS_ERR(mixer_res->sclk_hdmi)) {
780 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
781 return -ENODEV;
782 }
783 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
784 if (res == NULL) {
785 dev_err(dev, "get memory resource failed.\n");
786 return -ENXIO;
787 }
788
789 mixer_res->mixer_regs = devm_ioremap(dev, res->start,
790 resource_size(res));
791 if (mixer_res->mixer_regs == NULL) {
792 dev_err(dev, "register mapping failed.\n");
793 return -ENXIO;
794 }
795
796 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
797 if (res == NULL) {
798 dev_err(dev, "get interrupt resource failed.\n");
799 return -ENXIO;
800 }
801
802 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
803 0, "drm_mixer", mixer_ctx);
804 if (ret) {
805 dev_err(dev, "request interrupt failed.\n");
806 return ret;
807 }
808 mixer_res->irq = res->start;
809
810 return 0;
811}
812
813static int vp_resources_init(struct mixer_context *mixer_ctx)
814{
815 struct device *dev = &mixer_ctx->pdev->dev;
816 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
817 struct resource *res;
818
819 mixer_res->vp = devm_clk_get(dev, "vp");
820 if (IS_ERR(mixer_res->vp)) {
821 dev_err(dev, "failed to get clock 'vp'\n");
822 return -ENODEV;
823 }
Sean Paul45517892014-01-30 16:19:05 -0500824
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200825 if (mixer_ctx->has_sclk) {
826 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
827 if (IS_ERR(mixer_res->sclk_mixer)) {
828 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
829 return -ENODEV;
830 }
831 mixer_res->mout_mixer = devm_clk_get(dev, "mout_mixer");
832 if (IS_ERR(mixer_res->mout_mixer)) {
833 dev_err(dev, "failed to get clock 'mout_mixer'\n");
834 return -ENODEV;
835 }
836
837 if (mixer_res->sclk_hdmi && mixer_res->mout_mixer)
838 clk_set_parent(mixer_res->mout_mixer,
839 mixer_res->sclk_hdmi);
840 }
Sean Paul45517892014-01-30 16:19:05 -0500841
842 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
843 if (res == NULL) {
844 dev_err(dev, "get memory resource failed.\n");
845 return -ENXIO;
846 }
847
848 mixer_res->vp_regs = devm_ioremap(dev, res->start,
849 resource_size(res));
850 if (mixer_res->vp_regs == NULL) {
851 dev_err(dev, "register mapping failed.\n");
852 return -ENXIO;
853 }
854
855 return 0;
856}
857
Gustavo Padovan93bca242015-01-18 18:16:23 +0900858static int mixer_initialize(struct mixer_context *mixer_ctx,
Inki Daef37cd5e2014-05-09 14:25:20 +0900859 struct drm_device *drm_dev)
Sean Paul45517892014-01-30 16:19:05 -0500860{
861 int ret;
Inki Daef37cd5e2014-05-09 14:25:20 +0900862 struct exynos_drm_private *priv;
863 priv = drm_dev->dev_private;
Sean Paul45517892014-01-30 16:19:05 -0500864
Gustavo Padovaneb88e422014-11-26 16:43:27 -0200865 mixer_ctx->drm_dev = drm_dev;
Gustavo Padovan8a326ed2014-11-04 18:44:47 -0200866 mixer_ctx->pipe = priv->pipe++;
Sean Paul45517892014-01-30 16:19:05 -0500867
868 /* acquire resources: regs, irqs, clocks */
869 ret = mixer_resources_init(mixer_ctx);
870 if (ret) {
871 DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
872 return ret;
873 }
874
875 if (mixer_ctx->vp_enabled) {
876 /* acquire vp resources: regs, irqs, clocks */
877 ret = vp_resources_init(mixer_ctx);
878 if (ret) {
879 DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
880 return ret;
881 }
882 }
883
Sean Paulf041b252014-01-30 16:19:15 -0500884 if (!is_drm_iommu_supported(mixer_ctx->drm_dev))
885 return 0;
886
887 return drm_iommu_attach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Sean Paul45517892014-01-30 16:19:05 -0500888}
889
Gustavo Padovan93bca242015-01-18 18:16:23 +0900890static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
Inki Dae1055b392012-10-19 17:37:35 +0900891{
Sean Paulf041b252014-01-30 16:19:15 -0500892 if (is_drm_iommu_supported(mixer_ctx->drm_dev))
893 drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Inki Dae1055b392012-10-19 17:37:35 +0900894}
895
Gustavo Padovan93bca242015-01-18 18:16:23 +0900896static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900897{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900898 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900899 struct mixer_resources *res = &mixer_ctx->mixer_res;
900
Sean Paulf041b252014-01-30 16:19:15 -0500901 if (!mixer_ctx->powered) {
902 mixer_ctx->int_en |= MXR_INT_EN_VSYNC;
903 return 0;
904 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900905
906 /* enable vsync interrupt */
907 mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
908 MXR_INT_EN_VSYNC);
909
910 return 0;
911}
912
Gustavo Padovan93bca242015-01-18 18:16:23 +0900913static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900914{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900915 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900916 struct mixer_resources *res = &mixer_ctx->mixer_res;
917
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900918 /* disable vsync interrupt */
919 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
920}
921
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +0900922static void mixer_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900923{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900924 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900925
YoungJun Chocbc4c332013-06-12 10:44:40 +0900926 DRM_DEBUG_KMS("win: %d\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900927
Shirish Sdda90122013-01-23 22:03:18 -0500928 mutex_lock(&mixer_ctx->mixer_mutex);
929 if (!mixer_ctx->powered) {
930 mutex_unlock(&mixer_ctx->mixer_mutex);
931 return;
932 }
933 mutex_unlock(&mixer_ctx->mixer_mutex);
934
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530935 if (win > 1 && mixer_ctx->vp_enabled)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900936 vp_video_buffer(mixer_ctx, win);
937 else
938 mixer_graph_buffer(mixer_ctx, win);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530939
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900940 mixer_ctx->planes[win].enabled = true;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900941}
942
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +0900943static void mixer_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900944{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900945 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900946 struct mixer_resources *res = &mixer_ctx->mixer_res;
947 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900948
YoungJun Chocbc4c332013-06-12 10:44:40 +0900949 DRM_DEBUG_KMS("win: %d\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900950
Prathyush Kdb43fd12012-12-06 20:16:05 +0530951 mutex_lock(&mixer_ctx->mixer_mutex);
952 if (!mixer_ctx->powered) {
953 mutex_unlock(&mixer_ctx->mixer_mutex);
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900954 mixer_ctx->planes[win].resume = false;
Prathyush Kdb43fd12012-12-06 20:16:05 +0530955 return;
956 }
957 mutex_unlock(&mixer_ctx->mixer_mutex);
958
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900959 spin_lock_irqsave(&res->reg_slock, flags);
960 mixer_vsync_set_update(mixer_ctx, false);
961
962 mixer_cfg_layer(mixer_ctx, win, false);
963
964 mixer_vsync_set_update(mixer_ctx, true);
965 spin_unlock_irqrestore(&res->reg_slock, flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530966
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900967 mixer_ctx->planes[win].enabled = false;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900968}
969
Gustavo Padovan93bca242015-01-18 18:16:23 +0900970static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
Rahul Sharma0ea68222013-01-15 08:11:06 -0500971{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900972 struct mixer_context *mixer_ctx = crtc->ctx;
Joonyoung Shim7c4c5582015-01-18 17:48:29 +0900973 int err;
Prathyush K8137a2e2012-12-06 20:16:01 +0530974
Prathyush K6e95d5e2012-12-06 20:16:03 +0530975 mutex_lock(&mixer_ctx->mixer_mutex);
976 if (!mixer_ctx->powered) {
977 mutex_unlock(&mixer_ctx->mixer_mutex);
978 return;
979 }
980 mutex_unlock(&mixer_ctx->mixer_mutex);
981
Gustavo Padovan93bca242015-01-18 18:16:23 +0900982 err = drm_vblank_get(mixer_ctx->drm_dev, mixer_ctx->pipe);
Joonyoung Shim7c4c5582015-01-18 17:48:29 +0900983 if (err < 0) {
984 DRM_DEBUG_KMS("failed to acquire vblank counter\n");
985 return;
986 }
Rahul Sharma5d39b9e2014-06-23 11:02:25 +0530987
Prathyush K6e95d5e2012-12-06 20:16:03 +0530988 atomic_set(&mixer_ctx->wait_vsync_event, 1);
989
990 /*
991 * wait for MIXER to signal VSYNC interrupt or return after
992 * timeout which is set to 50ms (refresh rate of 20).
993 */
994 if (!wait_event_timeout(mixer_ctx->wait_vsync_queue,
995 !atomic_read(&mixer_ctx->wait_vsync_event),
Daniel Vetterbfd83032013-12-11 11:34:41 +0100996 HZ/20))
Prathyush K8137a2e2012-12-06 20:16:01 +0530997 DRM_DEBUG_KMS("vblank wait timed out.\n");
Rahul Sharma5d39b9e2014-06-23 11:02:25 +0530998
Gustavo Padovan93bca242015-01-18 18:16:23 +0900999 drm_vblank_put(mixer_ctx->drm_dev, mixer_ctx->pipe);
Prathyush K8137a2e2012-12-06 20:16:01 +05301000}
1001
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001002static void mixer_window_suspend(struct mixer_context *ctx)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301003{
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001004 struct exynos_drm_plane *plane;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301005 int i;
1006
1007 for (i = 0; i < MIXER_WIN_NR; i++) {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001008 plane = &ctx->planes[i];
1009 plane->resume = plane->enabled;
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001010 mixer_win_disable(ctx->crtc, i);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301011 }
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001012 mixer_wait_for_vblank(ctx->crtc);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301013}
1014
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001015static void mixer_window_resume(struct mixer_context *ctx)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301016{
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001017 struct exynos_drm_plane *plane;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301018 int i;
1019
1020 for (i = 0; i < MIXER_WIN_NR; i++) {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001021 plane = &ctx->planes[i];
1022 plane->enabled = plane->resume;
1023 plane->resume = false;
1024 if (plane->enabled)
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001025 mixer_win_commit(ctx->crtc, i);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301026 }
1027}
1028
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001029static void mixer_poweron(struct mixer_context *ctx)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301030{
1031 struct mixer_resources *res = &ctx->mixer_res;
1032
Prathyush Kdb43fd12012-12-06 20:16:05 +05301033 mutex_lock(&ctx->mixer_mutex);
1034 if (ctx->powered) {
1035 mutex_unlock(&ctx->mixer_mutex);
1036 return;
1037 }
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301038
Prathyush Kdb43fd12012-12-06 20:16:05 +05301039 mutex_unlock(&ctx->mixer_mutex);
1040
Sean Paulaf65c802014-01-30 16:19:27 -05001041 pm_runtime_get_sync(ctx->dev);
1042
Sean Paul0bfb1f82013-06-11 12:24:02 +05301043 clk_prepare_enable(res->mixer);
Marek Szyprowski04427ec2015-02-02 14:20:28 +01001044 clk_prepare_enable(res->hdmi);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301045 if (ctx->vp_enabled) {
Sean Paul0bfb1f82013-06-11 12:24:02 +05301046 clk_prepare_enable(res->vp);
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001047 if (ctx->has_sclk)
1048 clk_prepare_enable(res->sclk_mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301049 }
1050
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301051 mutex_lock(&ctx->mixer_mutex);
1052 ctx->powered = true;
1053 mutex_unlock(&ctx->mixer_mutex);
1054
Rahul Sharmad74ed932014-06-23 11:02:24 +05301055 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
1056
Prathyush Kdb43fd12012-12-06 20:16:05 +05301057 mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
1058 mixer_win_reset(ctx);
1059
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001060 mixer_window_resume(ctx);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301061}
1062
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001063static void mixer_poweroff(struct mixer_context *ctx)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301064{
1065 struct mixer_resources *res = &ctx->mixer_res;
1066
Prathyush Kdb43fd12012-12-06 20:16:05 +05301067 mutex_lock(&ctx->mixer_mutex);
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301068 if (!ctx->powered) {
1069 mutex_unlock(&ctx->mixer_mutex);
1070 return;
1071 }
Prathyush Kdb43fd12012-12-06 20:16:05 +05301072 mutex_unlock(&ctx->mixer_mutex);
1073
Rahul Sharma381be022014-06-23 11:02:22 +05301074 mixer_stop(ctx);
Tobias Jakobic0734fb2015-05-06 14:10:21 +02001075 mixer_regs_dump(ctx);
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001076 mixer_window_suspend(ctx);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301077
1078 ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
1079
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301080 mutex_lock(&ctx->mixer_mutex);
1081 ctx->powered = false;
1082 mutex_unlock(&ctx->mixer_mutex);
1083
Marek Szyprowski04427ec2015-02-02 14:20:28 +01001084 clk_disable_unprepare(res->hdmi);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301085 clk_disable_unprepare(res->mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301086 if (ctx->vp_enabled) {
Sean Paul0bfb1f82013-06-11 12:24:02 +05301087 clk_disable_unprepare(res->vp);
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001088 if (ctx->has_sclk)
1089 clk_disable_unprepare(res->sclk_mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301090 }
1091
Sean Paulaf65c802014-01-30 16:19:27 -05001092 pm_runtime_put_sync(ctx->dev);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301093}
1094
Gustavo Padovan93bca242015-01-18 18:16:23 +09001095static void mixer_dpms(struct exynos_drm_crtc *crtc, int mode)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301096{
Prathyush Kdb43fd12012-12-06 20:16:05 +05301097 switch (mode) {
1098 case DRM_MODE_DPMS_ON:
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001099 mixer_poweron(crtc->ctx);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301100 break;
1101 case DRM_MODE_DPMS_STANDBY:
1102 case DRM_MODE_DPMS_SUSPEND:
1103 case DRM_MODE_DPMS_OFF:
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001104 mixer_poweroff(crtc->ctx);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301105 break;
1106 default:
1107 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
1108 break;
1109 }
1110}
1111
Sean Paulf041b252014-01-30 16:19:15 -05001112/* Only valid for Mixer version 16.0.33.0 */
1113int mixer_check_mode(struct drm_display_mode *mode)
1114{
1115 u32 w, h;
1116
1117 w = mode->hdisplay;
1118 h = mode->vdisplay;
1119
1120 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
1121 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1122 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1123
1124 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
1125 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1126 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1127 return 0;
1128
1129 return -EINVAL;
1130}
1131
Krzysztof Kozlowskif3aaf762015-05-07 09:04:45 +09001132static const struct exynos_drm_crtc_ops mixer_crtc_ops = {
Sean Paulf041b252014-01-30 16:19:15 -05001133 .dpms = mixer_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001134 .enable_vblank = mixer_enable_vblank,
1135 .disable_vblank = mixer_disable_vblank,
Prathyush K8137a2e2012-12-06 20:16:01 +05301136 .wait_for_vblank = mixer_wait_for_vblank,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001137 .win_commit = mixer_win_commit,
1138 .win_disable = mixer_win_disable,
Sean Paulf041b252014-01-30 16:19:15 -05001139};
Rahul Sharma0ea68222013-01-15 08:11:06 -05001140
Rahul Sharmadef5e092013-06-19 18:21:08 +05301141static struct mixer_drv_data exynos5420_mxr_drv_data = {
1142 .version = MXR_VER_128_0_0_184,
1143 .is_vp_enabled = 0,
1144};
1145
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301146static struct mixer_drv_data exynos5250_mxr_drv_data = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301147 .version = MXR_VER_16_0_33_0,
1148 .is_vp_enabled = 0,
1149};
1150
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001151static struct mixer_drv_data exynos4212_mxr_drv_data = {
1152 .version = MXR_VER_0_0_0_16,
1153 .is_vp_enabled = 1,
1154};
1155
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301156static struct mixer_drv_data exynos4210_mxr_drv_data = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301157 .version = MXR_VER_0_0_0_16,
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301158 .is_vp_enabled = 1,
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001159 .has_sclk = 1,
Rahul Sharma1e123442012-10-04 20:48:51 +05301160};
1161
Krzysztof Kozlowskid6b16302015-05-02 00:56:36 +09001162static const struct platform_device_id mixer_driver_types[] = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301163 {
1164 .name = "s5p-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301165 .driver_data = (unsigned long)&exynos4210_mxr_drv_data,
Rahul Sharma1e123442012-10-04 20:48:51 +05301166 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301167 .name = "exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301168 .driver_data = (unsigned long)&exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301169 }, {
1170 /* end node */
1171 }
1172};
1173
1174static struct of_device_id mixer_match_types[] = {
1175 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001176 .compatible = "samsung,exynos4210-mixer",
1177 .data = &exynos4210_mxr_drv_data,
1178 }, {
1179 .compatible = "samsung,exynos4212-mixer",
1180 .data = &exynos4212_mxr_drv_data,
1181 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301182 .compatible = "samsung,exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301183 .data = &exynos5250_mxr_drv_data,
1184 }, {
1185 .compatible = "samsung,exynos5250-mixer",
1186 .data = &exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301187 }, {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301188 .compatible = "samsung,exynos5420-mixer",
1189 .data = &exynos5420_mxr_drv_data,
1190 }, {
Rahul Sharma1e123442012-10-04 20:48:51 +05301191 /* end node */
1192 }
1193};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001194MODULE_DEVICE_TABLE(of, mixer_match_types);
Rahul Sharma1e123442012-10-04 20:48:51 +05301195
Inki Daef37cd5e2014-05-09 14:25:20 +09001196static int mixer_bind(struct device *dev, struct device *manager, void *data)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001197{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001198 struct mixer_context *ctx = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09001199 struct drm_device *drm_dev = data;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001200 struct exynos_drm_plane *exynos_plane;
1201 enum drm_plane_type type;
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +09001202 unsigned int zpos;
1203 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001204
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001205 ret = mixer_initialize(ctx, drm_dev);
1206 if (ret)
1207 return ret;
1208
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001209 for (zpos = 0; zpos < MIXER_WIN_NR; zpos++) {
1210 type = (zpos == MIXER_DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY :
1211 DRM_PLANE_TYPE_OVERLAY;
1212 ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +09001213 1 << ctx->pipe, type, zpos);
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001214 if (ret)
1215 return ret;
1216 }
1217
1218 exynos_plane = &ctx->planes[MIXER_DEFAULT_WIN];
1219 ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
1220 ctx->pipe, EXYNOS_DISPLAY_TYPE_HDMI,
1221 &mixer_crtc_ops, ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001222 if (IS_ERR(ctx->crtc)) {
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001223 mixer_ctx_remove(ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001224 ret = PTR_ERR(ctx->crtc);
1225 goto free_ctx;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001226 }
1227
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001228 return 0;
Gustavo Padovan93bca242015-01-18 18:16:23 +09001229
1230free_ctx:
1231 devm_kfree(dev, ctx);
1232 return ret;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001233}
1234
1235static void mixer_unbind(struct device *dev, struct device *master, void *data)
1236{
1237 struct mixer_context *ctx = dev_get_drvdata(dev);
1238
Gustavo Padovan93bca242015-01-18 18:16:23 +09001239 mixer_ctx_remove(ctx);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001240}
1241
1242static const struct component_ops mixer_component_ops = {
1243 .bind = mixer_bind,
1244 .unbind = mixer_unbind,
1245};
1246
1247static int mixer_probe(struct platform_device *pdev)
1248{
1249 struct device *dev = &pdev->dev;
1250 struct mixer_drv_data *drv;
1251 struct mixer_context *ctx;
1252 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001253
Sean Paulf041b252014-01-30 16:19:15 -05001254 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1255 if (!ctx) {
1256 DRM_ERROR("failed to alloc mixer context.\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001257 return -ENOMEM;
Sean Paulf041b252014-01-30 16:19:15 -05001258 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001259
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001260 mutex_init(&ctx->mixer_mutex);
1261
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301262 if (dev->of_node) {
1263 const struct of_device_id *match;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001264
Sachin Kamate436b092013-06-05 16:00:23 +09001265 match = of_match_node(mixer_match_types, dev->of_node);
Rahul Sharma2cdc53b2012-10-31 09:36:26 +05301266 drv = (struct mixer_drv_data *)match->data;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301267 } else {
1268 drv = (struct mixer_drv_data *)
1269 platform_get_device_id(pdev)->driver_data;
1270 }
1271
Sean Paul45517892014-01-30 16:19:05 -05001272 ctx->pdev = pdev;
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001273 ctx->dev = dev;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301274 ctx->vp_enabled = drv->is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001275 ctx->has_sclk = drv->has_sclk;
Rahul Sharma1e123442012-10-04 20:48:51 +05301276 ctx->mxr_ver = drv->version;
Daniel Vetter57ed0f72013-12-11 11:34:43 +01001277 init_waitqueue_head(&ctx->wait_vsync_queue);
Prathyush K6e95d5e2012-12-06 20:16:03 +05301278 atomic_set(&ctx->wait_vsync_event, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001279
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001280 platform_set_drvdata(pdev, ctx);
Inki Daedf5225b2014-05-29 18:28:02 +09001281
1282 ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
Gustavo Padovan5d1741a2014-11-05 19:51:35 -02001283 EXYNOS_DISPLAY_TYPE_HDMI);
Inki Daedf5225b2014-05-29 18:28:02 +09001284 if (ret)
1285 return ret;
1286
1287 ret = component_add(&pdev->dev, &mixer_component_ops);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001288 if (ret) {
Inki Daedf5225b2014-05-29 18:28:02 +09001289 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001290 return ret;
1291 }
1292
1293 pm_runtime_enable(dev);
Inki Daedf5225b2014-05-29 18:28:02 +09001294
1295 return ret;
Inki Daef37cd5e2014-05-09 14:25:20 +09001296}
1297
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001298static int mixer_remove(struct platform_device *pdev)
1299{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001300 pm_runtime_disable(&pdev->dev);
1301
Inki Daedf5225b2014-05-29 18:28:02 +09001302 component_del(&pdev->dev, &mixer_component_ops);
1303 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
1304
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001305 return 0;
1306}
1307
1308struct platform_driver mixer_driver = {
1309 .driver = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301310 .name = "exynos-mixer",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001311 .owner = THIS_MODULE,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301312 .of_match_table = mixer_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001313 },
1314 .probe = mixer_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001315 .remove = mixer_remove,
Rahul Sharma1e123442012-10-04 20:48:51 +05301316 .id_table = mixer_driver_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001317};