summaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorAjay Kumar <ajaykumar.rs@samsung.com>2015-02-05 10:54:04 -0500
committerInki Dae <inki.dae@samsung.com>2015-02-11 06:27:08 -0500
commit96976c3d9aff4e1387c30f6356ac01fa6f72ef46 (patch)
treef0af6014cf2a72153307e611c94610d35875805e /drivers/gpu
parent936ce5cce66ce6f9b5138a1ac0fbf0c2d459a960 (diff)
drm/exynos: Add DECON driver
This patch is based on exynos-drm-next branch of Inki Dae's tree at: git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos.git DECON(Display and Enhancement Controller) is the new IP in exynos7 SOC for generating video signals using pixel data. DECON driver can be used to drive 2 different interfaces on Exynos7: DECON-INT(video controller) and DECON-EXT(Mixer for HDMI) The existing FIMD driver code was used as a template to create DECON driver. Only DECON-INT is supported as of now, and DECON-EXT support will be added later. The current version of the driver supports video mode displays. Changelog v2: - Change config name, DRM_EXYNOS_DECON to DRM_EXYNOS7_DECON. Signed-off-by: Akshu Agrawal <akshua@gmail.com> Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com> Signed-off-by: Inki Dae <inki.dae@samsung.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/exynos/Kconfig13
-rw-r--r--drivers/gpu/drm/exynos/Makefile1
-rw-r--r--drivers/gpu/drm/exynos/exynos7_drm_decon.c990
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h1
5 files changed, 1006 insertions, 3 deletions
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 627aaa04776c..a5e74612100e 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -24,9 +24,16 @@ config DRM_EXYNOS_FIMD
24 help 24 help
25 Choose this option if you want to use Exynos FIMD for DRM. 25 Choose this option if you want to use Exynos FIMD for DRM.
26 26
27config DRM_EXYNOS7_DECON
28 bool "Exynos DRM DECON"
29 depends on DRM_EXYNOS
30 select FB_MODE_HELPERS
31 help
32 Choose this option if you want to use Exynos DECON for DRM.
33
27config DRM_EXYNOS_DPI 34config DRM_EXYNOS_DPI
28 bool "EXYNOS DRM parallel output support" 35 bool "EXYNOS DRM parallel output support"
29 depends on DRM_EXYNOS_FIMD 36 depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON)
30 select DRM_PANEL 37 select DRM_PANEL
31 default n 38 default n
32 help 39 help
@@ -34,7 +41,7 @@ config DRM_EXYNOS_DPI
34 41
35config DRM_EXYNOS_DSI 42config DRM_EXYNOS_DSI
36 bool "EXYNOS DRM MIPI-DSI driver support" 43 bool "EXYNOS DRM MIPI-DSI driver support"
37 depends on DRM_EXYNOS_FIMD 44 depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON)
38 select DRM_MIPI_DSI 45 select DRM_MIPI_DSI
39 select DRM_PANEL 46 select DRM_PANEL
40 default n 47 default n
@@ -43,7 +50,7 @@ config DRM_EXYNOS_DSI
43 50
44config DRM_EXYNOS_DP 51config DRM_EXYNOS_DP
45 bool "EXYNOS DRM DP driver support" 52 bool "EXYNOS DRM DP driver support"
46 depends on DRM_EXYNOS_FIMD && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS) 53 depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7DECON) && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS)
47 default DRM_EXYNOS 54 default DRM_EXYNOS
48 select DRM_PANEL 55 select DRM_PANEL
49 help 56 help
diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index 0856891f9bbf..cc90679cfc06 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -10,6 +10,7 @@ exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o \
10 10
11exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o 11exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o
12exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o 12exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
13exynosdrm-$(CONFIG_DRM_EXYNOS7_DECON) += exynos7_drm_decon.o
13exynosdrm-$(CONFIG_DRM_EXYNOS_DPI) += exynos_drm_dpi.o 14exynosdrm-$(CONFIG_DRM_EXYNOS_DPI) += exynos_drm_dpi.o
14exynosdrm-$(CONFIG_DRM_EXYNOS_DSI) += exynos_drm_dsi.o 15exynosdrm-$(CONFIG_DRM_EXYNOS_DSI) += exynos_drm_dsi.o
15exynosdrm-$(CONFIG_DRM_EXYNOS_DP) += exynos_dp_core.o exynos_dp_reg.o 16exynosdrm-$(CONFIG_DRM_EXYNOS_DP) += exynos_dp_core.o exynos_dp_reg.o
diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c
new file mode 100644
index 000000000000..63f02e2380ae
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c
@@ -0,0 +1,990 @@
1/* drivers/gpu/drm/exynos/exynos7_drm_decon.c
2 *
3 * Copyright (C) 2014 Samsung Electronics Co.Ltd
4 * Authors:
5 * Akshu Agarwal <akshua@gmail.com>
6 * Ajay Kumar <ajaykumar.rs@samsung.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 */
14#include <drm/drmP.h>
15#include <drm/exynos_drm.h>
16
17#include <linux/clk.h>
18#include <linux/component.h>
19#include <linux/kernel.h>
20#include <linux/of.h>
21#include <linux/of_address.h>
22#include <linux/of_device.h>
23#include <linux/platform_device.h>
24#include <linux/pm_runtime.h>
25
26#include <video/of_display_timing.h>
27#include <video/of_videomode.h>
28#include <video/exynos7_decon.h>
29
30#include "exynos_drm_crtc.h"
31#include "exynos_drm_drv.h"
32#include "exynos_drm_fbdev.h"
33#include "exynos_drm_iommu.h"
34
35/*
36 * DECON stands for Display and Enhancement controller.
37 */
38
39#define DECON_DEFAULT_FRAMERATE 60
40#define MIN_FB_WIDTH_FOR_16WORD_BURST 128
41
42#define WINDOWS_NR 2
43
44struct decon_win_data {
45 unsigned int ovl_x;
46 unsigned int ovl_y;
47 unsigned int offset_x;
48 unsigned int offset_y;
49 unsigned int ovl_width;
50 unsigned int ovl_height;
51 unsigned int fb_width;
52 unsigned int fb_height;
53 unsigned int bpp;
54 unsigned int pixel_format;
55 dma_addr_t dma_addr;
56 bool enabled;
57 bool resume;
58};
59
60struct decon_context {
61 struct device *dev;
62 struct drm_device *drm_dev;
63 struct exynos_drm_crtc *crtc;
64 struct clk *pclk;
65 struct clk *aclk;
66 struct clk *eclk;
67 struct clk *vclk;
68 void __iomem *regs;
69 struct decon_win_data win_data[WINDOWS_NR];
70 unsigned int default_win;
71 unsigned long irq_flags;
72 bool i80_if;
73 bool suspended;
74 int pipe;
75 wait_queue_head_t wait_vsync_queue;
76 atomic_t wait_vsync_event;
77
78 struct exynos_drm_panel_info panel;
79 struct exynos_drm_display *display;
80};
81
82static const struct of_device_id decon_driver_dt_match[] = {
83 {.compatible = "samsung,exynos7-decon"},
84 {},
85};
86MODULE_DEVICE_TABLE(of, decon_driver_dt_match);
87
88static void decon_wait_for_vblank(struct exynos_drm_crtc *crtc)
89{
90 struct decon_context *ctx = crtc->ctx;
91
92 if (ctx->suspended)
93 return;
94
95 atomic_set(&ctx->wait_vsync_event, 1);
96
97 /*
98 * wait for DECON to signal VSYNC interrupt or return after
99 * timeout which is set to 50ms (refresh rate of 20).
100 */
101 if (!wait_event_timeout(ctx->wait_vsync_queue,
102 !atomic_read(&ctx->wait_vsync_event),
103 HZ/20))
104 DRM_DEBUG_KMS("vblank wait timed out.\n");
105}
106
107static void decon_clear_channel(struct decon_context *ctx)
108{
109 int win, ch_enabled = 0;
110
111 DRM_DEBUG_KMS("%s\n", __FILE__);
112
113 /* Check if any channel is enabled. */
114 for (win = 0; win < WINDOWS_NR; win++) {
115 u32 val = readl(ctx->regs + WINCON(win));
116
117 if (val & WINCONx_ENWIN) {
118 val &= ~WINCONx_ENWIN;
119 writel(val, ctx->regs + WINCON(win));
120 ch_enabled = 1;
121 }
122 }
123
124 /* Wait for vsync, as disable channel takes effect at next vsync */
125 if (ch_enabled) {
126 unsigned int state = ctx->suspended;
127
128 ctx->suspended = 0;
129 decon_wait_for_vblank(ctx->crtc);
130 ctx->suspended = state;
131 }
132}
133
134static int decon_ctx_initialize(struct decon_context *ctx,
135 struct drm_device *drm_dev)
136{
137 struct exynos_drm_private *priv = drm_dev->dev_private;
138
139 ctx->drm_dev = drm_dev;
140 ctx->pipe = priv->pipe++;
141
142 /* attach this sub driver to iommu mapping if supported. */
143 if (is_drm_iommu_supported(ctx->drm_dev)) {
144 int ret;
145
146 /*
147 * If any channel is already active, iommu will throw
148 * a PAGE FAULT when enabled. So clear any channel if enabled.
149 */
150 decon_clear_channel(ctx);
151 ret = drm_iommu_attach_device(ctx->drm_dev, ctx->dev);
152 if (ret) {
153 DRM_ERROR("drm_iommu_attach failed.\n");
154 return ret;
155 }
156 }
157
158 return 0;
159}
160
161static void decon_ctx_remove(struct decon_context *ctx)
162{
163 /* detach this sub driver from iommu mapping if supported. */
164 if (is_drm_iommu_supported(ctx->drm_dev))
165 drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
166}
167
168static u32 decon_calc_clkdiv(struct decon_context *ctx,
169 const struct drm_display_mode *mode)
170{
171 unsigned long ideal_clk = mode->htotal * mode->vtotal * mode->vrefresh;
172 u32 clkdiv;
173
174 /* Find the clock divider value that gets us closest to ideal_clk */
175 clkdiv = DIV_ROUND_UP(clk_get_rate(ctx->vclk), ideal_clk);
176
177 return (clkdiv < 0x100) ? clkdiv : 0xff;
178}
179
180static bool decon_mode_fixup(struct exynos_drm_crtc *crtc,
181 const struct drm_display_mode *mode,
182 struct drm_display_mode *adjusted_mode)
183{
184 if (adjusted_mode->vrefresh == 0)
185 adjusted_mode->vrefresh = DECON_DEFAULT_FRAMERATE;
186
187 return true;
188}
189
190static void decon_commit(struct exynos_drm_crtc *crtc)
191{
192 struct decon_context *ctx = crtc->ctx;
193 struct drm_display_mode *mode = &crtc->base.mode;
194 u32 val, clkdiv;
195
196 if (ctx->suspended)
197 return;
198
199 /* nothing to do if we haven't set the mode yet */
200 if (mode->htotal == 0 || mode->vtotal == 0)
201 return;
202
203 if (!ctx->i80_if) {
204 int vsync_len, vbpd, vfpd, hsync_len, hbpd, hfpd;
205 /* setup vertical timing values. */
206 vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
207 vbpd = mode->crtc_vtotal - mode->crtc_vsync_end;
208 vfpd = mode->crtc_vsync_start - mode->crtc_vdisplay;
209
210 val = VIDTCON0_VBPD(vbpd - 1) | VIDTCON0_VFPD(vfpd - 1);
211 writel(val, ctx->regs + VIDTCON0);
212
213 val = VIDTCON1_VSPW(vsync_len - 1);
214 writel(val, ctx->regs + VIDTCON1);
215
216 /* setup horizontal timing values. */
217 hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
218 hbpd = mode->crtc_htotal - mode->crtc_hsync_end;
219 hfpd = mode->crtc_hsync_start - mode->crtc_hdisplay;
220
221 /* setup horizontal timing values. */
222 val = VIDTCON2_HBPD(hbpd - 1) | VIDTCON2_HFPD(hfpd - 1);
223 writel(val, ctx->regs + VIDTCON2);
224
225 val = VIDTCON3_HSPW(hsync_len - 1);
226 writel(val, ctx->regs + VIDTCON3);
227 }
228
229 /* setup horizontal and vertical display size. */
230 val = VIDTCON4_LINEVAL(mode->vdisplay - 1) |
231 VIDTCON4_HOZVAL(mode->hdisplay - 1);
232 writel(val, ctx->regs + VIDTCON4);
233
234 writel(mode->vdisplay - 1, ctx->regs + LINECNT_OP_THRESHOLD);
235
236 /*
237 * fields of register with prefix '_F' would be updated
238 * at vsync(same as dma start)
239 */
240 val = VIDCON0_ENVID | VIDCON0_ENVID_F;
241 writel(val, ctx->regs + VIDCON0);
242
243 clkdiv = decon_calc_clkdiv(ctx, mode);
244 if (clkdiv > 1) {
245 val = VCLKCON1_CLKVAL_NUM_VCLK(clkdiv - 1);
246 writel(val, ctx->regs + VCLKCON1);
247 writel(val, ctx->regs + VCLKCON2);
248 }
249
250 val = readl(ctx->regs + DECON_UPDATE);
251 val |= DECON_UPDATE_STANDALONE_F;
252 writel(val, ctx->regs + DECON_UPDATE);
253}
254
255static int decon_enable_vblank(struct exynos_drm_crtc *crtc)
256{
257 struct decon_context *ctx = crtc->ctx;
258 u32 val;
259
260 if (ctx->suspended)
261 return -EPERM;
262
263 if (!test_and_set_bit(0, &ctx->irq_flags)) {
264 val = readl(ctx->regs + VIDINTCON0);
265
266 val |= VIDINTCON0_INT_ENABLE;
267
268 if (!ctx->i80_if) {
269 val |= VIDINTCON0_INT_FRAME;
270 val &= ~VIDINTCON0_FRAMESEL0_MASK;
271 val |= VIDINTCON0_FRAMESEL0_VSYNC;
272 }
273
274 writel(val, ctx->regs + VIDINTCON0);
275 }
276
277 return 0;
278}
279
280static void decon_disable_vblank(struct exynos_drm_crtc *crtc)
281{
282 struct decon_context *ctx = crtc->ctx;
283 u32 val;
284
285 if (ctx->suspended)
286 return;
287
288 if (test_and_clear_bit(0, &ctx->irq_flags)) {
289 val = readl(ctx->regs + VIDINTCON0);
290
291 val &= ~VIDINTCON0_INT_ENABLE;
292 if (!ctx->i80_if)
293 val &= ~VIDINTCON0_INT_FRAME;
294
295 writel(val, ctx->regs + VIDINTCON0);
296 }
297}
298
299static void decon_win_mode_set(struct exynos_drm_crtc *crtc,
300 struct exynos_drm_plane *plane)
301{
302 struct decon_context *ctx = crtc->ctx;
303 struct decon_win_data *win_data;
304 int win, padding;
305
306 if (!plane) {
307 DRM_ERROR("plane is NULL\n");
308 return;
309 }
310
311 win = plane->zpos;
312 if (win == DEFAULT_ZPOS)
313 win = ctx->default_win;
314
315 if (win < 0 || win >= WINDOWS_NR)
316 return;
317
318
319 win_data = &ctx->win_data[win];
320
321 padding = (plane->pitch / (plane->bpp >> 3)) - plane->fb_width;
322 win_data->offset_x = plane->fb_x;
323 win_data->offset_y = plane->fb_y;
324 win_data->fb_width = plane->fb_width + padding;
325 win_data->fb_height = plane->fb_height;
326 win_data->ovl_x = plane->crtc_x;
327 win_data->ovl_y = plane->crtc_y;
328 win_data->ovl_width = plane->crtc_width;
329 win_data->ovl_height = plane->crtc_height;
330 win_data->dma_addr = plane->dma_addr[0];
331 win_data->bpp = plane->bpp;
332 win_data->pixel_format = plane->pixel_format;
333
334 DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
335 win_data->offset_x, win_data->offset_y);
336 DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
337 win_data->ovl_width, win_data->ovl_height);
338 DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
339 DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
340 plane->fb_width, plane->crtc_width);
341}
342
343static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win)
344{
345 struct decon_win_data *win_data = &ctx->win_data[win];
346 unsigned long val;
347
348 val = readl(ctx->regs + WINCON(win));
349 val &= ~WINCONx_BPPMODE_MASK;
350
351 switch (win_data->pixel_format) {
352 case DRM_FORMAT_RGB565:
353 val |= WINCONx_BPPMODE_16BPP_565;
354 val |= WINCONx_BURSTLEN_16WORD;
355 break;
356 case DRM_FORMAT_XRGB8888:
357 val |= WINCONx_BPPMODE_24BPP_xRGB;
358 val |= WINCONx_BURSTLEN_16WORD;
359 break;
360 case DRM_FORMAT_XBGR8888:
361 val |= WINCONx_BPPMODE_24BPP_xBGR;
362 val |= WINCONx_BURSTLEN_16WORD;
363 break;
364 case DRM_FORMAT_RGBX8888:
365 val |= WINCONx_BPPMODE_24BPP_RGBx;
366 val |= WINCONx_BURSTLEN_16WORD;
367 break;
368 case DRM_FORMAT_BGRX8888:
369 val |= WINCONx_BPPMODE_24BPP_BGRx;
370 val |= WINCONx_BURSTLEN_16WORD;
371 break;
372 case DRM_FORMAT_ARGB8888:
373 val |= WINCONx_BPPMODE_32BPP_ARGB | WINCONx_BLD_PIX |
374 WINCONx_ALPHA_SEL;
375 val |= WINCONx_BURSTLEN_16WORD;
376 break;
377 case DRM_FORMAT_ABGR8888:
378 val |= WINCONx_BPPMODE_32BPP_ABGR | WINCONx_BLD_PIX |
379 WINCONx_ALPHA_SEL;
380 val |= WINCONx_BURSTLEN_16WORD;
381 break;
382 case DRM_FORMAT_RGBA8888:
383 val |= WINCONx_BPPMODE_32BPP_RGBA | WINCONx_BLD_PIX |
384 WINCONx_ALPHA_SEL;
385 val |= WINCONx_BURSTLEN_16WORD;
386 break;
387 case DRM_FORMAT_BGRA8888:
388 val |= WINCONx_BPPMODE_32BPP_BGRA | WINCONx_BLD_PIX |
389 WINCONx_ALPHA_SEL;
390 val |= WINCONx_BURSTLEN_16WORD;
391 break;
392 default:
393 DRM_DEBUG_KMS("invalid pixel size so using unpacked 24bpp.\n");
394
395 val |= WINCONx_BPPMODE_24BPP_xRGB;
396 val |= WINCONx_BURSTLEN_16WORD;
397 break;
398 }
399
400 DRM_DEBUG_KMS("bpp = %d\n", win_data->bpp);
401
402 /*
403 * In case of exynos, setting dma-burst to 16Word causes permanent
404 * tearing for very small buffers, e.g. cursor buffer. Burst Mode
405 * switching which is based on plane size is not recommended as
406 * plane size varies a lot towards the end of the screen and rapid
407 * movement causes unstable DMA which results into iommu crash/tear.
408 */
409
410 if (win_data->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) {
411 val &= ~WINCONx_BURSTLEN_MASK;
412 val |= WINCONx_BURSTLEN_8WORD;
413 }
414
415 writel(val, ctx->regs + WINCON(win));
416}
417
418static void decon_win_set_colkey(struct decon_context *ctx, unsigned int win)
419{
420 unsigned int keycon0 = 0, keycon1 = 0;
421
422 keycon0 = ~(WxKEYCON0_KEYBL_EN | WxKEYCON0_KEYEN_F |
423 WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0);
424
425 keycon1 = WxKEYCON1_COLVAL(0xffffffff);
426
427 writel(keycon0, ctx->regs + WKEYCON0_BASE(win));
428 writel(keycon1, ctx->regs + WKEYCON1_BASE(win));
429}
430
431/**
432 * shadow_protect_win() - disable updating values from shadow registers at vsync
433 *
434 * @win: window to protect registers for
435 * @protect: 1 to protect (disable updates)
436 */
437static void decon_shadow_protect_win(struct decon_context *ctx,
438 int win, bool protect)
439{
440 u32 bits, val;
441
442 bits = SHADOWCON_WINx_PROTECT(win);
443
444 val = readl(ctx->regs + SHADOWCON);
445 if (protect)
446 val |= bits;
447 else
448 val &= ~bits;
449 writel(val, ctx->regs + SHADOWCON);
450}
451
452static void decon_win_commit(struct exynos_drm_crtc *crtc, int zpos)
453{
454 struct decon_context *ctx = crtc->ctx;
455 struct drm_display_mode *mode = &crtc->base.mode;
456 struct decon_win_data *win_data;
457 int win = zpos;
458 unsigned long val, alpha;
459 unsigned int last_x;
460 unsigned int last_y;
461
462 if (ctx->suspended)
463 return;
464
465 if (win == DEFAULT_ZPOS)
466 win = ctx->default_win;
467
468 if (win < 0 || win >= WINDOWS_NR)
469 return;
470
471 win_data = &ctx->win_data[win];
472
473 /* If suspended, enable this on resume */
474 if (ctx->suspended) {
475 win_data->resume = true;
476 return;
477 }
478
479 /*
480 * SHADOWCON/PRTCON register is used for enabling timing.
481 *
482 * for example, once only width value of a register is set,
483 * if the dma is started then decon hardware could malfunction so
484 * with protect window setting, the register fields with prefix '_F'
485 * wouldn't be updated at vsync also but updated once unprotect window
486 * is set.
487 */
488
489 /* protect windows */
490 decon_shadow_protect_win(ctx, win, true);
491
492 /* buffer start address */
493 val = (unsigned long)win_data->dma_addr;
494 writel(val, ctx->regs + VIDW_BUF_START(win));
495
496 /* buffer size */
497 writel(win_data->fb_width, ctx->regs + VIDW_WHOLE_X(win));
498 writel(win_data->fb_height, ctx->regs + VIDW_WHOLE_Y(win));
499
500 /* offset from the start of the buffer to read */
501 writel(win_data->offset_x, ctx->regs + VIDW_OFFSET_X(win));
502 writel(win_data->offset_y, ctx->regs + VIDW_OFFSET_Y(win));
503
504 DRM_DEBUG_KMS("start addr = 0x%lx\n",
505 (unsigned long)win_data->dma_addr);
506 DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
507 win_data->ovl_width, win_data->ovl_height);
508
509 /*
510 * OSD position.
511 * In case the window layout goes of LCD layout, DECON fails.
512 */
513 if ((win_data->ovl_x + win_data->ovl_width) > mode->hdisplay)
514 win_data->ovl_x = mode->hdisplay - win_data->ovl_width;
515 if ((win_data->ovl_y + win_data->ovl_height) > mode->vdisplay)
516 win_data->ovl_y = mode->vdisplay - win_data->ovl_height;
517
518 val = VIDOSDxA_TOPLEFT_X(win_data->ovl_x) |
519 VIDOSDxA_TOPLEFT_Y(win_data->ovl_y);
520 writel(val, ctx->regs + VIDOSD_A(win));
521
522 last_x = win_data->ovl_x + win_data->ovl_width;
523 if (last_x)
524 last_x--;
525 last_y = win_data->ovl_y + win_data->ovl_height;
526 if (last_y)
527 last_y--;
528
529 val = VIDOSDxB_BOTRIGHT_X(last_x) | VIDOSDxB_BOTRIGHT_Y(last_y);
530
531 writel(val, ctx->regs + VIDOSD_B(win));
532
533 DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %d\n",
534 win_data->ovl_x, win_data->ovl_y, last_x, last_y);
535
536 /* OSD alpha */
537 alpha = VIDOSDxC_ALPHA0_R_F(0x0) |
538 VIDOSDxC_ALPHA0_G_F(0x0) |
539 VIDOSDxC_ALPHA0_B_F(0x0);
540
541 writel(alpha, ctx->regs + VIDOSD_C(win));
542
543 alpha = VIDOSDxD_ALPHA1_R_F(0xff) |
544 VIDOSDxD_ALPHA1_G_F(0xff) |
545 VIDOSDxD_ALPHA1_B_F(0xff);
546
547 writel(alpha, ctx->regs + VIDOSD_D(win));
548
549 decon_win_set_pixfmt(ctx, win);
550
551 /* hardware window 0 doesn't support color key. */
552 if (win != 0)
553 decon_win_set_colkey(ctx, win);
554
555 /* wincon */
556 val = readl(ctx->regs + WINCON(win));
557 val |= WINCONx_TRIPLE_BUF_MODE;
558 val |= WINCONx_ENWIN;
559 writel(val, ctx->regs + WINCON(win));
560
561 /* Enable DMA channel and unprotect windows */
562 decon_shadow_protect_win(ctx, win, false);
563
564 val = readl(ctx->regs + DECON_UPDATE);
565 val |= DECON_UPDATE_STANDALONE_F;
566 writel(val, ctx->regs + DECON_UPDATE);
567
568 win_data->enabled = true;
569}
570
571static void decon_win_disable(struct exynos_drm_crtc *crtc, int zpos)
572{
573 struct decon_context *ctx = crtc->ctx;
574 struct decon_win_data *win_data;
575 int win = zpos;
576 u32 val;
577
578 if (win == DEFAULT_ZPOS)
579 win = ctx->default_win;
580
581 if (win < 0 || win >= WINDOWS_NR)
582 return;
583
584 win_data = &ctx->win_data[win];
585
586 if (ctx->suspended) {
587 /* do not resume this window*/
588 win_data->resume = false;
589 return;
590 }
591
592 /* protect windows */
593 decon_shadow_protect_win(ctx, win, true);
594
595 /* wincon */
596 val = readl(ctx->regs + WINCON(win));
597 val &= ~WINCONx_ENWIN;
598 writel(val, ctx->regs + WINCON(win));
599
600 /* unprotect windows */
601 decon_shadow_protect_win(ctx, win, false);
602
603 val = readl(ctx->regs + DECON_UPDATE);
604 val |= DECON_UPDATE_STANDALONE_F;
605 writel(val, ctx->regs + DECON_UPDATE);
606
607 win_data->enabled = false;
608}
609
610static void decon_window_suspend(struct decon_context *ctx)
611{
612 struct decon_win_data *win_data;
613 int i;
614
615 for (i = 0; i < WINDOWS_NR; i++) {
616 win_data = &ctx->win_data[i];
617 win_data->resume = win_data->enabled;
618 if (win_data->enabled)
619 decon_win_disable(ctx->crtc, i);
620 }
621}
622
623static void decon_window_resume(struct decon_context *ctx)
624{
625 struct decon_win_data *win_data;
626 int i;
627
628 for (i = 0; i < WINDOWS_NR; i++) {
629 win_data = &ctx->win_data[i];
630 win_data->enabled = win_data->resume;
631 win_data->resume = false;
632 }
633}
634
635static void decon_apply(struct decon_context *ctx)
636{
637 struct decon_win_data *win_data;
638 int i;
639
640 for (i = 0; i < WINDOWS_NR; i++) {
641 win_data = &ctx->win_data[i];
642 if (win_data->enabled)
643 decon_win_commit(ctx->crtc, i);
644 else
645 decon_win_disable(ctx->crtc, i);
646 }
647
648 decon_commit(ctx->crtc);
649}
650
651static void decon_init(struct decon_context *ctx)
652{
653 u32 val;
654
655 writel(VIDCON0_SWRESET, ctx->regs + VIDCON0);
656
657 val = VIDOUTCON0_DISP_IF_0_ON;
658 if (!ctx->i80_if)
659 val |= VIDOUTCON0_RGBIF;
660 writel(val, ctx->regs + VIDOUTCON0);
661
662 writel(VCLKCON0_CLKVALUP | VCLKCON0_VCLKFREE, ctx->regs + VCLKCON0);
663
664 if (!ctx->i80_if)
665 writel(VIDCON1_VCLK_HOLD, ctx->regs + VIDCON1(0));
666}
667
668static int decon_poweron(struct decon_context *ctx)
669{
670 int ret;
671
672 if (!ctx->suspended)
673 return 0;
674
675 ctx->suspended = false;
676
677 pm_runtime_get_sync(ctx->dev);
678
679 ret = clk_prepare_enable(ctx->pclk);
680 if (ret < 0) {
681 DRM_ERROR("Failed to prepare_enable the pclk [%d]\n", ret);
682 goto pclk_err;
683 }
684
685 ret = clk_prepare_enable(ctx->aclk);
686 if (ret < 0) {
687 DRM_ERROR("Failed to prepare_enable the aclk [%d]\n", ret);
688 goto aclk_err;
689 }
690
691 ret = clk_prepare_enable(ctx->eclk);
692 if (ret < 0) {
693 DRM_ERROR("Failed to prepare_enable the eclk [%d]\n", ret);
694 goto eclk_err;
695 }
696
697 ret = clk_prepare_enable(ctx->vclk);
698 if (ret < 0) {
699 DRM_ERROR("Failed to prepare_enable the vclk [%d]\n", ret);
700 goto vclk_err;
701 }
702
703 decon_init(ctx);
704
705 /* if vblank was enabled status, enable it again. */
706 if (test_and_clear_bit(0, &ctx->irq_flags)) {
707 ret = decon_enable_vblank(ctx->crtc);
708 if (ret) {
709 DRM_ERROR("Failed to re-enable vblank [%d]\n", ret);
710 goto err;
711 }
712 }
713
714 decon_window_resume(ctx);
715
716 decon_apply(ctx);
717
718 return 0;
719
720err:
721 clk_disable_unprepare(ctx->vclk);
722vclk_err:
723 clk_disable_unprepare(ctx->eclk);
724eclk_err:
725 clk_disable_unprepare(ctx->aclk);
726aclk_err:
727 clk_disable_unprepare(ctx->pclk);
728pclk_err:
729 ctx->suspended = true;
730 return ret;
731}
732
733static int decon_poweroff(struct decon_context *ctx)
734{
735 if (ctx->suspended)
736 return 0;
737
738 /*
739 * We need to make sure that all windows are disabled before we
740 * suspend that connector. Otherwise we might try to scan from
741 * a destroyed buffer later.
742 */
743 decon_window_suspend(ctx);
744
745 clk_disable_unprepare(ctx->vclk);
746 clk_disable_unprepare(ctx->eclk);
747 clk_disable_unprepare(ctx->aclk);
748 clk_disable_unprepare(ctx->pclk);
749
750 pm_runtime_put_sync(ctx->dev);
751
752 ctx->suspended = true;
753 return 0;
754}
755
756static void decon_dpms(struct exynos_drm_crtc *crtc, int mode)
757{
758 DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
759
760 switch (mode) {
761 case DRM_MODE_DPMS_ON:
762 decon_poweron(crtc->ctx);
763 break;
764 case DRM_MODE_DPMS_STANDBY:
765 case DRM_MODE_DPMS_SUSPEND:
766 case DRM_MODE_DPMS_OFF:
767 decon_poweroff(crtc->ctx);
768 break;
769 default:
770 DRM_DEBUG_KMS("unspecified mode %d\n", mode);
771 break;
772 }
773}
774
775static struct exynos_drm_crtc_ops decon_crtc_ops = {
776 .dpms = decon_dpms,
777 .mode_fixup = decon_mode_fixup,
778 .commit = decon_commit,
779 .enable_vblank = decon_enable_vblank,
780 .disable_vblank = decon_disable_vblank,
781 .wait_for_vblank = decon_wait_for_vblank,
782 .win_mode_set = decon_win_mode_set,
783 .win_commit = decon_win_commit,
784 .win_disable = decon_win_disable,
785};
786
787
788static irqreturn_t decon_irq_handler(int irq, void *dev_id)
789{
790 struct decon_context *ctx = (struct decon_context *)dev_id;
791 u32 val, clear_bit;
792
793 val = readl(ctx->regs + VIDINTCON1);
794
795 clear_bit = ctx->i80_if ? VIDINTCON1_INT_I80 : VIDINTCON1_INT_FRAME;
796 if (val & clear_bit)
797 writel(clear_bit, ctx->regs + VIDINTCON1);
798
799 /* check the crtc is detached already from encoder */
800 if (ctx->pipe < 0 || !ctx->drm_dev)
801 goto out;
802
803 if (!ctx->i80_if) {
804 drm_handle_vblank(ctx->drm_dev, ctx->pipe);
805 exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
806
807 /* set wait vsync event to zero and wake up queue. */
808 if (atomic_read(&ctx->wait_vsync_event)) {
809 atomic_set(&ctx->wait_vsync_event, 0);
810 wake_up(&ctx->wait_vsync_queue);
811 }
812 }
813out:
814 return IRQ_HANDLED;
815}
816
817static int decon_bind(struct device *dev, struct device *master, void *data)
818{
819 struct decon_context *ctx = dev_get_drvdata(dev);
820 struct drm_device *drm_dev = data;
821 int ret;
822
823 ret = decon_ctx_initialize(ctx, drm_dev);
824 if (ret) {
825 DRM_ERROR("decon_ctx_initialize failed.\n");
826 return ret;
827 }
828
829 ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
830 EXYNOS_DISPLAY_TYPE_LCD,
831 &decon_crtc_ops, ctx);
832 if (IS_ERR(ctx->crtc)) {
833 decon_ctx_remove(ctx);
834 return PTR_ERR(ctx->crtc);
835 }
836
837 if (ctx->display)
838 exynos_drm_create_enc_conn(drm_dev, ctx->display);
839
840 return 0;
841
842}
843
844static void decon_unbind(struct device *dev, struct device *master,
845 void *data)
846{
847 struct decon_context *ctx = dev_get_drvdata(dev);
848
849 decon_dpms(ctx->crtc, DRM_MODE_DPMS_OFF);
850
851 if (ctx->display)
852 exynos_dpi_remove(ctx->display);
853
854 decon_ctx_remove(ctx);
855}
856
857static const struct component_ops decon_component_ops = {
858 .bind = decon_bind,
859 .unbind = decon_unbind,
860};
861
862static int decon_probe(struct platform_device *pdev)
863{
864 struct device *dev = &pdev->dev;
865 struct decon_context *ctx;
866 struct device_node *i80_if_timings;
867 struct resource *res;
868 int ret;
869
870 if (!dev->of_node)
871 return -ENODEV;
872
873 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
874 if (!ctx)
875 return -ENOMEM;
876
877 ret = exynos_drm_component_add(dev, EXYNOS_DEVICE_TYPE_CRTC,
878 EXYNOS_DISPLAY_TYPE_LCD);
879 if (ret)
880 return ret;
881
882 ctx->dev = dev;
883 ctx->suspended = true;
884
885 i80_if_timings = of_get_child_by_name(dev->of_node, "i80-if-timings");
886 if (i80_if_timings)
887 ctx->i80_if = true;
888 of_node_put(i80_if_timings);
889
890 ctx->regs = of_iomap(dev->of_node, 0);
891 if (IS_ERR(ctx->regs)) {
892 ret = PTR_ERR(ctx->regs);
893 goto err_del_component;
894 }
895
896 ctx->pclk = devm_clk_get(dev, "pclk_decon0");
897 if (IS_ERR(ctx->pclk)) {
898 dev_err(dev, "failed to get bus clock pclk\n");
899 ret = PTR_ERR(ctx->pclk);
900 goto err_iounmap;
901 }
902
903 ctx->aclk = devm_clk_get(dev, "aclk_decon0");
904 if (IS_ERR(ctx->aclk)) {
905 dev_err(dev, "failed to get bus clock aclk\n");
906 ret = PTR_ERR(ctx->aclk);
907 goto err_iounmap;
908 }
909
910 ctx->eclk = devm_clk_get(dev, "decon0_eclk");
911 if (IS_ERR(ctx->eclk)) {
912 dev_err(dev, "failed to get eclock\n");
913 ret = PTR_ERR(ctx->eclk);
914 goto err_iounmap;
915 }
916
917 ctx->vclk = devm_clk_get(dev, "decon0_vclk");
918 if (IS_ERR(ctx->vclk)) {
919 dev_err(dev, "failed to get vclock\n");
920 ret = PTR_ERR(ctx->vclk);
921 goto err_iounmap;
922 }
923
924 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
925 ctx->i80_if ? "lcd_sys" : "vsync");
926 if (!res) {
927 dev_err(dev, "irq request failed.\n");
928 ret = -ENXIO;
929 goto err_iounmap;
930 }
931
932 ret = devm_request_irq(dev, res->start, decon_irq_handler,
933 0, "drm_decon", ctx);
934 if (ret) {
935 dev_err(dev, "irq request failed.\n");
936 goto err_iounmap;
937 }
938
939 init_waitqueue_head(&ctx->wait_vsync_queue);
940 atomic_set(&ctx->wait_vsync_event, 0);
941
942 platform_set_drvdata(pdev, ctx);
943
944 ctx->display = exynos_dpi_probe(dev);
945 if (IS_ERR(ctx->display)) {
946 ret = PTR_ERR(ctx->display);
947 goto err_iounmap;
948 }
949
950 pm_runtime_enable(dev);
951
952 ret = component_add(dev, &decon_component_ops);
953 if (ret)
954 goto err_disable_pm_runtime;
955
956 return ret;
957
958err_disable_pm_runtime:
959 pm_runtime_disable(dev);
960
961err_iounmap:
962 iounmap(ctx->regs);
963
964err_del_component:
965 exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CRTC);
966 return ret;
967}
968
969static int decon_remove(struct platform_device *pdev)
970{
971 struct decon_context *ctx = dev_get_drvdata(&pdev->dev);
972
973 pm_runtime_disable(&pdev->dev);
974
975 iounmap(ctx->regs);
976
977 component_del(&pdev->dev, &decon_component_ops);
978 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
979
980 return 0;
981}
982
983struct platform_driver decon_driver = {
984 .probe = decon_probe,
985 .remove = decon_remove,
986 .driver = {
987 .name = "exynos-decon",
988 .of_match_table = decon_driver_dt_match,
989 },
990};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 1bcbe07cecfc..90168d7cf66a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -556,6 +556,9 @@ static struct platform_driver *const exynos_drm_kms_drivers[] = {
556#ifdef CONFIG_DRM_EXYNOS_FIMD 556#ifdef CONFIG_DRM_EXYNOS_FIMD
557 &fimd_driver, 557 &fimd_driver,
558#endif 558#endif
559#ifdef CONFIG_DRM_EXYNOS7_DECON
560 &decon_driver,
561#endif
559#ifdef CONFIG_DRM_EXYNOS_DP 562#ifdef CONFIG_DRM_EXYNOS_DP
560 &dp_driver, 563 &dp_driver,
561#endif 564#endif
@@ -612,6 +615,7 @@ static const char * const strings[] = {
612 "samsung,exynos3", 615 "samsung,exynos3",
613 "samsung,exynos4", 616 "samsung,exynos4",
614 "samsung,exynos5", 617 "samsung,exynos5",
618 "samsung,exynos7",
615}; 619};
616 620
617static struct platform_driver exynos_drm_platform_driver = { 621static struct platform_driver exynos_drm_platform_driver = {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 1aceafce7bbf..9afd390d4674 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -344,6 +344,7 @@ void exynos_drm_component_del(struct device *dev,
344 enum exynos_drm_device_type dev_type); 344 enum exynos_drm_device_type dev_type);
345 345
346extern struct platform_driver fimd_driver; 346extern struct platform_driver fimd_driver;
347extern struct platform_driver decon_driver;
347extern struct platform_driver dp_driver; 348extern struct platform_driver dp_driver;
348extern struct platform_driver dsi_driver; 349extern struct platform_driver dsi_driver;
349extern struct platform_driver mixer_driver; 350extern struct platform_driver mixer_driver;