blob: edb20a34c66c06f1533513f02ed9eaceedeed63b [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;
757
758 spin_lock(&res->reg_slock);
759
760 /* read interrupt status for handling and clearing flags for VSYNC */
761 val = mixer_reg_read(res, MXR_INT_STATUS);
762
763 /* handling VSYNC */
764 if (val & MXR_INT_STATUS_VSYNC) {
Andrzej Hajda81a464d2015-07-09 10:07:53 +0200765 /* vsync interrupt use different bit for read and clear */
766 val |= MXR_INT_CLEAR_VSYNC;
767 val &= ~MXR_INT_STATUS_VSYNC;
768
Sean Paul45517892014-01-30 16:19:05 -0500769 /* interlace scan need to check shadow register */
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900770 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
Sean Paul45517892014-01-30 16:19:05 -0500771 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
772 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
773 if (base != shadow)
774 goto out;
775
776 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
777 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
778 if (base != shadow)
779 goto out;
780 }
781
Gustavo Padovaneafd5402015-07-16 12:23:32 -0300782 drm_crtc_handle_vblank(&ctx->crtc->base);
Sean Paul45517892014-01-30 16:19:05 -0500783 }
784
785out:
786 /* clear interrupts */
Sean Paul45517892014-01-30 16:19:05 -0500787 mixer_reg_write(res, MXR_INT_STATUS, val);
788
789 spin_unlock(&res->reg_slock);
790
791 return IRQ_HANDLED;
792}
793
794static int mixer_resources_init(struct mixer_context *mixer_ctx)
795{
796 struct device *dev = &mixer_ctx->pdev->dev;
797 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
798 struct resource *res;
799 int ret;
800
801 spin_lock_init(&mixer_res->reg_slock);
802
803 mixer_res->mixer = devm_clk_get(dev, "mixer");
804 if (IS_ERR(mixer_res->mixer)) {
805 dev_err(dev, "failed to get clock 'mixer'\n");
806 return -ENODEV;
807 }
808
Marek Szyprowski04427ec2015-02-02 14:20:28 +0100809 mixer_res->hdmi = devm_clk_get(dev, "hdmi");
810 if (IS_ERR(mixer_res->hdmi)) {
811 dev_err(dev, "failed to get clock 'hdmi'\n");
812 return PTR_ERR(mixer_res->hdmi);
813 }
814
Sean Paul45517892014-01-30 16:19:05 -0500815 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
816 if (IS_ERR(mixer_res->sclk_hdmi)) {
817 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
818 return -ENODEV;
819 }
820 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
821 if (res == NULL) {
822 dev_err(dev, "get memory resource failed.\n");
823 return -ENXIO;
824 }
825
826 mixer_res->mixer_regs = devm_ioremap(dev, res->start,
827 resource_size(res));
828 if (mixer_res->mixer_regs == NULL) {
829 dev_err(dev, "register mapping failed.\n");
830 return -ENXIO;
831 }
832
833 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
834 if (res == NULL) {
835 dev_err(dev, "get interrupt resource failed.\n");
836 return -ENXIO;
837 }
838
839 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
840 0, "drm_mixer", mixer_ctx);
841 if (ret) {
842 dev_err(dev, "request interrupt failed.\n");
843 return ret;
844 }
845 mixer_res->irq = res->start;
846
847 return 0;
848}
849
850static int vp_resources_init(struct mixer_context *mixer_ctx)
851{
852 struct device *dev = &mixer_ctx->pdev->dev;
853 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
854 struct resource *res;
855
856 mixer_res->vp = devm_clk_get(dev, "vp");
857 if (IS_ERR(mixer_res->vp)) {
858 dev_err(dev, "failed to get clock 'vp'\n");
859 return -ENODEV;
860 }
Sean Paul45517892014-01-30 16:19:05 -0500861
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900862 if (test_bit(MXR_BIT_HAS_SCLK, &mixer_ctx->flags)) {
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200863 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
864 if (IS_ERR(mixer_res->sclk_mixer)) {
865 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
866 return -ENODEV;
867 }
868 mixer_res->mout_mixer = devm_clk_get(dev, "mout_mixer");
869 if (IS_ERR(mixer_res->mout_mixer)) {
870 dev_err(dev, "failed to get clock 'mout_mixer'\n");
871 return -ENODEV;
872 }
873
874 if (mixer_res->sclk_hdmi && mixer_res->mout_mixer)
875 clk_set_parent(mixer_res->mout_mixer,
876 mixer_res->sclk_hdmi);
877 }
Sean Paul45517892014-01-30 16:19:05 -0500878
879 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
880 if (res == NULL) {
881 dev_err(dev, "get memory resource failed.\n");
882 return -ENXIO;
883 }
884
885 mixer_res->vp_regs = devm_ioremap(dev, res->start,
886 resource_size(res));
887 if (mixer_res->vp_regs == NULL) {
888 dev_err(dev, "register mapping failed.\n");
889 return -ENXIO;
890 }
891
892 return 0;
893}
894
Gustavo Padovan93bca242015-01-18 18:16:23 +0900895static int mixer_initialize(struct mixer_context *mixer_ctx,
Inki Daef37cd5e2014-05-09 14:25:20 +0900896 struct drm_device *drm_dev)
Sean Paul45517892014-01-30 16:19:05 -0500897{
898 int ret;
Inki Daef37cd5e2014-05-09 14:25:20 +0900899 struct exynos_drm_private *priv;
900 priv = drm_dev->dev_private;
Sean Paul45517892014-01-30 16:19:05 -0500901
Gustavo Padovaneb88e422014-11-26 16:43:27 -0200902 mixer_ctx->drm_dev = drm_dev;
Gustavo Padovan8a326ed2014-11-04 18:44:47 -0200903 mixer_ctx->pipe = priv->pipe++;
Sean Paul45517892014-01-30 16:19:05 -0500904
905 /* acquire resources: regs, irqs, clocks */
906 ret = mixer_resources_init(mixer_ctx);
907 if (ret) {
908 DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
909 return ret;
910 }
911
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900912 if (test_bit(MXR_BIT_VP_ENABLED, &mixer_ctx->flags)) {
Sean Paul45517892014-01-30 16:19:05 -0500913 /* acquire vp resources: regs, irqs, clocks */
914 ret = vp_resources_init(mixer_ctx);
915 if (ret) {
916 DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
917 return ret;
918 }
919 }
920
Joonyoung Shimeb7a3fc2015-07-02 21:49:39 +0900921 ret = drm_iommu_attach_device(drm_dev, mixer_ctx->dev);
Hyungwon Hwangfc2e0132015-06-22 19:05:04 +0900922 if (ret)
923 priv->pipe--;
Sean Paulf041b252014-01-30 16:19:15 -0500924
Hyungwon Hwangfc2e0132015-06-22 19:05:04 +0900925 return ret;
Sean Paul45517892014-01-30 16:19:05 -0500926}
927
Gustavo Padovan93bca242015-01-18 18:16:23 +0900928static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
Inki Dae1055b392012-10-19 17:37:35 +0900929{
Joonyoung Shimbf566082015-07-02 21:49:38 +0900930 drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Inki Dae1055b392012-10-19 17:37:35 +0900931}
932
Gustavo Padovan93bca242015-01-18 18:16:23 +0900933static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900934{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900935 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900936 struct mixer_resources *res = &mixer_ctx->mixer_res;
937
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200938 __set_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
939 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Sean Paulf041b252014-01-30 16:19:15 -0500940 return 0;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900941
942 /* enable vsync interrupt */
Andrzej Hajdafc0732482015-07-09 08:25:40 +0200943 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
944 mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900945
946 return 0;
947}
948
Gustavo Padovan93bca242015-01-18 18:16:23 +0900949static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900950{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900951 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900952 struct mixer_resources *res = &mixer_ctx->mixer_res;
953
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200954 __clear_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
955
956 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Andrzej Hajda947710c2015-07-09 08:25:41 +0200957 return;
Andrzej Hajda947710c2015-07-09 08:25:41 +0200958
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900959 /* disable vsync interrupt */
Andrzej Hajdafc0732482015-07-09 08:25:40 +0200960 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900961 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
962}
963
Marek Szyprowski3dbaab12016-01-05 13:52:52 +0100964static void mixer_atomic_begin(struct exynos_drm_crtc *crtc)
965{
966 struct mixer_context *mixer_ctx = crtc->ctx;
967
968 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
969 return;
970
971 mixer_vsync_set_update(mixer_ctx, false);
972}
973
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900974static void mixer_update_plane(struct exynos_drm_crtc *crtc,
975 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900976{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900977 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900978
Marek Szyprowski40bdfb02015-12-16 13:21:42 +0100979 DRM_DEBUG_KMS("win: %d\n", plane->index);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900980
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200981 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Shirish Sdda90122013-01-23 22:03:18 -0500982 return;
Shirish Sdda90122013-01-23 22:03:18 -0500983
Marek Szyprowski5e68fef2015-12-16 13:21:48 +0100984 if (plane->index == VP_DEFAULT_WIN)
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900985 vp_video_buffer(mixer_ctx, plane);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900986 else
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900987 mixer_graph_buffer(mixer_ctx, plane);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900988}
989
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900990static void mixer_disable_plane(struct exynos_drm_crtc *crtc,
991 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900992{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900993 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900994 struct mixer_resources *res = &mixer_ctx->mixer_res;
995 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900996
Marek Szyprowski40bdfb02015-12-16 13:21:42 +0100997 DRM_DEBUG_KMS("win: %d\n", plane->index);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900998
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200999 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Prathyush Kdb43fd12012-12-06 20:16:05 +05301000 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301001
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001002 spin_lock_irqsave(&res->reg_slock, flags);
Marek Szyprowskia2cb9112015-12-16 13:21:44 +01001003 mixer_cfg_layer(mixer_ctx, plane->index, 0, false);
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001004 spin_unlock_irqrestore(&res->reg_slock, flags);
1005}
1006
1007static void mixer_atomic_flush(struct exynos_drm_crtc *crtc)
1008{
1009 struct mixer_context *mixer_ctx = crtc->ctx;
1010
1011 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
1012 return;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001013
1014 mixer_vsync_set_update(mixer_ctx, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001015}
1016
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001017static void mixer_enable(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301018{
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001019 struct mixer_context *ctx = crtc->ctx;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301020 struct mixer_resources *res = &ctx->mixer_res;
1021
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001022 if (test_bit(MXR_BIT_POWERED, &ctx->flags))
Prathyush Kdb43fd12012-12-06 20:16:05 +05301023 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301024
Sean Paulaf65c802014-01-30 16:19:27 -05001025 pm_runtime_get_sync(ctx->dev);
1026
Andrzej Hajdaa121d172016-03-23 14:26:01 +01001027 exynos_drm_pipe_clk_enable(crtc, true);
1028
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001029 mixer_vsync_set_update(ctx, false);
1030
Rahul Sharmad74ed932014-06-23 11:02:24 +05301031 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
1032
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +02001033 if (test_bit(MXR_BIT_VSYNC, &ctx->flags)) {
Andrzej Hajdafc0732482015-07-09 08:25:40 +02001034 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +02001035 mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
1036 }
Prathyush Kdb43fd12012-12-06 20:16:05 +05301037 mixer_win_reset(ctx);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001038
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001039 mixer_vsync_set_update(ctx, true);
1040
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001041 set_bit(MXR_BIT_POWERED, &ctx->flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301042}
1043
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001044static void mixer_disable(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301045{
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001046 struct mixer_context *ctx = crtc->ctx;
Joonyoung Shimc329f662015-06-12 20:34:28 +09001047 int i;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301048
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001049 if (!test_bit(MXR_BIT_POWERED, &ctx->flags))
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301050 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301051
Rahul Sharma381be022014-06-23 11:02:22 +05301052 mixer_stop(ctx);
Tobias Jakobic0734fb2015-05-06 14:10:21 +02001053 mixer_regs_dump(ctx);
Joonyoung Shimc329f662015-06-12 20:34:28 +09001054
1055 for (i = 0; i < MIXER_WIN_NR; i++)
Gustavo Padovan1e1d1392015-08-03 14:39:36 +09001056 mixer_disable_plane(crtc, &ctx->planes[i]);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301057
Andrzej Hajdaa121d172016-03-23 14:26:01 +01001058 exynos_drm_pipe_clk_enable(crtc, false);
1059
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001060 pm_runtime_put(ctx->dev);
1061
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001062 clear_bit(MXR_BIT_POWERED, &ctx->flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301063}
1064
Sean Paulf041b252014-01-30 16:19:15 -05001065/* Only valid for Mixer version 16.0.33.0 */
Andrzej Hajda3ae24362015-10-26 13:03:40 +01001066static int mixer_atomic_check(struct exynos_drm_crtc *crtc,
1067 struct drm_crtc_state *state)
Sean Paulf041b252014-01-30 16:19:15 -05001068{
Andrzej Hajda3ae24362015-10-26 13:03:40 +01001069 struct drm_display_mode *mode = &state->adjusted_mode;
Sean Paulf041b252014-01-30 16:19:15 -05001070 u32 w, h;
1071
1072 w = mode->hdisplay;
1073 h = mode->vdisplay;
1074
1075 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
1076 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1077 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1078
1079 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
1080 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1081 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1082 return 0;
1083
1084 return -EINVAL;
1085}
1086
Krzysztof Kozlowskif3aaf762015-05-07 09:04:45 +09001087static const struct exynos_drm_crtc_ops mixer_crtc_ops = {
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001088 .enable = mixer_enable,
1089 .disable = mixer_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001090 .enable_vblank = mixer_enable_vblank,
1091 .disable_vblank = mixer_disable_vblank,
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001092 .atomic_begin = mixer_atomic_begin,
Gustavo Padovan9cc76102015-08-03 14:38:05 +09001093 .update_plane = mixer_update_plane,
1094 .disable_plane = mixer_disable_plane,
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001095 .atomic_flush = mixer_atomic_flush,
Andrzej Hajda3ae24362015-10-26 13:03:40 +01001096 .atomic_check = mixer_atomic_check,
Sean Paulf041b252014-01-30 16:19:15 -05001097};
Rahul Sharma0ea68222013-01-15 08:11:06 -05001098
Rahul Sharmadef5e092013-06-19 18:21:08 +05301099static struct mixer_drv_data exynos5420_mxr_drv_data = {
1100 .version = MXR_VER_128_0_0_184,
1101 .is_vp_enabled = 0,
1102};
1103
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301104static struct mixer_drv_data exynos5250_mxr_drv_data = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301105 .version = MXR_VER_16_0_33_0,
1106 .is_vp_enabled = 0,
1107};
1108
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001109static struct mixer_drv_data exynos4212_mxr_drv_data = {
1110 .version = MXR_VER_0_0_0_16,
1111 .is_vp_enabled = 1,
1112};
1113
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301114static struct mixer_drv_data exynos4210_mxr_drv_data = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301115 .version = MXR_VER_0_0_0_16,
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301116 .is_vp_enabled = 1,
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001117 .has_sclk = 1,
Rahul Sharma1e123442012-10-04 20:48:51 +05301118};
1119
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301120static struct of_device_id mixer_match_types[] = {
1121 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001122 .compatible = "samsung,exynos4210-mixer",
1123 .data = &exynos4210_mxr_drv_data,
1124 }, {
1125 .compatible = "samsung,exynos4212-mixer",
1126 .data = &exynos4212_mxr_drv_data,
1127 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301128 .compatible = "samsung,exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301129 .data = &exynos5250_mxr_drv_data,
1130 }, {
1131 .compatible = "samsung,exynos5250-mixer",
1132 .data = &exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301133 }, {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301134 .compatible = "samsung,exynos5420-mixer",
1135 .data = &exynos5420_mxr_drv_data,
1136 }, {
Rahul Sharma1e123442012-10-04 20:48:51 +05301137 /* end node */
1138 }
1139};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001140MODULE_DEVICE_TABLE(of, mixer_match_types);
Rahul Sharma1e123442012-10-04 20:48:51 +05301141
Inki Daef37cd5e2014-05-09 14:25:20 +09001142static int mixer_bind(struct device *dev, struct device *manager, void *data)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001143{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001144 struct mixer_context *ctx = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09001145 struct drm_device *drm_dev = data;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001146 struct exynos_drm_plane *exynos_plane;
Marek Szyprowskifd2d2fc22015-11-30 14:53:25 +01001147 unsigned int i;
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +09001148 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001149
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001150 ret = mixer_initialize(ctx, drm_dev);
1151 if (ret)
1152 return ret;
1153
Marek Szyprowskifd2d2fc22015-11-30 14:53:25 +01001154 for (i = 0; i < MIXER_WIN_NR; i++) {
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001155 if (i == VP_DEFAULT_WIN && !test_bit(MXR_BIT_VP_ENABLED,
1156 &ctx->flags))
Marek Szyprowskiab144202015-11-30 14:53:24 +01001157 continue;
1158
Marek Szyprowski40bdfb02015-12-16 13:21:42 +01001159 ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
Marek Szyprowskifd2d2fc22015-11-30 14:53:25 +01001160 1 << ctx->pipe, &plane_configs[i]);
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001161 if (ret)
1162 return ret;
1163 }
1164
Gustavo Padovan5d3d0992015-10-12 22:07:48 +09001165 exynos_plane = &ctx->planes[DEFAULT_WIN];
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001166 ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
1167 ctx->pipe, EXYNOS_DISPLAY_TYPE_HDMI,
1168 &mixer_crtc_ops, ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001169 if (IS_ERR(ctx->crtc)) {
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001170 mixer_ctx_remove(ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001171 ret = PTR_ERR(ctx->crtc);
1172 goto free_ctx;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001173 }
1174
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001175 return 0;
Gustavo Padovan93bca242015-01-18 18:16:23 +09001176
1177free_ctx:
1178 devm_kfree(dev, ctx);
1179 return ret;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001180}
1181
1182static void mixer_unbind(struct device *dev, struct device *master, void *data)
1183{
1184 struct mixer_context *ctx = dev_get_drvdata(dev);
1185
Gustavo Padovan93bca242015-01-18 18:16:23 +09001186 mixer_ctx_remove(ctx);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001187}
1188
1189static const struct component_ops mixer_component_ops = {
1190 .bind = mixer_bind,
1191 .unbind = mixer_unbind,
1192};
1193
1194static int mixer_probe(struct platform_device *pdev)
1195{
1196 struct device *dev = &pdev->dev;
Marek Szyprowski48f61552016-04-01 15:17:46 +02001197 const struct mixer_drv_data *drv;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001198 struct mixer_context *ctx;
1199 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001200
Sean Paulf041b252014-01-30 16:19:15 -05001201 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1202 if (!ctx) {
1203 DRM_ERROR("failed to alloc mixer context.\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001204 return -ENOMEM;
Sean Paulf041b252014-01-30 16:19:15 -05001205 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001206
Marek Szyprowski48f61552016-04-01 15:17:46 +02001207 drv = of_device_get_match_data(dev);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301208
Sean Paul45517892014-01-30 16:19:05 -05001209 ctx->pdev = pdev;
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001210 ctx->dev = dev;
Rahul Sharma1e123442012-10-04 20:48:51 +05301211 ctx->mxr_ver = drv->version;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001212
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001213 if (drv->is_vp_enabled)
1214 __set_bit(MXR_BIT_VP_ENABLED, &ctx->flags);
1215 if (drv->has_sclk)
1216 __set_bit(MXR_BIT_HAS_SCLK, &ctx->flags);
1217
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001218 platform_set_drvdata(pdev, ctx);
Inki Daedf5225b2014-05-29 18:28:02 +09001219
Inki Daedf5225b2014-05-29 18:28:02 +09001220 ret = component_add(&pdev->dev, &mixer_component_ops);
Andrzej Hajda86650402015-06-11 23:23:37 +09001221 if (!ret)
1222 pm_runtime_enable(dev);
Inki Daedf5225b2014-05-29 18:28:02 +09001223
1224 return ret;
Inki Daef37cd5e2014-05-09 14:25:20 +09001225}
1226
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001227static int mixer_remove(struct platform_device *pdev)
1228{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001229 pm_runtime_disable(&pdev->dev);
1230
Inki Daedf5225b2014-05-29 18:28:02 +09001231 component_del(&pdev->dev, &mixer_component_ops);
Inki Daedf5225b2014-05-29 18:28:02 +09001232
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001233 return 0;
1234}
1235
Arnd Bergmanne0fea7e2015-11-17 16:08:36 +01001236static int __maybe_unused exynos_mixer_suspend(struct device *dev)
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001237{
1238 struct mixer_context *ctx = dev_get_drvdata(dev);
1239 struct mixer_resources *res = &ctx->mixer_res;
1240
1241 clk_disable_unprepare(res->hdmi);
1242 clk_disable_unprepare(res->mixer);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001243 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001244 clk_disable_unprepare(res->vp);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001245 if (test_bit(MXR_BIT_HAS_SCLK, &ctx->flags))
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001246 clk_disable_unprepare(res->sclk_mixer);
1247 }
1248
1249 return 0;
1250}
1251
Arnd Bergmanne0fea7e2015-11-17 16:08:36 +01001252static int __maybe_unused exynos_mixer_resume(struct device *dev)
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001253{
1254 struct mixer_context *ctx = dev_get_drvdata(dev);
1255 struct mixer_resources *res = &ctx->mixer_res;
1256 int ret;
1257
1258 ret = clk_prepare_enable(res->mixer);
1259 if (ret < 0) {
1260 DRM_ERROR("Failed to prepare_enable the mixer clk [%d]\n", ret);
1261 return ret;
1262 }
1263 ret = clk_prepare_enable(res->hdmi);
1264 if (ret < 0) {
1265 DRM_ERROR("Failed to prepare_enable the hdmi clk [%d]\n", ret);
1266 return ret;
1267 }
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001268 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001269 ret = clk_prepare_enable(res->vp);
1270 if (ret < 0) {
1271 DRM_ERROR("Failed to prepare_enable the vp clk [%d]\n",
1272 ret);
1273 return ret;
1274 }
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001275 if (test_bit(MXR_BIT_HAS_SCLK, &ctx->flags)) {
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001276 ret = clk_prepare_enable(res->sclk_mixer);
1277 if (ret < 0) {
1278 DRM_ERROR("Failed to prepare_enable the " \
1279 "sclk_mixer clk [%d]\n",
1280 ret);
1281 return ret;
1282 }
1283 }
1284 }
1285
1286 return 0;
1287}
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001288
1289static const struct dev_pm_ops exynos_mixer_pm_ops = {
1290 SET_RUNTIME_PM_OPS(exynos_mixer_suspend, exynos_mixer_resume, NULL)
1291};
1292
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001293struct platform_driver mixer_driver = {
1294 .driver = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301295 .name = "exynos-mixer",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001296 .owner = THIS_MODULE,
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001297 .pm = &exynos_mixer_pm_ops,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301298 .of_match_table = mixer_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001299 },
1300 .probe = mixer_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001301 .remove = mixer_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001302};