blob: 6bed4f3ffcd6bd8592c51ee398a3ccdbe10355e1 [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 Jakobiadeb6f42016-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 |
151 EXYNOS_DRM_PLANE_CAP_ZPOS,
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +0100152 },
153};
154
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900155static const u8 filter_y_horiz_tap8[] = {
156 0, -1, -1, -1, -1, -1, -1, -1,
157 -1, -1, -1, -1, -1, 0, 0, 0,
158 0, 2, 4, 5, 6, 6, 6, 6,
159 6, 5, 5, 4, 3, 2, 1, 1,
160 0, -6, -12, -16, -18, -20, -21, -20,
161 -20, -18, -16, -13, -10, -8, -5, -2,
162 127, 126, 125, 121, 114, 107, 99, 89,
163 79, 68, 57, 46, 35, 25, 16, 8,
164};
165
166static const u8 filter_y_vert_tap4[] = {
167 0, -3, -6, -8, -8, -8, -8, -7,
168 -6, -5, -4, -3, -2, -1, -1, 0,
169 127, 126, 124, 118, 111, 102, 92, 81,
170 70, 59, 48, 37, 27, 19, 11, 5,
171 0, 5, 11, 19, 27, 37, 48, 59,
172 70, 81, 92, 102, 111, 118, 124, 126,
173 0, 0, -1, -1, -2, -3, -4, -5,
174 -6, -7, -8, -8, -8, -8, -6, -3,
175};
176
177static const u8 filter_cr_horiz_tap4[] = {
178 0, -3, -6, -8, -8, -8, -8, -7,
179 -6, -5, -4, -3, -2, -1, -1, 0,
180 127, 126, 124, 118, 111, 102, 92, 81,
181 70, 59, 48, 37, 27, 19, 11, 5,
182};
183
Marek Szyprowskif657a992015-12-16 13:21:46 +0100184static inline bool is_alpha_format(unsigned int pixel_format)
185{
186 switch (pixel_format) {
187 case DRM_FORMAT_ARGB8888:
Tobias Jakobi26a7af32015-12-16 13:21:47 +0100188 case DRM_FORMAT_ARGB1555:
189 case DRM_FORMAT_ARGB4444:
Marek Szyprowskif657a992015-12-16 13:21:46 +0100190 return true;
191 default:
192 return false;
193 }
194}
195
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900196static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
197{
198 return readl(res->vp_regs + reg_id);
199}
200
201static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
202 u32 val)
203{
204 writel(val, res->vp_regs + reg_id);
205}
206
207static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
208 u32 val, u32 mask)
209{
210 u32 old = vp_reg_read(res, reg_id);
211
212 val = (val & mask) | (old & ~mask);
213 writel(val, res->vp_regs + reg_id);
214}
215
216static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
217{
218 return readl(res->mixer_regs + reg_id);
219}
220
221static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
222 u32 val)
223{
224 writel(val, res->mixer_regs + reg_id);
225}
226
227static inline void mixer_reg_writemask(struct mixer_resources *res,
228 u32 reg_id, u32 val, u32 mask)
229{
230 u32 old = mixer_reg_read(res, reg_id);
231
232 val = (val & mask) | (old & ~mask);
233 writel(val, res->mixer_regs + reg_id);
234}
235
236static void mixer_regs_dump(struct mixer_context *ctx)
237{
238#define DUMPREG(reg_id) \
239do { \
240 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
241 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
242} while (0)
243
244 DUMPREG(MXR_STATUS);
245 DUMPREG(MXR_CFG);
246 DUMPREG(MXR_INT_EN);
247 DUMPREG(MXR_INT_STATUS);
248
249 DUMPREG(MXR_LAYER_CFG);
250 DUMPREG(MXR_VIDEO_CFG);
251
252 DUMPREG(MXR_GRAPHIC0_CFG);
253 DUMPREG(MXR_GRAPHIC0_BASE);
254 DUMPREG(MXR_GRAPHIC0_SPAN);
255 DUMPREG(MXR_GRAPHIC0_WH);
256 DUMPREG(MXR_GRAPHIC0_SXY);
257 DUMPREG(MXR_GRAPHIC0_DXY);
258
259 DUMPREG(MXR_GRAPHIC1_CFG);
260 DUMPREG(MXR_GRAPHIC1_BASE);
261 DUMPREG(MXR_GRAPHIC1_SPAN);
262 DUMPREG(MXR_GRAPHIC1_WH);
263 DUMPREG(MXR_GRAPHIC1_SXY);
264 DUMPREG(MXR_GRAPHIC1_DXY);
265#undef DUMPREG
266}
267
268static void vp_regs_dump(struct mixer_context *ctx)
269{
270#define DUMPREG(reg_id) \
271do { \
272 DRM_DEBUG_KMS(#reg_id " = %08x\n", \
273 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
274} while (0)
275
276 DUMPREG(VP_ENABLE);
277 DUMPREG(VP_SRESET);
278 DUMPREG(VP_SHADOW_UPDATE);
279 DUMPREG(VP_FIELD_ID);
280 DUMPREG(VP_MODE);
281 DUMPREG(VP_IMG_SIZE_Y);
282 DUMPREG(VP_IMG_SIZE_C);
283 DUMPREG(VP_PER_RATE_CTRL);
284 DUMPREG(VP_TOP_Y_PTR);
285 DUMPREG(VP_BOT_Y_PTR);
286 DUMPREG(VP_TOP_C_PTR);
287 DUMPREG(VP_BOT_C_PTR);
288 DUMPREG(VP_ENDIAN_MODE);
289 DUMPREG(VP_SRC_H_POSITION);
290 DUMPREG(VP_SRC_V_POSITION);
291 DUMPREG(VP_SRC_WIDTH);
292 DUMPREG(VP_SRC_HEIGHT);
293 DUMPREG(VP_DST_H_POSITION);
294 DUMPREG(VP_DST_V_POSITION);
295 DUMPREG(VP_DST_WIDTH);
296 DUMPREG(VP_DST_HEIGHT);
297 DUMPREG(VP_H_RATIO);
298 DUMPREG(VP_V_RATIO);
299
300#undef DUMPREG
301}
302
303static inline void vp_filter_set(struct mixer_resources *res,
304 int reg_id, const u8 *data, unsigned int size)
305{
306 /* assure 4-byte align */
307 BUG_ON(size & 3);
308 for (; size; size -= 4, reg_id += 4, data += 4) {
309 u32 val = (data[0] << 24) | (data[1] << 16) |
310 (data[2] << 8) | data[3];
311 vp_reg_write(res, reg_id, val);
312 }
313}
314
315static void vp_default_filter(struct mixer_resources *res)
316{
317 vp_filter_set(res, VP_POLY8_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530318 filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900319 vp_filter_set(res, VP_POLY4_Y0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530320 filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900321 vp_filter_set(res, VP_POLY4_C0_LL,
Sachin Kamate25e1b62012-08-31 15:50:48 +0530322 filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900323}
324
Marek Szyprowskif657a992015-12-16 13:21:46 +0100325static void mixer_cfg_gfx_blend(struct mixer_context *ctx, unsigned int win,
326 bool alpha)
327{
328 struct mixer_resources *res = &ctx->mixer_res;
329 u32 val;
330
331 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
332 if (alpha) {
333 /* blending based on pixel alpha */
334 val |= MXR_GRP_CFG_BLEND_PRE_MUL;
335 val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
336 }
337 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
338 val, MXR_GRP_CFG_MISC_MASK);
339}
340
341static void mixer_cfg_vp_blend(struct mixer_context *ctx)
342{
343 struct mixer_resources *res = &ctx->mixer_res;
344 u32 val;
345
346 /*
347 * No blending at the moment since the NV12/NV21 pixelformats don't
348 * have an alpha channel. However the mixer supports a global alpha
349 * value for a layer. Once this functionality is exposed, we can
350 * support blending of the video layer through this.
351 */
352 val = 0;
353 mixer_reg_write(res, MXR_VIDEO_CFG, val);
354}
355
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900356static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
357{
358 struct mixer_resources *res = &ctx->mixer_res;
359
360 /* block update on vsync */
361 mixer_reg_writemask(res, MXR_STATUS, enable ?
362 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
363
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900364 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags))
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530365 vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900366 VP_SHADOW_UPDATE_ENABLE : 0);
367}
368
369static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
370{
371 struct mixer_resources *res = &ctx->mixer_res;
372 u32 val;
373
374 /* choosing between interlace and progressive mode */
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900375 val = test_bit(MXR_BIT_INTERLACE, &ctx->flags) ?
376 MXR_CFG_SCAN_INTERLACE : MXR_CFG_SCAN_PROGRESSIVE;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900377
Rahul Sharmadef5e092013-06-19 18:21:08 +0530378 if (ctx->mxr_ver != MXR_VER_128_0_0_184) {
379 /* choosing between proper HD and SD mode */
380 if (height <= 480)
381 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
382 else if (height <= 576)
383 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
384 else if (height <= 720)
385 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
386 else if (height <= 1080)
387 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
388 else
389 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
390 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900391
392 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
393}
394
395static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
396{
397 struct mixer_resources *res = &ctx->mixer_res;
398 u32 val;
399
Tobias Jakobi2a39db02017-03-10 14:30:16 +0100400 switch (height) {
401 case 480:
402 case 576:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900403 val = MXR_CFG_RGB601_0_255;
Tobias Jakobi2a39db02017-03-10 14:30:16 +0100404 break;
405 case 720:
406 case 1080:
407 default:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900408 val = MXR_CFG_RGB709_16_235;
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100409 /* Configure the BT.709 CSC matrix for full range RGB. */
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900410 mixer_reg_write(res, MXR_CM_COEFF_Y,
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100411 MXR_CSC_CT( 0.184, 0.614, 0.063) |
412 MXR_CM_COEFF_RGB_FULL);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900413 mixer_reg_write(res, MXR_CM_COEFF_CB,
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100414 MXR_CSC_CT(-0.102, -0.338, 0.440));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900415 mixer_reg_write(res, MXR_CM_COEFF_CR,
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100416 MXR_CSC_CT( 0.440, -0.399, -0.040));
Tobias Jakobi2a39db02017-03-10 14:30:16 +0100417 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900418 }
419
420 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
421}
422
Tobias Jakobi5b1d5bc2015-05-06 14:10:22 +0200423static void mixer_cfg_layer(struct mixer_context *ctx, unsigned int win,
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100424 unsigned int priority, bool enable)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900425{
426 struct mixer_resources *res = &ctx->mixer_res;
427 u32 val = enable ? ~0 : 0;
428
429 switch (win) {
430 case 0:
431 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100432 mixer_reg_writemask(res, MXR_LAYER_CFG,
433 MXR_LAYER_CFG_GRP0_VAL(priority),
434 MXR_LAYER_CFG_GRP0_MASK);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900435 break;
436 case 1:
437 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100438 mixer_reg_writemask(res, MXR_LAYER_CFG,
439 MXR_LAYER_CFG_GRP1_VAL(priority),
440 MXR_LAYER_CFG_GRP1_MASK);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900441
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900442 break;
Marek Szyprowski5e68fef2015-12-16 13:21:48 +0100443 case VP_DEFAULT_WIN:
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900444 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530445 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
446 mixer_reg_writemask(res, MXR_CFG, val,
447 MXR_CFG_VP_ENABLE);
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100448 mixer_reg_writemask(res, MXR_LAYER_CFG,
449 MXR_LAYER_CFG_VP_VAL(priority),
450 MXR_LAYER_CFG_VP_MASK);
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530451 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900452 break;
453 }
454}
455
456static void mixer_run(struct mixer_context *ctx)
457{
458 struct mixer_resources *res = &ctx->mixer_res;
459
460 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900461}
462
Rahul Sharma381be022014-06-23 11:02:22 +0530463static void mixer_stop(struct mixer_context *ctx)
464{
465 struct mixer_resources *res = &ctx->mixer_res;
466 int timeout = 20;
467
468 mixer_reg_writemask(res, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
469
470 while (!(mixer_reg_read(res, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
471 --timeout)
472 usleep_range(10000, 12000);
Rahul Sharma381be022014-06-23 11:02:22 +0530473}
474
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900475static void vp_video_buffer(struct mixer_context *ctx,
476 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900477{
Marek Szyprowski0114f402015-11-30 14:53:22 +0100478 struct exynos_drm_plane_state *state =
479 to_exynos_plane_state(plane->base.state);
Marek Szyprowski2ee35d82015-11-30 14:53:23 +0100480 struct drm_display_mode *mode = &state->base.crtc->state->adjusted_mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900481 struct mixer_resources *res = &ctx->mixer_res;
Marek Szyprowski0114f402015-11-30 14:53:22 +0100482 struct drm_framebuffer *fb = state->base.fb;
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200483 unsigned int priority = state->base.normalized_zpos + 1;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900484 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900485 dma_addr_t luma_addr[2], chroma_addr[2];
486 bool tiled_mode = false;
487 bool crcb_mode = false;
488 u32 val;
489
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200490 switch (fb->format->format) {
Ville Syrjälä363b06a2012-05-14 11:08:51 +0900491 case DRM_FORMAT_NV12:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900492 crcb_mode = false;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900493 break;
Tobias Jakobi8f2590f2015-04-27 23:10:16 +0200494 case DRM_FORMAT_NV21:
495 crcb_mode = true;
496 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900497 default:
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900498 DRM_ERROR("pixel format for vp is wrong [%d].\n",
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200499 fb->format->format);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900500 return;
501 }
502
Marek Szyprowski0488f502015-11-30 14:53:21 +0100503 luma_addr[0] = exynos_drm_fb_dma_addr(fb, 0);
504 chroma_addr[0] = exynos_drm_fb_dma_addr(fb, 1);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900505
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900506 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900507 __set_bit(MXR_BIT_INTERLACE, &ctx->flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900508 if (tiled_mode) {
509 luma_addr[1] = luma_addr[0] + 0x40;
510 chroma_addr[1] = chroma_addr[0] + 0x40;
511 } else {
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900512 luma_addr[1] = luma_addr[0] + fb->pitches[0];
513 chroma_addr[1] = chroma_addr[0] + fb->pitches[0];
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900514 }
515 } else {
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900516 __clear_bit(MXR_BIT_INTERLACE, &ctx->flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900517 luma_addr[1] = 0;
518 chroma_addr[1] = 0;
519 }
520
521 spin_lock_irqsave(&res->reg_slock, flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900522
523 /* interlace or progressive scan mode */
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900524 val = (test_bit(MXR_BIT_INTERLACE, &ctx->flags) ? ~0 : 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900525 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
526
527 /* setup format */
528 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
529 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
530 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
531
532 /* setting size of input image */
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900533 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(fb->pitches[0]) |
534 VP_IMG_VSIZE(fb->height));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900535 /* chroma height has to reduced by 2 to avoid chroma distorions */
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900536 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(fb->pitches[0]) |
537 VP_IMG_VSIZE(fb->height / 2));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900538
Marek Szyprowski0114f402015-11-30 14:53:22 +0100539 vp_reg_write(res, VP_SRC_WIDTH, state->src.w);
540 vp_reg_write(res, VP_SRC_HEIGHT, state->src.h);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900541 vp_reg_write(res, VP_SRC_H_POSITION,
Marek Szyprowski0114f402015-11-30 14:53:22 +0100542 VP_SRC_H_POSITION_VAL(state->src.x));
543 vp_reg_write(res, VP_SRC_V_POSITION, state->src.y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900544
Marek Szyprowski0114f402015-11-30 14:53:22 +0100545 vp_reg_write(res, VP_DST_WIDTH, state->crtc.w);
546 vp_reg_write(res, VP_DST_H_POSITION, state->crtc.x);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900547 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
Marek Szyprowski0114f402015-11-30 14:53:22 +0100548 vp_reg_write(res, VP_DST_HEIGHT, state->crtc.h / 2);
549 vp_reg_write(res, VP_DST_V_POSITION, state->crtc.y / 2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900550 } else {
Marek Szyprowski0114f402015-11-30 14:53:22 +0100551 vp_reg_write(res, VP_DST_HEIGHT, state->crtc.h);
552 vp_reg_write(res, VP_DST_V_POSITION, state->crtc.y);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900553 }
554
Marek Szyprowski0114f402015-11-30 14:53:22 +0100555 vp_reg_write(res, VP_H_RATIO, state->h_ratio);
556 vp_reg_write(res, VP_V_RATIO, state->v_ratio);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900557
558 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
559
560 /* set buffer address to vp */
561 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
562 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
563 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
564 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
565
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900566 mixer_cfg_scan(ctx, mode->vdisplay);
567 mixer_cfg_rgb_fmt(ctx, mode->vdisplay);
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200568 mixer_cfg_layer(ctx, plane->index, priority, true);
Marek Szyprowskif657a992015-12-16 13:21:46 +0100569 mixer_cfg_vp_blend(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900570 mixer_run(ctx);
571
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900572 spin_unlock_irqrestore(&res->reg_slock, flags);
573
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200574 mixer_regs_dump(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900575 vp_regs_dump(ctx);
576}
577
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530578static void mixer_layer_update(struct mixer_context *ctx)
579{
580 struct mixer_resources *res = &ctx->mixer_res;
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530581
Rahul Sharma5c0f4822014-06-23 11:02:23 +0530582 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530583}
584
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900585static void mixer_graph_buffer(struct mixer_context *ctx,
586 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900587{
Marek Szyprowski0114f402015-11-30 14:53:22 +0100588 struct exynos_drm_plane_state *state =
589 to_exynos_plane_state(plane->base.state);
Marek Szyprowski2ee35d82015-11-30 14:53:23 +0100590 struct drm_display_mode *mode = &state->base.crtc->state->adjusted_mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900591 struct mixer_resources *res = &ctx->mixer_res;
Marek Szyprowski0114f402015-11-30 14:53:22 +0100592 struct drm_framebuffer *fb = state->base.fb;
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200593 unsigned int priority = state->base.normalized_zpos + 1;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900594 unsigned long flags;
Marek Szyprowski40bdfb02015-12-16 13:21:42 +0100595 unsigned int win = plane->index;
Tobias Jakobi26110152015-04-07 01:14:52 +0200596 unsigned int x_ratio = 0, y_ratio = 0;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900597 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900598 dma_addr_t dma_addr;
599 unsigned int fmt;
600 u32 val;
601
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200602 switch (fb->format->format) {
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200603 case DRM_FORMAT_XRGB4444:
Tobias Jakobi26a7af32015-12-16 13:21:47 +0100604 case DRM_FORMAT_ARGB4444:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200605 fmt = MXR_FORMAT_ARGB4444;
606 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900607
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200608 case DRM_FORMAT_XRGB1555:
Tobias Jakobi26a7af32015-12-16 13:21:47 +0100609 case DRM_FORMAT_ARGB1555:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200610 fmt = MXR_FORMAT_ARGB1555;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900611 break;
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200612
613 case DRM_FORMAT_RGB565:
614 fmt = MXR_FORMAT_RGB565;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900615 break;
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200616
617 case DRM_FORMAT_XRGB8888:
618 case DRM_FORMAT_ARGB8888:
619 fmt = MXR_FORMAT_ARGB8888;
620 break;
621
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900622 default:
Tobias Jakobi7a57ca72015-04-27 23:11:59 +0200623 DRM_DEBUG_KMS("pixelformat unsupported by mixer\n");
624 return;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900625 }
626
Marek Szyprowskie463b062015-11-30 14:53:27 +0100627 /* ratio is already checked by common plane code */
628 x_ratio = state->h_ratio == (1 << 15);
629 y_ratio = state->v_ratio == (1 << 15);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900630
Marek Szyprowski0114f402015-11-30 14:53:22 +0100631 dst_x_offset = state->crtc.x;
632 dst_y_offset = state->crtc.y;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900633
634 /* converting dma address base and source offset */
Marek Szyprowski0488f502015-11-30 14:53:21 +0100635 dma_addr = exynos_drm_fb_dma_addr(fb, 0)
Ville Syrjälä272725c2016-12-14 23:32:20 +0200636 + (state->src.x * fb->format->cpp[0])
Marek Szyprowski0114f402015-11-30 14:53:22 +0100637 + (state->src.y * fb->pitches[0]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900638 src_x_offset = 0;
639 src_y_offset = 0;
640
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900641 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900642 __set_bit(MXR_BIT_INTERLACE, &ctx->flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900643 else
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900644 __clear_bit(MXR_BIT_INTERLACE, &ctx->flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900645
646 spin_lock_irqsave(&res->reg_slock, flags);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900647
648 /* setup format */
649 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
650 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
651
652 /* setup geometry */
Daniel Stoneadacb222015-03-17 13:24:58 +0000653 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win),
Ville Syrjälä272725c2016-12-14 23:32:20 +0200654 fb->pitches[0] / fb->format->cpp[0]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900655
Rahul Sharmadef5e092013-06-19 18:21:08 +0530656 /* setup display size */
657 if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
Gustavo Padovan5d3d0992015-10-12 22:07:48 +0900658 win == DEFAULT_WIN) {
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900659 val = MXR_MXR_RES_HEIGHT(mode->vdisplay);
660 val |= MXR_MXR_RES_WIDTH(mode->hdisplay);
Rahul Sharmadef5e092013-06-19 18:21:08 +0530661 mixer_reg_write(res, MXR_RESOLUTION, val);
662 }
663
Marek Szyprowski0114f402015-11-30 14:53:22 +0100664 val = MXR_GRP_WH_WIDTH(state->src.w);
665 val |= MXR_GRP_WH_HEIGHT(state->src.h);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900666 val |= MXR_GRP_WH_H_SCALE(x_ratio);
667 val |= MXR_GRP_WH_V_SCALE(y_ratio);
668 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
669
670 /* setup offsets in source image */
671 val = MXR_GRP_SXY_SX(src_x_offset);
672 val |= MXR_GRP_SXY_SY(src_y_offset);
673 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
674
675 /* setup offsets in display image */
676 val = MXR_GRP_DXY_DX(dst_x_offset);
677 val |= MXR_GRP_DXY_DY(dst_y_offset);
678 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
679
680 /* set buffer address to mixer */
681 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
682
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900683 mixer_cfg_scan(ctx, mode->vdisplay);
684 mixer_cfg_rgb_fmt(ctx, mode->vdisplay);
Marek Szyprowskie47726a2016-05-11 17:16:06 +0200685 mixer_cfg_layer(ctx, win, priority, true);
Ville Syrjälä438b74a2016-12-14 23:32:55 +0200686 mixer_cfg_gfx_blend(ctx, win, is_alpha_format(fb->format->format));
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530687
688 /* layer update mandatory for mixer 16.0.33.0 */
Rahul Sharmadef5e092013-06-19 18:21:08 +0530689 if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
690 ctx->mxr_ver == MXR_VER_128_0_0_184)
Rahul Sharmaaaf8b492012-10-04 20:48:53 +0530691 mixer_layer_update(ctx);
692
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900693 mixer_run(ctx);
694
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900695 spin_unlock_irqrestore(&res->reg_slock, flags);
Tobias Jakobic0734fb2015-05-06 14:10:21 +0200696
697 mixer_regs_dump(ctx);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900698}
699
700static void vp_win_reset(struct mixer_context *ctx)
701{
702 struct mixer_resources *res = &ctx->mixer_res;
Tobias Jakobia6963942016-09-22 16:57:19 +0200703 unsigned int tries = 100;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900704
705 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
Dan Carpenter8646dcb2017-01-20 17:54:32 +0100706 while (--tries) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900707 /* waiting until VP_SRESET_PROCESSING is 0 */
708 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
709 break;
Tomasz Stanislawski02b3de42015-09-25 14:48:29 +0200710 mdelay(10);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900711 }
712 WARN(tries == 0, "failed to reset Video Processor\n");
713}
714
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900715static void mixer_win_reset(struct mixer_context *ctx)
716{
717 struct mixer_resources *res = &ctx->mixer_res;
718 unsigned long flags;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900719
720 spin_lock_irqsave(&res->reg_slock, flags);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900721
722 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
723
724 /* set output in RGB888 mode */
725 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
726
727 /* 16 beat burst in DMA */
728 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
729 MXR_STATUS_BURST_MASK);
730
Marek Szyprowskia2cb9112015-12-16 13:21:44 +0100731 /* reset default layer priority */
732 mixer_reg_write(res, MXR_LAYER_CFG, 0);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900733
Tobias Jakobi2a6e4cd2017-03-10 15:21:54 +0100734 /* set all background colors to RGB (0,0,0) */
735 mixer_reg_write(res, MXR_BG_COLOR0, MXR_YCBCR_VAL(0, 128, 128));
736 mixer_reg_write(res, MXR_BG_COLOR1, MXR_YCBCR_VAL(0, 128, 128));
737 mixer_reg_write(res, MXR_BG_COLOR2, MXR_YCBCR_VAL(0, 128, 128));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900738
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900739 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530740 /* configuration of Video Processor Registers */
741 vp_win_reset(ctx);
742 vp_default_filter(res);
743 }
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900744
745 /* disable all layers */
746 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
747 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900748 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags))
Rahul Sharma1b8e5742012-10-04 20:48:52 +0530749 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900750
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900751 spin_unlock_irqrestore(&res->reg_slock, flags);
752}
753
Sean Paul45517892014-01-30 16:19:05 -0500754static irqreturn_t mixer_irq_handler(int irq, void *arg)
755{
756 struct mixer_context *ctx = arg;
757 struct mixer_resources *res = &ctx->mixer_res;
758 u32 val, base, shadow;
759
760 spin_lock(&res->reg_slock);
761
762 /* read interrupt status for handling and clearing flags for VSYNC */
763 val = mixer_reg_read(res, MXR_INT_STATUS);
764
765 /* handling VSYNC */
766 if (val & MXR_INT_STATUS_VSYNC) {
Andrzej Hajda81a464d2015-07-09 10:07:53 +0200767 /* vsync interrupt use different bit for read and clear */
768 val |= MXR_INT_CLEAR_VSYNC;
769 val &= ~MXR_INT_STATUS_VSYNC;
770
Sean Paul45517892014-01-30 16:19:05 -0500771 /* interlace scan need to check shadow register */
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900772 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
Sean Paul45517892014-01-30 16:19:05 -0500773 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
774 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
775 if (base != shadow)
776 goto out;
777
778 base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
779 shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
780 if (base != shadow)
781 goto out;
782 }
783
Gustavo Padovaneafd5402015-07-16 12:23:32 -0300784 drm_crtc_handle_vblank(&ctx->crtc->base);
Sean Paul45517892014-01-30 16:19:05 -0500785 }
786
787out:
788 /* clear interrupts */
Sean Paul45517892014-01-30 16:19:05 -0500789 mixer_reg_write(res, MXR_INT_STATUS, val);
790
791 spin_unlock(&res->reg_slock);
792
793 return IRQ_HANDLED;
794}
795
796static int mixer_resources_init(struct mixer_context *mixer_ctx)
797{
798 struct device *dev = &mixer_ctx->pdev->dev;
799 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
800 struct resource *res;
801 int ret;
802
803 spin_lock_init(&mixer_res->reg_slock);
804
805 mixer_res->mixer = devm_clk_get(dev, "mixer");
806 if (IS_ERR(mixer_res->mixer)) {
807 dev_err(dev, "failed to get clock 'mixer'\n");
808 return -ENODEV;
809 }
810
Marek Szyprowski04427ec2015-02-02 14:20:28 +0100811 mixer_res->hdmi = devm_clk_get(dev, "hdmi");
812 if (IS_ERR(mixer_res->hdmi)) {
813 dev_err(dev, "failed to get clock 'hdmi'\n");
814 return PTR_ERR(mixer_res->hdmi);
815 }
816
Sean Paul45517892014-01-30 16:19:05 -0500817 mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
818 if (IS_ERR(mixer_res->sclk_hdmi)) {
819 dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
820 return -ENODEV;
821 }
822 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
823 if (res == NULL) {
824 dev_err(dev, "get memory resource failed.\n");
825 return -ENXIO;
826 }
827
828 mixer_res->mixer_regs = devm_ioremap(dev, res->start,
829 resource_size(res));
830 if (mixer_res->mixer_regs == NULL) {
831 dev_err(dev, "register mapping failed.\n");
832 return -ENXIO;
833 }
834
835 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
836 if (res == NULL) {
837 dev_err(dev, "get interrupt resource failed.\n");
838 return -ENXIO;
839 }
840
841 ret = devm_request_irq(dev, res->start, mixer_irq_handler,
842 0, "drm_mixer", mixer_ctx);
843 if (ret) {
844 dev_err(dev, "request interrupt failed.\n");
845 return ret;
846 }
847 mixer_res->irq = res->start;
848
849 return 0;
850}
851
852static int vp_resources_init(struct mixer_context *mixer_ctx)
853{
854 struct device *dev = &mixer_ctx->pdev->dev;
855 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
856 struct resource *res;
857
858 mixer_res->vp = devm_clk_get(dev, "vp");
859 if (IS_ERR(mixer_res->vp)) {
860 dev_err(dev, "failed to get clock 'vp'\n");
861 return -ENODEV;
862 }
Sean Paul45517892014-01-30 16:19:05 -0500863
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900864 if (test_bit(MXR_BIT_HAS_SCLK, &mixer_ctx->flags)) {
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200865 mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
866 if (IS_ERR(mixer_res->sclk_mixer)) {
867 dev_err(dev, "failed to get clock 'sclk_mixer'\n");
868 return -ENODEV;
869 }
870 mixer_res->mout_mixer = devm_clk_get(dev, "mout_mixer");
871 if (IS_ERR(mixer_res->mout_mixer)) {
872 dev_err(dev, "failed to get clock 'mout_mixer'\n");
873 return -ENODEV;
874 }
875
876 if (mixer_res->sclk_hdmi && mixer_res->mout_mixer)
877 clk_set_parent(mixer_res->mout_mixer,
878 mixer_res->sclk_hdmi);
879 }
Sean Paul45517892014-01-30 16:19:05 -0500880
881 res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
882 if (res == NULL) {
883 dev_err(dev, "get memory resource failed.\n");
884 return -ENXIO;
885 }
886
887 mixer_res->vp_regs = devm_ioremap(dev, res->start,
888 resource_size(res));
889 if (mixer_res->vp_regs == NULL) {
890 dev_err(dev, "register mapping failed.\n");
891 return -ENXIO;
892 }
893
894 return 0;
895}
896
Gustavo Padovan93bca242015-01-18 18:16:23 +0900897static int mixer_initialize(struct mixer_context *mixer_ctx,
Inki Daef37cd5e2014-05-09 14:25:20 +0900898 struct drm_device *drm_dev)
Sean Paul45517892014-01-30 16:19:05 -0500899{
900 int ret;
Inki Daef37cd5e2014-05-09 14:25:20 +0900901 struct exynos_drm_private *priv;
902 priv = drm_dev->dev_private;
Sean Paul45517892014-01-30 16:19:05 -0500903
Gustavo Padovaneb88e422014-11-26 16:43:27 -0200904 mixer_ctx->drm_dev = drm_dev;
Sean Paul45517892014-01-30 16:19:05 -0500905
906 /* acquire resources: regs, irqs, clocks */
907 ret = mixer_resources_init(mixer_ctx);
908 if (ret) {
909 DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
910 return ret;
911 }
912
Tobias Jakobiadeb6f42016-09-22 11:36:13 +0900913 if (test_bit(MXR_BIT_VP_ENABLED, &mixer_ctx->flags)) {
Sean Paul45517892014-01-30 16:19:05 -0500914 /* acquire vp resources: regs, irqs, clocks */
915 ret = vp_resources_init(mixer_ctx);
916 if (ret) {
917 DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
918 return ret;
919 }
920 }
921
Andrzej Hajdaf44d3d22017-03-15 15:41:04 +0100922 return drm_iommu_attach_device(drm_dev, mixer_ctx->dev);
Sean Paul45517892014-01-30 16:19:05 -0500923}
924
Gustavo Padovan93bca242015-01-18 18:16:23 +0900925static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
Inki Dae1055b392012-10-19 17:37:35 +0900926{
Joonyoung Shimbf566082015-07-02 21:49:38 +0900927 drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
Inki Dae1055b392012-10-19 17:37:35 +0900928}
929
Gustavo Padovan93bca242015-01-18 18:16:23 +0900930static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900931{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900932 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900933 struct mixer_resources *res = &mixer_ctx->mixer_res;
934
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200935 __set_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
936 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Sean Paulf041b252014-01-30 16:19:15 -0500937 return 0;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900938
939 /* enable vsync interrupt */
Andrzej Hajdafc0732482015-07-09 08:25:40 +0200940 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
941 mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900942
943 return 0;
944}
945
Gustavo Padovan93bca242015-01-18 18:16:23 +0900946static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900947{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900948 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900949 struct mixer_resources *res = &mixer_ctx->mixer_res;
950
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +0200951 __clear_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
952
953 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Andrzej Hajda947710c2015-07-09 08:25:41 +0200954 return;
Andrzej Hajda947710c2015-07-09 08:25:41 +0200955
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900956 /* disable vsync interrupt */
Andrzej Hajdafc0732482015-07-09 08:25:40 +0200957 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900958 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
959}
960
Marek Szyprowski3dbaab12016-01-05 13:52:52 +0100961static void mixer_atomic_begin(struct exynos_drm_crtc *crtc)
962{
963 struct mixer_context *mixer_ctx = crtc->ctx;
964
965 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
966 return;
967
968 mixer_vsync_set_update(mixer_ctx, false);
969}
970
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900971static void mixer_update_plane(struct exynos_drm_crtc *crtc,
972 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900973{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900974 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900975
Marek Szyprowski40bdfb02015-12-16 13:21:42 +0100976 DRM_DEBUG_KMS("win: %d\n", plane->index);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900977
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200978 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Shirish Sdda90122013-01-23 22:03:18 -0500979 return;
Shirish Sdda90122013-01-23 22:03:18 -0500980
Marek Szyprowski5e68fef2015-12-16 13:21:48 +0100981 if (plane->index == VP_DEFAULT_WIN)
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900982 vp_video_buffer(mixer_ctx, plane);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900983 else
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900984 mixer_graph_buffer(mixer_ctx, plane);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900985}
986
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900987static void mixer_disable_plane(struct exynos_drm_crtc *crtc,
988 struct exynos_drm_plane *plane)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900989{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900990 struct mixer_context *mixer_ctx = crtc->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900991 struct mixer_resources *res = &mixer_ctx->mixer_res;
992 unsigned long flags;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900993
Marek Szyprowski40bdfb02015-12-16 13:21:42 +0100994 DRM_DEBUG_KMS("win: %d\n", plane->index);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900995
Andrzej Hajdaa44652e2015-07-09 08:25:42 +0200996 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
Prathyush Kdb43fd12012-12-06 20:16:05 +0530997 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +0530998
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900999 spin_lock_irqsave(&res->reg_slock, flags);
Marek Szyprowskia2cb9112015-12-16 13:21:44 +01001000 mixer_cfg_layer(mixer_ctx, plane->index, 0, false);
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001001 spin_unlock_irqrestore(&res->reg_slock, flags);
1002}
1003
1004static void mixer_atomic_flush(struct exynos_drm_crtc *crtc)
1005{
1006 struct mixer_context *mixer_ctx = crtc->ctx;
1007
1008 if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
1009 return;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001010
1011 mixer_vsync_set_update(mixer_ctx, true);
Andrzej Hajdaa3922762017-03-14 09:27:56 +01001012 exynos_crtc_handle_event(crtc);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001013}
1014
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001015static void mixer_enable(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301016{
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001017 struct mixer_context *ctx = crtc->ctx;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301018 struct mixer_resources *res = &ctx->mixer_res;
1019
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001020 if (test_bit(MXR_BIT_POWERED, &ctx->flags))
Prathyush Kdb43fd12012-12-06 20:16:05 +05301021 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301022
Sean Paulaf65c802014-01-30 16:19:27 -05001023 pm_runtime_get_sync(ctx->dev);
1024
Andrzej Hajdaa121d172016-03-23 14:26:01 +01001025 exynos_drm_pipe_clk_enable(crtc, true);
1026
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001027 mixer_vsync_set_update(ctx, false);
1028
Rahul Sharmad74ed932014-06-23 11:02:24 +05301029 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
1030
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +02001031 if (test_bit(MXR_BIT_VSYNC, &ctx->flags)) {
Andrzej Hajdafc0732482015-07-09 08:25:40 +02001032 mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
Andrzej Hajda0df5e4a2015-07-09 08:25:43 +02001033 mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
1034 }
Prathyush Kdb43fd12012-12-06 20:16:05 +05301035 mixer_win_reset(ctx);
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001036
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001037 mixer_vsync_set_update(ctx, true);
1038
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001039 set_bit(MXR_BIT_POWERED, &ctx->flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301040}
1041
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001042static void mixer_disable(struct exynos_drm_crtc *crtc)
Prathyush Kdb43fd12012-12-06 20:16:05 +05301043{
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001044 struct mixer_context *ctx = crtc->ctx;
Joonyoung Shimc329f662015-06-12 20:34:28 +09001045 int i;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301046
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001047 if (!test_bit(MXR_BIT_POWERED, &ctx->flags))
Rahul Sharmab4bfa3c2014-06-23 11:02:21 +05301048 return;
Prathyush Kdb43fd12012-12-06 20:16:05 +05301049
Rahul Sharma381be022014-06-23 11:02:22 +05301050 mixer_stop(ctx);
Tobias Jakobic0734fb2015-05-06 14:10:21 +02001051 mixer_regs_dump(ctx);
Joonyoung Shimc329f662015-06-12 20:34:28 +09001052
1053 for (i = 0; i < MIXER_WIN_NR; i++)
Gustavo Padovan1e1d1392015-08-03 14:39:36 +09001054 mixer_disable_plane(crtc, &ctx->planes[i]);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301055
Andrzej Hajdaa121d172016-03-23 14:26:01 +01001056 exynos_drm_pipe_clk_enable(crtc, false);
1057
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001058 pm_runtime_put(ctx->dev);
1059
Andrzej Hajdaa44652e2015-07-09 08:25:42 +02001060 clear_bit(MXR_BIT_POWERED, &ctx->flags);
Prathyush Kdb43fd12012-12-06 20:16:05 +05301061}
1062
Sean Paulf041b252014-01-30 16:19:15 -05001063/* Only valid for Mixer version 16.0.33.0 */
Andrzej Hajda3ae24362015-10-26 13:03:40 +01001064static int mixer_atomic_check(struct exynos_drm_crtc *crtc,
1065 struct drm_crtc_state *state)
Sean Paulf041b252014-01-30 16:19:15 -05001066{
Andrzej Hajda3ae24362015-10-26 13:03:40 +01001067 struct drm_display_mode *mode = &state->adjusted_mode;
Sean Paulf041b252014-01-30 16:19:15 -05001068 u32 w, h;
1069
1070 w = mode->hdisplay;
1071 h = mode->vdisplay;
1072
1073 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
1074 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1075 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1076
1077 if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
1078 (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
1079 (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
1080 return 0;
1081
1082 return -EINVAL;
1083}
1084
Krzysztof Kozlowskif3aaf762015-05-07 09:04:45 +09001085static const struct exynos_drm_crtc_ops mixer_crtc_ops = {
Gustavo Padovan3cecda02015-06-01 12:04:55 -03001086 .enable = mixer_enable,
1087 .disable = mixer_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001088 .enable_vblank = mixer_enable_vblank,
1089 .disable_vblank = mixer_disable_vblank,
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001090 .atomic_begin = mixer_atomic_begin,
Gustavo Padovan9cc76102015-08-03 14:38:05 +09001091 .update_plane = mixer_update_plane,
1092 .disable_plane = mixer_disable_plane,
Marek Szyprowski3dbaab12016-01-05 13:52:52 +01001093 .atomic_flush = mixer_atomic_flush,
Andrzej Hajda3ae24362015-10-26 13:03:40 +01001094 .atomic_check = mixer_atomic_check,
Sean Paulf041b252014-01-30 16:19:15 -05001095};
Rahul Sharma0ea68222013-01-15 08:11:06 -05001096
Rahul Sharmadef5e092013-06-19 18:21:08 +05301097static struct mixer_drv_data exynos5420_mxr_drv_data = {
1098 .version = MXR_VER_128_0_0_184,
1099 .is_vp_enabled = 0,
1100};
1101
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301102static struct mixer_drv_data exynos5250_mxr_drv_data = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301103 .version = MXR_VER_16_0_33_0,
1104 .is_vp_enabled = 0,
1105};
1106
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001107static struct mixer_drv_data exynos4212_mxr_drv_data = {
1108 .version = MXR_VER_0_0_0_16,
1109 .is_vp_enabled = 1,
1110};
1111
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301112static struct mixer_drv_data exynos4210_mxr_drv_data = {
Rahul Sharma1e123442012-10-04 20:48:51 +05301113 .version = MXR_VER_0_0_0_16,
Rahul Sharma1b8e5742012-10-04 20:48:52 +05301114 .is_vp_enabled = 1,
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001115 .has_sclk = 1,
Rahul Sharma1e123442012-10-04 20:48:51 +05301116};
1117
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301118static struct of_device_id mixer_match_types[] = {
1119 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001120 .compatible = "samsung,exynos4210-mixer",
1121 .data = &exynos4210_mxr_drv_data,
1122 }, {
1123 .compatible = "samsung,exynos4212-mixer",
1124 .data = &exynos4212_mxr_drv_data,
1125 }, {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301126 .compatible = "samsung,exynos5-mixer",
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301127 .data = &exynos5250_mxr_drv_data,
1128 }, {
1129 .compatible = "samsung,exynos5250-mixer",
1130 .data = &exynos5250_mxr_drv_data,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301131 }, {
Rahul Sharmadef5e092013-06-19 18:21:08 +05301132 .compatible = "samsung,exynos5420-mixer",
1133 .data = &exynos5420_mxr_drv_data,
1134 }, {
Rahul Sharma1e123442012-10-04 20:48:51 +05301135 /* end node */
1136 }
1137};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001138MODULE_DEVICE_TABLE(of, mixer_match_types);
Rahul Sharma1e123442012-10-04 20:48:51 +05301139
Inki Daef37cd5e2014-05-09 14:25:20 +09001140static int mixer_bind(struct device *dev, struct device *manager, void *data)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001141{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001142 struct mixer_context *ctx = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09001143 struct drm_device *drm_dev = data;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001144 struct exynos_drm_plane *exynos_plane;
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +01001145 unsigned int i;
Gustavo Padovan6e2a3b62015-04-03 21:05:52 +09001146 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001147
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001148 ret = mixer_initialize(ctx, drm_dev);
1149 if (ret)
1150 return ret;
1151
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +01001152 for (i = 0; i < MIXER_WIN_NR; i++) {
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001153 if (i == VP_DEFAULT_WIN && !test_bit(MXR_BIT_VP_ENABLED,
1154 &ctx->flags))
Marek Szyprowskiab144202015-11-30 14:53:24 +01001155 continue;
1156
Marek Szyprowski40bdfb02015-12-16 13:21:42 +01001157 ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
Andrzej Hajda2c826072017-03-15 15:41:05 +01001158 &plane_configs[i]);
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001159 if (ret)
1160 return ret;
1161 }
1162
Gustavo Padovan5d3d0992015-10-12 22:07:48 +09001163 exynos_plane = &ctx->planes[DEFAULT_WIN];
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +09001164 ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
Andrzej Hajdad6449512017-05-29 10:05:25 +09001165 EXYNOS_DISPLAY_TYPE_HDMI, &mixer_crtc_ops, ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001166 if (IS_ERR(ctx->crtc)) {
Alban Browaeyse2dc3f72015-01-29 22:18:40 +01001167 mixer_ctx_remove(ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +09001168 ret = PTR_ERR(ctx->crtc);
1169 goto free_ctx;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001170 }
1171
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001172 return 0;
Gustavo Padovan93bca242015-01-18 18:16:23 +09001173
1174free_ctx:
1175 devm_kfree(dev, ctx);
1176 return ret;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001177}
1178
1179static void mixer_unbind(struct device *dev, struct device *master, void *data)
1180{
1181 struct mixer_context *ctx = dev_get_drvdata(dev);
1182
Gustavo Padovan93bca242015-01-18 18:16:23 +09001183 mixer_ctx_remove(ctx);
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001184}
1185
1186static const struct component_ops mixer_component_ops = {
1187 .bind = mixer_bind,
1188 .unbind = mixer_unbind,
1189};
1190
1191static int mixer_probe(struct platform_device *pdev)
1192{
1193 struct device *dev = &pdev->dev;
Marek Szyprowski48f61552016-04-01 15:17:46 +02001194 const struct mixer_drv_data *drv;
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001195 struct mixer_context *ctx;
1196 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001197
Sean Paulf041b252014-01-30 16:19:15 -05001198 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1199 if (!ctx) {
1200 DRM_ERROR("failed to alloc mixer context.\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001201 return -ENOMEM;
Sean Paulf041b252014-01-30 16:19:15 -05001202 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001203
Marek Szyprowski48f61552016-04-01 15:17:46 +02001204 drv = of_device_get_match_data(dev);
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301205
Sean Paul45517892014-01-30 16:19:05 -05001206 ctx->pdev = pdev;
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001207 ctx->dev = dev;
Rahul Sharma1e123442012-10-04 20:48:51 +05301208 ctx->mxr_ver = drv->version;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001209
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001210 if (drv->is_vp_enabled)
1211 __set_bit(MXR_BIT_VP_ENABLED, &ctx->flags);
1212 if (drv->has_sclk)
1213 __set_bit(MXR_BIT_HAS_SCLK, &ctx->flags);
1214
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001215 platform_set_drvdata(pdev, ctx);
Inki Daedf5225b2014-05-29 18:28:02 +09001216
Inki Daedf5225b2014-05-29 18:28:02 +09001217 ret = component_add(&pdev->dev, &mixer_component_ops);
Andrzej Hajda86650402015-06-11 23:23:37 +09001218 if (!ret)
1219 pm_runtime_enable(dev);
Inki Daedf5225b2014-05-29 18:28:02 +09001220
1221 return ret;
Inki Daef37cd5e2014-05-09 14:25:20 +09001222}
1223
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001224static int mixer_remove(struct platform_device *pdev)
1225{
Andrzej Hajda8103ef12014-11-24 14:12:46 +09001226 pm_runtime_disable(&pdev->dev);
1227
Inki Daedf5225b2014-05-29 18:28:02 +09001228 component_del(&pdev->dev, &mixer_component_ops);
Inki Daedf5225b2014-05-29 18:28:02 +09001229
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001230 return 0;
1231}
1232
Arnd Bergmanne0fea7e2015-11-17 16:08:36 +01001233static int __maybe_unused exynos_mixer_suspend(struct device *dev)
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001234{
1235 struct mixer_context *ctx = dev_get_drvdata(dev);
1236 struct mixer_resources *res = &ctx->mixer_res;
1237
1238 clk_disable_unprepare(res->hdmi);
1239 clk_disable_unprepare(res->mixer);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001240 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001241 clk_disable_unprepare(res->vp);
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001242 if (test_bit(MXR_BIT_HAS_SCLK, &ctx->flags))
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001243 clk_disable_unprepare(res->sclk_mixer);
1244 }
1245
1246 return 0;
1247}
1248
Arnd Bergmanne0fea7e2015-11-17 16:08:36 +01001249static int __maybe_unused exynos_mixer_resume(struct device *dev)
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001250{
1251 struct mixer_context *ctx = dev_get_drvdata(dev);
1252 struct mixer_resources *res = &ctx->mixer_res;
1253 int ret;
1254
1255 ret = clk_prepare_enable(res->mixer);
1256 if (ret < 0) {
1257 DRM_ERROR("Failed to prepare_enable the mixer clk [%d]\n", ret);
1258 return ret;
1259 }
1260 ret = clk_prepare_enable(res->hdmi);
1261 if (ret < 0) {
1262 DRM_ERROR("Failed to prepare_enable the hdmi clk [%d]\n", ret);
1263 return ret;
1264 }
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001265 if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001266 ret = clk_prepare_enable(res->vp);
1267 if (ret < 0) {
1268 DRM_ERROR("Failed to prepare_enable the vp clk [%d]\n",
1269 ret);
1270 return ret;
1271 }
Tobias Jakobiadeb6f42016-09-22 11:36:13 +09001272 if (test_bit(MXR_BIT_HAS_SCLK, &ctx->flags)) {
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001273 ret = clk_prepare_enable(res->sclk_mixer);
1274 if (ret < 0) {
1275 DRM_ERROR("Failed to prepare_enable the " \
1276 "sclk_mixer clk [%d]\n",
1277 ret);
1278 return ret;
1279 }
1280 }
1281 }
1282
1283 return 0;
1284}
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001285
1286static const struct dev_pm_ops exynos_mixer_pm_ops = {
1287 SET_RUNTIME_PM_OPS(exynos_mixer_suspend, exynos_mixer_resume, NULL)
1288};
1289
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001290struct platform_driver mixer_driver = {
1291 .driver = {
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301292 .name = "exynos-mixer",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001293 .owner = THIS_MODULE,
Gustavo Padovanccf034a2015-09-04 17:15:46 -03001294 .pm = &exynos_mixer_pm_ops,
Rahul Sharmaaaf8b492012-10-04 20:48:53 +05301295 .of_match_table = mixer_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001296 },
1297 .probe = mixer_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001298 .remove = mixer_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001299};