blob: 272c79f5f5bff856dfa4a29a2574a70ee72366cf [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
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200182static inline u32 vp_reg_read(struct mixer_context *ctx, u32 reg_id)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900183{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200184 return readl(ctx->vp_regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900185}
186
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200187static inline void vp_reg_write(struct mixer_context *ctx, u32 reg_id,
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900188 u32 val)
189{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200190 writel(val, ctx->vp_regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900191}
192
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200193static inline void vp_reg_writemask(struct mixer_context *ctx, u32 reg_id,
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900194 u32 val, u32 mask)
195{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200196 u32 old = vp_reg_read(ctx, reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900197
198 val = (val & mask) | (old & ~mask);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200199 writel(val, ctx->vp_regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900200}
201
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200202static inline u32 mixer_reg_read(struct mixer_context *ctx, u32 reg_id)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900203{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200204 return readl(ctx->mixer_regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900205}
206
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200207static inline void mixer_reg_write(struct mixer_context *ctx, u32 reg_id,
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900208 u32 val)
209{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200210 writel(val, ctx->mixer_regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900211}
212
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200213static inline void mixer_reg_writemask(struct mixer_context *ctx,
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900214 u32 reg_id, u32 val, u32 mask)
215{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200216 u32 old = mixer_reg_read(ctx, reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900217
218 val = (val & mask) | (old & ~mask);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200219 writel(val, ctx->mixer_regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900220}
221
222static void mixer_regs_dump(struct mixer_context *ctx)
223{
224#define DUMPREG(reg_id) \
225do { \
226 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200227 (u32)readl(ctx->mixer_regs + reg_id)); \
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900228} while (0)
229
230 DUMPREG(MXR_STATUS);
231 DUMPREG(MXR_CFG);
232 DUMPREG(MXR_INT_EN);
233 DUMPREG(MXR_INT_STATUS);
234
235 DUMPREG(MXR_LAYER_CFG);
236 DUMPREG(MXR_VIDEO_CFG);
237
238 DUMPREG(MXR_GRAPHIC0_CFG);
239 DUMPREG(MXR_GRAPHIC0_BASE);
240 DUMPREG(MXR_GRAPHIC0_SPAN);
241 DUMPREG(MXR_GRAPHIC0_WH);
242 DUMPREG(MXR_GRAPHIC0_SXY);
243 DUMPREG(MXR_GRAPHIC0_DXY);
244
245 DUMPREG(MXR_GRAPHIC1_CFG);
246 DUMPREG(MXR_GRAPHIC1_BASE);
247 DUMPREG(MXR_GRAPHIC1_SPAN);
248 DUMPREG(MXR_GRAPHIC1_WH);
249 DUMPREG(MXR_GRAPHIC1_SXY);
250 DUMPREG(MXR_GRAPHIC1_DXY);
251#undef DUMPREG
252}
253
254static void vp_regs_dump(struct mixer_context *ctx)
255{
256#define DUMPREG(reg_id) \
257do { \
258 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200259 (u32) readl(ctx->vp_regs + reg_id)); \
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900260} while (0)
261
262 DUMPREG(VP_ENABLE);
263 DUMPREG(VP_SRESET);
264 DUMPREG(VP_SHADOW_UPDATE);
265 DUMPREG(VP_FIELD_ID);
266 DUMPREG(VP_MODE);
267 DUMPREG(VP_IMG_SIZE_Y);
268 DUMPREG(VP_IMG_SIZE_C);
269 DUMPREG(VP_PER_RATE_CTRL);
270 DUMPREG(VP_TOP_Y_PTR);
271 DUMPREG(VP_BOT_Y_PTR);
272 DUMPREG(VP_TOP_C_PTR);
273 DUMPREG(VP_BOT_C_PTR);
274 DUMPREG(VP_ENDIAN_MODE);
275 DUMPREG(VP_SRC_H_POSITION);
276 DUMPREG(VP_SRC_V_POSITION);
277 DUMPREG(VP_SRC_WIDTH);
278 DUMPREG(VP_SRC_HEIGHT);
279 DUMPREG(VP_DST_H_POSITION);
280 DUMPREG(VP_DST_V_POSITION);
281 DUMPREG(VP_DST_WIDTH);
282 DUMPREG(VP_DST_HEIGHT);
283 DUMPREG(VP_H_RATIO);
284 DUMPREG(VP_V_RATIO);
285
286#undef DUMPREG
287}
288
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200289static inline void vp_filter_set(struct mixer_context *ctx,
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900290 int reg_id, const u8 *data, unsigned int size)
291{
292 /* assure 4-byte align */
293 BUG_ON(size & 3);
294 for (; size; size -= 4, reg_id += 4, data += 4) {
295 u32 val = (data[0] << 24) | (data[1] << 16) |
296 (data[2] << 8) | data[3];
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200297 vp_reg_write(ctx, reg_id, val);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900298 }
299}
300
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200301static void vp_default_filter(struct mixer_context *ctx)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900302{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200303 vp_filter_set(ctx, VP_POLY8_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530304 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200305 vp_filter_set(ctx, VP_POLY4_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530306 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200307 vp_filter_set(ctx, VP_POLY4_C0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530308 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900309}
310
Marek Szyprowskif657a992015-12-16 13:21:46 +0100311static void mixer_cfg_gfx_blend(struct mixer_context *ctx, unsigned int win,
312 bool alpha)
313{
Marek Szyprowskif657a992015-12-16 13:21:46 +0100314 u32 val;
315
316 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
317 if (alpha) {
318 /* blending based on pixel alpha */
319 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
320 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
321 }
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200322 mixer_reg_writemask(ctx, MXR_GRAPHIC_CFG(win),
Marek Szyprowskif657a992015-12-16 13:21:46 +0100323 val, MXR_GRP_CFG_MISC_MASK);
324}
325
326static void mixer_cfg_vp_blend(struct mixer_context *ctx)
327{
Marek Szyprowskif657a992015-12-16 13:21:46 +0100328 u32 val;
329
330 /*
331 * No blending at the moment since the NV12/NV21 pixelformats don't
332 * have an alpha channel. However the mixer supports a global alpha
333 * value for a layer. Once this functionality is exposed, we can
334 * support blending of the video layer through this.
335 */
336 val = 0;
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200337 mixer_reg_write(ctx, MXR_VIDEO_CFG, val);
Marek Szyprowskif657a992015-12-16 13:21:46 +0100338}
339
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900340static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
341{
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900342 /* block update on vsync */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200343 mixer_reg_writemask(ctx, MXR_STATUS, enable ?
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900344 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
345
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900346 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags))
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200347 vp_reg_write(ctx, VP_SHADOW_UPDATE, enable ?
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900348 VP_SHADOW_UPDATE_ENABLE : 0);
349}
350
Andrzej Hajda3fc40ca2017-09-29 12:05:34 +0200351static void mixer_cfg_scan(struct mixer_context *ctx, int width, int height)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900352{
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900353 u32 val;
354
355 /* choosing between interlace and progressive mode */
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900356 val = test_bit(MXR_BIT_INTERLACE, &ctx->flags) ?
357 MXR_CFG_SCAN_INTERLACE : MXR_CFG_SCAN_PROGRESSIVE;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900358
Andrzej Hajdaacc8bf02017-09-29 12:05:39 +0200359 if (ctx->mxr_ver == MXR_VER_128_0_0_184)
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200360 mixer_reg_write(ctx, MXR_RESOLUTION,
Andrzej Hajda3fc40ca2017-09-29 12:05:34 +0200361 MXR_MXR_RES_HEIGHT(height) | MXR_MXR_RES_WIDTH(width));
Andrzej Hajdaacc8bf02017-09-29 12:05:39 +0200362 else
363 val |= ctx->scan_value;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900364
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200365 mixer_reg_writemask(ctx, MXR_CFG, val, MXR_CFG_SCAN_MASK);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900366}
367
368static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
369{
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900370 u32 val;
371
Tobias Jakobi2a39db02017-03-10 14:30:16 +0100372 switch (height) {
373 case 480:
374 case 576:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900375 val = MXR_CFG_RGB601_0_255;
Tobias Jakobi2a39db02017-03-10 14:30:16 +0100376 break;
377 case 720:
378 case 1080:
379 default:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900380 val = MXR_CFG_RGB709_16_235;
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100381 /* Configure the BT.709 CSC matrix for full range RGB. */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200382 mixer_reg_write(ctx, MXR_CM_COEFF_Y,
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100383 MXR_CSC_CT( 0.184, 0.614, 0.063) |
384 MXR_CM_COEFF_RGB_FULL);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200385 mixer_reg_write(ctx, MXR_CM_COEFF_CB,
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100386 MXR_CSC_CT(-0.102, -0.338, 0.440));
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200387 mixer_reg_write(ctx, MXR_CM_COEFF_CR,
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100388 MXR_CSC_CT( 0.440, -0.399, -0.040));
Tobias Jakobi2a39db02017-03-10 14:30:16 +0100389 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900390 }
391
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200392 mixer_reg_writemask(ctx, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900393}
394
Tobias Jakobi5b1d5bc2015-05-06 14:10:22 +0200395static void mixer_cfg_layer(struct mixer_context *ctx, unsigned int win,
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100396 unsigned int priority, bool enable)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900397{
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900398 u32 val = enable ? ~0 : 0;
399
400 switch (win) {
401 case 0:
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200402 mixer_reg_writemask(ctx, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
403 mixer_reg_writemask(ctx, MXR_LAYER_CFG,
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100404 MXR_LAYER_CFG_GRP0_VAL(priority),
405 MXR_LAYER_CFG_GRP0_MASK);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900406 break;
407 case 1:
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200408 mixer_reg_writemask(ctx, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
409 mixer_reg_writemask(ctx, MXR_LAYER_CFG,
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100410 MXR_LAYER_CFG_GRP1_VAL(priority),
411 MXR_LAYER_CFG_GRP1_MASK);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900412
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900413 break;
Marek Szyprowski5e68fef2015-12-16 13:21:48 +0100414 case VP_DEFAULT_WIN:
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900415 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200416 vp_reg_writemask(ctx, VP_ENABLE, val, VP_ENABLE_ON);
417 mixer_reg_writemask(ctx, MXR_CFG, val,
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530418 MXR_CFG_VP_ENABLE);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200419 mixer_reg_writemask(ctx, MXR_LAYER_CFG,
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100420 MXR_LAYER_CFG_VP_VAL(priority),
421 MXR_LAYER_CFG_VP_MASK);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530422 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900423 break;
424 }
425}
426
427static void mixer_run(struct mixer_context *ctx)
428{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200429 mixer_reg_writemask(ctx, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900430}
431
Rahul Sharma381be022014-06-23 11:02:22 +0530432static void mixer_stop(struct mixer_context *ctx)
433{
Rahul Sharma381be022014-06-23 11:02:22 +0530434 int timeout = 20;
435
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200436 mixer_reg_writemask(ctx, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
Rahul Sharma381be022014-06-23 11:02:22 +0530437
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200438 while (!(mixer_reg_read(ctx, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
Rahul Sharma381be022014-06-23 11:02:22 +0530439 --timeout)
440 usleep_range(10000, 12000);
Rahul Sharma381be022014-06-23 11:02:22 +0530441}
442
Andrzej Hajda521d98a2017-09-29 12:05:32 +0200443static void mixer_commit(struct mixer_context *ctx)
444{
445 struct drm_display_mode *mode = &ctx->crtc->base.state->adjusted_mode;
446
Andrzej Hajda3fc40ca2017-09-29 12:05:34 +0200447 mixer_cfg_scan(ctx, mode->hdisplay, mode->vdisplay);
Andrzej Hajda521d98a2017-09-29 12:05:32 +0200448 mixer_cfg_rgb_fmt(ctx, mode->vdisplay);
449 mixer_run(ctx);
450}
451
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900452static void vp_video_buffer(struct mixer_context *ctx,
453 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900454{
Marek Szyprowski0114f402015-11-30 14:53:22 +0100455 struct exynos_drm_plane_state *state =
456 to_exynos_plane_state(plane->base.state);
Marek Szyprowski0114f402015-11-30 14:53:22 +0100457 struct drm_framebuffer *fb = state->base.fb;
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200458 unsigned int priority = state->base.normalized_zpos + 1;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900459 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900460 dma_addr_t luma_addr[2], chroma_addr[2];
Tobias Jakobi0f752692017-08-22 16:19:38 +0200461 bool is_tiled, is_nv21;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900462 u32 val;
463
Tobias Jakobi0f752692017-08-22 16:19:38 +0200464 is_nv21 = (fb->format->format == DRM_FORMAT_NV21);
465 is_tiled = (fb->modifier == DRM_FORMAT_MOD_SAMSUNG_64_32_TILE);
Tobias Jakobif40031c2017-08-22 16:19:37 +0200466
Marek Szyprowski0488f502015-11-30 14:53:21 +0100467 luma_addr[0] = exynos_drm_fb_dma_addr(fb, 0);
468 chroma_addr[0] = exynos_drm_fb_dma_addr(fb, 1);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900469
Andrzej Hajda71469942017-09-29 12:05:33 +0200470 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
Tobias Jakobi0f752692017-08-22 16:19:38 +0200471 if (is_tiled) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900472 luma_addr[1] = luma_addr[0] + 0x40;
473 chroma_addr[1] = chroma_addr[0] + 0x40;
474 } else {
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900475 luma_addr[1] = luma_addr[0] + fb->pitches[0];
Tobias Jakobi0ccc1c82018-02-02 16:11:23 +0100476 chroma_addr[1] = chroma_addr[0] + fb->pitches[1];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900477 }
478 } else {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900479 luma_addr[1] = 0;
480 chroma_addr[1] = 0;
481 }
482
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200483 spin_lock_irqsave(&ctx->reg_slock, flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900484
Andrzej Hajda2eced8e2018-02-02 16:11:22 +0100485 vp_reg_write(ctx, VP_SHADOW_UPDATE, 1);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900486 /* interlace or progressive scan mode */
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900487 val = (test_bit(MXR_BIT_INTERLACE, &ctx->flags) ? ~0 : 0);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200488 vp_reg_writemask(ctx, VP_MODE, val, VP_MODE_LINE_SKIP);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900489
490 /* setup format */
Tobias Jakobi0f752692017-08-22 16:19:38 +0200491 val = (is_nv21 ? VP_MODE_NV21 : VP_MODE_NV12);
492 val |= (is_tiled ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200493 vp_reg_writemask(ctx, VP_MODE, val, VP_MODE_FMT_MASK);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900494
495 /* setting size of input image */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200496 vp_reg_write(ctx, VP_IMG_SIZE_Y, VP_IMG_HSIZE(fb->pitches[0]) |
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900497 VP_IMG_VSIZE(fb->height));
Tobias Jakobidc500cf2017-08-22 16:19:36 +0200498 /* chroma plane for NV12/NV21 is half the height of the luma plane */
Tobias Jakobi0ccc1c82018-02-02 16:11:23 +0100499 vp_reg_write(ctx, VP_IMG_SIZE_C, VP_IMG_HSIZE(fb->pitches[1]) |
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900500 VP_IMG_VSIZE(fb->height / 2));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900501
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200502 vp_reg_write(ctx, VP_SRC_WIDTH, state->src.w);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200503 vp_reg_write(ctx, VP_SRC_H_POSITION,
Marek Szyprowski0114f402015-11-30 14:53:22 +0100504 VP_SRC_H_POSITION_VAL(state->src.x));
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200505 vp_reg_write(ctx, VP_DST_WIDTH, state->crtc.w);
506 vp_reg_write(ctx, VP_DST_H_POSITION, state->crtc.x);
Tobias Jakobi0ccc1c82018-02-02 16:11:23 +0100507
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900508 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
Tobias Jakobi0ccc1c82018-02-02 16:11:23 +0100509 vp_reg_write(ctx, VP_SRC_HEIGHT, state->src.h / 2);
510 vp_reg_write(ctx, VP_SRC_V_POSITION, state->src.y / 2);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200511 vp_reg_write(ctx, VP_DST_HEIGHT, state->crtc.h / 2);
512 vp_reg_write(ctx, VP_DST_V_POSITION, state->crtc.y / 2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900513 } else {
Tobias Jakobi0ccc1c82018-02-02 16:11:23 +0100514 vp_reg_write(ctx, VP_SRC_HEIGHT, state->src.h);
515 vp_reg_write(ctx, VP_SRC_V_POSITION, state->src.y);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200516 vp_reg_write(ctx, VP_DST_HEIGHT, state->crtc.h);
517 vp_reg_write(ctx, VP_DST_V_POSITION, state->crtc.y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900518 }
519
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200520 vp_reg_write(ctx, VP_H_RATIO, state->h_ratio);
521 vp_reg_write(ctx, VP_V_RATIO, state->v_ratio);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900522
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200523 vp_reg_write(ctx, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900524
525 /* set buffer address to vp */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200526 vp_reg_write(ctx, VP_TOP_Y_PTR, luma_addr[0]);
527 vp_reg_write(ctx, VP_BOT_Y_PTR, luma_addr[1]);
528 vp_reg_write(ctx, VP_TOP_C_PTR, chroma_addr[0]);
529 vp_reg_write(ctx, VP_BOT_C_PTR, chroma_addr[1]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900530
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200531 mixer_cfg_layer(ctx, plane->index, priority, true);
Marek Szyprowskif657a992015-12-16 13:21:46 +0100532 mixer_cfg_vp_blend(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900533
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200534 spin_unlock_irqrestore(&ctx->reg_slock, flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900535
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200536 mixer_regs_dump(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900537 vp_regs_dump(ctx);
538}
539
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530540static void mixer_layer_update(struct mixer_context *ctx)
541{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200542 mixer_reg_writemask(ctx, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530543}
544
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900545static void mixer_graph_buffer(struct mixer_context *ctx,
546 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900547{
Marek Szyprowski0114f402015-11-30 14:53:22 +0100548 struct exynos_drm_plane_state *state =
549 to_exynos_plane_state(plane->base.state);
Marek Szyprowski0114f402015-11-30 14:53:22 +0100550 struct drm_framebuffer *fb = state->base.fb;
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200551 unsigned int priority = state->base.normalized_zpos + 1;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900552 unsigned long flags;
Marek Szyprowski40bdfb02015-12-16 13:21:42 +0100553 unsigned int win = plane->index;
Tobias Jakobi26110152015-04-07 01:14:52 +0200554 unsigned int x_ratio = 0, y_ratio = 0;
Tobias Jakobi5dff6902017-08-22 16:19:40 +0200555 unsigned int dst_x_offset, dst_y_offset;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900556 dma_addr_t dma_addr;
557 unsigned int fmt;
558 u32 val;
559
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200560 switch (fb->format->format) {
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200561 case DRM_FORMAT_XRGB4444:
Tobias Jakobi26a7af32015-12-16 13:21:47 +0100562 case DRM_FORMAT_ARGB4444:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200563 fmt = MXR_FORMAT_ARGB4444;
564 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900565
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200566 case DRM_FORMAT_XRGB1555:
Tobias Jakobi26a7af32015-12-16 13:21:47 +0100567 case DRM_FORMAT_ARGB1555:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200568 fmt = MXR_FORMAT_ARGB1555;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900569 break;
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200570
571 case DRM_FORMAT_RGB565:
572 fmt = MXR_FORMAT_RGB565;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900573 break;
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200574
575 case DRM_FORMAT_XRGB8888:
576 case DRM_FORMAT_ARGB8888:
Tobias Jakobi1e60d622017-08-22 16:19:39 +0200577 default:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200578 fmt = MXR_FORMAT_ARGB8888;
579 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900580 }
581
Marek Szyprowskie463b062015-11-30 14:53:27 +0100582 /* ratio is already checked by common plane code */
583 x_ratio = state->h_ratio == (1 << 15);
584 y_ratio = state->v_ratio == (1 << 15);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900585
Marek Szyprowski0114f402015-11-30 14:53:22 +0100586 dst_x_offset = state->crtc.x;
587 dst_y_offset = state->crtc.y;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900588
Tobias Jakobi5dff6902017-08-22 16:19:40 +0200589 /* translate dma address base s.t. the source image offset is zero */
Marek Szyprowski0488f502015-11-30 14:53:21 +0100590 dma_addr = exynos_drm_fb_dma_addr(fb, 0)
Ville Syrjälä272725c2016-12-14 23:32:20 +0200591 + (state->src.x * fb->format->cpp[0])
Marek Szyprowski0114f402015-11-30 14:53:22 +0100592 + (state->src.y * fb->pitches[0]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900593
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200594 spin_lock_irqsave(&ctx->reg_slock, flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900595
596 /* setup format */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200597 mixer_reg_writemask(ctx, MXR_GRAPHIC_CFG(win),
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900598 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
599
600 /* setup geometry */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200601 mixer_reg_write(ctx, MXR_GRAPHIC_SPAN(win),
Ville Syrjälä272725c2016-12-14 23:32:20 +0200602 fb->pitches[0] / fb->format->cpp[0]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900603
Marek Szyprowski0114f402015-11-30 14:53:22 +0100604 val = MXR_GRP_WH_WIDTH(state->src.w);
605 val |= MXR_GRP_WH_HEIGHT(state->src.h);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900606 val |= MXR_GRP_WH_H_SCALE(x_ratio);
607 val |= MXR_GRP_WH_V_SCALE(y_ratio);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200608 mixer_reg_write(ctx, MXR_GRAPHIC_WH(win), val);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900609
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900610 /* setup offsets in display image */
611 val = MXR_GRP_DXY_DX(dst_x_offset);
612 val |= MXR_GRP_DXY_DY(dst_y_offset);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200613 mixer_reg_write(ctx, MXR_GRAPHIC_DXY(win), val);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900614
615 /* set buffer address to mixer */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200616 mixer_reg_write(ctx, MXR_GRAPHIC_BASE(win), dma_addr);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900617
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200618 mixer_cfg_layer(ctx, win, priority, true);
Maxime Ripardc89e1d22017-12-22 15:31:27 +0100619 mixer_cfg_gfx_blend(ctx, win, fb->format->has_alpha);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530620
621 /* layer update mandatory for mixer 16.0.33.0 */
Rahul Sharmadef5e092013-06-19 18:21:08 +0530622 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
623 ctx->mxr_ver == MXR_VER_128_0_0_184)
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530624 mixer_layer_update(ctx);
625
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200626 spin_unlock_irqrestore(&ctx->reg_slock, flags);
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200627
628 mixer_regs_dump(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900629}
630
631static void vp_win_reset(struct mixer_context *ctx)
632{
Tobias Jakobia6963942016-09-22 16:57:19 +0200633 unsigned int tries = 100;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900634
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200635 vp_reg_write(ctx, VP_SRESET, VP_SRESET_PROCESSING);
Dan Carpenter8646dcb2017-01-20 17:54:32 +0100636 while (--tries) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900637 /* waiting until VP_SRESET_PROCESSING is 0 */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200638 if (~vp_reg_read(ctx, VP_SRESET) & VP_SRESET_PROCESSING)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900639 break;
Tomasz Stanislawski02b3de42015-09-25 14:48:29 +0200640 mdelay(10);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900641 }
642 WARN(tries == 0, "failed to reset Video Processor\n");
643}
644
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900645static void mixer_win_reset(struct mixer_context *ctx)
646{
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900647 unsigned long flags;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900648
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200649 spin_lock_irqsave(&ctx->reg_slock, flags);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900650
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200651 mixer_reg_writemask(ctx, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900652
653 /* set output in RGB888 mode */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200654 mixer_reg_writemask(ctx, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900655
656 /* 16 beat burst in DMA */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200657 mixer_reg_writemask(ctx, MXR_STATUS, MXR_STATUS_16_BURST,
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900658 MXR_STATUS_BURST_MASK);
659
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100660 /* reset default layer priority */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200661 mixer_reg_write(ctx, MXR_LAYER_CFG, 0);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900662
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100663 /* set all background colors to RGB (0,0,0) */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200664 mixer_reg_write(ctx, MXR_BG_COLOR0, MXR_YCBCR_VAL(0, 128, 128));
665 mixer_reg_write(ctx, MXR_BG_COLOR1, MXR_YCBCR_VAL(0, 128, 128));
666 mixer_reg_write(ctx, MXR_BG_COLOR2, MXR_YCBCR_VAL(0, 128, 128));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900667
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900668 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530669 /* configuration of Video Processor Registers */
670 vp_win_reset(ctx);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200671 vp_default_filter(ctx);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530672 }
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900673
674 /* disable all layers */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200675 mixer_reg_writemask(ctx, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
676 mixer_reg_writemask(ctx, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900677 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags))
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200678 mixer_reg_writemask(ctx, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900679
Tobias Jakobi5dff6902017-08-22 16:19:40 +0200680 /* set all source image offsets to zero */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200681 mixer_reg_write(ctx, MXR_GRAPHIC_SXY(0), 0);
682 mixer_reg_write(ctx, MXR_GRAPHIC_SXY(1), 0);
Tobias Jakobi5dff6902017-08-22 16:19:40 +0200683
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200684 spin_unlock_irqrestore(&ctx->reg_slock, flags);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900685}
686
Sean Paul45517892014-01-30 16:19:05 -0500687static irqreturn_t mixer_irq_handler(int irq, void *arg)
688{
689 struct mixer_context *ctx = arg;
Sean Paul45517892014-01-30 16:19:05 -0500690 u32 val, base, shadow;
691
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200692 spin_lock(&ctx->reg_slock);
Sean Paul45517892014-01-30 16:19:05 -0500693
694 /* read interrupt status for handling and clearing flags for VSYNC */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200695 val = mixer_reg_read(ctx, MXR_INT_STATUS);
Sean Paul45517892014-01-30 16:19:05 -0500696
697 /* handling VSYNC */
698 if (val & MXR_INT_STATUS_VSYNC) {
Andrzej Hajda81a464d2015-07-09 10:07:53 +0200699 /* vsync interrupt use different bit for read and clear */
700 val |= MXR_INT_CLEAR_VSYNC;
701 val &= ~MXR_INT_STATUS_VSYNC;
702
Sean Paul45517892014-01-30 16:19:05 -0500703 /* interlace scan need to check shadow register */
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900704 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
Andrzej Hajda2eced8e2018-02-02 16:11:22 +0100705 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags) &&
706 vp_reg_read(ctx, VP_SHADOW_UPDATE))
707 goto out;
708
709 base = mixer_reg_read(ctx, MXR_CFG);
710 shadow = mixer_reg_read(ctx, MXR_CFG_S);
711 if (base != shadow)
712 goto out;
713
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};