blob: c0e92021748b16237d013e44372567da85422100 [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;
118};
119
120struct mixer_drv_data {
121 enum mixer_version_id version;
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530122 bool is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200123 bool has_sclk;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +0900124};
125
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +0100126static const struct exynos_drm_plane_config plane_configs[MIXER_WIN_NR] = {
127 {
128 .zpos = 0,
129 .type = DRM_PLANE_TYPE_PRIMARY,
130 .pixel_formats = mixer_formats,
131 .num_pixel_formats = ARRAY_SIZE(mixer_formats),
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100132 .capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE |
133 EXYNOS_DRM_PLANE_CAP_ZPOS,
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +0100134 }, {
135 .zpos = 1,
136 .type = DRM_PLANE_TYPE_CURSOR,
137 .pixel_formats = mixer_formats,
138 .num_pixel_formats = ARRAY_SIZE(mixer_formats),
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100139 .capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE |
140 EXYNOS_DRM_PLANE_CAP_ZPOS,
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +0100141 }, {
142 .zpos = 2,
143 .type = DRM_PLANE_TYPE_OVERLAY,
144 .pixel_formats = vp_formats,
145 .num_pixel_formats = ARRAY_SIZE(vp_formats),
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100146 .capabilities = EXYNOS_DRM_PLANE_CAP_SCALE |
Tobias Jakobif40031c2017-08-22 16:19:37 +0200147 EXYNOS_DRM_PLANE_CAP_ZPOS |
148 EXYNOS_DRM_PLANE_CAP_TILE,
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +0100149 },
150};
151
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900152static const u8 filter_y_horiz_tap8[] = {
153 0, -1, -1, -1, -1, -1, -1, -1,
154 -1, -1, -1, -1, -1, 0, 0, 0,
155 0, 2, 4, 5, 6, 6, 6, 6,
156 6, 5, 5, 4, 3, 2, 1, 1,
157 0, -6, -12, -16, -18, -20, -21, -20,
158 -20, -18, -16, -13, -10, -8, -5, -2,
159 127, 126, 125, 121, 114, 107, 99, 89,
160 79, 68, 57, 46, 35, 25, 16, 8,
161};
162
163static const u8 filter_y_vert_tap4[] = {
164 0, -3, -6, -8, -8, -8, -8, -7,
165 -6, -5, -4, -3, -2, -1, -1, 0,
166 127, 126, 124, 118, 111, 102, 92, 81,
167 70, 59, 48, 37, 27, 19, 11, 5,
168 0, 5, 11, 19, 27, 37, 48, 59,
169 70, 81, 92, 102, 111, 118, 124, 126,
170 0, 0, -1, -1, -2, -3, -4, -5,
171 -6, -7, -8, -8, -8, -8, -6, -3,
172};
173
174static const u8 filter_cr_horiz_tap4[] = {
175 0, -3, -6, -8, -8, -8, -8, -7,
176 -6, -5, -4, -3, -2, -1, -1, 0,
177 127, 126, 124, 118, 111, 102, 92, 81,
178 70, 59, 48, 37, 27, 19, 11, 5,
179};
180
Marek Szyprowskif657a992015-12-16 13:21:46 +0100181static inline bool is_alpha_format(unsigned int pixel_format)
182{
183 switch (pixel_format) {
184 case DRM_FORMAT_ARGB8888:
Tobias Jakobi26a7af32015-12-16 13:21:47 +0100185 case DRM_FORMAT_ARGB1555:
186 case DRM_FORMAT_ARGB4444:
Marek Szyprowskif657a992015-12-16 13:21:46 +0100187 return true;
188 default:
189 return false;
190 }
191}
192
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200193static inline u32 vp_reg_read(struct mixer_context *ctx, u32 reg_id)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900194{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200195 return readl(ctx->vp_regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900196}
197
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200198static inline void vp_reg_write(struct mixer_context *ctx, u32 reg_id,
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900199 u32 val)
200{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200201 writel(val, ctx->vp_regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900202}
203
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200204static inline void vp_reg_writemask(struct mixer_context *ctx, u32 reg_id,
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900205 u32 val, u32 mask)
206{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200207 u32 old = vp_reg_read(ctx, reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900208
209 val = (val & mask) | (old & ~mask);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200210 writel(val, ctx->vp_regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900211}
212
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200213static inline u32 mixer_reg_read(struct mixer_context *ctx, u32 reg_id)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900214{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200215 return readl(ctx->mixer_regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900216}
217
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200218static inline void mixer_reg_write(struct mixer_context *ctx, u32 reg_id,
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900219 u32 val)
220{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200221 writel(val, ctx->mixer_regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900222}
223
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200224static inline void mixer_reg_writemask(struct mixer_context *ctx,
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900225 u32 reg_id, u32 val, u32 mask)
226{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200227 u32 old = mixer_reg_read(ctx, reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900228
229 val = (val & mask) | (old & ~mask);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200230 writel(val, ctx->mixer_regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900231}
232
233static void mixer_regs_dump(struct mixer_context *ctx)
234{
235#define DUMPREG(reg_id) \
236do { \
237 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200238 (u32)readl(ctx->mixer_regs + reg_id)); \
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900239} while (0)
240
241 DUMPREG(MXR_STATUS);
242 DUMPREG(MXR_CFG);
243 DUMPREG(MXR_INT_EN);
244 DUMPREG(MXR_INT_STATUS);
245
246 DUMPREG(MXR_LAYER_CFG);
247 DUMPREG(MXR_VIDEO_CFG);
248
249 DUMPREG(MXR_GRAPHIC0_CFG);
250 DUMPREG(MXR_GRAPHIC0_BASE);
251 DUMPREG(MXR_GRAPHIC0_SPAN);
252 DUMPREG(MXR_GRAPHIC0_WH);
253 DUMPREG(MXR_GRAPHIC0_SXY);
254 DUMPREG(MXR_GRAPHIC0_DXY);
255
256 DUMPREG(MXR_GRAPHIC1_CFG);
257 DUMPREG(MXR_GRAPHIC1_BASE);
258 DUMPREG(MXR_GRAPHIC1_SPAN);
259 DUMPREG(MXR_GRAPHIC1_WH);
260 DUMPREG(MXR_GRAPHIC1_SXY);
261 DUMPREG(MXR_GRAPHIC1_DXY);
262#undef DUMPREG
263}
264
265static void vp_regs_dump(struct mixer_context *ctx)
266{
267#define DUMPREG(reg_id) \
268do { \
269 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200270 (u32) readl(ctx->vp_regs + reg_id)); \
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900271} while (0)
272
273 DUMPREG(VP_ENABLE);
274 DUMPREG(VP_SRESET);
275 DUMPREG(VP_SHADOW_UPDATE);
276 DUMPREG(VP_FIELD_ID);
277 DUMPREG(VP_MODE);
278 DUMPREG(VP_IMG_SIZE_Y);
279 DUMPREG(VP_IMG_SIZE_C);
280 DUMPREG(VP_PER_RATE_CTRL);
281 DUMPREG(VP_TOP_Y_PTR);
282 DUMPREG(VP_BOT_Y_PTR);
283 DUMPREG(VP_TOP_C_PTR);
284 DUMPREG(VP_BOT_C_PTR);
285 DUMPREG(VP_ENDIAN_MODE);
286 DUMPREG(VP_SRC_H_POSITION);
287 DUMPREG(VP_SRC_V_POSITION);
288 DUMPREG(VP_SRC_WIDTH);
289 DUMPREG(VP_SRC_HEIGHT);
290 DUMPREG(VP_DST_H_POSITION);
291 DUMPREG(VP_DST_V_POSITION);
292 DUMPREG(VP_DST_WIDTH);
293 DUMPREG(VP_DST_HEIGHT);
294 DUMPREG(VP_H_RATIO);
295 DUMPREG(VP_V_RATIO);
296
297#undef DUMPREG
298}
299
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200300static inline void vp_filter_set(struct mixer_context *ctx,
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900301 int reg_id, const u8 *data, unsigned int size)
302{
303 /* assure 4-byte align */
304 BUG_ON(size & 3);
305 for (; size; size -= 4, reg_id += 4, data += 4) {
306 u32 val = (data[0] << 24) | (data[1] << 16) |
307 (data[2] << 8) | data[3];
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200308 vp_reg_write(ctx, reg_id, val);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900309 }
310}
311
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200312static void vp_default_filter(struct mixer_context *ctx)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900313{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200314 vp_filter_set(ctx, VP_POLY8_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530315 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200316 vp_filter_set(ctx, VP_POLY4_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530317 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200318 vp_filter_set(ctx, VP_POLY4_C0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530319 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900320}
321
Marek Szyprowskif657a992015-12-16 13:21:46 +0100322static void mixer_cfg_gfx_blend(struct mixer_context *ctx, unsigned int win,
323 bool alpha)
324{
Marek Szyprowskif657a992015-12-16 13:21:46 +0100325 u32 val;
326
327 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
328 if (alpha) {
329 /* blending based on pixel alpha */
330 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
331 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
332 }
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200333 mixer_reg_writemask(ctx, MXR_GRAPHIC_CFG(win),
Marek Szyprowskif657a992015-12-16 13:21:46 +0100334 val, MXR_GRP_CFG_MISC_MASK);
335}
336
337static void mixer_cfg_vp_blend(struct mixer_context *ctx)
338{
Marek Szyprowskif657a992015-12-16 13:21:46 +0100339 u32 val;
340
341 /*
342 * No blending at the moment since the NV12/NV21 pixelformats don't
343 * have an alpha channel. However the mixer supports a global alpha
344 * value for a layer. Once this functionality is exposed, we can
345 * support blending of the video layer through this.
346 */
347 val = 0;
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200348 mixer_reg_write(ctx, MXR_VIDEO_CFG, val);
Marek Szyprowskif657a992015-12-16 13:21:46 +0100349}
350
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900351static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
352{
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900353 /* block update on vsync */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200354 mixer_reg_writemask(ctx, MXR_STATUS, enable ?
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900355 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
356
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900357 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags))
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200358 vp_reg_write(ctx, VP_SHADOW_UPDATE, enable ?
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900359 VP_SHADOW_UPDATE_ENABLE : 0);
360}
361
Andrzej Hajda3fc40ca2017-09-29 12:05:34 +0200362static void mixer_cfg_scan(struct mixer_context *ctx, int width, int height)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900363{
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900364 u32 val;
365
366 /* choosing between interlace and progressive mode */
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900367 val = test_bit(MXR_BIT_INTERLACE, &ctx->flags) ?
368 MXR_CFG_SCAN_INTERLACE : MXR_CFG_SCAN_PROGRESSIVE;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900369
Andrzej Hajda3fc40ca2017-09-29 12:05:34 +0200370 /* setup display size */
371 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));
374 } else {
Rahul Sharmadef5e092013-06-19 18:21:08 +0530375 /* choosing between proper HD and SD mode */
376 if (height <= 480)
377 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
378 else if (height <= 576)
379 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
380 else if (height <= 720)
381 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
382 else if (height <= 1080)
383 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
384 else
385 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
386 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900387
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200388 mixer_reg_writemask(ctx, MXR_CFG, val, MXR_CFG_SCAN_MASK);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900389}
390
391static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
392{
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900393 u32 val;
394
Tobias Jakobi2a39db02017-03-10 14:30:16 +0100395 switch (height) {
396 case 480:
397 case 576:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900398 val = MXR_CFG_RGB601_0_255;
Tobias Jakobi2a39db02017-03-10 14:30:16 +0100399 break;
400 case 720:
401 case 1080:
402 default:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900403 val = MXR_CFG_RGB709_16_235;
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100404 /* Configure the BT.709 CSC matrix for full range RGB. */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200405 mixer_reg_write(ctx, MXR_CM_COEFF_Y,
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100406 MXR_CSC_CT( 0.184, 0.614, 0.063) |
407 MXR_CM_COEFF_RGB_FULL);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200408 mixer_reg_write(ctx, MXR_CM_COEFF_CB,
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100409 MXR_CSC_CT(-0.102, -0.338, 0.440));
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200410 mixer_reg_write(ctx, MXR_CM_COEFF_CR,
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100411 MXR_CSC_CT( 0.440, -0.399, -0.040));
Tobias Jakobi2a39db02017-03-10 14:30:16 +0100412 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900413 }
414
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200415 mixer_reg_writemask(ctx, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900416}
417
Tobias Jakobi5b1d5bc2015-05-06 14:10:22 +0200418static void mixer_cfg_layer(struct mixer_context *ctx, unsigned int win,
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100419 unsigned int priority, bool enable)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900420{
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900421 u32 val = enable ? ~0 : 0;
422
423 switch (win) {
424 case 0:
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200425 mixer_reg_writemask(ctx, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
426 mixer_reg_writemask(ctx, MXR_LAYER_CFG,
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100427 MXR_LAYER_CFG_GRP0_VAL(priority),
428 MXR_LAYER_CFG_GRP0_MASK);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900429 break;
430 case 1:
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200431 mixer_reg_writemask(ctx, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
432 mixer_reg_writemask(ctx, MXR_LAYER_CFG,
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100433 MXR_LAYER_CFG_GRP1_VAL(priority),
434 MXR_LAYER_CFG_GRP1_MASK);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900435
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900436 break;
Marek Szyprowski5e68fef2015-12-16 13:21:48 +0100437 case VP_DEFAULT_WIN:
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900438 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200439 vp_reg_writemask(ctx, VP_ENABLE, val, VP_ENABLE_ON);
440 mixer_reg_writemask(ctx, MXR_CFG, val,
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530441 MXR_CFG_VP_ENABLE);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200442 mixer_reg_writemask(ctx, MXR_LAYER_CFG,
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100443 MXR_LAYER_CFG_VP_VAL(priority),
444 MXR_LAYER_CFG_VP_MASK);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530445 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900446 break;
447 }
448}
449
450static void mixer_run(struct mixer_context *ctx)
451{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200452 mixer_reg_writemask(ctx, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900453}
454
Rahul Sharma381be022014-06-23 11:02:22 +0530455static void mixer_stop(struct mixer_context *ctx)
456{
Rahul Sharma381be022014-06-23 11:02:22 +0530457 int timeout = 20;
458
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200459 mixer_reg_writemask(ctx, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
Rahul Sharma381be022014-06-23 11:02:22 +0530460
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200461 while (!(mixer_reg_read(ctx, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
Rahul Sharma381be022014-06-23 11:02:22 +0530462 --timeout)
463 usleep_range(10000, 12000);
Rahul Sharma381be022014-06-23 11:02:22 +0530464}
465
Andrzej Hajda521d98a2017-09-29 12:05:32 +0200466static void mixer_commit(struct mixer_context *ctx)
467{
468 struct drm_display_mode *mode = &ctx->crtc->base.state->adjusted_mode;
469
Andrzej Hajda71469942017-09-29 12:05:33 +0200470 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
471 __set_bit(MXR_BIT_INTERLACE, &ctx->flags);
472 else
473 __clear_bit(MXR_BIT_INTERLACE, &ctx->flags);
474
Andrzej Hajda3fc40ca2017-09-29 12:05:34 +0200475 mixer_cfg_scan(ctx, mode->hdisplay, mode->vdisplay);
Andrzej Hajda521d98a2017-09-29 12:05:32 +0200476 mixer_cfg_rgb_fmt(ctx, mode->vdisplay);
477 mixer_run(ctx);
478}
479
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900480static void vp_video_buffer(struct mixer_context *ctx,
481 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900482{
Marek Szyprowski0114f402015-11-30 14:53:22 +0100483 struct exynos_drm_plane_state *state =
484 to_exynos_plane_state(plane->base.state);
Marek Szyprowski0114f402015-11-30 14:53:22 +0100485 struct drm_framebuffer *fb = state->base.fb;
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200486 unsigned int priority = state->base.normalized_zpos + 1;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900487 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900488 dma_addr_t luma_addr[2], chroma_addr[2];
Tobias Jakobi0f752692017-08-22 16:19:38 +0200489 bool is_tiled, is_nv21;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900490 u32 val;
491
Tobias Jakobi0f752692017-08-22 16:19:38 +0200492 is_nv21 = (fb->format->format == DRM_FORMAT_NV21);
493 is_tiled = (fb->modifier == DRM_FORMAT_MOD_SAMSUNG_64_32_TILE);
Tobias Jakobif40031c2017-08-22 16:19:37 +0200494
Marek Szyprowski0488f502015-11-30 14:53:21 +0100495 luma_addr[0] = exynos_drm_fb_dma_addr(fb, 0);
496 chroma_addr[0] = exynos_drm_fb_dma_addr(fb, 1);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900497
Andrzej Hajda71469942017-09-29 12:05:33 +0200498 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
Tobias Jakobi0f752692017-08-22 16:19:38 +0200499 if (is_tiled) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900500 luma_addr[1] = luma_addr[0] + 0x40;
501 chroma_addr[1] = chroma_addr[0] + 0x40;
502 } else {
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900503 luma_addr[1] = luma_addr[0] + fb->pitches[0];
504 chroma_addr[1] = chroma_addr[0] + fb->pitches[0];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900505 }
506 } else {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900507 luma_addr[1] = 0;
508 chroma_addr[1] = 0;
509 }
510
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200511 spin_lock_irqsave(&ctx->reg_slock, flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900512
513 /* interlace or progressive scan mode */
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900514 val = (test_bit(MXR_BIT_INTERLACE, &ctx->flags) ? ~0 : 0);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200515 vp_reg_writemask(ctx, VP_MODE, val, VP_MODE_LINE_SKIP);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900516
517 /* setup format */
Tobias Jakobi0f752692017-08-22 16:19:38 +0200518 val = (is_nv21 ? VP_MODE_NV21 : VP_MODE_NV12);
519 val |= (is_tiled ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200520 vp_reg_writemask(ctx, VP_MODE, val, VP_MODE_FMT_MASK);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900521
522 /* setting size of input image */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200523 vp_reg_write(ctx, VP_IMG_SIZE_Y, VP_IMG_HSIZE(fb->pitches[0]) |
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900524 VP_IMG_VSIZE(fb->height));
Tobias Jakobidc500cf2017-08-22 16:19:36 +0200525 /* chroma plane for NV12/NV21 is half the height of the luma plane */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200526 vp_reg_write(ctx, VP_IMG_SIZE_C, VP_IMG_HSIZE(fb->pitches[0]) |
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900527 VP_IMG_VSIZE(fb->height / 2));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900528
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200529 vp_reg_write(ctx, VP_SRC_WIDTH, state->src.w);
530 vp_reg_write(ctx, VP_SRC_HEIGHT, state->src.h);
531 vp_reg_write(ctx, VP_SRC_H_POSITION,
Marek Szyprowski0114f402015-11-30 14:53:22 +0100532 VP_SRC_H_POSITION_VAL(state->src.x));
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200533 vp_reg_write(ctx, VP_SRC_V_POSITION, state->src.y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900534
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200535 vp_reg_write(ctx, VP_DST_WIDTH, state->crtc.w);
536 vp_reg_write(ctx, VP_DST_H_POSITION, state->crtc.x);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900537 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200538 vp_reg_write(ctx, VP_DST_HEIGHT, state->crtc.h / 2);
539 vp_reg_write(ctx, VP_DST_V_POSITION, state->crtc.y / 2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900540 } else {
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200541 vp_reg_write(ctx, VP_DST_HEIGHT, state->crtc.h);
542 vp_reg_write(ctx, VP_DST_V_POSITION, state->crtc.y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900543 }
544
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200545 vp_reg_write(ctx, VP_H_RATIO, state->h_ratio);
546 vp_reg_write(ctx, VP_V_RATIO, state->v_ratio);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900547
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200548 vp_reg_write(ctx, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900549
550 /* set buffer address to vp */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200551 vp_reg_write(ctx, VP_TOP_Y_PTR, luma_addr[0]);
552 vp_reg_write(ctx, VP_BOT_Y_PTR, luma_addr[1]);
553 vp_reg_write(ctx, VP_TOP_C_PTR, chroma_addr[0]);
554 vp_reg_write(ctx, VP_BOT_C_PTR, chroma_addr[1]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900555
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200556 mixer_cfg_layer(ctx, plane->index, priority, true);
Marek Szyprowskif657a992015-12-16 13:21:46 +0100557 mixer_cfg_vp_blend(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900558
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200559 spin_unlock_irqrestore(&ctx->reg_slock, flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900560
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200561 mixer_regs_dump(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900562 vp_regs_dump(ctx);
563}
564
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530565static void mixer_layer_update(struct mixer_context *ctx)
566{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200567 mixer_reg_writemask(ctx, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530568}
569
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900570static void mixer_graph_buffer(struct mixer_context *ctx,
571 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900572{
Marek Szyprowski0114f402015-11-30 14:53:22 +0100573 struct exynos_drm_plane_state *state =
574 to_exynos_plane_state(plane->base.state);
Marek Szyprowski0114f402015-11-30 14:53:22 +0100575 struct drm_framebuffer *fb = state->base.fb;
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200576 unsigned int priority = state->base.normalized_zpos + 1;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900577 unsigned long flags;
Marek Szyprowski40bdfb02015-12-16 13:21:42 +0100578 unsigned int win = plane->index;
Tobias Jakobi26110152015-04-07 01:14:52 +0200579 unsigned int x_ratio = 0, y_ratio = 0;
Tobias Jakobi5dff6902017-08-22 16:19:40 +0200580 unsigned int dst_x_offset, dst_y_offset;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900581 dma_addr_t dma_addr;
582 unsigned int fmt;
583 u32 val;
584
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200585 switch (fb->format->format) {
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200586 case DRM_FORMAT_XRGB4444:
Tobias Jakobi26a7af32015-12-16 13:21:47 +0100587 case DRM_FORMAT_ARGB4444:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200588 fmt = MXR_FORMAT_ARGB4444;
589 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900590
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200591 case DRM_FORMAT_XRGB1555:
Tobias Jakobi26a7af32015-12-16 13:21:47 +0100592 case DRM_FORMAT_ARGB1555:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200593 fmt = MXR_FORMAT_ARGB1555;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900594 break;
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200595
596 case DRM_FORMAT_RGB565:
597 fmt = MXR_FORMAT_RGB565;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900598 break;
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200599
600 case DRM_FORMAT_XRGB8888:
601 case DRM_FORMAT_ARGB8888:
Tobias Jakobi1e60d622017-08-22 16:19:39 +0200602 default:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200603 fmt = MXR_FORMAT_ARGB8888;
604 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900605 }
606
Marek Szyprowskie463b062015-11-30 14:53:27 +0100607 /* ratio is already checked by common plane code */
608 x_ratio = state->h_ratio == (1 << 15);
609 y_ratio = state->v_ratio == (1 << 15);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900610
Marek Szyprowski0114f402015-11-30 14:53:22 +0100611 dst_x_offset = state->crtc.x;
612 dst_y_offset = state->crtc.y;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900613
Tobias Jakobi5dff6902017-08-22 16:19:40 +0200614 /* translate dma address base s.t. the source image offset is zero */
Marek Szyprowski0488f502015-11-30 14:53:21 +0100615 dma_addr = exynos_drm_fb_dma_addr(fb, 0)
Ville Syrjälä272725c2016-12-14 23:32:20 +0200616 + (state->src.x * fb->format->cpp[0])
Marek Szyprowski0114f402015-11-30 14:53:22 +0100617 + (state->src.y * fb->pitches[0]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900618
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200619 spin_lock_irqsave(&ctx->reg_slock, flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900620
621 /* setup format */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200622 mixer_reg_writemask(ctx, MXR_GRAPHIC_CFG(win),
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900623 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
624
625 /* setup geometry */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200626 mixer_reg_write(ctx, MXR_GRAPHIC_SPAN(win),
Ville Syrjälä272725c2016-12-14 23:32:20 +0200627 fb->pitches[0] / fb->format->cpp[0]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900628
Marek Szyprowski0114f402015-11-30 14:53:22 +0100629 val = MXR_GRP_WH_WIDTH(state->src.w);
630 val |= MXR_GRP_WH_HEIGHT(state->src.h);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900631 val |= MXR_GRP_WH_H_SCALE(x_ratio);
632 val |= MXR_GRP_WH_V_SCALE(y_ratio);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200633 mixer_reg_write(ctx, MXR_GRAPHIC_WH(win), val);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900634
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900635 /* setup offsets in display image */
636 val = MXR_GRP_DXY_DX(dst_x_offset);
637 val |= MXR_GRP_DXY_DY(dst_y_offset);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200638 mixer_reg_write(ctx, MXR_GRAPHIC_DXY(win), val);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900639
640 /* set buffer address to mixer */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200641 mixer_reg_write(ctx, MXR_GRAPHIC_BASE(win), dma_addr);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900642
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200643 mixer_cfg_layer(ctx, win, priority, true);
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200644 mixer_cfg_gfx_blend(ctx, win, is_alpha_format(fb->format->format));
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530645
646 /* layer update mandatory for mixer 16.0.33.0 */
Rahul Sharmadef5e092013-06-19 18:21:08 +0530647 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
648 ctx->mxr_ver == MXR_VER_128_0_0_184)
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530649 mixer_layer_update(ctx);
650
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200651 spin_unlock_irqrestore(&ctx->reg_slock, flags);
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200652
653 mixer_regs_dump(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900654}
655
656static void vp_win_reset(struct mixer_context *ctx)
657{
Tobias Jakobia6963942016-09-22 16:57:19 +0200658 unsigned int tries = 100;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900659
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200660 vp_reg_write(ctx, VP_SRESET, VP_SRESET_PROCESSING);
Dan Carpenter8646dcb2017-01-20 17:54:32 +0100661 while (--tries) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900662 /* waiting until VP_SRESET_PROCESSING is 0 */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200663 if (~vp_reg_read(ctx, VP_SRESET) & VP_SRESET_PROCESSING)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900664 break;
Tomasz Stanislawski02b3de42015-09-25 14:48:29 +0200665 mdelay(10);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900666 }
667 WARN(tries == 0, "failed to reset Video Processor\n");
668}
669
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900670static void mixer_win_reset(struct mixer_context *ctx)
671{
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900672 unsigned long flags;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900673
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200674 spin_lock_irqsave(&ctx->reg_slock, flags);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900675
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200676 mixer_reg_writemask(ctx, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900677
678 /* set output in RGB888 mode */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200679 mixer_reg_writemask(ctx, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900680
681 /* 16 beat burst in DMA */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200682 mixer_reg_writemask(ctx, MXR_STATUS, MXR_STATUS_16_BURST,
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900683 MXR_STATUS_BURST_MASK);
684
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100685 /* reset default layer priority */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200686 mixer_reg_write(ctx, MXR_LAYER_CFG, 0);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900687
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100688 /* set all background colors to RGB (0,0,0) */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200689 mixer_reg_write(ctx, MXR_BG_COLOR0, MXR_YCBCR_VAL(0, 128, 128));
690 mixer_reg_write(ctx, MXR_BG_COLOR1, MXR_YCBCR_VAL(0, 128, 128));
691 mixer_reg_write(ctx, MXR_BG_COLOR2, MXR_YCBCR_VAL(0, 128, 128));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900692
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900693 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530694 /* configuration of Video Processor Registers */
695 vp_win_reset(ctx);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200696 vp_default_filter(ctx);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530697 }
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900698
699 /* disable all layers */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200700 mixer_reg_writemask(ctx, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
701 mixer_reg_writemask(ctx, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900702 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags))
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200703 mixer_reg_writemask(ctx, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900704
Tobias Jakobi5dff6902017-08-22 16:19:40 +0200705 /* set all source image offsets to zero */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200706 mixer_reg_write(ctx, MXR_GRAPHIC_SXY(0), 0);
707 mixer_reg_write(ctx, MXR_GRAPHIC_SXY(1), 0);
Tobias Jakobi5dff6902017-08-22 16:19:40 +0200708
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200709 spin_unlock_irqrestore(&ctx->reg_slock, flags);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900710}
711
Sean Paul45517892014-01-30 16:19:05 -0500712static irqreturn_t mixer_irq_handler(int irq, void *arg)
713{
714 struct mixer_context *ctx = arg;
Sean Paul45517892014-01-30 16:19:05 -0500715 u32 val, base, shadow;
716
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200717 spin_lock(&ctx->reg_slock);
Sean Paul45517892014-01-30 16:19:05 -0500718
719 /* read interrupt status for handling and clearing flags for VSYNC */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200720 val = mixer_reg_read(ctx, MXR_INT_STATUS);
Sean Paul45517892014-01-30 16:19:05 -0500721
722 /* handling VSYNC */
723 if (val & MXR_INT_STATUS_VSYNC) {
Andrzej Hajda81a464d2015-07-09 10:07:53 +0200724 /* vsync interrupt use different bit for read and clear */
725 val |= MXR_INT_CLEAR_VSYNC;
726 val &= ~MXR_INT_STATUS_VSYNC;
727
Sean Paul45517892014-01-30 16:19:05 -0500728 /* interlace scan need to check shadow register */
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900729 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200730 base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(0));
731 shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(0));
Sean Paul45517892014-01-30 16:19:05 -0500732 if (base != shadow)
733 goto out;
734
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200735 base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(1));
736 shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(1));
Sean Paul45517892014-01-30 16:19:05 -0500737 if (base != shadow)
738 goto out;
739 }
740
Gustavo Padovaneafd5402015-07-16 12:23:32 -0300741 drm_crtc_handle_vblank(&ctx->crtc->base);
Sean Paul45517892014-01-30 16:19:05 -0500742 }
743
744out:
745 /* clear interrupts */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200746 mixer_reg_write(ctx, MXR_INT_STATUS, val);
Sean Paul45517892014-01-30 16:19:05 -0500747
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200748 spin_unlock(&ctx->reg_slock);
Sean Paul45517892014-01-30 16:19:05 -0500749
750 return IRQ_HANDLED;
751}
752
753static int mixer_resources_init(struct mixer_context *mixer_ctx)
754{
755 struct device *dev = &mixer_ctx->pdev->dev;
Sean Paul45517892014-01-30 16:19:05 -0500756 struct resource *res;
757 int ret;
758
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200759 spin_lock_init(&mixer_ctx->reg_slock);
Sean Paul45517892014-01-30 16:19:05 -0500760
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200761 mixer_ctx->mixer = devm_clk_get(dev, "mixer");
762 if (IS_ERR(mixer_ctx->mixer)) {
Sean Paul45517892014-01-30 16:19:05 -0500763 dev_err(dev, "failed to get clock 'mixer'\n");
764 return -ENODEV;
765 }
766
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200767 mixer_ctx->hdmi = devm_clk_get(dev, "hdmi");
768 if (IS_ERR(mixer_ctx->hdmi)) {
Marek Szyprowski04427ec2015-02-02 14:20:28 +0100769 dev_err(dev, "failed to get clock 'hdmi'\n");
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200770 return PTR_ERR(mixer_ctx->hdmi);
Marek Szyprowski04427ec2015-02-02 14:20:28 +0100771 }
772
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200773 mixer_ctx->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
774 if (IS_ERR(mixer_ctx->sclk_hdmi)) {
Sean Paul45517892014-01-30 16:19:05 -0500775 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
776 return -ENODEV;
777 }
778 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
779 if (res == NULL) {
780 dev_err(dev, "get memory resource failed.\n");
781 return -ENXIO;
782 }
783
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200784 mixer_ctx->mixer_regs = devm_ioremap(dev, res->start,
Sean Paul45517892014-01-30 16:19:05 -0500785 resource_size(res));
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200786 if (mixer_ctx->mixer_regs == NULL) {
Sean Paul45517892014-01-30 16:19:05 -0500787 dev_err(dev, "register mapping failed.\n");
788 return -ENXIO;
789 }
790
791 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
792 if (res == NULL) {
793 dev_err(dev, "get interrupt resource failed.\n");
794 return -ENXIO;
795 }
796
797 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
798 0, "drm_mixer", mixer_ctx);
799 if (ret) {
800 dev_err(dev, "request interrupt failed.\n");
801 return ret;
802 }
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200803 mixer_ctx->irq = res->start;
Sean Paul45517892014-01-30 16:19:05 -0500804
805 return 0;
806}
807
808static int vp_resources_init(struct mixer_context *mixer_ctx)
809{
810 struct device *dev = &mixer_ctx->pdev->dev;
Sean Paul45517892014-01-30 16:19:05 -0500811 struct resource *res;
812
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200813 mixer_ctx->vp = devm_clk_get(dev, "vp");
814 if (IS_ERR(mixer_ctx->vp)) {
Sean Paul45517892014-01-30 16:19:05 -0500815 dev_err(dev, "failed to get clock 'vp'\n");
816 return -ENODEV;
817 }
Sean Paul45517892014-01-30 16:19:05 -0500818
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900819 if (test_bit(MXR_BIT_HAS_SCLK, &mixer_ctx->flags)) {
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200820 mixer_ctx->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
821 if (IS_ERR(mixer_ctx->sclk_mixer)) {
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200822 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
823 return -ENODEV;
824 }
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200825 mixer_ctx->mout_mixer = devm_clk_get(dev, "mout_mixer");
826 if (IS_ERR(mixer_ctx->mout_mixer)) {
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200827 dev_err(dev, "failed to get clock 'mout_mixer'\n");
828 return -ENODEV;
829 }
830
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200831 if (mixer_ctx->sclk_hdmi && mixer_ctx->mout_mixer)
832 clk_set_parent(mixer_ctx->mout_mixer,
833 mixer_ctx->sclk_hdmi);
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200834 }
Sean Paul45517892014-01-30 16:19:05 -0500835
836 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
837 if (res == NULL) {
838 dev_err(dev, "get memory resource failed.\n");
839 return -ENXIO;
840 }
841
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200842 mixer_ctx->vp_regs = devm_ioremap(dev, res->start,
Sean Paul45517892014-01-30 16:19:05 -0500843 resource_size(res));
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200844 if (mixer_ctx->vp_regs == NULL) {
Sean Paul45517892014-01-30 16:19:05 -0500845 dev_err(dev, "register mapping failed.\n");
846 return -ENXIO;
847 }
848
849 return 0;
850}
851
Gustavo Padovan93bca242015-01-18 18:16:23 +0900852static int mixer_initialize(struct mixer_context *mixer_ctx,
Inki Daef37cd5e2014-05-09 14:25:20 +0900853 struct drm_device *drm_dev)
Sean Paul45517892014-01-30 16:19:05 -0500854{
855 int ret;
Inki Daef37cd5e2014-05-09 14:25:20 +0900856 struct exynos_drm_private *priv;
857 priv = drm_dev->dev_private;
Sean Paul45517892014-01-30 16:19:05 -0500858
Gustavo Padovaneb88e422014-11-26 16:43:27 -0200859 mixer_ctx->drm_dev = drm_dev;
Sean Paul45517892014-01-30 16:19:05 -0500860
861 /* acquire resources: regs, irqs, clocks */
862 ret = mixer_resources_init(mixer_ctx);
863 if (ret) {
864 DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
865 return ret;
866 }
867
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900868 if (test_bit(MXR_BIT_VP_ENABLED, &mixer_ctx->flags)) {
Sean Paul45517892014-01-30 16:19:05 -0500869 /* acquire vp resources: regs, irqs, clocks */
870 ret = vp_resources_init(mixer_ctx);
871 if (ret) {
872 DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
873 return ret;
874 }
875 }
876
Andrzej Hajdaf44d3d22017-03-15 15:41:04 +0100877 return drm_iommu_attach_device(drm_dev, mixer_ctx->dev);
Sean Paul45517892014-01-30 16:19:05 -0500878}
879
Gustavo Padovan93bca242015-01-18 18:16:23 +0900880static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
Inki Dae1055b392012-10-19 17:37:35 +0900881{
Joonyoung Shimbf566082015-07-02 21:49:38 +0900882 drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Inki Dae1055b392012-10-19 17:37:35 +0900883}
884
Gustavo Padovan93bca242015-01-18 18:16:23 +0900885static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900886{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900887 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900888
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200889 __set_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
890 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Sean Paulf041b252014-01-30 16:19:15 -0500891 return 0;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900892
893 /* enable 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 return 0;
898}
899
Gustavo Padovan93bca242015-01-18 18:16:23 +0900900static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900901{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900902 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900903
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200904 __clear_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
905
906 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Andrzej Hajda947710c2015-07-09 08:25:41 +0200907 return;
Andrzej Hajda947710c2015-07-09 08:25:41 +0200908
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900909 /* disable vsync interrupt */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200910 mixer_reg_writemask(mixer_ctx, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
911 mixer_reg_writemask(mixer_ctx, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900912}
913
Marek Szyprowski3dbaab12016-01-05 13:52:52 +0100914static void mixer_atomic_begin(struct exynos_drm_crtc *crtc)
915{
916 struct mixer_context *mixer_ctx = crtc->ctx;
917
918 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
919 return;
920
921 mixer_vsync_set_update(mixer_ctx, false);
922}
923
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900924static void mixer_update_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
Marek Szyprowski40bdfb02015-12-16 13:21:42 +0100929 DRM_DEBUG_KMS("win: %d\n", plane->index);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900930
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200931 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Shirish Sdda90122013-01-23 22:03:18 -0500932 return;
Shirish Sdda90122013-01-23 22:03:18 -0500933
Marek Szyprowski5e68fef2015-12-16 13:21:48 +0100934 if (plane->index == VP_DEFAULT_WIN)
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900935 vp_video_buffer(mixer_ctx, plane);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900936 else
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900937 mixer_graph_buffer(mixer_ctx, plane);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900938}
939
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900940static void mixer_disable_plane(struct exynos_drm_crtc *crtc,
941 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900942{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900943 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900944 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900945
Marek Szyprowski40bdfb02015-12-16 13:21:42 +0100946 DRM_DEBUG_KMS("win: %d\n", plane->index);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900947
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200948 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Prathyush Kdb43fd12012-12-06 20:16:05 +0530949 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +0530950
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200951 spin_lock_irqsave(&mixer_ctx->reg_slock, flags);
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100952 mixer_cfg_layer(mixer_ctx, plane->index, 0, false);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200953 spin_unlock_irqrestore(&mixer_ctx->reg_slock, flags);
Marek Szyprowski3dbaab12016-01-05 13:52:52 +0100954}
955
956static void mixer_atomic_flush(struct exynos_drm_crtc *crtc)
957{
958 struct mixer_context *mixer_ctx = crtc->ctx;
959
960 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
961 return;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900962
963 mixer_vsync_set_update(mixer_ctx, true);
Andrzej Hajdaa3922762017-03-14 09:27:56 +0100964 exynos_crtc_handle_event(crtc);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900965}
966
Gustavo Padovan3cecda02015-06-01 12:04:55 -0300967static void mixer_enable(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +0530968{
Gustavo Padovan3cecda02015-06-01 12:04:55 -0300969 struct mixer_context *ctx = crtc->ctx;
Prathyush Kdb43fd12012-12-06 20:16:05 +0530970
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200971 if (test_bit(MXR_BIT_POWERED, &ctx->flags))
Prathyush Kdb43fd12012-12-06 20:16:05 +0530972 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +0530973
Sean Paulaf65c802014-01-30 16:19:27 -0500974 pm_runtime_get_sync(ctx->dev);
975
Andrzej Hajdaa121d172016-03-23 14:26:01 +0100976 exynos_drm_pipe_clk_enable(crtc, true);
977
Marek Szyprowski3dbaab12016-01-05 13:52:52 +0100978 mixer_vsync_set_update(ctx, false);
979
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200980 mixer_reg_writemask(ctx, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
Rahul Sharmad74ed932014-06-23 11:02:24 +0530981
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200982 if (test_bit(MXR_BIT_VSYNC, &ctx->flags)) {
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200983 mixer_reg_writemask(ctx, MXR_INT_STATUS, ~0,
984 MXR_INT_CLEAR_VSYNC);
985 mixer_reg_writemask(ctx, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200986 }
Prathyush Kdb43fd12012-12-06 20:16:05 +0530987 mixer_win_reset(ctx);
Gustavo Padovanccf034a2015-09-04 17:15:46 -0300988
Andrzej Hajda71469942017-09-29 12:05:33 +0200989 mixer_commit(ctx);
990
Marek Szyprowski3dbaab12016-01-05 13:52:52 +0100991 mixer_vsync_set_update(ctx, true);
992
Gustavo Padovanccf034a2015-09-04 17:15:46 -0300993 set_bit(MXR_BIT_POWERED, &ctx->flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530994}
995
Gustavo Padovan3cecda02015-06-01 12:04:55 -0300996static void mixer_disable(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +0530997{
Gustavo Padovan3cecda02015-06-01 12:04:55 -0300998 struct mixer_context *ctx = crtc->ctx;
Joonyoung Shimc329f662015-06-12 20:34:28 +0900999 int i;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301000
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001001 if (!test_bit(MXR_BIT_POWERED, &ctx->flags))
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301002 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301003
Rahul Sharma381be022014-06-23 11:02:22 +05301004 mixer_stop(ctx);
Tobias Jakobic0734fb2015-05-06 14:10:21 +02001005 mixer_regs_dump(ctx);
Joonyoung Shimc329f662015-06-12 20:34:28 +09001006
1007 for (i = 0; i < MIXER_WIN_NR; i++)
Gustavo Padovan1e1d1392015-08-03 14:39:36 +09001008 mixer_disable_plane(crtc, &ctx->planes[i]);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301009
Andrzej Hajdaa121d172016-03-23 14:26:01 +01001010 exynos_drm_pipe_clk_enable(crtc, false);
1011
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001012 pm_runtime_put(ctx->dev);
1013
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001014 clear_bit(MXR_BIT_POWERED, &ctx->flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301015}
1016
Andrzej Hajda6ace38a2017-09-29 12:05:35 +02001017static int mixer_mode_valid(struct exynos_drm_crtc *crtc,
1018 const struct drm_display_mode *mode)
Sean Paulf041b252014-01-30 16:19:15 -05001019{
Andrzej Hajda6ace38a2017-09-29 12:05:35 +02001020 struct mixer_context *ctx = crtc->ctx;
1021 u32 w = mode->hdisplay, h = mode->vdisplay;
Sean Paulf041b252014-01-30 16:19:15 -05001022
Andrzej Hajda6ace38a2017-09-29 12:05:35 +02001023 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n", w, h,
1024 mode->vrefresh, !!(mode->flags & DRM_MODE_FLAG_INTERLACE));
Sean Paulf041b252014-01-30 16:19:15 -05001025
Andrzej Hajda6ace38a2017-09-29 12:05:35 +02001026 if (ctx->mxr_ver == MXR_VER_128_0_0_184)
1027 return MODE_OK;
Sean Paulf041b252014-01-30 16:19:15 -05001028
1029 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
Andrzej Hajda6ace38a2017-09-29 12:05:35 +02001030 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1031 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1032 return MODE_OK;
Sean Paulf041b252014-01-30 16:19:15 -05001033
Andrzej Hajda6ace38a2017-09-29 12:05:35 +02001034 return MODE_BAD;
Sean Paulf041b252014-01-30 16:19:15 -05001035}
1036
Krzysztof Kozlowskif3aaf762015-05-07 09:04:45 +09001037static const struct exynos_drm_crtc_ops mixer_crtc_ops = {
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001038 .enable = mixer_enable,
1039 .disable = mixer_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001040 .enable_vblank = mixer_enable_vblank,
1041 .disable_vblank = mixer_disable_vblank,
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001042 .atomic_begin = mixer_atomic_begin,
Gustavo Padovan9cc76102015-08-03 14:38:05 +09001043 .update_plane = mixer_update_plane,
1044 .disable_plane = mixer_disable_plane,
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001045 .atomic_flush = mixer_atomic_flush,
Andrzej Hajda6ace38a2017-09-29 12:05:35 +02001046 .mode_valid = mixer_mode_valid,
Sean Paulf041b252014-01-30 16:19:15 -05001047};
Rahul Sharma0ea68222013-01-15 08:11:06 -05001048
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301049static const struct mixer_drv_data exynos5420_mxr_drv_data = {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301050 .version = MXR_VER_128_0_0_184,
1051 .is_vp_enabled = 0,
1052};
1053
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301054static const struct mixer_drv_data exynos5250_mxr_drv_data = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301055 .version = MXR_VER_16_0_33_0,
1056 .is_vp_enabled = 0,
1057};
1058
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301059static const struct mixer_drv_data exynos4212_mxr_drv_data = {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001060 .version = MXR_VER_0_0_0_16,
1061 .is_vp_enabled = 1,
1062};
1063
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301064static const struct mixer_drv_data exynos4210_mxr_drv_data = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301065 .version = MXR_VER_0_0_0_16,
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301066 .is_vp_enabled = 1,
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001067 .has_sclk = 1,
Rahul Sharma1e123442012-10-04 20:48:51 +05301068};
1069
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301070static const struct of_device_id mixer_match_types[] = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301071 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001072 .compatible = "samsung,exynos4210-mixer",
1073 .data = &exynos4210_mxr_drv_data,
1074 }, {
1075 .compatible = "samsung,exynos4212-mixer",
1076 .data = &exynos4212_mxr_drv_data,
1077 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301078 .compatible = "samsung,exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301079 .data = &exynos5250_mxr_drv_data,
1080 }, {
1081 .compatible = "samsung,exynos5250-mixer",
1082 .data = &exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301083 }, {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301084 .compatible = "samsung,exynos5420-mixer",
1085 .data = &exynos5420_mxr_drv_data,
1086 }, {
Rahul Sharma1e123442012-10-04 20:48:51 +05301087 /* end node */
1088 }
1089};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001090MODULE_DEVICE_TABLE(of, mixer_match_types);
Rahul Sharma1e123442012-10-04 20:48:51 +05301091
Inki Daef37cd5e2014-05-09 14:25:20 +09001092static int mixer_bind(struct device *dev, struct device *manager, void *data)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001093{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001094 struct mixer_context *ctx = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09001095 struct drm_device *drm_dev = data;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001096 struct exynos_drm_plane *exynos_plane;
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +01001097 unsigned int i;
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +09001098 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001099
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001100 ret = mixer_initialize(ctx, drm_dev);
1101 if (ret)
1102 return ret;
1103
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +01001104 for (i = 0; i < MIXER_WIN_NR; i++) {
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001105 if (i == VP_DEFAULT_WIN && !test_bit(MXR_BIT_VP_ENABLED,
1106 &ctx->flags))
Marek Szyprowskiab144202015-11-30 14:53:24 +01001107 continue;
1108
Marek Szyprowski40bdfb02015-12-16 13:21:42 +01001109 ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
Andrzej Hajda2c826072017-03-15 15:41:05 +01001110 &plane_configs[i]);
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001111 if (ret)
1112 return ret;
1113 }
1114
Gustavo Padovan5d3d0992015-10-12 22:07:48 +09001115 exynos_plane = &ctx->planes[DEFAULT_WIN];
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001116 ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
Andrzej Hajdad6449512017-05-29 10:05:25 +09001117 EXYNOS_DISPLAY_TYPE_HDMI, &mixer_crtc_ops, ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001118 if (IS_ERR(ctx->crtc)) {
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001119 mixer_ctx_remove(ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001120 ret = PTR_ERR(ctx->crtc);
1121 goto free_ctx;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001122 }
1123
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001124 return 0;
Gustavo Padovan93bca242015-01-18 18:16:23 +09001125
1126free_ctx:
1127 devm_kfree(dev, ctx);
1128 return ret;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001129}
1130
1131static void mixer_unbind(struct device *dev, struct device *master, void *data)
1132{
1133 struct mixer_context *ctx = dev_get_drvdata(dev);
1134
Gustavo Padovan93bca242015-01-18 18:16:23 +09001135 mixer_ctx_remove(ctx);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001136}
1137
1138static const struct component_ops mixer_component_ops = {
1139 .bind = mixer_bind,
1140 .unbind = mixer_unbind,
1141};
1142
1143static int mixer_probe(struct platform_device *pdev)
1144{
1145 struct device *dev = &pdev->dev;
Marek Szyprowski48f61552016-04-01 15:17:46 +02001146 const struct mixer_drv_data *drv;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001147 struct mixer_context *ctx;
1148 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001149
Sean Paulf041b252014-01-30 16:19:15 -05001150 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1151 if (!ctx) {
1152 DRM_ERROR("failed to alloc mixer context.\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001153 return -ENOMEM;
Sean Paulf041b252014-01-30 16:19:15 -05001154 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001155
Marek Szyprowski48f61552016-04-01 15:17:46 +02001156 drv = of_device_get_match_data(dev);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301157
Sean Paul45517892014-01-30 16:19:05 -05001158 ctx->pdev = pdev;
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001159 ctx->dev = dev;
Rahul Sharma1e123442012-10-04 20:48:51 +05301160 ctx->mxr_ver = drv->version;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001161
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001162 if (drv->is_vp_enabled)
1163 __set_bit(MXR_BIT_VP_ENABLED, &ctx->flags);
1164 if (drv->has_sclk)
1165 __set_bit(MXR_BIT_HAS_SCLK, &ctx->flags);
1166
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001167 platform_set_drvdata(pdev, ctx);
Inki Daedf5225b2014-05-29 18:28:02 +09001168
Inki Daedf5225b2014-05-29 18:28:02 +09001169 ret = component_add(&pdev->dev, &mixer_component_ops);
Andrzej Hajda86650402015-06-11 23:23:37 +09001170 if (!ret)
1171 pm_runtime_enable(dev);
Inki Daedf5225b2014-05-29 18:28:02 +09001172
1173 return ret;
Inki Daef37cd5e2014-05-09 14:25:20 +09001174}
1175
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001176static int mixer_remove(struct platform_device *pdev)
1177{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001178 pm_runtime_disable(&pdev->dev);
1179
Inki Daedf5225b2014-05-29 18:28:02 +09001180 component_del(&pdev->dev, &mixer_component_ops);
Inki Daedf5225b2014-05-29 18:28:02 +09001181
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001182 return 0;
1183}
1184
Arnd Bergmanne0fea7e2015-11-17 16:08:36 +01001185static int __maybe_unused exynos_mixer_suspend(struct device *dev)
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001186{
1187 struct mixer_context *ctx = dev_get_drvdata(dev);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001188
Andrzej Hajda524c59f2017-09-29 12:05:36 +02001189 clk_disable_unprepare(ctx->hdmi);
1190 clk_disable_unprepare(ctx->mixer);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001191 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Andrzej Hajda524c59f2017-09-29 12:05:36 +02001192 clk_disable_unprepare(ctx->vp);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001193 if (test_bit(MXR_BIT_HAS_SCLK, &ctx->flags))
Andrzej Hajda524c59f2017-09-29 12:05:36 +02001194 clk_disable_unprepare(ctx->sclk_mixer);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001195 }
1196
1197 return 0;
1198}
1199
Arnd Bergmanne0fea7e2015-11-17 16:08:36 +01001200static int __maybe_unused exynos_mixer_resume(struct device *dev)
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001201{
1202 struct mixer_context *ctx = dev_get_drvdata(dev);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001203 int ret;
1204
Andrzej Hajda524c59f2017-09-29 12:05:36 +02001205 ret = clk_prepare_enable(ctx->mixer);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001206 if (ret < 0) {
1207 DRM_ERROR("Failed to prepare_enable the mixer clk [%d]\n", ret);
1208 return ret;
1209 }
Andrzej Hajda524c59f2017-09-29 12:05:36 +02001210 ret = clk_prepare_enable(ctx->hdmi);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001211 if (ret < 0) {
1212 DRM_ERROR("Failed to prepare_enable the hdmi clk [%d]\n", ret);
1213 return ret;
1214 }
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001215 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Andrzej Hajda524c59f2017-09-29 12:05:36 +02001216 ret = clk_prepare_enable(ctx->vp);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001217 if (ret < 0) {
1218 DRM_ERROR("Failed to prepare_enable the vp clk [%d]\n",
1219 ret);
1220 return ret;
1221 }
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001222 if (test_bit(MXR_BIT_HAS_SCLK, &ctx->flags)) {
Andrzej Hajda524c59f2017-09-29 12:05:36 +02001223 ret = clk_prepare_enable(ctx->sclk_mixer);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001224 if (ret < 0) {
1225 DRM_ERROR("Failed to prepare_enable the " \
1226 "sclk_mixer clk [%d]\n",
1227 ret);
1228 return ret;
1229 }
1230 }
1231 }
1232
1233 return 0;
1234}
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001235
1236static const struct dev_pm_ops exynos_mixer_pm_ops = {
1237 SET_RUNTIME_PM_OPS(exynos_mixer_suspend, exynos_mixer_resume, NULL)
1238};
1239
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001240struct platform_driver mixer_driver = {
1241 .driver = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301242 .name = "exynos-mixer",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001243 .owner = THIS_MODULE,
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001244 .pm = &exynos_mixer_pm_ops,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301245 .of_match_table = mixer_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001246 },
1247 .probe = mixer_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001248 .remove = mixer_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001249};