blob: ae89e53186eeeba185593c47b8fe701cc73f0717 [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
Andrzej Hajda521d98a2017-09-29 12:05:32 +0200476static void mixer_commit(struct mixer_context *ctx)
477{
478 struct drm_display_mode *mode = &ctx->crtc->base.state->adjusted_mode;
479
Andrzej Hajda71469942017-09-29 12:05:33 +0200480 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
481 __set_bit(MXR_BIT_INTERLACE, &ctx->flags);
482 else
483 __clear_bit(MXR_BIT_INTERLACE, &ctx->flags);
484
Andrzej Hajda521d98a2017-09-29 12:05:32 +0200485 /* setup display size */
486 if (ctx->mxr_ver == MXR_VER_128_0_0_184) {
487 u32 val = MXR_MXR_RES_HEIGHT(mode->vdisplay)
488 | MXR_MXR_RES_WIDTH(mode->hdisplay);
489 mixer_reg_write(&ctx->mixer_res, MXR_RESOLUTION, val);
490 }
491
492 mixer_cfg_scan(ctx, mode->vdisplay);
493 mixer_cfg_rgb_fmt(ctx, mode->vdisplay);
494 mixer_run(ctx);
495}
496
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900497static void vp_video_buffer(struct mixer_context *ctx,
498 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900499{
Marek Szyprowski0114f402015-11-30 14:53:22 +0100500 struct exynos_drm_plane_state *state =
501 to_exynos_plane_state(plane->base.state);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900502 struct mixer_resources *res = &ctx->mixer_res;
Marek Szyprowski0114f402015-11-30 14:53:22 +0100503 struct drm_framebuffer *fb = state->base.fb;
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200504 unsigned int priority = state->base.normalized_zpos + 1;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900505 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900506 dma_addr_t luma_addr[2], chroma_addr[2];
Tobias Jakobi0f752692017-08-22 16:19:38 +0200507 bool is_tiled, is_nv21;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900508 u32 val;
509
Tobias Jakobi0f752692017-08-22 16:19:38 +0200510 is_nv21 = (fb->format->format == DRM_FORMAT_NV21);
511 is_tiled = (fb->modifier == DRM_FORMAT_MOD_SAMSUNG_64_32_TILE);
Tobias Jakobif40031c2017-08-22 16:19:37 +0200512
Marek Szyprowski0488f502015-11-30 14:53:21 +0100513 luma_addr[0] = exynos_drm_fb_dma_addr(fb, 0);
514 chroma_addr[0] = exynos_drm_fb_dma_addr(fb, 1);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900515
Andrzej Hajda71469942017-09-29 12:05:33 +0200516 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
Tobias Jakobi0f752692017-08-22 16:19:38 +0200517 if (is_tiled) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900518 luma_addr[1] = luma_addr[0] + 0x40;
519 chroma_addr[1] = chroma_addr[0] + 0x40;
520 } else {
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900521 luma_addr[1] = luma_addr[0] + fb->pitches[0];
522 chroma_addr[1] = chroma_addr[0] + fb->pitches[0];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900523 }
524 } else {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900525 luma_addr[1] = 0;
526 chroma_addr[1] = 0;
527 }
528
529 spin_lock_irqsave(&res->reg_slock, flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900530
531 /* interlace or progressive scan mode */
Tobias Jakobiadeb6f442016-09-22 11:36:13 +0900532 val = (test_bit(MXR_BIT_INTERLACE, &ctx->flags) ? ~0 : 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900533 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
534
535 /* setup format */
Tobias Jakobi0f752692017-08-22 16:19:38 +0200536 val = (is_nv21 ? VP_MODE_NV21 : VP_MODE_NV12);
537 val |= (is_tiled ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900538 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
539
540 /* setting size of input image */
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900541 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(fb->pitches[0]) |
542 VP_IMG_VSIZE(fb->height));
Tobias Jakobidc500cf2017-08-22 16:19:36 +0200543 /* chroma plane for NV12/NV21 is half the height of the luma plane */
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900544 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(fb->pitches[0]) |
545 VP_IMG_VSIZE(fb->height / 2));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900546
Marek Szyprowski0114f402015-11-30 14:53:22 +0100547 vp_reg_write(res, VP_SRC_WIDTH, state->src.w);
548 vp_reg_write(res, VP_SRC_HEIGHT, state->src.h);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900549 vp_reg_write(res, VP_SRC_H_POSITION,
Marek Szyprowski0114f402015-11-30 14:53:22 +0100550 VP_SRC_H_POSITION_VAL(state->src.x));
551 vp_reg_write(res, VP_SRC_V_POSITION, state->src.y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900552
Marek Szyprowski0114f402015-11-30 14:53:22 +0100553 vp_reg_write(res, VP_DST_WIDTH, state->crtc.w);
554 vp_reg_write(res, VP_DST_H_POSITION, state->crtc.x);
Tobias Jakobiadeb6f442016-09-22 11:36:13 +0900555 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
Marek Szyprowski0114f402015-11-30 14:53:22 +0100556 vp_reg_write(res, VP_DST_HEIGHT, state->crtc.h / 2);
557 vp_reg_write(res, VP_DST_V_POSITION, state->crtc.y / 2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900558 } else {
Marek Szyprowski0114f402015-11-30 14:53:22 +0100559 vp_reg_write(res, VP_DST_HEIGHT, state->crtc.h);
560 vp_reg_write(res, VP_DST_V_POSITION, state->crtc.y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900561 }
562
Marek Szyprowski0114f402015-11-30 14:53:22 +0100563 vp_reg_write(res, VP_H_RATIO, state->h_ratio);
564 vp_reg_write(res, VP_V_RATIO, state->v_ratio);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900565
566 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
567
568 /* set buffer address to vp */
569 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
570 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
571 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
572 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
573
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200574 mixer_cfg_layer(ctx, plane->index, priority, true);
Marek Szyprowskif657a992015-12-16 13:21:46 +0100575 mixer_cfg_vp_blend(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900576
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900577 spin_unlock_irqrestore(&res->reg_slock, flags);
578
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200579 mixer_regs_dump(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900580 vp_regs_dump(ctx);
581}
582
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530583static void mixer_layer_update(struct mixer_context *ctx)
584{
585 struct mixer_resources *res = &ctx->mixer_res;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530586
Rahul Sharma5c0f4822014-06-23 11:02:23 +0530587 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530588}
589
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900590static void mixer_graph_buffer(struct mixer_context *ctx,
591 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900592{
Marek Szyprowski0114f402015-11-30 14:53:22 +0100593 struct exynos_drm_plane_state *state =
594 to_exynos_plane_state(plane->base.state);
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;
Tobias Jakobi5dff6902017-08-22 16:19:40 +0200601 unsigned int 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:
Tobias Jakobi1e60d622017-08-22 16:19:39 +0200623 default:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200624 fmt = MXR_FORMAT_ARGB8888;
625 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900626 }
627
Marek Szyprowskie463b062015-11-30 14:53:27 +0100628 /* ratio is already checked by common plane code */
629 x_ratio = state->h_ratio == (1 << 15);
630 y_ratio = state->v_ratio == (1 << 15);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900631
Marek Szyprowski0114f402015-11-30 14:53:22 +0100632 dst_x_offset = state->crtc.x;
633 dst_y_offset = state->crtc.y;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900634
Tobias Jakobi5dff6902017-08-22 16:19:40 +0200635 /* translate dma address base s.t. the source image offset is zero */
Marek Szyprowski0488f502015-11-30 14:53:21 +0100636 dma_addr = exynos_drm_fb_dma_addr(fb, 0)
Ville Syrjälä272725c2016-12-14 23:32:20 +0200637 + (state->src.x * fb->format->cpp[0])
Marek Szyprowski0114f402015-11-30 14:53:22 +0100638 + (state->src.y * fb->pitches[0]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900639
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900640 spin_lock_irqsave(&res->reg_slock, flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900641
642 /* setup format */
643 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
644 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
645
646 /* setup geometry */
Daniel Stoneadacb222015-03-17 13:24:58 +0000647 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win),
Ville Syrjälä272725c2016-12-14 23:32:20 +0200648 fb->pitches[0] / fb->format->cpp[0]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900649
Marek Szyprowski0114f402015-11-30 14:53:22 +0100650 val = MXR_GRP_WH_WIDTH(state->src.w);
651 val |= MXR_GRP_WH_HEIGHT(state->src.h);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900652 val |= MXR_GRP_WH_H_SCALE(x_ratio);
653 val |= MXR_GRP_WH_V_SCALE(y_ratio);
654 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
655
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900656 /* setup offsets in display image */
657 val = MXR_GRP_DXY_DX(dst_x_offset);
658 val |= MXR_GRP_DXY_DY(dst_y_offset);
659 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
660
661 /* set buffer address to mixer */
662 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
663
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200664 mixer_cfg_layer(ctx, win, priority, true);
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200665 mixer_cfg_gfx_blend(ctx, win, is_alpha_format(fb->format->format));
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530666
667 /* layer update mandatory for mixer 16.0.33.0 */
Rahul Sharmadef5e092013-06-19 18:21:08 +0530668 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
669 ctx->mxr_ver == MXR_VER_128_0_0_184)
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530670 mixer_layer_update(ctx);
671
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900672 spin_unlock_irqrestore(&res->reg_slock, flags);
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200673
674 mixer_regs_dump(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900675}
676
677static void vp_win_reset(struct mixer_context *ctx)
678{
679 struct mixer_resources *res = &ctx->mixer_res;
Tobias Jakobia6963942016-09-22 16:57:19 +0200680 unsigned int tries = 100;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900681
682 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
Dan Carpenter8646dcb2017-01-20 17:54:32 +0100683 while (--tries) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900684 /* waiting until VP_SRESET_PROCESSING is 0 */
685 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
686 break;
Tomasz Stanislawski02b3de42015-09-25 14:48:29 +0200687 mdelay(10);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900688 }
689 WARN(tries == 0, "failed to reset Video Processor\n");
690}
691
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900692static void mixer_win_reset(struct mixer_context *ctx)
693{
694 struct mixer_resources *res = &ctx->mixer_res;
695 unsigned long flags;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900696
697 spin_lock_irqsave(&res->reg_slock, flags);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900698
699 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
700
701 /* set output in RGB888 mode */
702 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
703
704 /* 16 beat burst in DMA */
705 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
706 MXR_STATUS_BURST_MASK);
707
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100708 /* reset default layer priority */
709 mixer_reg_write(res, MXR_LAYER_CFG, 0);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900710
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100711 /* set all background colors to RGB (0,0,0) */
712 mixer_reg_write(res, MXR_BG_COLOR0, MXR_YCBCR_VAL(0, 128, 128));
713 mixer_reg_write(res, MXR_BG_COLOR1, MXR_YCBCR_VAL(0, 128, 128));
714 mixer_reg_write(res, MXR_BG_COLOR2, MXR_YCBCR_VAL(0, 128, 128));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900715
Tobias Jakobiadeb6f442016-09-22 11:36:13 +0900716 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530717 /* configuration of Video Processor Registers */
718 vp_win_reset(ctx);
719 vp_default_filter(res);
720 }
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900721
722 /* disable all layers */
723 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
724 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
Tobias Jakobiadeb6f442016-09-22 11:36:13 +0900725 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags))
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530726 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900727
Tobias Jakobi5dff6902017-08-22 16:19:40 +0200728 /* set all source image offsets to zero */
729 mixer_reg_write(res, MXR_GRAPHIC_SXY(0), 0);
730 mixer_reg_write(res, MXR_GRAPHIC_SXY(1), 0);
731
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900732 spin_unlock_irqrestore(&res->reg_slock, flags);
733}
734
Sean Paul45517892014-01-30 16:19:05 -0500735static irqreturn_t mixer_irq_handler(int irq, void *arg)
736{
737 struct mixer_context *ctx = arg;
738 struct mixer_resources *res = &ctx->mixer_res;
739 u32 val, base, shadow;
740
741 spin_lock(&res->reg_slock);
742
743 /* read interrupt status for handling and clearing flags for VSYNC */
744 val = mixer_reg_read(res, MXR_INT_STATUS);
745
746 /* handling VSYNC */
747 if (val & MXR_INT_STATUS_VSYNC) {
Andrzej Hajda81a464d2015-07-09 10:07:53 +0200748 /* vsync interrupt use different bit for read and clear */
749 val |= MXR_INT_CLEAR_VSYNC;
750 val &= ~MXR_INT_STATUS_VSYNC;
751
Sean Paul45517892014-01-30 16:19:05 -0500752 /* interlace scan need to check shadow register */
Tobias Jakobiadeb6f442016-09-22 11:36:13 +0900753 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
Sean Paul45517892014-01-30 16:19:05 -0500754 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
755 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
756 if (base != shadow)
757 goto out;
758
759 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
760 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
761 if (base != shadow)
762 goto out;
763 }
764
Gustavo Padovaneafd5402015-07-16 12:23:32 -0300765 drm_crtc_handle_vblank(&ctx->crtc->base);
Sean Paul45517892014-01-30 16:19:05 -0500766 }
767
768out:
769 /* clear interrupts */
Sean Paul45517892014-01-30 16:19:05 -0500770 mixer_reg_write(res, MXR_INT_STATUS, val);
771
772 spin_unlock(&res->reg_slock);
773
774 return IRQ_HANDLED;
775}
776
777static int mixer_resources_init(struct mixer_context *mixer_ctx)
778{
779 struct device *dev = &mixer_ctx->pdev->dev;
780 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
781 struct resource *res;
782 int ret;
783
784 spin_lock_init(&mixer_res->reg_slock);
785
786 mixer_res->mixer = devm_clk_get(dev, "mixer");
787 if (IS_ERR(mixer_res->mixer)) {
788 dev_err(dev, "failed to get clock 'mixer'\n");
789 return -ENODEV;
790 }
791
Marek Szyprowski04427ec2015-02-02 14:20:28 +0100792 mixer_res->hdmi = devm_clk_get(dev, "hdmi");
793 if (IS_ERR(mixer_res->hdmi)) {
794 dev_err(dev, "failed to get clock 'hdmi'\n");
795 return PTR_ERR(mixer_res->hdmi);
796 }
797
Sean Paul45517892014-01-30 16:19:05 -0500798 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
799 if (IS_ERR(mixer_res->sclk_hdmi)) {
800 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
801 return -ENODEV;
802 }
803 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
804 if (res == NULL) {
805 dev_err(dev, "get memory resource failed.\n");
806 return -ENXIO;
807 }
808
809 mixer_res->mixer_regs = devm_ioremap(dev, res->start,
810 resource_size(res));
811 if (mixer_res->mixer_regs == NULL) {
812 dev_err(dev, "register mapping failed.\n");
813 return -ENXIO;
814 }
815
816 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
817 if (res == NULL) {
818 dev_err(dev, "get interrupt resource failed.\n");
819 return -ENXIO;
820 }
821
822 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
823 0, "drm_mixer", mixer_ctx);
824 if (ret) {
825 dev_err(dev, "request interrupt failed.\n");
826 return ret;
827 }
828 mixer_res->irq = res->start;
829
830 return 0;
831}
832
833static int vp_resources_init(struct mixer_context *mixer_ctx)
834{
835 struct device *dev = &mixer_ctx->pdev->dev;
836 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
837 struct resource *res;
838
839 mixer_res->vp = devm_clk_get(dev, "vp");
840 if (IS_ERR(mixer_res->vp)) {
841 dev_err(dev, "failed to get clock 'vp'\n");
842 return -ENODEV;
843 }
Sean Paul45517892014-01-30 16:19:05 -0500844
Tobias Jakobiadeb6f442016-09-22 11:36:13 +0900845 if (test_bit(MXR_BIT_HAS_SCLK, &mixer_ctx->flags)) {
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200846 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
847 if (IS_ERR(mixer_res->sclk_mixer)) {
848 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
849 return -ENODEV;
850 }
851 mixer_res->mout_mixer = devm_clk_get(dev, "mout_mixer");
852 if (IS_ERR(mixer_res->mout_mixer)) {
853 dev_err(dev, "failed to get clock 'mout_mixer'\n");
854 return -ENODEV;
855 }
856
857 if (mixer_res->sclk_hdmi && mixer_res->mout_mixer)
858 clk_set_parent(mixer_res->mout_mixer,
859 mixer_res->sclk_hdmi);
860 }
Sean Paul45517892014-01-30 16:19:05 -0500861
862 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
863 if (res == NULL) {
864 dev_err(dev, "get memory resource failed.\n");
865 return -ENXIO;
866 }
867
868 mixer_res->vp_regs = devm_ioremap(dev, res->start,
869 resource_size(res));
870 if (mixer_res->vp_regs == NULL) {
871 dev_err(dev, "register mapping failed.\n");
872 return -ENXIO;
873 }
874
875 return 0;
876}
877
Gustavo Padovan93bca242015-01-18 18:16:23 +0900878static int mixer_initialize(struct mixer_context *mixer_ctx,
Inki Daef37cd5e2014-05-09 14:25:20 +0900879 struct drm_device *drm_dev)
Sean Paul45517892014-01-30 16:19:05 -0500880{
881 int ret;
Inki Daef37cd5e2014-05-09 14:25:20 +0900882 struct exynos_drm_private *priv;
883 priv = drm_dev->dev_private;
Sean Paul45517892014-01-30 16:19:05 -0500884
Gustavo Padovaneb88e422014-11-26 16:43:27 -0200885 mixer_ctx->drm_dev = drm_dev;
Sean Paul45517892014-01-30 16:19:05 -0500886
887 /* acquire resources: regs, irqs, clocks */
888 ret = mixer_resources_init(mixer_ctx);
889 if (ret) {
890 DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
891 return ret;
892 }
893
Tobias Jakobiadeb6f442016-09-22 11:36:13 +0900894 if (test_bit(MXR_BIT_VP_ENABLED, &mixer_ctx->flags)) {
Sean Paul45517892014-01-30 16:19:05 -0500895 /* acquire vp resources: regs, irqs, clocks */
896 ret = vp_resources_init(mixer_ctx);
897 if (ret) {
898 DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
899 return ret;
900 }
901 }
902
Andrzej Hajdaf44d3d22017-03-15 15:41:04 +0100903 return drm_iommu_attach_device(drm_dev, mixer_ctx->dev);
Sean Paul45517892014-01-30 16:19:05 -0500904}
905
Gustavo Padovan93bca242015-01-18 18:16:23 +0900906static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
Inki Dae1055b392012-10-19 17:37:35 +0900907{
Joonyoung Shimbf566082015-07-02 21:49:38 +0900908 drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Inki Dae1055b392012-10-19 17:37:35 +0900909}
910
Gustavo Padovan93bca242015-01-18 18:16:23 +0900911static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900912{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900913 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900914 struct mixer_resources *res = &mixer_ctx->mixer_res;
915
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200916 __set_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
917 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Sean Paulf041b252014-01-30 16:19:15 -0500918 return 0;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900919
920 /* enable vsync interrupt */
Andrzej Hajdafc0732482015-07-09 08:25:40 +0200921 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
922 mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900923
924 return 0;
925}
926
Gustavo Padovan93bca242015-01-18 18:16:23 +0900927static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900928{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900929 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900930 struct mixer_resources *res = &mixer_ctx->mixer_res;
931
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200932 __clear_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
933
934 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Andrzej Hajda947710c2015-07-09 08:25:41 +0200935 return;
Andrzej Hajda947710c2015-07-09 08:25:41 +0200936
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900937 /* disable vsync interrupt */
Andrzej Hajdafc0732482015-07-09 08:25:40 +0200938 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900939 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
940}
941
Marek Szyprowski3dbaab12016-01-05 13:52:52 +0100942static void mixer_atomic_begin(struct exynos_drm_crtc *crtc)
943{
944 struct mixer_context *mixer_ctx = crtc->ctx;
945
946 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
947 return;
948
949 mixer_vsync_set_update(mixer_ctx, false);
950}
951
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900952static void mixer_update_plane(struct exynos_drm_crtc *crtc,
953 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900954{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900955 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900956
Marek Szyprowski40bdfb02015-12-16 13:21:42 +0100957 DRM_DEBUG_KMS("win: %d\n", plane->index);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900958
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200959 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Shirish Sdda90122013-01-23 22:03:18 -0500960 return;
Shirish Sdda90122013-01-23 22:03:18 -0500961
Marek Szyprowski5e68fef2015-12-16 13:21:48 +0100962 if (plane->index == VP_DEFAULT_WIN)
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900963 vp_video_buffer(mixer_ctx, plane);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900964 else
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900965 mixer_graph_buffer(mixer_ctx, plane);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900966}
967
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900968static void mixer_disable_plane(struct exynos_drm_crtc *crtc,
969 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900970{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900971 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900972 struct mixer_resources *res = &mixer_ctx->mixer_res;
973 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900974
Marek Szyprowski40bdfb02015-12-16 13:21:42 +0100975 DRM_DEBUG_KMS("win: %d\n", plane->index);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900976
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200977 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Prathyush Kdb43fd12012-12-06 20:16:05 +0530978 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +0530979
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900980 spin_lock_irqsave(&res->reg_slock, flags);
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100981 mixer_cfg_layer(mixer_ctx, plane->index, 0, false);
Marek Szyprowski3dbaab12016-01-05 13:52:52 +0100982 spin_unlock_irqrestore(&res->reg_slock, flags);
983}
984
985static void mixer_atomic_flush(struct exynos_drm_crtc *crtc)
986{
987 struct mixer_context *mixer_ctx = crtc->ctx;
988
989 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
990 return;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900991
992 mixer_vsync_set_update(mixer_ctx, true);
Andrzej Hajdaa3922762017-03-14 09:27:56 +0100993 exynos_crtc_handle_event(crtc);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900994}
995
Gustavo Padovan3cecda02015-06-01 12:04:55 -0300996static void mixer_enable(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +0530997{
Gustavo Padovan3cecda02015-06-01 12:04:55 -0300998 struct mixer_context *ctx = crtc->ctx;
Prathyush Kdb43fd12012-12-06 20:16:05 +0530999 struct mixer_resources *res = &ctx->mixer_res;
1000
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001001 if (test_bit(MXR_BIT_POWERED, &ctx->flags))
Prathyush Kdb43fd12012-12-06 20:16:05 +05301002 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301003
Sean Paulaf65c802014-01-30 16:19:27 -05001004 pm_runtime_get_sync(ctx->dev);
1005
Andrzej Hajdaa121d172016-03-23 14:26:01 +01001006 exynos_drm_pipe_clk_enable(crtc, true);
1007
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001008 mixer_vsync_set_update(ctx, false);
1009
Rahul Sharmad74ed932014-06-23 11:02:24 +05301010 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
1011
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +02001012 if (test_bit(MXR_BIT_VSYNC, &ctx->flags)) {
Andrzej Hajdafc0732482015-07-09 08:25:40 +02001013 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +02001014 mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
1015 }
Prathyush Kdb43fd12012-12-06 20:16:05 +05301016 mixer_win_reset(ctx);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001017
Andrzej Hajda71469942017-09-29 12:05:33 +02001018 mixer_commit(ctx);
1019
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001020 mixer_vsync_set_update(ctx, true);
1021
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001022 set_bit(MXR_BIT_POWERED, &ctx->flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301023}
1024
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001025static void mixer_disable(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301026{
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001027 struct mixer_context *ctx = crtc->ctx;
Joonyoung Shimc329f662015-06-12 20:34:28 +09001028 int i;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301029
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001030 if (!test_bit(MXR_BIT_POWERED, &ctx->flags))
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301031 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301032
Rahul Sharma381be022014-06-23 11:02:22 +05301033 mixer_stop(ctx);
Tobias Jakobic0734fb2015-05-06 14:10:21 +02001034 mixer_regs_dump(ctx);
Joonyoung Shimc329f662015-06-12 20:34:28 +09001035
1036 for (i = 0; i < MIXER_WIN_NR; i++)
Gustavo Padovan1e1d1392015-08-03 14:39:36 +09001037 mixer_disable_plane(crtc, &ctx->planes[i]);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301038
Andrzej Hajdaa121d172016-03-23 14:26:01 +01001039 exynos_drm_pipe_clk_enable(crtc, false);
1040
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001041 pm_runtime_put(ctx->dev);
1042
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001043 clear_bit(MXR_BIT_POWERED, &ctx->flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301044}
1045
Sean Paulf041b252014-01-30 16:19:15 -05001046/* Only valid for Mixer version 16.0.33.0 */
Andrzej Hajda3ae24362015-10-26 13:03:40 +01001047static int mixer_atomic_check(struct exynos_drm_crtc *crtc,
1048 struct drm_crtc_state *state)
Sean Paulf041b252014-01-30 16:19:15 -05001049{
Andrzej Hajda3ae24362015-10-26 13:03:40 +01001050 struct drm_display_mode *mode = &state->adjusted_mode;
Sean Paulf041b252014-01-30 16:19:15 -05001051 u32 w, h;
1052
1053 w = mode->hdisplay;
1054 h = mode->vdisplay;
1055
1056 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
1057 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1058 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1059
1060 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
1061 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1062 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1063 return 0;
1064
1065 return -EINVAL;
1066}
1067
Krzysztof Kozlowskif3aaf762015-05-07 09:04:45 +09001068static const struct exynos_drm_crtc_ops mixer_crtc_ops = {
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001069 .enable = mixer_enable,
1070 .disable = mixer_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001071 .enable_vblank = mixer_enable_vblank,
1072 .disable_vblank = mixer_disable_vblank,
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001073 .atomic_begin = mixer_atomic_begin,
Gustavo Padovan9cc76102015-08-03 14:38:05 +09001074 .update_plane = mixer_update_plane,
1075 .disable_plane = mixer_disable_plane,
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001076 .atomic_flush = mixer_atomic_flush,
Andrzej Hajda3ae24362015-10-26 13:03:40 +01001077 .atomic_check = mixer_atomic_check,
Sean Paulf041b252014-01-30 16:19:15 -05001078};
Rahul Sharma0ea68222013-01-15 08:11:06 -05001079
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301080static const struct mixer_drv_data exynos5420_mxr_drv_data = {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301081 .version = MXR_VER_128_0_0_184,
1082 .is_vp_enabled = 0,
1083};
1084
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301085static const struct mixer_drv_data exynos5250_mxr_drv_data = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301086 .version = MXR_VER_16_0_33_0,
1087 .is_vp_enabled = 0,
1088};
1089
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301090static const struct mixer_drv_data exynos4212_mxr_drv_data = {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001091 .version = MXR_VER_0_0_0_16,
1092 .is_vp_enabled = 1,
1093};
1094
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301095static const struct mixer_drv_data exynos4210_mxr_drv_data = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301096 .version = MXR_VER_0_0_0_16,
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301097 .is_vp_enabled = 1,
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001098 .has_sclk = 1,
Rahul Sharma1e123442012-10-04 20:48:51 +05301099};
1100
Arvind Yadav5e6cc1c2017-06-19 15:42:42 +05301101static const struct of_device_id mixer_match_types[] = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301102 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001103 .compatible = "samsung,exynos4210-mixer",
1104 .data = &exynos4210_mxr_drv_data,
1105 }, {
1106 .compatible = "samsung,exynos4212-mixer",
1107 .data = &exynos4212_mxr_drv_data,
1108 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301109 .compatible = "samsung,exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301110 .data = &exynos5250_mxr_drv_data,
1111 }, {
1112 .compatible = "samsung,exynos5250-mixer",
1113 .data = &exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301114 }, {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301115 .compatible = "samsung,exynos5420-mixer",
1116 .data = &exynos5420_mxr_drv_data,
1117 }, {
Rahul Sharma1e123442012-10-04 20:48:51 +05301118 /* end node */
1119 }
1120};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001121MODULE_DEVICE_TABLE(of, mixer_match_types);
Rahul Sharma1e123442012-10-04 20:48:51 +05301122
Inki Daef37cd5e2014-05-09 14:25:20 +09001123static int mixer_bind(struct device *dev, struct device *manager, void *data)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001124{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001125 struct mixer_context *ctx = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09001126 struct drm_device *drm_dev = data;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001127 struct exynos_drm_plane *exynos_plane;
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +01001128 unsigned int i;
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +09001129 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001130
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001131 ret = mixer_initialize(ctx, drm_dev);
1132 if (ret)
1133 return ret;
1134
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +01001135 for (i = 0; i < MIXER_WIN_NR; i++) {
Tobias Jakobiadeb6f442016-09-22 11:36:13 +09001136 if (i == VP_DEFAULT_WIN && !test_bit(MXR_BIT_VP_ENABLED,
1137 &ctx->flags))
Marek Szyprowskiab144202015-11-30 14:53:24 +01001138 continue;
1139
Marek Szyprowski40bdfb02015-12-16 13:21:42 +01001140 ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
Andrzej Hajda2c826072017-03-15 15:41:05 +01001141 &plane_configs[i]);
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001142 if (ret)
1143 return ret;
1144 }
1145
Gustavo Padovan5d3d0992015-10-12 22:07:48 +09001146 exynos_plane = &ctx->planes[DEFAULT_WIN];
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001147 ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
Andrzej Hajdad6449512017-05-29 10:05:25 +09001148 EXYNOS_DISPLAY_TYPE_HDMI, &mixer_crtc_ops, ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001149 if (IS_ERR(ctx->crtc)) {
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001150 mixer_ctx_remove(ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001151 ret = PTR_ERR(ctx->crtc);
1152 goto free_ctx;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001153 }
1154
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001155 return 0;
Gustavo Padovan93bca242015-01-18 18:16:23 +09001156
1157free_ctx:
1158 devm_kfree(dev, ctx);
1159 return ret;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001160}
1161
1162static void mixer_unbind(struct device *dev, struct device *master, void *data)
1163{
1164 struct mixer_context *ctx = dev_get_drvdata(dev);
1165
Gustavo Padovan93bca242015-01-18 18:16:23 +09001166 mixer_ctx_remove(ctx);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001167}
1168
1169static const struct component_ops mixer_component_ops = {
1170 .bind = mixer_bind,
1171 .unbind = mixer_unbind,
1172};
1173
1174static int mixer_probe(struct platform_device *pdev)
1175{
1176 struct device *dev = &pdev->dev;
Marek Szyprowski48f61552016-04-01 15:17:46 +02001177 const struct mixer_drv_data *drv;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001178 struct mixer_context *ctx;
1179 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001180
Sean Paulf041b252014-01-30 16:19:15 -05001181 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1182 if (!ctx) {
1183 DRM_ERROR("failed to alloc mixer context.\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001184 return -ENOMEM;
Sean Paulf041b252014-01-30 16:19:15 -05001185 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001186
Marek Szyprowski48f61552016-04-01 15:17:46 +02001187 drv = of_device_get_match_data(dev);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301188
Sean Paul45517892014-01-30 16:19:05 -05001189 ctx->pdev = pdev;
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001190 ctx->dev = dev;
Rahul Sharma1e123442012-10-04 20:48:51 +05301191 ctx->mxr_ver = drv->version;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001192
Tobias Jakobiadeb6f442016-09-22 11:36:13 +09001193 if (drv->is_vp_enabled)
1194 __set_bit(MXR_BIT_VP_ENABLED, &ctx->flags);
1195 if (drv->has_sclk)
1196 __set_bit(MXR_BIT_HAS_SCLK, &ctx->flags);
1197
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001198 platform_set_drvdata(pdev, ctx);
Inki Daedf5225b2014-05-29 18:28:02 +09001199
Inki Daedf5225b2014-05-29 18:28:02 +09001200 ret = component_add(&pdev->dev, &mixer_component_ops);
Andrzej Hajda86650402015-06-11 23:23:37 +09001201 if (!ret)
1202 pm_runtime_enable(dev);
Inki Daedf5225b2014-05-29 18:28:02 +09001203
1204 return ret;
Inki Daef37cd5e2014-05-09 14:25:20 +09001205}
1206
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001207static int mixer_remove(struct platform_device *pdev)
1208{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001209 pm_runtime_disable(&pdev->dev);
1210
Inki Daedf5225b2014-05-29 18:28:02 +09001211 component_del(&pdev->dev, &mixer_component_ops);
Inki Daedf5225b2014-05-29 18:28:02 +09001212
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001213 return 0;
1214}
1215
Arnd Bergmanne0fea7e2015-11-17 16:08:36 +01001216static int __maybe_unused exynos_mixer_suspend(struct device *dev)
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001217{
1218 struct mixer_context *ctx = dev_get_drvdata(dev);
1219 struct mixer_resources *res = &ctx->mixer_res;
1220
1221 clk_disable_unprepare(res->hdmi);
1222 clk_disable_unprepare(res->mixer);
Tobias Jakobiadeb6f442016-09-22 11:36:13 +09001223 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001224 clk_disable_unprepare(res->vp);
Tobias Jakobiadeb6f442016-09-22 11:36:13 +09001225 if (test_bit(MXR_BIT_HAS_SCLK, &ctx->flags))
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001226 clk_disable_unprepare(res->sclk_mixer);
1227 }
1228
1229 return 0;
1230}
1231
Arnd Bergmanne0fea7e2015-11-17 16:08:36 +01001232static int __maybe_unused exynos_mixer_resume(struct device *dev)
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001233{
1234 struct mixer_context *ctx = dev_get_drvdata(dev);
1235 struct mixer_resources *res = &ctx->mixer_res;
1236 int ret;
1237
1238 ret = clk_prepare_enable(res->mixer);
1239 if (ret < 0) {
1240 DRM_ERROR("Failed to prepare_enable the mixer clk [%d]\n", ret);
1241 return ret;
1242 }
1243 ret = clk_prepare_enable(res->hdmi);
1244 if (ret < 0) {
1245 DRM_ERROR("Failed to prepare_enable the hdmi clk [%d]\n", ret);
1246 return ret;
1247 }
Tobias Jakobiadeb6f442016-09-22 11:36:13 +09001248 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001249 ret = clk_prepare_enable(res->vp);
1250 if (ret < 0) {
1251 DRM_ERROR("Failed to prepare_enable the vp clk [%d]\n",
1252 ret);
1253 return ret;
1254 }
Tobias Jakobiadeb6f442016-09-22 11:36:13 +09001255 if (test_bit(MXR_BIT_HAS_SCLK, &ctx->flags)) {
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001256 ret = clk_prepare_enable(res->sclk_mixer);
1257 if (ret < 0) {
1258 DRM_ERROR("Failed to prepare_enable the " \
1259 "sclk_mixer clk [%d]\n",
1260 ret);
1261 return ret;
1262 }
1263 }
1264 }
1265
1266 return 0;
1267}
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001268
1269static const struct dev_pm_ops exynos_mixer_pm_ops = {
1270 SET_RUNTIME_PM_OPS(exynos_mixer_suspend, exynos_mixer_resume, NULL)
1271};
1272
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001273struct platform_driver mixer_driver = {
1274 .driver = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301275 .name = "exynos-mixer",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001276 .owner = THIS_MODULE,
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001277 .pm = &exynos_mixer_pm_ops,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301278 .of_match_table = mixer_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001279 },
1280 .probe = mixer_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001281 .remove = mixer_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001282};