blob: f467ce05f6cd7d5a6e91844b4e88caa4005500ff [file] [log] [blame]
Joonyoung Shimc8466a92015-06-12 21:59:00 +09001/* drivers/gpu/drm/exynos5433_drm_decon.c
2 *
3 * Copyright (C) 2015 Samsung Electronics Co.Ltd
4 * Authors:
5 * Joonyoung Shim <jy0922.shim@samsung.com>
6 * Hyungwon Hwang <human.hwang@samsung.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundationr
11 */
12
13#include <linux/platform_device.h>
14#include <linux/clk.h>
15#include <linux/component.h>
16#include <linux/of_gpio.h>
17#include <linux/pm_runtime.h>
18
19#include <video/exynos5433_decon.h>
20
21#include "exynos_drm_drv.h"
22#include "exynos_drm_crtc.h"
23#include "exynos_drm_plane.h"
24#include "exynos_drm_iommu.h"
25
26#define WINDOWS_NR 3
27#define MIN_FB_WIDTH_FOR_16WORD_BURST 128
28
29struct decon_context {
30 struct device *dev;
31 struct drm_device *drm_dev;
32 struct exynos_drm_crtc *crtc;
33 struct exynos_drm_plane planes[WINDOWS_NR];
34 void __iomem *addr;
35 struct clk *clks[6];
Joonyoung Shimc8466a92015-06-12 21:59:00 +090036 unsigned long irq_flags;
37 int pipe;
38 bool suspended;
39
40#define BIT_CLKS_ENABLED 0
41#define BIT_IRQS_ENABLED 1
42 unsigned long enabled;
43 bool i80_if;
44 atomic_t win_updated;
45};
46
47static const char * const decon_clks_name[] = {
48 "aclk_decon",
49 "aclk_smmu_decon0x",
50 "aclk_xiu_decon0x",
51 "pclk_smmu_decon0x",
52 "sclk_decon_vclk",
53 "sclk_decon_eclk",
54};
55
Marek Szyprowskifbbb1e12015-08-31 00:53:57 +090056static const uint32_t decon_formats[] = {
57 DRM_FORMAT_XRGB1555,
58 DRM_FORMAT_RGB565,
59 DRM_FORMAT_XRGB8888,
60 DRM_FORMAT_ARGB8888,
61};
62
Joonyoung Shimc8466a92015-06-12 21:59:00 +090063static int decon_enable_vblank(struct exynos_drm_crtc *crtc)
64{
65 struct decon_context *ctx = crtc->ctx;
66 u32 val;
67
68 if (ctx->suspended)
69 return -EPERM;
70
71 if (test_and_set_bit(0, &ctx->irq_flags)) {
72 val = VIDINTCON0_INTEN;
73 if (ctx->i80_if)
74 val |= VIDINTCON0_FRAMEDONE;
75 else
76 val |= VIDINTCON0_INTFRMEN;
77
78 writel(val, ctx->addr + DECON_VIDINTCON0);
79 }
80
81 return 0;
82}
83
84static void decon_disable_vblank(struct exynos_drm_crtc *crtc)
85{
86 struct decon_context *ctx = crtc->ctx;
87
88 if (ctx->suspended)
89 return;
90
91 if (test_and_clear_bit(0, &ctx->irq_flags))
92 writel(0, ctx->addr + DECON_VIDINTCON0);
93}
94
95static void decon_setup_trigger(struct decon_context *ctx)
96{
97 u32 val = TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F |
98 TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN;
99 writel(val, ctx->addr + DECON_TRIGCON);
100}
101
102static void decon_commit(struct exynos_drm_crtc *crtc)
103{
104 struct decon_context *ctx = crtc->ctx;
105 struct drm_display_mode *mode = &crtc->base.mode;
106 u32 val;
107
108 if (ctx->suspended)
109 return;
110
111 /* enable clock gate */
112 val = CMU_CLKGAGE_MODE_SFR_F | CMU_CLKGAGE_MODE_MEM_F;
113 writel(val, ctx->addr + DECON_CMU);
114
115 /* lcd on and use command if */
116 val = VIDOUT_LCD_ON;
117 if (ctx->i80_if)
118 val |= VIDOUT_COMMAND_IF;
119 else
120 val |= VIDOUT_RGB_IF;
121 writel(val, ctx->addr + DECON_VIDOUTCON0);
122
123 val = VIDTCON2_LINEVAL(mode->vdisplay - 1) |
124 VIDTCON2_HOZVAL(mode->hdisplay - 1);
125 writel(val, ctx->addr + DECON_VIDTCON2);
126
127 if (!ctx->i80_if) {
128 val = VIDTCON00_VBPD_F(
129 mode->crtc_vtotal - mode->crtc_vsync_end) |
130 VIDTCON00_VFPD_F(
131 mode->crtc_vsync_start - mode->crtc_vdisplay);
132 writel(val, ctx->addr + DECON_VIDTCON00);
133
134 val = VIDTCON01_VSPW_F(
135 mode->crtc_vsync_end - mode->crtc_vsync_start);
136 writel(val, ctx->addr + DECON_VIDTCON01);
137
138 val = VIDTCON10_HBPD_F(
139 mode->crtc_htotal - mode->crtc_hsync_end) |
140 VIDTCON10_HFPD_F(
141 mode->crtc_hsync_start - mode->crtc_hdisplay);
142 writel(val, ctx->addr + DECON_VIDTCON10);
143
144 val = VIDTCON11_HSPW_F(
145 mode->crtc_hsync_end - mode->crtc_hsync_start);
146 writel(val, ctx->addr + DECON_VIDTCON11);
147 }
148
149 decon_setup_trigger(ctx);
150
151 /* enable output and display signal */
152 val = VIDCON0_ENVID | VIDCON0_ENVID_F;
153 writel(val, ctx->addr + DECON_VIDCON0);
154}
155
156#define COORDINATE_X(x) (((x) & 0xfff) << 12)
157#define COORDINATE_Y(x) ((x) & 0xfff)
158#define OFFSIZE(x) (((x) & 0x3fff) << 14)
159#define PAGEWIDTH(x) ((x) & 0x3fff)
160
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900161static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
162 struct drm_framebuffer *fb)
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900163{
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900164 unsigned long val;
165
166 val = readl(ctx->addr + DECON_WINCONx(win));
167 val &= ~WINCONx_BPPMODE_MASK;
168
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900169 switch (fb->pixel_format) {
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900170 case DRM_FORMAT_XRGB1555:
171 val |= WINCONx_BPPMODE_16BPP_I1555;
172 val |= WINCONx_HAWSWP_F;
173 val |= WINCONx_BURSTLEN_16WORD;
174 break;
175 case DRM_FORMAT_RGB565:
176 val |= WINCONx_BPPMODE_16BPP_565;
177 val |= WINCONx_HAWSWP_F;
178 val |= WINCONx_BURSTLEN_16WORD;
179 break;
180 case DRM_FORMAT_XRGB8888:
181 val |= WINCONx_BPPMODE_24BPP_888;
182 val |= WINCONx_WSWP_F;
183 val |= WINCONx_BURSTLEN_16WORD;
184 break;
185 case DRM_FORMAT_ARGB8888:
186 val |= WINCONx_BPPMODE_32BPP_A8888;
187 val |= WINCONx_WSWP_F | WINCONx_BLD_PIX_F | WINCONx_ALPHA_SEL_F;
188 val |= WINCONx_BURSTLEN_16WORD;
189 break;
190 default:
191 DRM_ERROR("Proper pixel format is not set\n");
192 return;
193 }
194
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900195 DRM_DEBUG_KMS("bpp = %u\n", fb->bits_per_pixel);
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900196
197 /*
198 * In case of exynos, setting dma-burst to 16Word causes permanent
199 * tearing for very small buffers, e.g. cursor buffer. Burst Mode
200 * switching which is based on plane size is not recommended as
201 * plane size varies a lot towards the end of the screen and rapid
202 * movement causes unstable DMA which results into iommu crash/tear.
203 */
204
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900205 if (fb->width < MIN_FB_WIDTH_FOR_16WORD_BURST) {
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900206 val &= ~WINCONx_BURSTLEN_MASK;
207 val |= WINCONx_BURSTLEN_8WORD;
208 }
209
210 writel(val, ctx->addr + DECON_WINCONx(win));
211}
212
213static void decon_shadow_protect_win(struct decon_context *ctx, int win,
214 bool protect)
215{
216 u32 val;
217
218 val = readl(ctx->addr + DECON_SHADOWCON);
219
220 if (protect)
221 val |= SHADOWCON_Wx_PROTECT(win);
222 else
223 val &= ~SHADOWCON_Wx_PROTECT(win);
224
225 writel(val, ctx->addr + DECON_SHADOWCON);
226}
227
Hyungwon Hwangcc5a7b32015-08-27 18:21:14 +0900228static void decon_atomic_begin(struct exynos_drm_crtc *crtc,
229 struct exynos_drm_plane *plane)
230{
231 struct decon_context *ctx = crtc->ctx;
232
233 if (ctx->suspended)
234 return;
235
236 decon_shadow_protect_win(ctx, plane->zpos, true);
237}
238
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900239static void decon_update_plane(struct exynos_drm_crtc *crtc,
240 struct exynos_drm_plane *plane)
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900241{
242 struct decon_context *ctx = crtc->ctx;
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900243 struct drm_plane_state *state = plane->base.state;
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900244 unsigned int win = plane->zpos;
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900245 unsigned int bpp = state->fb->bits_per_pixel >> 3;
246 unsigned int pitch = state->fb->pitches[0];
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900247 u32 val;
248
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900249 if (ctx->suspended)
250 return;
251
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900252 val = COORDINATE_X(plane->crtc_x) | COORDINATE_Y(plane->crtc_y);
253 writel(val, ctx->addr + DECON_VIDOSDxA(win));
254
Gustavo Padovand88d2462015-07-16 12:23:38 -0300255 val = COORDINATE_X(plane->crtc_x + plane->crtc_w - 1) |
256 COORDINATE_Y(plane->crtc_y + plane->crtc_h - 1);
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900257 writel(val, ctx->addr + DECON_VIDOSDxB(win));
258
259 val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) |
260 VIDOSD_Wx_ALPHA_B_F(0x0);
261 writel(val, ctx->addr + DECON_VIDOSDxC(win));
262
263 val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) |
264 VIDOSD_Wx_ALPHA_B_F(0x0);
265 writel(val, ctx->addr + DECON_VIDOSDxD(win));
266
267 writel(plane->dma_addr[0], ctx->addr + DECON_VIDW0xADD0B0(win));
268
Gustavo Padovand88d2462015-07-16 12:23:38 -0300269 val = plane->dma_addr[0] + pitch * plane->crtc_h;
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900270 writel(val, ctx->addr + DECON_VIDW0xADD1B0(win));
271
Gustavo Padovand88d2462015-07-16 12:23:38 -0300272 val = OFFSIZE(pitch - plane->crtc_w * bpp)
273 | PAGEWIDTH(plane->crtc_w * bpp);
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900274 writel(val, ctx->addr + DECON_VIDW0xADD2(win));
275
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900276 decon_win_set_pixfmt(ctx, win, state->fb);
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900277
278 /* window enable */
279 val = readl(ctx->addr + DECON_WINCONx(win));
280 val |= WINCONx_ENWIN_F;
281 writel(val, ctx->addr + DECON_WINCONx(win));
282
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900283 /* standalone update */
284 val = readl(ctx->addr + DECON_UPDATE);
285 val |= STANDALONE_UPDATE_F;
286 writel(val, ctx->addr + DECON_UPDATE);
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900287}
288
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900289static void decon_disable_plane(struct exynos_drm_crtc *crtc,
290 struct exynos_drm_plane *plane)
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900291{
292 struct decon_context *ctx = crtc->ctx;
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900293 unsigned int win = plane->zpos;
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900294 u32 val;
295
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900296 if (ctx->suspended)
297 return;
298
299 decon_shadow_protect_win(ctx, win, true);
300
301 /* window disable */
302 val = readl(ctx->addr + DECON_WINCONx(win));
303 val &= ~WINCONx_ENWIN_F;
304 writel(val, ctx->addr + DECON_WINCONx(win));
305
306 decon_shadow_protect_win(ctx, win, false);
307
308 /* standalone update */
309 val = readl(ctx->addr + DECON_UPDATE);
310 val |= STANDALONE_UPDATE_F;
311 writel(val, ctx->addr + DECON_UPDATE);
312}
313
Hyungwon Hwangcc5a7b32015-08-27 18:21:14 +0900314static void decon_atomic_flush(struct exynos_drm_crtc *crtc,
315 struct exynos_drm_plane *plane)
316{
317 struct decon_context *ctx = crtc->ctx;
318
319 if (ctx->suspended)
320 return;
321
322 decon_shadow_protect_win(ctx, plane->zpos, false);
323
324 if (ctx->i80_if)
325 atomic_set(&ctx->win_updated, 1);
326}
327
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900328static void decon_swreset(struct decon_context *ctx)
329{
330 unsigned int tries;
331
332 writel(0, ctx->addr + DECON_VIDCON0);
333 for (tries = 2000; tries; --tries) {
334 if (~readl(ctx->addr + DECON_VIDCON0) & VIDCON0_STOP_STATUS)
335 break;
336 udelay(10);
337 }
338
339 WARN(tries == 0, "failed to disable DECON\n");
340
341 writel(VIDCON0_SWRESET, ctx->addr + DECON_VIDCON0);
342 for (tries = 2000; tries; --tries) {
343 if (~readl(ctx->addr + DECON_VIDCON0) & VIDCON0_SWRESET)
344 break;
345 udelay(10);
346 }
347
348 WARN(tries == 0, "failed to software reset DECON\n");
349}
350
351static void decon_enable(struct exynos_drm_crtc *crtc)
352{
353 struct decon_context *ctx = crtc->ctx;
354 int ret;
355 int i;
356
357 if (!ctx->suspended)
358 return;
359
360 ctx->suspended = false;
361
362 pm_runtime_get_sync(ctx->dev);
363
364 for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) {
365 ret = clk_prepare_enable(ctx->clks[i]);
366 if (ret < 0)
367 goto err;
368 }
369
370 set_bit(BIT_CLKS_ENABLED, &ctx->enabled);
371
372 /* if vblank was enabled status, enable it again. */
373 if (test_and_clear_bit(0, &ctx->irq_flags))
374 decon_enable_vblank(ctx->crtc);
375
376 decon_commit(ctx->crtc);
377
378 return;
379err:
380 while (--i >= 0)
381 clk_disable_unprepare(ctx->clks[i]);
382
383 ctx->suspended = true;
384}
385
386static void decon_disable(struct exynos_drm_crtc *crtc)
387{
388 struct decon_context *ctx = crtc->ctx;
389 int i;
390
391 if (ctx->suspended)
392 return;
393
394 /*
395 * We need to make sure that all windows are disabled before we
396 * suspend that connector. Otherwise we might try to scan from
397 * a destroyed buffer later.
398 */
399 for (i = 0; i < WINDOWS_NR; i++)
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900400 decon_disable_plane(crtc, &ctx->planes[i]);
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900401
402 decon_swreset(ctx);
403
404 for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++)
405 clk_disable_unprepare(ctx->clks[i]);
406
407 clear_bit(BIT_CLKS_ENABLED, &ctx->enabled);
408
409 pm_runtime_put_sync(ctx->dev);
410
411 ctx->suspended = true;
412}
413
414void decon_te_irq_handler(struct exynos_drm_crtc *crtc)
415{
416 struct decon_context *ctx = crtc->ctx;
417 u32 val;
418
419 if (!test_bit(BIT_CLKS_ENABLED, &ctx->enabled))
420 return;
421
422 if (atomic_add_unless(&ctx->win_updated, -1, 0)) {
423 /* trigger */
424 val = readl(ctx->addr + DECON_TRIGCON);
425 val |= TRIGCON_SWTRIGCMD;
426 writel(val, ctx->addr + DECON_TRIGCON);
427 }
428
Gustavo Padovaneafd5402015-07-16 12:23:32 -0300429 drm_crtc_handle_vblank(&ctx->crtc->base);
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900430}
431
432static void decon_clear_channels(struct exynos_drm_crtc *crtc)
433{
434 struct decon_context *ctx = crtc->ctx;
435 int win, i, ret;
436 u32 val;
437
438 DRM_DEBUG_KMS("%s\n", __FILE__);
439
440 for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) {
441 ret = clk_prepare_enable(ctx->clks[i]);
442 if (ret < 0)
443 goto err;
444 }
445
446 for (win = 0; win < WINDOWS_NR; win++) {
447 /* shadow update disable */
448 val = readl(ctx->addr + DECON_SHADOWCON);
449 val |= SHADOWCON_Wx_PROTECT(win);
450 writel(val, ctx->addr + DECON_SHADOWCON);
451
452 /* window disable */
453 val = readl(ctx->addr + DECON_WINCONx(win));
454 val &= ~WINCONx_ENWIN_F;
455 writel(val, ctx->addr + DECON_WINCONx(win));
456
457 /* shadow update enable */
458 val = readl(ctx->addr + DECON_SHADOWCON);
459 val &= ~SHADOWCON_Wx_PROTECT(win);
460 writel(val, ctx->addr + DECON_SHADOWCON);
461
462 /* standalone update */
463 val = readl(ctx->addr + DECON_UPDATE);
464 val |= STANDALONE_UPDATE_F;
465 writel(val, ctx->addr + DECON_UPDATE);
466 }
467 /* TODO: wait for possible vsync */
468 msleep(50);
469
470err:
471 while (--i >= 0)
472 clk_disable_unprepare(ctx->clks[i]);
473}
474
475static struct exynos_drm_crtc_ops decon_crtc_ops = {
476 .enable = decon_enable,
477 .disable = decon_disable,
478 .commit = decon_commit,
479 .enable_vblank = decon_enable_vblank,
480 .disable_vblank = decon_disable_vblank,
481 .commit = decon_commit,
Hyungwon Hwangcc5a7b32015-08-27 18:21:14 +0900482 .atomic_begin = decon_atomic_begin,
Gustavo Padovan9cc76102015-08-03 14:38:05 +0900483 .update_plane = decon_update_plane,
484 .disable_plane = decon_disable_plane,
Hyungwon Hwangcc5a7b32015-08-27 18:21:14 +0900485 .atomic_flush = decon_atomic_flush,
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900486 .te_handler = decon_te_irq_handler,
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900487};
488
489static int decon_bind(struct device *dev, struct device *master, void *data)
490{
491 struct decon_context *ctx = dev_get_drvdata(dev);
492 struct drm_device *drm_dev = data;
493 struct exynos_drm_private *priv = drm_dev->dev_private;
494 struct exynos_drm_plane *exynos_plane;
495 enum drm_plane_type type;
496 unsigned int zpos;
497 int ret;
498
499 ctx->drm_dev = drm_dev;
500 ctx->pipe = priv->pipe++;
501
502 for (zpos = 0; zpos < WINDOWS_NR; zpos++) {
Gustavo Padovan5d3d0992015-10-12 22:07:48 +0900503 type = (zpos == DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY :
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900504 DRM_PLANE_TYPE_OVERLAY;
505 ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
Marek Szyprowskifbbb1e12015-08-31 00:53:57 +0900506 1 << ctx->pipe, type, decon_formats,
507 ARRAY_SIZE(decon_formats), zpos);
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900508 if (ret)
509 return ret;
510 }
511
Gustavo Padovan5d3d0992015-10-12 22:07:48 +0900512 exynos_plane = &ctx->planes[DEFAULT_WIN];
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900513 ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
514 ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD,
515 &decon_crtc_ops, ctx);
516 if (IS_ERR(ctx->crtc)) {
517 ret = PTR_ERR(ctx->crtc);
518 goto err;
519 }
520
Joonyoung Shimeb7a3fc2015-07-02 21:49:39 +0900521 decon_clear_channels(ctx->crtc);
522
523 ret = drm_iommu_attach_device(drm_dev, dev);
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900524 if (ret)
525 goto err;
526
527 return ret;
528err:
529 priv->pipe--;
530 return ret;
531}
532
533static void decon_unbind(struct device *dev, struct device *master, void *data)
534{
535 struct decon_context *ctx = dev_get_drvdata(dev);
536
537 decon_disable(ctx->crtc);
538
539 /* detach this sub driver from iommu mapping if supported. */
Joonyoung Shimbf566082015-07-02 21:49:38 +0900540 drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900541}
542
543static const struct component_ops decon_component_ops = {
544 .bind = decon_bind,
545 .unbind = decon_unbind,
546};
547
548static irqreturn_t decon_vsync_irq_handler(int irq, void *dev_id)
549{
550 struct decon_context *ctx = dev_id;
551 u32 val;
552
553 if (!test_bit(BIT_CLKS_ENABLED, &ctx->enabled))
554 goto out;
555
556 val = readl(ctx->addr + DECON_VIDINTCON1);
557 if (val & VIDINTCON1_INTFRMPEND) {
Gustavo Padovaneafd5402015-07-16 12:23:32 -0300558 drm_crtc_handle_vblank(&ctx->crtc->base);
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900559
560 /* clear */
561 writel(VIDINTCON1_INTFRMPEND, ctx->addr + DECON_VIDINTCON1);
562 }
563
564out:
565 return IRQ_HANDLED;
566}
567
568static irqreturn_t decon_lcd_sys_irq_handler(int irq, void *dev_id)
569{
570 struct decon_context *ctx = dev_id;
571 u32 val;
Gustavo Padovan822f6df2015-08-15 13:26:14 -0300572 int win;
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900573
574 if (!test_bit(BIT_CLKS_ENABLED, &ctx->enabled))
575 goto out;
576
577 val = readl(ctx->addr + DECON_VIDINTCON1);
578 if (val & VIDINTCON1_INTFRMDONEPEND) {
Gustavo Padovan822f6df2015-08-15 13:26:14 -0300579 for (win = 0 ; win < WINDOWS_NR ; win++) {
580 struct exynos_drm_plane *plane = &ctx->planes[win];
581
582 if (!plane->pending_fb)
583 continue;
584
585 exynos_drm_crtc_finish_update(ctx->crtc, plane);
586 }
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900587
588 /* clear */
589 writel(VIDINTCON1_INTFRMDONEPEND,
590 ctx->addr + DECON_VIDINTCON1);
591 }
592
593out:
594 return IRQ_HANDLED;
595}
596
597static int exynos5433_decon_probe(struct platform_device *pdev)
598{
599 struct device *dev = &pdev->dev;
600 struct decon_context *ctx;
601 struct resource *res;
602 int ret;
603 int i;
604
605 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
606 if (!ctx)
607 return -ENOMEM;
608
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900609 ctx->suspended = true;
610 ctx->dev = dev;
611 if (of_get_child_by_name(dev->of_node, "i80-if-timings"))
612 ctx->i80_if = true;
613
614 for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) {
615 struct clk *clk;
616
617 clk = devm_clk_get(ctx->dev, decon_clks_name[i]);
618 if (IS_ERR(clk))
619 return PTR_ERR(clk);
620
621 ctx->clks[i] = clk;
622 }
623
624 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
625 if (!res) {
626 dev_err(dev, "cannot find IO resource\n");
627 return -ENXIO;
628 }
629
630 ctx->addr = devm_ioremap_resource(dev, res);
631 if (IS_ERR(ctx->addr)) {
632 dev_err(dev, "ioremap failed\n");
633 return PTR_ERR(ctx->addr);
634 }
635
636 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
637 ctx->i80_if ? "lcd_sys" : "vsync");
638 if (!res) {
639 dev_err(dev, "cannot find IRQ resource\n");
640 return -ENXIO;
641 }
642
643 ret = devm_request_irq(dev, res->start, ctx->i80_if ?
644 decon_lcd_sys_irq_handler : decon_vsync_irq_handler, 0,
645 "drm_decon", ctx);
646 if (ret < 0) {
647 dev_err(dev, "lcd_sys irq request failed\n");
648 return ret;
649 }
650
651 platform_set_drvdata(pdev, ctx);
652
653 pm_runtime_enable(dev);
654
655 ret = component_add(dev, &decon_component_ops);
656 if (ret)
657 goto err_disable_pm_runtime;
658
659 return 0;
660
661err_disable_pm_runtime:
662 pm_runtime_disable(dev);
663
664 return ret;
665}
666
667static int exynos5433_decon_remove(struct platform_device *pdev)
668{
669 pm_runtime_disable(&pdev->dev);
670
671 component_del(&pdev->dev, &decon_component_ops);
672
673 return 0;
674}
675
676static const struct of_device_id exynos5433_decon_driver_dt_match[] = {
677 { .compatible = "samsung,exynos5433-decon" },
678 {},
679};
680MODULE_DEVICE_TABLE(of, exynos5433_decon_driver_dt_match);
681
682struct platform_driver exynos5433_decon_driver = {
683 .probe = exynos5433_decon_probe,
684 .remove = exynos5433_decon_remove,
685 .driver = {
686 .name = "exynos5433-decon",
687 .of_match_table = exynos5433_decon_driver_dt_match,
688 },
689};