1c8466a91SJoonyoung Shim /* drivers/gpu/drm/exynos5433_drm_decon.c 2c8466a91SJoonyoung Shim * 3c8466a91SJoonyoung Shim * Copyright (C) 2015 Samsung Electronics Co.Ltd 4c8466a91SJoonyoung Shim * Authors: 5c8466a91SJoonyoung Shim * Joonyoung Shim <jy0922.shim@samsung.com> 6c8466a91SJoonyoung Shim * Hyungwon Hwang <human.hwang@samsung.com> 7c8466a91SJoonyoung Shim * 8c8466a91SJoonyoung Shim * This program is free software; you can redistribute it and/or modify 9c8466a91SJoonyoung Shim * it under the terms of the GNU General Public License version 2 as 10c8466a91SJoonyoung Shim * published by the Free Software Foundationr 11c8466a91SJoonyoung Shim */ 12c8466a91SJoonyoung Shim 13c8466a91SJoonyoung Shim #include <linux/platform_device.h> 14c8466a91SJoonyoung Shim #include <linux/clk.h> 15c8466a91SJoonyoung Shim #include <linux/component.h> 16b8182832SAndrzej Hajda #include <linux/of_device.h> 17c8466a91SJoonyoung Shim #include <linux/of_gpio.h> 18c8466a91SJoonyoung Shim #include <linux/pm_runtime.h> 19c8466a91SJoonyoung Shim 20c8466a91SJoonyoung Shim #include <video/exynos5433_decon.h> 21c8466a91SJoonyoung Shim 22c8466a91SJoonyoung Shim #include "exynos_drm_drv.h" 23c8466a91SJoonyoung Shim #include "exynos_drm_crtc.h" 24c8466a91SJoonyoung Shim #include "exynos_drm_plane.h" 25c8466a91SJoonyoung Shim #include "exynos_drm_iommu.h" 26c8466a91SJoonyoung Shim 27c8466a91SJoonyoung Shim #define WINDOWS_NR 3 28323db0edSGustavo Padovan #define CURSOR_WIN 2 29c8466a91SJoonyoung Shim #define MIN_FB_WIDTH_FOR_16WORD_BURST 128 30c8466a91SJoonyoung Shim 314f54f21cSAndrzej Hajda static const char * const decon_clks_name[] = { 324f54f21cSAndrzej Hajda "pclk", 334f54f21cSAndrzej Hajda "aclk_decon", 344f54f21cSAndrzej Hajda "aclk_smmu_decon0x", 354f54f21cSAndrzej Hajda "aclk_xiu_decon0x", 364f54f21cSAndrzej Hajda "pclk_smmu_decon0x", 374f54f21cSAndrzej Hajda "sclk_decon_vclk", 384f54f21cSAndrzej Hajda "sclk_decon_eclk", 394f54f21cSAndrzej Hajda }; 404f54f21cSAndrzej Hajda 41b8182832SAndrzej Hajda enum decon_iftype { 42b8182832SAndrzej Hajda IFTYPE_RGB, 43b8182832SAndrzej Hajda IFTYPE_I80, 44b8182832SAndrzej Hajda IFTYPE_HDMI 45b8182832SAndrzej Hajda }; 46b8182832SAndrzej Hajda 477b6bb6edSAndrzej Hajda enum decon_flag_bits { 487b6bb6edSAndrzej Hajda BIT_CLKS_ENABLED, 497b6bb6edSAndrzej Hajda BIT_IRQS_ENABLED, 507b6bb6edSAndrzej Hajda BIT_WIN_UPDATED, 517b6bb6edSAndrzej Hajda BIT_SUSPENDED 527b6bb6edSAndrzej Hajda }; 537b6bb6edSAndrzej Hajda 54c8466a91SJoonyoung Shim struct decon_context { 55c8466a91SJoonyoung Shim struct device *dev; 56c8466a91SJoonyoung Shim struct drm_device *drm_dev; 57c8466a91SJoonyoung Shim struct exynos_drm_crtc *crtc; 58c8466a91SJoonyoung Shim struct exynos_drm_plane planes[WINDOWS_NR]; 59c8466a91SJoonyoung Shim void __iomem *addr; 604f54f21cSAndrzej Hajda struct clk *clks[ARRAY_SIZE(decon_clks_name)]; 61c8466a91SJoonyoung Shim int pipe; 627b6bb6edSAndrzej Hajda unsigned long flags; 63b8182832SAndrzej Hajda enum decon_iftype out_type; 64b8182832SAndrzej Hajda int first_win; 65c8466a91SJoonyoung Shim }; 66c8466a91SJoonyoung Shim 67fbbb1e1aSMarek Szyprowski static const uint32_t decon_formats[] = { 68fbbb1e1aSMarek Szyprowski DRM_FORMAT_XRGB1555, 69fbbb1e1aSMarek Szyprowski DRM_FORMAT_RGB565, 70fbbb1e1aSMarek Szyprowski DRM_FORMAT_XRGB8888, 71fbbb1e1aSMarek Szyprowski DRM_FORMAT_ARGB8888, 72fbbb1e1aSMarek Szyprowski }; 73fbbb1e1aSMarek Szyprowski 74b2192073SAndrzej Hajda static inline void decon_set_bits(struct decon_context *ctx, u32 reg, u32 mask, 75b2192073SAndrzej Hajda u32 val) 76b2192073SAndrzej Hajda { 77b2192073SAndrzej Hajda val = (val & mask) | (readl(ctx->addr + reg) & ~mask); 78b2192073SAndrzej Hajda writel(val, ctx->addr + reg); 79b2192073SAndrzej Hajda } 80b2192073SAndrzej Hajda 81c8466a91SJoonyoung Shim static int decon_enable_vblank(struct exynos_drm_crtc *crtc) 82c8466a91SJoonyoung Shim { 83c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 84c8466a91SJoonyoung Shim u32 val; 85c8466a91SJoonyoung Shim 867b6bb6edSAndrzej Hajda if (test_bit(BIT_SUSPENDED, &ctx->flags)) 87c8466a91SJoonyoung Shim return -EPERM; 88c8466a91SJoonyoung Shim 897b6bb6edSAndrzej Hajda if (test_and_set_bit(BIT_IRQS_ENABLED, &ctx->flags)) { 90c8466a91SJoonyoung Shim val = VIDINTCON0_INTEN; 91b8182832SAndrzej Hajda if (ctx->out_type == IFTYPE_I80) 92c8466a91SJoonyoung Shim val |= VIDINTCON0_FRAMEDONE; 93c8466a91SJoonyoung Shim else 94c8466a91SJoonyoung Shim val |= VIDINTCON0_INTFRMEN; 95c8466a91SJoonyoung Shim 96c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDINTCON0); 97c8466a91SJoonyoung Shim } 98c8466a91SJoonyoung Shim 99c8466a91SJoonyoung Shim return 0; 100c8466a91SJoonyoung Shim } 101c8466a91SJoonyoung Shim 102c8466a91SJoonyoung Shim static void decon_disable_vblank(struct exynos_drm_crtc *crtc) 103c8466a91SJoonyoung Shim { 104c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 105c8466a91SJoonyoung Shim 1067b6bb6edSAndrzej Hajda if (test_bit(BIT_SUSPENDED, &ctx->flags)) 107c8466a91SJoonyoung Shim return; 108c8466a91SJoonyoung Shim 1097b6bb6edSAndrzej Hajda if (test_and_clear_bit(BIT_IRQS_ENABLED, &ctx->flags)) 110c8466a91SJoonyoung Shim writel(0, ctx->addr + DECON_VIDINTCON0); 111c8466a91SJoonyoung Shim } 112c8466a91SJoonyoung Shim 113c8466a91SJoonyoung Shim static void decon_setup_trigger(struct decon_context *ctx) 114c8466a91SJoonyoung Shim { 115b8182832SAndrzej Hajda u32 val = (ctx->out_type != IFTYPE_HDMI) 116b8182832SAndrzej Hajda ? TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F | 117b8182832SAndrzej Hajda TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN 118b8182832SAndrzej Hajda : TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F | 119b8182832SAndrzej Hajda TRIGCON_HWTRIGMASK_I80_RGB | TRIGCON_HWTRIGEN_I80_RGB; 120c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_TRIGCON); 121c8466a91SJoonyoung Shim } 122c8466a91SJoonyoung Shim 123c8466a91SJoonyoung Shim static void decon_commit(struct exynos_drm_crtc *crtc) 124c8466a91SJoonyoung Shim { 125c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 12685de275aSAndrzej Hajda struct drm_display_mode *m = &crtc->base.mode; 127c8466a91SJoonyoung Shim u32 val; 128c8466a91SJoonyoung Shim 1297b6bb6edSAndrzej Hajda if (test_bit(BIT_SUSPENDED, &ctx->flags)) 130c8466a91SJoonyoung Shim return; 131c8466a91SJoonyoung Shim 132b8182832SAndrzej Hajda if (ctx->out_type == IFTYPE_HDMI) { 133b8182832SAndrzej Hajda m->crtc_hsync_start = m->crtc_hdisplay + 10; 134b8182832SAndrzej Hajda m->crtc_hsync_end = m->crtc_htotal - 92; 135b8182832SAndrzej Hajda m->crtc_vsync_start = m->crtc_vdisplay + 1; 136b8182832SAndrzej Hajda m->crtc_vsync_end = m->crtc_vsync_start + 1; 137b8182832SAndrzej Hajda } 138b8182832SAndrzej Hajda 139b8182832SAndrzej Hajda decon_set_bits(ctx, DECON_VIDCON0, VIDCON0_ENVID, 0); 140b8182832SAndrzej Hajda 141c8466a91SJoonyoung Shim /* enable clock gate */ 142c8466a91SJoonyoung Shim val = CMU_CLKGAGE_MODE_SFR_F | CMU_CLKGAGE_MODE_MEM_F; 143c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_CMU); 144c8466a91SJoonyoung Shim 145c8466a91SJoonyoung Shim /* lcd on and use command if */ 146c8466a91SJoonyoung Shim val = VIDOUT_LCD_ON; 147b8182832SAndrzej Hajda if (ctx->out_type == IFTYPE_I80) 148c8466a91SJoonyoung Shim val |= VIDOUT_COMMAND_IF; 149c8466a91SJoonyoung Shim else 150c8466a91SJoonyoung Shim val |= VIDOUT_RGB_IF; 151c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDOUTCON0); 152c8466a91SJoonyoung Shim 15385de275aSAndrzej Hajda val = VIDTCON2_LINEVAL(m->vdisplay - 1) | 15485de275aSAndrzej Hajda VIDTCON2_HOZVAL(m->hdisplay - 1); 155c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDTCON2); 156c8466a91SJoonyoung Shim 157b8182832SAndrzej Hajda if (ctx->out_type != IFTYPE_I80) { 158c8466a91SJoonyoung Shim val = VIDTCON00_VBPD_F( 15985de275aSAndrzej Hajda m->crtc_vtotal - m->crtc_vsync_end - 1) | 160c8466a91SJoonyoung Shim VIDTCON00_VFPD_F( 16185de275aSAndrzej Hajda m->crtc_vsync_start - m->crtc_vdisplay - 1); 162c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDTCON00); 163c8466a91SJoonyoung Shim 164c8466a91SJoonyoung Shim val = VIDTCON01_VSPW_F( 16585de275aSAndrzej Hajda m->crtc_vsync_end - m->crtc_vsync_start - 1); 166c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDTCON01); 167c8466a91SJoonyoung Shim 168c8466a91SJoonyoung Shim val = VIDTCON10_HBPD_F( 16985de275aSAndrzej Hajda m->crtc_htotal - m->crtc_hsync_end - 1) | 170c8466a91SJoonyoung Shim VIDTCON10_HFPD_F( 17185de275aSAndrzej Hajda m->crtc_hsync_start - m->crtc_hdisplay - 1); 172c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDTCON10); 173c8466a91SJoonyoung Shim 174c8466a91SJoonyoung Shim val = VIDTCON11_HSPW_F( 17585de275aSAndrzej Hajda m->crtc_hsync_end - m->crtc_hsync_start - 1); 176c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDTCON11); 177c8466a91SJoonyoung Shim } 178c8466a91SJoonyoung Shim 179c8466a91SJoonyoung Shim decon_setup_trigger(ctx); 180c8466a91SJoonyoung Shim 181c8466a91SJoonyoung Shim /* enable output and display signal */ 182b8182832SAndrzej Hajda decon_set_bits(ctx, DECON_VIDCON0, VIDCON0_ENVID | VIDCON0_ENVID_F, ~0); 183c8466a91SJoonyoung Shim } 184c8466a91SJoonyoung Shim 1852eeb2e5eSGustavo Padovan static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win, 1862eeb2e5eSGustavo Padovan struct drm_framebuffer *fb) 187c8466a91SJoonyoung Shim { 188c8466a91SJoonyoung Shim unsigned long val; 189c8466a91SJoonyoung Shim 190c8466a91SJoonyoung Shim val = readl(ctx->addr + DECON_WINCONx(win)); 191c8466a91SJoonyoung Shim val &= ~WINCONx_BPPMODE_MASK; 192c8466a91SJoonyoung Shim 1932eeb2e5eSGustavo Padovan switch (fb->pixel_format) { 194c8466a91SJoonyoung Shim case DRM_FORMAT_XRGB1555: 195c8466a91SJoonyoung Shim val |= WINCONx_BPPMODE_16BPP_I1555; 196c8466a91SJoonyoung Shim val |= WINCONx_HAWSWP_F; 197c8466a91SJoonyoung Shim val |= WINCONx_BURSTLEN_16WORD; 198c8466a91SJoonyoung Shim break; 199c8466a91SJoonyoung Shim case DRM_FORMAT_RGB565: 200c8466a91SJoonyoung Shim val |= WINCONx_BPPMODE_16BPP_565; 201c8466a91SJoonyoung Shim val |= WINCONx_HAWSWP_F; 202c8466a91SJoonyoung Shim val |= WINCONx_BURSTLEN_16WORD; 203c8466a91SJoonyoung Shim break; 204c8466a91SJoonyoung Shim case DRM_FORMAT_XRGB8888: 205c8466a91SJoonyoung Shim val |= WINCONx_BPPMODE_24BPP_888; 206c8466a91SJoonyoung Shim val |= WINCONx_WSWP_F; 207c8466a91SJoonyoung Shim val |= WINCONx_BURSTLEN_16WORD; 208c8466a91SJoonyoung Shim break; 209c8466a91SJoonyoung Shim case DRM_FORMAT_ARGB8888: 210c8466a91SJoonyoung Shim val |= WINCONx_BPPMODE_32BPP_A8888; 211c8466a91SJoonyoung Shim val |= WINCONx_WSWP_F | WINCONx_BLD_PIX_F | WINCONx_ALPHA_SEL_F; 212c8466a91SJoonyoung Shim val |= WINCONx_BURSTLEN_16WORD; 213c8466a91SJoonyoung Shim break; 214c8466a91SJoonyoung Shim default: 215c8466a91SJoonyoung Shim DRM_ERROR("Proper pixel format is not set\n"); 216c8466a91SJoonyoung Shim return; 217c8466a91SJoonyoung Shim } 218c8466a91SJoonyoung Shim 2192eeb2e5eSGustavo Padovan DRM_DEBUG_KMS("bpp = %u\n", fb->bits_per_pixel); 220c8466a91SJoonyoung Shim 221c8466a91SJoonyoung Shim /* 222c8466a91SJoonyoung Shim * In case of exynos, setting dma-burst to 16Word causes permanent 223c8466a91SJoonyoung Shim * tearing for very small buffers, e.g. cursor buffer. Burst Mode 224c8466a91SJoonyoung Shim * switching which is based on plane size is not recommended as 225c8466a91SJoonyoung Shim * plane size varies a lot towards the end of the screen and rapid 226c8466a91SJoonyoung Shim * movement causes unstable DMA which results into iommu crash/tear. 227c8466a91SJoonyoung Shim */ 228c8466a91SJoonyoung Shim 2292eeb2e5eSGustavo Padovan if (fb->width < MIN_FB_WIDTH_FOR_16WORD_BURST) { 230c8466a91SJoonyoung Shim val &= ~WINCONx_BURSTLEN_MASK; 231c8466a91SJoonyoung Shim val |= WINCONx_BURSTLEN_8WORD; 232c8466a91SJoonyoung Shim } 233c8466a91SJoonyoung Shim 234c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_WINCONx(win)); 235c8466a91SJoonyoung Shim } 236c8466a91SJoonyoung Shim 237c8466a91SJoonyoung Shim static void decon_shadow_protect_win(struct decon_context *ctx, int win, 238c8466a91SJoonyoung Shim bool protect) 239c8466a91SJoonyoung Shim { 240b2192073SAndrzej Hajda decon_set_bits(ctx, DECON_SHADOWCON, SHADOWCON_Wx_PROTECT(win), 241b2192073SAndrzej Hajda protect ? ~0 : 0); 242c8466a91SJoonyoung Shim } 243c8466a91SJoonyoung Shim 244cc5a7b35SHyungwon Hwang static void decon_atomic_begin(struct exynos_drm_crtc *crtc, 245cc5a7b35SHyungwon Hwang struct exynos_drm_plane *plane) 246cc5a7b35SHyungwon Hwang { 247cc5a7b35SHyungwon Hwang struct decon_context *ctx = crtc->ctx; 248cc5a7b35SHyungwon Hwang 2497b6bb6edSAndrzej Hajda if (test_bit(BIT_SUSPENDED, &ctx->flags)) 250cc5a7b35SHyungwon Hwang return; 251cc5a7b35SHyungwon Hwang 252cc5a7b35SHyungwon Hwang decon_shadow_protect_win(ctx, plane->zpos, true); 253cc5a7b35SHyungwon Hwang } 254cc5a7b35SHyungwon Hwang 255b8182832SAndrzej Hajda #define BIT_VAL(x, e, s) (((x) & ((1 << ((e) - (s) + 1)) - 1)) << (s)) 256b8182832SAndrzej Hajda #define COORDINATE_X(x) BIT_VAL((x), 23, 12) 257b8182832SAndrzej Hajda #define COORDINATE_Y(x) BIT_VAL((x), 11, 0) 258b8182832SAndrzej Hajda 2591e1d1393SGustavo Padovan static void decon_update_plane(struct exynos_drm_crtc *crtc, 2601e1d1393SGustavo Padovan struct exynos_drm_plane *plane) 261c8466a91SJoonyoung Shim { 262c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 2632eeb2e5eSGustavo Padovan struct drm_plane_state *state = plane->base.state; 2641e1d1393SGustavo Padovan unsigned int win = plane->zpos; 2652eeb2e5eSGustavo Padovan unsigned int bpp = state->fb->bits_per_pixel >> 3; 2662eeb2e5eSGustavo Padovan unsigned int pitch = state->fb->pitches[0]; 267c8466a91SJoonyoung Shim u32 val; 268c8466a91SJoonyoung Shim 2697b6bb6edSAndrzej Hajda if (test_bit(BIT_SUSPENDED, &ctx->flags)) 270c8466a91SJoonyoung Shim return; 271c8466a91SJoonyoung Shim 272c8466a91SJoonyoung Shim val = COORDINATE_X(plane->crtc_x) | COORDINATE_Y(plane->crtc_y); 273c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDOSDxA(win)); 274c8466a91SJoonyoung Shim 275d88d2463SGustavo Padovan val = COORDINATE_X(plane->crtc_x + plane->crtc_w - 1) | 276d88d2463SGustavo Padovan COORDINATE_Y(plane->crtc_y + plane->crtc_h - 1); 277c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDOSDxB(win)); 278c8466a91SJoonyoung Shim 279c8466a91SJoonyoung Shim val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | 280c8466a91SJoonyoung Shim VIDOSD_Wx_ALPHA_B_F(0x0); 281c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDOSDxC(win)); 282c8466a91SJoonyoung Shim 283c8466a91SJoonyoung Shim val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | 284c8466a91SJoonyoung Shim VIDOSD_Wx_ALPHA_B_F(0x0); 285c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDOSDxD(win)); 286c8466a91SJoonyoung Shim 287c8466a91SJoonyoung Shim writel(plane->dma_addr[0], ctx->addr + DECON_VIDW0xADD0B0(win)); 288c8466a91SJoonyoung Shim 289d88d2463SGustavo Padovan val = plane->dma_addr[0] + pitch * plane->crtc_h; 290c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDW0xADD1B0(win)); 291c8466a91SJoonyoung Shim 292b8182832SAndrzej Hajda if (ctx->out_type != IFTYPE_HDMI) 293b8182832SAndrzej Hajda val = BIT_VAL(pitch - plane->crtc_w * bpp, 27, 14) 294b8182832SAndrzej Hajda | BIT_VAL(plane->crtc_w * bpp, 13, 0); 295b8182832SAndrzej Hajda else 296b8182832SAndrzej Hajda val = BIT_VAL(pitch - plane->crtc_w * bpp, 29, 15) 297b8182832SAndrzej Hajda | BIT_VAL(plane->crtc_w * bpp, 14, 0); 298c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDW0xADD2(win)); 299c8466a91SJoonyoung Shim 3002eeb2e5eSGustavo Padovan decon_win_set_pixfmt(ctx, win, state->fb); 301c8466a91SJoonyoung Shim 302c8466a91SJoonyoung Shim /* window enable */ 303b2192073SAndrzej Hajda decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, ~0); 304c8466a91SJoonyoung Shim 305c8466a91SJoonyoung Shim /* standalone update */ 306b2192073SAndrzej Hajda decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); 307c8466a91SJoonyoung Shim } 308c8466a91SJoonyoung Shim 3091e1d1393SGustavo Padovan static void decon_disable_plane(struct exynos_drm_crtc *crtc, 3101e1d1393SGustavo Padovan struct exynos_drm_plane *plane) 311c8466a91SJoonyoung Shim { 312c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 3131e1d1393SGustavo Padovan unsigned int win = plane->zpos; 314c8466a91SJoonyoung Shim 3157b6bb6edSAndrzej Hajda if (test_bit(BIT_SUSPENDED, &ctx->flags)) 316c8466a91SJoonyoung Shim return; 317c8466a91SJoonyoung Shim 318c8466a91SJoonyoung Shim decon_shadow_protect_win(ctx, win, true); 319c8466a91SJoonyoung Shim 320c8466a91SJoonyoung Shim /* window disable */ 321b2192073SAndrzej Hajda decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0); 322c8466a91SJoonyoung Shim 323c8466a91SJoonyoung Shim decon_shadow_protect_win(ctx, win, false); 324c8466a91SJoonyoung Shim 325c8466a91SJoonyoung Shim /* standalone update */ 326b2192073SAndrzej Hajda decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); 327c8466a91SJoonyoung Shim } 328c8466a91SJoonyoung Shim 329cc5a7b35SHyungwon Hwang static void decon_atomic_flush(struct exynos_drm_crtc *crtc, 330cc5a7b35SHyungwon Hwang struct exynos_drm_plane *plane) 331cc5a7b35SHyungwon Hwang { 332cc5a7b35SHyungwon Hwang struct decon_context *ctx = crtc->ctx; 333cc5a7b35SHyungwon Hwang 3347b6bb6edSAndrzej Hajda if (test_bit(BIT_SUSPENDED, &ctx->flags)) 335cc5a7b35SHyungwon Hwang return; 336cc5a7b35SHyungwon Hwang 337cc5a7b35SHyungwon Hwang decon_shadow_protect_win(ctx, plane->zpos, false); 338cc5a7b35SHyungwon Hwang 339b8182832SAndrzej Hajda if (ctx->out_type == IFTYPE_I80) 3407b6bb6edSAndrzej Hajda set_bit(BIT_WIN_UPDATED, &ctx->flags); 341cc5a7b35SHyungwon Hwang } 342cc5a7b35SHyungwon Hwang 343c8466a91SJoonyoung Shim static void decon_swreset(struct decon_context *ctx) 344c8466a91SJoonyoung Shim { 345c8466a91SJoonyoung Shim unsigned int tries; 346c8466a91SJoonyoung Shim 347c8466a91SJoonyoung Shim writel(0, ctx->addr + DECON_VIDCON0); 348c8466a91SJoonyoung Shim for (tries = 2000; tries; --tries) { 349c8466a91SJoonyoung Shim if (~readl(ctx->addr + DECON_VIDCON0) & VIDCON0_STOP_STATUS) 350c8466a91SJoonyoung Shim break; 351c8466a91SJoonyoung Shim udelay(10); 352c8466a91SJoonyoung Shim } 353c8466a91SJoonyoung Shim 354c8466a91SJoonyoung Shim WARN(tries == 0, "failed to disable DECON\n"); 355c8466a91SJoonyoung Shim 356c8466a91SJoonyoung Shim writel(VIDCON0_SWRESET, ctx->addr + DECON_VIDCON0); 357c8466a91SJoonyoung Shim for (tries = 2000; tries; --tries) { 358c8466a91SJoonyoung Shim if (~readl(ctx->addr + DECON_VIDCON0) & VIDCON0_SWRESET) 359c8466a91SJoonyoung Shim break; 360c8466a91SJoonyoung Shim udelay(10); 361c8466a91SJoonyoung Shim } 362c8466a91SJoonyoung Shim 363c8466a91SJoonyoung Shim WARN(tries == 0, "failed to software reset DECON\n"); 364b8182832SAndrzej Hajda 365b8182832SAndrzej Hajda if (ctx->out_type != IFTYPE_HDMI) 366b8182832SAndrzej Hajda return; 367b8182832SAndrzej Hajda 368b8182832SAndrzej Hajda writel(VIDCON0_CLKVALUP | VIDCON0_VLCKFREE, ctx->addr + DECON_VIDCON0); 369b8182832SAndrzej Hajda decon_set_bits(ctx, DECON_CMU, 370b8182832SAndrzej Hajda CMU_CLKGAGE_MODE_SFR_F | CMU_CLKGAGE_MODE_MEM_F, ~0); 371b8182832SAndrzej Hajda writel(VIDCON1_VCLK_RUN_VDEN_DISABLE, ctx->addr + DECON_VIDCON1); 372b8182832SAndrzej Hajda writel(CRCCTRL_CRCEN | CRCCTRL_CRCSTART_F | CRCCTRL_CRCCLKEN, 373b8182832SAndrzej Hajda ctx->addr + DECON_CRCCTRL); 374b8182832SAndrzej Hajda decon_setup_trigger(ctx); 375c8466a91SJoonyoung Shim } 376c8466a91SJoonyoung Shim 377c8466a91SJoonyoung Shim static void decon_enable(struct exynos_drm_crtc *crtc) 378c8466a91SJoonyoung Shim { 379c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 380c8466a91SJoonyoung Shim int ret; 381c8466a91SJoonyoung Shim int i; 382c8466a91SJoonyoung Shim 3837b6bb6edSAndrzej Hajda if (!test_and_clear_bit(BIT_SUSPENDED, &ctx->flags)) 384c8466a91SJoonyoung Shim return; 385c8466a91SJoonyoung Shim 386c8466a91SJoonyoung Shim pm_runtime_get_sync(ctx->dev); 387c8466a91SJoonyoung Shim 388c8466a91SJoonyoung Shim for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { 389c8466a91SJoonyoung Shim ret = clk_prepare_enable(ctx->clks[i]); 390c8466a91SJoonyoung Shim if (ret < 0) 391c8466a91SJoonyoung Shim goto err; 392c8466a91SJoonyoung Shim } 393c8466a91SJoonyoung Shim 3947b6bb6edSAndrzej Hajda set_bit(BIT_CLKS_ENABLED, &ctx->flags); 395c8466a91SJoonyoung Shim 396c8466a91SJoonyoung Shim /* if vblank was enabled status, enable it again. */ 3977b6bb6edSAndrzej Hajda if (test_and_clear_bit(BIT_IRQS_ENABLED, &ctx->flags)) 398c8466a91SJoonyoung Shim decon_enable_vblank(ctx->crtc); 399c8466a91SJoonyoung Shim 400c8466a91SJoonyoung Shim decon_commit(ctx->crtc); 401c8466a91SJoonyoung Shim 402c8466a91SJoonyoung Shim return; 403c8466a91SJoonyoung Shim err: 404c8466a91SJoonyoung Shim while (--i >= 0) 405c8466a91SJoonyoung Shim clk_disable_unprepare(ctx->clks[i]); 406c8466a91SJoonyoung Shim 4077b6bb6edSAndrzej Hajda set_bit(BIT_SUSPENDED, &ctx->flags); 408c8466a91SJoonyoung Shim } 409c8466a91SJoonyoung Shim 410c8466a91SJoonyoung Shim static void decon_disable(struct exynos_drm_crtc *crtc) 411c8466a91SJoonyoung Shim { 412c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 413c8466a91SJoonyoung Shim int i; 414c8466a91SJoonyoung Shim 4157b6bb6edSAndrzej Hajda if (test_bit(BIT_SUSPENDED, &ctx->flags)) 416c8466a91SJoonyoung Shim return; 417c8466a91SJoonyoung Shim 418c8466a91SJoonyoung Shim /* 419c8466a91SJoonyoung Shim * We need to make sure that all windows are disabled before we 420c8466a91SJoonyoung Shim * suspend that connector. Otherwise we might try to scan from 421c8466a91SJoonyoung Shim * a destroyed buffer later. 422c8466a91SJoonyoung Shim */ 423b8182832SAndrzej Hajda for (i = ctx->first_win; i < WINDOWS_NR; i++) 4241e1d1393SGustavo Padovan decon_disable_plane(crtc, &ctx->planes[i]); 425c8466a91SJoonyoung Shim 426c8466a91SJoonyoung Shim decon_swreset(ctx); 427c8466a91SJoonyoung Shim 428c8466a91SJoonyoung Shim for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) 429c8466a91SJoonyoung Shim clk_disable_unprepare(ctx->clks[i]); 430c8466a91SJoonyoung Shim 4317b6bb6edSAndrzej Hajda clear_bit(BIT_CLKS_ENABLED, &ctx->flags); 432c8466a91SJoonyoung Shim 433c8466a91SJoonyoung Shim pm_runtime_put_sync(ctx->dev); 434c8466a91SJoonyoung Shim 4357b6bb6edSAndrzej Hajda set_bit(BIT_SUSPENDED, &ctx->flags); 436c8466a91SJoonyoung Shim } 437c8466a91SJoonyoung Shim 438c8466a91SJoonyoung Shim void decon_te_irq_handler(struct exynos_drm_crtc *crtc) 439c8466a91SJoonyoung Shim { 440c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 441c8466a91SJoonyoung Shim 4427b6bb6edSAndrzej Hajda if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags)) 443c8466a91SJoonyoung Shim return; 444c8466a91SJoonyoung Shim 4457b6bb6edSAndrzej Hajda if (test_and_clear_bit(BIT_WIN_UPDATED, &ctx->flags)) 446b2192073SAndrzej Hajda decon_set_bits(ctx, DECON_TRIGCON, TRIGCON_SWTRIGCMD, ~0); 447c8466a91SJoonyoung Shim 448eafd540aSGustavo Padovan drm_crtc_handle_vblank(&ctx->crtc->base); 449c8466a91SJoonyoung Shim } 450c8466a91SJoonyoung Shim 451c8466a91SJoonyoung Shim static void decon_clear_channels(struct exynos_drm_crtc *crtc) 452c8466a91SJoonyoung Shim { 453c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 454c8466a91SJoonyoung Shim int win, i, ret; 455c8466a91SJoonyoung Shim 456c8466a91SJoonyoung Shim DRM_DEBUG_KMS("%s\n", __FILE__); 457c8466a91SJoonyoung Shim 458c8466a91SJoonyoung Shim for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { 459c8466a91SJoonyoung Shim ret = clk_prepare_enable(ctx->clks[i]); 460c8466a91SJoonyoung Shim if (ret < 0) 461c8466a91SJoonyoung Shim goto err; 462c8466a91SJoonyoung Shim } 463c8466a91SJoonyoung Shim 464c8466a91SJoonyoung Shim for (win = 0; win < WINDOWS_NR; win++) { 465b2192073SAndrzej Hajda decon_shadow_protect_win(ctx, win, true); 466b2192073SAndrzej Hajda decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0); 467b2192073SAndrzej Hajda decon_shadow_protect_win(ctx, win, false); 468b2192073SAndrzej Hajda decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); 469c8466a91SJoonyoung Shim } 470c8466a91SJoonyoung Shim /* TODO: wait for possible vsync */ 471c8466a91SJoonyoung Shim msleep(50); 472c8466a91SJoonyoung Shim 473c8466a91SJoonyoung Shim err: 474c8466a91SJoonyoung Shim while (--i >= 0) 475c8466a91SJoonyoung Shim clk_disable_unprepare(ctx->clks[i]); 476c8466a91SJoonyoung Shim } 477c8466a91SJoonyoung Shim 478c8466a91SJoonyoung Shim static struct exynos_drm_crtc_ops decon_crtc_ops = { 479c8466a91SJoonyoung Shim .enable = decon_enable, 480c8466a91SJoonyoung Shim .disable = decon_disable, 481c8466a91SJoonyoung Shim .commit = decon_commit, 482c8466a91SJoonyoung Shim .enable_vblank = decon_enable_vblank, 483c8466a91SJoonyoung Shim .disable_vblank = decon_disable_vblank, 484cc5a7b35SHyungwon Hwang .atomic_begin = decon_atomic_begin, 4859cc7610aSGustavo Padovan .update_plane = decon_update_plane, 4869cc7610aSGustavo Padovan .disable_plane = decon_disable_plane, 487cc5a7b35SHyungwon Hwang .atomic_flush = decon_atomic_flush, 488c8466a91SJoonyoung Shim .te_handler = decon_te_irq_handler, 489c8466a91SJoonyoung Shim }; 490c8466a91SJoonyoung Shim 491c8466a91SJoonyoung Shim static int decon_bind(struct device *dev, struct device *master, void *data) 492c8466a91SJoonyoung Shim { 493c8466a91SJoonyoung Shim struct decon_context *ctx = dev_get_drvdata(dev); 494c8466a91SJoonyoung Shim struct drm_device *drm_dev = data; 495c8466a91SJoonyoung Shim struct exynos_drm_private *priv = drm_dev->dev_private; 496c8466a91SJoonyoung Shim struct exynos_drm_plane *exynos_plane; 497b8182832SAndrzej Hajda enum exynos_drm_output_type out_type; 498c8466a91SJoonyoung Shim enum drm_plane_type type; 499b8182832SAndrzej Hajda unsigned int win; 500c8466a91SJoonyoung Shim int ret; 501c8466a91SJoonyoung Shim 502c8466a91SJoonyoung Shim ctx->drm_dev = drm_dev; 503c8466a91SJoonyoung Shim ctx->pipe = priv->pipe++; 504c8466a91SJoonyoung Shim 505b8182832SAndrzej Hajda for (win = ctx->first_win; win < WINDOWS_NR; win++) { 506b8182832SAndrzej Hajda int tmp = (win == ctx->first_win) ? 0 : win; 507b8182832SAndrzej Hajda 508b8182832SAndrzej Hajda type = exynos_plane_get_type(tmp, CURSOR_WIN); 509b8182832SAndrzej Hajda ret = exynos_plane_init(drm_dev, &ctx->planes[win], 510fbbb1e1aSMarek Szyprowski 1 << ctx->pipe, type, decon_formats, 511b8182832SAndrzej Hajda ARRAY_SIZE(decon_formats), win); 512c8466a91SJoonyoung Shim if (ret) 513c8466a91SJoonyoung Shim return ret; 514c8466a91SJoonyoung Shim } 515c8466a91SJoonyoung Shim 516b8182832SAndrzej Hajda exynos_plane = &ctx->planes[ctx->first_win]; 517b8182832SAndrzej Hajda out_type = (ctx->out_type == IFTYPE_HDMI) ? EXYNOS_DISPLAY_TYPE_HDMI 518b8182832SAndrzej Hajda : EXYNOS_DISPLAY_TYPE_LCD; 519c8466a91SJoonyoung Shim ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, 520b8182832SAndrzej Hajda ctx->pipe, out_type, 521c8466a91SJoonyoung Shim &decon_crtc_ops, ctx); 522c8466a91SJoonyoung Shim if (IS_ERR(ctx->crtc)) { 523c8466a91SJoonyoung Shim ret = PTR_ERR(ctx->crtc); 524c8466a91SJoonyoung Shim goto err; 525c8466a91SJoonyoung Shim } 526c8466a91SJoonyoung Shim 527eb7a3fc7SJoonyoung Shim decon_clear_channels(ctx->crtc); 528eb7a3fc7SJoonyoung Shim 529eb7a3fc7SJoonyoung Shim ret = drm_iommu_attach_device(drm_dev, dev); 530c8466a91SJoonyoung Shim if (ret) 531c8466a91SJoonyoung Shim goto err; 532c8466a91SJoonyoung Shim 533c8466a91SJoonyoung Shim return ret; 534c8466a91SJoonyoung Shim err: 535c8466a91SJoonyoung Shim priv->pipe--; 536c8466a91SJoonyoung Shim return ret; 537c8466a91SJoonyoung Shim } 538c8466a91SJoonyoung Shim 539c8466a91SJoonyoung Shim static void decon_unbind(struct device *dev, struct device *master, void *data) 540c8466a91SJoonyoung Shim { 541c8466a91SJoonyoung Shim struct decon_context *ctx = dev_get_drvdata(dev); 542c8466a91SJoonyoung Shim 543c8466a91SJoonyoung Shim decon_disable(ctx->crtc); 544c8466a91SJoonyoung Shim 545c8466a91SJoonyoung Shim /* detach this sub driver from iommu mapping if supported. */ 546c8466a91SJoonyoung Shim drm_iommu_detach_device(ctx->drm_dev, ctx->dev); 547c8466a91SJoonyoung Shim } 548c8466a91SJoonyoung Shim 549c8466a91SJoonyoung Shim static const struct component_ops decon_component_ops = { 550c8466a91SJoonyoung Shim .bind = decon_bind, 551c8466a91SJoonyoung Shim .unbind = decon_unbind, 552c8466a91SJoonyoung Shim }; 553c8466a91SJoonyoung Shim 554b8182832SAndrzej Hajda static irqreturn_t decon_irq_handler(int irq, void *dev_id) 555c8466a91SJoonyoung Shim { 556c8466a91SJoonyoung Shim struct decon_context *ctx = dev_id; 557c8466a91SJoonyoung Shim u32 val; 558822f6dfdSGustavo Padovan int win; 559c8466a91SJoonyoung Shim 5607b6bb6edSAndrzej Hajda if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags)) 561c8466a91SJoonyoung Shim goto out; 562c8466a91SJoonyoung Shim 563c8466a91SJoonyoung Shim val = readl(ctx->addr + DECON_VIDINTCON1); 564b8182832SAndrzej Hajda val &= VIDINTCON1_INTFRMDONEPEND | VIDINTCON1_INTFRMPEND; 565b8182832SAndrzej Hajda 566b8182832SAndrzej Hajda if (val) { 567b8182832SAndrzej Hajda for (win = ctx->first_win; win < WINDOWS_NR ; win++) { 568822f6dfdSGustavo Padovan struct exynos_drm_plane *plane = &ctx->planes[win]; 569822f6dfdSGustavo Padovan 570822f6dfdSGustavo Padovan if (!plane->pending_fb) 571822f6dfdSGustavo Padovan continue; 572822f6dfdSGustavo Padovan 573822f6dfdSGustavo Padovan exynos_drm_crtc_finish_update(ctx->crtc, plane); 574822f6dfdSGustavo Padovan } 575c8466a91SJoonyoung Shim 576c8466a91SJoonyoung Shim /* clear */ 577b8182832SAndrzej Hajda writel(val, ctx->addr + DECON_VIDINTCON1); 578c8466a91SJoonyoung Shim } 579c8466a91SJoonyoung Shim 580c8466a91SJoonyoung Shim out: 581c8466a91SJoonyoung Shim return IRQ_HANDLED; 582c8466a91SJoonyoung Shim } 583c8466a91SJoonyoung Shim 584b8182832SAndrzej Hajda static const struct of_device_id exynos5433_decon_driver_dt_match[] = { 585b8182832SAndrzej Hajda { 586b8182832SAndrzej Hajda .compatible = "samsung,exynos5433-decon", 587b8182832SAndrzej Hajda .data = (void *)IFTYPE_RGB 588b8182832SAndrzej Hajda }, 589b8182832SAndrzej Hajda { 590b8182832SAndrzej Hajda .compatible = "samsung,exynos5433-decon-tv", 591b8182832SAndrzej Hajda .data = (void *)IFTYPE_HDMI 592b8182832SAndrzej Hajda }, 593b8182832SAndrzej Hajda {}, 594b8182832SAndrzej Hajda }; 595b8182832SAndrzej Hajda MODULE_DEVICE_TABLE(of, exynos5433_decon_driver_dt_match); 596b8182832SAndrzej Hajda 597c8466a91SJoonyoung Shim static int exynos5433_decon_probe(struct platform_device *pdev) 598c8466a91SJoonyoung Shim { 599b8182832SAndrzej Hajda const struct of_device_id *of_id; 600c8466a91SJoonyoung Shim struct device *dev = &pdev->dev; 601c8466a91SJoonyoung Shim struct decon_context *ctx; 602c8466a91SJoonyoung Shim struct resource *res; 603c8466a91SJoonyoung Shim int ret; 604c8466a91SJoonyoung Shim int i; 605c8466a91SJoonyoung Shim 606c8466a91SJoonyoung Shim ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 607c8466a91SJoonyoung Shim if (!ctx) 608c8466a91SJoonyoung Shim return -ENOMEM; 609c8466a91SJoonyoung Shim 6107b6bb6edSAndrzej Hajda __set_bit(BIT_SUSPENDED, &ctx->flags); 611c8466a91SJoonyoung Shim ctx->dev = dev; 612b8182832SAndrzej Hajda 613b8182832SAndrzej Hajda of_id = of_match_device(exynos5433_decon_driver_dt_match, &pdev->dev); 614b8182832SAndrzej Hajda ctx->out_type = (enum decon_iftype)of_id->data; 615b8182832SAndrzej Hajda 616b8182832SAndrzej Hajda if (ctx->out_type == IFTYPE_HDMI) 617b8182832SAndrzej Hajda ctx->first_win = 1; 618b8182832SAndrzej Hajda else if (of_get_child_by_name(dev->of_node, "i80-if-timings")) 619b8182832SAndrzej Hajda ctx->out_type = IFTYPE_I80; 620c8466a91SJoonyoung Shim 621c8466a91SJoonyoung Shim for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { 622c8466a91SJoonyoung Shim struct clk *clk; 623c8466a91SJoonyoung Shim 624c8466a91SJoonyoung Shim clk = devm_clk_get(ctx->dev, decon_clks_name[i]); 625c8466a91SJoonyoung Shim if (IS_ERR(clk)) 626c8466a91SJoonyoung Shim return PTR_ERR(clk); 627c8466a91SJoonyoung Shim 628c8466a91SJoonyoung Shim ctx->clks[i] = clk; 629c8466a91SJoonyoung Shim } 630c8466a91SJoonyoung Shim 631c8466a91SJoonyoung Shim res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 632c8466a91SJoonyoung Shim if (!res) { 633c8466a91SJoonyoung Shim dev_err(dev, "cannot find IO resource\n"); 634c8466a91SJoonyoung Shim return -ENXIO; 635c8466a91SJoonyoung Shim } 636c8466a91SJoonyoung Shim 637c8466a91SJoonyoung Shim ctx->addr = devm_ioremap_resource(dev, res); 638c8466a91SJoonyoung Shim if (IS_ERR(ctx->addr)) { 639c8466a91SJoonyoung Shim dev_err(dev, "ioremap failed\n"); 640c8466a91SJoonyoung Shim return PTR_ERR(ctx->addr); 641c8466a91SJoonyoung Shim } 642c8466a91SJoonyoung Shim 643c8466a91SJoonyoung Shim res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, 644b8182832SAndrzej Hajda (ctx->out_type == IFTYPE_I80) ? "lcd_sys" : "vsync"); 645c8466a91SJoonyoung Shim if (!res) { 646c8466a91SJoonyoung Shim dev_err(dev, "cannot find IRQ resource\n"); 647c8466a91SJoonyoung Shim return -ENXIO; 648c8466a91SJoonyoung Shim } 649c8466a91SJoonyoung Shim 650b8182832SAndrzej Hajda ret = devm_request_irq(dev, res->start, decon_irq_handler, 0, 651c8466a91SJoonyoung Shim "drm_decon", ctx); 652c8466a91SJoonyoung Shim if (ret < 0) { 653c8466a91SJoonyoung Shim dev_err(dev, "lcd_sys irq request failed\n"); 654c8466a91SJoonyoung Shim return ret; 655c8466a91SJoonyoung Shim } 656c8466a91SJoonyoung Shim 657c8466a91SJoonyoung Shim platform_set_drvdata(pdev, ctx); 658c8466a91SJoonyoung Shim 659c8466a91SJoonyoung Shim pm_runtime_enable(dev); 660c8466a91SJoonyoung Shim 661c8466a91SJoonyoung Shim ret = component_add(dev, &decon_component_ops); 662c8466a91SJoonyoung Shim if (ret) 663c8466a91SJoonyoung Shim goto err_disable_pm_runtime; 664c8466a91SJoonyoung Shim 665c8466a91SJoonyoung Shim return 0; 666c8466a91SJoonyoung Shim 667c8466a91SJoonyoung Shim err_disable_pm_runtime: 668c8466a91SJoonyoung Shim pm_runtime_disable(dev); 669c8466a91SJoonyoung Shim 670c8466a91SJoonyoung Shim return ret; 671c8466a91SJoonyoung Shim } 672c8466a91SJoonyoung Shim 673c8466a91SJoonyoung Shim static int exynos5433_decon_remove(struct platform_device *pdev) 674c8466a91SJoonyoung Shim { 675c8466a91SJoonyoung Shim pm_runtime_disable(&pdev->dev); 676c8466a91SJoonyoung Shim 677c8466a91SJoonyoung Shim component_del(&pdev->dev, &decon_component_ops); 678c8466a91SJoonyoung Shim 679c8466a91SJoonyoung Shim return 0; 680c8466a91SJoonyoung Shim } 681c8466a91SJoonyoung Shim 682c8466a91SJoonyoung Shim struct platform_driver exynos5433_decon_driver = { 683c8466a91SJoonyoung Shim .probe = exynos5433_decon_probe, 684c8466a91SJoonyoung Shim .remove = exynos5433_decon_remove, 685c8466a91SJoonyoung Shim .driver = { 686c8466a91SJoonyoung Shim .name = "exynos5433-decon", 687c8466a91SJoonyoung Shim .of_match_table = exynos5433_decon_driver_dt_match, 688c8466a91SJoonyoung Shim }, 689c8466a91SJoonyoung Shim }; 690