blob: 2489e7a0a3d24684286e4655cb7ba5141a2a2360 [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];
36 unsigned int default_win;
37 unsigned long irq_flags;
38 int pipe;
39 bool suspended;
40
41#define BIT_CLKS_ENABLED 0
42#define BIT_IRQS_ENABLED 1
43 unsigned long enabled;
44 bool i80_if;
45 atomic_t win_updated;
46};
47
48static const char * const decon_clks_name[] = {
49 "aclk_decon",
50 "aclk_smmu_decon0x",
51 "aclk_xiu_decon0x",
52 "pclk_smmu_decon0x",
53 "sclk_decon_vclk",
54 "sclk_decon_eclk",
55};
56
57static int decon_enable_vblank(struct exynos_drm_crtc *crtc)
58{
59 struct decon_context *ctx = crtc->ctx;
60 u32 val;
61
62 if (ctx->suspended)
63 return -EPERM;
64
65 if (test_and_set_bit(0, &ctx->irq_flags)) {
66 val = VIDINTCON0_INTEN;
67 if (ctx->i80_if)
68 val |= VIDINTCON0_FRAMEDONE;
69 else
70 val |= VIDINTCON0_INTFRMEN;
71
72 writel(val, ctx->addr + DECON_VIDINTCON0);
73 }
74
75 return 0;
76}
77
78static void decon_disable_vblank(struct exynos_drm_crtc *crtc)
79{
80 struct decon_context *ctx = crtc->ctx;
81
82 if (ctx->suspended)
83 return;
84
85 if (test_and_clear_bit(0, &ctx->irq_flags))
86 writel(0, ctx->addr + DECON_VIDINTCON0);
87}
88
89static void decon_setup_trigger(struct decon_context *ctx)
90{
91 u32 val = TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F |
92 TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN;
93 writel(val, ctx->addr + DECON_TRIGCON);
94}
95
96static void decon_commit(struct exynos_drm_crtc *crtc)
97{
98 struct decon_context *ctx = crtc->ctx;
99 struct drm_display_mode *mode = &crtc->base.mode;
100 u32 val;
101
102 if (ctx->suspended)
103 return;
104
105 /* enable clock gate */
106 val = CMU_CLKGAGE_MODE_SFR_F | CMU_CLKGAGE_MODE_MEM_F;
107 writel(val, ctx->addr + DECON_CMU);
108
109 /* lcd on and use command if */
110 val = VIDOUT_LCD_ON;
111 if (ctx->i80_if)
112 val |= VIDOUT_COMMAND_IF;
113 else
114 val |= VIDOUT_RGB_IF;
115 writel(val, ctx->addr + DECON_VIDOUTCON0);
116
117 val = VIDTCON2_LINEVAL(mode->vdisplay - 1) |
118 VIDTCON2_HOZVAL(mode->hdisplay - 1);
119 writel(val, ctx->addr + DECON_VIDTCON2);
120
121 if (!ctx->i80_if) {
122 val = VIDTCON00_VBPD_F(
123 mode->crtc_vtotal - mode->crtc_vsync_end) |
124 VIDTCON00_VFPD_F(
125 mode->crtc_vsync_start - mode->crtc_vdisplay);
126 writel(val, ctx->addr + DECON_VIDTCON00);
127
128 val = VIDTCON01_VSPW_F(
129 mode->crtc_vsync_end - mode->crtc_vsync_start);
130 writel(val, ctx->addr + DECON_VIDTCON01);
131
132 val = VIDTCON10_HBPD_F(
133 mode->crtc_htotal - mode->crtc_hsync_end) |
134 VIDTCON10_HFPD_F(
135 mode->crtc_hsync_start - mode->crtc_hdisplay);
136 writel(val, ctx->addr + DECON_VIDTCON10);
137
138 val = VIDTCON11_HSPW_F(
139 mode->crtc_hsync_end - mode->crtc_hsync_start);
140 writel(val, ctx->addr + DECON_VIDTCON11);
141 }
142
143 decon_setup_trigger(ctx);
144
145 /* enable output and display signal */
146 val = VIDCON0_ENVID | VIDCON0_ENVID_F;
147 writel(val, ctx->addr + DECON_VIDCON0);
148}
149
150#define COORDINATE_X(x) (((x) & 0xfff) << 12)
151#define COORDINATE_Y(x) ((x) & 0xfff)
152#define OFFSIZE(x) (((x) & 0x3fff) << 14)
153#define PAGEWIDTH(x) ((x) & 0x3fff)
154
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900155static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
156 struct drm_framebuffer *fb)
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900157{
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900158 unsigned long val;
159
160 val = readl(ctx->addr + DECON_WINCONx(win));
161 val &= ~WINCONx_BPPMODE_MASK;
162
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900163 switch (fb->pixel_format) {
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900164 case DRM_FORMAT_XRGB1555:
165 val |= WINCONx_BPPMODE_16BPP_I1555;
166 val |= WINCONx_HAWSWP_F;
167 val |= WINCONx_BURSTLEN_16WORD;
168 break;
169 case DRM_FORMAT_RGB565:
170 val |= WINCONx_BPPMODE_16BPP_565;
171 val |= WINCONx_HAWSWP_F;
172 val |= WINCONx_BURSTLEN_16WORD;
173 break;
174 case DRM_FORMAT_XRGB8888:
175 val |= WINCONx_BPPMODE_24BPP_888;
176 val |= WINCONx_WSWP_F;
177 val |= WINCONx_BURSTLEN_16WORD;
178 break;
179 case DRM_FORMAT_ARGB8888:
180 val |= WINCONx_BPPMODE_32BPP_A8888;
181 val |= WINCONx_WSWP_F | WINCONx_BLD_PIX_F | WINCONx_ALPHA_SEL_F;
182 val |= WINCONx_BURSTLEN_16WORD;
183 break;
184 default:
185 DRM_ERROR("Proper pixel format is not set\n");
186 return;
187 }
188
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900189 DRM_DEBUG_KMS("bpp = %u\n", fb->bits_per_pixel);
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900190
191 /*
192 * In case of exynos, setting dma-burst to 16Word causes permanent
193 * tearing for very small buffers, e.g. cursor buffer. Burst Mode
194 * switching which is based on plane size is not recommended as
195 * plane size varies a lot towards the end of the screen and rapid
196 * movement causes unstable DMA which results into iommu crash/tear.
197 */
198
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900199 if (fb->width < MIN_FB_WIDTH_FOR_16WORD_BURST) {
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900200 val &= ~WINCONx_BURSTLEN_MASK;
201 val |= WINCONx_BURSTLEN_8WORD;
202 }
203
204 writel(val, ctx->addr + DECON_WINCONx(win));
205}
206
207static void decon_shadow_protect_win(struct decon_context *ctx, int win,
208 bool protect)
209{
210 u32 val;
211
212 val = readl(ctx->addr + DECON_SHADOWCON);
213
214 if (protect)
215 val |= SHADOWCON_Wx_PROTECT(win);
216 else
217 val &= ~SHADOWCON_Wx_PROTECT(win);
218
219 writel(val, ctx->addr + DECON_SHADOWCON);
220}
221
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900222static void decon_update_plane(struct exynos_drm_crtc *crtc,
223 struct exynos_drm_plane *plane)
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900224{
225 struct decon_context *ctx = crtc->ctx;
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900226 struct drm_plane_state *state = plane->base.state;
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900227 unsigned int win = plane->zpos;
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900228 unsigned int bpp = state->fb->bits_per_pixel >> 3;
229 unsigned int pitch = state->fb->pitches[0];
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900230 u32 val;
231
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900232 if (ctx->suspended)
233 return;
234
235 decon_shadow_protect_win(ctx, win, true);
236
237 val = COORDINATE_X(plane->crtc_x) | COORDINATE_Y(plane->crtc_y);
238 writel(val, ctx->addr + DECON_VIDOSDxA(win));
239
240 val = COORDINATE_X(plane->crtc_x + plane->crtc_width - 1) |
241 COORDINATE_Y(plane->crtc_y + plane->crtc_height - 1);
242 writel(val, ctx->addr + DECON_VIDOSDxB(win));
243
244 val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) |
245 VIDOSD_Wx_ALPHA_B_F(0x0);
246 writel(val, ctx->addr + DECON_VIDOSDxC(win));
247
248 val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) |
249 VIDOSD_Wx_ALPHA_B_F(0x0);
250 writel(val, ctx->addr + DECON_VIDOSDxD(win));
251
252 writel(plane->dma_addr[0], ctx->addr + DECON_VIDW0xADD0B0(win));
253
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900254 val = plane->dma_addr[0] + pitch * plane->crtc_height;
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900255 writel(val, ctx->addr + DECON_VIDW0xADD1B0(win));
256
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900257 val = OFFSIZE(pitch - plane->crtc_width * bpp)
258 | PAGEWIDTH(plane->crtc_width * bpp);
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900259 writel(val, ctx->addr + DECON_VIDW0xADD2(win));
260
Gustavo Padovan2eeb2e52015-08-03 14:40:44 +0900261 decon_win_set_pixfmt(ctx, win, state->fb);
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900262
263 /* window enable */
264 val = readl(ctx->addr + DECON_WINCONx(win));
265 val |= WINCONx_ENWIN_F;
266 writel(val, ctx->addr + DECON_WINCONx(win));
267
268 decon_shadow_protect_win(ctx, win, false);
269
270 /* standalone update */
271 val = readl(ctx->addr + DECON_UPDATE);
272 val |= STANDALONE_UPDATE_F;
273 writel(val, ctx->addr + DECON_UPDATE);
274
275 if (ctx->i80_if)
276 atomic_set(&ctx->win_updated, 1);
277}
278
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900279static void decon_disable_plane(struct exynos_drm_crtc *crtc,
280 struct exynos_drm_plane *plane)
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900281{
282 struct decon_context *ctx = crtc->ctx;
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900283 unsigned int win = plane->zpos;
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900284 u32 val;
285
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900286 if (ctx->suspended)
287 return;
288
289 decon_shadow_protect_win(ctx, win, true);
290
291 /* window disable */
292 val = readl(ctx->addr + DECON_WINCONx(win));
293 val &= ~WINCONx_ENWIN_F;
294 writel(val, ctx->addr + DECON_WINCONx(win));
295
296 decon_shadow_protect_win(ctx, win, false);
297
298 /* standalone update */
299 val = readl(ctx->addr + DECON_UPDATE);
300 val |= STANDALONE_UPDATE_F;
301 writel(val, ctx->addr + DECON_UPDATE);
302}
303
304static void decon_swreset(struct decon_context *ctx)
305{
306 unsigned int tries;
307
308 writel(0, ctx->addr + DECON_VIDCON0);
309 for (tries = 2000; tries; --tries) {
310 if (~readl(ctx->addr + DECON_VIDCON0) & VIDCON0_STOP_STATUS)
311 break;
312 udelay(10);
313 }
314
315 WARN(tries == 0, "failed to disable DECON\n");
316
317 writel(VIDCON0_SWRESET, ctx->addr + DECON_VIDCON0);
318 for (tries = 2000; tries; --tries) {
319 if (~readl(ctx->addr + DECON_VIDCON0) & VIDCON0_SWRESET)
320 break;
321 udelay(10);
322 }
323
324 WARN(tries == 0, "failed to software reset DECON\n");
325}
326
327static void decon_enable(struct exynos_drm_crtc *crtc)
328{
329 struct decon_context *ctx = crtc->ctx;
330 int ret;
331 int i;
332
333 if (!ctx->suspended)
334 return;
335
336 ctx->suspended = false;
337
338 pm_runtime_get_sync(ctx->dev);
339
340 for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) {
341 ret = clk_prepare_enable(ctx->clks[i]);
342 if (ret < 0)
343 goto err;
344 }
345
346 set_bit(BIT_CLKS_ENABLED, &ctx->enabled);
347
348 /* if vblank was enabled status, enable it again. */
349 if (test_and_clear_bit(0, &ctx->irq_flags))
350 decon_enable_vblank(ctx->crtc);
351
352 decon_commit(ctx->crtc);
353
354 return;
355err:
356 while (--i >= 0)
357 clk_disable_unprepare(ctx->clks[i]);
358
359 ctx->suspended = true;
360}
361
362static void decon_disable(struct exynos_drm_crtc *crtc)
363{
364 struct decon_context *ctx = crtc->ctx;
365 int i;
366
367 if (ctx->suspended)
368 return;
369
370 /*
371 * We need to make sure that all windows are disabled before we
372 * suspend that connector. Otherwise we might try to scan from
373 * a destroyed buffer later.
374 */
375 for (i = 0; i < WINDOWS_NR; i++)
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900376 decon_disable_plane(crtc, &ctx->planes[i]);
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900377
378 decon_swreset(ctx);
379
380 for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++)
381 clk_disable_unprepare(ctx->clks[i]);
382
383 clear_bit(BIT_CLKS_ENABLED, &ctx->enabled);
384
385 pm_runtime_put_sync(ctx->dev);
386
387 ctx->suspended = true;
388}
389
390void decon_te_irq_handler(struct exynos_drm_crtc *crtc)
391{
392 struct decon_context *ctx = crtc->ctx;
393 u32 val;
394
395 if (!test_bit(BIT_CLKS_ENABLED, &ctx->enabled))
396 return;
397
398 if (atomic_add_unless(&ctx->win_updated, -1, 0)) {
399 /* trigger */
400 val = readl(ctx->addr + DECON_TRIGCON);
401 val |= TRIGCON_SWTRIGCMD;
402 writel(val, ctx->addr + DECON_TRIGCON);
403 }
404
Gustavo Padovaneafd5402015-07-16 12:23:32 -0300405 drm_crtc_handle_vblank(&ctx->crtc->base);
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900406}
407
408static void decon_clear_channels(struct exynos_drm_crtc *crtc)
409{
410 struct decon_context *ctx = crtc->ctx;
411 int win, i, ret;
412 u32 val;
413
414 DRM_DEBUG_KMS("%s\n", __FILE__);
415
416 for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) {
417 ret = clk_prepare_enable(ctx->clks[i]);
418 if (ret < 0)
419 goto err;
420 }
421
422 for (win = 0; win < WINDOWS_NR; win++) {
423 /* shadow update disable */
424 val = readl(ctx->addr + DECON_SHADOWCON);
425 val |= SHADOWCON_Wx_PROTECT(win);
426 writel(val, ctx->addr + DECON_SHADOWCON);
427
428 /* window disable */
429 val = readl(ctx->addr + DECON_WINCONx(win));
430 val &= ~WINCONx_ENWIN_F;
431 writel(val, ctx->addr + DECON_WINCONx(win));
432
433 /* shadow update enable */
434 val = readl(ctx->addr + DECON_SHADOWCON);
435 val &= ~SHADOWCON_Wx_PROTECT(win);
436 writel(val, ctx->addr + DECON_SHADOWCON);
437
438 /* standalone update */
439 val = readl(ctx->addr + DECON_UPDATE);
440 val |= STANDALONE_UPDATE_F;
441 writel(val, ctx->addr + DECON_UPDATE);
442 }
443 /* TODO: wait for possible vsync */
444 msleep(50);
445
446err:
447 while (--i >= 0)
448 clk_disable_unprepare(ctx->clks[i]);
449}
450
451static struct exynos_drm_crtc_ops decon_crtc_ops = {
452 .enable = decon_enable,
453 .disable = decon_disable,
454 .commit = decon_commit,
455 .enable_vblank = decon_enable_vblank,
456 .disable_vblank = decon_disable_vblank,
457 .commit = decon_commit,
Gustavo Padovan9cc76102015-08-03 14:38:05 +0900458 .update_plane = decon_update_plane,
459 .disable_plane = decon_disable_plane,
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900460 .te_handler = decon_te_irq_handler,
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900461};
462
463static int decon_bind(struct device *dev, struct device *master, void *data)
464{
465 struct decon_context *ctx = dev_get_drvdata(dev);
466 struct drm_device *drm_dev = data;
467 struct exynos_drm_private *priv = drm_dev->dev_private;
468 struct exynos_drm_plane *exynos_plane;
469 enum drm_plane_type type;
470 unsigned int zpos;
471 int ret;
472
473 ctx->drm_dev = drm_dev;
474 ctx->pipe = priv->pipe++;
475
476 for (zpos = 0; zpos < WINDOWS_NR; zpos++) {
477 type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY :
478 DRM_PLANE_TYPE_OVERLAY;
479 ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
480 1 << ctx->pipe, type, zpos);
481 if (ret)
482 return ret;
483 }
484
485 exynos_plane = &ctx->planes[ctx->default_win];
486 ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
487 ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD,
488 &decon_crtc_ops, ctx);
489 if (IS_ERR(ctx->crtc)) {
490 ret = PTR_ERR(ctx->crtc);
491 goto err;
492 }
493
Joonyoung Shimeb7a3fc2015-07-02 21:49:39 +0900494 decon_clear_channels(ctx->crtc);
495
496 ret = drm_iommu_attach_device(drm_dev, dev);
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900497 if (ret)
498 goto err;
499
500 return ret;
501err:
502 priv->pipe--;
503 return ret;
504}
505
506static void decon_unbind(struct device *dev, struct device *master, void *data)
507{
508 struct decon_context *ctx = dev_get_drvdata(dev);
509
510 decon_disable(ctx->crtc);
511
512 /* detach this sub driver from iommu mapping if supported. */
Joonyoung Shimbf566082015-07-02 21:49:38 +0900513 drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900514}
515
516static const struct component_ops decon_component_ops = {
517 .bind = decon_bind,
518 .unbind = decon_unbind,
519};
520
521static irqreturn_t decon_vsync_irq_handler(int irq, void *dev_id)
522{
523 struct decon_context *ctx = dev_id;
524 u32 val;
525
526 if (!test_bit(BIT_CLKS_ENABLED, &ctx->enabled))
527 goto out;
528
529 val = readl(ctx->addr + DECON_VIDINTCON1);
530 if (val & VIDINTCON1_INTFRMPEND) {
Gustavo Padovaneafd5402015-07-16 12:23:32 -0300531 drm_crtc_handle_vblank(&ctx->crtc->base);
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900532
533 /* clear */
534 writel(VIDINTCON1_INTFRMPEND, ctx->addr + DECON_VIDINTCON1);
535 }
536
537out:
538 return IRQ_HANDLED;
539}
540
541static irqreturn_t decon_lcd_sys_irq_handler(int irq, void *dev_id)
542{
543 struct decon_context *ctx = dev_id;
544 u32 val;
545
546 if (!test_bit(BIT_CLKS_ENABLED, &ctx->enabled))
547 goto out;
548
549 val = readl(ctx->addr + DECON_VIDINTCON1);
550 if (val & VIDINTCON1_INTFRMDONEPEND) {
Gustavo Padovaneafd5402015-07-16 12:23:32 -0300551 exynos_drm_crtc_finish_pageflip(ctx->crtc);
Joonyoung Shimc8466a92015-06-12 21:59:00 +0900552
553 /* clear */
554 writel(VIDINTCON1_INTFRMDONEPEND,
555 ctx->addr + DECON_VIDINTCON1);
556 }
557
558out:
559 return IRQ_HANDLED;
560}
561
562static int exynos5433_decon_probe(struct platform_device *pdev)
563{
564 struct device *dev = &pdev->dev;
565 struct decon_context *ctx;
566 struct resource *res;
567 int ret;
568 int i;
569
570 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
571 if (!ctx)
572 return -ENOMEM;
573
574 ctx->default_win = 0;
575 ctx->suspended = true;
576 ctx->dev = dev;
577 if (of_get_child_by_name(dev->of_node, "i80-if-timings"))
578 ctx->i80_if = true;
579
580 for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) {
581 struct clk *clk;
582
583 clk = devm_clk_get(ctx->dev, decon_clks_name[i]);
584 if (IS_ERR(clk))
585 return PTR_ERR(clk);
586
587 ctx->clks[i] = clk;
588 }
589
590 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
591 if (!res) {
592 dev_err(dev, "cannot find IO resource\n");
593 return -ENXIO;
594 }
595
596 ctx->addr = devm_ioremap_resource(dev, res);
597 if (IS_ERR(ctx->addr)) {
598 dev_err(dev, "ioremap failed\n");
599 return PTR_ERR(ctx->addr);
600 }
601
602 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
603 ctx->i80_if ? "lcd_sys" : "vsync");
604 if (!res) {
605 dev_err(dev, "cannot find IRQ resource\n");
606 return -ENXIO;
607 }
608
609 ret = devm_request_irq(dev, res->start, ctx->i80_if ?
610 decon_lcd_sys_irq_handler : decon_vsync_irq_handler, 0,
611 "drm_decon", ctx);
612 if (ret < 0) {
613 dev_err(dev, "lcd_sys irq request failed\n");
614 return ret;
615 }
616
617 platform_set_drvdata(pdev, ctx);
618
619 pm_runtime_enable(dev);
620
621 ret = component_add(dev, &decon_component_ops);
622 if (ret)
623 goto err_disable_pm_runtime;
624
625 return 0;
626
627err_disable_pm_runtime:
628 pm_runtime_disable(dev);
629
630 return ret;
631}
632
633static int exynos5433_decon_remove(struct platform_device *pdev)
634{
635 pm_runtime_disable(&pdev->dev);
636
637 component_del(&pdev->dev, &decon_component_ops);
638
639 return 0;
640}
641
642static const struct of_device_id exynos5433_decon_driver_dt_match[] = {
643 { .compatible = "samsung,exynos5433-decon" },
644 {},
645};
646MODULE_DEVICE_TABLE(of, exynos5433_decon_driver_dt_match);
647
648struct platform_driver exynos5433_decon_driver = {
649 .probe = exynos5433_decon_probe,
650 .remove = exynos5433_decon_remove,
651 .driver = {
652 .name = "exynos5433-decon",
653 .of_match_table = exynos5433_decon_driver_dt_match,
654 },
655};