blob: dc5d79465f9b7f8708c09ccf6df097b90ac2c6f7 [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 Jakobi2a6e4cd2017-03-10 15:21:54 +010048/*
49 * Mixer color space conversion coefficient triplet.
50 * Used for CSC from RGB to YCbCr.
51 * Each coefficient is a 10-bit fixed point number with
52 * sign and no integer part, i.e.
53 * [0:8] = fractional part (representing a value y = x / 2^9)
54 * [9] = sign
55 * Negative values are encoded with two's complement.
56 */
57#define MXR_CSC_C(x) ((int)((x) * 512.0) & 0x3ff)
58#define MXR_CSC_CT(a0, a1, a2) \
59 ((MXR_CSC_C(a0) << 20) | (MXR_CSC_C(a1) << 10) | (MXR_CSC_C(a2) << 0))
60
61/* YCbCr value, used for mixer background color configuration. */
62#define MXR_YCBCR_VAL(y, cb, cr) (((y) << 16) | ((cb) << 8) | ((cr) << 0))
63
Tobias Jakobi7a57ca72015-04-27 23:11:59 +020064/* The pixelformats that are natively supported by the mixer. */
65#define MXR_FORMAT_RGB565 4
66#define MXR_FORMAT_ARGB1555 5
67#define MXR_FORMAT_ARGB4444 6
68#define MXR_FORMAT_ARGB8888 7
69
Rahul Sharma1e123442012-10-04 20:48:51 +053070enum mixer_version_id {
71 MXR_VER_0_0_0_16,
72 MXR_VER_16_0_33_0,
Rahul Sharmadef5e092013-06-19 18:21:08 +053073 MXR_VER_128_0_0_184,
Rahul Sharma1e123442012-10-04 20:48:51 +053074};
75
Andrzej Hajdaa44652e2015-07-09 08:25:42 +020076enum mixer_flag_bits {
77 MXR_BIT_POWERED,
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +020078 MXR_BIT_VSYNC,
Tobias Jakobiadeb6f42016-09-22 11:36:13 +090079 MXR_BIT_INTERLACE,
80 MXR_BIT_VP_ENABLED,
81 MXR_BIT_HAS_SCLK,
Andrzej Hajdaa44652e2015-07-09 08:25:42 +020082};
83
Marek Szyprowskifbbb1e12015-08-31 00:53:57 +090084static const uint32_t mixer_formats[] = {
85 DRM_FORMAT_XRGB4444,
Tobias Jakobi26a7af32015-12-16 13:21:47 +010086 DRM_FORMAT_ARGB4444,
Marek Szyprowskifbbb1e12015-08-31 00:53:57 +090087 DRM_FORMAT_XRGB1555,
Tobias Jakobi26a7af32015-12-16 13:21:47 +010088 DRM_FORMAT_ARGB1555,
Marek Szyprowskifbbb1e12015-08-31 00:53:57 +090089 DRM_FORMAT_RGB565,
90 DRM_FORMAT_XRGB8888,
91 DRM_FORMAT_ARGB8888,
92};
93
94static const uint32_t vp_formats[] = {
95 DRM_FORMAT_NV12,
96 DRM_FORMAT_NV21,
97};
98
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090099struct mixer_context {
Sean Paul45517892014-01-30 16:19:05 -0500100 struct platform_device *pdev;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900101 struct device *dev;
Inki Dae1055b392012-10-19 17:37:35 +0900102 struct drm_device *drm_dev;
Gustavo Padovan93bca242015-01-18 18:16:23 +0900103 struct exynos_drm_crtc *crtc;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900104 struct exynos_drm_plane planes[MIXER_WIN_NR];
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200105 unsigned long flags;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +0900106
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200107 int irq;
108 void __iomem *mixer_regs;
109 void __iomem *vp_regs;
110 spinlock_t reg_slock;
111 struct clk *mixer;
112 struct clk *vp;
113 struct clk *hdmi;
114 struct clk *sclk_mixer;
115 struct clk *sclk_hdmi;
116 struct clk *mout_mixer;
Rahul Sharma1e123442012-10-04 20:48:51 +0530117 enum mixer_version_id mxr_ver;
Andrzej Hajdaacc8bf02017-09-29 12:05:39 +0200118 int scan_value;
Rahul Sharma1e123442012-10-04 20:48:51 +0530119};
120
121struct mixer_drv_data {
122 enum mixer_version_id version;
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530123 bool is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200124 bool has_sclk;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +0900125};
126
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +0100127static const struct exynos_drm_plane_config plane_configs[MIXER_WIN_NR] = {
128 {
129 .zpos = 0,
130 .type = DRM_PLANE_TYPE_PRIMARY,
131 .pixel_formats = mixer_formats,
132 .num_pixel_formats = ARRAY_SIZE(mixer_formats),
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100133 .capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE |
134 EXYNOS_DRM_PLANE_CAP_ZPOS,
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +0100135 }, {
136 .zpos = 1,
137 .type = DRM_PLANE_TYPE_CURSOR,
138 .pixel_formats = mixer_formats,
139 .num_pixel_formats = ARRAY_SIZE(mixer_formats),
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100140 .capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE |
141 EXYNOS_DRM_PLANE_CAP_ZPOS,
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +0100142 }, {
143 .zpos = 2,
144 .type = DRM_PLANE_TYPE_OVERLAY,
145 .pixel_formats = vp_formats,
146 .num_pixel_formats = ARRAY_SIZE(vp_formats),
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100147 .capabilities = EXYNOS_DRM_PLANE_CAP_SCALE |
Tobias Jakobif40031c2017-08-22 16:19:37 +0200148 EXYNOS_DRM_PLANE_CAP_ZPOS |
149 EXYNOS_DRM_PLANE_CAP_TILE,
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +0100150 },
151};
152
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900153static const u8 filter_y_horiz_tap8[] = {
154 0, -1, -1, -1, -1, -1, -1, -1,
155 -1, -1, -1, -1, -1, 0, 0, 0,
156 0, 2, 4, 5, 6, 6, 6, 6,
157 6, 5, 5, 4, 3, 2, 1, 1,
158 0, -6, -12, -16, -18, -20, -21, -20,
159 -20, -18, -16, -13, -10, -8, -5, -2,
160 127, 126, 125, 121, 114, 107, 99, 89,
161 79, 68, 57, 46, 35, 25, 16, 8,
162};
163
164static const u8 filter_y_vert_tap4[] = {
165 0, -3, -6, -8, -8, -8, -8, -7,
166 -6, -5, -4, -3, -2, -1, -1, 0,
167 127, 126, 124, 118, 111, 102, 92, 81,
168 70, 59, 48, 37, 27, 19, 11, 5,
169 0, 5, 11, 19, 27, 37, 48, 59,
170 70, 81, 92, 102, 111, 118, 124, 126,
171 0, 0, -1, -1, -2, -3, -4, -5,
172 -6, -7, -8, -8, -8, -8, -6, -3,
173};
174
175static const u8 filter_cr_horiz_tap4[] = {
176 0, -3, -6, -8, -8, -8, -8, -7,
177 -6, -5, -4, -3, -2, -1, -1, 0,
178 127, 126, 124, 118, 111, 102, 92, 81,
179 70, 59, 48, 37, 27, 19, 11, 5,
180};
181
Marek Szyprowskif657a992015-12-16 13:21:46 +0100182static inline bool is_alpha_format(unsigned int pixel_format)
183{
184 switch (pixel_format) {
185 case DRM_FORMAT_ARGB8888:
Tobias Jakobi26a7af32015-12-16 13:21:47 +0100186 case DRM_FORMAT_ARGB1555:
187 case DRM_FORMAT_ARGB4444:
Marek Szyprowskif657a992015-12-16 13:21:46 +0100188 return true;
189 default:
190 return false;
191 }
192}
193
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200194static inline u32 vp_reg_read(struct mixer_context *ctx, u32 reg_id)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900195{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200196 return readl(ctx->vp_regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900197}
198
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200199static inline void vp_reg_write(struct mixer_context *ctx, u32 reg_id,
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900200 u32 val)
201{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200202 writel(val, ctx->vp_regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900203}
204
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200205static inline void vp_reg_writemask(struct mixer_context *ctx, u32 reg_id,
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900206 u32 val, u32 mask)
207{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200208 u32 old = vp_reg_read(ctx, reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900209
210 val = (val & mask) | (old & ~mask);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200211 writel(val, ctx->vp_regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900212}
213
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200214static inline u32 mixer_reg_read(struct mixer_context *ctx, u32 reg_id)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900215{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200216 return readl(ctx->mixer_regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900217}
218
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200219static inline void mixer_reg_write(struct mixer_context *ctx, u32 reg_id,
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900220 u32 val)
221{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200222 writel(val, ctx->mixer_regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900223}
224
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200225static inline void mixer_reg_writemask(struct mixer_context *ctx,
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900226 u32 reg_id, u32 val, u32 mask)
227{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200228 u32 old = mixer_reg_read(ctx, reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900229
230 val = (val & mask) | (old & ~mask);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200231 writel(val, ctx->mixer_regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900232}
233
234static void mixer_regs_dump(struct mixer_context *ctx)
235{
236#define DUMPREG(reg_id) \
237do { \
238 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200239 (u32)readl(ctx->mixer_regs + reg_id)); \
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900240} while (0)
241
242 DUMPREG(MXR_STATUS);
243 DUMPREG(MXR_CFG);
244 DUMPREG(MXR_INT_EN);
245 DUMPREG(MXR_INT_STATUS);
246
247 DUMPREG(MXR_LAYER_CFG);
248 DUMPREG(MXR_VIDEO_CFG);
249
250 DUMPREG(MXR_GRAPHIC0_CFG);
251 DUMPREG(MXR_GRAPHIC0_BASE);
252 DUMPREG(MXR_GRAPHIC0_SPAN);
253 DUMPREG(MXR_GRAPHIC0_WH);
254 DUMPREG(MXR_GRAPHIC0_SXY);
255 DUMPREG(MXR_GRAPHIC0_DXY);
256
257 DUMPREG(MXR_GRAPHIC1_CFG);
258 DUMPREG(MXR_GRAPHIC1_BASE);
259 DUMPREG(MXR_GRAPHIC1_SPAN);
260 DUMPREG(MXR_GRAPHIC1_WH);
261 DUMPREG(MXR_GRAPHIC1_SXY);
262 DUMPREG(MXR_GRAPHIC1_DXY);
263#undef DUMPREG
264}
265
266static void vp_regs_dump(struct mixer_context *ctx)
267{
268#define DUMPREG(reg_id) \
269do { \
270 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200271 (u32) readl(ctx->vp_regs + reg_id)); \
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900272} while (0)
273
274 DUMPREG(VP_ENABLE);
275 DUMPREG(VP_SRESET);
276 DUMPREG(VP_SHADOW_UPDATE);
277 DUMPREG(VP_FIELD_ID);
278 DUMPREG(VP_MODE);
279 DUMPREG(VP_IMG_SIZE_Y);
280 DUMPREG(VP_IMG_SIZE_C);
281 DUMPREG(VP_PER_RATE_CTRL);
282 DUMPREG(VP_TOP_Y_PTR);
283 DUMPREG(VP_BOT_Y_PTR);
284 DUMPREG(VP_TOP_C_PTR);
285 DUMPREG(VP_BOT_C_PTR);
286 DUMPREG(VP_ENDIAN_MODE);
287 DUMPREG(VP_SRC_H_POSITION);
288 DUMPREG(VP_SRC_V_POSITION);
289 DUMPREG(VP_SRC_WIDTH);
290 DUMPREG(VP_SRC_HEIGHT);
291 DUMPREG(VP_DST_H_POSITION);
292 DUMPREG(VP_DST_V_POSITION);
293 DUMPREG(VP_DST_WIDTH);
294 DUMPREG(VP_DST_HEIGHT);
295 DUMPREG(VP_H_RATIO);
296 DUMPREG(VP_V_RATIO);
297
298#undef DUMPREG
299}
300
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200301static inline void vp_filter_set(struct mixer_context *ctx,
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900302 int reg_id, const u8 *data, unsigned int size)
303{
304 /* assure 4-byte align */
305 BUG_ON(size & 3);
306 for (; size; size -= 4, reg_id += 4, data += 4) {
307 u32 val = (data[0] << 24) | (data[1] << 16) |
308 (data[2] << 8) | data[3];
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200309 vp_reg_write(ctx, reg_id, val);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900310 }
311}
312
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200313static void vp_default_filter(struct mixer_context *ctx)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900314{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200315 vp_filter_set(ctx, VP_POLY8_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530316 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200317 vp_filter_set(ctx, VP_POLY4_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530318 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200319 vp_filter_set(ctx, VP_POLY4_C0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530320 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900321}
322
Marek Szyprowskif657a992015-12-16 13:21:46 +0100323static void mixer_cfg_gfx_blend(struct mixer_context *ctx, unsigned int win,
324 bool alpha)
325{
Marek Szyprowskif657a992015-12-16 13:21:46 +0100326 u32 val;
327
328 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
329 if (alpha) {
330 /* blending based on pixel alpha */
331 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
332 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
333 }
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200334 mixer_reg_writemask(ctx, MXR_GRAPHIC_CFG(win),
Marek Szyprowskif657a992015-12-16 13:21:46 +0100335 val, MXR_GRP_CFG_MISC_MASK);
336}
337
338static void mixer_cfg_vp_blend(struct mixer_context *ctx)
339{
Marek Szyprowskif657a992015-12-16 13:21:46 +0100340 u32 val;
341
342 /*
343 * No blending at the moment since the NV12/NV21 pixelformats don't
344 * have an alpha channel. However the mixer supports a global alpha
345 * value for a layer. Once this functionality is exposed, we can
346 * support blending of the video layer through this.
347 */
348 val = 0;
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200349 mixer_reg_write(ctx, MXR_VIDEO_CFG, val);
Marek Szyprowskif657a992015-12-16 13:21:46 +0100350}
351
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900352static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
353{
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900354 /* block update on vsync */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200355 mixer_reg_writemask(ctx, MXR_STATUS, enable ?
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900356 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
357
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900358 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags))
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200359 vp_reg_write(ctx, VP_SHADOW_UPDATE, enable ?
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900360 VP_SHADOW_UPDATE_ENABLE : 0);
361}
362
Andrzej Hajda3fc40ca2017-09-29 12:05:34 +0200363static void mixer_cfg_scan(struct mixer_context *ctx, int width, int height)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900364{
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900365 u32 val;
366
367 /* choosing between interlace and progressive mode */
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900368 val = test_bit(MXR_BIT_INTERLACE, &ctx->flags) ?
369 MXR_CFG_SCAN_INTERLACE : MXR_CFG_SCAN_PROGRESSIVE;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900370
Andrzej Hajdaacc8bf02017-09-29 12:05:39 +0200371 if (ctx->mxr_ver == MXR_VER_128_0_0_184)
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200372 mixer_reg_write(ctx, MXR_RESOLUTION,
Andrzej Hajda3fc40ca2017-09-29 12:05:34 +0200373 MXR_MXR_RES_HEIGHT(height) | MXR_MXR_RES_WIDTH(width));
Andrzej Hajdaacc8bf02017-09-29 12:05:39 +0200374 else
375 val |= ctx->scan_value;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900376
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200377 mixer_reg_writemask(ctx, MXR_CFG, val, MXR_CFG_SCAN_MASK);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900378}
379
380static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
381{
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900382 u32 val;
383
Tobias Jakobi2a39db02017-03-10 14:30:16 +0100384 switch (height) {
385 case 480:
386 case 576:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900387 val = MXR_CFG_RGB601_0_255;
Tobias Jakobi2a39db02017-03-10 14:30:16 +0100388 break;
389 case 720:
390 case 1080:
391 default:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900392 val = MXR_CFG_RGB709_16_235;
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100393 /* Configure the BT.709 CSC matrix for full range RGB. */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200394 mixer_reg_write(ctx, MXR_CM_COEFF_Y,
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100395 MXR_CSC_CT( 0.184, 0.614, 0.063) |
396 MXR_CM_COEFF_RGB_FULL);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200397 mixer_reg_write(ctx, MXR_CM_COEFF_CB,
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100398 MXR_CSC_CT(-0.102, -0.338, 0.440));
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200399 mixer_reg_write(ctx, MXR_CM_COEFF_CR,
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100400 MXR_CSC_CT( 0.440, -0.399, -0.040));
Tobias Jakobi2a39db02017-03-10 14:30:16 +0100401 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900402 }
403
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200404 mixer_reg_writemask(ctx, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900405}
406
Tobias Jakobi5b1d5bc2015-05-06 14:10:22 +0200407static void mixer_cfg_layer(struct mixer_context *ctx, unsigned int win,
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100408 unsigned int priority, bool enable)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900409{
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900410 u32 val = enable ? ~0 : 0;
411
412 switch (win) {
413 case 0:
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200414 mixer_reg_writemask(ctx, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
415 mixer_reg_writemask(ctx, MXR_LAYER_CFG,
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100416 MXR_LAYER_CFG_GRP0_VAL(priority),
417 MXR_LAYER_CFG_GRP0_MASK);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900418 break;
419 case 1:
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200420 mixer_reg_writemask(ctx, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
421 mixer_reg_writemask(ctx, MXR_LAYER_CFG,
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100422 MXR_LAYER_CFG_GRP1_VAL(priority),
423 MXR_LAYER_CFG_GRP1_MASK);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900424
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900425 break;
Marek Szyprowski5e68fef2015-12-16 13:21:48 +0100426 case VP_DEFAULT_WIN:
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900427 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200428 vp_reg_writemask(ctx, VP_ENABLE, val, VP_ENABLE_ON);
429 mixer_reg_writemask(ctx, MXR_CFG, val,
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530430 MXR_CFG_VP_ENABLE);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200431 mixer_reg_writemask(ctx, MXR_LAYER_CFG,
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100432 MXR_LAYER_CFG_VP_VAL(priority),
433 MXR_LAYER_CFG_VP_MASK);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530434 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900435 break;
436 }
437}
438
439static void mixer_run(struct mixer_context *ctx)
440{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200441 mixer_reg_writemask(ctx, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900442}
443
Rahul Sharma381be022014-06-23 11:02:22 +0530444static void mixer_stop(struct mixer_context *ctx)
445{
Rahul Sharma381be022014-06-23 11:02:22 +0530446 int timeout = 20;
447
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200448 mixer_reg_writemask(ctx, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
Rahul Sharma381be022014-06-23 11:02:22 +0530449
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200450 while (!(mixer_reg_read(ctx, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
Rahul Sharma381be022014-06-23 11:02:22 +0530451 --timeout)
452 usleep_range(10000, 12000);
Rahul Sharma381be022014-06-23 11:02:22 +0530453}
454
Andrzej Hajda521d98a2017-09-29 12:05:32 +0200455static void mixer_commit(struct mixer_context *ctx)
456{
457 struct drm_display_mode *mode = &ctx->crtc->base.state->adjusted_mode;
458
Andrzej Hajda3fc40ca2017-09-29 12:05:34 +0200459 mixer_cfg_scan(ctx, mode->hdisplay, mode->vdisplay);
Andrzej Hajda521d98a2017-09-29 12:05:32 +0200460 mixer_cfg_rgb_fmt(ctx, mode->vdisplay);
461 mixer_run(ctx);
462}
463
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900464static void vp_video_buffer(struct mixer_context *ctx,
465 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900466{
Marek Szyprowski0114f402015-11-30 14:53:22 +0100467 struct exynos_drm_plane_state *state =
468 to_exynos_plane_state(plane->base.state);
Marek Szyprowski0114f402015-11-30 14:53:22 +0100469 struct drm_framebuffer *fb = state->base.fb;
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200470 unsigned int priority = state->base.normalized_zpos + 1;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900471 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900472 dma_addr_t luma_addr[2], chroma_addr[2];
Tobias Jakobi0f752692017-08-22 16:19:38 +0200473 bool is_tiled, is_nv21;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900474 u32 val;
475
Tobias Jakobi0f752692017-08-22 16:19:38 +0200476 is_nv21 = (fb->format->format == DRM_FORMAT_NV21);
477 is_tiled = (fb->modifier == DRM_FORMAT_MOD_SAMSUNG_64_32_TILE);
Tobias Jakobif40031c2017-08-22 16:19:37 +0200478
Marek Szyprowski0488f502015-11-30 14:53:21 +0100479 luma_addr[0] = exynos_drm_fb_dma_addr(fb, 0);
480 chroma_addr[0] = exynos_drm_fb_dma_addr(fb, 1);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900481
Andrzej Hajda71469942017-09-29 12:05:33 +0200482 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
Tobias Jakobi0f752692017-08-22 16:19:38 +0200483 if (is_tiled) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900484 luma_addr[1] = luma_addr[0] + 0x40;
485 chroma_addr[1] = chroma_addr[0] + 0x40;
486 } else {
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900487 luma_addr[1] = luma_addr[0] + fb->pitches[0];
488 chroma_addr[1] = chroma_addr[0] + fb->pitches[0];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900489 }
490 } else {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900491 luma_addr[1] = 0;
492 chroma_addr[1] = 0;
493 }
494
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200495 spin_lock_irqsave(&ctx->reg_slock, flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900496
497 /* interlace or progressive scan mode */
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900498 val = (test_bit(MXR_BIT_INTERLACE, &ctx->flags) ? ~0 : 0);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200499 vp_reg_writemask(ctx, VP_MODE, val, VP_MODE_LINE_SKIP);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900500
501 /* setup format */
Tobias Jakobi0f752692017-08-22 16:19:38 +0200502 val = (is_nv21 ? VP_MODE_NV21 : VP_MODE_NV12);
503 val |= (is_tiled ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200504 vp_reg_writemask(ctx, VP_MODE, val, VP_MODE_FMT_MASK);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900505
506 /* setting size of input image */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200507 vp_reg_write(ctx, VP_IMG_SIZE_Y, VP_IMG_HSIZE(fb->pitches[0]) |
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900508 VP_IMG_VSIZE(fb->height));
Tobias Jakobidc500cf2017-08-22 16:19:36 +0200509 /* chroma plane for NV12/NV21 is half the height of the luma plane */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200510 vp_reg_write(ctx, VP_IMG_SIZE_C, VP_IMG_HSIZE(fb->pitches[0]) |
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900511 VP_IMG_VSIZE(fb->height / 2));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900512
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200513 vp_reg_write(ctx, VP_SRC_WIDTH, state->src.w);
514 vp_reg_write(ctx, VP_SRC_HEIGHT, state->src.h);
515 vp_reg_write(ctx, VP_SRC_H_POSITION,
Marek Szyprowski0114f402015-11-30 14:53:22 +0100516 VP_SRC_H_POSITION_VAL(state->src.x));
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200517 vp_reg_write(ctx, VP_SRC_V_POSITION, state->src.y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900518
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200519 vp_reg_write(ctx, VP_DST_WIDTH, state->crtc.w);
520 vp_reg_write(ctx, VP_DST_H_POSITION, state->crtc.x);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900521 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200522 vp_reg_write(ctx, VP_DST_HEIGHT, state->crtc.h / 2);
523 vp_reg_write(ctx, VP_DST_V_POSITION, state->crtc.y / 2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900524 } else {
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200525 vp_reg_write(ctx, VP_DST_HEIGHT, state->crtc.h);
526 vp_reg_write(ctx, VP_DST_V_POSITION, state->crtc.y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900527 }
528
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200529 vp_reg_write(ctx, VP_H_RATIO, state->h_ratio);
530 vp_reg_write(ctx, VP_V_RATIO, state->v_ratio);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900531
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200532 vp_reg_write(ctx, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900533
534 /* set buffer address to vp */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200535 vp_reg_write(ctx, VP_TOP_Y_PTR, luma_addr[0]);
536 vp_reg_write(ctx, VP_BOT_Y_PTR, luma_addr[1]);
537 vp_reg_write(ctx, VP_TOP_C_PTR, chroma_addr[0]);
538 vp_reg_write(ctx, VP_BOT_C_PTR, chroma_addr[1]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900539
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200540 mixer_cfg_layer(ctx, plane->index, priority, true);
Marek Szyprowskif657a992015-12-16 13:21:46 +0100541 mixer_cfg_vp_blend(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900542
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200543 spin_unlock_irqrestore(&ctx->reg_slock, flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900544
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200545 mixer_regs_dump(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900546 vp_regs_dump(ctx);
547}
548
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530549static void mixer_layer_update(struct mixer_context *ctx)
550{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200551 mixer_reg_writemask(ctx, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530552}
553
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900554static void mixer_graph_buffer(struct mixer_context *ctx,
555 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900556{
Marek Szyprowski0114f402015-11-30 14:53:22 +0100557 struct exynos_drm_plane_state *state =
558 to_exynos_plane_state(plane->base.state);
Marek Szyprowski0114f402015-11-30 14:53:22 +0100559 struct drm_framebuffer *fb = state->base.fb;
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200560 unsigned int priority = state->base.normalized_zpos + 1;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900561 unsigned long flags;
Marek Szyprowski40bdfb02015-12-16 13:21:42 +0100562 unsigned int win = plane->index;
Tobias Jakobi26110152015-04-07 01:14:52 +0200563 unsigned int x_ratio = 0, y_ratio = 0;
Tobias Jakobi5dff6902017-08-22 16:19:40 +0200564 unsigned int dst_x_offset, dst_y_offset;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900565 dma_addr_t dma_addr;
566 unsigned int fmt;
567 u32 val;
568
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200569 switch (fb->format->format) {
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200570 case DRM_FORMAT_XRGB4444:
Tobias Jakobi26a7af32015-12-16 13:21:47 +0100571 case DRM_FORMAT_ARGB4444:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200572 fmt = MXR_FORMAT_ARGB4444;
573 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900574
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200575 case DRM_FORMAT_XRGB1555:
Tobias Jakobi26a7af32015-12-16 13:21:47 +0100576 case DRM_FORMAT_ARGB1555:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200577 fmt = MXR_FORMAT_ARGB1555;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900578 break;
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200579
580 case DRM_FORMAT_RGB565:
581 fmt = MXR_FORMAT_RGB565;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900582 break;
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200583
584 case DRM_FORMAT_XRGB8888:
585 case DRM_FORMAT_ARGB8888:
Tobias Jakobi1e60d622017-08-22 16:19:39 +0200586 default:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200587 fmt = MXR_FORMAT_ARGB8888;
588 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900589 }
590
Marek Szyprowskie463b062015-11-30 14:53:27 +0100591 /* ratio is already checked by common plane code */
592 x_ratio = state->h_ratio == (1 << 15);
593 y_ratio = state->v_ratio == (1 << 15);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900594
Marek Szyprowski0114f402015-11-30 14:53:22 +0100595 dst_x_offset = state->crtc.x;
596 dst_y_offset = state->crtc.y;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900597
Tobias Jakobi5dff6902017-08-22 16:19:40 +0200598 /* translate dma address base s.t. the source image offset is zero */
Marek Szyprowski0488f502015-11-30 14:53:21 +0100599 dma_addr = exynos_drm_fb_dma_addr(fb, 0)
Ville Syrjälä272725c2016-12-14 23:32:20 +0200600 + (state->src.x * fb->format->cpp[0])
Marek Szyprowski0114f402015-11-30 14:53:22 +0100601 + (state->src.y * fb->pitches[0]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900602
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200603 spin_lock_irqsave(&ctx->reg_slock, flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900604
605 /* setup format */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200606 mixer_reg_writemask(ctx, MXR_GRAPHIC_CFG(win),
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900607 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
608
609 /* setup geometry */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200610 mixer_reg_write(ctx, MXR_GRAPHIC_SPAN(win),
Ville Syrjälä272725c2016-12-14 23:32:20 +0200611 fb->pitches[0] / fb->format->cpp[0]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900612
Marek Szyprowski0114f402015-11-30 14:53:22 +0100613 val = MXR_GRP_WH_WIDTH(state->src.w);
614 val |= MXR_GRP_WH_HEIGHT(state->src.h);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900615 val |= MXR_GRP_WH_H_SCALE(x_ratio);
616 val |= MXR_GRP_WH_V_SCALE(y_ratio);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200617 mixer_reg_write(ctx, MXR_GRAPHIC_WH(win), val);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900618
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900619 /* setup offsets in display image */
620 val = MXR_GRP_DXY_DX(dst_x_offset);
621 val |= MXR_GRP_DXY_DY(dst_y_offset);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200622 mixer_reg_write(ctx, MXR_GRAPHIC_DXY(win), val);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900623
624 /* set buffer address to mixer */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200625 mixer_reg_write(ctx, MXR_GRAPHIC_BASE(win), dma_addr);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900626
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200627 mixer_cfg_layer(ctx, win, priority, true);
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200628 mixer_cfg_gfx_blend(ctx, win, is_alpha_format(fb->format->format));
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530629
630 /* layer update mandatory for mixer 16.0.33.0 */
Rahul Sharmadef5e092013-06-19 18:21:08 +0530631 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
632 ctx->mxr_ver == MXR_VER_128_0_0_184)
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530633 mixer_layer_update(ctx);
634
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200635 spin_unlock_irqrestore(&ctx->reg_slock, flags);
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200636
637 mixer_regs_dump(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900638}
639
640static void vp_win_reset(struct mixer_context *ctx)
641{
Tobias Jakobia6963942016-09-22 16:57:19 +0200642 unsigned int tries = 100;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900643
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200644 vp_reg_write(ctx, VP_SRESET, VP_SRESET_PROCESSING);
Dan Carpenter8646dcb2017-01-20 17:54:32 +0100645 while (--tries) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900646 /* waiting until VP_SRESET_PROCESSING is 0 */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200647 if (~vp_reg_read(ctx, VP_SRESET) & VP_SRESET_PROCESSING)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900648 break;
Tomasz Stanislawski02b3de42015-09-25 14:48:29 +0200649 mdelay(10);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900650 }
651 WARN(tries == 0, "failed to reset Video Processor\n");
652}
653
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900654static void mixer_win_reset(struct mixer_context *ctx)
655{
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900656 unsigned long flags;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900657
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200658 spin_lock_irqsave(&ctx->reg_slock, flags);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900659
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200660 mixer_reg_writemask(ctx, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900661
662 /* set output in RGB888 mode */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200663 mixer_reg_writemask(ctx, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900664
665 /* 16 beat burst in DMA */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200666 mixer_reg_writemask(ctx, MXR_STATUS, MXR_STATUS_16_BURST,
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900667 MXR_STATUS_BURST_MASK);
668
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100669 /* reset default layer priority */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200670 mixer_reg_write(ctx, MXR_LAYER_CFG, 0);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900671
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100672 /* set all background colors to RGB (0,0,0) */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200673 mixer_reg_write(ctx, MXR_BG_COLOR0, MXR_YCBCR_VAL(0, 128, 128));
674 mixer_reg_write(ctx, MXR_BG_COLOR1, MXR_YCBCR_VAL(0, 128, 128));
675 mixer_reg_write(ctx, MXR_BG_COLOR2, MXR_YCBCR_VAL(0, 128, 128));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900676
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900677 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530678 /* configuration of Video Processor Registers */
679 vp_win_reset(ctx);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200680 vp_default_filter(ctx);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530681 }
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900682
683 /* disable all layers */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200684 mixer_reg_writemask(ctx, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
685 mixer_reg_writemask(ctx, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900686 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags))
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200687 mixer_reg_writemask(ctx, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900688
Tobias Jakobi5dff6902017-08-22 16:19:40 +0200689 /* set all source image offsets to zero */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200690 mixer_reg_write(ctx, MXR_GRAPHIC_SXY(0), 0);
691 mixer_reg_write(ctx, MXR_GRAPHIC_SXY(1), 0);
Tobias Jakobi5dff6902017-08-22 16:19:40 +0200692
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200693 spin_unlock_irqrestore(&ctx->reg_slock, flags);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900694}
695
Sean Paul45517892014-01-30 16:19:05 -0500696static irqreturn_t mixer_irq_handler(int irq, void *arg)
697{
698 struct mixer_context *ctx = arg;
Sean Paul45517892014-01-30 16:19:05 -0500699 u32 val, base, shadow;
700
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200701 spin_lock(&ctx->reg_slock);
Sean Paul45517892014-01-30 16:19:05 -0500702
703 /* read interrupt status for handling and clearing flags for VSYNC */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200704 val = mixer_reg_read(ctx, MXR_INT_STATUS);
Sean Paul45517892014-01-30 16:19:05 -0500705
706 /* handling VSYNC */
707 if (val & MXR_INT_STATUS_VSYNC) {
Andrzej Hajda81a464d2015-07-09 10:07:53 +0200708 /* vsync interrupt use different bit for read and clear */
709 val |= MXR_INT_CLEAR_VSYNC;
710 val &= ~MXR_INT_STATUS_VSYNC;
711
Sean Paul45517892014-01-30 16:19:05 -0500712 /* interlace scan need to check shadow register */
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900713 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200714 base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(0));
715 shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(0));
Sean Paul45517892014-01-30 16:19:05 -0500716 if (base != shadow)
717 goto out;
718
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200719 base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(1));
720 shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(1));
Sean Paul45517892014-01-30 16:19:05 -0500721 if (base != shadow)
722 goto out;
723 }
724
Gustavo Padovaneafd5402015-07-16 12:23:32 -0300725 drm_crtc_handle_vblank(&ctx->crtc->base);
Sean Paul45517892014-01-30 16:19:05 -0500726 }
727
728out:
729 /* clear interrupts */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200730 mixer_reg_write(ctx, MXR_INT_STATUS, val);
Sean Paul45517892014-01-30 16:19:05 -0500731
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200732 spin_unlock(&ctx->reg_slock);
Sean Paul45517892014-01-30 16:19:05 -0500733
734 return IRQ_HANDLED;
735}
736
737static int mixer_resources_init(struct mixer_context *mixer_ctx)
738{
739 struct device *dev = &mixer_ctx->pdev->dev;
Sean Paul45517892014-01-30 16:19:05 -0500740 struct resource *res;
741 int ret;
742
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200743 spin_lock_init(&mixer_ctx->reg_slock);
Sean Paul45517892014-01-30 16:19:05 -0500744
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200745 mixer_ctx->mixer = devm_clk_get(dev, "mixer");
746 if (IS_ERR(mixer_ctx->mixer)) {
Sean Paul45517892014-01-30 16:19:05 -0500747 dev_err(dev, "failed to get clock 'mixer'\n");
748 return -ENODEV;
749 }
750
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200751 mixer_ctx->hdmi = devm_clk_get(dev, "hdmi");
752 if (IS_ERR(mixer_ctx->hdmi)) {
Marek Szyprowski04427ec2015-02-02 14:20:28 +0100753 dev_err(dev, "failed to get clock 'hdmi'\n");
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200754 return PTR_ERR(mixer_ctx->hdmi);
Marek Szyprowski04427ec2015-02-02 14:20:28 +0100755 }
756
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200757 mixer_ctx->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
758 if (IS_ERR(mixer_ctx->sclk_hdmi)) {
Sean Paul45517892014-01-30 16:19:05 -0500759 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
760 return -ENODEV;
761 }
762 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
763 if (res == NULL) {
764 dev_err(dev, "get memory resource failed.\n");
765 return -ENXIO;
766 }
767
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200768 mixer_ctx->mixer_regs = devm_ioremap(dev, res->start,
Sean Paul45517892014-01-30 16:19:05 -0500769 resource_size(res));
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200770 if (mixer_ctx->mixer_regs == NULL) {
Sean Paul45517892014-01-30 16:19:05 -0500771 dev_err(dev, "register mapping failed.\n");
772 return -ENXIO;
773 }
774
775 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
776 if (res == NULL) {
777 dev_err(dev, "get interrupt resource failed.\n");
778 return -ENXIO;
779 }
780
781 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
782 0, "drm_mixer", mixer_ctx);
783 if (ret) {
784 dev_err(dev, "request interrupt failed.\n");
785 return ret;
786 }
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200787 mixer_ctx->irq = res->start;
Sean Paul45517892014-01-30 16:19:05 -0500788
789 return 0;
790}
791
792static int vp_resources_init(struct mixer_context *mixer_ctx)
793{
794 struct device *dev = &mixer_ctx->pdev->dev;
Sean Paul45517892014-01-30 16:19:05 -0500795 struct resource *res;
796
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200797 mixer_ctx->vp = devm_clk_get(dev, "vp");
798 if (IS_ERR(mixer_ctx->vp)) {
Sean Paul45517892014-01-30 16:19:05 -0500799 dev_err(dev, "failed to get clock 'vp'\n");
800 return -ENODEV;
801 }
Sean Paul45517892014-01-30 16:19:05 -0500802
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900803 if (test_bit(MXR_BIT_HAS_SCLK, &mixer_ctx->flags)) {
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200804 mixer_ctx->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
805 if (IS_ERR(mixer_ctx->sclk_mixer)) {
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200806 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
807 return -ENODEV;
808 }
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200809 mixer_ctx->mout_mixer = devm_clk_get(dev, "mout_mixer");
810 if (IS_ERR(mixer_ctx->mout_mixer)) {
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200811 dev_err(dev, "failed to get clock 'mout_mixer'\n");
812 return -ENODEV;
813 }
814
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200815 if (mixer_ctx->sclk_hdmi && mixer_ctx->mout_mixer)
816 clk_set_parent(mixer_ctx->mout_mixer,
817 mixer_ctx->sclk_hdmi);
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200818 }
Sean Paul45517892014-01-30 16:19:05 -0500819
820 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
821 if (res == NULL) {
822 dev_err(dev, "get memory resource failed.\n");
823 return -ENXIO;
824 }
825
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200826 mixer_ctx->vp_regs = devm_ioremap(dev, res->start,
Sean Paul45517892014-01-30 16:19:05 -0500827 resource_size(res));
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200828 if (mixer_ctx->vp_regs == NULL) {
Sean Paul45517892014-01-30 16:19:05 -0500829 dev_err(dev, "register mapping failed.\n");
830 return -ENXIO;
831 }
832
833 return 0;
834}
835
Gustavo Padovan93bca242015-01-18 18:16:23 +0900836static int mixer_initialize(struct mixer_context *mixer_ctx,
Inki Daef37cd5e2014-05-09 14:25:20 +0900837 struct drm_device *drm_dev)
Sean Paul45517892014-01-30 16:19:05 -0500838{
839 int ret;
Inki Daef37cd5e2014-05-09 14:25:20 +0900840 struct exynos_drm_private *priv;
841 priv = drm_dev->dev_private;
Sean Paul45517892014-01-30 16:19:05 -0500842
Gustavo Padovaneb88e422014-11-26 16:43:27 -0200843 mixer_ctx->drm_dev = drm_dev;
Sean Paul45517892014-01-30 16:19:05 -0500844
845 /* acquire resources: regs, irqs, clocks */
846 ret = mixer_resources_init(mixer_ctx);
847 if (ret) {
848 DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
849 return ret;
850 }
851
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900852 if (test_bit(MXR_BIT_VP_ENABLED, &mixer_ctx->flags)) {
Sean Paul45517892014-01-30 16:19:05 -0500853 /* acquire vp resources: regs, irqs, clocks */
854 ret = vp_resources_init(mixer_ctx);
855 if (ret) {
856 DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
857 return ret;
858 }
859 }
860
Andrzej Hajdaf44d3d22017-03-15 15:41:04 +0100861 return drm_iommu_attach_device(drm_dev, mixer_ctx->dev);
Sean Paul45517892014-01-30 16:19:05 -0500862}
863
Gustavo Padovan93bca242015-01-18 18:16:23 +0900864static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
Inki Dae1055b392012-10-19 17:37:35 +0900865{
Joonyoung Shimbf566082015-07-02 21:49:38 +0900866 drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Inki Dae1055b392012-10-19 17:37:35 +0900867}
868
Gustavo Padovan93bca242015-01-18 18:16:23 +0900869static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900870{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900871 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900872
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200873 __set_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
874 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Sean Paulf041b252014-01-30 16:19:15 -0500875 return 0;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900876
877 /* enable vsync interrupt */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200878 mixer_reg_writemask(mixer_ctx, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
879 mixer_reg_writemask(mixer_ctx, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900880
881 return 0;
882}
883
Gustavo Padovan93bca242015-01-18 18:16:23 +0900884static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900885{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900886 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900887
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200888 __clear_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
889
890 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Andrzej Hajda947710c2015-07-09 08:25:41 +0200891 return;
Andrzej Hajda947710c2015-07-09 08:25:41 +0200892
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900893 /* disable vsync interrupt */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200894 mixer_reg_writemask(mixer_ctx, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
895 mixer_reg_writemask(mixer_ctx, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900896}
897
Marek Szyprowski3dbaab12016-01-05 13:52:52 +0100898static void mixer_atomic_begin(struct exynos_drm_crtc *crtc)
899{
900 struct mixer_context *mixer_ctx = crtc->ctx;
901
902 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
903 return;
904
905 mixer_vsync_set_update(mixer_ctx, false);
906}
907
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900908static void mixer_update_plane(struct exynos_drm_crtc *crtc,
909 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900910{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900911 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900912
Marek Szyprowski40bdfb02015-12-16 13:21:42 +0100913 DRM_DEBUG_KMS("win: %d\n", plane->index);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900914
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200915 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Shirish Sdda90122013-01-23 22:03:18 -0500916 return;
Shirish Sdda90122013-01-23 22:03:18 -0500917
Marek Szyprowski5e68fef2015-12-16 13:21:48 +0100918 if (plane->index == VP_DEFAULT_WIN)
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900919 vp_video_buffer(mixer_ctx, plane);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900920 else
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900921 mixer_graph_buffer(mixer_ctx, plane);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900922}
923
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900924static void mixer_disable_plane(struct exynos_drm_crtc *crtc,
925 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900926{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900927 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900928 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900929
Marek Szyprowski40bdfb02015-12-16 13:21:42 +0100930 DRM_DEBUG_KMS("win: %d\n", plane->index);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900931
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200932 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Prathyush Kdb43fd12012-12-06 20:16:05 +0530933 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +0530934
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200935 spin_lock_irqsave(&mixer_ctx->reg_slock, flags);
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100936 mixer_cfg_layer(mixer_ctx, plane->index, 0, false);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200937 spin_unlock_irqrestore(&mixer_ctx->reg_slock, flags);
Marek Szyprowski3dbaab12016-01-05 13:52:52 +0100938}
939
940static void mixer_atomic_flush(struct exynos_drm_crtc *crtc)
941{
942 struct mixer_context *mixer_ctx = crtc->ctx;
943
944 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
945 return;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900946
947 mixer_vsync_set_update(mixer_ctx, true);
Andrzej Hajdaa3922762017-03-14 09:27:56 +0100948 exynos_crtc_handle_event(crtc);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900949}
950
Gustavo Padovan3cecda02015-06-01 12:04:55 -0300951static void mixer_enable(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +0530952{
Gustavo Padovan3cecda02015-06-01 12:04:55 -0300953 struct mixer_context *ctx = crtc->ctx;
Prathyush Kdb43fd12012-12-06 20:16:05 +0530954
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200955 if (test_bit(MXR_BIT_POWERED, &ctx->flags))
Prathyush Kdb43fd12012-12-06 20:16:05 +0530956 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +0530957
Sean Paulaf65c802014-01-30 16:19:27 -0500958 pm_runtime_get_sync(ctx->dev);
959
Andrzej Hajdaa121d172016-03-23 14:26:01 +0100960 exynos_drm_pipe_clk_enable(crtc, true);
961
Marek Szyprowski3dbaab12016-01-05 13:52:52 +0100962 mixer_vsync_set_update(ctx, false);
963
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200964 mixer_reg_writemask(ctx, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
Rahul Sharmad74ed932014-06-23 11:02:24 +0530965
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200966 if (test_bit(MXR_BIT_VSYNC, &ctx->flags)) {
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200967 mixer_reg_writemask(ctx, MXR_INT_STATUS, ~0,
968 MXR_INT_CLEAR_VSYNC);
969 mixer_reg_writemask(ctx, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200970 }
Prathyush Kdb43fd12012-12-06 20:16:05 +0530971 mixer_win_reset(ctx);
Gustavo Padovanccf034a2015-09-04 17:15:46 -0300972
Andrzej Hajda71469942017-09-29 12:05:33 +0200973 mixer_commit(ctx);
974
Marek Szyprowski3dbaab12016-01-05 13:52:52 +0100975 mixer_vsync_set_update(ctx, true);
976
Gustavo Padovanccf034a2015-09-04 17:15:46 -0300977 set_bit(MXR_BIT_POWERED, &ctx->flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530978}
979
Gustavo Padovan3cecda02015-06-01 12:04:55 -0300980static void mixer_disable(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +0530981{
Gustavo Padovan3cecda02015-06-01 12:04:55 -0300982 struct mixer_context *ctx = crtc->ctx;
Joonyoung Shimc329f662015-06-12 20:34:28 +0900983 int i;
Prathyush Kdb43fd12012-12-06 20:16:05 +0530984
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200985 if (!test_bit(MXR_BIT_POWERED, &ctx->flags))
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +0530986 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +0530987
Rahul Sharma381be022014-06-23 11:02:22 +0530988 mixer_stop(ctx);
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200989 mixer_regs_dump(ctx);
Joonyoung Shimc329f662015-06-12 20:34:28 +0900990
991 for (i = 0; i < MIXER_WIN_NR; i++)
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900992 mixer_disable_plane(crtc, &ctx->planes[i]);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530993
Andrzej Hajdaa121d172016-03-23 14:26:01 +0100994 exynos_drm_pipe_clk_enable(crtc, false);
995
Gustavo Padovanccf034a2015-09-04 17:15:46 -0300996 pm_runtime_put(ctx->dev);
997
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200998 clear_bit(MXR_BIT_POWERED, &ctx->flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530999}
1000
Andrzej Hajda6ace38a2017-09-29 12:05:35 +02001001static int mixer_mode_valid(struct exynos_drm_crtc *crtc,
1002 const struct drm_display_mode *mode)
Sean Paulf041b252014-01-30 16:19:15 -05001003{
Andrzej Hajda6ace38a2017-09-29 12:05:35 +02001004 struct mixer_context *ctx = crtc->ctx;
1005 u32 w = mode->hdisplay, h = mode->vdisplay;
Sean Paulf041b252014-01-30 16:19:15 -05001006
Andrzej Hajda6ace38a2017-09-29 12:05:35 +02001007 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n", w, h,
1008 mode->vrefresh, !!(mode->flags & DRM_MODE_FLAG_INTERLACE));
Sean Paulf041b252014-01-30 16:19:15 -05001009
Andrzej Hajda6ace38a2017-09-29 12:05:35 +02001010 if (ctx->mxr_ver == MXR_VER_128_0_0_184)
1011 return MODE_OK;
Sean Paulf041b252014-01-30 16:19:15 -05001012
1013 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
Andrzej Hajda6ace38a2017-09-29 12:05:35 +02001014 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1015 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1016 return MODE_OK;
Sean Paulf041b252014-01-30 16:19:15 -05001017
Daniel Drakeae58c032017-09-29 12:05:42 +02001018 if ((w == 1024 && h == 768) ||
1019 (w == 1366 && h == 768) ||
1020 (w == 1280 && h == 1024))
Andrzej Hajda09006732017-09-29 12:05:41 +02001021 return MODE_OK;
1022
Andrzej Hajda6ace38a2017-09-29 12:05:35 +02001023 return MODE_BAD;
Sean Paulf041b252014-01-30 16:19:15 -05001024}
1025
Andrzej Hajdaacc8bf02017-09-29 12:05:39 +02001026static bool mixer_mode_fixup(struct exynos_drm_crtc *crtc,
1027 const struct drm_display_mode *mode,
1028 struct drm_display_mode *adjusted_mode)
1029{
1030 struct mixer_context *ctx = crtc->ctx;
1031 int width = mode->hdisplay, height = mode->vdisplay, i;
1032
1033 struct {
1034 int hdisplay, vdisplay, htotal, vtotal, scan_val;
1035 } static const modes[] = {
1036 { 720, 480, 858, 525, MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD },
1037 { 720, 576, 864, 625, MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD },
1038 { 1280, 720, 1650, 750, MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD },
1039 { 1920, 1080, 2200, 1125, MXR_CFG_SCAN_HD_1080 |
1040 MXR_CFG_SCAN_HD }
1041 };
1042
1043 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
1044 __set_bit(MXR_BIT_INTERLACE, &ctx->flags);
1045 else
1046 __clear_bit(MXR_BIT_INTERLACE, &ctx->flags);
1047
1048 if (ctx->mxr_ver == MXR_VER_128_0_0_184)
1049 return true;
1050
1051 for (i = 0; i < ARRAY_SIZE(modes); ++i)
1052 if (width <= modes[i].hdisplay && height <= modes[i].vdisplay) {
1053 ctx->scan_value = modes[i].scan_val;
1054 if (width < modes[i].hdisplay ||
1055 height < modes[i].vdisplay) {
1056 adjusted_mode->hdisplay = modes[i].hdisplay;
1057 adjusted_mode->hsync_start = modes[i].hdisplay;
1058 adjusted_mode->hsync_end = modes[i].htotal;
1059 adjusted_mode->htotal = modes[i].htotal;
1060 adjusted_mode->vdisplay = modes[i].vdisplay;
1061 adjusted_mode->vsync_start = modes[i].vdisplay;
1062 adjusted_mode->vsync_end = modes[i].vtotal;
1063 adjusted_mode->vtotal = modes[i].vtotal;
1064 }
1065
1066 return true;
1067 }
1068
1069 return false;
1070}
1071
Krzysztof Kozlowskif3aaf762015-05-07 09:04:45 +09001072static const struct exynos_drm_crtc_ops mixer_crtc_ops = {
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001073 .enable = mixer_enable,
1074 .disable = mixer_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001075 .enable_vblank = mixer_enable_vblank,
1076 .disable_vblank = mixer_disable_vblank,
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001077 .atomic_begin = mixer_atomic_begin,
Gustavo Padovan9cc76102015-08-03 14:38:05 +09001078 .update_plane = mixer_update_plane,
1079 .disable_plane = mixer_disable_plane,
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001080 .atomic_flush = mixer_atomic_flush,
Andrzej Hajda6ace38a2017-09-29 12:05:35 +02001081 .mode_valid = mixer_mode_valid,
Andrzej Hajdaacc8bf02017-09-29 12:05:39 +02001082 .mode_fixup = mixer_mode_fixup,
Sean Paulf041b252014-01-30 16:19:15 -05001083};
Rahul Sharma0ea68222013-01-15 08:11:06 -05001084
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301085static const struct mixer_drv_data exynos5420_mxr_drv_data = {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301086 .version = MXR_VER_128_0_0_184,
1087 .is_vp_enabled = 0,
1088};
1089
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301090static const struct mixer_drv_data exynos5250_mxr_drv_data = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301091 .version = MXR_VER_16_0_33_0,
1092 .is_vp_enabled = 0,
1093};
1094
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301095static const struct mixer_drv_data exynos4212_mxr_drv_data = {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001096 .version = MXR_VER_0_0_0_16,
1097 .is_vp_enabled = 1,
1098};
1099
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301100static const struct mixer_drv_data exynos4210_mxr_drv_data = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301101 .version = MXR_VER_0_0_0_16,
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301102 .is_vp_enabled = 1,
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001103 .has_sclk = 1,
Rahul Sharma1e123442012-10-04 20:48:51 +05301104};
1105
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301106static const struct of_device_id mixer_match_types[] = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301107 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001108 .compatible = "samsung,exynos4210-mixer",
1109 .data = &exynos4210_mxr_drv_data,
1110 }, {
1111 .compatible = "samsung,exynos4212-mixer",
1112 .data = &exynos4212_mxr_drv_data,
1113 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301114 .compatible = "samsung,exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301115 .data = &exynos5250_mxr_drv_data,
1116 }, {
1117 .compatible = "samsung,exynos5250-mixer",
1118 .data = &exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301119 }, {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301120 .compatible = "samsung,exynos5420-mixer",
1121 .data = &exynos5420_mxr_drv_data,
1122 }, {
Rahul Sharma1e123442012-10-04 20:48:51 +05301123 /* end node */
1124 }
1125};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001126MODULE_DEVICE_TABLE(of, mixer_match_types);
Rahul Sharma1e123442012-10-04 20:48:51 +05301127
Inki Daef37cd5e2014-05-09 14:25:20 +09001128static int mixer_bind(struct device *dev, struct device *manager, void *data)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001129{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001130 struct mixer_context *ctx = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09001131 struct drm_device *drm_dev = data;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001132 struct exynos_drm_plane *exynos_plane;
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +01001133 unsigned int i;
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +09001134 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001135
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001136 ret = mixer_initialize(ctx, drm_dev);
1137 if (ret)
1138 return ret;
1139
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +01001140 for (i = 0; i < MIXER_WIN_NR; i++) {
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001141 if (i == VP_DEFAULT_WIN && !test_bit(MXR_BIT_VP_ENABLED,
1142 &ctx->flags))
Marek Szyprowskiab144202015-11-30 14:53:24 +01001143 continue;
1144
Marek Szyprowski40bdfb02015-12-16 13:21:42 +01001145 ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
Andrzej Hajda2c826072017-03-15 15:41:05 +01001146 &plane_configs[i]);
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001147 if (ret)
1148 return ret;
1149 }
1150
Gustavo Padovan5d3d0992015-10-12 22:07:48 +09001151 exynos_plane = &ctx->planes[DEFAULT_WIN];
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001152 ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
Andrzej Hajdad6449512017-05-29 10:05:25 +09001153 EXYNOS_DISPLAY_TYPE_HDMI, &mixer_crtc_ops, ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001154 if (IS_ERR(ctx->crtc)) {
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001155 mixer_ctx_remove(ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001156 ret = PTR_ERR(ctx->crtc);
1157 goto free_ctx;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001158 }
1159
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001160 return 0;
Gustavo Padovan93bca242015-01-18 18:16:23 +09001161
1162free_ctx:
1163 devm_kfree(dev, ctx);
1164 return ret;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001165}
1166
1167static void mixer_unbind(struct device *dev, struct device *master, void *data)
1168{
1169 struct mixer_context *ctx = dev_get_drvdata(dev);
1170
Gustavo Padovan93bca242015-01-18 18:16:23 +09001171 mixer_ctx_remove(ctx);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001172}
1173
1174static const struct component_ops mixer_component_ops = {
1175 .bind = mixer_bind,
1176 .unbind = mixer_unbind,
1177};
1178
1179static int mixer_probe(struct platform_device *pdev)
1180{
1181 struct device *dev = &pdev->dev;
Marek Szyprowski48f61552016-04-01 15:17:46 +02001182 const struct mixer_drv_data *drv;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001183 struct mixer_context *ctx;
1184 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001185
Sean Paulf041b252014-01-30 16:19:15 -05001186 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1187 if (!ctx) {
1188 DRM_ERROR("failed to alloc mixer context.\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001189 return -ENOMEM;
Sean Paulf041b252014-01-30 16:19:15 -05001190 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001191
Marek Szyprowski48f61552016-04-01 15:17:46 +02001192 drv = of_device_get_match_data(dev);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301193
Sean Paul45517892014-01-30 16:19:05 -05001194 ctx->pdev = pdev;
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001195 ctx->dev = dev;
Rahul Sharma1e123442012-10-04 20:48:51 +05301196 ctx->mxr_ver = drv->version;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001197
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001198 if (drv->is_vp_enabled)
1199 __set_bit(MXR_BIT_VP_ENABLED, &ctx->flags);
1200 if (drv->has_sclk)
1201 __set_bit(MXR_BIT_HAS_SCLK, &ctx->flags);
1202
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001203 platform_set_drvdata(pdev, ctx);
Inki Daedf5225b2014-05-29 18:28:02 +09001204
Inki Daedf5225b2014-05-29 18:28:02 +09001205 ret = component_add(&pdev->dev, &mixer_component_ops);
Andrzej Hajda86650402015-06-11 23:23:37 +09001206 if (!ret)
1207 pm_runtime_enable(dev);
Inki Daedf5225b2014-05-29 18:28:02 +09001208
1209 return ret;
Inki Daef37cd5e2014-05-09 14:25:20 +09001210}
1211
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001212static int mixer_remove(struct platform_device *pdev)
1213{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001214 pm_runtime_disable(&pdev->dev);
1215
Inki Daedf5225b2014-05-29 18:28:02 +09001216 component_del(&pdev->dev, &mixer_component_ops);
Inki Daedf5225b2014-05-29 18:28:02 +09001217
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001218 return 0;
1219}
1220
Arnd Bergmanne0fea7e2015-11-17 16:08:36 +01001221static int __maybe_unused exynos_mixer_suspend(struct device *dev)
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001222{
1223 struct mixer_context *ctx = dev_get_drvdata(dev);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001224
Andrzej Hajda524c59f2017-09-29 12:05:36 +02001225 clk_disable_unprepare(ctx->hdmi);
1226 clk_disable_unprepare(ctx->mixer);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001227 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Andrzej Hajda524c59f2017-09-29 12:05:36 +02001228 clk_disable_unprepare(ctx->vp);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001229 if (test_bit(MXR_BIT_HAS_SCLK, &ctx->flags))
Andrzej Hajda524c59f2017-09-29 12:05:36 +02001230 clk_disable_unprepare(ctx->sclk_mixer);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001231 }
1232
1233 return 0;
1234}
1235
Arnd Bergmanne0fea7e2015-11-17 16:08:36 +01001236static int __maybe_unused exynos_mixer_resume(struct device *dev)
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001237{
1238 struct mixer_context *ctx = dev_get_drvdata(dev);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001239 int ret;
1240
Andrzej Hajda524c59f2017-09-29 12:05:36 +02001241 ret = clk_prepare_enable(ctx->mixer);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001242 if (ret < 0) {
1243 DRM_ERROR("Failed to prepare_enable the mixer clk [%d]\n", ret);
1244 return ret;
1245 }
Andrzej Hajda524c59f2017-09-29 12:05:36 +02001246 ret = clk_prepare_enable(ctx->hdmi);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001247 if (ret < 0) {
1248 DRM_ERROR("Failed to prepare_enable the hdmi clk [%d]\n", ret);
1249 return ret;
1250 }
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001251 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Andrzej Hajda524c59f2017-09-29 12:05:36 +02001252 ret = clk_prepare_enable(ctx->vp);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001253 if (ret < 0) {
1254 DRM_ERROR("Failed to prepare_enable the vp clk [%d]\n",
1255 ret);
1256 return ret;
1257 }
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001258 if (test_bit(MXR_BIT_HAS_SCLK, &ctx->flags)) {
Andrzej Hajda524c59f2017-09-29 12:05:36 +02001259 ret = clk_prepare_enable(ctx->sclk_mixer);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001260 if (ret < 0) {
1261 DRM_ERROR("Failed to prepare_enable the " \
1262 "sclk_mixer clk [%d]\n",
1263 ret);
1264 return ret;
1265 }
1266 }
1267 }
1268
1269 return 0;
1270}
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001271
1272static const struct dev_pm_ops exynos_mixer_pm_ops = {
1273 SET_RUNTIME_PM_OPS(exynos_mixer_suspend, exynos_mixer_resume, NULL)
1274};
1275
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001276struct platform_driver mixer_driver = {
1277 .driver = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301278 .name = "exynos-mixer",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001279 .owner = THIS_MODULE,
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001280 .pm = &exynos_mixer_pm_ops,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301281 .of_match_table = mixer_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001282 },
1283 .probe = mixer_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001284 .remove = mixer_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001285};