blob: 9275d3af385ff503c9fa6b87f753034fa351c8aa [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
Andrzej Hajdaa44652e2015-07-09 08:25:42 +020072enum mixer_flag_bits {
73 MXR_BIT_POWERED,
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +020074 MXR_BIT_VSYNC,
Andrzej Hajdaa44652e2015-07-09 08:25:42 +020075};
76
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090077struct mixer_context {
Sean Paul45517892014-01-30 16:19:05 -050078 struct platform_device *pdev;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090079 struct device *dev;
Inki Dae1055b392012-10-19 17:37:35 +090080 struct drm_device *drm_dev;
Gustavo Padovan93bca242015-01-18 18:16:23 +090081 struct exynos_drm_crtc *crtc;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +090082 struct exynos_drm_plane planes[MIXER_WIN_NR];
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090083 int pipe;
Andrzej Hajdaa44652e2015-07-09 08:25:42 +020084 unsigned long flags;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090085 bool interlace;
Rahul Sharma1b8e5742012-10-04 20:48:52 +053086 bool vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +020087 bool has_sclk;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090088
89 struct mixer_resources mixer_res;
Rahul Sharma1e123442012-10-04 20:48:51 +053090 enum mixer_version_id mxr_ver;
Prathyush K6e95d5e2012-12-06 20:16:03 +053091 wait_queue_head_t wait_vsync_queue;
92 atomic_t wait_vsync_event;
Rahul Sharma1e123442012-10-04 20:48:51 +053093};
94
95struct mixer_drv_data {
96 enum mixer_version_id version;
Rahul Sharma1b8e5742012-10-04 20:48:52 +053097 bool is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +020098 bool has_sclk;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090099};
100
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900101static const u8 filter_y_horiz_tap8[] = {
102 0, -1, -1, -1, -1, -1, -1, -1,
103 -1, -1, -1, -1, -1, 0, 0, 0,
104 0, 2, 4, 5, 6, 6, 6, 6,
105 6, 5, 5, 4, 3, 2, 1, 1,
106 0, -6, -12, -16, -18, -20, -21, -20,
107 -20, -18, -16, -13, -10, -8, -5, -2,
108 127, 126, 125, 121, 114, 107, 99, 89,
109 79, 68, 57, 46, 35, 25, 16, 8,
110};
111
112static const u8 filter_y_vert_tap4[] = {
113 0, -3, -6, -8, -8, -8, -8, -7,
114 -6, -5, -4, -3, -2, -1, -1, 0,
115 127, 126, 124, 118, 111, 102, 92, 81,
116 70, 59, 48, 37, 27, 19, 11, 5,
117 0, 5, 11, 19, 27, 37, 48, 59,
118 70, 81, 92, 102, 111, 118, 124, 126,
119 0, 0, -1, -1, -2, -3, -4, -5,
120 -6, -7, -8, -8, -8, -8, -6, -3,
121};
122
123static const u8 filter_cr_horiz_tap4[] = {
124 0, -3, -6, -8, -8, -8, -8, -7,
125 -6, -5, -4, -3, -2, -1, -1, 0,
126 127, 126, 124, 118, 111, 102, 92, 81,
127 70, 59, 48, 37, 27, 19, 11, 5,
128};
129
130static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
131{
132 return readl(res->vp_regs + reg_id);
133}
134
135static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
136 u32 val)
137{
138 writel(val, res->vp_regs + reg_id);
139}
140
141static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
142 u32 val, u32 mask)
143{
144 u32 old = vp_reg_read(res, reg_id);
145
146 val = (val & mask) | (old & ~mask);
147 writel(val, res->vp_regs + reg_id);
148}
149
150static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
151{
152 return readl(res->mixer_regs + reg_id);
153}
154
155static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
156 u32 val)
157{
158 writel(val, res->mixer_regs + reg_id);
159}
160
161static inline void mixer_reg_writemask(struct mixer_resources *res,
162 u32 reg_id, u32 val, u32 mask)
163{
164 u32 old = mixer_reg_read(res, reg_id);
165
166 val = (val & mask) | (old & ~mask);
167 writel(val, res->mixer_regs + reg_id);
168}
169
170static void mixer_regs_dump(struct mixer_context *ctx)
171{
172#define DUMPREG(reg_id) \
173do { \
174 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
175 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
176} while (0)
177
178 DUMPREG(MXR_STATUS);
179 DUMPREG(MXR_CFG);
180 DUMPREG(MXR_INT_EN);
181 DUMPREG(MXR_INT_STATUS);
182
183 DUMPREG(MXR_LAYER_CFG);
184 DUMPREG(MXR_VIDEO_CFG);
185
186 DUMPREG(MXR_GRAPHIC0_CFG);
187 DUMPREG(MXR_GRAPHIC0_BASE);
188 DUMPREG(MXR_GRAPHIC0_SPAN);
189 DUMPREG(MXR_GRAPHIC0_WH);
190 DUMPREG(MXR_GRAPHIC0_SXY);
191 DUMPREG(MXR_GRAPHIC0_DXY);
192
193 DUMPREG(MXR_GRAPHIC1_CFG);
194 DUMPREG(MXR_GRAPHIC1_BASE);
195 DUMPREG(MXR_GRAPHIC1_SPAN);
196 DUMPREG(MXR_GRAPHIC1_WH);
197 DUMPREG(MXR_GRAPHIC1_SXY);
198 DUMPREG(MXR_GRAPHIC1_DXY);
199#undef DUMPREG
200}
201
202static void vp_regs_dump(struct mixer_context *ctx)
203{
204#define DUMPREG(reg_id) \
205do { \
206 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
207 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
208} while (0)
209
210 DUMPREG(VP_ENABLE);
211 DUMPREG(VP_SRESET);
212 DUMPREG(VP_SHADOW_UPDATE);
213 DUMPREG(VP_FIELD_ID);
214 DUMPREG(VP_MODE);
215 DUMPREG(VP_IMG_SIZE_Y);
216 DUMPREG(VP_IMG_SIZE_C);
217 DUMPREG(VP_PER_RATE_CTRL);
218 DUMPREG(VP_TOP_Y_PTR);
219 DUMPREG(VP_BOT_Y_PTR);
220 DUMPREG(VP_TOP_C_PTR);
221 DUMPREG(VP_BOT_C_PTR);
222 DUMPREG(VP_ENDIAN_MODE);
223 DUMPREG(VP_SRC_H_POSITION);
224 DUMPREG(VP_SRC_V_POSITION);
225 DUMPREG(VP_SRC_WIDTH);
226 DUMPREG(VP_SRC_HEIGHT);
227 DUMPREG(VP_DST_H_POSITION);
228 DUMPREG(VP_DST_V_POSITION);
229 DUMPREG(VP_DST_WIDTH);
230 DUMPREG(VP_DST_HEIGHT);
231 DUMPREG(VP_H_RATIO);
232 DUMPREG(VP_V_RATIO);
233
234#undef DUMPREG
235}
236
237static inline void vp_filter_set(struct mixer_resources *res,
238 int reg_id, const u8 *data, unsigned int size)
239{
240 /* assure 4-byte align */
241 BUG_ON(size & 3);
242 for (; size; size -= 4, reg_id += 4, data += 4) {
243 u32 val = (data[0] << 24) | (data[1] << 16) |
244 (data[2] << 8) | data[3];
245 vp_reg_write(res, reg_id, val);
246 }
247}
248
249static void vp_default_filter(struct mixer_resources *res)
250{
251 vp_filter_set(res, VP_POLY8_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530252 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900253 vp_filter_set(res, VP_POLY4_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530254 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900255 vp_filter_set(res, VP_POLY4_C0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530256 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900257}
258
259static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
260{
261 struct mixer_resources *res = &ctx->mixer_res;
262
263 /* block update on vsync */
264 mixer_reg_writemask(res, MXR_STATUS, enable ?
265 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
266
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530267 if (ctx->vp_enabled)
268 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900269 VP_SHADOW_UPDATE_ENABLE : 0);
270}
271
272static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
273{
274 struct mixer_resources *res = &ctx->mixer_res;
275 u32 val;
276
277 /* choosing between interlace and progressive mode */
278 val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
Tobias Jakobi1e6d4592015-04-07 01:14:50 +0200279 MXR_CFG_SCAN_PROGRESSIVE);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900280
Rahul Sharmadef5e092013-06-19 18:21:08 +0530281 if (ctx->mxr_ver != MXR_VER_128_0_0_184) {
282 /* choosing between proper HD and SD mode */
283 if (height <= 480)
284 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
285 else if (height <= 576)
286 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
287 else if (height <= 720)
288 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
289 else if (height <= 1080)
290 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
291 else
292 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
293 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900294
295 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
296}
297
298static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
299{
300 struct mixer_resources *res = &ctx->mixer_res;
301 u32 val;
302
303 if (height == 480) {
304 val = MXR_CFG_RGB601_0_255;
305 } else if (height == 576) {
306 val = MXR_CFG_RGB601_0_255;
307 } else if (height == 720) {
308 val = MXR_CFG_RGB709_16_235;
309 mixer_reg_write(res, MXR_CM_COEFF_Y,
310 (1 << 30) | (94 << 20) | (314 << 10) |
311 (32 << 0));
312 mixer_reg_write(res, MXR_CM_COEFF_CB,
313 (972 << 20) | (851 << 10) | (225 << 0));
314 mixer_reg_write(res, MXR_CM_COEFF_CR,
315 (225 << 20) | (820 << 10) | (1004 << 0));
316 } else if (height == 1080) {
317 val = MXR_CFG_RGB709_16_235;
318 mixer_reg_write(res, MXR_CM_COEFF_Y,
319 (1 << 30) | (94 << 20) | (314 << 10) |
320 (32 << 0));
321 mixer_reg_write(res, MXR_CM_COEFF_CB,
322 (972 << 20) | (851 << 10) | (225 << 0));
323 mixer_reg_write(res, MXR_CM_COEFF_CR,
324 (225 << 20) | (820 << 10) | (1004 << 0));
325 } else {
326 val = MXR_CFG_RGB709_16_235;
327 mixer_reg_write(res, MXR_CM_COEFF_Y,
328 (1 << 30) | (94 << 20) | (314 << 10) |
329 (32 << 0));
330 mixer_reg_write(res, MXR_CM_COEFF_CB,
331 (972 << 20) | (851 << 10) | (225 << 0));
332 mixer_reg_write(res, MXR_CM_COEFF_CR,
333 (225 << 20) | (820 << 10) | (1004 << 0));
334 }
335
336 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
337}
338
Tobias Jakobi5b1d5bc2015-05-06 14:10:22 +0200339static void mixer_cfg_layer(struct mixer_context *ctx, unsigned int win,
340 bool enable)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900341{
342 struct mixer_resources *res = &ctx->mixer_res;
343 u32 val = enable ? ~0 : 0;
344
345 switch (win) {
346 case 0:
347 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
348 break;
349 case 1:
350 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
351 break;
352 case 2:
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530353 if (ctx->vp_enabled) {
354 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
355 mixer_reg_writemask(res, MXR_CFG, val,
356 MXR_CFG_VP_ENABLE);
Joonyoung Shimf1e716d2014-07-25 19:59:10 +0900357
358 /* control blending of graphic layer 0 */
359 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(0), val,
360 MXR_GRP_CFG_BLEND_PRE_MUL |
361 MXR_GRP_CFG_PIXEL_BLEND_EN);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530362 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900363 break;
364 }
365}
366
367static void mixer_run(struct mixer_context *ctx)
368{
369 struct mixer_resources *res = &ctx->mixer_res;
370
371 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900372}
373
Rahul Sharma381be022014-06-23 11:02:22 +0530374static void mixer_stop(struct mixer_context *ctx)
375{
376 struct mixer_resources *res = &ctx->mixer_res;
377 int timeout = 20;
378
379 mixer_reg_writemask(res, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
380
381 while (!(mixer_reg_read(res, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
382 --timeout)
383 usleep_range(10000, 12000);
Rahul Sharma381be022014-06-23 11:02:22 +0530384}
385
Tobias Jakobi5b1d5bc2015-05-06 14:10:22 +0200386static void vp_video_buffer(struct mixer_context *ctx, unsigned int win)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900387{
388 struct mixer_resources *res = &ctx->mixer_res;
389 unsigned long flags;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900390 struct exynos_drm_plane *plane;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900391 dma_addr_t luma_addr[2], chroma_addr[2];
392 bool tiled_mode = false;
393 bool crcb_mode = false;
394 u32 val;
395
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900396 plane = &ctx->planes[win];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900397
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900398 switch (plane->pixel_format) {
Ville Syrjälä363b06a2012-05-14 11:08:51 +0900399 case DRM_FORMAT_NV12:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900400 crcb_mode = false;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900401 break;
Tobias Jakobi8f2590f2015-04-27 23:10:16 +0200402 case DRM_FORMAT_NV21:
403 crcb_mode = true;
404 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900405 default:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900406 DRM_ERROR("pixel format for vp is wrong [%d].\n",
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900407 plane->pixel_format);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900408 return;
409 }
410
Tobias Jakobifac8a5b2015-04-27 23:10:15 +0200411 luma_addr[0] = plane->dma_addr[0];
412 chroma_addr[0] = plane->dma_addr[1];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900413
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900414 if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900415 ctx->interlace = true;
416 if (tiled_mode) {
417 luma_addr[1] = luma_addr[0] + 0x40;
418 chroma_addr[1] = chroma_addr[0] + 0x40;
419 } else {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900420 luma_addr[1] = luma_addr[0] + plane->pitch;
421 chroma_addr[1] = chroma_addr[0] + plane->pitch;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900422 }
423 } else {
424 ctx->interlace = false;
425 luma_addr[1] = 0;
426 chroma_addr[1] = 0;
427 }
428
429 spin_lock_irqsave(&res->reg_slock, flags);
430 mixer_vsync_set_update(ctx, false);
431
432 /* interlace or progressive scan mode */
433 val = (ctx->interlace ? ~0 : 0);
434 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
435
436 /* setup format */
437 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
438 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
439 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
440
441 /* setting size of input image */
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900442 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(plane->pitch) |
443 VP_IMG_VSIZE(plane->fb_height));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900444 /* chroma height has to reduced by 2 to avoid chroma distorions */
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900445 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(plane->pitch) |
446 VP_IMG_VSIZE(plane->fb_height / 2));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900447
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900448 vp_reg_write(res, VP_SRC_WIDTH, plane->src_width);
449 vp_reg_write(res, VP_SRC_HEIGHT, plane->src_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900450 vp_reg_write(res, VP_SRC_H_POSITION,
Joonyoung Shimcb8a3db2015-04-07 15:59:38 +0900451 VP_SRC_H_POSITION_VAL(plane->src_x));
452 vp_reg_write(res, VP_SRC_V_POSITION, plane->src_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900453
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900454 vp_reg_write(res, VP_DST_WIDTH, plane->crtc_width);
455 vp_reg_write(res, VP_DST_H_POSITION, plane->crtc_x);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900456 if (ctx->interlace) {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900457 vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height / 2);
458 vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y / 2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900459 } else {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900460 vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height);
461 vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900462 }
463
Joonyoung Shim3cabaf72015-04-07 15:59:39 +0900464 vp_reg_write(res, VP_H_RATIO, plane->h_ratio);
465 vp_reg_write(res, VP_V_RATIO, plane->v_ratio);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900466
467 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
468
469 /* set buffer address to vp */
470 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
471 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
472 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
473 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
474
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900475 mixer_cfg_scan(ctx, plane->mode_height);
476 mixer_cfg_rgb_fmt(ctx, plane->mode_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900477 mixer_cfg_layer(ctx, win, true);
478 mixer_run(ctx);
479
480 mixer_vsync_set_update(ctx, true);
481 spin_unlock_irqrestore(&res->reg_slock, flags);
482
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200483 mixer_regs_dump(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900484 vp_regs_dump(ctx);
485}
486
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530487static void mixer_layer_update(struct mixer_context *ctx)
488{
489 struct mixer_resources *res = &ctx->mixer_res;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530490
Rahul Sharma5c0f4822014-06-23 11:02:23 +0530491 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530492}
493
Tobias Jakobi26110152015-04-07 01:14:52 +0200494static int mixer_setup_scale(const struct exynos_drm_plane *plane,
495 unsigned int *x_ratio, unsigned int *y_ratio)
496{
497 if (plane->crtc_width != plane->src_width) {
498 if (plane->crtc_width == 2 * plane->src_width)
499 *x_ratio = 1;
500 else
501 goto fail;
502 }
503
504 if (plane->crtc_height != plane->src_height) {
505 if (plane->crtc_height == 2 * plane->src_height)
506 *y_ratio = 1;
507 else
508 goto fail;
509 }
510
511 return 0;
512
513fail:
514 DRM_DEBUG_KMS("only 2x width/height scaling of plane supported\n");
515 return -ENOTSUPP;
516}
517
Tobias Jakobi5b1d5bc2015-05-06 14:10:22 +0200518static void mixer_graph_buffer(struct mixer_context *ctx, unsigned int win)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900519{
520 struct mixer_resources *res = &ctx->mixer_res;
521 unsigned long flags;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900522 struct exynos_drm_plane *plane;
Tobias Jakobi26110152015-04-07 01:14:52 +0200523 unsigned int x_ratio = 0, y_ratio = 0;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900524 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900525 dma_addr_t dma_addr;
526 unsigned int fmt;
527 u32 val;
528
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900529 plane = &ctx->planes[win];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900530
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200531 switch (plane->pixel_format) {
532 case DRM_FORMAT_XRGB4444:
533 fmt = MXR_FORMAT_ARGB4444;
534 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900535
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200536 case DRM_FORMAT_XRGB1555:
537 fmt = MXR_FORMAT_ARGB1555;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900538 break;
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200539
540 case DRM_FORMAT_RGB565:
541 fmt = MXR_FORMAT_RGB565;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900542 break;
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200543
544 case DRM_FORMAT_XRGB8888:
545 case DRM_FORMAT_ARGB8888:
546 fmt = MXR_FORMAT_ARGB8888;
547 break;
548
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900549 default:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200550 DRM_DEBUG_KMS("pixelformat unsupported by mixer\n");
551 return;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900552 }
553
Tobias Jakobi26110152015-04-07 01:14:52 +0200554 /* check if mixer supports requested scaling setup */
555 if (mixer_setup_scale(plane, &x_ratio, &y_ratio))
556 return;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900557
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900558 dst_x_offset = plane->crtc_x;
559 dst_y_offset = plane->crtc_y;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900560
561 /* converting dma address base and source offset */
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900562 dma_addr = plane->dma_addr[0]
Joonyoung Shimcb8a3db2015-04-07 15:59:38 +0900563 + (plane->src_x * plane->bpp >> 3)
564 + (plane->src_y * plane->pitch);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900565 src_x_offset = 0;
566 src_y_offset = 0;
567
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900568 if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900569 ctx->interlace = true;
570 else
571 ctx->interlace = false;
572
573 spin_lock_irqsave(&res->reg_slock, flags);
574 mixer_vsync_set_update(ctx, false);
575
576 /* setup format */
577 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
578 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
579
580 /* setup geometry */
Daniel Stoneadacb222015-03-17 13:24:58 +0000581 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win),
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900582 plane->pitch / (plane->bpp >> 3));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900583
Rahul Sharmadef5e092013-06-19 18:21:08 +0530584 /* setup display size */
585 if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
586 win == MIXER_DEFAULT_WIN) {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900587 val = MXR_MXR_RES_HEIGHT(plane->mode_height);
588 val |= MXR_MXR_RES_WIDTH(plane->mode_width);
Rahul Sharmadef5e092013-06-19 18:21:08 +0530589 mixer_reg_write(res, MXR_RESOLUTION, val);
590 }
591
Tobias Jakobi26110152015-04-07 01:14:52 +0200592 val = MXR_GRP_WH_WIDTH(plane->src_width);
593 val |= MXR_GRP_WH_HEIGHT(plane->src_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900594 val |= MXR_GRP_WH_H_SCALE(x_ratio);
595 val |= MXR_GRP_WH_V_SCALE(y_ratio);
596 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
597
598 /* setup offsets in source image */
599 val = MXR_GRP_SXY_SX(src_x_offset);
600 val |= MXR_GRP_SXY_SY(src_y_offset);
601 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
602
603 /* setup offsets in display image */
604 val = MXR_GRP_DXY_DX(dst_x_offset);
605 val |= MXR_GRP_DXY_DY(dst_y_offset);
606 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
607
608 /* set buffer address to mixer */
609 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
610
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900611 mixer_cfg_scan(ctx, plane->mode_height);
612 mixer_cfg_rgb_fmt(ctx, plane->mode_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900613 mixer_cfg_layer(ctx, win, true);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530614
615 /* layer update mandatory for mixer 16.0.33.0 */
Rahul Sharmadef5e092013-06-19 18:21:08 +0530616 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
617 ctx->mxr_ver == MXR_VER_128_0_0_184)
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530618 mixer_layer_update(ctx);
619
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900620 mixer_run(ctx);
621
622 mixer_vsync_set_update(ctx, true);
623 spin_unlock_irqrestore(&res->reg_slock, flags);
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200624
625 mixer_regs_dump(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900626}
627
628static void vp_win_reset(struct mixer_context *ctx)
629{
630 struct mixer_resources *res = &ctx->mixer_res;
631 int tries = 100;
632
633 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
634 for (tries = 100; tries; --tries) {
635 /* waiting until VP_SRESET_PROCESSING is 0 */
636 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
637 break;
Sean Paul09760ea2013-01-14 17:03:20 -0500638 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900639 }
640 WARN(tries == 0, "failed to reset Video Processor\n");
641}
642
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900643static void mixer_win_reset(struct mixer_context *ctx)
644{
645 struct mixer_resources *res = &ctx->mixer_res;
646 unsigned long flags;
647 u32 val; /* value stored to register */
648
649 spin_lock_irqsave(&res->reg_slock, flags);
650 mixer_vsync_set_update(ctx, false);
651
652 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
653
654 /* set output in RGB888 mode */
655 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
656
657 /* 16 beat burst in DMA */
658 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
659 MXR_STATUS_BURST_MASK);
660
661 /* setting default layer priority: layer1 > layer0 > video
662 * because typical usage scenario would be
663 * layer1 - OSD
664 * layer0 - framebuffer
665 * video - video overlay
666 */
667 val = MXR_LAYER_CFG_GRP1_VAL(3);
668 val |= MXR_LAYER_CFG_GRP0_VAL(2);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530669 if (ctx->vp_enabled)
670 val |= MXR_LAYER_CFG_VP_VAL(1);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900671 mixer_reg_write(res, MXR_LAYER_CFG, val);
672
673 /* setting background color */
674 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
675 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
676 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
677
678 /* setting graphical layers */
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900679 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
680 val |= MXR_GRP_CFG_WIN_BLEND_EN;
681 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
682
Sean Paul0377f4e2013-04-25 15:13:26 -0400683 /* Don't blend layer 0 onto the mixer background */
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900684 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
Sean Paul0377f4e2013-04-25 15:13:26 -0400685
686 /* Blend layer 1 into layer 0 */
687 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
688 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900689 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
690
Seung-Woo Kim57366032012-05-15 17:22:08 +0900691 /* setting video layers */
692 val = MXR_GRP_CFG_ALPHA_VAL(0);
693 mixer_reg_write(res, MXR_VIDEO_CFG, val);
694
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530695 if (ctx->vp_enabled) {
696 /* configuration of Video Processor Registers */
697 vp_win_reset(ctx);
698 vp_default_filter(res);
699 }
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900700
701 /* disable all layers */
702 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
703 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530704 if (ctx->vp_enabled)
705 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900706
707 mixer_vsync_set_update(ctx, true);
708 spin_unlock_irqrestore(&res->reg_slock, flags);
709}
710
Sean Paul45517892014-01-30 16:19:05 -0500711static irqreturn_t mixer_irq_handler(int irq, void *arg)
712{
713 struct mixer_context *ctx = arg;
714 struct mixer_resources *res = &ctx->mixer_res;
715 u32 val, base, shadow;
716
717 spin_lock(&res->reg_slock);
718
719 /* read interrupt status for handling and clearing flags for VSYNC */
720 val = mixer_reg_read(res, MXR_INT_STATUS);
721
722 /* handling VSYNC */
723 if (val & MXR_INT_STATUS_VSYNC) {
Andrzej Hajda81a464d2015-07-09 10:07:53 +0200724 /* vsync interrupt use different bit for read and clear */
725 val |= MXR_INT_CLEAR_VSYNC;
726 val &= ~MXR_INT_STATUS_VSYNC;
727
Sean Paul45517892014-01-30 16:19:05 -0500728 /* interlace scan need to check shadow register */
729 if (ctx->interlace) {
730 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
731 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
732 if (base != shadow)
733 goto out;
734
735 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
736 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
737 if (base != shadow)
738 goto out;
739 }
740
Gustavo Padovaneafd5402015-07-16 12:23:32 -0300741 drm_crtc_handle_vblank(&ctx->crtc->base);
742 exynos_drm_crtc_finish_pageflip(ctx->crtc);
Sean Paul45517892014-01-30 16:19:05 -0500743
744 /* set wait vsync event to zero and wake up queue. */
745 if (atomic_read(&ctx->wait_vsync_event)) {
746 atomic_set(&ctx->wait_vsync_event, 0);
747 wake_up(&ctx->wait_vsync_queue);
748 }
749 }
750
751out:
752 /* clear interrupts */
Sean Paul45517892014-01-30 16:19:05 -0500753 mixer_reg_write(res, MXR_INT_STATUS, val);
754
755 spin_unlock(&res->reg_slock);
756
757 return IRQ_HANDLED;
758}
759
760static int mixer_resources_init(struct mixer_context *mixer_ctx)
761{
762 struct device *dev = &mixer_ctx->pdev->dev;
763 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
764 struct resource *res;
765 int ret;
766
767 spin_lock_init(&mixer_res->reg_slock);
768
769 mixer_res->mixer = devm_clk_get(dev, "mixer");
770 if (IS_ERR(mixer_res->mixer)) {
771 dev_err(dev, "failed to get clock 'mixer'\n");
772 return -ENODEV;
773 }
774
Marek Szyprowski04427ec2015-02-02 14:20:28 +0100775 mixer_res->hdmi = devm_clk_get(dev, "hdmi");
776 if (IS_ERR(mixer_res->hdmi)) {
777 dev_err(dev, "failed to get clock 'hdmi'\n");
778 return PTR_ERR(mixer_res->hdmi);
779 }
780
Sean Paul45517892014-01-30 16:19:05 -0500781 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
782 if (IS_ERR(mixer_res->sclk_hdmi)) {
783 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
784 return -ENODEV;
785 }
786 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
787 if (res == NULL) {
788 dev_err(dev, "get memory resource failed.\n");
789 return -ENXIO;
790 }
791
792 mixer_res->mixer_regs = devm_ioremap(dev, res->start,
793 resource_size(res));
794 if (mixer_res->mixer_regs == NULL) {
795 dev_err(dev, "register mapping failed.\n");
796 return -ENXIO;
797 }
798
799 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
800 if (res == NULL) {
801 dev_err(dev, "get interrupt resource failed.\n");
802 return -ENXIO;
803 }
804
805 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
806 0, "drm_mixer", mixer_ctx);
807 if (ret) {
808 dev_err(dev, "request interrupt failed.\n");
809 return ret;
810 }
811 mixer_res->irq = res->start;
812
813 return 0;
814}
815
816static int vp_resources_init(struct mixer_context *mixer_ctx)
817{
818 struct device *dev = &mixer_ctx->pdev->dev;
819 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
820 struct resource *res;
821
822 mixer_res->vp = devm_clk_get(dev, "vp");
823 if (IS_ERR(mixer_res->vp)) {
824 dev_err(dev, "failed to get clock 'vp'\n");
825 return -ENODEV;
826 }
Sean Paul45517892014-01-30 16:19:05 -0500827
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200828 if (mixer_ctx->has_sclk) {
829 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
830 if (IS_ERR(mixer_res->sclk_mixer)) {
831 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
832 return -ENODEV;
833 }
834 mixer_res->mout_mixer = devm_clk_get(dev, "mout_mixer");
835 if (IS_ERR(mixer_res->mout_mixer)) {
836 dev_err(dev, "failed to get clock 'mout_mixer'\n");
837 return -ENODEV;
838 }
839
840 if (mixer_res->sclk_hdmi && mixer_res->mout_mixer)
841 clk_set_parent(mixer_res->mout_mixer,
842 mixer_res->sclk_hdmi);
843 }
Sean Paul45517892014-01-30 16:19:05 -0500844
845 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
846 if (res == NULL) {
847 dev_err(dev, "get memory resource failed.\n");
848 return -ENXIO;
849 }
850
851 mixer_res->vp_regs = devm_ioremap(dev, res->start,
852 resource_size(res));
853 if (mixer_res->vp_regs == NULL) {
854 dev_err(dev, "register mapping failed.\n");
855 return -ENXIO;
856 }
857
858 return 0;
859}
860
Gustavo Padovan93bca242015-01-18 18:16:23 +0900861static int mixer_initialize(struct mixer_context *mixer_ctx,
Inki Daef37cd5e2014-05-09 14:25:20 +0900862 struct drm_device *drm_dev)
Sean Paul45517892014-01-30 16:19:05 -0500863{
864 int ret;
Inki Daef37cd5e2014-05-09 14:25:20 +0900865 struct exynos_drm_private *priv;
866 priv = drm_dev->dev_private;
Sean Paul45517892014-01-30 16:19:05 -0500867
Gustavo Padovaneb88e422014-11-26 16:43:27 -0200868 mixer_ctx->drm_dev = drm_dev;
Gustavo Padovan8a326ed2014-11-04 18:44:47 -0200869 mixer_ctx->pipe = priv->pipe++;
Sean Paul45517892014-01-30 16:19:05 -0500870
871 /* acquire resources: regs, irqs, clocks */
872 ret = mixer_resources_init(mixer_ctx);
873 if (ret) {
874 DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
875 return ret;
876 }
877
878 if (mixer_ctx->vp_enabled) {
879 /* acquire vp resources: regs, irqs, clocks */
880 ret = vp_resources_init(mixer_ctx);
881 if (ret) {
882 DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
883 return ret;
884 }
885 }
886
Joonyoung Shimeb7a3fc2015-07-02 21:49:39 +0900887 ret = drm_iommu_attach_device(drm_dev, mixer_ctx->dev);
Hyungwon Hwangfc2e0132015-06-22 19:05:04 +0900888 if (ret)
889 priv->pipe--;
Sean Paulf041b252014-01-30 16:19:15 -0500890
Hyungwon Hwangfc2e0132015-06-22 19:05:04 +0900891 return ret;
Sean Paul45517892014-01-30 16:19:05 -0500892}
893
Gustavo Padovan93bca242015-01-18 18:16:23 +0900894static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
Inki Dae1055b392012-10-19 17:37:35 +0900895{
Joonyoung Shimbf566082015-07-02 21:49:38 +0900896 drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Inki Dae1055b392012-10-19 17:37:35 +0900897}
898
Gustavo Padovan93bca242015-01-18 18:16:23 +0900899static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900900{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900901 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900902 struct mixer_resources *res = &mixer_ctx->mixer_res;
903
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200904 __set_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
905 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Sean Paulf041b252014-01-30 16:19:15 -0500906 return 0;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900907
908 /* enable vsync interrupt */
Andrzej Hajdafc0732482015-07-09 08:25:40 +0200909 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
910 mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900911
912 return 0;
913}
914
Gustavo Padovan93bca242015-01-18 18:16:23 +0900915static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900916{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900917 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900918 struct mixer_resources *res = &mixer_ctx->mixer_res;
919
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200920 __clear_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
921
922 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Andrzej Hajda947710c2015-07-09 08:25:41 +0200923 return;
Andrzej Hajda947710c2015-07-09 08:25:41 +0200924
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900925 /* disable vsync interrupt */
Andrzej Hajdafc0732482015-07-09 08:25:40 +0200926 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900927 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
928}
929
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900930static void mixer_update_plane(struct exynos_drm_crtc *crtc,
931 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900932{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900933 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900934
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900935 DRM_DEBUG_KMS("win: %d\n", plane->zpos);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900936
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200937 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Shirish Sdda90122013-01-23 22:03:18 -0500938 return;
Shirish Sdda90122013-01-23 22:03:18 -0500939
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900940 if (plane->zpos > 1 && mixer_ctx->vp_enabled)
941 vp_video_buffer(mixer_ctx, plane->zpos);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900942 else
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900943 mixer_graph_buffer(mixer_ctx, plane->zpos);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900944}
945
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900946static void mixer_disable_plane(struct exynos_drm_crtc *crtc,
947 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900948{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900949 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900950 struct mixer_resources *res = &mixer_ctx->mixer_res;
951 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900952
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900953 DRM_DEBUG_KMS("win: %d\n", plane->zpos);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900954
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200955 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Prathyush Kdb43fd12012-12-06 20:16:05 +0530956 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +0530957
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900958 spin_lock_irqsave(&res->reg_slock, flags);
959 mixer_vsync_set_update(mixer_ctx, false);
960
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900961 mixer_cfg_layer(mixer_ctx, plane->zpos, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900962
963 mixer_vsync_set_update(mixer_ctx, true);
964 spin_unlock_irqrestore(&res->reg_slock, flags);
965}
966
Gustavo Padovan93bca242015-01-18 18:16:23 +0900967static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
Rahul Sharma0ea68222013-01-15 08:11:06 -0500968{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900969 struct mixer_context *mixer_ctx = crtc->ctx;
Joonyoung Shim7c4c5582015-01-18 17:48:29 +0900970 int err;
Prathyush K8137a2e2012-12-06 20:16:01 +0530971
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200972 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Prathyush K6e95d5e2012-12-06 20:16:03 +0530973 return;
Prathyush K6e95d5e2012-12-06 20:16:03 +0530974
Gustavo Padovan93bca242015-01-18 18:16:23 +0900975 err = drm_vblank_get(mixer_ctx->drm_dev, mixer_ctx->pipe);
Joonyoung Shim7c4c5582015-01-18 17:48:29 +0900976 if (err < 0) {
977 DRM_DEBUG_KMS("failed to acquire vblank counter\n");
978 return;
979 }
Rahul Sharma5d39b9e2014-06-23 11:02:25 +0530980
Prathyush K6e95d5e2012-12-06 20:16:03 +0530981 atomic_set(&mixer_ctx->wait_vsync_event, 1);
982
983 /*
984 * wait for MIXER to signal VSYNC interrupt or return after
985 * timeout which is set to 50ms (refresh rate of 20).
986 */
987 if (!wait_event_timeout(mixer_ctx->wait_vsync_queue,
988 !atomic_read(&mixer_ctx->wait_vsync_event),
Daniel Vetterbfd83032013-12-11 11:34:41 +0100989 HZ/20))
Prathyush K8137a2e2012-12-06 20:16:01 +0530990 DRM_DEBUG_KMS("vblank wait timed out.\n");
Rahul Sharma5d39b9e2014-06-23 11:02:25 +0530991
Gustavo Padovan93bca242015-01-18 18:16:23 +0900992 drm_vblank_put(mixer_ctx->drm_dev, mixer_ctx->pipe);
Prathyush K8137a2e2012-12-06 20:16:01 +0530993}
994
Gustavo Padovan3cecda02015-06-01 12:04:55 -0300995static void mixer_enable(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +0530996{
Gustavo Padovan3cecda02015-06-01 12:04:55 -0300997 struct mixer_context *ctx = crtc->ctx;
Prathyush Kdb43fd12012-12-06 20:16:05 +0530998 struct mixer_resources *res = &ctx->mixer_res;
Gustavo Padovan38000db2015-06-03 17:17:16 -0300999 int ret;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301000
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001001 if (test_bit(MXR_BIT_POWERED, &ctx->flags))
Prathyush Kdb43fd12012-12-06 20:16:05 +05301002 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301003
Sean Paulaf65c802014-01-30 16:19:27 -05001004 pm_runtime_get_sync(ctx->dev);
1005
Gustavo Padovan38000db2015-06-03 17:17:16 -03001006 ret = clk_prepare_enable(res->mixer);
1007 if (ret < 0) {
1008 DRM_ERROR("Failed to prepare_enable the mixer clk [%d]\n", ret);
1009 return;
1010 }
1011 ret = clk_prepare_enable(res->hdmi);
1012 if (ret < 0) {
1013 DRM_ERROR("Failed to prepare_enable the hdmi clk [%d]\n", ret);
1014 return;
1015 }
Prathyush Kdb43fd12012-12-06 20:16:05 +05301016 if (ctx->vp_enabled) {
Gustavo Padovan38000db2015-06-03 17:17:16 -03001017 ret = clk_prepare_enable(res->vp);
1018 if (ret < 0) {
1019 DRM_ERROR("Failed to prepare_enable the vp clk [%d]\n",
1020 ret);
1021 return;
1022 }
1023 if (ctx->has_sclk) {
1024 ret = clk_prepare_enable(res->sclk_mixer);
1025 if (ret < 0) {
1026 DRM_ERROR("Failed to prepare_enable the " \
1027 "sclk_mixer clk [%d]\n",
1028 ret);
1029 return;
1030 }
1031 }
Prathyush Kdb43fd12012-12-06 20:16:05 +05301032 }
1033
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001034 set_bit(MXR_BIT_POWERED, &ctx->flags);
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301035
Rahul Sharmad74ed932014-06-23 11:02:24 +05301036 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
1037
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +02001038 if (test_bit(MXR_BIT_VSYNC, &ctx->flags)) {
Andrzej Hajdafc0732482015-07-09 08:25:40 +02001039 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +02001040 mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
1041 }
Prathyush Kdb43fd12012-12-06 20:16:05 +05301042 mixer_win_reset(ctx);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301043}
1044
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001045static void mixer_disable(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301046{
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001047 struct mixer_context *ctx = crtc->ctx;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301048 struct mixer_resources *res = &ctx->mixer_res;
Joonyoung Shimc329f662015-06-12 20:34:28 +09001049 int i;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301050
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001051 if (!test_bit(MXR_BIT_POWERED, &ctx->flags))
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301052 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301053
Rahul Sharma381be022014-06-23 11:02:22 +05301054 mixer_stop(ctx);
Tobias Jakobic0734fb2015-05-06 14:10:21 +02001055 mixer_regs_dump(ctx);
Joonyoung Shimc329f662015-06-12 20:34:28 +09001056
1057 for (i = 0; i < MIXER_WIN_NR; i++)
Gustavo Padovan1e1d1392015-08-03 14:39:36 +09001058 mixer_disable_plane(crtc, &ctx->planes[i]);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301059
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001060 clear_bit(MXR_BIT_POWERED, &ctx->flags);
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301061
Marek Szyprowski04427ec2015-02-02 14:20:28 +01001062 clk_disable_unprepare(res->hdmi);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301063 clk_disable_unprepare(res->mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301064 if (ctx->vp_enabled) {
Sean Paul0bfb1f82013-06-11 12:24:02 +05301065 clk_disable_unprepare(res->vp);
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001066 if (ctx->has_sclk)
1067 clk_disable_unprepare(res->sclk_mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301068 }
1069
Sean Paulaf65c802014-01-30 16:19:27 -05001070 pm_runtime_put_sync(ctx->dev);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301071}
1072
Sean Paulf041b252014-01-30 16:19:15 -05001073/* Only valid for Mixer version 16.0.33.0 */
1074int mixer_check_mode(struct drm_display_mode *mode)
1075{
1076 u32 w, h;
1077
1078 w = mode->hdisplay;
1079 h = mode->vdisplay;
1080
1081 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
1082 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1083 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1084
1085 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
1086 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1087 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1088 return 0;
1089
1090 return -EINVAL;
1091}
1092
Krzysztof Kozlowskif3aaf762015-05-07 09:04:45 +09001093static const struct exynos_drm_crtc_ops mixer_crtc_ops = {
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001094 .enable = mixer_enable,
1095 .disable = mixer_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001096 .enable_vblank = mixer_enable_vblank,
1097 .disable_vblank = mixer_disable_vblank,
Prathyush K8137a2e2012-12-06 20:16:01 +05301098 .wait_for_vblank = mixer_wait_for_vblank,
Gustavo Padovan9cc76102015-08-03 14:38:05 +09001099 .update_plane = mixer_update_plane,
1100 .disable_plane = mixer_disable_plane,
Sean Paulf041b252014-01-30 16:19:15 -05001101};
Rahul Sharma0ea68222013-01-15 08:11:06 -05001102
Rahul Sharmadef5e092013-06-19 18:21:08 +05301103static struct mixer_drv_data exynos5420_mxr_drv_data = {
1104 .version = MXR_VER_128_0_0_184,
1105 .is_vp_enabled = 0,
1106};
1107
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301108static struct mixer_drv_data exynos5250_mxr_drv_data = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301109 .version = MXR_VER_16_0_33_0,
1110 .is_vp_enabled = 0,
1111};
1112
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001113static struct mixer_drv_data exynos4212_mxr_drv_data = {
1114 .version = MXR_VER_0_0_0_16,
1115 .is_vp_enabled = 1,
1116};
1117
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301118static struct mixer_drv_data exynos4210_mxr_drv_data = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301119 .version = MXR_VER_0_0_0_16,
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301120 .is_vp_enabled = 1,
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001121 .has_sclk = 1,
Rahul Sharma1e123442012-10-04 20:48:51 +05301122};
1123
Krzysztof Kozlowskid6b16302015-05-02 00:56:36 +09001124static const struct platform_device_id mixer_driver_types[] = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301125 {
1126 .name = "s5p-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301127 .driver_data = (unsigned long)&exynos4210_mxr_drv_data,
Rahul Sharma1e123442012-10-04 20:48:51 +05301128 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301129 .name = "exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301130 .driver_data = (unsigned long)&exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301131 }, {
1132 /* end node */
1133 }
1134};
1135
1136static struct of_device_id mixer_match_types[] = {
1137 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001138 .compatible = "samsung,exynos4210-mixer",
1139 .data = &exynos4210_mxr_drv_data,
1140 }, {
1141 .compatible = "samsung,exynos4212-mixer",
1142 .data = &exynos4212_mxr_drv_data,
1143 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301144 .compatible = "samsung,exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301145 .data = &exynos5250_mxr_drv_data,
1146 }, {
1147 .compatible = "samsung,exynos5250-mixer",
1148 .data = &exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301149 }, {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301150 .compatible = "samsung,exynos5420-mixer",
1151 .data = &exynos5420_mxr_drv_data,
1152 }, {
Rahul Sharma1e123442012-10-04 20:48:51 +05301153 /* end node */
1154 }
1155};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001156MODULE_DEVICE_TABLE(of, mixer_match_types);
Rahul Sharma1e123442012-10-04 20:48:51 +05301157
Inki Daef37cd5e2014-05-09 14:25:20 +09001158static int mixer_bind(struct device *dev, struct device *manager, void *data)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001159{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001160 struct mixer_context *ctx = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09001161 struct drm_device *drm_dev = data;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001162 struct exynos_drm_plane *exynos_plane;
1163 enum drm_plane_type type;
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +09001164 unsigned int zpos;
1165 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001166
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001167 ret = mixer_initialize(ctx, drm_dev);
1168 if (ret)
1169 return ret;
1170
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001171 for (zpos = 0; zpos < MIXER_WIN_NR; zpos++) {
1172 type = (zpos == MIXER_DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY :
1173 DRM_PLANE_TYPE_OVERLAY;
1174 ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +09001175 1 << ctx->pipe, type, zpos);
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001176 if (ret)
1177 return ret;
1178 }
1179
1180 exynos_plane = &ctx->planes[MIXER_DEFAULT_WIN];
1181 ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
1182 ctx->pipe, EXYNOS_DISPLAY_TYPE_HDMI,
1183 &mixer_crtc_ops, ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001184 if (IS_ERR(ctx->crtc)) {
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001185 mixer_ctx_remove(ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001186 ret = PTR_ERR(ctx->crtc);
1187 goto free_ctx;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001188 }
1189
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001190 return 0;
Gustavo Padovan93bca242015-01-18 18:16:23 +09001191
1192free_ctx:
1193 devm_kfree(dev, ctx);
1194 return ret;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001195}
1196
1197static void mixer_unbind(struct device *dev, struct device *master, void *data)
1198{
1199 struct mixer_context *ctx = dev_get_drvdata(dev);
1200
Gustavo Padovan93bca242015-01-18 18:16:23 +09001201 mixer_ctx_remove(ctx);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001202}
1203
1204static const struct component_ops mixer_component_ops = {
1205 .bind = mixer_bind,
1206 .unbind = mixer_unbind,
1207};
1208
1209static int mixer_probe(struct platform_device *pdev)
1210{
1211 struct device *dev = &pdev->dev;
1212 struct mixer_drv_data *drv;
1213 struct mixer_context *ctx;
1214 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001215
Sean Paulf041b252014-01-30 16:19:15 -05001216 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1217 if (!ctx) {
1218 DRM_ERROR("failed to alloc mixer context.\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001219 return -ENOMEM;
Sean Paulf041b252014-01-30 16:19:15 -05001220 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001221
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301222 if (dev->of_node) {
1223 const struct of_device_id *match;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001224
Sachin Kamate436b092013-06-05 16:00:23 +09001225 match = of_match_node(mixer_match_types, dev->of_node);
Rahul Sharma2cdc53b2012-10-31 09:36:26 +05301226 drv = (struct mixer_drv_data *)match->data;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301227 } else {
1228 drv = (struct mixer_drv_data *)
1229 platform_get_device_id(pdev)->driver_data;
1230 }
1231
Sean Paul45517892014-01-30 16:19:05 -05001232 ctx->pdev = pdev;
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001233 ctx->dev = dev;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301234 ctx->vp_enabled = drv->is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001235 ctx->has_sclk = drv->has_sclk;
Rahul Sharma1e123442012-10-04 20:48:51 +05301236 ctx->mxr_ver = drv->version;
Daniel Vetter57ed0f72013-12-11 11:34:43 +01001237 init_waitqueue_head(&ctx->wait_vsync_queue);
Prathyush K6e95d5e2012-12-06 20:16:03 +05301238 atomic_set(&ctx->wait_vsync_event, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001239
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001240 platform_set_drvdata(pdev, ctx);
Inki Daedf5225b2014-05-29 18:28:02 +09001241
Inki Daedf5225b2014-05-29 18:28:02 +09001242 ret = component_add(&pdev->dev, &mixer_component_ops);
Andrzej Hajda86650402015-06-11 23:23:37 +09001243 if (!ret)
1244 pm_runtime_enable(dev);
Inki Daedf5225b2014-05-29 18:28:02 +09001245
1246 return ret;
Inki Daef37cd5e2014-05-09 14:25:20 +09001247}
1248
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001249static int mixer_remove(struct platform_device *pdev)
1250{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001251 pm_runtime_disable(&pdev->dev);
1252
Inki Daedf5225b2014-05-29 18:28:02 +09001253 component_del(&pdev->dev, &mixer_component_ops);
Inki Daedf5225b2014-05-29 18:28:02 +09001254
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001255 return 0;
1256}
1257
1258struct platform_driver mixer_driver = {
1259 .driver = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301260 .name = "exynos-mixer",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001261 .owner = THIS_MODULE,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301262 .of_match_table = mixer_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001263 },
1264 .probe = mixer_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001265 .remove = mixer_remove,
Rahul Sharma1e123442012-10-04 20:48:51 +05301266 .id_table = mixer_driver_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001267};