blob: f9a06b8007c51f180c6caa94717483537f8b4d58 [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
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090070struct mixer_resources {
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090071 int irq;
72 void __iomem *mixer_regs;
73 void __iomem *vp_regs;
74 spinlock_t reg_slock;
75 struct clk *mixer;
76 struct clk *vp;
Marek Szyprowski04427ec2015-02-02 14:20:28 +010077 struct clk *hdmi;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090078 struct clk *sclk_mixer;
79 struct clk *sclk_hdmi;
Marek Szyprowskiff830c92014-07-01 10:10:07 +020080 struct clk *mout_mixer;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +090081};
82
Rahul Sharma1e123442012-10-04 20:48:51 +053083enum mixer_version_id {
84 MXR_VER_0_0_0_16,
85 MXR_VER_16_0_33_0,
Rahul Sharmadef5e092013-06-19 18:21:08 +053086 MXR_VER_128_0_0_184,
Rahul Sharma1e123442012-10-04 20:48:51 +053087};
88
Andrzej Hajdaa44652e2015-07-09 08:25:42 +020089enum mixer_flag_bits {
90 MXR_BIT_POWERED,
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +020091 MXR_BIT_VSYNC,
Tobias Jakobiadeb6f442016-09-22 11:36:13 +090092 MXR_BIT_INTERLACE,
93 MXR_BIT_VP_ENABLED,
94 MXR_BIT_HAS_SCLK,
Andrzej Hajdaa44652e2015-07-09 08:25:42 +020095};
96
Marek Szyprowskifbbb1e12015-08-31 00:53:57 +090097static const uint32_t mixer_formats[] = {
98 DRM_FORMAT_XRGB4444,
Tobias Jakobi26a7af32015-12-16 13:21:47 +010099 DRM_FORMAT_ARGB4444,
Marek Szyprowskifbbb1e12015-08-31 00:53:57 +0900100 DRM_FORMAT_XRGB1555,
Tobias Jakobi26a7af32015-12-16 13:21:47 +0100101 DRM_FORMAT_ARGB1555,
Marek Szyprowskifbbb1e12015-08-31 00:53:57 +0900102 DRM_FORMAT_RGB565,
103 DRM_FORMAT_XRGB8888,
104 DRM_FORMAT_ARGB8888,
105};
106
107static const uint32_t vp_formats[] = {
108 DRM_FORMAT_NV12,
109 DRM_FORMAT_NV21,
110};
111
Joonyoung Shim22b21ae2012-03-15 17:19:04 +0900112struct mixer_context {
Sean Paul45517892014-01-30 16:19:05 -0500113 struct platform_device *pdev;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900114 struct device *dev;
Inki Dae1055b392012-10-19 17:37:35 +0900115 struct drm_device *drm_dev;
Gustavo Padovan93bca242015-01-18 18:16:23 +0900116 struct exynos_drm_crtc *crtc;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900117 struct exynos_drm_plane planes[MIXER_WIN_NR];
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200118 unsigned long flags;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +0900119
120 struct mixer_resources mixer_res;
Rahul Sharma1e123442012-10-04 20:48:51 +0530121 enum mixer_version_id mxr_ver;
122};
123
124struct mixer_drv_data {
125 enum mixer_version_id version;
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530126 bool is_vp_enabled;
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200127 bool has_sclk;
Joonyoung Shim22b21ae2012-03-15 17:19:04 +0900128};
129
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +0100130static const struct exynos_drm_plane_config plane_configs[MIXER_WIN_NR] = {
131 {
132 .zpos = 0,
133 .type = DRM_PLANE_TYPE_PRIMARY,
134 .pixel_formats = mixer_formats,
135 .num_pixel_formats = ARRAY_SIZE(mixer_formats),
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100136 .capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE |
137 EXYNOS_DRM_PLANE_CAP_ZPOS,
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +0100138 }, {
139 .zpos = 1,
140 .type = DRM_PLANE_TYPE_CURSOR,
141 .pixel_formats = mixer_formats,
142 .num_pixel_formats = ARRAY_SIZE(mixer_formats),
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100143 .capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE |
144 EXYNOS_DRM_PLANE_CAP_ZPOS,
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +0100145 }, {
146 .zpos = 2,
147 .type = DRM_PLANE_TYPE_OVERLAY,
148 .pixel_formats = vp_formats,
149 .num_pixel_formats = ARRAY_SIZE(vp_formats),
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100150 .capabilities = EXYNOS_DRM_PLANE_CAP_SCALE |
Tobias Jakobif40031c2017-08-22 16:19:37 +0200151 EXYNOS_DRM_PLANE_CAP_ZPOS |
152 EXYNOS_DRM_PLANE_CAP_TILE,
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +0100153 },
154};
155
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900156static const u8 filter_y_horiz_tap8[] = {
157 0, -1, -1, -1, -1, -1, -1, -1,
158 -1, -1, -1, -1, -1, 0, 0, 0,
159 0, 2, 4, 5, 6, 6, 6, 6,
160 6, 5, 5, 4, 3, 2, 1, 1,
161 0, -6, -12, -16, -18, -20, -21, -20,
162 -20, -18, -16, -13, -10, -8, -5, -2,
163 127, 126, 125, 121, 114, 107, 99, 89,
164 79, 68, 57, 46, 35, 25, 16, 8,
165};
166
167static const u8 filter_y_vert_tap4[] = {
168 0, -3, -6, -8, -8, -8, -8, -7,
169 -6, -5, -4, -3, -2, -1, -1, 0,
170 127, 126, 124, 118, 111, 102, 92, 81,
171 70, 59, 48, 37, 27, 19, 11, 5,
172 0, 5, 11, 19, 27, 37, 48, 59,
173 70, 81, 92, 102, 111, 118, 124, 126,
174 0, 0, -1, -1, -2, -3, -4, -5,
175 -6, -7, -8, -8, -8, -8, -6, -3,
176};
177
178static const u8 filter_cr_horiz_tap4[] = {
179 0, -3, -6, -8, -8, -8, -8, -7,
180 -6, -5, -4, -3, -2, -1, -1, 0,
181 127, 126, 124, 118, 111, 102, 92, 81,
182 70, 59, 48, 37, 27, 19, 11, 5,
183};
184
Marek Szyprowskif657a992015-12-16 13:21:46 +0100185static inline bool is_alpha_format(unsigned int pixel_format)
186{
187 switch (pixel_format) {
188 case DRM_FORMAT_ARGB8888:
Tobias Jakobi26a7af32015-12-16 13:21:47 +0100189 case DRM_FORMAT_ARGB1555:
190 case DRM_FORMAT_ARGB4444:
Marek Szyprowskif657a992015-12-16 13:21:46 +0100191 return true;
192 default:
193 return false;
194 }
195}
196
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900197static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
198{
199 return readl(res->vp_regs + reg_id);
200}
201
202static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
203 u32 val)
204{
205 writel(val, res->vp_regs + reg_id);
206}
207
208static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
209 u32 val, u32 mask)
210{
211 u32 old = vp_reg_read(res, reg_id);
212
213 val = (val & mask) | (old & ~mask);
214 writel(val, res->vp_regs + reg_id);
215}
216
217static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
218{
219 return readl(res->mixer_regs + reg_id);
220}
221
222static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
223 u32 val)
224{
225 writel(val, res->mixer_regs + reg_id);
226}
227
228static inline void mixer_reg_writemask(struct mixer_resources *res,
229 u32 reg_id, u32 val, u32 mask)
230{
231 u32 old = mixer_reg_read(res, reg_id);
232
233 val = (val & mask) | (old & ~mask);
234 writel(val, res->mixer_regs + reg_id);
235}
236
237static void mixer_regs_dump(struct mixer_context *ctx)
238{
239#define DUMPREG(reg_id) \
240do { \
241 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
242 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
243} while (0)
244
245 DUMPREG(MXR_STATUS);
246 DUMPREG(MXR_CFG);
247 DUMPREG(MXR_INT_EN);
248 DUMPREG(MXR_INT_STATUS);
249
250 DUMPREG(MXR_LAYER_CFG);
251 DUMPREG(MXR_VIDEO_CFG);
252
253 DUMPREG(MXR_GRAPHIC0_CFG);
254 DUMPREG(MXR_GRAPHIC0_BASE);
255 DUMPREG(MXR_GRAPHIC0_SPAN);
256 DUMPREG(MXR_GRAPHIC0_WH);
257 DUMPREG(MXR_GRAPHIC0_SXY);
258 DUMPREG(MXR_GRAPHIC0_DXY);
259
260 DUMPREG(MXR_GRAPHIC1_CFG);
261 DUMPREG(MXR_GRAPHIC1_BASE);
262 DUMPREG(MXR_GRAPHIC1_SPAN);
263 DUMPREG(MXR_GRAPHIC1_WH);
264 DUMPREG(MXR_GRAPHIC1_SXY);
265 DUMPREG(MXR_GRAPHIC1_DXY);
266#undef DUMPREG
267}
268
269static void vp_regs_dump(struct mixer_context *ctx)
270{
271#define DUMPREG(reg_id) \
272do { \
273 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
274 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
275} while (0)
276
277 DUMPREG(VP_ENABLE);
278 DUMPREG(VP_SRESET);
279 DUMPREG(VP_SHADOW_UPDATE);
280 DUMPREG(VP_FIELD_ID);
281 DUMPREG(VP_MODE);
282 DUMPREG(VP_IMG_SIZE_Y);
283 DUMPREG(VP_IMG_SIZE_C);
284 DUMPREG(VP_PER_RATE_CTRL);
285 DUMPREG(VP_TOP_Y_PTR);
286 DUMPREG(VP_BOT_Y_PTR);
287 DUMPREG(VP_TOP_C_PTR);
288 DUMPREG(VP_BOT_C_PTR);
289 DUMPREG(VP_ENDIAN_MODE);
290 DUMPREG(VP_SRC_H_POSITION);
291 DUMPREG(VP_SRC_V_POSITION);
292 DUMPREG(VP_SRC_WIDTH);
293 DUMPREG(VP_SRC_HEIGHT);
294 DUMPREG(VP_DST_H_POSITION);
295 DUMPREG(VP_DST_V_POSITION);
296 DUMPREG(VP_DST_WIDTH);
297 DUMPREG(VP_DST_HEIGHT);
298 DUMPREG(VP_H_RATIO);
299 DUMPREG(VP_V_RATIO);
300
301#undef DUMPREG
302}
303
304static inline void vp_filter_set(struct mixer_resources *res,
305 int reg_id, const u8 *data, unsigned int size)
306{
307 /* assure 4-byte align */
308 BUG_ON(size & 3);
309 for (; size; size -= 4, reg_id += 4, data += 4) {
310 u32 val = (data[0] << 24) | (data[1] << 16) |
311 (data[2] << 8) | data[3];
312 vp_reg_write(res, reg_id, val);
313 }
314}
315
316static void vp_default_filter(struct mixer_resources *res)
317{
318 vp_filter_set(res, VP_POLY8_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530319 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900320 vp_filter_set(res, VP_POLY4_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530321 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900322 vp_filter_set(res, VP_POLY4_C0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530323 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900324}
325
Marek Szyprowskif657a992015-12-16 13:21:46 +0100326static void mixer_cfg_gfx_blend(struct mixer_context *ctx, unsigned int win,
327 bool alpha)
328{
329 struct mixer_resources *res = &ctx->mixer_res;
330 u32 val;
331
332 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
333 if (alpha) {
334 /* blending based on pixel alpha */
335 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
336 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
337 }
338 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
339 val, MXR_GRP_CFG_MISC_MASK);
340}
341
342static void mixer_cfg_vp_blend(struct mixer_context *ctx)
343{
344 struct mixer_resources *res = &ctx->mixer_res;
345 u32 val;
346
347 /*
348 * No blending at the moment since the NV12/NV21 pixelformats don't
349 * have an alpha channel. However the mixer supports a global alpha
350 * value for a layer. Once this functionality is exposed, we can
351 * support blending of the video layer through this.
352 */
353 val = 0;
354 mixer_reg_write(res, MXR_VIDEO_CFG, val);
355}
356
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900357static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
358{
359 struct mixer_resources *res = &ctx->mixer_res;
360
361 /* block update on vsync */
362 mixer_reg_writemask(res, MXR_STATUS, enable ?
363 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
364
Tobias Jakobiadeb6f442016-09-22 11:36:13 +0900365 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags))
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530366 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900367 VP_SHADOW_UPDATE_ENABLE : 0);
368}
369
370static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
371{
372 struct mixer_resources *res = &ctx->mixer_res;
373 u32 val;
374
375 /* choosing between interlace and progressive mode */
Tobias Jakobiadeb6f442016-09-22 11:36:13 +0900376 val = test_bit(MXR_BIT_INTERLACE, &ctx->flags) ?
377 MXR_CFG_SCAN_INTERLACE : MXR_CFG_SCAN_PROGRESSIVE;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900378
Rahul Sharmadef5e092013-06-19 18:21:08 +0530379 if (ctx->mxr_ver != MXR_VER_128_0_0_184) {
380 /* choosing between proper HD and SD mode */
381 if (height <= 480)
382 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
383 else if (height <= 576)
384 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
385 else if (height <= 720)
386 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
387 else if (height <= 1080)
388 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
389 else
390 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
391 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900392
393 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
394}
395
396static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
397{
398 struct mixer_resources *res = &ctx->mixer_res;
399 u32 val;
400
Tobias Jakobi2a39db02017-03-10 14:30:16 +0100401 switch (height) {
402 case 480:
403 case 576:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900404 val = MXR_CFG_RGB601_0_255;
Tobias Jakobi2a39db02017-03-10 14:30:16 +0100405 break;
406 case 720:
407 case 1080:
408 default:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900409 val = MXR_CFG_RGB709_16_235;
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100410 /* Configure the BT.709 CSC matrix for full range RGB. */
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900411 mixer_reg_write(res, MXR_CM_COEFF_Y,
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100412 MXR_CSC_CT( 0.184, 0.614, 0.063) |
413 MXR_CM_COEFF_RGB_FULL);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900414 mixer_reg_write(res, MXR_CM_COEFF_CB,
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100415 MXR_CSC_CT(-0.102, -0.338, 0.440));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900416 mixer_reg_write(res, MXR_CM_COEFF_CR,
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100417 MXR_CSC_CT( 0.440, -0.399, -0.040));
Tobias Jakobi2a39db02017-03-10 14:30:16 +0100418 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900419 }
420
421 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
422}
423
Tobias Jakobi5b1d5bc2015-05-06 14:10:22 +0200424static void mixer_cfg_layer(struct mixer_context *ctx, unsigned int win,
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100425 unsigned int priority, bool enable)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900426{
427 struct mixer_resources *res = &ctx->mixer_res;
428 u32 val = enable ? ~0 : 0;
429
430 switch (win) {
431 case 0:
432 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100433 mixer_reg_writemask(res, MXR_LAYER_CFG,
434 MXR_LAYER_CFG_GRP0_VAL(priority),
435 MXR_LAYER_CFG_GRP0_MASK);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900436 break;
437 case 1:
438 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100439 mixer_reg_writemask(res, MXR_LAYER_CFG,
440 MXR_LAYER_CFG_GRP1_VAL(priority),
441 MXR_LAYER_CFG_GRP1_MASK);
Tobias Jakobiadeb6f442016-09-22 11:36:13 +0900442
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900443 break;
Marek Szyprowski5e68fef2015-12-16 13:21:48 +0100444 case VP_DEFAULT_WIN:
Tobias Jakobiadeb6f442016-09-22 11:36:13 +0900445 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530446 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
447 mixer_reg_writemask(res, MXR_CFG, val,
448 MXR_CFG_VP_ENABLE);
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100449 mixer_reg_writemask(res, MXR_LAYER_CFG,
450 MXR_LAYER_CFG_VP_VAL(priority),
451 MXR_LAYER_CFG_VP_MASK);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530452 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900453 break;
454 }
455}
456
457static void mixer_run(struct mixer_context *ctx)
458{
459 struct mixer_resources *res = &ctx->mixer_res;
460
461 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900462}
463
Rahul Sharma381be022014-06-23 11:02:22 +0530464static void mixer_stop(struct mixer_context *ctx)
465{
466 struct mixer_resources *res = &ctx->mixer_res;
467 int timeout = 20;
468
469 mixer_reg_writemask(res, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
470
471 while (!(mixer_reg_read(res, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
472 --timeout)
473 usleep_range(10000, 12000);
Rahul Sharma381be022014-06-23 11:02:22 +0530474}
475
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900476static void vp_video_buffer(struct mixer_context *ctx,
477 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900478{
Marek Szyprowski0114f402015-11-30 14:53:22 +0100479 struct exynos_drm_plane_state *state =
480 to_exynos_plane_state(plane->base.state);
Marek Szyprowski2ee35d82015-11-30 14:53:23 +0100481 struct drm_display_mode *mode = &state->base.crtc->state->adjusted_mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900482 struct mixer_resources *res = &ctx->mixer_res;
Marek Szyprowski0114f402015-11-30 14:53:22 +0100483 struct drm_framebuffer *fb = state->base.fb;
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200484 unsigned int priority = state->base.normalized_zpos + 1;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900485 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900486 dma_addr_t luma_addr[2], chroma_addr[2];
487 bool tiled_mode = false;
488 bool crcb_mode = false;
489 u32 val;
490
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200491 switch (fb->format->format) {
Ville Syrjälä363b06a2012-05-14 11:08:51 +0900492 case DRM_FORMAT_NV12:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900493 crcb_mode = false;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900494 break;
Tobias Jakobi8f2590f2015-04-27 23:10:16 +0200495 case DRM_FORMAT_NV21:
496 crcb_mode = true;
497 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900498 default:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900499 DRM_ERROR("pixel format for vp is wrong [%d].\n",
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200500 fb->format->format);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900501 return;
502 }
503
Tobias Jakobif40031c2017-08-22 16:19:37 +0200504 if (fb->modifier == DRM_FORMAT_MOD_SAMSUNG_64_32_TILE)
505 tiled_mode = true;
506
Marek Szyprowski0488f502015-11-30 14:53:21 +0100507 luma_addr[0] = exynos_drm_fb_dma_addr(fb, 0);
508 chroma_addr[0] = exynos_drm_fb_dma_addr(fb, 1);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900509
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900510 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
Tobias Jakobiadeb6f442016-09-22 11:36:13 +0900511 __set_bit(MXR_BIT_INTERLACE, &ctx->flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900512 if (tiled_mode) {
513 luma_addr[1] = luma_addr[0] + 0x40;
514 chroma_addr[1] = chroma_addr[0] + 0x40;
515 } else {
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900516 luma_addr[1] = luma_addr[0] + fb->pitches[0];
517 chroma_addr[1] = chroma_addr[0] + fb->pitches[0];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900518 }
519 } else {
Tobias Jakobiadeb6f442016-09-22 11:36:13 +0900520 __clear_bit(MXR_BIT_INTERLACE, &ctx->flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900521 luma_addr[1] = 0;
522 chroma_addr[1] = 0;
523 }
524
525 spin_lock_irqsave(&res->reg_slock, flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900526
527 /* interlace or progressive scan mode */
Tobias Jakobiadeb6f442016-09-22 11:36:13 +0900528 val = (test_bit(MXR_BIT_INTERLACE, &ctx->flags) ? ~0 : 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900529 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
530
531 /* setup format */
532 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
533 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
534 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
535
536 /* setting size of input image */
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900537 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(fb->pitches[0]) |
538 VP_IMG_VSIZE(fb->height));
Tobias Jakobidc500cf2017-08-22 16:19:36 +0200539 /* chroma plane for NV12/NV21 is half the height of the luma plane */
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900540 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(fb->pitches[0]) |
541 VP_IMG_VSIZE(fb->height / 2));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900542
Marek Szyprowski0114f402015-11-30 14:53:22 +0100543 vp_reg_write(res, VP_SRC_WIDTH, state->src.w);
544 vp_reg_write(res, VP_SRC_HEIGHT, state->src.h);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900545 vp_reg_write(res, VP_SRC_H_POSITION,
Marek Szyprowski0114f402015-11-30 14:53:22 +0100546 VP_SRC_H_POSITION_VAL(state->src.x));
547 vp_reg_write(res, VP_SRC_V_POSITION, state->src.y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900548
Marek Szyprowski0114f402015-11-30 14:53:22 +0100549 vp_reg_write(res, VP_DST_WIDTH, state->crtc.w);
550 vp_reg_write(res, VP_DST_H_POSITION, state->crtc.x);
Tobias Jakobiadeb6f442016-09-22 11:36:13 +0900551 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
Marek Szyprowski0114f402015-11-30 14:53:22 +0100552 vp_reg_write(res, VP_DST_HEIGHT, state->crtc.h / 2);
553 vp_reg_write(res, VP_DST_V_POSITION, state->crtc.y / 2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900554 } else {
Marek Szyprowski0114f402015-11-30 14:53:22 +0100555 vp_reg_write(res, VP_DST_HEIGHT, state->crtc.h);
556 vp_reg_write(res, VP_DST_V_POSITION, state->crtc.y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900557 }
558
Marek Szyprowski0114f402015-11-30 14:53:22 +0100559 vp_reg_write(res, VP_H_RATIO, state->h_ratio);
560 vp_reg_write(res, VP_V_RATIO, state->v_ratio);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900561
562 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
563
564 /* set buffer address to vp */
565 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
566 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
567 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
568 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
569
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900570 mixer_cfg_scan(ctx, mode->vdisplay);
571 mixer_cfg_rgb_fmt(ctx, mode->vdisplay);
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200572 mixer_cfg_layer(ctx, plane->index, priority, true);
Marek Szyprowskif657a992015-12-16 13:21:46 +0100573 mixer_cfg_vp_blend(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900574 mixer_run(ctx);
575
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900576 spin_unlock_irqrestore(&res->reg_slock, flags);
577
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200578 mixer_regs_dump(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900579 vp_regs_dump(ctx);
580}
581
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530582static void mixer_layer_update(struct mixer_context *ctx)
583{
584 struct mixer_resources *res = &ctx->mixer_res;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530585
Rahul Sharma5c0f4822014-06-23 11:02:23 +0530586 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530587}
588
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900589static void mixer_graph_buffer(struct mixer_context *ctx,
590 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900591{
Marek Szyprowski0114f402015-11-30 14:53:22 +0100592 struct exynos_drm_plane_state *state =
593 to_exynos_plane_state(plane->base.state);
Marek Szyprowski2ee35d82015-11-30 14:53:23 +0100594 struct drm_display_mode *mode = &state->base.crtc->state->adjusted_mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900595 struct mixer_resources *res = &ctx->mixer_res;
Marek Szyprowski0114f402015-11-30 14:53:22 +0100596 struct drm_framebuffer *fb = state->base.fb;
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200597 unsigned int priority = state->base.normalized_zpos + 1;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900598 unsigned long flags;
Marek Szyprowski40bdfb02015-12-16 13:21:42 +0100599 unsigned int win = plane->index;
Tobias Jakobi26110152015-04-07 01:14:52 +0200600 unsigned int x_ratio = 0, y_ratio = 0;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900601 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900602 dma_addr_t dma_addr;
603 unsigned int fmt;
604 u32 val;
605
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200606 switch (fb->format->format) {
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200607 case DRM_FORMAT_XRGB4444:
Tobias Jakobi26a7af32015-12-16 13:21:47 +0100608 case DRM_FORMAT_ARGB4444:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200609 fmt = MXR_FORMAT_ARGB4444;
610 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900611
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200612 case DRM_FORMAT_XRGB1555:
Tobias Jakobi26a7af32015-12-16 13:21:47 +0100613 case DRM_FORMAT_ARGB1555:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200614 fmt = MXR_FORMAT_ARGB1555;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900615 break;
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200616
617 case DRM_FORMAT_RGB565:
618 fmt = MXR_FORMAT_RGB565;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900619 break;
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200620
621 case DRM_FORMAT_XRGB8888:
622 case DRM_FORMAT_ARGB8888:
623 fmt = MXR_FORMAT_ARGB8888;
624 break;
625
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900626 default:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200627 DRM_DEBUG_KMS("pixelformat unsupported by mixer\n");
628 return;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900629 }
630
Marek Szyprowskie463b062015-11-30 14:53:27 +0100631 /* ratio is already checked by common plane code */
632 x_ratio = state->h_ratio == (1 << 15);
633 y_ratio = state->v_ratio == (1 << 15);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900634
Marek Szyprowski0114f402015-11-30 14:53:22 +0100635 dst_x_offset = state->crtc.x;
636 dst_y_offset = state->crtc.y;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900637
638 /* converting dma address base and source offset */
Marek Szyprowski0488f502015-11-30 14:53:21 +0100639 dma_addr = exynos_drm_fb_dma_addr(fb, 0)
Ville Syrjälä272725c2016-12-14 23:32:20 +0200640 + (state->src.x * fb->format->cpp[0])
Marek Szyprowski0114f402015-11-30 14:53:22 +0100641 + (state->src.y * fb->pitches[0]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900642 src_x_offset = 0;
643 src_y_offset = 0;
644
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900645 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
Tobias Jakobiadeb6f442016-09-22 11:36:13 +0900646 __set_bit(MXR_BIT_INTERLACE, &ctx->flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900647 else
Tobias Jakobiadeb6f442016-09-22 11:36:13 +0900648 __clear_bit(MXR_BIT_INTERLACE, &ctx->flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900649
650 spin_lock_irqsave(&res->reg_slock, flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900651
652 /* setup format */
653 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
654 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
655
656 /* setup geometry */
Daniel Stoneadacb222015-03-17 13:24:58 +0000657 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win),
Ville Syrjälä272725c2016-12-14 23:32:20 +0200658 fb->pitches[0] / fb->format->cpp[0]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900659
Rahul Sharmadef5e092013-06-19 18:21:08 +0530660 /* setup display size */
661 if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
Gustavo Padovan5d3d0992015-10-12 22:07:48 +0900662 win == DEFAULT_WIN) {
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900663 val = MXR_MXR_RES_HEIGHT(mode->vdisplay);
664 val |= MXR_MXR_RES_WIDTH(mode->hdisplay);
Rahul Sharmadef5e092013-06-19 18:21:08 +0530665 mixer_reg_write(res, MXR_RESOLUTION, val);
666 }
667
Marek Szyprowski0114f402015-11-30 14:53:22 +0100668 val = MXR_GRP_WH_WIDTH(state->src.w);
669 val |= MXR_GRP_WH_HEIGHT(state->src.h);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900670 val |= MXR_GRP_WH_H_SCALE(x_ratio);
671 val |= MXR_GRP_WH_V_SCALE(y_ratio);
672 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
673
674 /* setup offsets in source image */
675 val = MXR_GRP_SXY_SX(src_x_offset);
676 val |= MXR_GRP_SXY_SY(src_y_offset);
677 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
678
679 /* setup offsets in display image */
680 val = MXR_GRP_DXY_DX(dst_x_offset);
681 val |= MXR_GRP_DXY_DY(dst_y_offset);
682 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
683
684 /* set buffer address to mixer */
685 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
686
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900687 mixer_cfg_scan(ctx, mode->vdisplay);
688 mixer_cfg_rgb_fmt(ctx, mode->vdisplay);
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200689 mixer_cfg_layer(ctx, win, priority, true);
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200690 mixer_cfg_gfx_blend(ctx, win, is_alpha_format(fb->format->format));
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530691
692 /* layer update mandatory for mixer 16.0.33.0 */
Rahul Sharmadef5e092013-06-19 18:21:08 +0530693 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
694 ctx->mxr_ver == MXR_VER_128_0_0_184)
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530695 mixer_layer_update(ctx);
696
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900697 mixer_run(ctx);
698
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900699 spin_unlock_irqrestore(&res->reg_slock, flags);
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200700
701 mixer_regs_dump(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900702}
703
704static void vp_win_reset(struct mixer_context *ctx)
705{
706 struct mixer_resources *res = &ctx->mixer_res;
Tobias Jakobia6963942016-09-22 16:57:19 +0200707 unsigned int tries = 100;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900708
709 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
Dan Carpenter8646dcb2017-01-20 17:54:32 +0100710 while (--tries) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900711 /* waiting until VP_SRESET_PROCESSING is 0 */
712 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
713 break;
Tomasz Stanislawski02b3de42015-09-25 14:48:29 +0200714 mdelay(10);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900715 }
716 WARN(tries == 0, "failed to reset Video Processor\n");
717}
718
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900719static void mixer_win_reset(struct mixer_context *ctx)
720{
721 struct mixer_resources *res = &ctx->mixer_res;
722 unsigned long flags;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900723
724 spin_lock_irqsave(&res->reg_slock, flags);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900725
726 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
727
728 /* set output in RGB888 mode */
729 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
730
731 /* 16 beat burst in DMA */
732 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
733 MXR_STATUS_BURST_MASK);
734
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100735 /* reset default layer priority */
736 mixer_reg_write(res, MXR_LAYER_CFG, 0);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900737
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100738 /* set all background colors to RGB (0,0,0) */
739 mixer_reg_write(res, MXR_BG_COLOR0, MXR_YCBCR_VAL(0, 128, 128));
740 mixer_reg_write(res, MXR_BG_COLOR1, MXR_YCBCR_VAL(0, 128, 128));
741 mixer_reg_write(res, MXR_BG_COLOR2, MXR_YCBCR_VAL(0, 128, 128));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900742
Tobias Jakobiadeb6f442016-09-22 11:36:13 +0900743 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530744 /* configuration of Video Processor Registers */
745 vp_win_reset(ctx);
746 vp_default_filter(res);
747 }
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900748
749 /* disable all layers */
750 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
751 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
Tobias Jakobiadeb6f442016-09-22 11:36:13 +0900752 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags))
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530753 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900754
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900755 spin_unlock_irqrestore(&res->reg_slock, flags);
756}
757
Sean Paul45517892014-01-30 16:19:05 -0500758static irqreturn_t mixer_irq_handler(int irq, void *arg)
759{
760 struct mixer_context *ctx = arg;
761 struct mixer_resources *res = &ctx->mixer_res;
762 u32 val, base, shadow;
763
764 spin_lock(&res->reg_slock);
765
766 /* read interrupt status for handling and clearing flags for VSYNC */
767 val = mixer_reg_read(res, MXR_INT_STATUS);
768
769 /* handling VSYNC */
770 if (val & MXR_INT_STATUS_VSYNC) {
Andrzej Hajda81a464d2015-07-09 10:07:53 +0200771 /* vsync interrupt use different bit for read and clear */
772 val |= MXR_INT_CLEAR_VSYNC;
773 val &= ~MXR_INT_STATUS_VSYNC;
774
Sean Paul45517892014-01-30 16:19:05 -0500775 /* interlace scan need to check shadow register */
Tobias Jakobiadeb6f442016-09-22 11:36:13 +0900776 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
Sean Paul45517892014-01-30 16:19:05 -0500777 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
778 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
779 if (base != shadow)
780 goto out;
781
782 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
783 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
784 if (base != shadow)
785 goto out;
786 }
787
Gustavo Padovaneafd5402015-07-16 12:23:32 -0300788 drm_crtc_handle_vblank(&ctx->crtc->base);
Sean Paul45517892014-01-30 16:19:05 -0500789 }
790
791out:
792 /* clear interrupts */
Sean Paul45517892014-01-30 16:19:05 -0500793 mixer_reg_write(res, MXR_INT_STATUS, val);
794
795 spin_unlock(&res->reg_slock);
796
797 return IRQ_HANDLED;
798}
799
800static int mixer_resources_init(struct mixer_context *mixer_ctx)
801{
802 struct device *dev = &mixer_ctx->pdev->dev;
803 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
804 struct resource *res;
805 int ret;
806
807 spin_lock_init(&mixer_res->reg_slock);
808
809 mixer_res->mixer = devm_clk_get(dev, "mixer");
810 if (IS_ERR(mixer_res->mixer)) {
811 dev_err(dev, "failed to get clock 'mixer'\n");
812 return -ENODEV;
813 }
814
Marek Szyprowski04427ec2015-02-02 14:20:28 +0100815 mixer_res->hdmi = devm_clk_get(dev, "hdmi");
816 if (IS_ERR(mixer_res->hdmi)) {
817 dev_err(dev, "failed to get clock 'hdmi'\n");
818 return PTR_ERR(mixer_res->hdmi);
819 }
820
Sean Paul45517892014-01-30 16:19:05 -0500821 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
822 if (IS_ERR(mixer_res->sclk_hdmi)) {
823 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
824 return -ENODEV;
825 }
826 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
827 if (res == NULL) {
828 dev_err(dev, "get memory resource failed.\n");
829 return -ENXIO;
830 }
831
832 mixer_res->mixer_regs = devm_ioremap(dev, res->start,
833 resource_size(res));
834 if (mixer_res->mixer_regs == NULL) {
835 dev_err(dev, "register mapping failed.\n");
836 return -ENXIO;
837 }
838
839 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
840 if (res == NULL) {
841 dev_err(dev, "get interrupt resource failed.\n");
842 return -ENXIO;
843 }
844
845 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
846 0, "drm_mixer", mixer_ctx);
847 if (ret) {
848 dev_err(dev, "request interrupt failed.\n");
849 return ret;
850 }
851 mixer_res->irq = res->start;
852
853 return 0;
854}
855
856static int vp_resources_init(struct mixer_context *mixer_ctx)
857{
858 struct device *dev = &mixer_ctx->pdev->dev;
859 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
860 struct resource *res;
861
862 mixer_res->vp = devm_clk_get(dev, "vp");
863 if (IS_ERR(mixer_res->vp)) {
864 dev_err(dev, "failed to get clock 'vp'\n");
865 return -ENODEV;
866 }
Sean Paul45517892014-01-30 16:19:05 -0500867
Tobias Jakobiadeb6f442016-09-22 11:36:13 +0900868 if (test_bit(MXR_BIT_HAS_SCLK, &mixer_ctx->flags)) {
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200869 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
870 if (IS_ERR(mixer_res->sclk_mixer)) {
871 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
872 return -ENODEV;
873 }
874 mixer_res->mout_mixer = devm_clk_get(dev, "mout_mixer");
875 if (IS_ERR(mixer_res->mout_mixer)) {
876 dev_err(dev, "failed to get clock 'mout_mixer'\n");
877 return -ENODEV;
878 }
879
880 if (mixer_res->sclk_hdmi && mixer_res->mout_mixer)
881 clk_set_parent(mixer_res->mout_mixer,
882 mixer_res->sclk_hdmi);
883 }
Sean Paul45517892014-01-30 16:19:05 -0500884
885 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
886 if (res == NULL) {
887 dev_err(dev, "get memory resource failed.\n");
888 return -ENXIO;
889 }
890
891 mixer_res->vp_regs = devm_ioremap(dev, res->start,
892 resource_size(res));
893 if (mixer_res->vp_regs == NULL) {
894 dev_err(dev, "register mapping failed.\n");
895 return -ENXIO;
896 }
897
898 return 0;
899}
900
Gustavo Padovan93bca242015-01-18 18:16:23 +0900901static int mixer_initialize(struct mixer_context *mixer_ctx,
Inki Daef37cd5e2014-05-09 14:25:20 +0900902 struct drm_device *drm_dev)
Sean Paul45517892014-01-30 16:19:05 -0500903{
904 int ret;
Inki Daef37cd5e2014-05-09 14:25:20 +0900905 struct exynos_drm_private *priv;
906 priv = drm_dev->dev_private;
Sean Paul45517892014-01-30 16:19:05 -0500907
Gustavo Padovaneb88e422014-11-26 16:43:27 -0200908 mixer_ctx->drm_dev = drm_dev;
Sean Paul45517892014-01-30 16:19:05 -0500909
910 /* acquire resources: regs, irqs, clocks */
911 ret = mixer_resources_init(mixer_ctx);
912 if (ret) {
913 DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
914 return ret;
915 }
916
Tobias Jakobiadeb6f442016-09-22 11:36:13 +0900917 if (test_bit(MXR_BIT_VP_ENABLED, &mixer_ctx->flags)) {
Sean Paul45517892014-01-30 16:19:05 -0500918 /* acquire vp resources: regs, irqs, clocks */
919 ret = vp_resources_init(mixer_ctx);
920 if (ret) {
921 DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
922 return ret;
923 }
924 }
925
Andrzej Hajdaf44d3d22017-03-15 15:41:04 +0100926 return drm_iommu_attach_device(drm_dev, mixer_ctx->dev);
Sean Paul45517892014-01-30 16:19:05 -0500927}
928
Gustavo Padovan93bca242015-01-18 18:16:23 +0900929static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
Inki Dae1055b392012-10-19 17:37:35 +0900930{
Joonyoung Shimbf566082015-07-02 21:49:38 +0900931 drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Inki Dae1055b392012-10-19 17:37:35 +0900932}
933
Gustavo Padovan93bca242015-01-18 18:16:23 +0900934static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900935{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900936 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900937 struct mixer_resources *res = &mixer_ctx->mixer_res;
938
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200939 __set_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
940 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Sean Paulf041b252014-01-30 16:19:15 -0500941 return 0;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900942
943 /* enable vsync interrupt */
Andrzej Hajdafc0732482015-07-09 08:25:40 +0200944 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
945 mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900946
947 return 0;
948}
949
Gustavo Padovan93bca242015-01-18 18:16:23 +0900950static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900951{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900952 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900953 struct mixer_resources *res = &mixer_ctx->mixer_res;
954
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200955 __clear_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
956
957 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Andrzej Hajda947710c2015-07-09 08:25:41 +0200958 return;
Andrzej Hajda947710c2015-07-09 08:25:41 +0200959
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900960 /* disable vsync interrupt */
Andrzej Hajdafc0732482015-07-09 08:25:40 +0200961 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900962 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
963}
964
Marek Szyprowski3dbaab12016-01-05 13:52:52 +0100965static void mixer_atomic_begin(struct exynos_drm_crtc *crtc)
966{
967 struct mixer_context *mixer_ctx = crtc->ctx;
968
969 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
970 return;
971
972 mixer_vsync_set_update(mixer_ctx, false);
973}
974
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900975static void mixer_update_plane(struct exynos_drm_crtc *crtc,
976 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900977{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900978 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900979
Marek Szyprowski40bdfb02015-12-16 13:21:42 +0100980 DRM_DEBUG_KMS("win: %d\n", plane->index);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900981
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200982 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Shirish Sdda90122013-01-23 22:03:18 -0500983 return;
Shirish Sdda90122013-01-23 22:03:18 -0500984
Marek Szyprowski5e68fef2015-12-16 13:21:48 +0100985 if (plane->index == VP_DEFAULT_WIN)
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900986 vp_video_buffer(mixer_ctx, plane);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900987 else
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900988 mixer_graph_buffer(mixer_ctx, plane);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900989}
990
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900991static void mixer_disable_plane(struct exynos_drm_crtc *crtc,
992 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900993{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900994 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900995 struct mixer_resources *res = &mixer_ctx->mixer_res;
996 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900997
Marek Szyprowski40bdfb02015-12-16 13:21:42 +0100998 DRM_DEBUG_KMS("win: %d\n", plane->index);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900999
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001000 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Prathyush Kdb43fd12012-12-06 20:16:05 +05301001 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301002
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001003 spin_lock_irqsave(&res->reg_slock, flags);
Marek Szyprowskia2cb9112015-12-16 13:21:44 +01001004 mixer_cfg_layer(mixer_ctx, plane->index, 0, false);
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001005 spin_unlock_irqrestore(&res->reg_slock, flags);
1006}
1007
1008static void mixer_atomic_flush(struct exynos_drm_crtc *crtc)
1009{
1010 struct mixer_context *mixer_ctx = crtc->ctx;
1011
1012 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
1013 return;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001014
1015 mixer_vsync_set_update(mixer_ctx, true);
Andrzej Hajdaa3922762017-03-14 09:27:56 +01001016 exynos_crtc_handle_event(crtc);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001017}
1018
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001019static void mixer_enable(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301020{
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001021 struct mixer_context *ctx = crtc->ctx;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301022 struct mixer_resources *res = &ctx->mixer_res;
1023
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001024 if (test_bit(MXR_BIT_POWERED, &ctx->flags))
Prathyush Kdb43fd12012-12-06 20:16:05 +05301025 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301026
Sean Paulaf65c802014-01-30 16:19:27 -05001027 pm_runtime_get_sync(ctx->dev);
1028
Andrzej Hajdaa121d172016-03-23 14:26:01 +01001029 exynos_drm_pipe_clk_enable(crtc, true);
1030
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001031 mixer_vsync_set_update(ctx, false);
1032
Rahul Sharmad74ed932014-06-23 11:02:24 +05301033 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
1034
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +02001035 if (test_bit(MXR_BIT_VSYNC, &ctx->flags)) {
Andrzej Hajdafc0732482015-07-09 08:25:40 +02001036 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +02001037 mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
1038 }
Prathyush Kdb43fd12012-12-06 20:16:05 +05301039 mixer_win_reset(ctx);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001040
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001041 mixer_vsync_set_update(ctx, true);
1042
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001043 set_bit(MXR_BIT_POWERED, &ctx->flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301044}
1045
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001046static void mixer_disable(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301047{
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001048 struct mixer_context *ctx = crtc->ctx;
Joonyoung Shimc329f662015-06-12 20:34:28 +09001049 int i;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301050
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001051 if (!test_bit(MXR_BIT_POWERED, &ctx->flags))
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301052 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301053
Rahul Sharma381be022014-06-23 11:02:22 +05301054 mixer_stop(ctx);
Tobias Jakobic0734fb2015-05-06 14:10:21 +02001055 mixer_regs_dump(ctx);
Joonyoung Shimc329f662015-06-12 20:34:28 +09001056
1057 for (i = 0; i < MIXER_WIN_NR; i++)
Gustavo Padovan1e1d1392015-08-03 14:39:36 +09001058 mixer_disable_plane(crtc, &ctx->planes[i]);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301059
Andrzej Hajdaa121d172016-03-23 14:26:01 +01001060 exynos_drm_pipe_clk_enable(crtc, false);
1061
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001062 pm_runtime_put(ctx->dev);
1063
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001064 clear_bit(MXR_BIT_POWERED, &ctx->flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301065}
1066
Sean Paulf041b252014-01-30 16:19:15 -05001067/* Only valid for Mixer version 16.0.33.0 */
Andrzej Hajda3ae24362015-10-26 13:03:40 +01001068static int mixer_atomic_check(struct exynos_drm_crtc *crtc,
1069 struct drm_crtc_state *state)
Sean Paulf041b252014-01-30 16:19:15 -05001070{
Andrzej Hajda3ae24362015-10-26 13:03:40 +01001071 struct drm_display_mode *mode = &state->adjusted_mode;
Sean Paulf041b252014-01-30 16:19:15 -05001072 u32 w, h;
1073
1074 w = mode->hdisplay;
1075 h = mode->vdisplay;
1076
1077 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
1078 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1079 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1080
1081 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
1082 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1083 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1084 return 0;
1085
1086 return -EINVAL;
1087}
1088
Krzysztof Kozlowskif3aaf762015-05-07 09:04:45 +09001089static const struct exynos_drm_crtc_ops mixer_crtc_ops = {
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001090 .enable = mixer_enable,
1091 .disable = mixer_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001092 .enable_vblank = mixer_enable_vblank,
1093 .disable_vblank = mixer_disable_vblank,
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001094 .atomic_begin = mixer_atomic_begin,
Gustavo Padovan9cc76102015-08-03 14:38:05 +09001095 .update_plane = mixer_update_plane,
1096 .disable_plane = mixer_disable_plane,
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001097 .atomic_flush = mixer_atomic_flush,
Andrzej Hajda3ae24362015-10-26 13:03:40 +01001098 .atomic_check = mixer_atomic_check,
Sean Paulf041b252014-01-30 16:19:15 -05001099};
Rahul Sharma0ea68222013-01-15 08:11:06 -05001100
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301101static const struct mixer_drv_data exynos5420_mxr_drv_data = {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301102 .version = MXR_VER_128_0_0_184,
1103 .is_vp_enabled = 0,
1104};
1105
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301106static const struct mixer_drv_data exynos5250_mxr_drv_data = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301107 .version = MXR_VER_16_0_33_0,
1108 .is_vp_enabled = 0,
1109};
1110
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301111static const struct mixer_drv_data exynos4212_mxr_drv_data = {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001112 .version = MXR_VER_0_0_0_16,
1113 .is_vp_enabled = 1,
1114};
1115
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301116static const struct mixer_drv_data exynos4210_mxr_drv_data = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301117 .version = MXR_VER_0_0_0_16,
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301118 .is_vp_enabled = 1,
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001119 .has_sclk = 1,
Rahul Sharma1e123442012-10-04 20:48:51 +05301120};
1121
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301122static const struct of_device_id mixer_match_types[] = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301123 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001124 .compatible = "samsung,exynos4210-mixer",
1125 .data = &exynos4210_mxr_drv_data,
1126 }, {
1127 .compatible = "samsung,exynos4212-mixer",
1128 .data = &exynos4212_mxr_drv_data,
1129 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301130 .compatible = "samsung,exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301131 .data = &exynos5250_mxr_drv_data,
1132 }, {
1133 .compatible = "samsung,exynos5250-mixer",
1134 .data = &exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301135 }, {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301136 .compatible = "samsung,exynos5420-mixer",
1137 .data = &exynos5420_mxr_drv_data,
1138 }, {
Rahul Sharma1e123442012-10-04 20:48:51 +05301139 /* end node */
1140 }
1141};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001142MODULE_DEVICE_TABLE(of, mixer_match_types);
Rahul Sharma1e123442012-10-04 20:48:51 +05301143
Inki Daef37cd5e2014-05-09 14:25:20 +09001144static int mixer_bind(struct device *dev, struct device *manager, void *data)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001145{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001146 struct mixer_context *ctx = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09001147 struct drm_device *drm_dev = data;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001148 struct exynos_drm_plane *exynos_plane;
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +01001149 unsigned int i;
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +09001150 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001151
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001152 ret = mixer_initialize(ctx, drm_dev);
1153 if (ret)
1154 return ret;
1155
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +01001156 for (i = 0; i < MIXER_WIN_NR; i++) {
Tobias Jakobiadeb6f442016-09-22 11:36:13 +09001157 if (i == VP_DEFAULT_WIN && !test_bit(MXR_BIT_VP_ENABLED,
1158 &ctx->flags))
Marek Szyprowskiab144202015-11-30 14:53:24 +01001159 continue;
1160
Marek Szyprowski40bdfb02015-12-16 13:21:42 +01001161 ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
Andrzej Hajda2c826072017-03-15 15:41:05 +01001162 &plane_configs[i]);
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001163 if (ret)
1164 return ret;
1165 }
1166
Gustavo Padovan5d3d0992015-10-12 22:07:48 +09001167 exynos_plane = &ctx->planes[DEFAULT_WIN];
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001168 ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
Andrzej Hajdad6449512017-05-29 10:05:25 +09001169 EXYNOS_DISPLAY_TYPE_HDMI, &mixer_crtc_ops, ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001170 if (IS_ERR(ctx->crtc)) {
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001171 mixer_ctx_remove(ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001172 ret = PTR_ERR(ctx->crtc);
1173 goto free_ctx;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001174 }
1175
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001176 return 0;
Gustavo Padovan93bca242015-01-18 18:16:23 +09001177
1178free_ctx:
1179 devm_kfree(dev, ctx);
1180 return ret;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001181}
1182
1183static void mixer_unbind(struct device *dev, struct device *master, void *data)
1184{
1185 struct mixer_context *ctx = dev_get_drvdata(dev);
1186
Gustavo Padovan93bca242015-01-18 18:16:23 +09001187 mixer_ctx_remove(ctx);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001188}
1189
1190static const struct component_ops mixer_component_ops = {
1191 .bind = mixer_bind,
1192 .unbind = mixer_unbind,
1193};
1194
1195static int mixer_probe(struct platform_device *pdev)
1196{
1197 struct device *dev = &pdev->dev;
Marek Szyprowski48f61552016-04-01 15:17:46 +02001198 const struct mixer_drv_data *drv;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001199 struct mixer_context *ctx;
1200 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001201
Sean Paulf041b252014-01-30 16:19:15 -05001202 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1203 if (!ctx) {
1204 DRM_ERROR("failed to alloc mixer context.\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001205 return -ENOMEM;
Sean Paulf041b252014-01-30 16:19:15 -05001206 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001207
Marek Szyprowski48f61552016-04-01 15:17:46 +02001208 drv = of_device_get_match_data(dev);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301209
Sean Paul45517892014-01-30 16:19:05 -05001210 ctx->pdev = pdev;
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001211 ctx->dev = dev;
Rahul Sharma1e123442012-10-04 20:48:51 +05301212 ctx->mxr_ver = drv->version;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001213
Tobias Jakobiadeb6f442016-09-22 11:36:13 +09001214 if (drv->is_vp_enabled)
1215 __set_bit(MXR_BIT_VP_ENABLED, &ctx->flags);
1216 if (drv->has_sclk)
1217 __set_bit(MXR_BIT_HAS_SCLK, &ctx->flags);
1218
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001219 platform_set_drvdata(pdev, ctx);
Inki Daedf5225b2014-05-29 18:28:02 +09001220
Inki Daedf5225b2014-05-29 18:28:02 +09001221 ret = component_add(&pdev->dev, &mixer_component_ops);
Andrzej Hajda86650402015-06-11 23:23:37 +09001222 if (!ret)
1223 pm_runtime_enable(dev);
Inki Daedf5225b2014-05-29 18:28:02 +09001224
1225 return ret;
Inki Daef37cd5e2014-05-09 14:25:20 +09001226}
1227
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001228static int mixer_remove(struct platform_device *pdev)
1229{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001230 pm_runtime_disable(&pdev->dev);
1231
Inki Daedf5225b2014-05-29 18:28:02 +09001232 component_del(&pdev->dev, &mixer_component_ops);
Inki Daedf5225b2014-05-29 18:28:02 +09001233
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001234 return 0;
1235}
1236
Arnd Bergmanne0fea7e2015-11-17 16:08:36 +01001237static int __maybe_unused exynos_mixer_suspend(struct device *dev)
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001238{
1239 struct mixer_context *ctx = dev_get_drvdata(dev);
1240 struct mixer_resources *res = &ctx->mixer_res;
1241
1242 clk_disable_unprepare(res->hdmi);
1243 clk_disable_unprepare(res->mixer);
Tobias Jakobiadeb6f442016-09-22 11:36:13 +09001244 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001245 clk_disable_unprepare(res->vp);
Tobias Jakobiadeb6f442016-09-22 11:36:13 +09001246 if (test_bit(MXR_BIT_HAS_SCLK, &ctx->flags))
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001247 clk_disable_unprepare(res->sclk_mixer);
1248 }
1249
1250 return 0;
1251}
1252
Arnd Bergmanne0fea7e2015-11-17 16:08:36 +01001253static int __maybe_unused exynos_mixer_resume(struct device *dev)
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001254{
1255 struct mixer_context *ctx = dev_get_drvdata(dev);
1256 struct mixer_resources *res = &ctx->mixer_res;
1257 int ret;
1258
1259 ret = clk_prepare_enable(res->mixer);
1260 if (ret < 0) {
1261 DRM_ERROR("Failed to prepare_enable the mixer clk [%d]\n", ret);
1262 return ret;
1263 }
1264 ret = clk_prepare_enable(res->hdmi);
1265 if (ret < 0) {
1266 DRM_ERROR("Failed to prepare_enable the hdmi clk [%d]\n", ret);
1267 return ret;
1268 }
Tobias Jakobiadeb6f442016-09-22 11:36:13 +09001269 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001270 ret = clk_prepare_enable(res->vp);
1271 if (ret < 0) {
1272 DRM_ERROR("Failed to prepare_enable the vp clk [%d]\n",
1273 ret);
1274 return ret;
1275 }
Tobias Jakobiadeb6f442016-09-22 11:36:13 +09001276 if (test_bit(MXR_BIT_HAS_SCLK, &ctx->flags)) {
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001277 ret = clk_prepare_enable(res->sclk_mixer);
1278 if (ret < 0) {
1279 DRM_ERROR("Failed to prepare_enable the " \
1280 "sclk_mixer clk [%d]\n",
1281 ret);
1282 return ret;
1283 }
1284 }
1285 }
1286
1287 return 0;
1288}
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001289
1290static const struct dev_pm_ops exynos_mixer_pm_ops = {
1291 SET_RUNTIME_PM_OPS(exynos_mixer_suspend, exynos_mixer_resume, NULL)
1292};
1293
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001294struct platform_driver mixer_driver = {
1295 .driver = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301296 .name = "exynos-mixer",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001297 .owner = THIS_MODULE,
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001298 .pm = &exynos_mixer_pm_ops,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301299 .of_match_table = mixer_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001300 },
1301 .probe = mixer_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001302 .remove = mixer_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001303};