blob: 257299ec95c435ae08660f7f659f62c7577e2b1c [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];
476 chroma_addr[1] = chroma_addr[0] + fb->pitches[0];
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
485 /* interlace or progressive scan mode */
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900486 val = (test_bit(MXR_BIT_INTERLACE, &ctx->flags) ? ~0 : 0);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200487 vp_reg_writemask(ctx, VP_MODE, val, VP_MODE_LINE_SKIP);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900488
489 /* setup format */
Tobias Jakobi0f752692017-08-22 16:19:38 +0200490 val = (is_nv21 ? VP_MODE_NV21 : VP_MODE_NV12);
491 val |= (is_tiled ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200492 vp_reg_writemask(ctx, VP_MODE, val, VP_MODE_FMT_MASK);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900493
494 /* setting size of input image */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200495 vp_reg_write(ctx, VP_IMG_SIZE_Y, VP_IMG_HSIZE(fb->pitches[0]) |
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900496 VP_IMG_VSIZE(fb->height));
Tobias Jakobidc500cf2017-08-22 16:19:36 +0200497 /* chroma plane for NV12/NV21 is half the height of the luma plane */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200498 vp_reg_write(ctx, VP_IMG_SIZE_C, VP_IMG_HSIZE(fb->pitches[0]) |
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900499 VP_IMG_VSIZE(fb->height / 2));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900500
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200501 vp_reg_write(ctx, VP_SRC_WIDTH, state->src.w);
502 vp_reg_write(ctx, VP_SRC_HEIGHT, state->src.h);
503 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_SRC_V_POSITION, state->src.y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900506
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200507 vp_reg_write(ctx, VP_DST_WIDTH, state->crtc.w);
508 vp_reg_write(ctx, VP_DST_H_POSITION, state->crtc.x);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900509 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200510 vp_reg_write(ctx, VP_DST_HEIGHT, state->crtc.h / 2);
511 vp_reg_write(ctx, VP_DST_V_POSITION, state->crtc.y / 2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900512 } else {
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200513 vp_reg_write(ctx, VP_DST_HEIGHT, state->crtc.h);
514 vp_reg_write(ctx, VP_DST_V_POSITION, state->crtc.y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900515 }
516
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200517 vp_reg_write(ctx, VP_H_RATIO, state->h_ratio);
518 vp_reg_write(ctx, VP_V_RATIO, state->v_ratio);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900519
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200520 vp_reg_write(ctx, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900521
522 /* set buffer address to vp */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200523 vp_reg_write(ctx, VP_TOP_Y_PTR, luma_addr[0]);
524 vp_reg_write(ctx, VP_BOT_Y_PTR, luma_addr[1]);
525 vp_reg_write(ctx, VP_TOP_C_PTR, chroma_addr[0]);
526 vp_reg_write(ctx, VP_BOT_C_PTR, chroma_addr[1]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900527
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200528 mixer_cfg_layer(ctx, plane->index, priority, true);
Marek Szyprowskif657a992015-12-16 13:21:46 +0100529 mixer_cfg_vp_blend(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900530
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200531 spin_unlock_irqrestore(&ctx->reg_slock, flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900532
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200533 mixer_regs_dump(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900534 vp_regs_dump(ctx);
535}
536
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530537static void mixer_layer_update(struct mixer_context *ctx)
538{
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200539 mixer_reg_writemask(ctx, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530540}
541
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900542static void mixer_graph_buffer(struct mixer_context *ctx,
543 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900544{
Marek Szyprowski0114f402015-11-30 14:53:22 +0100545 struct exynos_drm_plane_state *state =
546 to_exynos_plane_state(plane->base.state);
Marek Szyprowski0114f402015-11-30 14:53:22 +0100547 struct drm_framebuffer *fb = state->base.fb;
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200548 unsigned int priority = state->base.normalized_zpos + 1;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900549 unsigned long flags;
Marek Szyprowski40bdfb02015-12-16 13:21:42 +0100550 unsigned int win = plane->index;
Tobias Jakobi26110152015-04-07 01:14:52 +0200551 unsigned int x_ratio = 0, y_ratio = 0;
Tobias Jakobi5dff6902017-08-22 16:19:40 +0200552 unsigned int dst_x_offset, dst_y_offset;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900553 dma_addr_t dma_addr;
554 unsigned int fmt;
555 u32 val;
556
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200557 switch (fb->format->format) {
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200558 case DRM_FORMAT_XRGB4444:
Tobias Jakobi26a7af32015-12-16 13:21:47 +0100559 case DRM_FORMAT_ARGB4444:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200560 fmt = MXR_FORMAT_ARGB4444;
561 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900562
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200563 case DRM_FORMAT_XRGB1555:
Tobias Jakobi26a7af32015-12-16 13:21:47 +0100564 case DRM_FORMAT_ARGB1555:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200565 fmt = MXR_FORMAT_ARGB1555;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900566 break;
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200567
568 case DRM_FORMAT_RGB565:
569 fmt = MXR_FORMAT_RGB565;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900570 break;
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200571
572 case DRM_FORMAT_XRGB8888:
573 case DRM_FORMAT_ARGB8888:
Tobias Jakobi1e60d622017-08-22 16:19:39 +0200574 default:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200575 fmt = MXR_FORMAT_ARGB8888;
576 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900577 }
578
Marek Szyprowskie463b062015-11-30 14:53:27 +0100579 /* ratio is already checked by common plane code */
580 x_ratio = state->h_ratio == (1 << 15);
581 y_ratio = state->v_ratio == (1 << 15);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900582
Marek Szyprowski0114f402015-11-30 14:53:22 +0100583 dst_x_offset = state->crtc.x;
584 dst_y_offset = state->crtc.y;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900585
Tobias Jakobi5dff6902017-08-22 16:19:40 +0200586 /* translate dma address base s.t. the source image offset is zero */
Marek Szyprowski0488f502015-11-30 14:53:21 +0100587 dma_addr = exynos_drm_fb_dma_addr(fb, 0)
Ville Syrjälä272725c2016-12-14 23:32:20 +0200588 + (state->src.x * fb->format->cpp[0])
Marek Szyprowski0114f402015-11-30 14:53:22 +0100589 + (state->src.y * fb->pitches[0]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900590
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200591 spin_lock_irqsave(&ctx->reg_slock, flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900592
593 /* setup format */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200594 mixer_reg_writemask(ctx, MXR_GRAPHIC_CFG(win),
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900595 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
596
597 /* setup geometry */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200598 mixer_reg_write(ctx, MXR_GRAPHIC_SPAN(win),
Ville Syrjälä272725c2016-12-14 23:32:20 +0200599 fb->pitches[0] / fb->format->cpp[0]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900600
Marek Szyprowski0114f402015-11-30 14:53:22 +0100601 val = MXR_GRP_WH_WIDTH(state->src.w);
602 val |= MXR_GRP_WH_HEIGHT(state->src.h);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900603 val |= MXR_GRP_WH_H_SCALE(x_ratio);
604 val |= MXR_GRP_WH_V_SCALE(y_ratio);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200605 mixer_reg_write(ctx, MXR_GRAPHIC_WH(win), val);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900606
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900607 /* setup offsets in display image */
608 val = MXR_GRP_DXY_DX(dst_x_offset);
609 val |= MXR_GRP_DXY_DY(dst_y_offset);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200610 mixer_reg_write(ctx, MXR_GRAPHIC_DXY(win), val);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900611
612 /* set buffer address to mixer */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200613 mixer_reg_write(ctx, MXR_GRAPHIC_BASE(win), dma_addr);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900614
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200615 mixer_cfg_layer(ctx, win, priority, true);
Maxime Ripardc89e1d22017-12-22 15:31:27 +0100616 mixer_cfg_gfx_blend(ctx, win, fb->format->has_alpha);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530617
618 /* layer update mandatory for mixer 16.0.33.0 */
Rahul Sharmadef5e092013-06-19 18:21:08 +0530619 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
620 ctx->mxr_ver == MXR_VER_128_0_0_184)
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530621 mixer_layer_update(ctx);
622
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200623 spin_unlock_irqrestore(&ctx->reg_slock, flags);
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200624
625 mixer_regs_dump(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900626}
627
628static void vp_win_reset(struct mixer_context *ctx)
629{
Tobias Jakobia6963942016-09-22 16:57:19 +0200630 unsigned int tries = 100;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900631
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200632 vp_reg_write(ctx, VP_SRESET, VP_SRESET_PROCESSING);
Dan Carpenter8646dcb2017-01-20 17:54:32 +0100633 while (--tries) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900634 /* waiting until VP_SRESET_PROCESSING is 0 */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200635 if (~vp_reg_read(ctx, VP_SRESET) & VP_SRESET_PROCESSING)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900636 break;
Tomasz Stanislawski02b3de42015-09-25 14:48:29 +0200637 mdelay(10);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900638 }
639 WARN(tries == 0, "failed to reset Video Processor\n");
640}
641
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900642static void mixer_win_reset(struct mixer_context *ctx)
643{
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900644 unsigned long flags;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900645
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200646 spin_lock_irqsave(&ctx->reg_slock, flags);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900647
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200648 mixer_reg_writemask(ctx, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900649
650 /* set output in RGB888 mode */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200651 mixer_reg_writemask(ctx, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900652
653 /* 16 beat burst in DMA */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200654 mixer_reg_writemask(ctx, MXR_STATUS, MXR_STATUS_16_BURST,
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900655 MXR_STATUS_BURST_MASK);
656
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100657 /* reset default layer priority */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200658 mixer_reg_write(ctx, MXR_LAYER_CFG, 0);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900659
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100660 /* set all background colors to RGB (0,0,0) */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200661 mixer_reg_write(ctx, MXR_BG_COLOR0, MXR_YCBCR_VAL(0, 128, 128));
662 mixer_reg_write(ctx, MXR_BG_COLOR1, MXR_YCBCR_VAL(0, 128, 128));
663 mixer_reg_write(ctx, MXR_BG_COLOR2, MXR_YCBCR_VAL(0, 128, 128));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900664
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900665 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530666 /* configuration of Video Processor Registers */
667 vp_win_reset(ctx);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200668 vp_default_filter(ctx);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530669 }
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900670
671 /* disable all layers */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200672 mixer_reg_writemask(ctx, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
673 mixer_reg_writemask(ctx, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900674 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags))
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200675 mixer_reg_writemask(ctx, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900676
Tobias Jakobi5dff6902017-08-22 16:19:40 +0200677 /* set all source image offsets to zero */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200678 mixer_reg_write(ctx, MXR_GRAPHIC_SXY(0), 0);
679 mixer_reg_write(ctx, MXR_GRAPHIC_SXY(1), 0);
Tobias Jakobi5dff6902017-08-22 16:19:40 +0200680
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200681 spin_unlock_irqrestore(&ctx->reg_slock, flags);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900682}
683
Sean Paul45517892014-01-30 16:19:05 -0500684static irqreturn_t mixer_irq_handler(int irq, void *arg)
685{
686 struct mixer_context *ctx = arg;
Sean Paul45517892014-01-30 16:19:05 -0500687 u32 val, base, shadow;
688
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200689 spin_lock(&ctx->reg_slock);
Sean Paul45517892014-01-30 16:19:05 -0500690
691 /* read interrupt status for handling and clearing flags for VSYNC */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200692 val = mixer_reg_read(ctx, MXR_INT_STATUS);
Sean Paul45517892014-01-30 16:19:05 -0500693
694 /* handling VSYNC */
695 if (val & MXR_INT_STATUS_VSYNC) {
Andrzej Hajda81a464d2015-07-09 10:07:53 +0200696 /* vsync interrupt use different bit for read and clear */
697 val |= MXR_INT_CLEAR_VSYNC;
698 val &= ~MXR_INT_STATUS_VSYNC;
699
Sean Paul45517892014-01-30 16:19:05 -0500700 /* interlace scan need to check shadow register */
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900701 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200702 base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(0));
703 shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(0));
Sean Paul45517892014-01-30 16:19:05 -0500704 if (base != shadow)
705 goto out;
706
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200707 base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(1));
708 shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(1));
Sean Paul45517892014-01-30 16:19:05 -0500709 if (base != shadow)
710 goto out;
711 }
712
Gustavo Padovaneafd5402015-07-16 12:23:32 -0300713 drm_crtc_handle_vblank(&ctx->crtc->base);
Sean Paul45517892014-01-30 16:19:05 -0500714 }
715
716out:
717 /* clear interrupts */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200718 mixer_reg_write(ctx, MXR_INT_STATUS, val);
Sean Paul45517892014-01-30 16:19:05 -0500719
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200720 spin_unlock(&ctx->reg_slock);
Sean Paul45517892014-01-30 16:19:05 -0500721
722 return IRQ_HANDLED;
723}
724
725static int mixer_resources_init(struct mixer_context *mixer_ctx)
726{
727 struct device *dev = &mixer_ctx->pdev->dev;
Sean Paul45517892014-01-30 16:19:05 -0500728 struct resource *res;
729 int ret;
730
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200731 spin_lock_init(&mixer_ctx->reg_slock);
Sean Paul45517892014-01-30 16:19:05 -0500732
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200733 mixer_ctx->mixer = devm_clk_get(dev, "mixer");
734 if (IS_ERR(mixer_ctx->mixer)) {
Sean Paul45517892014-01-30 16:19:05 -0500735 dev_err(dev, "failed to get clock 'mixer'\n");
736 return -ENODEV;
737 }
738
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200739 mixer_ctx->hdmi = devm_clk_get(dev, "hdmi");
740 if (IS_ERR(mixer_ctx->hdmi)) {
Marek Szyprowski04427ec2015-02-02 14:20:28 +0100741 dev_err(dev, "failed to get clock 'hdmi'\n");
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200742 return PTR_ERR(mixer_ctx->hdmi);
Marek Szyprowski04427ec2015-02-02 14:20:28 +0100743 }
744
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200745 mixer_ctx->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
746 if (IS_ERR(mixer_ctx->sclk_hdmi)) {
Sean Paul45517892014-01-30 16:19:05 -0500747 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
748 return -ENODEV;
749 }
750 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
751 if (res == NULL) {
752 dev_err(dev, "get memory resource failed.\n");
753 return -ENXIO;
754 }
755
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200756 mixer_ctx->mixer_regs = devm_ioremap(dev, res->start,
Sean Paul45517892014-01-30 16:19:05 -0500757 resource_size(res));
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200758 if (mixer_ctx->mixer_regs == NULL) {
Sean Paul45517892014-01-30 16:19:05 -0500759 dev_err(dev, "register mapping failed.\n");
760 return -ENXIO;
761 }
762
763 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
764 if (res == NULL) {
765 dev_err(dev, "get interrupt resource failed.\n");
766 return -ENXIO;
767 }
768
769 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
770 0, "drm_mixer", mixer_ctx);
771 if (ret) {
772 dev_err(dev, "request interrupt failed.\n");
773 return ret;
774 }
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200775 mixer_ctx->irq = res->start;
Sean Paul45517892014-01-30 16:19:05 -0500776
777 return 0;
778}
779
780static int vp_resources_init(struct mixer_context *mixer_ctx)
781{
782 struct device *dev = &mixer_ctx->pdev->dev;
Sean Paul45517892014-01-30 16:19:05 -0500783 struct resource *res;
784
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200785 mixer_ctx->vp = devm_clk_get(dev, "vp");
786 if (IS_ERR(mixer_ctx->vp)) {
Sean Paul45517892014-01-30 16:19:05 -0500787 dev_err(dev, "failed to get clock 'vp'\n");
788 return -ENODEV;
789 }
Sean Paul45517892014-01-30 16:19:05 -0500790
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900791 if (test_bit(MXR_BIT_HAS_SCLK, &mixer_ctx->flags)) {
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200792 mixer_ctx->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
793 if (IS_ERR(mixer_ctx->sclk_mixer)) {
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200794 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
795 return -ENODEV;
796 }
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200797 mixer_ctx->mout_mixer = devm_clk_get(dev, "mout_mixer");
798 if (IS_ERR(mixer_ctx->mout_mixer)) {
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200799 dev_err(dev, "failed to get clock 'mout_mixer'\n");
800 return -ENODEV;
801 }
802
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200803 if (mixer_ctx->sclk_hdmi && mixer_ctx->mout_mixer)
804 clk_set_parent(mixer_ctx->mout_mixer,
805 mixer_ctx->sclk_hdmi);
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200806 }
Sean Paul45517892014-01-30 16:19:05 -0500807
808 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
809 if (res == NULL) {
810 dev_err(dev, "get memory resource failed.\n");
811 return -ENXIO;
812 }
813
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200814 mixer_ctx->vp_regs = devm_ioremap(dev, res->start,
Sean Paul45517892014-01-30 16:19:05 -0500815 resource_size(res));
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200816 if (mixer_ctx->vp_regs == NULL) {
Sean Paul45517892014-01-30 16:19:05 -0500817 dev_err(dev, "register mapping failed.\n");
818 return -ENXIO;
819 }
820
821 return 0;
822}
823
Gustavo Padovan93bca242015-01-18 18:16:23 +0900824static int mixer_initialize(struct mixer_context *mixer_ctx,
Inki Daef37cd5e2014-05-09 14:25:20 +0900825 struct drm_device *drm_dev)
Sean Paul45517892014-01-30 16:19:05 -0500826{
827 int ret;
Inki Daef37cd5e2014-05-09 14:25:20 +0900828 struct exynos_drm_private *priv;
829 priv = drm_dev->dev_private;
Sean Paul45517892014-01-30 16:19:05 -0500830
Gustavo Padovaneb88e422014-11-26 16:43:27 -0200831 mixer_ctx->drm_dev = drm_dev;
Sean Paul45517892014-01-30 16:19:05 -0500832
833 /* acquire resources: regs, irqs, clocks */
834 ret = mixer_resources_init(mixer_ctx);
835 if (ret) {
836 DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
837 return ret;
838 }
839
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900840 if (test_bit(MXR_BIT_VP_ENABLED, &mixer_ctx->flags)) {
Sean Paul45517892014-01-30 16:19:05 -0500841 /* acquire vp resources: regs, irqs, clocks */
842 ret = vp_resources_init(mixer_ctx);
843 if (ret) {
844 DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
845 return ret;
846 }
847 }
848
Andrzej Hajdaf44d3d22017-03-15 15:41:04 +0100849 return drm_iommu_attach_device(drm_dev, mixer_ctx->dev);
Sean Paul45517892014-01-30 16:19:05 -0500850}
851
Gustavo Padovan93bca242015-01-18 18:16:23 +0900852static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
Inki Dae1055b392012-10-19 17:37:35 +0900853{
Joonyoung Shimbf566082015-07-02 21:49:38 +0900854 drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Inki Dae1055b392012-10-19 17:37:35 +0900855}
856
Gustavo Padovan93bca242015-01-18 18:16:23 +0900857static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900858{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900859 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900860
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200861 __set_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
862 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Sean Paulf041b252014-01-30 16:19:15 -0500863 return 0;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900864
865 /* enable vsync interrupt */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200866 mixer_reg_writemask(mixer_ctx, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
867 mixer_reg_writemask(mixer_ctx, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900868
869 return 0;
870}
871
Gustavo Padovan93bca242015-01-18 18:16:23 +0900872static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900873{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900874 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900875
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200876 __clear_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
877
878 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Andrzej Hajda947710c2015-07-09 08:25:41 +0200879 return;
Andrzej Hajda947710c2015-07-09 08:25:41 +0200880
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900881 /* disable vsync interrupt */
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200882 mixer_reg_writemask(mixer_ctx, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
883 mixer_reg_writemask(mixer_ctx, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900884}
885
Marek Szyprowski3dbaab12016-01-05 13:52:52 +0100886static void mixer_atomic_begin(struct exynos_drm_crtc *crtc)
887{
888 struct mixer_context *mixer_ctx = crtc->ctx;
889
890 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
891 return;
892
893 mixer_vsync_set_update(mixer_ctx, false);
894}
895
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900896static void mixer_update_plane(struct exynos_drm_crtc *crtc,
897 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900898{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900899 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900900
Marek Szyprowski40bdfb02015-12-16 13:21:42 +0100901 DRM_DEBUG_KMS("win: %d\n", plane->index);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900902
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200903 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Shirish Sdda90122013-01-23 22:03:18 -0500904 return;
Shirish Sdda90122013-01-23 22:03:18 -0500905
Marek Szyprowski5e68fef2015-12-16 13:21:48 +0100906 if (plane->index == VP_DEFAULT_WIN)
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900907 vp_video_buffer(mixer_ctx, plane);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900908 else
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900909 mixer_graph_buffer(mixer_ctx, plane);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900910}
911
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900912static void mixer_disable_plane(struct exynos_drm_crtc *crtc,
913 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900914{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900915 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900916 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900917
Marek Szyprowski40bdfb02015-12-16 13:21:42 +0100918 DRM_DEBUG_KMS("win: %d\n", plane->index);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900919
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200920 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Prathyush Kdb43fd12012-12-06 20:16:05 +0530921 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +0530922
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200923 spin_lock_irqsave(&mixer_ctx->reg_slock, flags);
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100924 mixer_cfg_layer(mixer_ctx, plane->index, 0, false);
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200925 spin_unlock_irqrestore(&mixer_ctx->reg_slock, flags);
Marek Szyprowski3dbaab12016-01-05 13:52:52 +0100926}
927
928static void mixer_atomic_flush(struct exynos_drm_crtc *crtc)
929{
930 struct mixer_context *mixer_ctx = crtc->ctx;
931
932 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
933 return;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900934
935 mixer_vsync_set_update(mixer_ctx, true);
Andrzej Hajdaa3922762017-03-14 09:27:56 +0100936 exynos_crtc_handle_event(crtc);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900937}
938
Gustavo Padovan3cecda02015-06-01 12:04:55 -0300939static void mixer_enable(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +0530940{
Gustavo Padovan3cecda02015-06-01 12:04:55 -0300941 struct mixer_context *ctx = crtc->ctx;
Prathyush Kdb43fd12012-12-06 20:16:05 +0530942
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200943 if (test_bit(MXR_BIT_POWERED, &ctx->flags))
Prathyush Kdb43fd12012-12-06 20:16:05 +0530944 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +0530945
Sean Paulaf65c802014-01-30 16:19:27 -0500946 pm_runtime_get_sync(ctx->dev);
947
Andrzej Hajdaa121d172016-03-23 14:26:01 +0100948 exynos_drm_pipe_clk_enable(crtc, true);
949
Marek Szyprowski3dbaab12016-01-05 13:52:52 +0100950 mixer_vsync_set_update(ctx, false);
951
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200952 mixer_reg_writemask(ctx, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
Rahul Sharmad74ed932014-06-23 11:02:24 +0530953
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200954 if (test_bit(MXR_BIT_VSYNC, &ctx->flags)) {
Andrzej Hajda524c59f2017-09-29 12:05:36 +0200955 mixer_reg_writemask(ctx, MXR_INT_STATUS, ~0,
956 MXR_INT_CLEAR_VSYNC);
957 mixer_reg_writemask(ctx, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200958 }
Prathyush Kdb43fd12012-12-06 20:16:05 +0530959 mixer_win_reset(ctx);
Gustavo Padovanccf034a2015-09-04 17:15:46 -0300960
Andrzej Hajda71469942017-09-29 12:05:33 +0200961 mixer_commit(ctx);
962
Marek Szyprowski3dbaab12016-01-05 13:52:52 +0100963 mixer_vsync_set_update(ctx, true);
964
Gustavo Padovanccf034a2015-09-04 17:15:46 -0300965 set_bit(MXR_BIT_POWERED, &ctx->flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530966}
967
Gustavo Padovan3cecda02015-06-01 12:04:55 -0300968static void mixer_disable(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +0530969{
Gustavo Padovan3cecda02015-06-01 12:04:55 -0300970 struct mixer_context *ctx = crtc->ctx;
Joonyoung Shimc329f662015-06-12 20:34:28 +0900971 int i;
Prathyush Kdb43fd12012-12-06 20:16:05 +0530972
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200973 if (!test_bit(MXR_BIT_POWERED, &ctx->flags))
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +0530974 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +0530975
Rahul Sharma381be022014-06-23 11:02:22 +0530976 mixer_stop(ctx);
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200977 mixer_regs_dump(ctx);
Joonyoung Shimc329f662015-06-12 20:34:28 +0900978
979 for (i = 0; i < MIXER_WIN_NR; i++)
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900980 mixer_disable_plane(crtc, &ctx->planes[i]);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530981
Andrzej Hajdaa121d172016-03-23 14:26:01 +0100982 exynos_drm_pipe_clk_enable(crtc, false);
983
Gustavo Padovanccf034a2015-09-04 17:15:46 -0300984 pm_runtime_put(ctx->dev);
985
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200986 clear_bit(MXR_BIT_POWERED, &ctx->flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +0530987}
988
Andrzej Hajda6ace38a2017-09-29 12:05:35 +0200989static int mixer_mode_valid(struct exynos_drm_crtc *crtc,
990 const struct drm_display_mode *mode)
Sean Paulf041b252014-01-30 16:19:15 -0500991{
Andrzej Hajda6ace38a2017-09-29 12:05:35 +0200992 struct mixer_context *ctx = crtc->ctx;
993 u32 w = mode->hdisplay, h = mode->vdisplay;
Sean Paulf041b252014-01-30 16:19:15 -0500994
Andrzej Hajda6ace38a2017-09-29 12:05:35 +0200995 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n", w, h,
996 mode->vrefresh, !!(mode->flags & DRM_MODE_FLAG_INTERLACE));
Sean Paulf041b252014-01-30 16:19:15 -0500997
Andrzej Hajda6ace38a2017-09-29 12:05:35 +0200998 if (ctx->mxr_ver == MXR_VER_128_0_0_184)
999 return MODE_OK;
Sean Paulf041b252014-01-30 16:19:15 -05001000
1001 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
Andrzej Hajda6ace38a2017-09-29 12:05:35 +02001002 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1003 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1004 return MODE_OK;
Sean Paulf041b252014-01-30 16:19:15 -05001005
Daniel Drakeae58c032017-09-29 12:05:42 +02001006 if ((w == 1024 && h == 768) ||
1007 (w == 1366 && h == 768) ||
1008 (w == 1280 && h == 1024))
Andrzej Hajda09006732017-09-29 12:05:41 +02001009 return MODE_OK;
1010
Andrzej Hajda6ace38a2017-09-29 12:05:35 +02001011 return MODE_BAD;
Sean Paulf041b252014-01-30 16:19:15 -05001012}
1013
Andrzej Hajdaacc8bf02017-09-29 12:05:39 +02001014static bool mixer_mode_fixup(struct exynos_drm_crtc *crtc,
1015 const struct drm_display_mode *mode,
1016 struct drm_display_mode *adjusted_mode)
1017{
1018 struct mixer_context *ctx = crtc->ctx;
1019 int width = mode->hdisplay, height = mode->vdisplay, i;
1020
1021 struct {
1022 int hdisplay, vdisplay, htotal, vtotal, scan_val;
1023 } static const modes[] = {
1024 { 720, 480, 858, 525, MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD },
1025 { 720, 576, 864, 625, MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD },
1026 { 1280, 720, 1650, 750, MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD },
1027 { 1920, 1080, 2200, 1125, MXR_CFG_SCAN_HD_1080 |
1028 MXR_CFG_SCAN_HD }
1029 };
1030
1031 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
1032 __set_bit(MXR_BIT_INTERLACE, &ctx->flags);
1033 else
1034 __clear_bit(MXR_BIT_INTERLACE, &ctx->flags);
1035
1036 if (ctx->mxr_ver == MXR_VER_128_0_0_184)
1037 return true;
1038
1039 for (i = 0; i < ARRAY_SIZE(modes); ++i)
1040 if (width <= modes[i].hdisplay && height <= modes[i].vdisplay) {
1041 ctx->scan_value = modes[i].scan_val;
1042 if (width < modes[i].hdisplay ||
1043 height < modes[i].vdisplay) {
1044 adjusted_mode->hdisplay = modes[i].hdisplay;
1045 adjusted_mode->hsync_start = modes[i].hdisplay;
1046 adjusted_mode->hsync_end = modes[i].htotal;
1047 adjusted_mode->htotal = modes[i].htotal;
1048 adjusted_mode->vdisplay = modes[i].vdisplay;
1049 adjusted_mode->vsync_start = modes[i].vdisplay;
1050 adjusted_mode->vsync_end = modes[i].vtotal;
1051 adjusted_mode->vtotal = modes[i].vtotal;
1052 }
1053
1054 return true;
1055 }
1056
1057 return false;
1058}
1059
Krzysztof Kozlowskif3aaf762015-05-07 09:04:45 +09001060static const struct exynos_drm_crtc_ops mixer_crtc_ops = {
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001061 .enable = mixer_enable,
1062 .disable = mixer_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001063 .enable_vblank = mixer_enable_vblank,
1064 .disable_vblank = mixer_disable_vblank,
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001065 .atomic_begin = mixer_atomic_begin,
Gustavo Padovan9cc76102015-08-03 14:38:05 +09001066 .update_plane = mixer_update_plane,
1067 .disable_plane = mixer_disable_plane,
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001068 .atomic_flush = mixer_atomic_flush,
Andrzej Hajda6ace38a2017-09-29 12:05:35 +02001069 .mode_valid = mixer_mode_valid,
Andrzej Hajdaacc8bf02017-09-29 12:05:39 +02001070 .mode_fixup = mixer_mode_fixup,
Sean Paulf041b252014-01-30 16:19:15 -05001071};
Rahul Sharma0ea68222013-01-15 08:11:06 -05001072
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301073static const struct mixer_drv_data exynos5420_mxr_drv_data = {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301074 .version = MXR_VER_128_0_0_184,
1075 .is_vp_enabled = 0,
1076};
1077
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301078static const struct mixer_drv_data exynos5250_mxr_drv_data = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301079 .version = MXR_VER_16_0_33_0,
1080 .is_vp_enabled = 0,
1081};
1082
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301083static const struct mixer_drv_data exynos4212_mxr_drv_data = {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001084 .version = MXR_VER_0_0_0_16,
1085 .is_vp_enabled = 1,
1086};
1087
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301088static const struct mixer_drv_data exynos4210_mxr_drv_data = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301089 .version = MXR_VER_0_0_0_16,
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301090 .is_vp_enabled = 1,
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001091 .has_sclk = 1,
Rahul Sharma1e123442012-10-04 20:48:51 +05301092};
1093
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301094static const struct of_device_id mixer_match_types[] = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301095 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001096 .compatible = "samsung,exynos4210-mixer",
1097 .data = &exynos4210_mxr_drv_data,
1098 }, {
1099 .compatible = "samsung,exynos4212-mixer",
1100 .data = &exynos4212_mxr_drv_data,
1101 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301102 .compatible = "samsung,exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301103 .data = &exynos5250_mxr_drv_data,
1104 }, {
1105 .compatible = "samsung,exynos5250-mixer",
1106 .data = &exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301107 }, {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301108 .compatible = "samsung,exynos5420-mixer",
1109 .data = &exynos5420_mxr_drv_data,
1110 }, {
Rahul Sharma1e123442012-10-04 20:48:51 +05301111 /* end node */
1112 }
1113};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001114MODULE_DEVICE_TABLE(of, mixer_match_types);
Rahul Sharma1e123442012-10-04 20:48:51 +05301115
Inki Daef37cd5e2014-05-09 14:25:20 +09001116static int mixer_bind(struct device *dev, struct device *manager, void *data)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001117{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001118 struct mixer_context *ctx = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09001119 struct drm_device *drm_dev = data;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001120 struct exynos_drm_plane *exynos_plane;
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +01001121 unsigned int i;
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +09001122 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001123
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001124 ret = mixer_initialize(ctx, drm_dev);
1125 if (ret)
1126 return ret;
1127
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +01001128 for (i = 0; i < MIXER_WIN_NR; i++) {
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001129 if (i == VP_DEFAULT_WIN && !test_bit(MXR_BIT_VP_ENABLED,
1130 &ctx->flags))
Marek Szyprowskiab144202015-11-30 14:53:24 +01001131 continue;
1132
Marek Szyprowski40bdfb02015-12-16 13:21:42 +01001133 ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
Andrzej Hajda2c826072017-03-15 15:41:05 +01001134 &plane_configs[i]);
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001135 if (ret)
1136 return ret;
1137 }
1138
Gustavo Padovan5d3d0992015-10-12 22:07:48 +09001139 exynos_plane = &ctx->planes[DEFAULT_WIN];
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001140 ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
Andrzej Hajdad6449512017-05-29 10:05:25 +09001141 EXYNOS_DISPLAY_TYPE_HDMI, &mixer_crtc_ops, ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001142 if (IS_ERR(ctx->crtc)) {
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001143 mixer_ctx_remove(ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001144 ret = PTR_ERR(ctx->crtc);
1145 goto free_ctx;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001146 }
1147
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001148 return 0;
Gustavo Padovan93bca242015-01-18 18:16:23 +09001149
1150free_ctx:
1151 devm_kfree(dev, ctx);
1152 return ret;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001153}
1154
1155static void mixer_unbind(struct device *dev, struct device *master, void *data)
1156{
1157 struct mixer_context *ctx = dev_get_drvdata(dev);
1158
Gustavo Padovan93bca242015-01-18 18:16:23 +09001159 mixer_ctx_remove(ctx);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001160}
1161
1162static const struct component_ops mixer_component_ops = {
1163 .bind = mixer_bind,
1164 .unbind = mixer_unbind,
1165};
1166
1167static int mixer_probe(struct platform_device *pdev)
1168{
1169 struct device *dev = &pdev->dev;
Marek Szyprowski48f61552016-04-01 15:17:46 +02001170 const struct mixer_drv_data *drv;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001171 struct mixer_context *ctx;
1172 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001173
Sean Paulf041b252014-01-30 16:19:15 -05001174 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1175 if (!ctx) {
1176 DRM_ERROR("failed to alloc mixer context.\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001177 return -ENOMEM;
Sean Paulf041b252014-01-30 16:19:15 -05001178 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001179
Marek Szyprowski48f61552016-04-01 15:17:46 +02001180 drv = of_device_get_match_data(dev);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301181
Sean Paul45517892014-01-30 16:19:05 -05001182 ctx->pdev = pdev;
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001183 ctx->dev = dev;
Rahul Sharma1e123442012-10-04 20:48:51 +05301184 ctx->mxr_ver = drv->version;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001185
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001186 if (drv->is_vp_enabled)
1187 __set_bit(MXR_BIT_VP_ENABLED, &ctx->flags);
1188 if (drv->has_sclk)
1189 __set_bit(MXR_BIT_HAS_SCLK, &ctx->flags);
1190
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001191 platform_set_drvdata(pdev, ctx);
Inki Daedf5225b2014-05-29 18:28:02 +09001192
Inki Daedf5225b2014-05-29 18:28:02 +09001193 ret = component_add(&pdev->dev, &mixer_component_ops);
Andrzej Hajda86650402015-06-11 23:23:37 +09001194 if (!ret)
1195 pm_runtime_enable(dev);
Inki Daedf5225b2014-05-29 18:28:02 +09001196
1197 return ret;
Inki Daef37cd5e2014-05-09 14:25:20 +09001198}
1199
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001200static int mixer_remove(struct platform_device *pdev)
1201{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001202 pm_runtime_disable(&pdev->dev);
1203
Inki Daedf5225b2014-05-29 18:28:02 +09001204 component_del(&pdev->dev, &mixer_component_ops);
Inki Daedf5225b2014-05-29 18:28:02 +09001205
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001206 return 0;
1207}
1208
Arnd Bergmanne0fea7e2015-11-17 16:08:36 +01001209static int __maybe_unused exynos_mixer_suspend(struct device *dev)
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001210{
1211 struct mixer_context *ctx = dev_get_drvdata(dev);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001212
Andrzej Hajda524c59f2017-09-29 12:05:36 +02001213 clk_disable_unprepare(ctx->hdmi);
1214 clk_disable_unprepare(ctx->mixer);
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 clk_disable_unprepare(ctx->vp);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001217 if (test_bit(MXR_BIT_HAS_SCLK, &ctx->flags))
Andrzej Hajda524c59f2017-09-29 12:05:36 +02001218 clk_disable_unprepare(ctx->sclk_mixer);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001219 }
1220
1221 return 0;
1222}
1223
Arnd Bergmanne0fea7e2015-11-17 16:08:36 +01001224static int __maybe_unused exynos_mixer_resume(struct device *dev)
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001225{
1226 struct mixer_context *ctx = dev_get_drvdata(dev);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001227 int ret;
1228
Andrzej Hajda524c59f2017-09-29 12:05:36 +02001229 ret = clk_prepare_enable(ctx->mixer);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001230 if (ret < 0) {
1231 DRM_ERROR("Failed to prepare_enable the mixer clk [%d]\n", ret);
1232 return ret;
1233 }
Andrzej Hajda524c59f2017-09-29 12:05:36 +02001234 ret = clk_prepare_enable(ctx->hdmi);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001235 if (ret < 0) {
1236 DRM_ERROR("Failed to prepare_enable the hdmi clk [%d]\n", ret);
1237 return ret;
1238 }
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001239 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Andrzej Hajda524c59f2017-09-29 12:05:36 +02001240 ret = clk_prepare_enable(ctx->vp);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001241 if (ret < 0) {
1242 DRM_ERROR("Failed to prepare_enable the vp clk [%d]\n",
1243 ret);
1244 return ret;
1245 }
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001246 if (test_bit(MXR_BIT_HAS_SCLK, &ctx->flags)) {
Andrzej Hajda524c59f2017-09-29 12:05:36 +02001247 ret = clk_prepare_enable(ctx->sclk_mixer);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001248 if (ret < 0) {
1249 DRM_ERROR("Failed to prepare_enable the " \
1250 "sclk_mixer clk [%d]\n",
1251 ret);
1252 return ret;
1253 }
1254 }
1255 }
1256
1257 return 0;
1258}
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001259
1260static const struct dev_pm_ops exynos_mixer_pm_ops = {
1261 SET_RUNTIME_PM_OPS(exynos_mixer_suspend, exynos_mixer_resume, NULL)
1262};
1263
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001264struct platform_driver mixer_driver = {
1265 .driver = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301266 .name = "exynos-mixer",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001267 .owner = THIS_MODULE,
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001268 .pm = &exynos_mixer_pm_ops,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301269 .of_match_table = mixer_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001270 },
1271 .probe = mixer_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001272 .remove = mixer_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001273};