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