blob: 1e8ce9ee039bd6f8e7945e29ce5337eeaf5673a4 [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
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090047struct mixer_resources {
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090048 int irq;
49 void __iomem *mixer_regs;
50 void __iomem *vp_regs;
51 spinlock_t reg_slock;
52 struct clk *mixer;
53 struct clk *vp;
Marek Szyprowski04427ec2015-02-02 14:20:28 +010054 struct clk *hdmi;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090055 struct clk *sclk_mixer;
56 struct clk *sclk_hdmi;
Marek Szyprowskiff830c92014-07-01 10:10:07 +020057 struct clk *mout_mixer;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090058};
59
Rahul Sharma1e123442012-10-04 20:48:51 +053060enum mixer_version_id {
61 MXR_VER_0_0_0_16,
62 MXR_VER_16_0_33_0,
Rahul Sharmadef5e092013-06-19 18:21:08 +053063 MXR_VER_128_0_0_184,
Rahul Sharma1e123442012-10-04 20:48:51 +053064};
65
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090066struct mixer_context {
Sean Paul45517892014-01-30 16:19:05 -050067 struct platform_device *pdev;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090068 struct device *dev;
Inki Dae1055b392012-10-19 17:37:35 +090069 struct drm_device *drm_dev;
Gustavo Padovan93bca242015-01-18 18:16:23 +090070 struct exynos_drm_crtc *crtc;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +090071 struct exynos_drm_plane planes[MIXER_WIN_NR];
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090072 int pipe;
73 bool interlace;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090074 bool powered;
Rahul Sharma1b8e5742012-10-04 20:48:52 +053075 bool vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +020076 bool has_sclk;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090077 u32 int_en;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090078
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090079 struct mutex mixer_mutex;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090080 struct mixer_resources mixer_res;
Rahul Sharma1e123442012-10-04 20:48:51 +053081 enum mixer_version_id mxr_ver;
Prathyush K6e95d5e2012-12-06 20:16:03 +053082 wait_queue_head_t wait_vsync_queue;
83 atomic_t wait_vsync_event;
Rahul Sharma1e123442012-10-04 20:48:51 +053084};
85
86struct mixer_drv_data {
87 enum mixer_version_id version;
Rahul Sharma1b8e5742012-10-04 20:48:52 +053088 bool is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +020089 bool has_sclk;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090090};
91
Seung-Woo Kimd8408322011-12-21 17:39:39 +090092static const u8 filter_y_horiz_tap8[] = {
93 0, -1, -1, -1, -1, -1, -1, -1,
94 -1, -1, -1, -1, -1, 0, 0, 0,
95 0, 2, 4, 5, 6, 6, 6, 6,
96 6, 5, 5, 4, 3, 2, 1, 1,
97 0, -6, -12, -16, -18, -20, -21, -20,
98 -20, -18, -16, -13, -10, -8, -5, -2,
99 127, 126, 125, 121, 114, 107, 99, 89,
100 79, 68, 57, 46, 35, 25, 16, 8,
101};
102
103static const u8 filter_y_vert_tap4[] = {
104 0, -3, -6, -8, -8, -8, -8, -7,
105 -6, -5, -4, -3, -2, -1, -1, 0,
106 127, 126, 124, 118, 111, 102, 92, 81,
107 70, 59, 48, 37, 27, 19, 11, 5,
108 0, 5, 11, 19, 27, 37, 48, 59,
109 70, 81, 92, 102, 111, 118, 124, 126,
110 0, 0, -1, -1, -2, -3, -4, -5,
111 -6, -7, -8, -8, -8, -8, -6, -3,
112};
113
114static const u8 filter_cr_horiz_tap4[] = {
115 0, -3, -6, -8, -8, -8, -8, -7,
116 -6, -5, -4, -3, -2, -1, -1, 0,
117 127, 126, 124, 118, 111, 102, 92, 81,
118 70, 59, 48, 37, 27, 19, 11, 5,
119};
120
121static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
122{
123 return readl(res->vp_regs + reg_id);
124}
125
126static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
127 u32 val)
128{
129 writel(val, res->vp_regs + reg_id);
130}
131
132static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
133 u32 val, u32 mask)
134{
135 u32 old = vp_reg_read(res, reg_id);
136
137 val = (val & mask) | (old & ~mask);
138 writel(val, res->vp_regs + reg_id);
139}
140
141static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
142{
143 return readl(res->mixer_regs + reg_id);
144}
145
146static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
147 u32 val)
148{
149 writel(val, res->mixer_regs + reg_id);
150}
151
152static inline void mixer_reg_writemask(struct mixer_resources *res,
153 u32 reg_id, u32 val, u32 mask)
154{
155 u32 old = mixer_reg_read(res, reg_id);
156
157 val = (val & mask) | (old & ~mask);
158 writel(val, res->mixer_regs + reg_id);
159}
160
161static void mixer_regs_dump(struct mixer_context *ctx)
162{
163#define DUMPREG(reg_id) \
164do { \
165 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
166 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
167} while (0)
168
169 DUMPREG(MXR_STATUS);
170 DUMPREG(MXR_CFG);
171 DUMPREG(MXR_INT_EN);
172 DUMPREG(MXR_INT_STATUS);
173
174 DUMPREG(MXR_LAYER_CFG);
175 DUMPREG(MXR_VIDEO_CFG);
176
177 DUMPREG(MXR_GRAPHIC0_CFG);
178 DUMPREG(MXR_GRAPHIC0_BASE);
179 DUMPREG(MXR_GRAPHIC0_SPAN);
180 DUMPREG(MXR_GRAPHIC0_WH);
181 DUMPREG(MXR_GRAPHIC0_SXY);
182 DUMPREG(MXR_GRAPHIC0_DXY);
183
184 DUMPREG(MXR_GRAPHIC1_CFG);
185 DUMPREG(MXR_GRAPHIC1_BASE);
186 DUMPREG(MXR_GRAPHIC1_SPAN);
187 DUMPREG(MXR_GRAPHIC1_WH);
188 DUMPREG(MXR_GRAPHIC1_SXY);
189 DUMPREG(MXR_GRAPHIC1_DXY);
190#undef DUMPREG
191}
192
193static void vp_regs_dump(struct mixer_context *ctx)
194{
195#define DUMPREG(reg_id) \
196do { \
197 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
198 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
199} while (0)
200
201 DUMPREG(VP_ENABLE);
202 DUMPREG(VP_SRESET);
203 DUMPREG(VP_SHADOW_UPDATE);
204 DUMPREG(VP_FIELD_ID);
205 DUMPREG(VP_MODE);
206 DUMPREG(VP_IMG_SIZE_Y);
207 DUMPREG(VP_IMG_SIZE_C);
208 DUMPREG(VP_PER_RATE_CTRL);
209 DUMPREG(VP_TOP_Y_PTR);
210 DUMPREG(VP_BOT_Y_PTR);
211 DUMPREG(VP_TOP_C_PTR);
212 DUMPREG(VP_BOT_C_PTR);
213 DUMPREG(VP_ENDIAN_MODE);
214 DUMPREG(VP_SRC_H_POSITION);
215 DUMPREG(VP_SRC_V_POSITION);
216 DUMPREG(VP_SRC_WIDTH);
217 DUMPREG(VP_SRC_HEIGHT);
218 DUMPREG(VP_DST_H_POSITION);
219 DUMPREG(VP_DST_V_POSITION);
220 DUMPREG(VP_DST_WIDTH);
221 DUMPREG(VP_DST_HEIGHT);
222 DUMPREG(VP_H_RATIO);
223 DUMPREG(VP_V_RATIO);
224
225#undef DUMPREG
226}
227
228static inline void vp_filter_set(struct mixer_resources *res,
229 int reg_id, const u8 *data, unsigned int size)
230{
231 /* assure 4-byte align */
232 BUG_ON(size & 3);
233 for (; size; size -= 4, reg_id += 4, data += 4) {
234 u32 val = (data[0] << 24) | (data[1] << 16) |
235 (data[2] << 8) | data[3];
236 vp_reg_write(res, reg_id, val);
237 }
238}
239
240static void vp_default_filter(struct mixer_resources *res)
241{
242 vp_filter_set(res, VP_POLY8_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530243 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900244 vp_filter_set(res, VP_POLY4_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530245 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900246 vp_filter_set(res, VP_POLY4_C0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530247 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900248}
249
250static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
251{
252 struct mixer_resources *res = &ctx->mixer_res;
253
254 /* block update on vsync */
255 mixer_reg_writemask(res, MXR_STATUS, enable ?
256 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
257
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530258 if (ctx->vp_enabled)
259 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900260 VP_SHADOW_UPDATE_ENABLE : 0);
261}
262
263static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
264{
265 struct mixer_resources *res = &ctx->mixer_res;
266 u32 val;
267
268 /* choosing between interlace and progressive mode */
269 val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
Tobias Jakobi1e6d4592015-04-07 01:14:50 +0200270 MXR_CFG_SCAN_PROGRESSIVE);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900271
Rahul Sharmadef5e092013-06-19 18:21:08 +0530272 if (ctx->mxr_ver != MXR_VER_128_0_0_184) {
273 /* choosing between proper HD and SD mode */
274 if (height <= 480)
275 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
276 else if (height <= 576)
277 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
278 else if (height <= 720)
279 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
280 else if (height <= 1080)
281 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
282 else
283 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
284 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900285
286 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
287}
288
289static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
290{
291 struct mixer_resources *res = &ctx->mixer_res;
292 u32 val;
293
294 if (height == 480) {
295 val = MXR_CFG_RGB601_0_255;
296 } else if (height == 576) {
297 val = MXR_CFG_RGB601_0_255;
298 } else if (height == 720) {
299 val = MXR_CFG_RGB709_16_235;
300 mixer_reg_write(res, MXR_CM_COEFF_Y,
301 (1 << 30) | (94 << 20) | (314 << 10) |
302 (32 << 0));
303 mixer_reg_write(res, MXR_CM_COEFF_CB,
304 (972 << 20) | (851 << 10) | (225 << 0));
305 mixer_reg_write(res, MXR_CM_COEFF_CR,
306 (225 << 20) | (820 << 10) | (1004 << 0));
307 } else if (height == 1080) {
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 {
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 }
326
327 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
328}
329
330static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable)
331{
332 struct mixer_resources *res = &ctx->mixer_res;
333 u32 val = enable ? ~0 : 0;
334
335 switch (win) {
336 case 0:
337 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
338 break;
339 case 1:
340 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
341 break;
342 case 2:
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530343 if (ctx->vp_enabled) {
344 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
345 mixer_reg_writemask(res, MXR_CFG, val,
346 MXR_CFG_VP_ENABLE);
Joonyoung Shimf1e716d2014-07-25 19:59:10 +0900347
348 /* control blending of graphic layer 0 */
349 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(0), val,
350 MXR_GRP_CFG_BLEND_PRE_MUL |
351 MXR_GRP_CFG_PIXEL_BLEND_EN);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530352 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900353 break;
354 }
355}
356
357static void mixer_run(struct mixer_context *ctx)
358{
359 struct mixer_resources *res = &ctx->mixer_res;
360
361 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
362
363 mixer_regs_dump(ctx);
364}
365
Rahul Sharma381be022014-06-23 11:02:22 +0530366static void mixer_stop(struct mixer_context *ctx)
367{
368 struct mixer_resources *res = &ctx->mixer_res;
369 int timeout = 20;
370
371 mixer_reg_writemask(res, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
372
373 while (!(mixer_reg_read(res, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
374 --timeout)
375 usleep_range(10000, 12000);
376
377 mixer_regs_dump(ctx);
378}
379
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900380static void vp_video_buffer(struct mixer_context *ctx, int win)
381{
382 struct mixer_resources *res = &ctx->mixer_res;
383 unsigned long flags;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900384 struct exynos_drm_plane *plane;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900385 dma_addr_t luma_addr[2], chroma_addr[2];
386 bool tiled_mode = false;
387 bool crcb_mode = false;
388 u32 val;
389
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900390 plane = &ctx->planes[win];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900391
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900392 switch (plane->pixel_format) {
Ville Syrjälä363b06a2012-05-14 11:08:51 +0900393 case DRM_FORMAT_NV12:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900394 crcb_mode = false;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900395 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900396 default:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900397 DRM_ERROR("pixel format for vp is wrong [%d].\n",
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900398 plane->pixel_format);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900399 return;
400 }
401
Tobias Jakobifac8a5b2015-04-27 23:10:15 +0200402 luma_addr[0] = plane->dma_addr[0];
403 chroma_addr[0] = plane->dma_addr[1];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900404
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900405 if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900406 ctx->interlace = true;
407 if (tiled_mode) {
408 luma_addr[1] = luma_addr[0] + 0x40;
409 chroma_addr[1] = chroma_addr[0] + 0x40;
410 } else {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900411 luma_addr[1] = luma_addr[0] + plane->pitch;
412 chroma_addr[1] = chroma_addr[0] + plane->pitch;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900413 }
414 } else {
415 ctx->interlace = false;
416 luma_addr[1] = 0;
417 chroma_addr[1] = 0;
418 }
419
420 spin_lock_irqsave(&res->reg_slock, flags);
421 mixer_vsync_set_update(ctx, false);
422
423 /* interlace or progressive scan mode */
424 val = (ctx->interlace ? ~0 : 0);
425 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
426
427 /* setup format */
428 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
429 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
430 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
431
432 /* setting size of input image */
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900433 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(plane->pitch) |
434 VP_IMG_VSIZE(plane->fb_height));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900435 /* chroma height has to reduced by 2 to avoid chroma distorions */
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900436 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(plane->pitch) |
437 VP_IMG_VSIZE(plane->fb_height / 2));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900438
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900439 vp_reg_write(res, VP_SRC_WIDTH, plane->src_width);
440 vp_reg_write(res, VP_SRC_HEIGHT, plane->src_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900441 vp_reg_write(res, VP_SRC_H_POSITION,
Joonyoung Shimcb8a3db2015-04-07 15:59:38 +0900442 VP_SRC_H_POSITION_VAL(plane->src_x));
443 vp_reg_write(res, VP_SRC_V_POSITION, plane->src_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900444
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900445 vp_reg_write(res, VP_DST_WIDTH, plane->crtc_width);
446 vp_reg_write(res, VP_DST_H_POSITION, plane->crtc_x);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900447 if (ctx->interlace) {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900448 vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height / 2);
449 vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y / 2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900450 } else {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900451 vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height);
452 vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900453 }
454
Joonyoung Shim3cabaf72015-04-07 15:59:39 +0900455 vp_reg_write(res, VP_H_RATIO, plane->h_ratio);
456 vp_reg_write(res, VP_V_RATIO, plane->v_ratio);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900457
458 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
459
460 /* set buffer address to vp */
461 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
462 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
463 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
464 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
465
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900466 mixer_cfg_scan(ctx, plane->mode_height);
467 mixer_cfg_rgb_fmt(ctx, plane->mode_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900468 mixer_cfg_layer(ctx, win, true);
469 mixer_run(ctx);
470
471 mixer_vsync_set_update(ctx, true);
472 spin_unlock_irqrestore(&res->reg_slock, flags);
473
474 vp_regs_dump(ctx);
475}
476
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530477static void mixer_layer_update(struct mixer_context *ctx)
478{
479 struct mixer_resources *res = &ctx->mixer_res;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530480
Rahul Sharma5c0f4822014-06-23 11:02:23 +0530481 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530482}
483
Tobias Jakobi26110152015-04-07 01:14:52 +0200484static int mixer_setup_scale(const struct exynos_drm_plane *plane,
485 unsigned int *x_ratio, unsigned int *y_ratio)
486{
487 if (plane->crtc_width != plane->src_width) {
488 if (plane->crtc_width == 2 * plane->src_width)
489 *x_ratio = 1;
490 else
491 goto fail;
492 }
493
494 if (plane->crtc_height != plane->src_height) {
495 if (plane->crtc_height == 2 * plane->src_height)
496 *y_ratio = 1;
497 else
498 goto fail;
499 }
500
501 return 0;
502
503fail:
504 DRM_DEBUG_KMS("only 2x width/height scaling of plane supported\n");
505 return -ENOTSUPP;
506}
507
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900508static void mixer_graph_buffer(struct mixer_context *ctx, int win)
509{
510 struct mixer_resources *res = &ctx->mixer_res;
511 unsigned long flags;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900512 struct exynos_drm_plane *plane;
Tobias Jakobi26110152015-04-07 01:14:52 +0200513 unsigned int x_ratio = 0, y_ratio = 0;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900514 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900515 dma_addr_t dma_addr;
516 unsigned int fmt;
517 u32 val;
518
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900519 plane = &ctx->planes[win];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900520
521 #define RGB565 4
522 #define ARGB1555 5
523 #define ARGB4444 6
524 #define ARGB8888 7
525
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900526 switch (plane->bpp) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900527 case 16:
528 fmt = ARGB4444;
529 break;
530 case 32:
531 fmt = ARGB8888;
532 break;
533 default:
534 fmt = ARGB8888;
535 }
536
Tobias Jakobi26110152015-04-07 01:14:52 +0200537 /* check if mixer supports requested scaling setup */
538 if (mixer_setup_scale(plane, &x_ratio, &y_ratio))
539 return;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900540
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900541 dst_x_offset = plane->crtc_x;
542 dst_y_offset = plane->crtc_y;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900543
544 /* converting dma address base and source offset */
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900545 dma_addr = plane->dma_addr[0]
Joonyoung Shimcb8a3db2015-04-07 15:59:38 +0900546 + (plane->src_x * plane->bpp >> 3)
547 + (plane->src_y * plane->pitch);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900548 src_x_offset = 0;
549 src_y_offset = 0;
550
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900551 if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900552 ctx->interlace = true;
553 else
554 ctx->interlace = false;
555
556 spin_lock_irqsave(&res->reg_slock, flags);
557 mixer_vsync_set_update(ctx, false);
558
559 /* setup format */
560 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
561 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
562
563 /* setup geometry */
Daniel Stoneadacb222015-03-17 13:24:58 +0000564 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win),
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900565 plane->pitch / (plane->bpp >> 3));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900566
Rahul Sharmadef5e092013-06-19 18:21:08 +0530567 /* setup display size */
568 if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
569 win == MIXER_DEFAULT_WIN) {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900570 val = MXR_MXR_RES_HEIGHT(plane->mode_height);
571 val |= MXR_MXR_RES_WIDTH(plane->mode_width);
Rahul Sharmadef5e092013-06-19 18:21:08 +0530572 mixer_reg_write(res, MXR_RESOLUTION, val);
573 }
574
Tobias Jakobi26110152015-04-07 01:14:52 +0200575 val = MXR_GRP_WH_WIDTH(plane->src_width);
576 val |= MXR_GRP_WH_HEIGHT(plane->src_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900577 val |= MXR_GRP_WH_H_SCALE(x_ratio);
578 val |= MXR_GRP_WH_V_SCALE(y_ratio);
579 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
580
581 /* setup offsets in source image */
582 val = MXR_GRP_SXY_SX(src_x_offset);
583 val |= MXR_GRP_SXY_SY(src_y_offset);
584 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
585
586 /* setup offsets in display image */
587 val = MXR_GRP_DXY_DX(dst_x_offset);
588 val |= MXR_GRP_DXY_DY(dst_y_offset);
589 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
590
591 /* set buffer address to mixer */
592 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
593
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900594 mixer_cfg_scan(ctx, plane->mode_height);
595 mixer_cfg_rgb_fmt(ctx, plane->mode_height);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900596 mixer_cfg_layer(ctx, win, true);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530597
598 /* layer update mandatory for mixer 16.0.33.0 */
Rahul Sharmadef5e092013-06-19 18:21:08 +0530599 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
600 ctx->mxr_ver == MXR_VER_128_0_0_184)
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530601 mixer_layer_update(ctx);
602
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900603 mixer_run(ctx);
604
605 mixer_vsync_set_update(ctx, true);
606 spin_unlock_irqrestore(&res->reg_slock, flags);
607}
608
609static void vp_win_reset(struct mixer_context *ctx)
610{
611 struct mixer_resources *res = &ctx->mixer_res;
612 int tries = 100;
613
614 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
615 for (tries = 100; tries; --tries) {
616 /* waiting until VP_SRESET_PROCESSING is 0 */
617 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
618 break;
Sean Paul09760ea2013-01-14 17:03:20 -0500619 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900620 }
621 WARN(tries == 0, "failed to reset Video Processor\n");
622}
623
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900624static void mixer_win_reset(struct mixer_context *ctx)
625{
626 struct mixer_resources *res = &ctx->mixer_res;
627 unsigned long flags;
628 u32 val; /* value stored to register */
629
630 spin_lock_irqsave(&res->reg_slock, flags);
631 mixer_vsync_set_update(ctx, false);
632
633 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
634
635 /* set output in RGB888 mode */
636 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
637
638 /* 16 beat burst in DMA */
639 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
640 MXR_STATUS_BURST_MASK);
641
642 /* setting default layer priority: layer1 > layer0 > video
643 * because typical usage scenario would be
644 * layer1 - OSD
645 * layer0 - framebuffer
646 * video - video overlay
647 */
648 val = MXR_LAYER_CFG_GRP1_VAL(3);
649 val |= MXR_LAYER_CFG_GRP0_VAL(2);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530650 if (ctx->vp_enabled)
651 val |= MXR_LAYER_CFG_VP_VAL(1);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900652 mixer_reg_write(res, MXR_LAYER_CFG, val);
653
654 /* setting background color */
655 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
656 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
657 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
658
659 /* setting graphical layers */
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900660 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
661 val |= MXR_GRP_CFG_WIN_BLEND_EN;
662 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
663
Sean Paul0377f4e2013-04-25 15:13:26 -0400664 /* Don't blend layer 0 onto the mixer background */
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900665 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
Sean Paul0377f4e2013-04-25 15:13:26 -0400666
667 /* Blend layer 1 into layer 0 */
668 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
669 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900670 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
671
Seung-Woo Kim57366032012-05-15 17:22:08 +0900672 /* setting video layers */
673 val = MXR_GRP_CFG_ALPHA_VAL(0);
674 mixer_reg_write(res, MXR_VIDEO_CFG, val);
675
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530676 if (ctx->vp_enabled) {
677 /* configuration of Video Processor Registers */
678 vp_win_reset(ctx);
679 vp_default_filter(res);
680 }
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900681
682 /* disable all layers */
683 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
684 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530685 if (ctx->vp_enabled)
686 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900687
688 mixer_vsync_set_update(ctx, true);
689 spin_unlock_irqrestore(&res->reg_slock, flags);
690}
691
Sean Paul45517892014-01-30 16:19:05 -0500692static irqreturn_t mixer_irq_handler(int irq, void *arg)
693{
694 struct mixer_context *ctx = arg;
695 struct mixer_resources *res = &ctx->mixer_res;
696 u32 val, base, shadow;
697
698 spin_lock(&res->reg_slock);
699
700 /* read interrupt status for handling and clearing flags for VSYNC */
701 val = mixer_reg_read(res, MXR_INT_STATUS);
702
703 /* handling VSYNC */
704 if (val & MXR_INT_STATUS_VSYNC) {
705 /* interlace scan need to check shadow register */
706 if (ctx->interlace) {
707 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
708 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
709 if (base != shadow)
710 goto out;
711
712 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
713 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
714 if (base != shadow)
715 goto out;
716 }
717
718 drm_handle_vblank(ctx->drm_dev, ctx->pipe);
719 exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
720
721 /* set wait vsync event to zero and wake up queue. */
722 if (atomic_read(&ctx->wait_vsync_event)) {
723 atomic_set(&ctx->wait_vsync_event, 0);
724 wake_up(&ctx->wait_vsync_queue);
725 }
726 }
727
728out:
729 /* clear interrupts */
730 if (~val & MXR_INT_EN_VSYNC) {
731 /* vsync interrupt use different bit for read and clear */
732 val &= ~MXR_INT_EN_VSYNC;
733 val |= MXR_INT_CLEAR_VSYNC;
734 }
735 mixer_reg_write(res, MXR_INT_STATUS, val);
736
737 spin_unlock(&res->reg_slock);
738
739 return IRQ_HANDLED;
740}
741
742static int mixer_resources_init(struct mixer_context *mixer_ctx)
743{
744 struct device *dev = &mixer_ctx->pdev->dev;
745 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
746 struct resource *res;
747 int ret;
748
749 spin_lock_init(&mixer_res->reg_slock);
750
751 mixer_res->mixer = devm_clk_get(dev, "mixer");
752 if (IS_ERR(mixer_res->mixer)) {
753 dev_err(dev, "failed to get clock 'mixer'\n");
754 return -ENODEV;
755 }
756
Marek Szyprowski04427ec2015-02-02 14:20:28 +0100757 mixer_res->hdmi = devm_clk_get(dev, "hdmi");
758 if (IS_ERR(mixer_res->hdmi)) {
759 dev_err(dev, "failed to get clock 'hdmi'\n");
760 return PTR_ERR(mixer_res->hdmi);
761 }
762
Sean Paul45517892014-01-30 16:19:05 -0500763 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
764 if (IS_ERR(mixer_res->sclk_hdmi)) {
765 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
766 return -ENODEV;
767 }
768 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
769 if (res == NULL) {
770 dev_err(dev, "get memory resource failed.\n");
771 return -ENXIO;
772 }
773
774 mixer_res->mixer_regs = devm_ioremap(dev, res->start,
775 resource_size(res));
776 if (mixer_res->mixer_regs == NULL) {
777 dev_err(dev, "register mapping failed.\n");
778 return -ENXIO;
779 }
780
781 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
782 if (res == NULL) {
783 dev_err(dev, "get interrupt resource failed.\n");
784 return -ENXIO;
785 }
786
787 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
788 0, "drm_mixer", mixer_ctx);
789 if (ret) {
790 dev_err(dev, "request interrupt failed.\n");
791 return ret;
792 }
793 mixer_res->irq = res->start;
794
795 return 0;
796}
797
798static int vp_resources_init(struct mixer_context *mixer_ctx)
799{
800 struct device *dev = &mixer_ctx->pdev->dev;
801 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
802 struct resource *res;
803
804 mixer_res->vp = devm_clk_get(dev, "vp");
805 if (IS_ERR(mixer_res->vp)) {
806 dev_err(dev, "failed to get clock 'vp'\n");
807 return -ENODEV;
808 }
Sean Paul45517892014-01-30 16:19:05 -0500809
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200810 if (mixer_ctx->has_sclk) {
811 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
812 if (IS_ERR(mixer_res->sclk_mixer)) {
813 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
814 return -ENODEV;
815 }
816 mixer_res->mout_mixer = devm_clk_get(dev, "mout_mixer");
817 if (IS_ERR(mixer_res->mout_mixer)) {
818 dev_err(dev, "failed to get clock 'mout_mixer'\n");
819 return -ENODEV;
820 }
821
822 if (mixer_res->sclk_hdmi && mixer_res->mout_mixer)
823 clk_set_parent(mixer_res->mout_mixer,
824 mixer_res->sclk_hdmi);
825 }
Sean Paul45517892014-01-30 16:19:05 -0500826
827 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
828 if (res == NULL) {
829 dev_err(dev, "get memory resource failed.\n");
830 return -ENXIO;
831 }
832
833 mixer_res->vp_regs = devm_ioremap(dev, res->start,
834 resource_size(res));
835 if (mixer_res->vp_regs == NULL) {
836 dev_err(dev, "register mapping failed.\n");
837 return -ENXIO;
838 }
839
840 return 0;
841}
842
Gustavo Padovan93bca242015-01-18 18:16:23 +0900843static int mixer_initialize(struct mixer_context *mixer_ctx,
Inki Daef37cd5e2014-05-09 14:25:20 +0900844 struct drm_device *drm_dev)
Sean Paul45517892014-01-30 16:19:05 -0500845{
846 int ret;
Inki Daef37cd5e2014-05-09 14:25:20 +0900847 struct exynos_drm_private *priv;
848 priv = drm_dev->dev_private;
Sean Paul45517892014-01-30 16:19:05 -0500849
Gustavo Padovaneb88e422014-11-26 16:43:27 -0200850 mixer_ctx->drm_dev = drm_dev;
Gustavo Padovan8a326ed2014-11-04 18:44:47 -0200851 mixer_ctx->pipe = priv->pipe++;
Sean Paul45517892014-01-30 16:19:05 -0500852
853 /* acquire resources: regs, irqs, clocks */
854 ret = mixer_resources_init(mixer_ctx);
855 if (ret) {
856 DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
857 return ret;
858 }
859
860 if (mixer_ctx->vp_enabled) {
861 /* acquire vp resources: regs, irqs, clocks */
862 ret = vp_resources_init(mixer_ctx);
863 if (ret) {
864 DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
865 return ret;
866 }
867 }
868
Sean Paulf041b252014-01-30 16:19:15 -0500869 if (!is_drm_iommu_supported(mixer_ctx->drm_dev))
870 return 0;
871
872 return drm_iommu_attach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Sean Paul45517892014-01-30 16:19:05 -0500873}
874
Gustavo Padovan93bca242015-01-18 18:16:23 +0900875static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
Inki Dae1055b392012-10-19 17:37:35 +0900876{
Sean Paulf041b252014-01-30 16:19:15 -0500877 if (is_drm_iommu_supported(mixer_ctx->drm_dev))
878 drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Inki Dae1055b392012-10-19 17:37:35 +0900879}
880
Gustavo Padovan93bca242015-01-18 18:16:23 +0900881static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900882{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900883 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900884 struct mixer_resources *res = &mixer_ctx->mixer_res;
885
Sean Paulf041b252014-01-30 16:19:15 -0500886 if (!mixer_ctx->powered) {
887 mixer_ctx->int_en |= MXR_INT_EN_VSYNC;
888 return 0;
889 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900890
891 /* enable vsync interrupt */
892 mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
893 MXR_INT_EN_VSYNC);
894
895 return 0;
896}
897
Gustavo Padovan93bca242015-01-18 18:16:23 +0900898static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900899{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900900 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900901 struct mixer_resources *res = &mixer_ctx->mixer_res;
902
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900903 /* disable vsync interrupt */
904 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
905}
906
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +0900907static void mixer_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900908{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900909 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900910
YoungJun Chocbc4c332013-06-12 10:44:40 +0900911 DRM_DEBUG_KMS("win: %d\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900912
Shirish Sdda90122013-01-23 22:03:18 -0500913 mutex_lock(&mixer_ctx->mixer_mutex);
914 if (!mixer_ctx->powered) {
915 mutex_unlock(&mixer_ctx->mixer_mutex);
916 return;
917 }
918 mutex_unlock(&mixer_ctx->mixer_mutex);
919
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530920 if (win > 1 && mixer_ctx->vp_enabled)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900921 vp_video_buffer(mixer_ctx, win);
922 else
923 mixer_graph_buffer(mixer_ctx, win);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530924
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900925 mixer_ctx->planes[win].enabled = true;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900926}
927
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +0900928static void mixer_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900929{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900930 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900931 struct mixer_resources *res = &mixer_ctx->mixer_res;
932 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900933
YoungJun Chocbc4c332013-06-12 10:44:40 +0900934 DRM_DEBUG_KMS("win: %d\n", win);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900935
Prathyush Kdb43fd12012-12-06 20:16:05 +0530936 mutex_lock(&mixer_ctx->mixer_mutex);
937 if (!mixer_ctx->powered) {
938 mutex_unlock(&mixer_ctx->mixer_mutex);
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900939 mixer_ctx->planes[win].resume = false;
Prathyush Kdb43fd12012-12-06 20:16:05 +0530940 return;
941 }
942 mutex_unlock(&mixer_ctx->mixer_mutex);
943
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900944 spin_lock_irqsave(&res->reg_slock, flags);
945 mixer_vsync_set_update(mixer_ctx, false);
946
947 mixer_cfg_layer(mixer_ctx, win, false);
948
949 mixer_vsync_set_update(mixer_ctx, true);
950 spin_unlock_irqrestore(&res->reg_slock, flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530951
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900952 mixer_ctx->planes[win].enabled = false;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900953}
954
Gustavo Padovan93bca242015-01-18 18:16:23 +0900955static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
Rahul Sharma0ea68222013-01-15 08:11:06 -0500956{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900957 struct mixer_context *mixer_ctx = crtc->ctx;
Joonyoung Shim7c4c5582015-01-18 17:48:29 +0900958 int err;
Prathyush K8137a2e2012-12-06 20:16:01 +0530959
Prathyush K6e95d5e2012-12-06 20:16:03 +0530960 mutex_lock(&mixer_ctx->mixer_mutex);
961 if (!mixer_ctx->powered) {
962 mutex_unlock(&mixer_ctx->mixer_mutex);
963 return;
964 }
965 mutex_unlock(&mixer_ctx->mixer_mutex);
966
Gustavo Padovan93bca242015-01-18 18:16:23 +0900967 err = drm_vblank_get(mixer_ctx->drm_dev, mixer_ctx->pipe);
Joonyoung Shim7c4c5582015-01-18 17:48:29 +0900968 if (err < 0) {
969 DRM_DEBUG_KMS("failed to acquire vblank counter\n");
970 return;
971 }
Rahul Sharma5d39b9e2014-06-23 11:02:25 +0530972
Prathyush K6e95d5e2012-12-06 20:16:03 +0530973 atomic_set(&mixer_ctx->wait_vsync_event, 1);
974
975 /*
976 * wait for MIXER to signal VSYNC interrupt or return after
977 * timeout which is set to 50ms (refresh rate of 20).
978 */
979 if (!wait_event_timeout(mixer_ctx->wait_vsync_queue,
980 !atomic_read(&mixer_ctx->wait_vsync_event),
Daniel Vetterbfd83032013-12-11 11:34:41 +0100981 HZ/20))
Prathyush K8137a2e2012-12-06 20:16:01 +0530982 DRM_DEBUG_KMS("vblank wait timed out.\n");
Rahul Sharma5d39b9e2014-06-23 11:02:25 +0530983
Gustavo Padovan93bca242015-01-18 18:16:23 +0900984 drm_vblank_put(mixer_ctx->drm_dev, mixer_ctx->pipe);
Prathyush K8137a2e2012-12-06 20:16:01 +0530985}
986
Joonyoung Shim92dc7a02015-01-30 16:43:02 +0900987static void mixer_window_suspend(struct mixer_context *ctx)
Prathyush Kdb43fd12012-12-06 20:16:05 +0530988{
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900989 struct exynos_drm_plane *plane;
Prathyush Kdb43fd12012-12-06 20:16:05 +0530990 int i;
991
992 for (i = 0; i < MIXER_WIN_NR; i++) {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900993 plane = &ctx->planes[i];
994 plane->resume = plane->enabled;
Joonyoung Shim92dc7a02015-01-30 16:43:02 +0900995 mixer_win_disable(ctx->crtc, i);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530996 }
Joonyoung Shim92dc7a02015-01-30 16:43:02 +0900997 mixer_wait_for_vblank(ctx->crtc);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530998}
999
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001000static void mixer_window_resume(struct mixer_context *ctx)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301001{
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001002 struct exynos_drm_plane *plane;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301003 int i;
1004
1005 for (i = 0; i < MIXER_WIN_NR; i++) {
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001006 plane = &ctx->planes[i];
1007 plane->enabled = plane->resume;
1008 plane->resume = false;
1009 if (plane->enabled)
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001010 mixer_win_commit(ctx->crtc, i);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301011 }
1012}
1013
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001014static void mixer_poweron(struct mixer_context *ctx)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301015{
1016 struct mixer_resources *res = &ctx->mixer_res;
1017
Prathyush Kdb43fd12012-12-06 20:16:05 +05301018 mutex_lock(&ctx->mixer_mutex);
1019 if (ctx->powered) {
1020 mutex_unlock(&ctx->mixer_mutex);
1021 return;
1022 }
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301023
Prathyush Kdb43fd12012-12-06 20:16:05 +05301024 mutex_unlock(&ctx->mixer_mutex);
1025
Sean Paulaf65c802014-01-30 16:19:27 -05001026 pm_runtime_get_sync(ctx->dev);
1027
Sean Paul0bfb1f82013-06-11 12:24:02 +05301028 clk_prepare_enable(res->mixer);
Marek Szyprowski04427ec2015-02-02 14:20:28 +01001029 clk_prepare_enable(res->hdmi);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301030 if (ctx->vp_enabled) {
Sean Paul0bfb1f82013-06-11 12:24:02 +05301031 clk_prepare_enable(res->vp);
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001032 if (ctx->has_sclk)
1033 clk_prepare_enable(res->sclk_mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301034 }
1035
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301036 mutex_lock(&ctx->mixer_mutex);
1037 ctx->powered = true;
1038 mutex_unlock(&ctx->mixer_mutex);
1039
Rahul Sharmad74ed932014-06-23 11:02:24 +05301040 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
1041
Prathyush Kdb43fd12012-12-06 20:16:05 +05301042 mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
1043 mixer_win_reset(ctx);
1044
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001045 mixer_window_resume(ctx);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301046}
1047
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001048static void mixer_poweroff(struct mixer_context *ctx)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301049{
1050 struct mixer_resources *res = &ctx->mixer_res;
1051
Prathyush Kdb43fd12012-12-06 20:16:05 +05301052 mutex_lock(&ctx->mixer_mutex);
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301053 if (!ctx->powered) {
1054 mutex_unlock(&ctx->mixer_mutex);
1055 return;
1056 }
Prathyush Kdb43fd12012-12-06 20:16:05 +05301057 mutex_unlock(&ctx->mixer_mutex);
1058
Rahul Sharma381be022014-06-23 11:02:22 +05301059 mixer_stop(ctx);
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001060 mixer_window_suspend(ctx);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301061
1062 ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
1063
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301064 mutex_lock(&ctx->mixer_mutex);
1065 ctx->powered = false;
1066 mutex_unlock(&ctx->mixer_mutex);
1067
Marek Szyprowski04427ec2015-02-02 14:20:28 +01001068 clk_disable_unprepare(res->hdmi);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301069 clk_disable_unprepare(res->mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301070 if (ctx->vp_enabled) {
Sean Paul0bfb1f82013-06-11 12:24:02 +05301071 clk_disable_unprepare(res->vp);
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001072 if (ctx->has_sclk)
1073 clk_disable_unprepare(res->sclk_mixer);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301074 }
1075
Sean Paulaf65c802014-01-30 16:19:27 -05001076 pm_runtime_put_sync(ctx->dev);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301077}
1078
Gustavo Padovan93bca242015-01-18 18:16:23 +09001079static void mixer_dpms(struct exynos_drm_crtc *crtc, int mode)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301080{
Prathyush Kdb43fd12012-12-06 20:16:05 +05301081 switch (mode) {
1082 case DRM_MODE_DPMS_ON:
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001083 mixer_poweron(crtc->ctx);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301084 break;
1085 case DRM_MODE_DPMS_STANDBY:
1086 case DRM_MODE_DPMS_SUSPEND:
1087 case DRM_MODE_DPMS_OFF:
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001088 mixer_poweroff(crtc->ctx);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301089 break;
1090 default:
1091 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
1092 break;
1093 }
1094}
1095
Sean Paulf041b252014-01-30 16:19:15 -05001096/* Only valid for Mixer version 16.0.33.0 */
1097int mixer_check_mode(struct drm_display_mode *mode)
1098{
1099 u32 w, h;
1100
1101 w = mode->hdisplay;
1102 h = mode->vdisplay;
1103
1104 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
1105 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1106 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1107
1108 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
1109 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1110 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1111 return 0;
1112
1113 return -EINVAL;
1114}
1115
Gustavo Padovan93bca242015-01-18 18:16:23 +09001116static struct exynos_drm_crtc_ops mixer_crtc_ops = {
Sean Paulf041b252014-01-30 16:19:15 -05001117 .dpms = mixer_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001118 .enable_vblank = mixer_enable_vblank,
1119 .disable_vblank = mixer_disable_vblank,
Prathyush K8137a2e2012-12-06 20:16:01 +05301120 .wait_for_vblank = mixer_wait_for_vblank,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001121 .win_commit = mixer_win_commit,
1122 .win_disable = mixer_win_disable,
Sean Paulf041b252014-01-30 16:19:15 -05001123};
Rahul Sharma0ea68222013-01-15 08:11:06 -05001124
Rahul Sharmadef5e092013-06-19 18:21:08 +05301125static struct mixer_drv_data exynos5420_mxr_drv_data = {
1126 .version = MXR_VER_128_0_0_184,
1127 .is_vp_enabled = 0,
1128};
1129
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301130static struct mixer_drv_data exynos5250_mxr_drv_data = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301131 .version = MXR_VER_16_0_33_0,
1132 .is_vp_enabled = 0,
1133};
1134
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001135static struct mixer_drv_data exynos4212_mxr_drv_data = {
1136 .version = MXR_VER_0_0_0_16,
1137 .is_vp_enabled = 1,
1138};
1139
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301140static struct mixer_drv_data exynos4210_mxr_drv_data = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301141 .version = MXR_VER_0_0_0_16,
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301142 .is_vp_enabled = 1,
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001143 .has_sclk = 1,
Rahul Sharma1e123442012-10-04 20:48:51 +05301144};
1145
1146static struct platform_device_id mixer_driver_types[] = {
1147 {
1148 .name = "s5p-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301149 .driver_data = (unsigned long)&exynos4210_mxr_drv_data,
Rahul Sharma1e123442012-10-04 20:48:51 +05301150 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301151 .name = "exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301152 .driver_data = (unsigned long)&exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301153 }, {
1154 /* end node */
1155 }
1156};
1157
1158static struct of_device_id mixer_match_types[] = {
1159 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001160 .compatible = "samsung,exynos4210-mixer",
1161 .data = &exynos4210_mxr_drv_data,
1162 }, {
1163 .compatible = "samsung,exynos4212-mixer",
1164 .data = &exynos4212_mxr_drv_data,
1165 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301166 .compatible = "samsung,exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301167 .data = &exynos5250_mxr_drv_data,
1168 }, {
1169 .compatible = "samsung,exynos5250-mixer",
1170 .data = &exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301171 }, {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301172 .compatible = "samsung,exynos5420-mixer",
1173 .data = &exynos5420_mxr_drv_data,
1174 }, {
Rahul Sharma1e123442012-10-04 20:48:51 +05301175 /* end node */
1176 }
1177};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001178MODULE_DEVICE_TABLE(of, mixer_match_types);
Rahul Sharma1e123442012-10-04 20:48:51 +05301179
Inki Daef37cd5e2014-05-09 14:25:20 +09001180static int mixer_bind(struct device *dev, struct device *manager, void *data)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001181{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001182 struct mixer_context *ctx = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09001183 struct drm_device *drm_dev = data;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001184 struct exynos_drm_plane *exynos_plane;
1185 enum drm_plane_type type;
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +09001186 unsigned int zpos;
1187 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001188
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001189 ret = mixer_initialize(ctx, drm_dev);
1190 if (ret)
1191 return ret;
1192
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001193 for (zpos = 0; zpos < MIXER_WIN_NR; zpos++) {
1194 type = (zpos == MIXER_DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY :
1195 DRM_PLANE_TYPE_OVERLAY;
1196 ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +09001197 1 << ctx->pipe, type, zpos);
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001198 if (ret)
1199 return ret;
1200 }
1201
1202 exynos_plane = &ctx->planes[MIXER_DEFAULT_WIN];
1203 ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
1204 ctx->pipe, EXYNOS_DISPLAY_TYPE_HDMI,
1205 &mixer_crtc_ops, ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001206 if (IS_ERR(ctx->crtc)) {
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001207 mixer_ctx_remove(ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001208 ret = PTR_ERR(ctx->crtc);
1209 goto free_ctx;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001210 }
1211
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001212 return 0;
Gustavo Padovan93bca242015-01-18 18:16:23 +09001213
1214free_ctx:
1215 devm_kfree(dev, ctx);
1216 return ret;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001217}
1218
1219static void mixer_unbind(struct device *dev, struct device *master, void *data)
1220{
1221 struct mixer_context *ctx = dev_get_drvdata(dev);
1222
Gustavo Padovan93bca242015-01-18 18:16:23 +09001223 mixer_ctx_remove(ctx);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001224}
1225
1226static const struct component_ops mixer_component_ops = {
1227 .bind = mixer_bind,
1228 .unbind = mixer_unbind,
1229};
1230
1231static int mixer_probe(struct platform_device *pdev)
1232{
1233 struct device *dev = &pdev->dev;
1234 struct mixer_drv_data *drv;
1235 struct mixer_context *ctx;
1236 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001237
Sean Paulf041b252014-01-30 16:19:15 -05001238 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1239 if (!ctx) {
1240 DRM_ERROR("failed to alloc mixer context.\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001241 return -ENOMEM;
Sean Paulf041b252014-01-30 16:19:15 -05001242 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001243
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001244 mutex_init(&ctx->mixer_mutex);
1245
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301246 if (dev->of_node) {
1247 const struct of_device_id *match;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001248
Sachin Kamate436b092013-06-05 16:00:23 +09001249 match = of_match_node(mixer_match_types, dev->of_node);
Rahul Sharma2cdc53b2012-10-31 09:36:26 +05301250 drv = (struct mixer_drv_data *)match->data;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301251 } else {
1252 drv = (struct mixer_drv_data *)
1253 platform_get_device_id(pdev)->driver_data;
1254 }
1255
Sean Paul45517892014-01-30 16:19:05 -05001256 ctx->pdev = pdev;
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001257 ctx->dev = dev;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301258 ctx->vp_enabled = drv->is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001259 ctx->has_sclk = drv->has_sclk;
Rahul Sharma1e123442012-10-04 20:48:51 +05301260 ctx->mxr_ver = drv->version;
Daniel Vetter57ed0f72013-12-11 11:34:43 +01001261 init_waitqueue_head(&ctx->wait_vsync_queue);
Prathyush K6e95d5e2012-12-06 20:16:03 +05301262 atomic_set(&ctx->wait_vsync_event, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001263
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001264 platform_set_drvdata(pdev, ctx);
Inki Daedf5225b2014-05-29 18:28:02 +09001265
1266 ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
Gustavo Padovan5d1741a2014-11-05 19:51:35 -02001267 EXYNOS_DISPLAY_TYPE_HDMI);
Inki Daedf5225b2014-05-29 18:28:02 +09001268 if (ret)
1269 return ret;
1270
1271 ret = component_add(&pdev->dev, &mixer_component_ops);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001272 if (ret) {
Inki Daedf5225b2014-05-29 18:28:02 +09001273 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001274 return ret;
1275 }
1276
1277 pm_runtime_enable(dev);
Inki Daedf5225b2014-05-29 18:28:02 +09001278
1279 return ret;
Inki Daef37cd5e2014-05-09 14:25:20 +09001280}
1281
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001282static int mixer_remove(struct platform_device *pdev)
1283{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001284 pm_runtime_disable(&pdev->dev);
1285
Inki Daedf5225b2014-05-29 18:28:02 +09001286 component_del(&pdev->dev, &mixer_component_ops);
1287 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
1288
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001289 return 0;
1290}
1291
1292struct platform_driver mixer_driver = {
1293 .driver = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301294 .name = "exynos-mixer",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001295 .owner = THIS_MODULE,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301296 .of_match_table = mixer_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001297 },
1298 .probe = mixer_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001299 .remove = mixer_remove,
Rahul Sharma1e123442012-10-04 20:48:51 +05301300 .id_table = mixer_driver_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001301};