1 /* exynos_drm_fimd.c
2  *
3  * Copyright (C) 2011 Samsung Electronics Co.Ltd
4  * Authors:
5  *	Joonyoung Shim <jy0922.shim@samsung.com>
6  *	Inki Dae <inki.dae@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 
16 #include <linux/kernel.h>
17 #include <linux/platform_device.h>
18 #include <linux/clk.h>
19 #include <linux/of.h>
20 #include <linux/of_device.h>
21 #include <linux/pm_runtime.h>
22 #include <linux/component.h>
23 
24 #include <video/of_display_timing.h>
25 #include <video/of_videomode.h>
26 #include <video/samsung_fimd.h>
27 #include <drm/exynos_drm.h>
28 
29 #include "exynos_drm_drv.h"
30 #include "exynos_drm_fbdev.h"
31 #include "exynos_drm_crtc.h"
32 #include "exynos_drm_iommu.h"
33 
34 /*
35  * FIMD stands for Fully Interactive Mobile Display and
36  * as a display controller, it transfers contents drawn on memory
37  * to a LCD Panel through Display Interfaces such as RGB or
38  * CPU Interface.
39  */
40 
41 #define FIMD_DEFAULT_FRAMERATE 60
42 #define MIN_FB_WIDTH_FOR_16WORD_BURST 128
43 
44 /* position control register for hardware window 0, 2 ~ 4.*/
45 #define VIDOSD_A(win)		(VIDOSD_BASE + 0x00 + (win) * 16)
46 #define VIDOSD_B(win)		(VIDOSD_BASE + 0x04 + (win) * 16)
47 /*
48  * size control register for hardware windows 0 and alpha control register
49  * for hardware windows 1 ~ 4
50  */
51 #define VIDOSD_C(win)		(VIDOSD_BASE + 0x08 + (win) * 16)
52 /* size control register for hardware windows 1 ~ 2. */
53 #define VIDOSD_D(win)		(VIDOSD_BASE + 0x0C + (win) * 16)
54 
55 #define VIDWx_BUF_START(win, buf)	(VIDW_BUF_START(buf) + (win) * 8)
56 #define VIDWx_BUF_END(win, buf)		(VIDW_BUF_END(buf) + (win) * 8)
57 #define VIDWx_BUF_SIZE(win, buf)	(VIDW_BUF_SIZE(buf) + (win) * 4)
58 
59 /* color key control register for hardware window 1 ~ 4. */
60 #define WKEYCON0_BASE(x)		((WKEYCON0 + 0x140) + ((x - 1) * 8))
61 /* color key value register for hardware window 1 ~ 4. */
62 #define WKEYCON1_BASE(x)		((WKEYCON1 + 0x140) + ((x - 1) * 8))
63 
64 /* FIMD has totally five hardware windows. */
65 #define WINDOWS_NR	5
66 
67 #define get_fimd_manager(mgr)	platform_get_drvdata(to_platform_device(dev))
68 
69 struct fimd_driver_data {
70 	unsigned int timing_base;
71 
72 	unsigned int has_shadowcon:1;
73 	unsigned int has_clksel:1;
74 	unsigned int has_limited_fmt:1;
75 };
76 
77 static struct fimd_driver_data s3c64xx_fimd_driver_data = {
78 	.timing_base = 0x0,
79 	.has_clksel = 1,
80 	.has_limited_fmt = 1,
81 };
82 
83 static struct fimd_driver_data exynos4_fimd_driver_data = {
84 	.timing_base = 0x0,
85 	.has_shadowcon = 1,
86 };
87 
88 static struct fimd_driver_data exynos5_fimd_driver_data = {
89 	.timing_base = 0x20000,
90 	.has_shadowcon = 1,
91 };
92 
93 struct fimd_win_data {
94 	unsigned int		offset_x;
95 	unsigned int		offset_y;
96 	unsigned int		ovl_width;
97 	unsigned int		ovl_height;
98 	unsigned int		fb_width;
99 	unsigned int		fb_height;
100 	unsigned int		bpp;
101 	unsigned int		pixel_format;
102 	dma_addr_t		dma_addr;
103 	unsigned int		buf_offsize;
104 	unsigned int		line_size;	/* bytes */
105 	bool			enabled;
106 	bool			resume;
107 };
108 
109 struct fimd_context {
110 	struct device			*dev;
111 	struct drm_device		*drm_dev;
112 	struct clk			*bus_clk;
113 	struct clk			*lcd_clk;
114 	void __iomem			*regs;
115 	struct drm_display_mode		mode;
116 	struct fimd_win_data		win_data[WINDOWS_NR];
117 	unsigned int			default_win;
118 	unsigned long			irq_flags;
119 	u32				vidcon1;
120 	bool				suspended;
121 	int				pipe;
122 	wait_queue_head_t		wait_vsync_queue;
123 	atomic_t			wait_vsync_event;
124 
125 	struct exynos_drm_panel_info panel;
126 	struct fimd_driver_data *driver_data;
127 	struct exynos_drm_display *display;
128 };
129 
130 static const struct of_device_id fimd_driver_dt_match[] = {
131 	{ .compatible = "samsung,s3c6400-fimd",
132 	  .data = &s3c64xx_fimd_driver_data },
133 	{ .compatible = "samsung,exynos4210-fimd",
134 	  .data = &exynos4_fimd_driver_data },
135 	{ .compatible = "samsung,exynos5250-fimd",
136 	  .data = &exynos5_fimd_driver_data },
137 	{},
138 };
139 
140 static inline struct fimd_driver_data *drm_fimd_get_driver_data(
141 	struct platform_device *pdev)
142 {
143 	const struct of_device_id *of_id =
144 			of_match_device(fimd_driver_dt_match, &pdev->dev);
145 
146 	return (struct fimd_driver_data *)of_id->data;
147 }
148 
149 static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr)
150 {
151 	struct fimd_context *ctx = mgr->ctx;
152 
153 	if (ctx->suspended)
154 		return;
155 
156 	atomic_set(&ctx->wait_vsync_event, 1);
157 
158 	/*
159 	 * wait for FIMD to signal VSYNC interrupt or return after
160 	 * timeout which is set to 50ms (refresh rate of 20).
161 	 */
162 	if (!wait_event_timeout(ctx->wait_vsync_queue,
163 				!atomic_read(&ctx->wait_vsync_event),
164 				HZ/20))
165 		DRM_DEBUG_KMS("vblank wait timed out.\n");
166 }
167 
168 
169 static void fimd_clear_channel(struct exynos_drm_manager *mgr)
170 {
171 	struct fimd_context *ctx = mgr->ctx;
172 	int win, ch_enabled = 0;
173 
174 	DRM_DEBUG_KMS("%s\n", __FILE__);
175 
176 	/* Check if any channel is enabled. */
177 	for (win = 0; win < WINDOWS_NR; win++) {
178 		u32 val = readl(ctx->regs + SHADOWCON);
179 		if (val & SHADOWCON_CHx_ENABLE(win)) {
180 			val &= ~SHADOWCON_CHx_ENABLE(win);
181 			writel(val, ctx->regs + SHADOWCON);
182 			ch_enabled = 1;
183 		}
184 	}
185 
186 	/* Wait for vsync, as disable channel takes effect at next vsync */
187 	if (ch_enabled)
188 		fimd_wait_for_vblank(mgr);
189 }
190 
191 static int fimd_mgr_initialize(struct exynos_drm_manager *mgr,
192 			struct drm_device *drm_dev)
193 {
194 	struct fimd_context *ctx = mgr->ctx;
195 	struct exynos_drm_private *priv;
196 	priv = drm_dev->dev_private;
197 
198 	mgr->drm_dev = ctx->drm_dev = drm_dev;
199 	mgr->pipe = ctx->pipe = priv->pipe++;
200 
201 	/*
202 	 * enable drm irq mode.
203 	 * - with irq_enabled = true, we can use the vblank feature.
204 	 *
205 	 * P.S. note that we wouldn't use drm irq handler but
206 	 *	just specific driver own one instead because
207 	 *	drm framework supports only one irq handler.
208 	 */
209 	drm_dev->irq_enabled = true;
210 
211 	/*
212 	 * with vblank_disable_allowed = true, vblank interrupt will be disabled
213 	 * by drm timer once a current process gives up ownership of
214 	 * vblank event.(after drm_vblank_put function is called)
215 	 */
216 	drm_dev->vblank_disable_allowed = true;
217 
218 	/* attach this sub driver to iommu mapping if supported. */
219 	if (is_drm_iommu_supported(ctx->drm_dev)) {
220 		/*
221 		 * If any channel is already active, iommu will throw
222 		 * a PAGE FAULT when enabled. So clear any channel if enabled.
223 		 */
224 		fimd_clear_channel(mgr);
225 		drm_iommu_attach_device(ctx->drm_dev, ctx->dev);
226 	}
227 
228 	return 0;
229 }
230 
231 static void fimd_mgr_remove(struct exynos_drm_manager *mgr)
232 {
233 	struct fimd_context *ctx = mgr->ctx;
234 
235 	/* detach this sub driver from iommu mapping if supported. */
236 	if (is_drm_iommu_supported(ctx->drm_dev))
237 		drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
238 }
239 
240 static u32 fimd_calc_clkdiv(struct fimd_context *ctx,
241 		const struct drm_display_mode *mode)
242 {
243 	unsigned long ideal_clk = mode->htotal * mode->vtotal * mode->vrefresh;
244 	u32 clkdiv;
245 
246 	/* Find the clock divider value that gets us closest to ideal_clk */
247 	clkdiv = DIV_ROUND_UP(clk_get_rate(ctx->lcd_clk), ideal_clk);
248 
249 	return (clkdiv < 0x100) ? clkdiv : 0xff;
250 }
251 
252 static bool fimd_mode_fixup(struct exynos_drm_manager *mgr,
253 		const struct drm_display_mode *mode,
254 		struct drm_display_mode *adjusted_mode)
255 {
256 	if (adjusted_mode->vrefresh == 0)
257 		adjusted_mode->vrefresh = FIMD_DEFAULT_FRAMERATE;
258 
259 	return true;
260 }
261 
262 static void fimd_mode_set(struct exynos_drm_manager *mgr,
263 		const struct drm_display_mode *in_mode)
264 {
265 	struct fimd_context *ctx = mgr->ctx;
266 
267 	drm_mode_copy(&ctx->mode, in_mode);
268 }
269 
270 static void fimd_commit(struct exynos_drm_manager *mgr)
271 {
272 	struct fimd_context *ctx = mgr->ctx;
273 	struct drm_display_mode *mode = &ctx->mode;
274 	struct fimd_driver_data *driver_data;
275 	u32 val, clkdiv, vidcon1;
276 	int vsync_len, vbpd, vfpd, hsync_len, hbpd, hfpd;
277 
278 	driver_data = ctx->driver_data;
279 	if (ctx->suspended)
280 		return;
281 
282 	/* nothing to do if we haven't set the mode yet */
283 	if (mode->htotal == 0 || mode->vtotal == 0)
284 		return;
285 
286 	/* setup polarity values */
287 	vidcon1 = ctx->vidcon1;
288 	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
289 		vidcon1 |= VIDCON1_INV_VSYNC;
290 	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
291 		vidcon1 |= VIDCON1_INV_HSYNC;
292 	writel(vidcon1, ctx->regs + driver_data->timing_base + VIDCON1);
293 
294 	/* setup vertical timing values. */
295 	vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
296 	vbpd = mode->crtc_vtotal - mode->crtc_vsync_end;
297 	vfpd = mode->crtc_vsync_start - mode->crtc_vdisplay;
298 
299 	val = VIDTCON0_VBPD(vbpd - 1) |
300 		VIDTCON0_VFPD(vfpd - 1) |
301 		VIDTCON0_VSPW(vsync_len - 1);
302 	writel(val, ctx->regs + driver_data->timing_base + VIDTCON0);
303 
304 	/* setup horizontal timing values.  */
305 	hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
306 	hbpd = mode->crtc_htotal - mode->crtc_hsync_end;
307 	hfpd = mode->crtc_hsync_start - mode->crtc_hdisplay;
308 
309 	val = VIDTCON1_HBPD(hbpd - 1) |
310 		VIDTCON1_HFPD(hfpd - 1) |
311 		VIDTCON1_HSPW(hsync_len - 1);
312 	writel(val, ctx->regs + driver_data->timing_base + VIDTCON1);
313 
314 	/* setup horizontal and vertical display size. */
315 	val = VIDTCON2_LINEVAL(mode->vdisplay - 1) |
316 	       VIDTCON2_HOZVAL(mode->hdisplay - 1) |
317 	       VIDTCON2_LINEVAL_E(mode->vdisplay - 1) |
318 	       VIDTCON2_HOZVAL_E(mode->hdisplay - 1);
319 	writel(val, ctx->regs + driver_data->timing_base + VIDTCON2);
320 
321 	/*
322 	 * fields of register with prefix '_F' would be updated
323 	 * at vsync(same as dma start)
324 	 */
325 	val = VIDCON0_ENVID | VIDCON0_ENVID_F;
326 
327 	if (ctx->driver_data->has_clksel)
328 		val |= VIDCON0_CLKSEL_LCD;
329 
330 	clkdiv = fimd_calc_clkdiv(ctx, mode);
331 	if (clkdiv > 1)
332 		val |= VIDCON0_CLKVAL_F(clkdiv - 1) | VIDCON0_CLKDIR;
333 
334 	writel(val, ctx->regs + VIDCON0);
335 }
336 
337 static int fimd_enable_vblank(struct exynos_drm_manager *mgr)
338 {
339 	struct fimd_context *ctx = mgr->ctx;
340 	u32 val;
341 
342 	if (ctx->suspended)
343 		return -EPERM;
344 
345 	if (!test_and_set_bit(0, &ctx->irq_flags)) {
346 		val = readl(ctx->regs + VIDINTCON0);
347 
348 		val |= VIDINTCON0_INT_ENABLE;
349 		val |= VIDINTCON0_INT_FRAME;
350 
351 		val &= ~VIDINTCON0_FRAMESEL0_MASK;
352 		val |= VIDINTCON0_FRAMESEL0_VSYNC;
353 		val &= ~VIDINTCON0_FRAMESEL1_MASK;
354 		val |= VIDINTCON0_FRAMESEL1_NONE;
355 
356 		writel(val, ctx->regs + VIDINTCON0);
357 	}
358 
359 	return 0;
360 }
361 
362 static void fimd_disable_vblank(struct exynos_drm_manager *mgr)
363 {
364 	struct fimd_context *ctx = mgr->ctx;
365 	u32 val;
366 
367 	if (ctx->suspended)
368 		return;
369 
370 	if (test_and_clear_bit(0, &ctx->irq_flags)) {
371 		val = readl(ctx->regs + VIDINTCON0);
372 
373 		val &= ~VIDINTCON0_INT_FRAME;
374 		val &= ~VIDINTCON0_INT_ENABLE;
375 
376 		writel(val, ctx->regs + VIDINTCON0);
377 	}
378 }
379 
380 static void fimd_win_mode_set(struct exynos_drm_manager *mgr,
381 			struct exynos_drm_overlay *overlay)
382 {
383 	struct fimd_context *ctx = mgr->ctx;
384 	struct fimd_win_data *win_data;
385 	int win;
386 	unsigned long offset;
387 
388 	if (!overlay) {
389 		DRM_ERROR("overlay is NULL\n");
390 		return;
391 	}
392 
393 	win = overlay->zpos;
394 	if (win == DEFAULT_ZPOS)
395 		win = ctx->default_win;
396 
397 	if (win < 0 || win >= WINDOWS_NR)
398 		return;
399 
400 	offset = overlay->fb_x * (overlay->bpp >> 3);
401 	offset += overlay->fb_y * overlay->pitch;
402 
403 	DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch);
404 
405 	win_data = &ctx->win_data[win];
406 
407 	win_data->offset_x = overlay->crtc_x;
408 	win_data->offset_y = overlay->crtc_y;
409 	win_data->ovl_width = overlay->crtc_width;
410 	win_data->ovl_height = overlay->crtc_height;
411 	win_data->fb_width = overlay->fb_width;
412 	win_data->fb_height = overlay->fb_height;
413 	win_data->dma_addr = overlay->dma_addr[0] + offset;
414 	win_data->bpp = overlay->bpp;
415 	win_data->pixel_format = overlay->pixel_format;
416 	win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
417 				(overlay->bpp >> 3);
418 	win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3);
419 
420 	DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
421 			win_data->offset_x, win_data->offset_y);
422 	DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
423 			win_data->ovl_width, win_data->ovl_height);
424 	DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
425 	DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
426 			overlay->fb_width, overlay->crtc_width);
427 }
428 
429 static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
430 {
431 	struct fimd_win_data *win_data = &ctx->win_data[win];
432 	unsigned long val;
433 
434 	val = WINCONx_ENWIN;
435 
436 	/*
437 	 * In case of s3c64xx, window 0 doesn't support alpha channel.
438 	 * So the request format is ARGB8888 then change it to XRGB8888.
439 	 */
440 	if (ctx->driver_data->has_limited_fmt && !win) {
441 		if (win_data->pixel_format == DRM_FORMAT_ARGB8888)
442 			win_data->pixel_format = DRM_FORMAT_XRGB8888;
443 	}
444 
445 	switch (win_data->pixel_format) {
446 	case DRM_FORMAT_C8:
447 		val |= WINCON0_BPPMODE_8BPP_PALETTE;
448 		val |= WINCONx_BURSTLEN_8WORD;
449 		val |= WINCONx_BYTSWP;
450 		break;
451 	case DRM_FORMAT_XRGB1555:
452 		val |= WINCON0_BPPMODE_16BPP_1555;
453 		val |= WINCONx_HAWSWP;
454 		val |= WINCONx_BURSTLEN_16WORD;
455 		break;
456 	case DRM_FORMAT_RGB565:
457 		val |= WINCON0_BPPMODE_16BPP_565;
458 		val |= WINCONx_HAWSWP;
459 		val |= WINCONx_BURSTLEN_16WORD;
460 		break;
461 	case DRM_FORMAT_XRGB8888:
462 		val |= WINCON0_BPPMODE_24BPP_888;
463 		val |= WINCONx_WSWP;
464 		val |= WINCONx_BURSTLEN_16WORD;
465 		break;
466 	case DRM_FORMAT_ARGB8888:
467 		val |= WINCON1_BPPMODE_25BPP_A1888
468 			| WINCON1_BLD_PIX | WINCON1_ALPHA_SEL;
469 		val |= WINCONx_WSWP;
470 		val |= WINCONx_BURSTLEN_16WORD;
471 		break;
472 	default:
473 		DRM_DEBUG_KMS("invalid pixel size so using unpacked 24bpp.\n");
474 
475 		val |= WINCON0_BPPMODE_24BPP_888;
476 		val |= WINCONx_WSWP;
477 		val |= WINCONx_BURSTLEN_16WORD;
478 		break;
479 	}
480 
481 	DRM_DEBUG_KMS("bpp = %d\n", win_data->bpp);
482 
483 	/*
484 	 * In case of exynos, setting dma-burst to 16Word causes permanent
485 	 * tearing for very small buffers, e.g. cursor buffer. Burst Mode
486 	 * switching which is based on overlay size is not recommended as
487 	 * overlay size varies alot towards the end of the screen and rapid
488 	 * movement causes unstable DMA which results into iommu crash/tear.
489 	 */
490 
491 	if (win_data->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) {
492 		val &= ~WINCONx_BURSTLEN_MASK;
493 		val |= WINCONx_BURSTLEN_4WORD;
494 	}
495 
496 	writel(val, ctx->regs + WINCON(win));
497 }
498 
499 static void fimd_win_set_colkey(struct fimd_context *ctx, unsigned int win)
500 {
501 	unsigned int keycon0 = 0, keycon1 = 0;
502 
503 	keycon0 = ~(WxKEYCON0_KEYBL_EN | WxKEYCON0_KEYEN_F |
504 			WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0);
505 
506 	keycon1 = WxKEYCON1_COLVAL(0xffffffff);
507 
508 	writel(keycon0, ctx->regs + WKEYCON0_BASE(win));
509 	writel(keycon1, ctx->regs + WKEYCON1_BASE(win));
510 }
511 
512 /**
513  * shadow_protect_win() - disable updating values from shadow registers at vsync
514  *
515  * @win: window to protect registers for
516  * @protect: 1 to protect (disable updates)
517  */
518 static void fimd_shadow_protect_win(struct fimd_context *ctx,
519 							int win, bool protect)
520 {
521 	u32 reg, bits, val;
522 
523 	if (ctx->driver_data->has_shadowcon) {
524 		reg = SHADOWCON;
525 		bits = SHADOWCON_WINx_PROTECT(win);
526 	} else {
527 		reg = PRTCON;
528 		bits = PRTCON_PROTECT;
529 	}
530 
531 	val = readl(ctx->regs + reg);
532 	if (protect)
533 		val |= bits;
534 	else
535 		val &= ~bits;
536 	writel(val, ctx->regs + reg);
537 }
538 
539 static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos)
540 {
541 	struct fimd_context *ctx = mgr->ctx;
542 	struct fimd_win_data *win_data;
543 	int win = zpos;
544 	unsigned long val, alpha, size;
545 	unsigned int last_x;
546 	unsigned int last_y;
547 
548 	if (ctx->suspended)
549 		return;
550 
551 	if (win == DEFAULT_ZPOS)
552 		win = ctx->default_win;
553 
554 	if (win < 0 || win >= WINDOWS_NR)
555 		return;
556 
557 	win_data = &ctx->win_data[win];
558 
559 	/* If suspended, enable this on resume */
560 	if (ctx->suspended) {
561 		win_data->resume = true;
562 		return;
563 	}
564 
565 	/*
566 	 * SHADOWCON/PRTCON register is used for enabling timing.
567 	 *
568 	 * for example, once only width value of a register is set,
569 	 * if the dma is started then fimd hardware could malfunction so
570 	 * with protect window setting, the register fields with prefix '_F'
571 	 * wouldn't be updated at vsync also but updated once unprotect window
572 	 * is set.
573 	 */
574 
575 	/* protect windows */
576 	fimd_shadow_protect_win(ctx, win, true);
577 
578 	/* buffer start address */
579 	val = (unsigned long)win_data->dma_addr;
580 	writel(val, ctx->regs + VIDWx_BUF_START(win, 0));
581 
582 	/* buffer end address */
583 	size = win_data->fb_width * win_data->ovl_height * (win_data->bpp >> 3);
584 	val = (unsigned long)(win_data->dma_addr + size);
585 	writel(val, ctx->regs + VIDWx_BUF_END(win, 0));
586 
587 	DRM_DEBUG_KMS("start addr = 0x%lx, end addr = 0x%lx, size = 0x%lx\n",
588 			(unsigned long)win_data->dma_addr, val, size);
589 	DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
590 			win_data->ovl_width, win_data->ovl_height);
591 
592 	/* buffer size */
593 	val = VIDW_BUF_SIZE_OFFSET(win_data->buf_offsize) |
594 		VIDW_BUF_SIZE_PAGEWIDTH(win_data->line_size) |
595 		VIDW_BUF_SIZE_OFFSET_E(win_data->buf_offsize) |
596 		VIDW_BUF_SIZE_PAGEWIDTH_E(win_data->line_size);
597 	writel(val, ctx->regs + VIDWx_BUF_SIZE(win, 0));
598 
599 	/* OSD position */
600 	val = VIDOSDxA_TOPLEFT_X(win_data->offset_x) |
601 		VIDOSDxA_TOPLEFT_Y(win_data->offset_y) |
602 		VIDOSDxA_TOPLEFT_X_E(win_data->offset_x) |
603 		VIDOSDxA_TOPLEFT_Y_E(win_data->offset_y);
604 	writel(val, ctx->regs + VIDOSD_A(win));
605 
606 	last_x = win_data->offset_x + win_data->ovl_width;
607 	if (last_x)
608 		last_x--;
609 	last_y = win_data->offset_y + win_data->ovl_height;
610 	if (last_y)
611 		last_y--;
612 
613 	val = VIDOSDxB_BOTRIGHT_X(last_x) | VIDOSDxB_BOTRIGHT_Y(last_y) |
614 		VIDOSDxB_BOTRIGHT_X_E(last_x) | VIDOSDxB_BOTRIGHT_Y_E(last_y);
615 
616 	writel(val, ctx->regs + VIDOSD_B(win));
617 
618 	DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %d\n",
619 			win_data->offset_x, win_data->offset_y, last_x, last_y);
620 
621 	/* hardware window 0 doesn't support alpha channel. */
622 	if (win != 0) {
623 		/* OSD alpha */
624 		alpha = VIDISD14C_ALPHA1_R(0xf) |
625 			VIDISD14C_ALPHA1_G(0xf) |
626 			VIDISD14C_ALPHA1_B(0xf);
627 
628 		writel(alpha, ctx->regs + VIDOSD_C(win));
629 	}
630 
631 	/* OSD size */
632 	if (win != 3 && win != 4) {
633 		u32 offset = VIDOSD_D(win);
634 		if (win == 0)
635 			offset = VIDOSD_C(win);
636 		val = win_data->ovl_width * win_data->ovl_height;
637 		writel(val, ctx->regs + offset);
638 
639 		DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val);
640 	}
641 
642 	fimd_win_set_pixfmt(ctx, win);
643 
644 	/* hardware window 0 doesn't support color key. */
645 	if (win != 0)
646 		fimd_win_set_colkey(ctx, win);
647 
648 	/* wincon */
649 	val = readl(ctx->regs + WINCON(win));
650 	val |= WINCONx_ENWIN;
651 	writel(val, ctx->regs + WINCON(win));
652 
653 	/* Enable DMA channel and unprotect windows */
654 	fimd_shadow_protect_win(ctx, win, false);
655 
656 	if (ctx->driver_data->has_shadowcon) {
657 		val = readl(ctx->regs + SHADOWCON);
658 		val |= SHADOWCON_CHx_ENABLE(win);
659 		writel(val, ctx->regs + SHADOWCON);
660 	}
661 
662 	win_data->enabled = true;
663 }
664 
665 static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos)
666 {
667 	struct fimd_context *ctx = mgr->ctx;
668 	struct fimd_win_data *win_data;
669 	int win = zpos;
670 	u32 val;
671 
672 	if (win == DEFAULT_ZPOS)
673 		win = ctx->default_win;
674 
675 	if (win < 0 || win >= WINDOWS_NR)
676 		return;
677 
678 	win_data = &ctx->win_data[win];
679 
680 	if (ctx->suspended) {
681 		/* do not resume this window*/
682 		win_data->resume = false;
683 		return;
684 	}
685 
686 	/* protect windows */
687 	fimd_shadow_protect_win(ctx, win, true);
688 
689 	/* wincon */
690 	val = readl(ctx->regs + WINCON(win));
691 	val &= ~WINCONx_ENWIN;
692 	writel(val, ctx->regs + WINCON(win));
693 
694 	/* unprotect windows */
695 	if (ctx->driver_data->has_shadowcon) {
696 		val = readl(ctx->regs + SHADOWCON);
697 		val &= ~SHADOWCON_CHx_ENABLE(win);
698 		writel(val, ctx->regs + SHADOWCON);
699 	}
700 
701 	fimd_shadow_protect_win(ctx, win, false);
702 
703 	win_data->enabled = false;
704 }
705 
706 static void fimd_window_suspend(struct exynos_drm_manager *mgr)
707 {
708 	struct fimd_context *ctx = mgr->ctx;
709 	struct fimd_win_data *win_data;
710 	int i;
711 
712 	for (i = 0; i < WINDOWS_NR; i++) {
713 		win_data = &ctx->win_data[i];
714 		win_data->resume = win_data->enabled;
715 		if (win_data->enabled)
716 			fimd_win_disable(mgr, i);
717 	}
718 	fimd_wait_for_vblank(mgr);
719 }
720 
721 static void fimd_window_resume(struct exynos_drm_manager *mgr)
722 {
723 	struct fimd_context *ctx = mgr->ctx;
724 	struct fimd_win_data *win_data;
725 	int i;
726 
727 	for (i = 0; i < WINDOWS_NR; i++) {
728 		win_data = &ctx->win_data[i];
729 		win_data->enabled = win_data->resume;
730 		win_data->resume = false;
731 	}
732 }
733 
734 static void fimd_apply(struct exynos_drm_manager *mgr)
735 {
736 	struct fimd_context *ctx = mgr->ctx;
737 	struct fimd_win_data *win_data;
738 	int i;
739 
740 	for (i = 0; i < WINDOWS_NR; i++) {
741 		win_data = &ctx->win_data[i];
742 		if (win_data->enabled)
743 			fimd_win_commit(mgr, i);
744 	}
745 
746 	fimd_commit(mgr);
747 }
748 
749 static int fimd_poweron(struct exynos_drm_manager *mgr)
750 {
751 	struct fimd_context *ctx = mgr->ctx;
752 	int ret;
753 
754 	if (!ctx->suspended)
755 		return 0;
756 
757 	ctx->suspended = false;
758 
759 	pm_runtime_get_sync(ctx->dev);
760 
761 	ret = clk_prepare_enable(ctx->bus_clk);
762 	if (ret < 0) {
763 		DRM_ERROR("Failed to prepare_enable the bus clk [%d]\n", ret);
764 		goto bus_clk_err;
765 	}
766 
767 	ret = clk_prepare_enable(ctx->lcd_clk);
768 	if  (ret < 0) {
769 		DRM_ERROR("Failed to prepare_enable the lcd clk [%d]\n", ret);
770 		goto lcd_clk_err;
771 	}
772 
773 	/* if vblank was enabled status, enable it again. */
774 	if (test_and_clear_bit(0, &ctx->irq_flags)) {
775 		ret = fimd_enable_vblank(mgr);
776 		if (ret) {
777 			DRM_ERROR("Failed to re-enable vblank [%d]\n", ret);
778 			goto enable_vblank_err;
779 		}
780 	}
781 
782 	fimd_window_resume(mgr);
783 
784 	fimd_apply(mgr);
785 
786 	return 0;
787 
788 enable_vblank_err:
789 	clk_disable_unprepare(ctx->lcd_clk);
790 lcd_clk_err:
791 	clk_disable_unprepare(ctx->bus_clk);
792 bus_clk_err:
793 	ctx->suspended = true;
794 	return ret;
795 }
796 
797 static int fimd_poweroff(struct exynos_drm_manager *mgr)
798 {
799 	struct fimd_context *ctx = mgr->ctx;
800 
801 	if (ctx->suspended)
802 		return 0;
803 
804 	/*
805 	 * We need to make sure that all windows are disabled before we
806 	 * suspend that connector. Otherwise we might try to scan from
807 	 * a destroyed buffer later.
808 	 */
809 	fimd_window_suspend(mgr);
810 
811 	clk_disable_unprepare(ctx->lcd_clk);
812 	clk_disable_unprepare(ctx->bus_clk);
813 
814 	pm_runtime_put_sync(ctx->dev);
815 
816 	ctx->suspended = true;
817 	return 0;
818 }
819 
820 static void fimd_dpms(struct exynos_drm_manager *mgr, int mode)
821 {
822 	DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
823 
824 	switch (mode) {
825 	case DRM_MODE_DPMS_ON:
826 		fimd_poweron(mgr);
827 		break;
828 	case DRM_MODE_DPMS_STANDBY:
829 	case DRM_MODE_DPMS_SUSPEND:
830 	case DRM_MODE_DPMS_OFF:
831 		fimd_poweroff(mgr);
832 		break;
833 	default:
834 		DRM_DEBUG_KMS("unspecified mode %d\n", mode);
835 		break;
836 	}
837 }
838 
839 static struct exynos_drm_manager_ops fimd_manager_ops = {
840 	.dpms = fimd_dpms,
841 	.mode_fixup = fimd_mode_fixup,
842 	.mode_set = fimd_mode_set,
843 	.commit = fimd_commit,
844 	.enable_vblank = fimd_enable_vblank,
845 	.disable_vblank = fimd_disable_vblank,
846 	.wait_for_vblank = fimd_wait_for_vblank,
847 	.win_mode_set = fimd_win_mode_set,
848 	.win_commit = fimd_win_commit,
849 	.win_disable = fimd_win_disable,
850 };
851 
852 static struct exynos_drm_manager fimd_manager = {
853 	.type = EXYNOS_DISPLAY_TYPE_LCD,
854 	.ops = &fimd_manager_ops,
855 };
856 
857 static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
858 {
859 	struct fimd_context *ctx = (struct fimd_context *)dev_id;
860 	u32 val;
861 
862 	val = readl(ctx->regs + VIDINTCON1);
863 
864 	if (val & VIDINTCON1_INT_FRAME)
865 		/* VSYNC interrupt */
866 		writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1);
867 
868 	/* check the crtc is detached already from encoder */
869 	if (ctx->pipe < 0 || !ctx->drm_dev)
870 		goto out;
871 
872 	drm_handle_vblank(ctx->drm_dev, ctx->pipe);
873 	exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
874 
875 	/* set wait vsync event to zero and wake up queue. */
876 	if (atomic_read(&ctx->wait_vsync_event)) {
877 		atomic_set(&ctx->wait_vsync_event, 0);
878 		wake_up(&ctx->wait_vsync_queue);
879 	}
880 out:
881 	return IRQ_HANDLED;
882 }
883 
884 static int fimd_bind(struct device *dev, struct device *master, void *data)
885 {
886 	struct fimd_context *ctx = fimd_manager.ctx;
887 	struct drm_device *drm_dev = data;
888 
889 	fimd_mgr_initialize(&fimd_manager, drm_dev);
890 	exynos_drm_crtc_create(&fimd_manager);
891 	if (ctx->display)
892 		exynos_drm_create_enc_conn(drm_dev, ctx->display);
893 
894 	return 0;
895 
896 }
897 
898 static void fimd_unbind(struct device *dev, struct device *master,
899 			void *data)
900 {
901 	struct exynos_drm_manager *mgr = dev_get_drvdata(dev);
902 	struct fimd_context *ctx = fimd_manager.ctx;
903 	struct drm_crtc *crtc = mgr->crtc;
904 
905 	fimd_dpms(mgr, DRM_MODE_DPMS_OFF);
906 
907 	if (ctx->display)
908 		exynos_dpi_remove(dev);
909 
910 	fimd_mgr_remove(mgr);
911 
912 	crtc->funcs->destroy(crtc);
913 }
914 
915 static const struct component_ops fimd_component_ops = {
916 	.bind	= fimd_bind,
917 	.unbind = fimd_unbind,
918 };
919 
920 static int fimd_probe(struct platform_device *pdev)
921 {
922 	struct device *dev = &pdev->dev;
923 	struct fimd_context *ctx;
924 	struct resource *res;
925 	int ret = -EINVAL;
926 
927 	if (!dev->of_node)
928 		return -ENODEV;
929 
930 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
931 	if (!ctx)
932 		return -ENOMEM;
933 
934 	ctx->dev = dev;
935 	ctx->suspended = true;
936 
937 	if (of_property_read_bool(dev->of_node, "samsung,invert-vden"))
938 		ctx->vidcon1 |= VIDCON1_INV_VDEN;
939 	if (of_property_read_bool(dev->of_node, "samsung,invert-vclk"))
940 		ctx->vidcon1 |= VIDCON1_INV_VCLK;
941 
942 	ctx->bus_clk = devm_clk_get(dev, "fimd");
943 	if (IS_ERR(ctx->bus_clk)) {
944 		dev_err(dev, "failed to get bus clock\n");
945 		return PTR_ERR(ctx->bus_clk);
946 	}
947 
948 	ctx->lcd_clk = devm_clk_get(dev, "sclk_fimd");
949 	if (IS_ERR(ctx->lcd_clk)) {
950 		dev_err(dev, "failed to get lcd clock\n");
951 		return PTR_ERR(ctx->lcd_clk);
952 	}
953 
954 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
955 
956 	ctx->regs = devm_ioremap_resource(dev, res);
957 	if (IS_ERR(ctx->regs))
958 		return PTR_ERR(ctx->regs);
959 
960 	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "vsync");
961 	if (!res) {
962 		dev_err(dev, "irq request failed.\n");
963 		return -ENXIO;
964 	}
965 
966 	ret = devm_request_irq(dev, res->start, fimd_irq_handler,
967 							0, "drm_fimd", ctx);
968 	if (ret) {
969 		dev_err(dev, "irq request failed.\n");
970 		return ret;
971 	}
972 
973 	ctx->driver_data = drm_fimd_get_driver_data(pdev);
974 	init_waitqueue_head(&ctx->wait_vsync_queue);
975 	atomic_set(&ctx->wait_vsync_event, 0);
976 
977 	platform_set_drvdata(pdev, &fimd_manager);
978 
979 	fimd_manager.ctx = ctx;
980 
981 	ctx->display = exynos_dpi_probe(dev);
982 	if (IS_ERR(ctx->display))
983 		return PTR_ERR(ctx->display);
984 
985 	pm_runtime_enable(&pdev->dev);
986 
987 	return exynos_drm_component_add(&pdev->dev, &fimd_component_ops);
988 }
989 
990 static int fimd_remove(struct platform_device *pdev)
991 {
992 	pm_runtime_disable(&pdev->dev);
993 
994 	exynos_drm_component_del(&pdev->dev, &fimd_component_ops);
995 	return 0;
996 }
997 
998 struct platform_driver fimd_driver = {
999 	.probe		= fimd_probe,
1000 	.remove		= fimd_remove,
1001 	.driver		= {
1002 		.name	= "exynos4-fb",
1003 		.owner	= THIS_MODULE,
1004 		.of_match_table = fimd_driver_dt_match,
1005 	},
1006 };
1007