blob: dfb35e2da4dbf8be1528ab47a2d6740786633560 [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"
Marek Szyprowski0488f502015-11-30 14:53:21 +010040#include "exynos_drm_fb.h"
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +090041#include "exynos_drm_plane.h"
Inki Dae1055b392012-10-19 17:37:35 +090042#include "exynos_drm_iommu.h"
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090043
Sean Paulf041b252014-01-30 16:19:15 -050044#define MIXER_WIN_NR 3
Marek Szyprowskifbbb1e12015-08-31 00:53:57 +090045#define VP_DEFAULT_WIN 2
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
Marek Szyprowskifbbb1e12015-08-31 00:53:57 +090077static const uint32_t mixer_formats[] = {
78 DRM_FORMAT_XRGB4444,
79 DRM_FORMAT_XRGB1555,
80 DRM_FORMAT_RGB565,
81 DRM_FORMAT_XRGB8888,
82 DRM_FORMAT_ARGB8888,
83};
84
85static const uint32_t vp_formats[] = {
86 DRM_FORMAT_NV12,
87 DRM_FORMAT_NV21,
88};
89
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090090struct mixer_context {
Sean Paul45517892014-01-30 16:19:05 -050091 struct platform_device *pdev;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090092 struct device *dev;
Inki Dae1055b392012-10-19 17:37:35 +090093 struct drm_device *drm_dev;
Gustavo Padovan93bca242015-01-18 18:16:23 +090094 struct exynos_drm_crtc *crtc;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +090095 struct exynos_drm_plane planes[MIXER_WIN_NR];
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090096 int pipe;
Andrzej Hajdaa44652e2015-07-09 08:25:42 +020097 unsigned long flags;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090098 bool interlace;
Rahul Sharma1b8e5742012-10-04 20:48:52 +053099 bool vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200100 bool has_sclk;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +0900101
102 struct mixer_resources mixer_res;
Rahul Sharma1e123442012-10-04 20:48:51 +0530103 enum mixer_version_id mxr_ver;
Prathyush K6e95d5e2012-12-06 20:16:03 +0530104 wait_queue_head_t wait_vsync_queue;
105 atomic_t wait_vsync_event;
Rahul Sharma1e123442012-10-04 20:48:51 +0530106};
107
108struct mixer_drv_data {
109 enum mixer_version_id version;
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530110 bool is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200111 bool has_sclk;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +0900112};
113
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +0100114static const struct exynos_drm_plane_config plane_configs[MIXER_WIN_NR] = {
115 {
116 .zpos = 0,
117 .type = DRM_PLANE_TYPE_PRIMARY,
118 .pixel_formats = mixer_formats,
119 .num_pixel_formats = ARRAY_SIZE(mixer_formats),
Marek Szyprowski6178d3d2015-11-30 14:53:26 +0100120 .capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE,
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +0100121 }, {
122 .zpos = 1,
123 .type = DRM_PLANE_TYPE_CURSOR,
124 .pixel_formats = mixer_formats,
125 .num_pixel_formats = ARRAY_SIZE(mixer_formats),
Marek Szyprowski6178d3d2015-11-30 14:53:26 +0100126 .capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE,
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +0100127 }, {
128 .zpos = 2,
129 .type = DRM_PLANE_TYPE_OVERLAY,
130 .pixel_formats = vp_formats,
131 .num_pixel_formats = ARRAY_SIZE(vp_formats),
Marek Szyprowski6178d3d2015-11-30 14:53:26 +0100132 .capabilities = EXYNOS_DRM_PLANE_CAP_SCALE,
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +0100133 },
134};
135
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900136static const u8 filter_y_horiz_tap8[] = {
137 0, -1, -1, -1, -1, -1, -1, -1,
138 -1, -1, -1, -1, -1, 0, 0, 0,
139 0, 2, 4, 5, 6, 6, 6, 6,
140 6, 5, 5, 4, 3, 2, 1, 1,
141 0, -6, -12, -16, -18, -20, -21, -20,
142 -20, -18, -16, -13, -10, -8, -5, -2,
143 127, 126, 125, 121, 114, 107, 99, 89,
144 79, 68, 57, 46, 35, 25, 16, 8,
145};
146
147static const u8 filter_y_vert_tap4[] = {
148 0, -3, -6, -8, -8, -8, -8, -7,
149 -6, -5, -4, -3, -2, -1, -1, 0,
150 127, 126, 124, 118, 111, 102, 92, 81,
151 70, 59, 48, 37, 27, 19, 11, 5,
152 0, 5, 11, 19, 27, 37, 48, 59,
153 70, 81, 92, 102, 111, 118, 124, 126,
154 0, 0, -1, -1, -2, -3, -4, -5,
155 -6, -7, -8, -8, -8, -8, -6, -3,
156};
157
158static const u8 filter_cr_horiz_tap4[] = {
159 0, -3, -6, -8, -8, -8, -8, -7,
160 -6, -5, -4, -3, -2, -1, -1, 0,
161 127, 126, 124, 118, 111, 102, 92, 81,
162 70, 59, 48, 37, 27, 19, 11, 5,
163};
164
165static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
166{
167 return readl(res->vp_regs + reg_id);
168}
169
170static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
171 u32 val)
172{
173 writel(val, res->vp_regs + reg_id);
174}
175
176static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
177 u32 val, u32 mask)
178{
179 u32 old = vp_reg_read(res, reg_id);
180
181 val = (val & mask) | (old & ~mask);
182 writel(val, res->vp_regs + reg_id);
183}
184
185static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
186{
187 return readl(res->mixer_regs + reg_id);
188}
189
190static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
191 u32 val)
192{
193 writel(val, res->mixer_regs + reg_id);
194}
195
196static inline void mixer_reg_writemask(struct mixer_resources *res,
197 u32 reg_id, u32 val, u32 mask)
198{
199 u32 old = mixer_reg_read(res, reg_id);
200
201 val = (val & mask) | (old & ~mask);
202 writel(val, res->mixer_regs + reg_id);
203}
204
205static void mixer_regs_dump(struct mixer_context *ctx)
206{
207#define DUMPREG(reg_id) \
208do { \
209 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
210 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
211} while (0)
212
213 DUMPREG(MXR_STATUS);
214 DUMPREG(MXR_CFG);
215 DUMPREG(MXR_INT_EN);
216 DUMPREG(MXR_INT_STATUS);
217
218 DUMPREG(MXR_LAYER_CFG);
219 DUMPREG(MXR_VIDEO_CFG);
220
221 DUMPREG(MXR_GRAPHIC0_CFG);
222 DUMPREG(MXR_GRAPHIC0_BASE);
223 DUMPREG(MXR_GRAPHIC0_SPAN);
224 DUMPREG(MXR_GRAPHIC0_WH);
225 DUMPREG(MXR_GRAPHIC0_SXY);
226 DUMPREG(MXR_GRAPHIC0_DXY);
227
228 DUMPREG(MXR_GRAPHIC1_CFG);
229 DUMPREG(MXR_GRAPHIC1_BASE);
230 DUMPREG(MXR_GRAPHIC1_SPAN);
231 DUMPREG(MXR_GRAPHIC1_WH);
232 DUMPREG(MXR_GRAPHIC1_SXY);
233 DUMPREG(MXR_GRAPHIC1_DXY);
234#undef DUMPREG
235}
236
237static void vp_regs_dump(struct mixer_context *ctx)
238{
239#define DUMPREG(reg_id) \
240do { \
241 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
242 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
243} while (0)
244
245 DUMPREG(VP_ENABLE);
246 DUMPREG(VP_SRESET);
247 DUMPREG(VP_SHADOW_UPDATE);
248 DUMPREG(VP_FIELD_ID);
249 DUMPREG(VP_MODE);
250 DUMPREG(VP_IMG_SIZE_Y);
251 DUMPREG(VP_IMG_SIZE_C);
252 DUMPREG(VP_PER_RATE_CTRL);
253 DUMPREG(VP_TOP_Y_PTR);
254 DUMPREG(VP_BOT_Y_PTR);
255 DUMPREG(VP_TOP_C_PTR);
256 DUMPREG(VP_BOT_C_PTR);
257 DUMPREG(VP_ENDIAN_MODE);
258 DUMPREG(VP_SRC_H_POSITION);
259 DUMPREG(VP_SRC_V_POSITION);
260 DUMPREG(VP_SRC_WIDTH);
261 DUMPREG(VP_SRC_HEIGHT);
262 DUMPREG(VP_DST_H_POSITION);
263 DUMPREG(VP_DST_V_POSITION);
264 DUMPREG(VP_DST_WIDTH);
265 DUMPREG(VP_DST_HEIGHT);
266 DUMPREG(VP_H_RATIO);
267 DUMPREG(VP_V_RATIO);
268
269#undef DUMPREG
270}
271
272static inline void vp_filter_set(struct mixer_resources *res,
273 int reg_id, const u8 *data, unsigned int size)
274{
275 /* assure 4-byte align */
276 BUG_ON(size & 3);
277 for (; size; size -= 4, reg_id += 4, data += 4) {
278 u32 val = (data[0] << 24) | (data[1] << 16) |
279 (data[2] << 8) | data[3];
280 vp_reg_write(res, reg_id, val);
281 }
282}
283
284static void vp_default_filter(struct mixer_resources *res)
285{
286 vp_filter_set(res, VP_POLY8_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530287 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900288 vp_filter_set(res, VP_POLY4_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530289 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900290 vp_filter_set(res, VP_POLY4_C0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530291 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900292}
293
294static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
295{
296 struct mixer_resources *res = &ctx->mixer_res;
297
298 /* block update on vsync */
299 mixer_reg_writemask(res, MXR_STATUS, enable ?
300 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
301
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530302 if (ctx->vp_enabled)
303 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900304 VP_SHADOW_UPDATE_ENABLE : 0);
305}
306
307static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
308{
309 struct mixer_resources *res = &ctx->mixer_res;
310 u32 val;
311
312 /* choosing between interlace and progressive mode */
313 val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
Tobias Jakobi1e6d4592015-04-07 01:14:50 +0200314 MXR_CFG_SCAN_PROGRESSIVE);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900315
Rahul Sharmadef5e092013-06-19 18:21:08 +0530316 if (ctx->mxr_ver != MXR_VER_128_0_0_184) {
317 /* choosing between proper HD and SD mode */
318 if (height <= 480)
319 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
320 else if (height <= 576)
321 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
322 else if (height <= 720)
323 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
324 else if (height <= 1080)
325 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
326 else
327 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
328 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900329
330 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
331}
332
333static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
334{
335 struct mixer_resources *res = &ctx->mixer_res;
336 u32 val;
337
338 if (height == 480) {
339 val = MXR_CFG_RGB601_0_255;
340 } else if (height == 576) {
341 val = MXR_CFG_RGB601_0_255;
342 } else if (height == 720) {
343 val = MXR_CFG_RGB709_16_235;
344 mixer_reg_write(res, MXR_CM_COEFF_Y,
345 (1 << 30) | (94 << 20) | (314 << 10) |
346 (32 << 0));
347 mixer_reg_write(res, MXR_CM_COEFF_CB,
348 (972 << 20) | (851 << 10) | (225 << 0));
349 mixer_reg_write(res, MXR_CM_COEFF_CR,
350 (225 << 20) | (820 << 10) | (1004 << 0));
351 } else if (height == 1080) {
352 val = MXR_CFG_RGB709_16_235;
353 mixer_reg_write(res, MXR_CM_COEFF_Y,
354 (1 << 30) | (94 << 20) | (314 << 10) |
355 (32 << 0));
356 mixer_reg_write(res, MXR_CM_COEFF_CB,
357 (972 << 20) | (851 << 10) | (225 << 0));
358 mixer_reg_write(res, MXR_CM_COEFF_CR,
359 (225 << 20) | (820 << 10) | (1004 << 0));
360 } else {
361 val = MXR_CFG_RGB709_16_235;
362 mixer_reg_write(res, MXR_CM_COEFF_Y,
363 (1 << 30) | (94 << 20) | (314 << 10) |
364 (32 << 0));
365 mixer_reg_write(res, MXR_CM_COEFF_CB,
366 (972 << 20) | (851 << 10) | (225 << 0));
367 mixer_reg_write(res, MXR_CM_COEFF_CR,
368 (225 << 20) | (820 << 10) | (1004 << 0));
369 }
370
371 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
372}
373
Tobias Jakobi5b1d5bc2015-05-06 14:10:22 +0200374static void mixer_cfg_layer(struct mixer_context *ctx, unsigned int win,
375 bool enable)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900376{
377 struct mixer_resources *res = &ctx->mixer_res;
378 u32 val = enable ? ~0 : 0;
379
380 switch (win) {
381 case 0:
382 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
383 break;
384 case 1:
385 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
386 break;
387 case 2:
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530388 if (ctx->vp_enabled) {
389 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
390 mixer_reg_writemask(res, MXR_CFG, val,
391 MXR_CFG_VP_ENABLE);
Joonyoung Shimf1e716d2014-07-25 19:59:10 +0900392
393 /* control blending of graphic layer 0 */
394 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(0), val,
395 MXR_GRP_CFG_BLEND_PRE_MUL |
396 MXR_GRP_CFG_PIXEL_BLEND_EN);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530397 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900398 break;
399 }
400}
401
402static void mixer_run(struct mixer_context *ctx)
403{
404 struct mixer_resources *res = &ctx->mixer_res;
405
406 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900407}
408
Rahul Sharma381be022014-06-23 11:02:22 +0530409static void mixer_stop(struct mixer_context *ctx)
410{
411 struct mixer_resources *res = &ctx->mixer_res;
412 int timeout = 20;
413
414 mixer_reg_writemask(res, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
415
416 while (!(mixer_reg_read(res, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
417 --timeout)
418 usleep_range(10000, 12000);
Rahul Sharma381be022014-06-23 11:02:22 +0530419}
420
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900421static void vp_video_buffer(struct mixer_context *ctx,
422 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900423{
Marek Szyprowski0114f402015-11-30 14:53:22 +0100424 struct exynos_drm_plane_state *state =
425 to_exynos_plane_state(plane->base.state);
Marek Szyprowski2ee35d82015-11-30 14:53:23 +0100426 struct drm_display_mode *mode = &state->base.crtc->state->adjusted_mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900427 struct mixer_resources *res = &ctx->mixer_res;
Marek Szyprowski0114f402015-11-30 14:53:22 +0100428 struct drm_framebuffer *fb = state->base.fb;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900429 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900430 dma_addr_t luma_addr[2], chroma_addr[2];
431 bool tiled_mode = false;
432 bool crcb_mode = false;
433 u32 val;
434
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900435 switch (fb->pixel_format) {
Ville Syrjälä363b06a2012-05-14 11:08:51 +0900436 case DRM_FORMAT_NV12:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900437 crcb_mode = false;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900438 break;
Tobias Jakobi8f2590f2015-04-27 23:10:16 +0200439 case DRM_FORMAT_NV21:
440 crcb_mode = true;
441 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900442 default:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900443 DRM_ERROR("pixel format for vp is wrong [%d].\n",
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900444 fb->pixel_format);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900445 return;
446 }
447
Marek Szyprowski0488f502015-11-30 14:53:21 +0100448 luma_addr[0] = exynos_drm_fb_dma_addr(fb, 0);
449 chroma_addr[0] = exynos_drm_fb_dma_addr(fb, 1);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900450
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900451 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900452 ctx->interlace = true;
453 if (tiled_mode) {
454 luma_addr[1] = luma_addr[0] + 0x40;
455 chroma_addr[1] = chroma_addr[0] + 0x40;
456 } else {
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900457 luma_addr[1] = luma_addr[0] + fb->pitches[0];
458 chroma_addr[1] = chroma_addr[0] + fb->pitches[0];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900459 }
460 } else {
461 ctx->interlace = false;
462 luma_addr[1] = 0;
463 chroma_addr[1] = 0;
464 }
465
466 spin_lock_irqsave(&res->reg_slock, flags);
467 mixer_vsync_set_update(ctx, false);
468
469 /* interlace or progressive scan mode */
470 val = (ctx->interlace ? ~0 : 0);
471 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
472
473 /* setup format */
474 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
475 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
476 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
477
478 /* setting size of input image */
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900479 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(fb->pitches[0]) |
480 VP_IMG_VSIZE(fb->height));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900481 /* chroma height has to reduced by 2 to avoid chroma distorions */
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900482 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(fb->pitches[0]) |
483 VP_IMG_VSIZE(fb->height / 2));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900484
Marek Szyprowski0114f402015-11-30 14:53:22 +0100485 vp_reg_write(res, VP_SRC_WIDTH, state->src.w);
486 vp_reg_write(res, VP_SRC_HEIGHT, state->src.h);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900487 vp_reg_write(res, VP_SRC_H_POSITION,
Marek Szyprowski0114f402015-11-30 14:53:22 +0100488 VP_SRC_H_POSITION_VAL(state->src.x));
489 vp_reg_write(res, VP_SRC_V_POSITION, state->src.y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900490
Marek Szyprowski0114f402015-11-30 14:53:22 +0100491 vp_reg_write(res, VP_DST_WIDTH, state->crtc.w);
492 vp_reg_write(res, VP_DST_H_POSITION, state->crtc.x);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900493 if (ctx->interlace) {
Marek Szyprowski0114f402015-11-30 14:53:22 +0100494 vp_reg_write(res, VP_DST_HEIGHT, state->crtc.h / 2);
495 vp_reg_write(res, VP_DST_V_POSITION, state->crtc.y / 2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900496 } else {
Marek Szyprowski0114f402015-11-30 14:53:22 +0100497 vp_reg_write(res, VP_DST_HEIGHT, state->crtc.h);
498 vp_reg_write(res, VP_DST_V_POSITION, state->crtc.y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900499 }
500
Marek Szyprowski0114f402015-11-30 14:53:22 +0100501 vp_reg_write(res, VP_H_RATIO, state->h_ratio);
502 vp_reg_write(res, VP_V_RATIO, state->v_ratio);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900503
504 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
505
506 /* set buffer address to vp */
507 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
508 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
509 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
510 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
511
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900512 mixer_cfg_scan(ctx, mode->vdisplay);
513 mixer_cfg_rgb_fmt(ctx, mode->vdisplay);
514 mixer_cfg_layer(ctx, plane->zpos, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900515 mixer_run(ctx);
516
517 mixer_vsync_set_update(ctx, true);
518 spin_unlock_irqrestore(&res->reg_slock, flags);
519
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200520 mixer_regs_dump(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900521 vp_regs_dump(ctx);
522}
523
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530524static void mixer_layer_update(struct mixer_context *ctx)
525{
526 struct mixer_resources *res = &ctx->mixer_res;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530527
Rahul Sharma5c0f4822014-06-23 11:02:23 +0530528 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530529}
530
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900531static void mixer_graph_buffer(struct mixer_context *ctx,
532 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900533{
Marek Szyprowski0114f402015-11-30 14:53:22 +0100534 struct exynos_drm_plane_state *state =
535 to_exynos_plane_state(plane->base.state);
Marek Szyprowski2ee35d82015-11-30 14:53:23 +0100536 struct drm_display_mode *mode = &state->base.crtc->state->adjusted_mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900537 struct mixer_resources *res = &ctx->mixer_res;
Marek Szyprowski0114f402015-11-30 14:53:22 +0100538 struct drm_framebuffer *fb = state->base.fb;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900539 unsigned long flags;
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900540 unsigned int win = plane->zpos;
Tobias Jakobi26110152015-04-07 01:14:52 +0200541 unsigned int x_ratio = 0, y_ratio = 0;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900542 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900543 dma_addr_t dma_addr;
544 unsigned int fmt;
545 u32 val;
546
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900547 switch (fb->pixel_format) {
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200548 case DRM_FORMAT_XRGB4444:
549 fmt = MXR_FORMAT_ARGB4444;
550 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900551
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200552 case DRM_FORMAT_XRGB1555:
553 fmt = MXR_FORMAT_ARGB1555;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900554 break;
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200555
556 case DRM_FORMAT_RGB565:
557 fmt = MXR_FORMAT_RGB565;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900558 break;
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200559
560 case DRM_FORMAT_XRGB8888:
561 case DRM_FORMAT_ARGB8888:
562 fmt = MXR_FORMAT_ARGB8888;
563 break;
564
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900565 default:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200566 DRM_DEBUG_KMS("pixelformat unsupported by mixer\n");
567 return;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900568 }
569
Marek Szyprowskie463b062015-11-30 14:53:27 +0100570 /* ratio is already checked by common plane code */
571 x_ratio = state->h_ratio == (1 << 15);
572 y_ratio = state->v_ratio == (1 << 15);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900573
Marek Szyprowski0114f402015-11-30 14:53:22 +0100574 dst_x_offset = state->crtc.x;
575 dst_y_offset = state->crtc.y;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900576
577 /* converting dma address base and source offset */
Marek Szyprowski0488f502015-11-30 14:53:21 +0100578 dma_addr = exynos_drm_fb_dma_addr(fb, 0)
Marek Szyprowski0114f402015-11-30 14:53:22 +0100579 + (state->src.x * fb->bits_per_pixel >> 3)
580 + (state->src.y * fb->pitches[0]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900581 src_x_offset = 0;
582 src_y_offset = 0;
583
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900584 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900585 ctx->interlace = true;
586 else
587 ctx->interlace = false;
588
589 spin_lock_irqsave(&res->reg_slock, flags);
590 mixer_vsync_set_update(ctx, false);
591
592 /* setup format */
593 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
594 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
595
596 /* setup geometry */
Daniel Stoneadacb222015-03-17 13:24:58 +0000597 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win),
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900598 fb->pitches[0] / (fb->bits_per_pixel >> 3));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900599
Rahul Sharmadef5e092013-06-19 18:21:08 +0530600 /* setup display size */
601 if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
Gustavo Padovan5d3d0992015-10-12 22:07:48 +0900602 win == DEFAULT_WIN) {
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900603 val = MXR_MXR_RES_HEIGHT(mode->vdisplay);
604 val |= MXR_MXR_RES_WIDTH(mode->hdisplay);
Rahul Sharmadef5e092013-06-19 18:21:08 +0530605 mixer_reg_write(res, MXR_RESOLUTION, val);
606 }
607
Marek Szyprowski0114f402015-11-30 14:53:22 +0100608 val = MXR_GRP_WH_WIDTH(state->src.w);
609 val |= MXR_GRP_WH_HEIGHT(state->src.h);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900610 val |= MXR_GRP_WH_H_SCALE(x_ratio);
611 val |= MXR_GRP_WH_V_SCALE(y_ratio);
612 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
613
614 /* setup offsets in source image */
615 val = MXR_GRP_SXY_SX(src_x_offset);
616 val |= MXR_GRP_SXY_SY(src_y_offset);
617 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
618
619 /* setup offsets in display image */
620 val = MXR_GRP_DXY_DX(dst_x_offset);
621 val |= MXR_GRP_DXY_DY(dst_y_offset);
622 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
623
624 /* set buffer address to mixer */
625 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
626
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900627 mixer_cfg_scan(ctx, mode->vdisplay);
628 mixer_cfg_rgb_fmt(ctx, mode->vdisplay);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900629 mixer_cfg_layer(ctx, win, true);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530630
631 /* layer update mandatory for mixer 16.0.33.0 */
Rahul Sharmadef5e092013-06-19 18:21:08 +0530632 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
633 ctx->mxr_ver == MXR_VER_128_0_0_184)
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530634 mixer_layer_update(ctx);
635
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900636 mixer_run(ctx);
637
638 mixer_vsync_set_update(ctx, true);
639 spin_unlock_irqrestore(&res->reg_slock, flags);
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200640
641 mixer_regs_dump(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900642}
643
644static void vp_win_reset(struct mixer_context *ctx)
645{
646 struct mixer_resources *res = &ctx->mixer_res;
647 int tries = 100;
648
649 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
650 for (tries = 100; tries; --tries) {
651 /* waiting until VP_SRESET_PROCESSING is 0 */
652 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
653 break;
Tomasz Stanislawski02b3de42015-09-25 14:48:29 +0200654 mdelay(10);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900655 }
656 WARN(tries == 0, "failed to reset Video Processor\n");
657}
658
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900659static void mixer_win_reset(struct mixer_context *ctx)
660{
661 struct mixer_resources *res = &ctx->mixer_res;
662 unsigned long flags;
663 u32 val; /* value stored to register */
664
665 spin_lock_irqsave(&res->reg_slock, flags);
666 mixer_vsync_set_update(ctx, false);
667
668 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
669
670 /* set output in RGB888 mode */
671 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
672
673 /* 16 beat burst in DMA */
674 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
675 MXR_STATUS_BURST_MASK);
676
677 /* setting default layer priority: layer1 > layer0 > video
678 * because typical usage scenario would be
679 * layer1 - OSD
680 * layer0 - framebuffer
681 * video - video overlay
682 */
683 val = MXR_LAYER_CFG_GRP1_VAL(3);
684 val |= MXR_LAYER_CFG_GRP0_VAL(2);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530685 if (ctx->vp_enabled)
686 val |= MXR_LAYER_CFG_VP_VAL(1);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900687 mixer_reg_write(res, MXR_LAYER_CFG, val);
688
689 /* setting background color */
690 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
691 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
692 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
693
694 /* setting graphical layers */
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900695 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
696 val |= MXR_GRP_CFG_WIN_BLEND_EN;
697 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
698
Sean Paul0377f4e2013-04-25 15:13:26 -0400699 /* Don't blend layer 0 onto the mixer background */
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900700 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
Sean Paul0377f4e2013-04-25 15:13:26 -0400701
702 /* Blend layer 1 into layer 0 */
703 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
704 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900705 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
706
Seung-Woo Kim57366032012-05-15 17:22:08 +0900707 /* setting video layers */
708 val = MXR_GRP_CFG_ALPHA_VAL(0);
709 mixer_reg_write(res, MXR_VIDEO_CFG, val);
710
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530711 if (ctx->vp_enabled) {
712 /* configuration of Video Processor Registers */
713 vp_win_reset(ctx);
714 vp_default_filter(res);
715 }
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900716
717 /* disable all layers */
718 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
719 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530720 if (ctx->vp_enabled)
721 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900722
723 mixer_vsync_set_update(ctx, true);
724 spin_unlock_irqrestore(&res->reg_slock, flags);
725}
726
Sean Paul45517892014-01-30 16:19:05 -0500727static irqreturn_t mixer_irq_handler(int irq, void *arg)
728{
729 struct mixer_context *ctx = arg;
730 struct mixer_resources *res = &ctx->mixer_res;
731 u32 val, base, shadow;
Gustavo Padovan822f6df2015-08-15 13:26:14 -0300732 int win;
Sean Paul45517892014-01-30 16:19:05 -0500733
734 spin_lock(&res->reg_slock);
735
736 /* read interrupt status for handling and clearing flags for VSYNC */
737 val = mixer_reg_read(res, MXR_INT_STATUS);
738
739 /* handling VSYNC */
740 if (val & MXR_INT_STATUS_VSYNC) {
Andrzej Hajda81a464d2015-07-09 10:07:53 +0200741 /* vsync interrupt use different bit for read and clear */
742 val |= MXR_INT_CLEAR_VSYNC;
743 val &= ~MXR_INT_STATUS_VSYNC;
744
Sean Paul45517892014-01-30 16:19:05 -0500745 /* interlace scan need to check shadow register */
746 if (ctx->interlace) {
747 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
748 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
749 if (base != shadow)
750 goto out;
751
752 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
753 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
754 if (base != shadow)
755 goto out;
756 }
757
Gustavo Padovaneafd5402015-07-16 12:23:32 -0300758 drm_crtc_handle_vblank(&ctx->crtc->base);
Gustavo Padovan822f6df2015-08-15 13:26:14 -0300759 for (win = 0 ; win < MIXER_WIN_NR ; win++) {
760 struct exynos_drm_plane *plane = &ctx->planes[win];
761
762 if (!plane->pending_fb)
763 continue;
764
765 exynos_drm_crtc_finish_update(ctx->crtc, plane);
766 }
Sean Paul45517892014-01-30 16:19:05 -0500767
768 /* set wait vsync event to zero and wake up queue. */
769 if (atomic_read(&ctx->wait_vsync_event)) {
770 atomic_set(&ctx->wait_vsync_event, 0);
771 wake_up(&ctx->wait_vsync_queue);
772 }
773 }
774
775out:
776 /* clear interrupts */
Sean Paul45517892014-01-30 16:19:05 -0500777 mixer_reg_write(res, MXR_INT_STATUS, val);
778
779 spin_unlock(&res->reg_slock);
780
781 return IRQ_HANDLED;
782}
783
784static int mixer_resources_init(struct mixer_context *mixer_ctx)
785{
786 struct device *dev = &mixer_ctx->pdev->dev;
787 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
788 struct resource *res;
789 int ret;
790
791 spin_lock_init(&mixer_res->reg_slock);
792
793 mixer_res->mixer = devm_clk_get(dev, "mixer");
794 if (IS_ERR(mixer_res->mixer)) {
795 dev_err(dev, "failed to get clock 'mixer'\n");
796 return -ENODEV;
797 }
798
Marek Szyprowski04427ec2015-02-02 14:20:28 +0100799 mixer_res->hdmi = devm_clk_get(dev, "hdmi");
800 if (IS_ERR(mixer_res->hdmi)) {
801 dev_err(dev, "failed to get clock 'hdmi'\n");
802 return PTR_ERR(mixer_res->hdmi);
803 }
804
Sean Paul45517892014-01-30 16:19:05 -0500805 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
806 if (IS_ERR(mixer_res->sclk_hdmi)) {
807 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
808 return -ENODEV;
809 }
810 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
811 if (res == NULL) {
812 dev_err(dev, "get memory resource failed.\n");
813 return -ENXIO;
814 }
815
816 mixer_res->mixer_regs = devm_ioremap(dev, res->start,
817 resource_size(res));
818 if (mixer_res->mixer_regs == NULL) {
819 dev_err(dev, "register mapping failed.\n");
820 return -ENXIO;
821 }
822
823 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
824 if (res == NULL) {
825 dev_err(dev, "get interrupt resource failed.\n");
826 return -ENXIO;
827 }
828
829 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
830 0, "drm_mixer", mixer_ctx);
831 if (ret) {
832 dev_err(dev, "request interrupt failed.\n");
833 return ret;
834 }
835 mixer_res->irq = res->start;
836
837 return 0;
838}
839
840static int vp_resources_init(struct mixer_context *mixer_ctx)
841{
842 struct device *dev = &mixer_ctx->pdev->dev;
843 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
844 struct resource *res;
845
846 mixer_res->vp = devm_clk_get(dev, "vp");
847 if (IS_ERR(mixer_res->vp)) {
848 dev_err(dev, "failed to get clock 'vp'\n");
849 return -ENODEV;
850 }
Sean Paul45517892014-01-30 16:19:05 -0500851
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200852 if (mixer_ctx->has_sclk) {
853 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
854 if (IS_ERR(mixer_res->sclk_mixer)) {
855 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
856 return -ENODEV;
857 }
858 mixer_res->mout_mixer = devm_clk_get(dev, "mout_mixer");
859 if (IS_ERR(mixer_res->mout_mixer)) {
860 dev_err(dev, "failed to get clock 'mout_mixer'\n");
861 return -ENODEV;
862 }
863
864 if (mixer_res->sclk_hdmi && mixer_res->mout_mixer)
865 clk_set_parent(mixer_res->mout_mixer,
866 mixer_res->sclk_hdmi);
867 }
Sean Paul45517892014-01-30 16:19:05 -0500868
869 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
870 if (res == NULL) {
871 dev_err(dev, "get memory resource failed.\n");
872 return -ENXIO;
873 }
874
875 mixer_res->vp_regs = devm_ioremap(dev, res->start,
876 resource_size(res));
877 if (mixer_res->vp_regs == NULL) {
878 dev_err(dev, "register mapping failed.\n");
879 return -ENXIO;
880 }
881
882 return 0;
883}
884
Gustavo Padovan93bca242015-01-18 18:16:23 +0900885static int mixer_initialize(struct mixer_context *mixer_ctx,
Inki Daef37cd5e2014-05-09 14:25:20 +0900886 struct drm_device *drm_dev)
Sean Paul45517892014-01-30 16:19:05 -0500887{
888 int ret;
Inki Daef37cd5e2014-05-09 14:25:20 +0900889 struct exynos_drm_private *priv;
890 priv = drm_dev->dev_private;
Sean Paul45517892014-01-30 16:19:05 -0500891
Gustavo Padovaneb88e422014-11-26 16:43:27 -0200892 mixer_ctx->drm_dev = drm_dev;
Gustavo Padovan8a326ed2014-11-04 18:44:47 -0200893 mixer_ctx->pipe = priv->pipe++;
Sean Paul45517892014-01-30 16:19:05 -0500894
895 /* acquire resources: regs, irqs, clocks */
896 ret = mixer_resources_init(mixer_ctx);
897 if (ret) {
898 DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
899 return ret;
900 }
901
902 if (mixer_ctx->vp_enabled) {
903 /* acquire vp resources: regs, irqs, clocks */
904 ret = vp_resources_init(mixer_ctx);
905 if (ret) {
906 DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
907 return ret;
908 }
909 }
910
Joonyoung Shimeb7a3fc2015-07-02 21:49:39 +0900911 ret = drm_iommu_attach_device(drm_dev, mixer_ctx->dev);
Hyungwon Hwangfc2e0132015-06-22 19:05:04 +0900912 if (ret)
913 priv->pipe--;
Sean Paulf041b252014-01-30 16:19:15 -0500914
Hyungwon Hwangfc2e0132015-06-22 19:05:04 +0900915 return ret;
Sean Paul45517892014-01-30 16:19:05 -0500916}
917
Gustavo Padovan93bca242015-01-18 18:16:23 +0900918static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
Inki Dae1055b392012-10-19 17:37:35 +0900919{
Joonyoung Shimbf566082015-07-02 21:49:38 +0900920 drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Inki Dae1055b392012-10-19 17:37:35 +0900921}
922
Gustavo Padovan93bca242015-01-18 18:16:23 +0900923static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900924{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900925 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900926 struct mixer_resources *res = &mixer_ctx->mixer_res;
927
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200928 __set_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
929 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Sean Paulf041b252014-01-30 16:19:15 -0500930 return 0;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900931
932 /* enable vsync interrupt */
Andrzej Hajdafc0732482015-07-09 08:25:40 +0200933 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
934 mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900935
936 return 0;
937}
938
Gustavo Padovan93bca242015-01-18 18:16:23 +0900939static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900940{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900941 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900942 struct mixer_resources *res = &mixer_ctx->mixer_res;
943
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200944 __clear_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
945
946 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Andrzej Hajda947710c2015-07-09 08:25:41 +0200947 return;
Andrzej Hajda947710c2015-07-09 08:25:41 +0200948
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900949 /* disable vsync interrupt */
Andrzej Hajdafc0732482015-07-09 08:25:40 +0200950 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900951 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
952}
953
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900954static void mixer_update_plane(struct exynos_drm_crtc *crtc,
955 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900956{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900957 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900958
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900959 DRM_DEBUG_KMS("win: %d\n", plane->zpos);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900960
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200961 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Shirish Sdda90122013-01-23 22:03:18 -0500962 return;
Shirish Sdda90122013-01-23 22:03:18 -0500963
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900964 if (plane->zpos > 1 && mixer_ctx->vp_enabled)
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900965 vp_video_buffer(mixer_ctx, plane);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900966 else
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900967 mixer_graph_buffer(mixer_ctx, plane);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900968}
969
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900970static void mixer_disable_plane(struct exynos_drm_crtc *crtc,
971 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900972{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900973 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900974 struct mixer_resources *res = &mixer_ctx->mixer_res;
975 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900976
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900977 DRM_DEBUG_KMS("win: %d\n", plane->zpos);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900978
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200979 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Prathyush Kdb43fd12012-12-06 20:16:05 +0530980 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +0530981
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900982 spin_lock_irqsave(&res->reg_slock, flags);
983 mixer_vsync_set_update(mixer_ctx, false);
984
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900985 mixer_cfg_layer(mixer_ctx, plane->zpos, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900986
987 mixer_vsync_set_update(mixer_ctx, true);
988 spin_unlock_irqrestore(&res->reg_slock, flags);
989}
990
Gustavo Padovan93bca242015-01-18 18:16:23 +0900991static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
Rahul Sharma0ea68222013-01-15 08:11:06 -0500992{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900993 struct mixer_context *mixer_ctx = crtc->ctx;
Joonyoung Shim7c4c5582015-01-18 17:48:29 +0900994 int err;
Prathyush K8137a2e2012-12-06 20:16:01 +0530995
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200996 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Prathyush K6e95d5e2012-12-06 20:16:03 +0530997 return;
Prathyush K6e95d5e2012-12-06 20:16:03 +0530998
Gustavo Padovan93bca242015-01-18 18:16:23 +0900999 err = drm_vblank_get(mixer_ctx->drm_dev, mixer_ctx->pipe);
Joonyoung Shim7c4c5582015-01-18 17:48:29 +09001000 if (err < 0) {
1001 DRM_DEBUG_KMS("failed to acquire vblank counter\n");
1002 return;
1003 }
Rahul Sharma5d39b9e2014-06-23 11:02:25 +05301004
Prathyush K6e95d5e2012-12-06 20:16:03 +05301005 atomic_set(&mixer_ctx->wait_vsync_event, 1);
1006
1007 /*
1008 * wait for MIXER to signal VSYNC interrupt or return after
1009 * timeout which is set to 50ms (refresh rate of 20).
1010 */
1011 if (!wait_event_timeout(mixer_ctx->wait_vsync_queue,
1012 !atomic_read(&mixer_ctx->wait_vsync_event),
Daniel Vetterbfd83032013-12-11 11:34:41 +01001013 HZ/20))
Prathyush K8137a2e2012-12-06 20:16:01 +05301014 DRM_DEBUG_KMS("vblank wait timed out.\n");
Rahul Sharma5d39b9e2014-06-23 11:02:25 +05301015
Gustavo Padovan93bca242015-01-18 18:16:23 +09001016 drm_vblank_put(mixer_ctx->drm_dev, mixer_ctx->pipe);
Prathyush K8137a2e2012-12-06 20:16:01 +05301017}
1018
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001019static void mixer_enable(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301020{
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001021 struct mixer_context *ctx = crtc->ctx;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301022 struct mixer_resources *res = &ctx->mixer_res;
1023
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001024 if (test_bit(MXR_BIT_POWERED, &ctx->flags))
Prathyush Kdb43fd12012-12-06 20:16:05 +05301025 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301026
Sean Paulaf65c802014-01-30 16:19:27 -05001027 pm_runtime_get_sync(ctx->dev);
1028
Rahul Sharmad74ed932014-06-23 11:02:24 +05301029 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
1030
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +02001031 if (test_bit(MXR_BIT_VSYNC, &ctx->flags)) {
Andrzej Hajdafc0732482015-07-09 08:25:40 +02001032 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +02001033 mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
1034 }
Prathyush Kdb43fd12012-12-06 20:16:05 +05301035 mixer_win_reset(ctx);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001036
1037 set_bit(MXR_BIT_POWERED, &ctx->flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301038}
1039
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001040static void mixer_disable(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301041{
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001042 struct mixer_context *ctx = crtc->ctx;
Joonyoung Shimc329f662015-06-12 20:34:28 +09001043 int i;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301044
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001045 if (!test_bit(MXR_BIT_POWERED, &ctx->flags))
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301046 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301047
Rahul Sharma381be022014-06-23 11:02:22 +05301048 mixer_stop(ctx);
Tobias Jakobic0734fb2015-05-06 14:10:21 +02001049 mixer_regs_dump(ctx);
Joonyoung Shimc329f662015-06-12 20:34:28 +09001050
1051 for (i = 0; i < MIXER_WIN_NR; i++)
Gustavo Padovan1e1d1392015-08-03 14:39:36 +09001052 mixer_disable_plane(crtc, &ctx->planes[i]);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301053
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001054 pm_runtime_put(ctx->dev);
1055
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001056 clear_bit(MXR_BIT_POWERED, &ctx->flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301057}
1058
Sean Paulf041b252014-01-30 16:19:15 -05001059/* Only valid for Mixer version 16.0.33.0 */
Andrzej Hajda3ae24362015-10-26 13:03:40 +01001060static int mixer_atomic_check(struct exynos_drm_crtc *crtc,
1061 struct drm_crtc_state *state)
Sean Paulf041b252014-01-30 16:19:15 -05001062{
Andrzej Hajda3ae24362015-10-26 13:03:40 +01001063 struct drm_display_mode *mode = &state->adjusted_mode;
Sean Paulf041b252014-01-30 16:19:15 -05001064 u32 w, h;
1065
1066 w = mode->hdisplay;
1067 h = mode->vdisplay;
1068
1069 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
1070 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1071 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1072
1073 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
1074 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1075 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1076 return 0;
1077
1078 return -EINVAL;
1079}
1080
Krzysztof Kozlowskif3aaf762015-05-07 09:04:45 +09001081static const struct exynos_drm_crtc_ops mixer_crtc_ops = {
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001082 .enable = mixer_enable,
1083 .disable = mixer_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001084 .enable_vblank = mixer_enable_vblank,
1085 .disable_vblank = mixer_disable_vblank,
Prathyush K8137a2e2012-12-06 20:16:01 +05301086 .wait_for_vblank = mixer_wait_for_vblank,
Gustavo Padovan9cc76102015-08-03 14:38:05 +09001087 .update_plane = mixer_update_plane,
1088 .disable_plane = mixer_disable_plane,
Andrzej Hajda3ae24362015-10-26 13:03:40 +01001089 .atomic_check = mixer_atomic_check,
Sean Paulf041b252014-01-30 16:19:15 -05001090};
Rahul Sharma0ea68222013-01-15 08:11:06 -05001091
Rahul Sharmadef5e092013-06-19 18:21:08 +05301092static struct mixer_drv_data exynos5420_mxr_drv_data = {
1093 .version = MXR_VER_128_0_0_184,
1094 .is_vp_enabled = 0,
1095};
1096
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301097static struct mixer_drv_data exynos5250_mxr_drv_data = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301098 .version = MXR_VER_16_0_33_0,
1099 .is_vp_enabled = 0,
1100};
1101
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001102static struct mixer_drv_data exynos4212_mxr_drv_data = {
1103 .version = MXR_VER_0_0_0_16,
1104 .is_vp_enabled = 1,
1105};
1106
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301107static struct mixer_drv_data exynos4210_mxr_drv_data = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301108 .version = MXR_VER_0_0_0_16,
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301109 .is_vp_enabled = 1,
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001110 .has_sclk = 1,
Rahul Sharma1e123442012-10-04 20:48:51 +05301111};
1112
Krzysztof Kozlowskid6b16302015-05-02 00:56:36 +09001113static const struct platform_device_id mixer_driver_types[] = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301114 {
1115 .name = "s5p-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301116 .driver_data = (unsigned long)&exynos4210_mxr_drv_data,
Rahul Sharma1e123442012-10-04 20:48:51 +05301117 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301118 .name = "exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301119 .driver_data = (unsigned long)&exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301120 }, {
1121 /* end node */
1122 }
1123};
1124
1125static struct of_device_id mixer_match_types[] = {
1126 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001127 .compatible = "samsung,exynos4210-mixer",
1128 .data = &exynos4210_mxr_drv_data,
1129 }, {
1130 .compatible = "samsung,exynos4212-mixer",
1131 .data = &exynos4212_mxr_drv_data,
1132 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301133 .compatible = "samsung,exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301134 .data = &exynos5250_mxr_drv_data,
1135 }, {
1136 .compatible = "samsung,exynos5250-mixer",
1137 .data = &exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301138 }, {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301139 .compatible = "samsung,exynos5420-mixer",
1140 .data = &exynos5420_mxr_drv_data,
1141 }, {
Rahul Sharma1e123442012-10-04 20:48:51 +05301142 /* end node */
1143 }
1144};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001145MODULE_DEVICE_TABLE(of, mixer_match_types);
Rahul Sharma1e123442012-10-04 20:48:51 +05301146
Inki Daef37cd5e2014-05-09 14:25:20 +09001147static int mixer_bind(struct device *dev, struct device *manager, void *data)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001148{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001149 struct mixer_context *ctx = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09001150 struct drm_device *drm_dev = data;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001151 struct exynos_drm_plane *exynos_plane;
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +01001152 unsigned int i;
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +09001153 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001154
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001155 ret = mixer_initialize(ctx, drm_dev);
1156 if (ret)
1157 return ret;
1158
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +01001159 for (i = 0; i < MIXER_WIN_NR; i++) {
1160 if (i == VP_DEFAULT_WIN && !ctx->vp_enabled)
Marek Szyprowskiab144202015-11-30 14:53:24 +01001161 continue;
1162
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +01001163 ret = exynos_plane_init(drm_dev, &ctx->planes[i],
1164 1 << ctx->pipe, &plane_configs[i]);
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001165 if (ret)
1166 return ret;
1167 }
1168
Gustavo Padovan5d3d0992015-10-12 22:07:48 +09001169 exynos_plane = &ctx->planes[DEFAULT_WIN];
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001170 ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
1171 ctx->pipe, EXYNOS_DISPLAY_TYPE_HDMI,
1172 &mixer_crtc_ops, ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001173 if (IS_ERR(ctx->crtc)) {
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001174 mixer_ctx_remove(ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001175 ret = PTR_ERR(ctx->crtc);
1176 goto free_ctx;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001177 }
1178
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001179 return 0;
Gustavo Padovan93bca242015-01-18 18:16:23 +09001180
1181free_ctx:
1182 devm_kfree(dev, ctx);
1183 return ret;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001184}
1185
1186static void mixer_unbind(struct device *dev, struct device *master, void *data)
1187{
1188 struct mixer_context *ctx = dev_get_drvdata(dev);
1189
Gustavo Padovan93bca242015-01-18 18:16:23 +09001190 mixer_ctx_remove(ctx);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001191}
1192
1193static const struct component_ops mixer_component_ops = {
1194 .bind = mixer_bind,
1195 .unbind = mixer_unbind,
1196};
1197
1198static int mixer_probe(struct platform_device *pdev)
1199{
1200 struct device *dev = &pdev->dev;
1201 struct mixer_drv_data *drv;
1202 struct mixer_context *ctx;
1203 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001204
Sean Paulf041b252014-01-30 16:19:15 -05001205 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1206 if (!ctx) {
1207 DRM_ERROR("failed to alloc mixer context.\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001208 return -ENOMEM;
Sean Paulf041b252014-01-30 16:19:15 -05001209 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001210
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301211 if (dev->of_node) {
1212 const struct of_device_id *match;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001213
Sachin Kamate436b092013-06-05 16:00:23 +09001214 match = of_match_node(mixer_match_types, dev->of_node);
Rahul Sharma2cdc53b2012-10-31 09:36:26 +05301215 drv = (struct mixer_drv_data *)match->data;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301216 } else {
1217 drv = (struct mixer_drv_data *)
1218 platform_get_device_id(pdev)->driver_data;
1219 }
1220
Sean Paul45517892014-01-30 16:19:05 -05001221 ctx->pdev = pdev;
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001222 ctx->dev = dev;
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301223 ctx->vp_enabled = drv->is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001224 ctx->has_sclk = drv->has_sclk;
Rahul Sharma1e123442012-10-04 20:48:51 +05301225 ctx->mxr_ver = drv->version;
Daniel Vetter57ed0f72013-12-11 11:34:43 +01001226 init_waitqueue_head(&ctx->wait_vsync_queue);
Prathyush K6e95d5e2012-12-06 20:16:03 +05301227 atomic_set(&ctx->wait_vsync_event, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001228
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001229 platform_set_drvdata(pdev, ctx);
Inki Daedf5225b2014-05-29 18:28:02 +09001230
Inki Daedf5225b2014-05-29 18:28:02 +09001231 ret = component_add(&pdev->dev, &mixer_component_ops);
Andrzej Hajda86650402015-06-11 23:23:37 +09001232 if (!ret)
1233 pm_runtime_enable(dev);
Inki Daedf5225b2014-05-29 18:28:02 +09001234
1235 return ret;
Inki Daef37cd5e2014-05-09 14:25:20 +09001236}
1237
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001238static int mixer_remove(struct platform_device *pdev)
1239{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001240 pm_runtime_disable(&pdev->dev);
1241
Inki Daedf5225b2014-05-29 18:28:02 +09001242 component_del(&pdev->dev, &mixer_component_ops);
Inki Daedf5225b2014-05-29 18:28:02 +09001243
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001244 return 0;
1245}
1246
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001247#ifdef CONFIG_PM_SLEEP
1248static int exynos_mixer_suspend(struct device *dev)
1249{
1250 struct mixer_context *ctx = dev_get_drvdata(dev);
1251 struct mixer_resources *res = &ctx->mixer_res;
1252
1253 clk_disable_unprepare(res->hdmi);
1254 clk_disable_unprepare(res->mixer);
1255 if (ctx->vp_enabled) {
1256 clk_disable_unprepare(res->vp);
1257 if (ctx->has_sclk)
1258 clk_disable_unprepare(res->sclk_mixer);
1259 }
1260
1261 return 0;
1262}
1263
1264static int exynos_mixer_resume(struct device *dev)
1265{
1266 struct mixer_context *ctx = dev_get_drvdata(dev);
1267 struct mixer_resources *res = &ctx->mixer_res;
1268 int ret;
1269
1270 ret = clk_prepare_enable(res->mixer);
1271 if (ret < 0) {
1272 DRM_ERROR("Failed to prepare_enable the mixer clk [%d]\n", ret);
1273 return ret;
1274 }
1275 ret = clk_prepare_enable(res->hdmi);
1276 if (ret < 0) {
1277 DRM_ERROR("Failed to prepare_enable the hdmi clk [%d]\n", ret);
1278 return ret;
1279 }
1280 if (ctx->vp_enabled) {
1281 ret = clk_prepare_enable(res->vp);
1282 if (ret < 0) {
1283 DRM_ERROR("Failed to prepare_enable the vp clk [%d]\n",
1284 ret);
1285 return ret;
1286 }
1287 if (ctx->has_sclk) {
1288 ret = clk_prepare_enable(res->sclk_mixer);
1289 if (ret < 0) {
1290 DRM_ERROR("Failed to prepare_enable the " \
1291 "sclk_mixer clk [%d]\n",
1292 ret);
1293 return ret;
1294 }
1295 }
1296 }
1297
1298 return 0;
1299}
1300#endif
1301
1302static const struct dev_pm_ops exynos_mixer_pm_ops = {
1303 SET_RUNTIME_PM_OPS(exynos_mixer_suspend, exynos_mixer_resume, NULL)
1304};
1305
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001306struct platform_driver mixer_driver = {
1307 .driver = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301308 .name = "exynos-mixer",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001309 .owner = THIS_MODULE,
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001310 .pm = &exynos_mixer_pm_ops,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301311 .of_match_table = mixer_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001312 },
1313 .probe = mixer_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001314 .remove = mixer_remove,
Rahul Sharma1e123442012-10-04 20:48:51 +05301315 .id_table = mixer_driver_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001316};