blob: bea3cbd39a2531ad9a91191e2a060cbb44faac75 [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>
Marek Szyprowski48f61552016-04-01 15:17:46 +020034#include <linux/of_device.h>
Inki Daef37cd5e2014-05-09 14:25:20 +090035#include <linux/component.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090036
37#include <drm/exynos_drm.h>
38
39#include "exynos_drm_drv.h"
Rahul Sharma663d8762013-01-03 05:44:04 -050040#include "exynos_drm_crtc.h"
Marek Szyprowski0488f502015-11-30 14:53:21 +010041#include "exynos_drm_fb.h"
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +090042#include "exynos_drm_plane.h"
Inki Dae1055b392012-10-19 17:37:35 +090043#include "exynos_drm_iommu.h"
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090044
Sean Paulf041b252014-01-30 16:19:15 -050045#define MIXER_WIN_NR 3
Marek Szyprowskifbbb1e12015-08-31 00:53:57 +090046#define VP_DEFAULT_WIN 2
Seung-Woo Kimd8408322011-12-21 17:39:39 +090047
Tobias Jakobi7a57ca72015-04-27 23:11:59 +020048/* The pixelformats that are natively supported by the mixer. */
49#define MXR_FORMAT_RGB565 4
50#define MXR_FORMAT_ARGB1555 5
51#define MXR_FORMAT_ARGB4444 6
52#define MXR_FORMAT_ARGB8888 7
53
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090054struct mixer_resources {
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090055 int irq;
56 void __iomem *mixer_regs;
57 void __iomem *vp_regs;
58 spinlock_t reg_slock;
59 struct clk *mixer;
60 struct clk *vp;
Marek Szyprowski04427ec2015-02-02 14:20:28 +010061 struct clk *hdmi;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090062 struct clk *sclk_mixer;
63 struct clk *sclk_hdmi;
Marek Szyprowskiff830c92014-07-01 10:10:07 +020064 struct clk *mout_mixer;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090065};
66
Rahul Sharma1e123442012-10-04 20:48:51 +053067enum mixer_version_id {
68 MXR_VER_0_0_0_16,
69 MXR_VER_16_0_33_0,
Rahul Sharmadef5e092013-06-19 18:21:08 +053070 MXR_VER_128_0_0_184,
Rahul Sharma1e123442012-10-04 20:48:51 +053071};
72
Andrzej Hajdaa44652e2015-07-09 08:25:42 +020073enum mixer_flag_bits {
74 MXR_BIT_POWERED,
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +020075 MXR_BIT_VSYNC,
Tobias Jakobiadeb6f42016-09-22 11:36:13 +090076 MXR_BIT_INTERLACE,
77 MXR_BIT_VP_ENABLED,
78 MXR_BIT_HAS_SCLK,
Andrzej Hajdaa44652e2015-07-09 08:25:42 +020079};
80
Marek Szyprowskifbbb1e12015-08-31 00:53:57 +090081static const uint32_t mixer_formats[] = {
82 DRM_FORMAT_XRGB4444,
Tobias Jakobi26a7af32015-12-16 13:21:47 +010083 DRM_FORMAT_ARGB4444,
Marek Szyprowskifbbb1e12015-08-31 00:53:57 +090084 DRM_FORMAT_XRGB1555,
Tobias Jakobi26a7af32015-12-16 13:21:47 +010085 DRM_FORMAT_ARGB1555,
Marek Szyprowskifbbb1e12015-08-31 00:53:57 +090086 DRM_FORMAT_RGB565,
87 DRM_FORMAT_XRGB8888,
88 DRM_FORMAT_ARGB8888,
89};
90
91static const uint32_t vp_formats[] = {
92 DRM_FORMAT_NV12,
93 DRM_FORMAT_NV21,
94};
95
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090096struct mixer_context {
Sean Paul45517892014-01-30 16:19:05 -050097 struct platform_device *pdev;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090098 struct device *dev;
Inki Dae1055b392012-10-19 17:37:35 +090099 struct drm_device *drm_dev;
Gustavo Padovan93bca242015-01-18 18:16:23 +0900100 struct exynos_drm_crtc *crtc;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900101 struct exynos_drm_plane planes[MIXER_WIN_NR];
Joonyoung Shim22b21ae2012-03-15 17:19:04 +0900102 int pipe;
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200103 unsigned long flags;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +0900104
105 struct mixer_resources mixer_res;
Rahul Sharma1e123442012-10-04 20:48:51 +0530106 enum mixer_version_id mxr_ver;
107};
108
109struct mixer_drv_data {
110 enum mixer_version_id version;
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530111 bool is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200112 bool has_sclk;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +0900113};
114
Marek Szyprowskifd2d2fc22015-11-30 14:53:25 +0100115static const struct exynos_drm_plane_config plane_configs[MIXER_WIN_NR] = {
116 {
117 .zpos = 0,
118 .type = DRM_PLANE_TYPE_PRIMARY,
119 .pixel_formats = mixer_formats,
120 .num_pixel_formats = ARRAY_SIZE(mixer_formats),
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100121 .capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE |
122 EXYNOS_DRM_PLANE_CAP_ZPOS,
Marek Szyprowskifd2d2fc22015-11-30 14:53:25 +0100123 }, {
124 .zpos = 1,
125 .type = DRM_PLANE_TYPE_CURSOR,
126 .pixel_formats = mixer_formats,
127 .num_pixel_formats = ARRAY_SIZE(mixer_formats),
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100128 .capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE |
129 EXYNOS_DRM_PLANE_CAP_ZPOS,
Marek Szyprowskifd2d2fc22015-11-30 14:53:25 +0100130 }, {
131 .zpos = 2,
132 .type = DRM_PLANE_TYPE_OVERLAY,
133 .pixel_formats = vp_formats,
134 .num_pixel_formats = ARRAY_SIZE(vp_formats),
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100135 .capabilities = EXYNOS_DRM_PLANE_CAP_SCALE |
136 EXYNOS_DRM_PLANE_CAP_ZPOS,
Marek Szyprowskifd2d2fc22015-11-30 14:53:25 +0100137 },
138};
139
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900140static const u8 filter_y_horiz_tap8[] = {
141 0, -1, -1, -1, -1, -1, -1, -1,
142 -1, -1, -1, -1, -1, 0, 0, 0,
143 0, 2, 4, 5, 6, 6, 6, 6,
144 6, 5, 5, 4, 3, 2, 1, 1,
145 0, -6, -12, -16, -18, -20, -21, -20,
146 -20, -18, -16, -13, -10, -8, -5, -2,
147 127, 126, 125, 121, 114, 107, 99, 89,
148 79, 68, 57, 46, 35, 25, 16, 8,
149};
150
151static const u8 filter_y_vert_tap4[] = {
152 0, -3, -6, -8, -8, -8, -8, -7,
153 -6, -5, -4, -3, -2, -1, -1, 0,
154 127, 126, 124, 118, 111, 102, 92, 81,
155 70, 59, 48, 37, 27, 19, 11, 5,
156 0, 5, 11, 19, 27, 37, 48, 59,
157 70, 81, 92, 102, 111, 118, 124, 126,
158 0, 0, -1, -1, -2, -3, -4, -5,
159 -6, -7, -8, -8, -8, -8, -6, -3,
160};
161
162static const u8 filter_cr_horiz_tap4[] = {
163 0, -3, -6, -8, -8, -8, -8, -7,
164 -6, -5, -4, -3, -2, -1, -1, 0,
165 127, 126, 124, 118, 111, 102, 92, 81,
166 70, 59, 48, 37, 27, 19, 11, 5,
167};
168
Marek Szyprowskif657a992015-12-16 13:21:46 +0100169static inline bool is_alpha_format(unsigned int pixel_format)
170{
171 switch (pixel_format) {
172 case DRM_FORMAT_ARGB8888:
Tobias Jakobi26a7af32015-12-16 13:21:47 +0100173 case DRM_FORMAT_ARGB1555:
174 case DRM_FORMAT_ARGB4444:
Marek Szyprowskif657a992015-12-16 13:21:46 +0100175 return true;
176 default:
177 return false;
178 }
179}
180
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900181static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
182{
183 return readl(res->vp_regs + reg_id);
184}
185
186static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
187 u32 val)
188{
189 writel(val, res->vp_regs + reg_id);
190}
191
192static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
193 u32 val, u32 mask)
194{
195 u32 old = vp_reg_read(res, reg_id);
196
197 val = (val & mask) | (old & ~mask);
198 writel(val, res->vp_regs + reg_id);
199}
200
201static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
202{
203 return readl(res->mixer_regs + reg_id);
204}
205
206static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
207 u32 val)
208{
209 writel(val, res->mixer_regs + reg_id);
210}
211
212static inline void mixer_reg_writemask(struct mixer_resources *res,
213 u32 reg_id, u32 val, u32 mask)
214{
215 u32 old = mixer_reg_read(res, reg_id);
216
217 val = (val & mask) | (old & ~mask);
218 writel(val, res->mixer_regs + reg_id);
219}
220
221static void mixer_regs_dump(struct mixer_context *ctx)
222{
223#define DUMPREG(reg_id) \
224do { \
225 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
226 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
227} while (0)
228
229 DUMPREG(MXR_STATUS);
230 DUMPREG(MXR_CFG);
231 DUMPREG(MXR_INT_EN);
232 DUMPREG(MXR_INT_STATUS);
233
234 DUMPREG(MXR_LAYER_CFG);
235 DUMPREG(MXR_VIDEO_CFG);
236
237 DUMPREG(MXR_GRAPHIC0_CFG);
238 DUMPREG(MXR_GRAPHIC0_BASE);
239 DUMPREG(MXR_GRAPHIC0_SPAN);
240 DUMPREG(MXR_GRAPHIC0_WH);
241 DUMPREG(MXR_GRAPHIC0_SXY);
242 DUMPREG(MXR_GRAPHIC0_DXY);
243
244 DUMPREG(MXR_GRAPHIC1_CFG);
245 DUMPREG(MXR_GRAPHIC1_BASE);
246 DUMPREG(MXR_GRAPHIC1_SPAN);
247 DUMPREG(MXR_GRAPHIC1_WH);
248 DUMPREG(MXR_GRAPHIC1_SXY);
249 DUMPREG(MXR_GRAPHIC1_DXY);
250#undef DUMPREG
251}
252
253static void vp_regs_dump(struct mixer_context *ctx)
254{
255#define DUMPREG(reg_id) \
256do { \
257 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
258 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
259} while (0)
260
261 DUMPREG(VP_ENABLE);
262 DUMPREG(VP_SRESET);
263 DUMPREG(VP_SHADOW_UPDATE);
264 DUMPREG(VP_FIELD_ID);
265 DUMPREG(VP_MODE);
266 DUMPREG(VP_IMG_SIZE_Y);
267 DUMPREG(VP_IMG_SIZE_C);
268 DUMPREG(VP_PER_RATE_CTRL);
269 DUMPREG(VP_TOP_Y_PTR);
270 DUMPREG(VP_BOT_Y_PTR);
271 DUMPREG(VP_TOP_C_PTR);
272 DUMPREG(VP_BOT_C_PTR);
273 DUMPREG(VP_ENDIAN_MODE);
274 DUMPREG(VP_SRC_H_POSITION);
275 DUMPREG(VP_SRC_V_POSITION);
276 DUMPREG(VP_SRC_WIDTH);
277 DUMPREG(VP_SRC_HEIGHT);
278 DUMPREG(VP_DST_H_POSITION);
279 DUMPREG(VP_DST_V_POSITION);
280 DUMPREG(VP_DST_WIDTH);
281 DUMPREG(VP_DST_HEIGHT);
282 DUMPREG(VP_H_RATIO);
283 DUMPREG(VP_V_RATIO);
284
285#undef DUMPREG
286}
287
288static inline void vp_filter_set(struct mixer_resources *res,
289 int reg_id, const u8 *data, unsigned int size)
290{
291 /* assure 4-byte align */
292 BUG_ON(size & 3);
293 for (; size; size -= 4, reg_id += 4, data += 4) {
294 u32 val = (data[0] << 24) | (data[1] << 16) |
295 (data[2] << 8) | data[3];
296 vp_reg_write(res, reg_id, val);
297 }
298}
299
300static void vp_default_filter(struct mixer_resources *res)
301{
302 vp_filter_set(res, VP_POLY8_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530303 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900304 vp_filter_set(res, VP_POLY4_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530305 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900306 vp_filter_set(res, VP_POLY4_C0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530307 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900308}
309
Marek Szyprowskif657a992015-12-16 13:21:46 +0100310static void mixer_cfg_gfx_blend(struct mixer_context *ctx, unsigned int win,
311 bool alpha)
312{
313 struct mixer_resources *res = &ctx->mixer_res;
314 u32 val;
315
316 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
317 if (alpha) {
318 /* blending based on pixel alpha */
319 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
320 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
321 }
322 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
323 val, MXR_GRP_CFG_MISC_MASK);
324}
325
326static void mixer_cfg_vp_blend(struct mixer_context *ctx)
327{
328 struct mixer_resources *res = &ctx->mixer_res;
329 u32 val;
330
331 /*
332 * No blending at the moment since the NV12/NV21 pixelformats don't
333 * have an alpha channel. However the mixer supports a global alpha
334 * value for a layer. Once this functionality is exposed, we can
335 * support blending of the video layer through this.
336 */
337 val = 0;
338 mixer_reg_write(res, MXR_VIDEO_CFG, val);
339}
340
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900341static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
342{
343 struct mixer_resources *res = &ctx->mixer_res;
344
345 /* block update on vsync */
346 mixer_reg_writemask(res, MXR_STATUS, enable ?
347 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
348
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900349 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags))
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530350 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900351 VP_SHADOW_UPDATE_ENABLE : 0);
352}
353
354static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
355{
356 struct mixer_resources *res = &ctx->mixer_res;
357 u32 val;
358
359 /* choosing between interlace and progressive mode */
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900360 val = test_bit(MXR_BIT_INTERLACE, &ctx->flags) ?
361 MXR_CFG_SCAN_INTERLACE : MXR_CFG_SCAN_PROGRESSIVE;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900362
Rahul Sharmadef5e092013-06-19 18:21:08 +0530363 if (ctx->mxr_ver != MXR_VER_128_0_0_184) {
364 /* choosing between proper HD and SD mode */
365 if (height <= 480)
366 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
367 else if (height <= 576)
368 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
369 else if (height <= 720)
370 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
371 else if (height <= 1080)
372 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
373 else
374 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
375 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900376
377 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
378}
379
380static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
381{
382 struct mixer_resources *res = &ctx->mixer_res;
383 u32 val;
384
385 if (height == 480) {
386 val = MXR_CFG_RGB601_0_255;
387 } else if (height == 576) {
388 val = MXR_CFG_RGB601_0_255;
389 } else if (height == 720) {
390 val = MXR_CFG_RGB709_16_235;
391 mixer_reg_write(res, MXR_CM_COEFF_Y,
392 (1 << 30) | (94 << 20) | (314 << 10) |
393 (32 << 0));
394 mixer_reg_write(res, MXR_CM_COEFF_CB,
395 (972 << 20) | (851 << 10) | (225 << 0));
396 mixer_reg_write(res, MXR_CM_COEFF_CR,
397 (225 << 20) | (820 << 10) | (1004 << 0));
398 } else if (height == 1080) {
399 val = MXR_CFG_RGB709_16_235;
400 mixer_reg_write(res, MXR_CM_COEFF_Y,
401 (1 << 30) | (94 << 20) | (314 << 10) |
402 (32 << 0));
403 mixer_reg_write(res, MXR_CM_COEFF_CB,
404 (972 << 20) | (851 << 10) | (225 << 0));
405 mixer_reg_write(res, MXR_CM_COEFF_CR,
406 (225 << 20) | (820 << 10) | (1004 << 0));
407 } else {
408 val = MXR_CFG_RGB709_16_235;
409 mixer_reg_write(res, MXR_CM_COEFF_Y,
410 (1 << 30) | (94 << 20) | (314 << 10) |
411 (32 << 0));
412 mixer_reg_write(res, MXR_CM_COEFF_CB,
413 (972 << 20) | (851 << 10) | (225 << 0));
414 mixer_reg_write(res, MXR_CM_COEFF_CR,
415 (225 << 20) | (820 << 10) | (1004 << 0));
416 }
417
418 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
419}
420
Tobias Jakobi5b1d5bc2015-05-06 14:10:22 +0200421static void mixer_cfg_layer(struct mixer_context *ctx, unsigned int win,
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100422 unsigned int priority, bool enable)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900423{
424 struct mixer_resources *res = &ctx->mixer_res;
425 u32 val = enable ? ~0 : 0;
426
427 switch (win) {
428 case 0:
429 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100430 mixer_reg_writemask(res, MXR_LAYER_CFG,
431 MXR_LAYER_CFG_GRP0_VAL(priority),
432 MXR_LAYER_CFG_GRP0_MASK);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900433 break;
434 case 1:
435 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100436 mixer_reg_writemask(res, MXR_LAYER_CFG,
437 MXR_LAYER_CFG_GRP1_VAL(priority),
438 MXR_LAYER_CFG_GRP1_MASK);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900439
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900440 break;
Marek Szyprowski5e68fef2015-12-16 13:21:48 +0100441 case VP_DEFAULT_WIN:
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900442 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530443 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
444 mixer_reg_writemask(res, MXR_CFG, val,
445 MXR_CFG_VP_ENABLE);
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100446 mixer_reg_writemask(res, MXR_LAYER_CFG,
447 MXR_LAYER_CFG_VP_VAL(priority),
448 MXR_LAYER_CFG_VP_MASK);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530449 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900450 break;
451 }
452}
453
454static void mixer_run(struct mixer_context *ctx)
455{
456 struct mixer_resources *res = &ctx->mixer_res;
457
458 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900459}
460
Rahul Sharma381be022014-06-23 11:02:22 +0530461static void mixer_stop(struct mixer_context *ctx)
462{
463 struct mixer_resources *res = &ctx->mixer_res;
464 int timeout = 20;
465
466 mixer_reg_writemask(res, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
467
468 while (!(mixer_reg_read(res, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
469 --timeout)
470 usleep_range(10000, 12000);
Rahul Sharma381be022014-06-23 11:02:22 +0530471}
472
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900473static void vp_video_buffer(struct mixer_context *ctx,
474 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900475{
Marek Szyprowski0114f402015-11-30 14:53:22 +0100476 struct exynos_drm_plane_state *state =
477 to_exynos_plane_state(plane->base.state);
Marek Szyprowski2ee35d82015-11-30 14:53:23 +0100478 struct drm_display_mode *mode = &state->base.crtc->state->adjusted_mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900479 struct mixer_resources *res = &ctx->mixer_res;
Marek Szyprowski0114f402015-11-30 14:53:22 +0100480 struct drm_framebuffer *fb = state->base.fb;
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200481 unsigned int priority = state->base.normalized_zpos + 1;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900482 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900483 dma_addr_t luma_addr[2], chroma_addr[2];
484 bool tiled_mode = false;
485 bool crcb_mode = false;
486 u32 val;
487
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900488 switch (fb->pixel_format) {
Ville Syrjälä363b06a2012-05-14 11:08:51 +0900489 case DRM_FORMAT_NV12:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900490 crcb_mode = false;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900491 break;
Tobias Jakobi8f2590f2015-04-27 23:10:16 +0200492 case DRM_FORMAT_NV21:
493 crcb_mode = true;
494 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900495 default:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900496 DRM_ERROR("pixel format for vp is wrong [%d].\n",
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900497 fb->pixel_format);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900498 return;
499 }
500
Marek Szyprowski0488f502015-11-30 14:53:21 +0100501 luma_addr[0] = exynos_drm_fb_dma_addr(fb, 0);
502 chroma_addr[0] = exynos_drm_fb_dma_addr(fb, 1);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900503
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900504 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900505 __set_bit(MXR_BIT_INTERLACE, &ctx->flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900506 if (tiled_mode) {
507 luma_addr[1] = luma_addr[0] + 0x40;
508 chroma_addr[1] = chroma_addr[0] + 0x40;
509 } else {
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900510 luma_addr[1] = luma_addr[0] + fb->pitches[0];
511 chroma_addr[1] = chroma_addr[0] + fb->pitches[0];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900512 }
513 } else {
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900514 __clear_bit(MXR_BIT_INTERLACE, &ctx->flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900515 luma_addr[1] = 0;
516 chroma_addr[1] = 0;
517 }
518
519 spin_lock_irqsave(&res->reg_slock, flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900520
521 /* interlace or progressive scan mode */
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900522 val = (test_bit(MXR_BIT_INTERLACE, &ctx->flags) ? ~0 : 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900523 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
524
525 /* setup format */
526 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
527 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
528 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
529
530 /* setting size of input image */
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900531 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(fb->pitches[0]) |
532 VP_IMG_VSIZE(fb->height));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900533 /* chroma height has to reduced by 2 to avoid chroma distorions */
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900534 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(fb->pitches[0]) |
535 VP_IMG_VSIZE(fb->height / 2));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900536
Marek Szyprowski0114f402015-11-30 14:53:22 +0100537 vp_reg_write(res, VP_SRC_WIDTH, state->src.w);
538 vp_reg_write(res, VP_SRC_HEIGHT, state->src.h);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900539 vp_reg_write(res, VP_SRC_H_POSITION,
Marek Szyprowski0114f402015-11-30 14:53:22 +0100540 VP_SRC_H_POSITION_VAL(state->src.x));
541 vp_reg_write(res, VP_SRC_V_POSITION, state->src.y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900542
Marek Szyprowski0114f402015-11-30 14:53:22 +0100543 vp_reg_write(res, VP_DST_WIDTH, state->crtc.w);
544 vp_reg_write(res, VP_DST_H_POSITION, state->crtc.x);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900545 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
Marek Szyprowski0114f402015-11-30 14:53:22 +0100546 vp_reg_write(res, VP_DST_HEIGHT, state->crtc.h / 2);
547 vp_reg_write(res, VP_DST_V_POSITION, state->crtc.y / 2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900548 } else {
Marek Szyprowski0114f402015-11-30 14:53:22 +0100549 vp_reg_write(res, VP_DST_HEIGHT, state->crtc.h);
550 vp_reg_write(res, VP_DST_V_POSITION, state->crtc.y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900551 }
552
Marek Szyprowski0114f402015-11-30 14:53:22 +0100553 vp_reg_write(res, VP_H_RATIO, state->h_ratio);
554 vp_reg_write(res, VP_V_RATIO, state->v_ratio);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900555
556 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
557
558 /* set buffer address to vp */
559 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
560 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
561 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
562 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
563
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900564 mixer_cfg_scan(ctx, mode->vdisplay);
565 mixer_cfg_rgb_fmt(ctx, mode->vdisplay);
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200566 mixer_cfg_layer(ctx, plane->index, priority, true);
Marek Szyprowskif657a992015-12-16 13:21:46 +0100567 mixer_cfg_vp_blend(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900568 mixer_run(ctx);
569
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900570 spin_unlock_irqrestore(&res->reg_slock, flags);
571
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200572 mixer_regs_dump(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900573 vp_regs_dump(ctx);
574}
575
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530576static void mixer_layer_update(struct mixer_context *ctx)
577{
578 struct mixer_resources *res = &ctx->mixer_res;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530579
Rahul Sharma5c0f4822014-06-23 11:02:23 +0530580 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530581}
582
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900583static void mixer_graph_buffer(struct mixer_context *ctx,
584 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900585{
Marek Szyprowski0114f402015-11-30 14:53:22 +0100586 struct exynos_drm_plane_state *state =
587 to_exynos_plane_state(plane->base.state);
Marek Szyprowski2ee35d82015-11-30 14:53:23 +0100588 struct drm_display_mode *mode = &state->base.crtc->state->adjusted_mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900589 struct mixer_resources *res = &ctx->mixer_res;
Marek Szyprowski0114f402015-11-30 14:53:22 +0100590 struct drm_framebuffer *fb = state->base.fb;
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200591 unsigned int priority = state->base.normalized_zpos + 1;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900592 unsigned long flags;
Marek Szyprowski40bdfb02015-12-16 13:21:42 +0100593 unsigned int win = plane->index;
Tobias Jakobi26110152015-04-07 01:14:52 +0200594 unsigned int x_ratio = 0, y_ratio = 0;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900595 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900596 dma_addr_t dma_addr;
597 unsigned int fmt;
598 u32 val;
599
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900600 switch (fb->pixel_format) {
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200601 case DRM_FORMAT_XRGB4444:
Tobias Jakobi26a7af32015-12-16 13:21:47 +0100602 case DRM_FORMAT_ARGB4444:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200603 fmt = MXR_FORMAT_ARGB4444;
604 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900605
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200606 case DRM_FORMAT_XRGB1555:
Tobias Jakobi26a7af32015-12-16 13:21:47 +0100607 case DRM_FORMAT_ARGB1555:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200608 fmt = MXR_FORMAT_ARGB1555;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900609 break;
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200610
611 case DRM_FORMAT_RGB565:
612 fmt = MXR_FORMAT_RGB565;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900613 break;
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200614
615 case DRM_FORMAT_XRGB8888:
616 case DRM_FORMAT_ARGB8888:
617 fmt = MXR_FORMAT_ARGB8888;
618 break;
619
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900620 default:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200621 DRM_DEBUG_KMS("pixelformat unsupported by mixer\n");
622 return;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900623 }
624
Marek Szyprowskie463b062015-11-30 14:53:27 +0100625 /* ratio is already checked by common plane code */
626 x_ratio = state->h_ratio == (1 << 15);
627 y_ratio = state->v_ratio == (1 << 15);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900628
Marek Szyprowski0114f402015-11-30 14:53:22 +0100629 dst_x_offset = state->crtc.x;
630 dst_y_offset = state->crtc.y;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900631
632 /* converting dma address base and source offset */
Marek Szyprowski0488f502015-11-30 14:53:21 +0100633 dma_addr = exynos_drm_fb_dma_addr(fb, 0)
Marek Szyprowski0114f402015-11-30 14:53:22 +0100634 + (state->src.x * fb->bits_per_pixel >> 3)
635 + (state->src.y * fb->pitches[0]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900636 src_x_offset = 0;
637 src_y_offset = 0;
638
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900639 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900640 __set_bit(MXR_BIT_INTERLACE, &ctx->flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900641 else
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900642 __clear_bit(MXR_BIT_INTERLACE, &ctx->flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900643
644 spin_lock_irqsave(&res->reg_slock, flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900645
646 /* setup format */
647 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
648 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
649
650 /* setup geometry */
Daniel Stoneadacb222015-03-17 13:24:58 +0000651 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win),
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900652 fb->pitches[0] / (fb->bits_per_pixel >> 3));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900653
Rahul Sharmadef5e092013-06-19 18:21:08 +0530654 /* setup display size */
655 if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
Gustavo Padovan5d3d0992015-10-12 22:07:48 +0900656 win == DEFAULT_WIN) {
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900657 val = MXR_MXR_RES_HEIGHT(mode->vdisplay);
658 val |= MXR_MXR_RES_WIDTH(mode->hdisplay);
Rahul Sharmadef5e092013-06-19 18:21:08 +0530659 mixer_reg_write(res, MXR_RESOLUTION, val);
660 }
661
Marek Szyprowski0114f402015-11-30 14:53:22 +0100662 val = MXR_GRP_WH_WIDTH(state->src.w);
663 val |= MXR_GRP_WH_HEIGHT(state->src.h);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900664 val |= MXR_GRP_WH_H_SCALE(x_ratio);
665 val |= MXR_GRP_WH_V_SCALE(y_ratio);
666 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
667
668 /* setup offsets in source image */
669 val = MXR_GRP_SXY_SX(src_x_offset);
670 val |= MXR_GRP_SXY_SY(src_y_offset);
671 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
672
673 /* setup offsets in display image */
674 val = MXR_GRP_DXY_DX(dst_x_offset);
675 val |= MXR_GRP_DXY_DY(dst_y_offset);
676 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
677
678 /* set buffer address to mixer */
679 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
680
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900681 mixer_cfg_scan(ctx, mode->vdisplay);
682 mixer_cfg_rgb_fmt(ctx, mode->vdisplay);
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200683 mixer_cfg_layer(ctx, win, priority, true);
Marek Szyprowskif657a992015-12-16 13:21:46 +0100684 mixer_cfg_gfx_blend(ctx, win, is_alpha_format(fb->pixel_format));
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530685
686 /* layer update mandatory for mixer 16.0.33.0 */
Rahul Sharmadef5e092013-06-19 18:21:08 +0530687 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
688 ctx->mxr_ver == MXR_VER_128_0_0_184)
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530689 mixer_layer_update(ctx);
690
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900691 mixer_run(ctx);
692
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900693 spin_unlock_irqrestore(&res->reg_slock, flags);
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200694
695 mixer_regs_dump(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900696}
697
698static void vp_win_reset(struct mixer_context *ctx)
699{
700 struct mixer_resources *res = &ctx->mixer_res;
Tobias Jakobia6963942016-09-22 16:57:19 +0200701 unsigned int tries = 100;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900702
703 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
Tobias Jakobia6963942016-09-22 16:57:19 +0200704 while (tries--) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900705 /* waiting until VP_SRESET_PROCESSING is 0 */
706 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
707 break;
Tomasz Stanislawski02b3de42015-09-25 14:48:29 +0200708 mdelay(10);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900709 }
710 WARN(tries == 0, "failed to reset Video Processor\n");
711}
712
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900713static void mixer_win_reset(struct mixer_context *ctx)
714{
715 struct mixer_resources *res = &ctx->mixer_res;
716 unsigned long flags;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900717
718 spin_lock_irqsave(&res->reg_slock, flags);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900719
720 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
721
722 /* set output in RGB888 mode */
723 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
724
725 /* 16 beat burst in DMA */
726 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
727 MXR_STATUS_BURST_MASK);
728
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100729 /* reset default layer priority */
730 mixer_reg_write(res, MXR_LAYER_CFG, 0);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900731
732 /* setting background color */
733 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
734 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
735 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
736
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900737 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530738 /* configuration of Video Processor Registers */
739 vp_win_reset(ctx);
740 vp_default_filter(res);
741 }
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900742
743 /* disable all layers */
744 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
745 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900746 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags))
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530747 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900748
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900749 spin_unlock_irqrestore(&res->reg_slock, flags);
750}
751
Sean Paul45517892014-01-30 16:19:05 -0500752static irqreturn_t mixer_irq_handler(int irq, void *arg)
753{
754 struct mixer_context *ctx = arg;
755 struct mixer_resources *res = &ctx->mixer_res;
756 u32 val, base, shadow;
Gustavo Padovan822f6df2015-08-15 13:26:14 -0300757 int win;
Sean Paul45517892014-01-30 16:19:05 -0500758
759 spin_lock(&res->reg_slock);
760
761 /* read interrupt status for handling and clearing flags for VSYNC */
762 val = mixer_reg_read(res, MXR_INT_STATUS);
763
764 /* handling VSYNC */
765 if (val & MXR_INT_STATUS_VSYNC) {
Andrzej Hajda81a464d2015-07-09 10:07:53 +0200766 /* vsync interrupt use different bit for read and clear */
767 val |= MXR_INT_CLEAR_VSYNC;
768 val &= ~MXR_INT_STATUS_VSYNC;
769
Sean Paul45517892014-01-30 16:19:05 -0500770 /* interlace scan need to check shadow register */
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900771 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
Sean Paul45517892014-01-30 16:19:05 -0500772 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
773 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
774 if (base != shadow)
775 goto out;
776
777 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
778 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
779 if (base != shadow)
780 goto out;
781 }
782
Gustavo Padovaneafd5402015-07-16 12:23:32 -0300783 drm_crtc_handle_vblank(&ctx->crtc->base);
Gustavo Padovan822f6df2015-08-15 13:26:14 -0300784 for (win = 0 ; win < MIXER_WIN_NR ; win++) {
785 struct exynos_drm_plane *plane = &ctx->planes[win];
786
787 if (!plane->pending_fb)
788 continue;
789
790 exynos_drm_crtc_finish_update(ctx->crtc, plane);
791 }
Sean Paul45517892014-01-30 16:19:05 -0500792 }
793
794out:
795 /* clear interrupts */
Sean Paul45517892014-01-30 16:19:05 -0500796 mixer_reg_write(res, MXR_INT_STATUS, val);
797
798 spin_unlock(&res->reg_slock);
799
800 return IRQ_HANDLED;
801}
802
803static int mixer_resources_init(struct mixer_context *mixer_ctx)
804{
805 struct device *dev = &mixer_ctx->pdev->dev;
806 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
807 struct resource *res;
808 int ret;
809
810 spin_lock_init(&mixer_res->reg_slock);
811
812 mixer_res->mixer = devm_clk_get(dev, "mixer");
813 if (IS_ERR(mixer_res->mixer)) {
814 dev_err(dev, "failed to get clock 'mixer'\n");
815 return -ENODEV;
816 }
817
Marek Szyprowski04427ec2015-02-02 14:20:28 +0100818 mixer_res->hdmi = devm_clk_get(dev, "hdmi");
819 if (IS_ERR(mixer_res->hdmi)) {
820 dev_err(dev, "failed to get clock 'hdmi'\n");
821 return PTR_ERR(mixer_res->hdmi);
822 }
823
Sean Paul45517892014-01-30 16:19:05 -0500824 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
825 if (IS_ERR(mixer_res->sclk_hdmi)) {
826 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
827 return -ENODEV;
828 }
829 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
830 if (res == NULL) {
831 dev_err(dev, "get memory resource failed.\n");
832 return -ENXIO;
833 }
834
835 mixer_res->mixer_regs = devm_ioremap(dev, res->start,
836 resource_size(res));
837 if (mixer_res->mixer_regs == NULL) {
838 dev_err(dev, "register mapping failed.\n");
839 return -ENXIO;
840 }
841
842 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
843 if (res == NULL) {
844 dev_err(dev, "get interrupt resource failed.\n");
845 return -ENXIO;
846 }
847
848 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
849 0, "drm_mixer", mixer_ctx);
850 if (ret) {
851 dev_err(dev, "request interrupt failed.\n");
852 return ret;
853 }
854 mixer_res->irq = res->start;
855
856 return 0;
857}
858
859static int vp_resources_init(struct mixer_context *mixer_ctx)
860{
861 struct device *dev = &mixer_ctx->pdev->dev;
862 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
863 struct resource *res;
864
865 mixer_res->vp = devm_clk_get(dev, "vp");
866 if (IS_ERR(mixer_res->vp)) {
867 dev_err(dev, "failed to get clock 'vp'\n");
868 return -ENODEV;
869 }
Sean Paul45517892014-01-30 16:19:05 -0500870
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900871 if (test_bit(MXR_BIT_HAS_SCLK, &mixer_ctx->flags)) {
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200872 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
873 if (IS_ERR(mixer_res->sclk_mixer)) {
874 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
875 return -ENODEV;
876 }
877 mixer_res->mout_mixer = devm_clk_get(dev, "mout_mixer");
878 if (IS_ERR(mixer_res->mout_mixer)) {
879 dev_err(dev, "failed to get clock 'mout_mixer'\n");
880 return -ENODEV;
881 }
882
883 if (mixer_res->sclk_hdmi && mixer_res->mout_mixer)
884 clk_set_parent(mixer_res->mout_mixer,
885 mixer_res->sclk_hdmi);
886 }
Sean Paul45517892014-01-30 16:19:05 -0500887
888 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
889 if (res == NULL) {
890 dev_err(dev, "get memory resource failed.\n");
891 return -ENXIO;
892 }
893
894 mixer_res->vp_regs = devm_ioremap(dev, res->start,
895 resource_size(res));
896 if (mixer_res->vp_regs == NULL) {
897 dev_err(dev, "register mapping failed.\n");
898 return -ENXIO;
899 }
900
901 return 0;
902}
903
Gustavo Padovan93bca242015-01-18 18:16:23 +0900904static int mixer_initialize(struct mixer_context *mixer_ctx,
Inki Daef37cd5e2014-05-09 14:25:20 +0900905 struct drm_device *drm_dev)
Sean Paul45517892014-01-30 16:19:05 -0500906{
907 int ret;
Inki Daef37cd5e2014-05-09 14:25:20 +0900908 struct exynos_drm_private *priv;
909 priv = drm_dev->dev_private;
Sean Paul45517892014-01-30 16:19:05 -0500910
Gustavo Padovaneb88e422014-11-26 16:43:27 -0200911 mixer_ctx->drm_dev = drm_dev;
Gustavo Padovan8a326ed2014-11-04 18:44:47 -0200912 mixer_ctx->pipe = priv->pipe++;
Sean Paul45517892014-01-30 16:19:05 -0500913
914 /* acquire resources: regs, irqs, clocks */
915 ret = mixer_resources_init(mixer_ctx);
916 if (ret) {
917 DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
918 return ret;
919 }
920
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900921 if (test_bit(MXR_BIT_VP_ENABLED, &mixer_ctx->flags)) {
Sean Paul45517892014-01-30 16:19:05 -0500922 /* acquire vp resources: regs, irqs, clocks */
923 ret = vp_resources_init(mixer_ctx);
924 if (ret) {
925 DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
926 return ret;
927 }
928 }
929
Joonyoung Shimeb7a3fc2015-07-02 21:49:39 +0900930 ret = drm_iommu_attach_device(drm_dev, mixer_ctx->dev);
Hyungwon Hwangfc2e0132015-06-22 19:05:04 +0900931 if (ret)
932 priv->pipe--;
Sean Paulf041b252014-01-30 16:19:15 -0500933
Hyungwon Hwangfc2e0132015-06-22 19:05:04 +0900934 return ret;
Sean Paul45517892014-01-30 16:19:05 -0500935}
936
Gustavo Padovan93bca242015-01-18 18:16:23 +0900937static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
Inki Dae1055b392012-10-19 17:37:35 +0900938{
Joonyoung Shimbf566082015-07-02 21:49:38 +0900939 drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Inki Dae1055b392012-10-19 17:37:35 +0900940}
941
Gustavo Padovan93bca242015-01-18 18:16:23 +0900942static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900943{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900944 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900945 struct mixer_resources *res = &mixer_ctx->mixer_res;
946
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200947 __set_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
948 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Sean Paulf041b252014-01-30 16:19:15 -0500949 return 0;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900950
951 /* enable vsync interrupt */
Andrzej Hajdafc0732482015-07-09 08:25:40 +0200952 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
953 mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900954
955 return 0;
956}
957
Gustavo Padovan93bca242015-01-18 18:16:23 +0900958static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900959{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900960 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900961 struct mixer_resources *res = &mixer_ctx->mixer_res;
962
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200963 __clear_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
964
965 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Andrzej Hajda947710c2015-07-09 08:25:41 +0200966 return;
Andrzej Hajda947710c2015-07-09 08:25:41 +0200967
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900968 /* disable vsync interrupt */
Andrzej Hajdafc0732482015-07-09 08:25:40 +0200969 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900970 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
971}
972
Marek Szyprowski3dbaab12016-01-05 13:52:52 +0100973static void mixer_atomic_begin(struct exynos_drm_crtc *crtc)
974{
975 struct mixer_context *mixer_ctx = crtc->ctx;
976
977 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
978 return;
979
980 mixer_vsync_set_update(mixer_ctx, false);
981}
982
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900983static void mixer_update_plane(struct exynos_drm_crtc *crtc,
984 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900985{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900986 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900987
Marek Szyprowski40bdfb02015-12-16 13:21:42 +0100988 DRM_DEBUG_KMS("win: %d\n", plane->index);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900989
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200990 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Shirish Sdda90122013-01-23 22:03:18 -0500991 return;
Shirish Sdda90122013-01-23 22:03:18 -0500992
Marek Szyprowski5e68fef2015-12-16 13:21:48 +0100993 if (plane->index == VP_DEFAULT_WIN)
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900994 vp_video_buffer(mixer_ctx, plane);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900995 else
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900996 mixer_graph_buffer(mixer_ctx, plane);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900997}
998
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900999static void mixer_disable_plane(struct exynos_drm_crtc *crtc,
1000 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001001{
Gustavo Padovan93bca242015-01-18 18:16:23 +09001002 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001003 struct mixer_resources *res = &mixer_ctx->mixer_res;
1004 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001005
Marek Szyprowski40bdfb02015-12-16 13:21:42 +01001006 DRM_DEBUG_KMS("win: %d\n", plane->index);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001007
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001008 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Prathyush Kdb43fd12012-12-06 20:16:05 +05301009 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301010
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001011 spin_lock_irqsave(&res->reg_slock, flags);
Marek Szyprowskia2cb9112015-12-16 13:21:44 +01001012 mixer_cfg_layer(mixer_ctx, plane->index, 0, false);
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001013 spin_unlock_irqrestore(&res->reg_slock, flags);
1014}
1015
1016static void mixer_atomic_flush(struct exynos_drm_crtc *crtc)
1017{
1018 struct mixer_context *mixer_ctx = crtc->ctx;
1019
1020 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
1021 return;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001022
1023 mixer_vsync_set_update(mixer_ctx, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001024}
1025
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001026static void mixer_enable(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301027{
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001028 struct mixer_context *ctx = crtc->ctx;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301029 struct mixer_resources *res = &ctx->mixer_res;
1030
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001031 if (test_bit(MXR_BIT_POWERED, &ctx->flags))
Prathyush Kdb43fd12012-12-06 20:16:05 +05301032 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301033
Sean Paulaf65c802014-01-30 16:19:27 -05001034 pm_runtime_get_sync(ctx->dev);
1035
Andrzej Hajdaa121d172016-03-23 14:26:01 +01001036 exynos_drm_pipe_clk_enable(crtc, true);
1037
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001038 mixer_vsync_set_update(ctx, false);
1039
Rahul Sharmad74ed932014-06-23 11:02:24 +05301040 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
1041
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +02001042 if (test_bit(MXR_BIT_VSYNC, &ctx->flags)) {
Andrzej Hajdafc0732482015-07-09 08:25:40 +02001043 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +02001044 mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
1045 }
Prathyush Kdb43fd12012-12-06 20:16:05 +05301046 mixer_win_reset(ctx);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001047
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001048 mixer_vsync_set_update(ctx, true);
1049
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001050 set_bit(MXR_BIT_POWERED, &ctx->flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301051}
1052
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001053static void mixer_disable(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301054{
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001055 struct mixer_context *ctx = crtc->ctx;
Joonyoung Shimc329f662015-06-12 20:34:28 +09001056 int i;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301057
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001058 if (!test_bit(MXR_BIT_POWERED, &ctx->flags))
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301059 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301060
Rahul Sharma381be022014-06-23 11:02:22 +05301061 mixer_stop(ctx);
Tobias Jakobic0734fb2015-05-06 14:10:21 +02001062 mixer_regs_dump(ctx);
Joonyoung Shimc329f662015-06-12 20:34:28 +09001063
1064 for (i = 0; i < MIXER_WIN_NR; i++)
Gustavo Padovan1e1d1392015-08-03 14:39:36 +09001065 mixer_disable_plane(crtc, &ctx->planes[i]);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301066
Andrzej Hajdaa121d172016-03-23 14:26:01 +01001067 exynos_drm_pipe_clk_enable(crtc, false);
1068
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001069 pm_runtime_put(ctx->dev);
1070
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001071 clear_bit(MXR_BIT_POWERED, &ctx->flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301072}
1073
Sean Paulf041b252014-01-30 16:19:15 -05001074/* Only valid for Mixer version 16.0.33.0 */
Andrzej Hajda3ae24362015-10-26 13:03:40 +01001075static int mixer_atomic_check(struct exynos_drm_crtc *crtc,
1076 struct drm_crtc_state *state)
Sean Paulf041b252014-01-30 16:19:15 -05001077{
Andrzej Hajda3ae24362015-10-26 13:03:40 +01001078 struct drm_display_mode *mode = &state->adjusted_mode;
Sean Paulf041b252014-01-30 16:19:15 -05001079 u32 w, h;
1080
1081 w = mode->hdisplay;
1082 h = mode->vdisplay;
1083
1084 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
1085 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1086 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1087
1088 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
1089 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1090 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1091 return 0;
1092
1093 return -EINVAL;
1094}
1095
Krzysztof Kozlowskif3aaf762015-05-07 09:04:45 +09001096static const struct exynos_drm_crtc_ops mixer_crtc_ops = {
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001097 .enable = mixer_enable,
1098 .disable = mixer_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001099 .enable_vblank = mixer_enable_vblank,
1100 .disable_vblank = mixer_disable_vblank,
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001101 .atomic_begin = mixer_atomic_begin,
Gustavo Padovan9cc76102015-08-03 14:38:05 +09001102 .update_plane = mixer_update_plane,
1103 .disable_plane = mixer_disable_plane,
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001104 .atomic_flush = mixer_atomic_flush,
Andrzej Hajda3ae24362015-10-26 13:03:40 +01001105 .atomic_check = mixer_atomic_check,
Sean Paulf041b252014-01-30 16:19:15 -05001106};
Rahul Sharma0ea68222013-01-15 08:11:06 -05001107
Rahul Sharmadef5e092013-06-19 18:21:08 +05301108static struct mixer_drv_data exynos5420_mxr_drv_data = {
1109 .version = MXR_VER_128_0_0_184,
1110 .is_vp_enabled = 0,
1111};
1112
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301113static struct mixer_drv_data exynos5250_mxr_drv_data = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301114 .version = MXR_VER_16_0_33_0,
1115 .is_vp_enabled = 0,
1116};
1117
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001118static struct mixer_drv_data exynos4212_mxr_drv_data = {
1119 .version = MXR_VER_0_0_0_16,
1120 .is_vp_enabled = 1,
1121};
1122
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301123static struct mixer_drv_data exynos4210_mxr_drv_data = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301124 .version = MXR_VER_0_0_0_16,
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301125 .is_vp_enabled = 1,
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001126 .has_sclk = 1,
Rahul Sharma1e123442012-10-04 20:48:51 +05301127};
1128
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301129static struct of_device_id mixer_match_types[] = {
1130 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001131 .compatible = "samsung,exynos4210-mixer",
1132 .data = &exynos4210_mxr_drv_data,
1133 }, {
1134 .compatible = "samsung,exynos4212-mixer",
1135 .data = &exynos4212_mxr_drv_data,
1136 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301137 .compatible = "samsung,exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301138 .data = &exynos5250_mxr_drv_data,
1139 }, {
1140 .compatible = "samsung,exynos5250-mixer",
1141 .data = &exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301142 }, {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301143 .compatible = "samsung,exynos5420-mixer",
1144 .data = &exynos5420_mxr_drv_data,
1145 }, {
Rahul Sharma1e123442012-10-04 20:48:51 +05301146 /* end node */
1147 }
1148};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001149MODULE_DEVICE_TABLE(of, mixer_match_types);
Rahul Sharma1e123442012-10-04 20:48:51 +05301150
Inki Daef37cd5e2014-05-09 14:25:20 +09001151static int mixer_bind(struct device *dev, struct device *manager, void *data)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001152{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001153 struct mixer_context *ctx = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09001154 struct drm_device *drm_dev = data;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001155 struct exynos_drm_plane *exynos_plane;
Marek Szyprowskifd2d2fc22015-11-30 14:53:25 +01001156 unsigned int i;
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +09001157 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001158
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001159 ret = mixer_initialize(ctx, drm_dev);
1160 if (ret)
1161 return ret;
1162
Marek Szyprowskifd2d2fc22015-11-30 14:53:25 +01001163 for (i = 0; i < MIXER_WIN_NR; i++) {
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001164 if (i == VP_DEFAULT_WIN && !test_bit(MXR_BIT_VP_ENABLED,
1165 &ctx->flags))
Marek Szyprowskiab144202015-11-30 14:53:24 +01001166 continue;
1167
Marek Szyprowski40bdfb02015-12-16 13:21:42 +01001168 ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
Marek Szyprowskifd2d2fc22015-11-30 14:53:25 +01001169 1 << ctx->pipe, &plane_configs[i]);
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001170 if (ret)
1171 return ret;
1172 }
1173
Gustavo Padovan5d3d0992015-10-12 22:07:48 +09001174 exynos_plane = &ctx->planes[DEFAULT_WIN];
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001175 ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
1176 ctx->pipe, EXYNOS_DISPLAY_TYPE_HDMI,
1177 &mixer_crtc_ops, ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001178 if (IS_ERR(ctx->crtc)) {
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001179 mixer_ctx_remove(ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001180 ret = PTR_ERR(ctx->crtc);
1181 goto free_ctx;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001182 }
1183
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001184 return 0;
Gustavo Padovan93bca242015-01-18 18:16:23 +09001185
1186free_ctx:
1187 devm_kfree(dev, ctx);
1188 return ret;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001189}
1190
1191static void mixer_unbind(struct device *dev, struct device *master, void *data)
1192{
1193 struct mixer_context *ctx = dev_get_drvdata(dev);
1194
Gustavo Padovan93bca242015-01-18 18:16:23 +09001195 mixer_ctx_remove(ctx);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001196}
1197
1198static const struct component_ops mixer_component_ops = {
1199 .bind = mixer_bind,
1200 .unbind = mixer_unbind,
1201};
1202
1203static int mixer_probe(struct platform_device *pdev)
1204{
1205 struct device *dev = &pdev->dev;
Marek Szyprowski48f61552016-04-01 15:17:46 +02001206 const struct mixer_drv_data *drv;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001207 struct mixer_context *ctx;
1208 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001209
Sean Paulf041b252014-01-30 16:19:15 -05001210 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1211 if (!ctx) {
1212 DRM_ERROR("failed to alloc mixer context.\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001213 return -ENOMEM;
Sean Paulf041b252014-01-30 16:19:15 -05001214 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001215
Marek Szyprowski48f61552016-04-01 15:17:46 +02001216 drv = of_device_get_match_data(dev);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301217
Sean Paul45517892014-01-30 16:19:05 -05001218 ctx->pdev = pdev;
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001219 ctx->dev = dev;
Rahul Sharma1e123442012-10-04 20:48:51 +05301220 ctx->mxr_ver = drv->version;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001221
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001222 if (drv->is_vp_enabled)
1223 __set_bit(MXR_BIT_VP_ENABLED, &ctx->flags);
1224 if (drv->has_sclk)
1225 __set_bit(MXR_BIT_HAS_SCLK, &ctx->flags);
1226
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001227 platform_set_drvdata(pdev, ctx);
Inki Daedf5225b2014-05-29 18:28:02 +09001228
Inki Daedf5225b2014-05-29 18:28:02 +09001229 ret = component_add(&pdev->dev, &mixer_component_ops);
Andrzej Hajda86650402015-06-11 23:23:37 +09001230 if (!ret)
1231 pm_runtime_enable(dev);
Inki Daedf5225b2014-05-29 18:28:02 +09001232
1233 return ret;
Inki Daef37cd5e2014-05-09 14:25:20 +09001234}
1235
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001236static int mixer_remove(struct platform_device *pdev)
1237{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001238 pm_runtime_disable(&pdev->dev);
1239
Inki Daedf5225b2014-05-29 18:28:02 +09001240 component_del(&pdev->dev, &mixer_component_ops);
Inki Daedf5225b2014-05-29 18:28:02 +09001241
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001242 return 0;
1243}
1244
Arnd Bergmanne0fea7e2015-11-17 16:08:36 +01001245static int __maybe_unused exynos_mixer_suspend(struct device *dev)
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001246{
1247 struct mixer_context *ctx = dev_get_drvdata(dev);
1248 struct mixer_resources *res = &ctx->mixer_res;
1249
1250 clk_disable_unprepare(res->hdmi);
1251 clk_disable_unprepare(res->mixer);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001252 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001253 clk_disable_unprepare(res->vp);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001254 if (test_bit(MXR_BIT_HAS_SCLK, &ctx->flags))
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001255 clk_disable_unprepare(res->sclk_mixer);
1256 }
1257
1258 return 0;
1259}
1260
Arnd Bergmanne0fea7e2015-11-17 16:08:36 +01001261static int __maybe_unused exynos_mixer_resume(struct device *dev)
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001262{
1263 struct mixer_context *ctx = dev_get_drvdata(dev);
1264 struct mixer_resources *res = &ctx->mixer_res;
1265 int ret;
1266
1267 ret = clk_prepare_enable(res->mixer);
1268 if (ret < 0) {
1269 DRM_ERROR("Failed to prepare_enable the mixer clk [%d]\n", ret);
1270 return ret;
1271 }
1272 ret = clk_prepare_enable(res->hdmi);
1273 if (ret < 0) {
1274 DRM_ERROR("Failed to prepare_enable the hdmi clk [%d]\n", ret);
1275 return ret;
1276 }
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001277 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001278 ret = clk_prepare_enable(res->vp);
1279 if (ret < 0) {
1280 DRM_ERROR("Failed to prepare_enable the vp clk [%d]\n",
1281 ret);
1282 return ret;
1283 }
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001284 if (test_bit(MXR_BIT_HAS_SCLK, &ctx->flags)) {
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001285 ret = clk_prepare_enable(res->sclk_mixer);
1286 if (ret < 0) {
1287 DRM_ERROR("Failed to prepare_enable the " \
1288 "sclk_mixer clk [%d]\n",
1289 ret);
1290 return ret;
1291 }
1292 }
1293 }
1294
1295 return 0;
1296}
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001297
1298static const struct dev_pm_ops exynos_mixer_pm_ops = {
1299 SET_RUNTIME_PM_OPS(exynos_mixer_suspend, exynos_mixer_resume, NULL)
1300};
1301
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001302struct platform_driver mixer_driver = {
1303 .driver = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301304 .name = "exynos-mixer",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001305 .owner = THIS_MODULE,
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001306 .pm = &exynos_mixer_pm_ops,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301307 .of_match_table = mixer_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001308 },
1309 .probe = mixer_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001310 .remove = mixer_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001311};