aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--Documentation/devicetree/bindings/video/exynos7-decon.txt68
-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
-rw-r--r--include/video/exynos7_decon.h349
7 files changed, 1423 insertions, 3 deletions
diff --git a/Documentation/devicetree/bindings/video/exynos7-decon.txt b/Documentation/devicetree/bindings/video/exynos7-decon.txt
new file mode 100644
index 000000000000..f5f9c8d4a55a
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/exynos7-decon.txt
@@ -0,0 +1,68 @@
1Device-Tree bindings for Samsung Exynos7 SoC display controller (DECON)
2
3DECON (Display and Enhancement Controller) is the Display Controller for the
4Exynos7 series of SoCs which transfers the image data from a video memory
5buffer to an external LCD interface.
6
7Required properties:
8- compatible: value should be "samsung,exynos7-decon";
9
10- reg: physical base address and length of the DECON registers set.
11
12- interrupt-parent: should be the phandle of the decon controller's
13 parent interrupt controller.
14
15- interrupts: should contain a list of all DECON IP block interrupts in the
16 order: FIFO Level, VSYNC, LCD_SYSTEM. The interrupt specifier
17 format depends on the interrupt controller used.
18
19- interrupt-names: should contain the interrupt names: "fifo", "vsync",
20 "lcd_sys", in the same order as they were listed in the interrupts
21 property.
22
23- pinctrl-0: pin control group to be used for this controller.
24
25- pinctrl-names: must contain a "default" entry.
26
27- clocks: must include clock specifiers corresponding to entries in the
28 clock-names property.
29
30- clock-names: list of clock names sorted in the same order as the clocks
31 property. Must contain "pclk_decon0", "aclk_decon0",
32 "decon0_eclk", "decon0_vclk".
33- i80-if-timings: timing configuration for lcd i80 interface support.
34
35Optional Properties:
36- samsung,power-domain: a phandle to DECON power domain node.
37- display-timings: timing settings for DECON, as described in document [1].
38 Can be used in case timings cannot be provided otherwise
39 or to override timings provided by the panel.
40
41[1]: Documentation/devicetree/bindings/video/display-timing.txt
42
43Example:
44
45SoC specific DT entry:
46
47 decon@13930000 {
48 compatible = "samsung,exynos7-decon";
49 interrupt-parent = <&combiner>;
50 reg = <0x13930000 0x1000>;
51 interrupt-names = "lcd_sys", "vsync", "fifo";
52 interrupts = <0 188 0>, <0 189 0>, <0 190 0>;
53 clocks = <&clock_disp PCLK_DECON_INT>,
54 <&clock_disp ACLK_DECON_INT>,
55 <&clock_disp SCLK_DECON_INT_ECLK>,
56 <&clock_disp SCLK_DECON_INT_EXTCLKPLL>;
57 clock-names = "pclk_decon0", "aclk_decon0", "decon0_eclk",
58 "decon0_vclk";
59 status = "disabled";
60 };
61
62Board specific DT entry:
63
64 decon@13930000 {
65 pinctrl-0 = <&lcd_clk &pwm1_out>;
66 pinctrl-names = "default";
67 status = "okay";
68 };
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;
diff --git a/include/video/exynos7_decon.h b/include/video/exynos7_decon.h
new file mode 100644
index 000000000000..a62b11b613f6
--- /dev/null
+++ b/include/video/exynos7_decon.h
@@ -0,0 +1,349 @@
1/* include/video/exynos7_decon.h
2 *
3 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 * Author: Ajay Kumar <ajaykumar.rs@samsung.com>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 */
11
12/* VIDCON0 */
13#define VIDCON0 0x00
14
15#define VIDCON0_SWRESET (1 << 28)
16#define VIDCON0_DECON_STOP_STATUS (1 << 2)
17#define VIDCON0_ENVID (1 << 1)
18#define VIDCON0_ENVID_F (1 << 0)
19
20/* VIDOUTCON0 */
21#define VIDOUTCON0 0x4
22
23#define VIDOUTCON0_DUAL_MASK (0x3 << 24)
24#define VIDOUTCON0_DUAL_ON (0x3 << 24)
25#define VIDOUTCON0_DISP_IF_1_ON (0x2 << 24)
26#define VIDOUTCON0_DISP_IF_0_ON (0x1 << 24)
27#define VIDOUTCON0_DUAL_OFF (0x0 << 24)
28#define VIDOUTCON0_IF_SHIFT 23
29#define VIDOUTCON0_IF_MASK (0x1 << 23)
30#define VIDOUTCON0_RGBIF (0x0 << 23)
31#define VIDOUTCON0_I80IF (0x1 << 23)
32
33/* VIDCON3 */
34#define VIDCON3 0x8
35
36/* VIDCON4 */
37#define VIDCON4 0xC
38#define VIDCON4_FIFOCNT_START_EN (1 << 0)
39
40/* VCLKCON0 */
41#define VCLKCON0 0x10
42#define VCLKCON0_CLKVALUP (1 << 8)
43#define VCLKCON0_VCLKFREE (1 << 0)
44
45/* VCLKCON */
46#define VCLKCON1 0x14
47#define VCLKCON1_CLKVAL_NUM_VCLK(val) (((val) & 0xff) << 0)
48#define VCLKCON2 0x18
49
50/* SHADOWCON */
51#define SHADOWCON 0x30
52
53#define SHADOWCON_WINx_PROTECT(_win) (1 << (10 + (_win)))
54
55/* WINCONx */
56#define WINCON(_win) (0x50 + ((_win) * 4))
57
58#define WINCONx_BUFSTATUS (0x3 << 30)
59#define WINCONx_BUFSEL_MASK (0x3 << 28)
60#define WINCONx_BUFSEL_SHIFT 28
61#define WINCONx_TRIPLE_BUF_MODE (0x1 << 18)
62#define WINCONx_DOUBLE_BUF_MODE (0x0 << 18)
63#define WINCONx_BURSTLEN_16WORD (0x0 << 11)
64#define WINCONx_BURSTLEN_8WORD (0x1 << 11)
65#define WINCONx_BURSTLEN_MASK (0x1 << 11)
66#define WINCONx_BURSTLEN_SHIFT 11
67#define WINCONx_BLD_PLANE (0 << 8)
68#define WINCONx_BLD_PIX (1 << 8)
69#define WINCONx_ALPHA_MUL (1 << 7)
70
71#define WINCONx_BPPMODE_MASK (0xf << 2)
72#define WINCONx_BPPMODE_SHIFT 2
73#define WINCONx_BPPMODE_16BPP_565 (0x8 << 2)
74#define WINCONx_BPPMODE_24BPP_BGRx (0x7 << 2)
75#define WINCONx_BPPMODE_24BPP_RGBx (0x6 << 2)
76#define WINCONx_BPPMODE_24BPP_xBGR (0x5 << 2)
77#define WINCONx_BPPMODE_24BPP_xRGB (0x4 << 2)
78#define WINCONx_BPPMODE_32BPP_BGRA (0x3 << 2)
79#define WINCONx_BPPMODE_32BPP_RGBA (0x2 << 2)
80#define WINCONx_BPPMODE_32BPP_ABGR (0x1 << 2)
81#define WINCONx_BPPMODE_32BPP_ARGB (0x0 << 2)
82#define WINCONx_ALPHA_SEL (1 << 1)
83#define WINCONx_ENWIN (1 << 0)
84
85#define WINCON1_ALPHA_MUL_F (1 << 7)
86#define WINCON2_ALPHA_MUL_F (1 << 7)
87#define WINCON3_ALPHA_MUL_F (1 << 7)
88#define WINCON4_ALPHA_MUL_F (1 << 7)
89
90/* VIDOSDxH: The height for the OSD image(READ ONLY)*/
91#define VIDOSD_H(_x) (0x80 + ((_x) * 4))
92
93/* Frame buffer start addresses: VIDWxxADD0n */
94#define VIDW_BUF_START(_win) (0x80 + ((_win) * 0x10))
95#define VIDW_BUF_START1(_win) (0x84 + ((_win) * 0x10))
96#define VIDW_BUF_START2(_win) (0x88 + ((_win) * 0x10))
97
98#define VIDW_WHOLE_X(_win) (0x0130 + ((_win) * 8))
99#define VIDW_WHOLE_Y(_win) (0x0134 + ((_win) * 8))
100#define VIDW_OFFSET_X(_win) (0x0170 + ((_win) * 8))
101#define VIDW_OFFSET_Y(_win) (0x0174 + ((_win) * 8))
102#define VIDW_BLKOFFSET(_win) (0x01B0 + ((_win) * 4))
103#define VIDW_BLKSIZE(win) (0x0200 + ((_win) * 4))
104
105/* Interrupt controls register */
106#define VIDINTCON2 0x228
107
108#define VIDINTCON1_INTEXTRA1_EN (1 << 1)
109#define VIDINTCON1_INTEXTRA0_EN (1 << 0)
110
111/* Interrupt controls and status register */
112#define VIDINTCON3 0x22C
113
114#define VIDINTCON1_INTEXTRA1_PEND (1 << 1)
115#define VIDINTCON1_INTEXTRA0_PEND (1 << 0)
116
117/* VIDOSDxA ~ VIDOSDxE */
118#define VIDOSD_BASE 0x230
119
120#define OSD_STRIDE 0x20
121
122#define VIDOSD_A(_win) (VIDOSD_BASE + \
123 ((_win) * OSD_STRIDE) + 0x00)
124#define VIDOSD_B(_win) (VIDOSD_BASE + \
125 ((_win) * OSD_STRIDE) + 0x04)
126#define VIDOSD_C(_win) (VIDOSD_BASE + \
127 ((_win) * OSD_STRIDE) + 0x08)
128#define VIDOSD_D(_win) (VIDOSD_BASE + \
129 ((_win) * OSD_STRIDE) + 0x0C)
130#define VIDOSD_E(_win) (VIDOSD_BASE + \
131 ((_win) * OSD_STRIDE) + 0x10)
132
133#define VIDOSDxA_TOPLEFT_X_MASK (0x1fff << 13)
134#define VIDOSDxA_TOPLEFT_X_SHIFT 13
135#define VIDOSDxA_TOPLEFT_X_LIMIT 0x1fff
136#define VIDOSDxA_TOPLEFT_X(_x) (((_x) & 0x1fff) << 13)
137
138#define VIDOSDxA_TOPLEFT_Y_MASK (0x1fff << 0)
139#define VIDOSDxA_TOPLEFT_Y_SHIFT 0
140#define VIDOSDxA_TOPLEFT_Y_LIMIT 0x1fff
141#define VIDOSDxA_TOPLEFT_Y(_x) (((_x) & 0x1fff) << 0)
142
143#define VIDOSDxB_BOTRIGHT_X_MASK (0x1fff << 13)
144#define VIDOSDxB_BOTRIGHT_X_SHIFT 13
145#define VIDOSDxB_BOTRIGHT_X_LIMIT 0x1fff
146#define VIDOSDxB_BOTRIGHT_X(_x) (((_x) & 0x1fff) << 13)
147
148#define VIDOSDxB_BOTRIGHT_Y_MASK (0x1fff << 0)
149#define VIDOSDxB_BOTRIGHT_Y_SHIFT 0
150#define VIDOSDxB_BOTRIGHT_Y_LIMIT 0x1fff
151#define VIDOSDxB_BOTRIGHT_Y(_x) (((_x) & 0x1fff) << 0)
152
153#define VIDOSDxC_ALPHA0_R_F(_x) (((_x) & 0xFF) << 16)
154#define VIDOSDxC_ALPHA0_G_F(_x) (((_x) & 0xFF) << 8)
155#define VIDOSDxC_ALPHA0_B_F(_x) (((_x) & 0xFF) << 0)
156
157#define VIDOSDxD_ALPHA1_R_F(_x) (((_x) & 0xFF) << 16)
158#define VIDOSDxD_ALPHA1_G_F(_x) (((_x) & 0xFF) << 8)
159#define VIDOSDxD_ALPHA1_B_F(_x) (((_x) & 0xFF) >> 0)
160
161/* Window MAP (Color map) */
162#define WINxMAP(_win) (0x340 + ((_win) * 4))
163
164#define WINxMAP_MAP (1 << 24)
165#define WINxMAP_MAP_COLOUR_MASK (0xffffff << 0)
166#define WINxMAP_MAP_COLOUR_SHIFT 0
167#define WINxMAP_MAP_COLOUR_LIMIT 0xffffff
168#define WINxMAP_MAP_COLOUR(_x) ((_x) << 0)
169
170/* Window colour-key control registers */
171#define WKEYCON 0x370
172
173#define WKEYCON0 0x00
174#define WKEYCON1 0x04
175#define WxKEYCON0_KEYBL_EN (1 << 26)
176#define WxKEYCON0_KEYEN_F (1 << 25)
177#define WxKEYCON0_DIRCON (1 << 24)
178#define WxKEYCON0_COMPKEY_MASK (0xffffff << 0)
179#define WxKEYCON0_COMPKEY_SHIFT 0
180#define WxKEYCON0_COMPKEY_LIMIT 0xffffff
181#define WxKEYCON0_COMPKEY(_x) ((_x) << 0)
182#define WxKEYCON1_COLVAL_MASK (0xffffff << 0)
183#define WxKEYCON1_COLVAL_SHIFT 0
184#define WxKEYCON1_COLVAL_LIMIT 0xffffff
185#define WxKEYCON1_COLVAL(_x) ((_x) << 0)
186
187/* color key control register for hardware window 1 ~ 4. */
188#define WKEYCON0_BASE(x) ((WKEYCON + WKEYCON0) + ((x - 1) * 8))
189/* color key value register for hardware window 1 ~ 4. */
190#define WKEYCON1_BASE(x) ((WKEYCON + WKEYCON1) + ((x - 1) * 8))
191
192/* Window KEY Alpha value */
193#define WxKEYALPHA(_win) (0x3A0 + (((_win) - 1) * 0x4))
194
195#define Wx_KEYALPHA_R_F_SHIFT 16
196#define Wx_KEYALPHA_G_F_SHIFT 8
197#define Wx_KEYALPHA_B_F_SHIFT 0
198
199/* Blending equation */
200#define BLENDE(_win) (0x03C0 + ((_win) * 4))
201#define BLENDE_COEF_ZERO 0x0
202#define BLENDE_COEF_ONE 0x1
203#define BLENDE_COEF_ALPHA_A 0x2
204#define BLENDE_COEF_ONE_MINUS_ALPHA_A 0x3
205#define BLENDE_COEF_ALPHA_B 0x4
206#define BLENDE_COEF_ONE_MINUS_ALPHA_B 0x5
207#define BLENDE_COEF_ALPHA0 0x6
208#define BLENDE_COEF_A 0xA
209#define BLENDE_COEF_ONE_MINUS_A 0xB
210#define BLENDE_COEF_B 0xC
211#define BLENDE_COEF_ONE_MINUS_B 0xD
212#define BLENDE_Q_FUNC(_v) ((_v) << 18)
213#define BLENDE_P_FUNC(_v) ((_v) << 12)
214#define BLENDE_B_FUNC(_v) ((_v) << 6)
215#define BLENDE_A_FUNC(_v) ((_v) << 0)
216
217/* Blending equation control */
218#define BLENDCON 0x3D8
219#define BLENDCON_NEW_MASK (1 << 0)
220#define BLENDCON_NEW_8BIT_ALPHA_VALUE (1 << 0)
221#define BLENDCON_NEW_4BIT_ALPHA_VALUE (0 << 0)
222
223/* Interrupt control register */
224#define VIDINTCON0 0x500
225
226#define VIDINTCON0_WAKEUP_MASK (0x3f << 26)
227#define VIDINTCON0_INTEXTRAEN (1 << 21)
228
229#define VIDINTCON0_FRAMESEL0_SHIFT 15
230#define VIDINTCON0_FRAMESEL0_MASK (0x3 << 15)
231#define VIDINTCON0_FRAMESEL0_BACKPORCH (0x0 << 15)
232#define VIDINTCON0_FRAMESEL0_VSYNC (0x1 << 15)
233#define VIDINTCON0_FRAMESEL0_ACTIVE (0x2 << 15)
234#define VIDINTCON0_FRAMESEL0_FRONTPORCH (0x3 << 15)
235
236#define VIDINTCON0_INT_FRAME (1 << 11)
237
238#define VIDINTCON0_FIFOLEVEL_MASK (0x7 << 3)
239#define VIDINTCON0_FIFOLEVEL_SHIFT 3
240#define VIDINTCON0_FIFOLEVEL_EMPTY (0x0 << 3)
241#define VIDINTCON0_FIFOLEVEL_TO25PC (0x1 << 3)
242#define VIDINTCON0_FIFOLEVEL_TO50PC (0x2 << 3)
243#define VIDINTCON0_FIFOLEVEL_FULL (0x4 << 3)
244
245#define VIDINTCON0_FIFOSEL_MAIN_EN (1 << 1)
246#define VIDINTCON0_INT_FIFO (1 << 1)
247
248#define VIDINTCON0_INT_ENABLE (1 << 0)
249
250/* Interrupt controls and status register */
251#define VIDINTCON1 0x504
252
253#define VIDINTCON1_INT_EXTRA (1 << 3)
254#define VIDINTCON1_INT_I80 (1 << 2)
255#define VIDINTCON1_INT_FRAME (1 << 1)
256#define VIDINTCON1_INT_FIFO (1 << 0)
257
258/* VIDCON1 */
259#define VIDCON1(_x) (0x0600 + ((_x) * 0x50))
260#define VIDCON1_LINECNT_GET(_v) (((_v) >> 17) & 0x1fff)
261#define VIDCON1_VCLK_MASK (0x3 << 9)
262#define VIDCON1_VCLK_HOLD (0x0 << 9)
263#define VIDCON1_VCLK_RUN (0x1 << 9)
264#define VIDCON1_VCLK_RUN_VDEN_DISABLE (0x3 << 9)
265#define VIDCON1_RGB_ORDER_O_MASK (0x7 << 4)
266#define VIDCON1_RGB_ORDER_O_RGB (0x0 << 4)
267#define VIDCON1_RGB_ORDER_O_GBR (0x1 << 4)
268#define VIDCON1_RGB_ORDER_O_BRG (0x2 << 4)
269#define VIDCON1_RGB_ORDER_O_BGR (0x4 << 4)
270#define VIDCON1_RGB_ORDER_O_RBG (0x5 << 4)
271#define VIDCON1_RGB_ORDER_O_GRB (0x6 << 4)
272
273/* VIDTCON0 */
274#define VIDTCON0 0x610
275
276#define VIDTCON0_VBPD_MASK (0xffff << 16)
277#define VIDTCON0_VBPD_SHIFT 16
278#define VIDTCON0_VBPD_LIMIT 0xffff
279#define VIDTCON0_VBPD(_x) ((_x) << 16)
280
281#define VIDTCON0_VFPD_MASK (0xffff << 0)
282#define VIDTCON0_VFPD_SHIFT 0
283#define VIDTCON0_VFPD_LIMIT 0xffff
284#define VIDTCON0_VFPD(_x) ((_x) << 0)
285
286/* VIDTCON1 */
287#define VIDTCON1 0x614
288
289#define VIDTCON1_VSPW_MASK (0xffff << 16)
290#define VIDTCON1_VSPW_SHIFT 16
291#define VIDTCON1_VSPW_LIMIT 0xffff
292#define VIDTCON1_VSPW(_x) ((_x) << 16)
293
294/* VIDTCON2 */
295#define VIDTCON2 0x618
296
297#define VIDTCON2_HBPD_MASK (0xffff << 16)
298#define VIDTCON2_HBPD_SHIFT 16
299#define VIDTCON2_HBPD_LIMIT 0xffff
300#define VIDTCON2_HBPD(_x) ((_x) << 16)
301
302#define VIDTCON2_HFPD_MASK (0xffff << 0)
303#define VIDTCON2_HFPD_SHIFT 0
304#define VIDTCON2_HFPD_LIMIT 0xffff
305#define VIDTCON2_HFPD(_x) ((_x) << 0)
306
307/* VIDTCON3 */
308#define VIDTCON3 0x61C
309
310#define VIDTCON3_HSPW_MASK (0xffff << 16)
311#define VIDTCON3_HSPW_SHIFT 16
312#define VIDTCON3_HSPW_LIMIT 0xffff
313#define VIDTCON3_HSPW(_x) ((_x) << 16)
314
315/* VIDTCON4 */
316#define VIDTCON4 0x620
317
318#define VIDTCON4_LINEVAL_MASK (0xfff << 16)
319#define VIDTCON4_LINEVAL_SHIFT 16
320#define VIDTCON4_LINEVAL_LIMIT 0xfff
321#define VIDTCON4_LINEVAL(_x) (((_x) & 0xfff) << 16)
322
323#define VIDTCON4_HOZVAL_MASK (0xfff << 0)
324#define VIDTCON4_HOZVAL_SHIFT 0
325#define VIDTCON4_HOZVAL_LIMIT 0xfff
326#define VIDTCON4_HOZVAL(_x) (((_x) & 0xfff) << 0)
327
328/* LINECNT OP THRSHOLD*/
329#define LINECNT_OP_THRESHOLD 0x630
330
331/* CRCCTRL */
332#define CRCCTRL 0x6C8
333#define CRCCTRL_CRCCLKEN (0x1 << 2)
334#define CRCCTRL_CRCSTART_F (0x1 << 1)
335#define CRCCTRL_CRCEN (0x1 << 0)
336
337/* DECON_CMU */
338#define DECON_CMU 0x704
339
340#define DECON_CMU_ALL_CLKGATE_ENABLE 0x3
341#define DECON_CMU_SE_CLKGATE_ENABLE (0x1 << 2)
342#define DECON_CMU_SFR_CLKGATE_ENABLE (0x1 << 1)
343#define DECON_CMU_MEM_CLKGATE_ENABLE (0x1 << 0)
344
345/* DECON_UPDATE */
346#define DECON_UPDATE 0x710
347
348#define DECON_UPDATE_SLAVE_SYNC (1 << 4)
349#define DECON_UPDATE_STANDALONE_F (1 << 0)