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" 240488f50eSMarek Szyprowski #include "exynos_drm_fb.h" 25c8466a91SJoonyoung Shim #include "exynos_drm_plane.h" 26c8466a91SJoonyoung Shim #include "exynos_drm_iommu.h" 27c8466a91SJoonyoung Shim 28c8466a91SJoonyoung Shim #define WINDOWS_NR 3 29c8466a91SJoonyoung Shim #define MIN_FB_WIDTH_FOR_16WORD_BURST 128 30c8466a91SJoonyoung Shim 319ac26de8SInki Dae #define IFTYPE_I80 (1 << 0) 329ac26de8SInki Dae #define I80_HW_TRG (1 << 1) 339ac26de8SInki Dae #define IFTYPE_HDMI (1 << 2) 349ac26de8SInki Dae 354f54f21cSAndrzej Hajda static const char * const decon_clks_name[] = { 364f54f21cSAndrzej Hajda "pclk", 374f54f21cSAndrzej Hajda "aclk_decon", 384f54f21cSAndrzej Hajda "aclk_smmu_decon0x", 394f54f21cSAndrzej Hajda "aclk_xiu_decon0x", 404f54f21cSAndrzej Hajda "pclk_smmu_decon0x", 414f54f21cSAndrzej Hajda "sclk_decon_vclk", 424f54f21cSAndrzej Hajda "sclk_decon_eclk", 434f54f21cSAndrzej Hajda }; 444f54f21cSAndrzej Hajda 457b6bb6edSAndrzej Hajda enum decon_flag_bits { 467b6bb6edSAndrzej Hajda BIT_CLKS_ENABLED, 477b6bb6edSAndrzej Hajda BIT_IRQS_ENABLED, 487b6bb6edSAndrzej Hajda BIT_WIN_UPDATED, 497b6bb6edSAndrzej Hajda BIT_SUSPENDED 507b6bb6edSAndrzej Hajda }; 517b6bb6edSAndrzej Hajda 52c8466a91SJoonyoung Shim struct decon_context { 53c8466a91SJoonyoung Shim struct device *dev; 54c8466a91SJoonyoung Shim struct drm_device *drm_dev; 55c8466a91SJoonyoung Shim struct exynos_drm_crtc *crtc; 56c8466a91SJoonyoung Shim struct exynos_drm_plane planes[WINDOWS_NR]; 57fd2d2fc2SMarek Szyprowski struct exynos_drm_plane_config configs[WINDOWS_NR]; 58c8466a91SJoonyoung Shim void __iomem *addr; 594f54f21cSAndrzej Hajda struct clk *clks[ARRAY_SIZE(decon_clks_name)]; 60c8466a91SJoonyoung Shim int pipe; 617b6bb6edSAndrzej Hajda unsigned long flags; 629ac26de8SInki Dae unsigned long out_type; 63b8182832SAndrzej Hajda int first_win; 64c8466a91SJoonyoung Shim }; 65c8466a91SJoonyoung Shim 66fbbb1e1aSMarek Szyprowski static const uint32_t decon_formats[] = { 67fbbb1e1aSMarek Szyprowski DRM_FORMAT_XRGB1555, 68fbbb1e1aSMarek Szyprowski DRM_FORMAT_RGB565, 69fbbb1e1aSMarek Szyprowski DRM_FORMAT_XRGB8888, 70fbbb1e1aSMarek Szyprowski DRM_FORMAT_ARGB8888, 71fbbb1e1aSMarek Szyprowski }; 72fbbb1e1aSMarek Szyprowski 73fd2d2fc2SMarek Szyprowski static const enum drm_plane_type decon_win_types[WINDOWS_NR] = { 74fd2d2fc2SMarek Szyprowski DRM_PLANE_TYPE_PRIMARY, 75fd2d2fc2SMarek Szyprowski DRM_PLANE_TYPE_OVERLAY, 76fd2d2fc2SMarek Szyprowski DRM_PLANE_TYPE_CURSOR, 77fd2d2fc2SMarek Szyprowski }; 78fd2d2fc2SMarek Szyprowski 79b2192073SAndrzej Hajda static inline void decon_set_bits(struct decon_context *ctx, u32 reg, u32 mask, 80b2192073SAndrzej Hajda u32 val) 81b2192073SAndrzej Hajda { 82b2192073SAndrzej Hajda val = (val & mask) | (readl(ctx->addr + reg) & ~mask); 83b2192073SAndrzej Hajda writel(val, ctx->addr + reg); 84b2192073SAndrzej Hajda } 85b2192073SAndrzej Hajda 86c8466a91SJoonyoung Shim static int decon_enable_vblank(struct exynos_drm_crtc *crtc) 87c8466a91SJoonyoung Shim { 88c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 89c8466a91SJoonyoung Shim u32 val; 90c8466a91SJoonyoung Shim 917b6bb6edSAndrzej Hajda if (test_bit(BIT_SUSPENDED, &ctx->flags)) 92c8466a91SJoonyoung Shim return -EPERM; 93c8466a91SJoonyoung Shim 94f3fb3d82SMarek Szyprowski if (!test_and_set_bit(BIT_IRQS_ENABLED, &ctx->flags)) { 95c8466a91SJoonyoung Shim val = VIDINTCON0_INTEN; 969ac26de8SInki Dae if (ctx->out_type & IFTYPE_I80) 97c8466a91SJoonyoung Shim val |= VIDINTCON0_FRAMEDONE; 98c8466a91SJoonyoung Shim else 99c8466a91SJoonyoung Shim val |= VIDINTCON0_INTFRMEN; 100c8466a91SJoonyoung Shim 101c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDINTCON0); 102c8466a91SJoonyoung Shim } 103c8466a91SJoonyoung Shim 104c8466a91SJoonyoung Shim return 0; 105c8466a91SJoonyoung Shim } 106c8466a91SJoonyoung Shim 107c8466a91SJoonyoung Shim static void decon_disable_vblank(struct exynos_drm_crtc *crtc) 108c8466a91SJoonyoung Shim { 109c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 110c8466a91SJoonyoung Shim 1117b6bb6edSAndrzej Hajda if (test_bit(BIT_SUSPENDED, &ctx->flags)) 112c8466a91SJoonyoung Shim return; 113c8466a91SJoonyoung Shim 1147b6bb6edSAndrzej Hajda if (test_and_clear_bit(BIT_IRQS_ENABLED, &ctx->flags)) 115c8466a91SJoonyoung Shim writel(0, ctx->addr + DECON_VIDINTCON0); 116c8466a91SJoonyoung Shim } 117c8466a91SJoonyoung Shim 118c8466a91SJoonyoung Shim static void decon_setup_trigger(struct decon_context *ctx) 119c8466a91SJoonyoung Shim { 1209ac26de8SInki Dae u32 val = !(ctx->out_type & I80_HW_TRG) 121b8182832SAndrzej Hajda ? TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F | 122b8182832SAndrzej Hajda TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN 123b8182832SAndrzej Hajda : TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F | 124b5bf0f1eSInki Dae TRIGCON_HWTRIGMASK | TRIGCON_HWTRIGEN; 125c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_TRIGCON); 126c8466a91SJoonyoung Shim } 127c8466a91SJoonyoung Shim 128c8466a91SJoonyoung Shim static void decon_commit(struct exynos_drm_crtc *crtc) 129c8466a91SJoonyoung Shim { 130c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 13185de275aSAndrzej Hajda struct drm_display_mode *m = &crtc->base.mode; 132c8466a91SJoonyoung Shim u32 val; 133c8466a91SJoonyoung Shim 1347b6bb6edSAndrzej Hajda if (test_bit(BIT_SUSPENDED, &ctx->flags)) 135c8466a91SJoonyoung Shim return; 136c8466a91SJoonyoung Shim 1379ac26de8SInki Dae if (ctx->out_type & IFTYPE_HDMI) { 138b8182832SAndrzej Hajda m->crtc_hsync_start = m->crtc_hdisplay + 10; 139b8182832SAndrzej Hajda m->crtc_hsync_end = m->crtc_htotal - 92; 140b8182832SAndrzej Hajda m->crtc_vsync_start = m->crtc_vdisplay + 1; 141b8182832SAndrzej Hajda m->crtc_vsync_end = m->crtc_vsync_start + 1; 142b8182832SAndrzej Hajda } 143b8182832SAndrzej Hajda 144b8182832SAndrzej Hajda decon_set_bits(ctx, DECON_VIDCON0, VIDCON0_ENVID, 0); 145b8182832SAndrzej Hajda 146c8466a91SJoonyoung Shim /* enable clock gate */ 147c8466a91SJoonyoung Shim val = CMU_CLKGAGE_MODE_SFR_F | CMU_CLKGAGE_MODE_MEM_F; 148c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_CMU); 149c8466a91SJoonyoung Shim 150c8466a91SJoonyoung Shim /* lcd on and use command if */ 151c8466a91SJoonyoung Shim val = VIDOUT_LCD_ON; 1529ac26de8SInki Dae if (ctx->out_type & IFTYPE_I80) { 153c8466a91SJoonyoung Shim val |= VIDOUT_COMMAND_IF; 1549ac26de8SInki Dae decon_setup_trigger(ctx); 1559ac26de8SInki Dae } else { 156c8466a91SJoonyoung Shim val |= VIDOUT_RGB_IF; 1579ac26de8SInki Dae } 1589ac26de8SInki Dae 159c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDOUTCON0); 160c8466a91SJoonyoung Shim 16185de275aSAndrzej Hajda val = VIDTCON2_LINEVAL(m->vdisplay - 1) | 16285de275aSAndrzej Hajda VIDTCON2_HOZVAL(m->hdisplay - 1); 163c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDTCON2); 164c8466a91SJoonyoung Shim 1659ac26de8SInki Dae if (!(ctx->out_type & IFTYPE_I80)) { 166c8466a91SJoonyoung Shim val = VIDTCON00_VBPD_F( 16785de275aSAndrzej Hajda m->crtc_vtotal - m->crtc_vsync_end - 1) | 168c8466a91SJoonyoung Shim VIDTCON00_VFPD_F( 16985de275aSAndrzej Hajda m->crtc_vsync_start - m->crtc_vdisplay - 1); 170c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDTCON00); 171c8466a91SJoonyoung Shim 172c8466a91SJoonyoung Shim val = VIDTCON01_VSPW_F( 17385de275aSAndrzej Hajda m->crtc_vsync_end - m->crtc_vsync_start - 1); 174c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDTCON01); 175c8466a91SJoonyoung Shim 176c8466a91SJoonyoung Shim val = VIDTCON10_HBPD_F( 17785de275aSAndrzej Hajda m->crtc_htotal - m->crtc_hsync_end - 1) | 178c8466a91SJoonyoung Shim VIDTCON10_HFPD_F( 17985de275aSAndrzej Hajda m->crtc_hsync_start - m->crtc_hdisplay - 1); 180c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDTCON10); 181c8466a91SJoonyoung Shim 182c8466a91SJoonyoung Shim val = VIDTCON11_HSPW_F( 18385de275aSAndrzej Hajda m->crtc_hsync_end - m->crtc_hsync_start - 1); 184c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDTCON11); 185c8466a91SJoonyoung Shim } 186c8466a91SJoonyoung Shim 187c8466a91SJoonyoung Shim /* enable output and display signal */ 188b8182832SAndrzej Hajda decon_set_bits(ctx, DECON_VIDCON0, VIDCON0_ENVID | VIDCON0_ENVID_F, ~0); 18992ead494SAndrzej Hajda 19092ead494SAndrzej Hajda decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); 191c8466a91SJoonyoung Shim } 192c8466a91SJoonyoung Shim 1932eeb2e5eSGustavo Padovan static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win, 1942eeb2e5eSGustavo Padovan struct drm_framebuffer *fb) 195c8466a91SJoonyoung Shim { 196c8466a91SJoonyoung Shim unsigned long val; 197c8466a91SJoonyoung Shim 198c8466a91SJoonyoung Shim val = readl(ctx->addr + DECON_WINCONx(win)); 199c8466a91SJoonyoung Shim val &= ~WINCONx_BPPMODE_MASK; 200c8466a91SJoonyoung Shim 2012eeb2e5eSGustavo Padovan switch (fb->pixel_format) { 202c8466a91SJoonyoung Shim case DRM_FORMAT_XRGB1555: 203c8466a91SJoonyoung Shim val |= WINCONx_BPPMODE_16BPP_I1555; 204c8466a91SJoonyoung Shim val |= WINCONx_HAWSWP_F; 205c8466a91SJoonyoung Shim val |= WINCONx_BURSTLEN_16WORD; 206c8466a91SJoonyoung Shim break; 207c8466a91SJoonyoung Shim case DRM_FORMAT_RGB565: 208c8466a91SJoonyoung Shim val |= WINCONx_BPPMODE_16BPP_565; 209c8466a91SJoonyoung Shim val |= WINCONx_HAWSWP_F; 210c8466a91SJoonyoung Shim val |= WINCONx_BURSTLEN_16WORD; 211c8466a91SJoonyoung Shim break; 212c8466a91SJoonyoung Shim case DRM_FORMAT_XRGB8888: 213c8466a91SJoonyoung Shim val |= WINCONx_BPPMODE_24BPP_888; 214c8466a91SJoonyoung Shim val |= WINCONx_WSWP_F; 215c8466a91SJoonyoung Shim val |= WINCONx_BURSTLEN_16WORD; 216c8466a91SJoonyoung Shim break; 217c8466a91SJoonyoung Shim case DRM_FORMAT_ARGB8888: 218c8466a91SJoonyoung Shim val |= WINCONx_BPPMODE_32BPP_A8888; 219c8466a91SJoonyoung Shim val |= WINCONx_WSWP_F | WINCONx_BLD_PIX_F | WINCONx_ALPHA_SEL_F; 220c8466a91SJoonyoung Shim val |= WINCONx_BURSTLEN_16WORD; 221c8466a91SJoonyoung Shim break; 222c8466a91SJoonyoung Shim default: 223c8466a91SJoonyoung Shim DRM_ERROR("Proper pixel format is not set\n"); 224c8466a91SJoonyoung Shim return; 225c8466a91SJoonyoung Shim } 226c8466a91SJoonyoung Shim 2272eeb2e5eSGustavo Padovan DRM_DEBUG_KMS("bpp = %u\n", fb->bits_per_pixel); 228c8466a91SJoonyoung Shim 229c8466a91SJoonyoung Shim /* 230c8466a91SJoonyoung Shim * In case of exynos, setting dma-burst to 16Word causes permanent 231c8466a91SJoonyoung Shim * tearing for very small buffers, e.g. cursor buffer. Burst Mode 232c8466a91SJoonyoung Shim * switching which is based on plane size is not recommended as 233c8466a91SJoonyoung Shim * plane size varies a lot towards the end of the screen and rapid 234c8466a91SJoonyoung Shim * movement causes unstable DMA which results into iommu crash/tear. 235c8466a91SJoonyoung Shim */ 236c8466a91SJoonyoung Shim 2372eeb2e5eSGustavo Padovan if (fb->width < MIN_FB_WIDTH_FOR_16WORD_BURST) { 238c8466a91SJoonyoung Shim val &= ~WINCONx_BURSTLEN_MASK; 239c8466a91SJoonyoung Shim val |= WINCONx_BURSTLEN_8WORD; 240c8466a91SJoonyoung Shim } 241c8466a91SJoonyoung Shim 242c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_WINCONx(win)); 243c8466a91SJoonyoung Shim } 244c8466a91SJoonyoung Shim 245c8466a91SJoonyoung Shim static void decon_shadow_protect_win(struct decon_context *ctx, int win, 246c8466a91SJoonyoung Shim bool protect) 247c8466a91SJoonyoung Shim { 248b2192073SAndrzej Hajda decon_set_bits(ctx, DECON_SHADOWCON, SHADOWCON_Wx_PROTECT(win), 249b2192073SAndrzej Hajda protect ? ~0 : 0); 250c8466a91SJoonyoung Shim } 251c8466a91SJoonyoung Shim 252d29c2c14SMarek Szyprowski static void decon_atomic_begin(struct exynos_drm_crtc *crtc) 253cc5a7b35SHyungwon Hwang { 254cc5a7b35SHyungwon Hwang struct decon_context *ctx = crtc->ctx; 255d29c2c14SMarek Szyprowski int i; 256cc5a7b35SHyungwon Hwang 2577b6bb6edSAndrzej Hajda if (test_bit(BIT_SUSPENDED, &ctx->flags)) 258cc5a7b35SHyungwon Hwang return; 259cc5a7b35SHyungwon Hwang 260d29c2c14SMarek Szyprowski for (i = ctx->first_win; i < WINDOWS_NR; i++) 261d29c2c14SMarek Szyprowski decon_shadow_protect_win(ctx, i, true); 262cc5a7b35SHyungwon Hwang } 263cc5a7b35SHyungwon Hwang 264b8182832SAndrzej Hajda #define BIT_VAL(x, e, s) (((x) & ((1 << ((e) - (s) + 1)) - 1)) << (s)) 265b8182832SAndrzej Hajda #define COORDINATE_X(x) BIT_VAL((x), 23, 12) 266b8182832SAndrzej Hajda #define COORDINATE_Y(x) BIT_VAL((x), 11, 0) 267b8182832SAndrzej Hajda 2681e1d1393SGustavo Padovan static void decon_update_plane(struct exynos_drm_crtc *crtc, 2691e1d1393SGustavo Padovan struct exynos_drm_plane *plane) 270c8466a91SJoonyoung Shim { 2710114f404SMarek Szyprowski struct exynos_drm_plane_state *state = 2720114f404SMarek Szyprowski to_exynos_plane_state(plane->base.state); 273c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 2740114f404SMarek Szyprowski struct drm_framebuffer *fb = state->base.fb; 27540bdfb0aSMarek Szyprowski unsigned int win = plane->index; 2760488f50eSMarek Szyprowski unsigned int bpp = fb->bits_per_pixel >> 3; 2770488f50eSMarek Szyprowski unsigned int pitch = fb->pitches[0]; 2780488f50eSMarek Szyprowski dma_addr_t dma_addr = exynos_drm_fb_dma_addr(fb, 0); 279c8466a91SJoonyoung Shim u32 val; 280c8466a91SJoonyoung Shim 2817b6bb6edSAndrzej Hajda if (test_bit(BIT_SUSPENDED, &ctx->flags)) 282c8466a91SJoonyoung Shim return; 283c8466a91SJoonyoung Shim 2840114f404SMarek Szyprowski val = COORDINATE_X(state->crtc.x) | COORDINATE_Y(state->crtc.y); 285c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDOSDxA(win)); 286c8466a91SJoonyoung Shim 2870114f404SMarek Szyprowski val = COORDINATE_X(state->crtc.x + state->crtc.w - 1) | 2880114f404SMarek Szyprowski COORDINATE_Y(state->crtc.y + state->crtc.h - 1); 289c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDOSDxB(win)); 290c8466a91SJoonyoung Shim 291c8466a91SJoonyoung Shim val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | 292c8466a91SJoonyoung Shim VIDOSD_Wx_ALPHA_B_F(0x0); 293c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDOSDxC(win)); 294c8466a91SJoonyoung Shim 295c8466a91SJoonyoung Shim val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | 296c8466a91SJoonyoung Shim VIDOSD_Wx_ALPHA_B_F(0x0); 297c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDOSDxD(win)); 298c8466a91SJoonyoung Shim 2990488f50eSMarek Szyprowski writel(dma_addr, ctx->addr + DECON_VIDW0xADD0B0(win)); 300c8466a91SJoonyoung Shim 3010114f404SMarek Szyprowski val = dma_addr + pitch * state->src.h; 302c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDW0xADD1B0(win)); 303c8466a91SJoonyoung Shim 3049ac26de8SInki Dae if (!(ctx->out_type & IFTYPE_HDMI)) 3050114f404SMarek Szyprowski val = BIT_VAL(pitch - state->crtc.w * bpp, 27, 14) 3060114f404SMarek Szyprowski | BIT_VAL(state->crtc.w * bpp, 13, 0); 307b8182832SAndrzej Hajda else 3080114f404SMarek Szyprowski val = BIT_VAL(pitch - state->crtc.w * bpp, 29, 15) 3090114f404SMarek Szyprowski | BIT_VAL(state->crtc.w * bpp, 14, 0); 310c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDW0xADD2(win)); 311c8466a91SJoonyoung Shim 3120488f50eSMarek Szyprowski decon_win_set_pixfmt(ctx, win, fb); 313c8466a91SJoonyoung Shim 314c8466a91SJoonyoung Shim /* window enable */ 315b2192073SAndrzej Hajda decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, ~0); 316c8466a91SJoonyoung Shim } 317c8466a91SJoonyoung Shim 3181e1d1393SGustavo Padovan static void decon_disable_plane(struct exynos_drm_crtc *crtc, 3191e1d1393SGustavo Padovan struct exynos_drm_plane *plane) 320c8466a91SJoonyoung Shim { 321c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 32240bdfb0aSMarek Szyprowski unsigned int win = plane->index; 323c8466a91SJoonyoung Shim 3247b6bb6edSAndrzej Hajda if (test_bit(BIT_SUSPENDED, &ctx->flags)) 325c8466a91SJoonyoung Shim return; 326c8466a91SJoonyoung Shim 327b2192073SAndrzej Hajda decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0); 328c8466a91SJoonyoung Shim } 329c8466a91SJoonyoung Shim 330d29c2c14SMarek Szyprowski static void decon_atomic_flush(struct exynos_drm_crtc *crtc) 331cc5a7b35SHyungwon Hwang { 332cc5a7b35SHyungwon Hwang struct decon_context *ctx = crtc->ctx; 333d29c2c14SMarek Szyprowski int i; 334cc5a7b35SHyungwon Hwang 3357b6bb6edSAndrzej Hajda if (test_bit(BIT_SUSPENDED, &ctx->flags)) 336cc5a7b35SHyungwon Hwang return; 337cc5a7b35SHyungwon Hwang 338d29c2c14SMarek Szyprowski for (i = ctx->first_win; i < WINDOWS_NR; i++) 339d29c2c14SMarek Szyprowski decon_shadow_protect_win(ctx, i, false); 340cc5a7b35SHyungwon Hwang 34192ead494SAndrzej Hajda /* standalone update */ 34292ead494SAndrzej Hajda decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); 34392ead494SAndrzej Hajda 3449ac26de8SInki Dae if (ctx->out_type & IFTYPE_I80) 3457b6bb6edSAndrzej Hajda set_bit(BIT_WIN_UPDATED, &ctx->flags); 346cc5a7b35SHyungwon Hwang } 347cc5a7b35SHyungwon Hwang 348c8466a91SJoonyoung Shim static void decon_swreset(struct decon_context *ctx) 349c8466a91SJoonyoung Shim { 350c8466a91SJoonyoung Shim unsigned int tries; 351c8466a91SJoonyoung Shim 352c8466a91SJoonyoung Shim writel(0, ctx->addr + DECON_VIDCON0); 353c8466a91SJoonyoung Shim for (tries = 2000; tries; --tries) { 354c8466a91SJoonyoung Shim if (~readl(ctx->addr + DECON_VIDCON0) & VIDCON0_STOP_STATUS) 355c8466a91SJoonyoung Shim break; 356c8466a91SJoonyoung Shim udelay(10); 357c8466a91SJoonyoung Shim } 358c8466a91SJoonyoung Shim 359c8466a91SJoonyoung Shim WARN(tries == 0, "failed to disable DECON\n"); 360c8466a91SJoonyoung Shim 361c8466a91SJoonyoung Shim writel(VIDCON0_SWRESET, ctx->addr + DECON_VIDCON0); 362c8466a91SJoonyoung Shim for (tries = 2000; tries; --tries) { 363c8466a91SJoonyoung Shim if (~readl(ctx->addr + DECON_VIDCON0) & VIDCON0_SWRESET) 364c8466a91SJoonyoung Shim break; 365c8466a91SJoonyoung Shim udelay(10); 366c8466a91SJoonyoung Shim } 367c8466a91SJoonyoung Shim 368c8466a91SJoonyoung Shim WARN(tries == 0, "failed to software reset DECON\n"); 369b8182832SAndrzej Hajda 3709ac26de8SInki Dae if (!(ctx->out_type & IFTYPE_HDMI)) 371b8182832SAndrzej Hajda return; 372b8182832SAndrzej Hajda 373b8182832SAndrzej Hajda writel(VIDCON0_CLKVALUP | VIDCON0_VLCKFREE, ctx->addr + DECON_VIDCON0); 374b8182832SAndrzej Hajda decon_set_bits(ctx, DECON_CMU, 375b8182832SAndrzej Hajda CMU_CLKGAGE_MODE_SFR_F | CMU_CLKGAGE_MODE_MEM_F, ~0); 376b8182832SAndrzej Hajda writel(VIDCON1_VCLK_RUN_VDEN_DISABLE, ctx->addr + DECON_VIDCON1); 377b8182832SAndrzej Hajda writel(CRCCTRL_CRCEN | CRCCTRL_CRCSTART_F | CRCCTRL_CRCCLKEN, 378b8182832SAndrzej Hajda ctx->addr + DECON_CRCCTRL); 3799ac26de8SInki Dae 3809ac26de8SInki Dae if (ctx->out_type & IFTYPE_I80) 381b8182832SAndrzej Hajda decon_setup_trigger(ctx); 382c8466a91SJoonyoung Shim } 383c8466a91SJoonyoung Shim 384c8466a91SJoonyoung Shim static void decon_enable(struct exynos_drm_crtc *crtc) 385c8466a91SJoonyoung Shim { 386c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 387c8466a91SJoonyoung Shim 3887b6bb6edSAndrzej Hajda if (!test_and_clear_bit(BIT_SUSPENDED, &ctx->flags)) 389c8466a91SJoonyoung Shim return; 390c8466a91SJoonyoung Shim 391c8466a91SJoonyoung Shim pm_runtime_get_sync(ctx->dev); 392c8466a91SJoonyoung Shim 393c60230ebSAndrzej Hajda exynos_drm_pipe_clk_enable(crtc, true); 394c60230ebSAndrzej Hajda 3957b6bb6edSAndrzej Hajda set_bit(BIT_CLKS_ENABLED, &ctx->flags); 396c8466a91SJoonyoung Shim 397e87b3c62SAndrzej Hajda decon_swreset(ctx); 398e87b3c62SAndrzej Hajda 399c8466a91SJoonyoung Shim /* if vblank was enabled status, enable it again. */ 4007b6bb6edSAndrzej Hajda if (test_and_clear_bit(BIT_IRQS_ENABLED, &ctx->flags)) 401c8466a91SJoonyoung Shim decon_enable_vblank(ctx->crtc); 402c8466a91SJoonyoung Shim 403c8466a91SJoonyoung Shim decon_commit(ctx->crtc); 404c8466a91SJoonyoung Shim } 405c8466a91SJoonyoung Shim 406c8466a91SJoonyoung Shim static void decon_disable(struct exynos_drm_crtc *crtc) 407c8466a91SJoonyoung Shim { 408c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 409c8466a91SJoonyoung Shim int i; 410c8466a91SJoonyoung Shim 4117b6bb6edSAndrzej Hajda if (test_bit(BIT_SUSPENDED, &ctx->flags)) 412c8466a91SJoonyoung Shim return; 413c8466a91SJoonyoung Shim 414c8466a91SJoonyoung Shim /* 415c8466a91SJoonyoung Shim * We need to make sure that all windows are disabled before we 416c8466a91SJoonyoung Shim * suspend that connector. Otherwise we might try to scan from 417c8466a91SJoonyoung Shim * a destroyed buffer later. 418c8466a91SJoonyoung Shim */ 419b8182832SAndrzej Hajda for (i = ctx->first_win; i < WINDOWS_NR; i++) 4201e1d1393SGustavo Padovan decon_disable_plane(crtc, &ctx->planes[i]); 421c8466a91SJoonyoung Shim 422c8466a91SJoonyoung Shim decon_swreset(ctx); 423c8466a91SJoonyoung Shim 4247b6bb6edSAndrzej Hajda clear_bit(BIT_CLKS_ENABLED, &ctx->flags); 425c8466a91SJoonyoung Shim 426c60230ebSAndrzej Hajda exynos_drm_pipe_clk_enable(crtc, false); 427c60230ebSAndrzej Hajda 428c8466a91SJoonyoung Shim pm_runtime_put_sync(ctx->dev); 429c8466a91SJoonyoung Shim 4307b6bb6edSAndrzej Hajda set_bit(BIT_SUSPENDED, &ctx->flags); 431c8466a91SJoonyoung Shim } 432c8466a91SJoonyoung Shim 4339844d6ebSAndrzej Hajda static void decon_te_irq_handler(struct exynos_drm_crtc *crtc) 434c8466a91SJoonyoung Shim { 435c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 436c8466a91SJoonyoung Shim 4373f4c8e5cSAndrzej Hajda if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags) || 4383f4c8e5cSAndrzej Hajda (ctx->out_type & I80_HW_TRG)) 439c8466a91SJoonyoung Shim return; 440c8466a91SJoonyoung Shim 4417b6bb6edSAndrzej Hajda if (test_and_clear_bit(BIT_WIN_UPDATED, &ctx->flags)) 442b2192073SAndrzej Hajda decon_set_bits(ctx, DECON_TRIGCON, TRIGCON_SWTRIGCMD, ~0); 443c8466a91SJoonyoung Shim } 444c8466a91SJoonyoung Shim 445c8466a91SJoonyoung Shim static void decon_clear_channels(struct exynos_drm_crtc *crtc) 446c8466a91SJoonyoung Shim { 447c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 448c8466a91SJoonyoung Shim int win, i, ret; 449c8466a91SJoonyoung Shim 450c8466a91SJoonyoung Shim DRM_DEBUG_KMS("%s\n", __FILE__); 451c8466a91SJoonyoung Shim 452c8466a91SJoonyoung Shim for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { 453c8466a91SJoonyoung Shim ret = clk_prepare_enable(ctx->clks[i]); 454c8466a91SJoonyoung Shim if (ret < 0) 455c8466a91SJoonyoung Shim goto err; 456c8466a91SJoonyoung Shim } 457c8466a91SJoonyoung Shim 458c8466a91SJoonyoung Shim for (win = 0; win < WINDOWS_NR; win++) { 459b2192073SAndrzej Hajda decon_shadow_protect_win(ctx, win, true); 460b2192073SAndrzej Hajda decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0); 461b2192073SAndrzej Hajda decon_shadow_protect_win(ctx, win, false); 462c8466a91SJoonyoung Shim } 46392ead494SAndrzej Hajda 46492ead494SAndrzej Hajda decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); 46592ead494SAndrzej Hajda 466c8466a91SJoonyoung Shim /* TODO: wait for possible vsync */ 467c8466a91SJoonyoung Shim msleep(50); 468c8466a91SJoonyoung Shim 469c8466a91SJoonyoung Shim err: 470c8466a91SJoonyoung Shim while (--i >= 0) 471c8466a91SJoonyoung Shim clk_disable_unprepare(ctx->clks[i]); 472c8466a91SJoonyoung Shim } 473c8466a91SJoonyoung Shim 474c8466a91SJoonyoung Shim static struct exynos_drm_crtc_ops decon_crtc_ops = { 475c8466a91SJoonyoung Shim .enable = decon_enable, 476c8466a91SJoonyoung Shim .disable = decon_disable, 477c8466a91SJoonyoung Shim .enable_vblank = decon_enable_vblank, 478c8466a91SJoonyoung Shim .disable_vblank = decon_disable_vblank, 479cc5a7b35SHyungwon Hwang .atomic_begin = decon_atomic_begin, 4809cc7610aSGustavo Padovan .update_plane = decon_update_plane, 4819cc7610aSGustavo Padovan .disable_plane = decon_disable_plane, 482cc5a7b35SHyungwon Hwang .atomic_flush = decon_atomic_flush, 483c8466a91SJoonyoung Shim .te_handler = decon_te_irq_handler, 484c8466a91SJoonyoung Shim }; 485c8466a91SJoonyoung Shim 486c8466a91SJoonyoung Shim static int decon_bind(struct device *dev, struct device *master, void *data) 487c8466a91SJoonyoung Shim { 488c8466a91SJoonyoung Shim struct decon_context *ctx = dev_get_drvdata(dev); 489c8466a91SJoonyoung Shim struct drm_device *drm_dev = data; 490c8466a91SJoonyoung Shim struct exynos_drm_private *priv = drm_dev->dev_private; 491c8466a91SJoonyoung Shim struct exynos_drm_plane *exynos_plane; 492b8182832SAndrzej Hajda enum exynos_drm_output_type out_type; 493b8182832SAndrzej Hajda unsigned int win; 494c8466a91SJoonyoung Shim int ret; 495c8466a91SJoonyoung Shim 496c8466a91SJoonyoung Shim ctx->drm_dev = drm_dev; 497c8466a91SJoonyoung Shim ctx->pipe = priv->pipe++; 498c8466a91SJoonyoung Shim 499b8182832SAndrzej Hajda for (win = ctx->first_win; win < WINDOWS_NR; win++) { 500b8182832SAndrzej Hajda int tmp = (win == ctx->first_win) ? 0 : win; 501b8182832SAndrzej Hajda 502fd2d2fc2SMarek Szyprowski ctx->configs[win].pixel_formats = decon_formats; 503fd2d2fc2SMarek Szyprowski ctx->configs[win].num_pixel_formats = ARRAY_SIZE(decon_formats); 504fd2d2fc2SMarek Szyprowski ctx->configs[win].zpos = win; 505fd2d2fc2SMarek Szyprowski ctx->configs[win].type = decon_win_types[tmp]; 506fd2d2fc2SMarek Szyprowski 50740bdfb0aSMarek Szyprowski ret = exynos_plane_init(drm_dev, &ctx->planes[win], win, 508fd2d2fc2SMarek Szyprowski 1 << ctx->pipe, &ctx->configs[win]); 509c8466a91SJoonyoung Shim if (ret) 510c8466a91SJoonyoung Shim return ret; 511c8466a91SJoonyoung Shim } 512c8466a91SJoonyoung Shim 513b8182832SAndrzej Hajda exynos_plane = &ctx->planes[ctx->first_win]; 5149ac26de8SInki Dae out_type = (ctx->out_type & IFTYPE_HDMI) ? EXYNOS_DISPLAY_TYPE_HDMI 515b8182832SAndrzej Hajda : EXYNOS_DISPLAY_TYPE_LCD; 516c8466a91SJoonyoung Shim ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, 517b8182832SAndrzej Hajda ctx->pipe, out_type, 518c8466a91SJoonyoung Shim &decon_crtc_ops, ctx); 519c8466a91SJoonyoung Shim if (IS_ERR(ctx->crtc)) { 520c8466a91SJoonyoung Shim ret = PTR_ERR(ctx->crtc); 521c8466a91SJoonyoung Shim goto err; 522c8466a91SJoonyoung Shim } 523c8466a91SJoonyoung Shim 524eb7a3fc7SJoonyoung Shim decon_clear_channels(ctx->crtc); 525eb7a3fc7SJoonyoung Shim 526eb7a3fc7SJoonyoung Shim ret = drm_iommu_attach_device(drm_dev, dev); 527c8466a91SJoonyoung Shim if (ret) 528c8466a91SJoonyoung Shim goto err; 529c8466a91SJoonyoung Shim 530c8466a91SJoonyoung Shim return ret; 531c8466a91SJoonyoung Shim err: 532c8466a91SJoonyoung Shim priv->pipe--; 533c8466a91SJoonyoung Shim return ret; 534c8466a91SJoonyoung Shim } 535c8466a91SJoonyoung Shim 536c8466a91SJoonyoung Shim static void decon_unbind(struct device *dev, struct device *master, void *data) 537c8466a91SJoonyoung Shim { 538c8466a91SJoonyoung Shim struct decon_context *ctx = dev_get_drvdata(dev); 539c8466a91SJoonyoung Shim 540c8466a91SJoonyoung Shim decon_disable(ctx->crtc); 541c8466a91SJoonyoung Shim 542c8466a91SJoonyoung Shim /* detach this sub driver from iommu mapping if supported. */ 543c8466a91SJoonyoung Shim drm_iommu_detach_device(ctx->drm_dev, ctx->dev); 544c8466a91SJoonyoung Shim } 545c8466a91SJoonyoung Shim 546c8466a91SJoonyoung Shim static const struct component_ops decon_component_ops = { 547c8466a91SJoonyoung Shim .bind = decon_bind, 548c8466a91SJoonyoung Shim .unbind = decon_unbind, 549c8466a91SJoonyoung Shim }; 550c8466a91SJoonyoung Shim 551b8182832SAndrzej Hajda static irqreturn_t decon_irq_handler(int irq, void *dev_id) 552c8466a91SJoonyoung Shim { 553c8466a91SJoonyoung Shim struct decon_context *ctx = dev_id; 554c8466a91SJoonyoung Shim u32 val; 555822f6dfdSGustavo Padovan int win; 556c8466a91SJoonyoung Shim 5577b6bb6edSAndrzej Hajda if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags)) 558c8466a91SJoonyoung Shim goto out; 559c8466a91SJoonyoung Shim 560c8466a91SJoonyoung Shim val = readl(ctx->addr + DECON_VIDINTCON1); 561b8182832SAndrzej Hajda val &= VIDINTCON1_INTFRMDONEPEND | VIDINTCON1_INTFRMPEND; 562b8182832SAndrzej Hajda 563b8182832SAndrzej Hajda if (val) { 564b8182832SAndrzej Hajda for (win = ctx->first_win; win < WINDOWS_NR ; win++) { 565822f6dfdSGustavo Padovan struct exynos_drm_plane *plane = &ctx->planes[win]; 566822f6dfdSGustavo Padovan 567822f6dfdSGustavo Padovan if (!plane->pending_fb) 568822f6dfdSGustavo Padovan continue; 569822f6dfdSGustavo Padovan 570822f6dfdSGustavo Padovan exynos_drm_crtc_finish_update(ctx->crtc, plane); 571822f6dfdSGustavo Padovan } 572c8466a91SJoonyoung Shim 573c8466a91SJoonyoung Shim /* clear */ 574b8182832SAndrzej Hajda writel(val, ctx->addr + DECON_VIDINTCON1); 575b0bb3d07SAndrzej Hajda drm_crtc_handle_vblank(&ctx->crtc->base); 576c8466a91SJoonyoung Shim } 577c8466a91SJoonyoung Shim 578c8466a91SJoonyoung Shim out: 579c8466a91SJoonyoung Shim return IRQ_HANDLED; 580c8466a91SJoonyoung Shim } 581c8466a91SJoonyoung Shim 582ebf3fd40SGustavo Padovan #ifdef CONFIG_PM 583ebf3fd40SGustavo Padovan static int exynos5433_decon_suspend(struct device *dev) 584ebf3fd40SGustavo Padovan { 585ebf3fd40SGustavo Padovan struct decon_context *ctx = dev_get_drvdata(dev); 58692c96ff8SAndrzej Hajda int i = ARRAY_SIZE(decon_clks_name); 587ebf3fd40SGustavo Padovan 58892c96ff8SAndrzej Hajda while (--i >= 0) 589ebf3fd40SGustavo Padovan clk_disable_unprepare(ctx->clks[i]); 590ebf3fd40SGustavo Padovan 591ebf3fd40SGustavo Padovan return 0; 592ebf3fd40SGustavo Padovan } 593ebf3fd40SGustavo Padovan 594ebf3fd40SGustavo Padovan static int exynos5433_decon_resume(struct device *dev) 595ebf3fd40SGustavo Padovan { 596ebf3fd40SGustavo Padovan struct decon_context *ctx = dev_get_drvdata(dev); 597ebf3fd40SGustavo Padovan int i, ret; 598ebf3fd40SGustavo Padovan 599ebf3fd40SGustavo Padovan for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { 600ebf3fd40SGustavo Padovan ret = clk_prepare_enable(ctx->clks[i]); 601ebf3fd40SGustavo Padovan if (ret < 0) 602ebf3fd40SGustavo Padovan goto err; 603ebf3fd40SGustavo Padovan } 604ebf3fd40SGustavo Padovan 605ebf3fd40SGustavo Padovan return 0; 606ebf3fd40SGustavo Padovan 607ebf3fd40SGustavo Padovan err: 608ebf3fd40SGustavo Padovan while (--i >= 0) 609ebf3fd40SGustavo Padovan clk_disable_unprepare(ctx->clks[i]); 610ebf3fd40SGustavo Padovan 611ebf3fd40SGustavo Padovan return ret; 612ebf3fd40SGustavo Padovan } 613ebf3fd40SGustavo Padovan #endif 614ebf3fd40SGustavo Padovan 615ebf3fd40SGustavo Padovan static const struct dev_pm_ops exynos5433_decon_pm_ops = { 616ebf3fd40SGustavo Padovan SET_RUNTIME_PM_OPS(exynos5433_decon_suspend, exynos5433_decon_resume, 617ebf3fd40SGustavo Padovan NULL) 618ebf3fd40SGustavo Padovan }; 619ebf3fd40SGustavo Padovan 620b8182832SAndrzej Hajda static const struct of_device_id exynos5433_decon_driver_dt_match[] = { 621b8182832SAndrzej Hajda { 622b8182832SAndrzej Hajda .compatible = "samsung,exynos5433-decon", 6239ac26de8SInki Dae .data = (void *)I80_HW_TRG 624b8182832SAndrzej Hajda }, 625b8182832SAndrzej Hajda { 626b8182832SAndrzej Hajda .compatible = "samsung,exynos5433-decon-tv", 6279ac26de8SInki Dae .data = (void *)(I80_HW_TRG | IFTYPE_HDMI) 628b8182832SAndrzej Hajda }, 629b8182832SAndrzej Hajda {}, 630b8182832SAndrzej Hajda }; 631b8182832SAndrzej Hajda MODULE_DEVICE_TABLE(of, exynos5433_decon_driver_dt_match); 632b8182832SAndrzej Hajda 633c8466a91SJoonyoung Shim static int exynos5433_decon_probe(struct platform_device *pdev) 634c8466a91SJoonyoung Shim { 635c8466a91SJoonyoung Shim struct device *dev = &pdev->dev; 636c8466a91SJoonyoung Shim struct decon_context *ctx; 637c8466a91SJoonyoung Shim struct resource *res; 638c8466a91SJoonyoung Shim int ret; 639c8466a91SJoonyoung Shim int i; 640c8466a91SJoonyoung Shim 641c8466a91SJoonyoung Shim ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 642c8466a91SJoonyoung Shim if (!ctx) 643c8466a91SJoonyoung Shim return -ENOMEM; 644c8466a91SJoonyoung Shim 6457b6bb6edSAndrzej Hajda __set_bit(BIT_SUSPENDED, &ctx->flags); 646c8466a91SJoonyoung Shim ctx->dev = dev; 6479ac26de8SInki Dae ctx->out_type = (unsigned long)of_device_get_match_data(dev); 648b8182832SAndrzej Hajda 6499ac26de8SInki Dae if (ctx->out_type & IFTYPE_HDMI) { 650b8182832SAndrzej Hajda ctx->first_win = 1; 651b8182832SAndrzej Hajda ctx->out_type = IFTYPE_I80; 6529ac26de8SInki Dae } else if (of_get_child_by_name(dev->of_node, "i80-if-timings")) { 6539ac26de8SInki Dae ctx->out_type = IFTYPE_I80; 6549ac26de8SInki Dae } 655c8466a91SJoonyoung Shim 656c8466a91SJoonyoung Shim for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { 657c8466a91SJoonyoung Shim struct clk *clk; 658c8466a91SJoonyoung Shim 659c8466a91SJoonyoung Shim clk = devm_clk_get(ctx->dev, decon_clks_name[i]); 660c8466a91SJoonyoung Shim if (IS_ERR(clk)) 661c8466a91SJoonyoung Shim return PTR_ERR(clk); 662c8466a91SJoonyoung Shim 663c8466a91SJoonyoung Shim ctx->clks[i] = clk; 664c8466a91SJoonyoung Shim } 665c8466a91SJoonyoung Shim 666c8466a91SJoonyoung Shim res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 667c8466a91SJoonyoung Shim if (!res) { 668c8466a91SJoonyoung Shim dev_err(dev, "cannot find IO resource\n"); 669c8466a91SJoonyoung Shim return -ENXIO; 670c8466a91SJoonyoung Shim } 671c8466a91SJoonyoung Shim 672c8466a91SJoonyoung Shim ctx->addr = devm_ioremap_resource(dev, res); 673c8466a91SJoonyoung Shim if (IS_ERR(ctx->addr)) { 674c8466a91SJoonyoung Shim dev_err(dev, "ioremap failed\n"); 675c8466a91SJoonyoung Shim return PTR_ERR(ctx->addr); 676c8466a91SJoonyoung Shim } 677c8466a91SJoonyoung Shim 678c8466a91SJoonyoung Shim res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, 6799ac26de8SInki Dae (ctx->out_type & IFTYPE_I80) ? "lcd_sys" : "vsync"); 680c8466a91SJoonyoung Shim if (!res) { 681c8466a91SJoonyoung Shim dev_err(dev, "cannot find IRQ resource\n"); 682c8466a91SJoonyoung Shim return -ENXIO; 683c8466a91SJoonyoung Shim } 684c8466a91SJoonyoung Shim 685b8182832SAndrzej Hajda ret = devm_request_irq(dev, res->start, decon_irq_handler, 0, 686c8466a91SJoonyoung Shim "drm_decon", ctx); 687c8466a91SJoonyoung Shim if (ret < 0) { 688c8466a91SJoonyoung Shim dev_err(dev, "lcd_sys irq request failed\n"); 689c8466a91SJoonyoung Shim return ret; 690c8466a91SJoonyoung Shim } 691c8466a91SJoonyoung Shim 692c8466a91SJoonyoung Shim platform_set_drvdata(pdev, ctx); 693c8466a91SJoonyoung Shim 694c8466a91SJoonyoung Shim pm_runtime_enable(dev); 695c8466a91SJoonyoung Shim 696c8466a91SJoonyoung Shim ret = component_add(dev, &decon_component_ops); 697c8466a91SJoonyoung Shim if (ret) 698c8466a91SJoonyoung Shim goto err_disable_pm_runtime; 699c8466a91SJoonyoung Shim 700c8466a91SJoonyoung Shim return 0; 701c8466a91SJoonyoung Shim 702c8466a91SJoonyoung Shim err_disable_pm_runtime: 703c8466a91SJoonyoung Shim pm_runtime_disable(dev); 704c8466a91SJoonyoung Shim 705c8466a91SJoonyoung Shim return ret; 706c8466a91SJoonyoung Shim } 707c8466a91SJoonyoung Shim 708c8466a91SJoonyoung Shim static int exynos5433_decon_remove(struct platform_device *pdev) 709c8466a91SJoonyoung Shim { 710c8466a91SJoonyoung Shim pm_runtime_disable(&pdev->dev); 711c8466a91SJoonyoung Shim 712c8466a91SJoonyoung Shim component_del(&pdev->dev, &decon_component_ops); 713c8466a91SJoonyoung Shim 714c8466a91SJoonyoung Shim return 0; 715c8466a91SJoonyoung Shim } 716c8466a91SJoonyoung Shim 717c8466a91SJoonyoung Shim struct platform_driver exynos5433_decon_driver = { 718c8466a91SJoonyoung Shim .probe = exynos5433_decon_probe, 719c8466a91SJoonyoung Shim .remove = exynos5433_decon_remove, 720c8466a91SJoonyoung Shim .driver = { 721c8466a91SJoonyoung Shim .name = "exynos5433-decon", 722ebf3fd40SGustavo Padovan .pm = &exynos5433_decon_pm_ops, 723c8466a91SJoonyoung Shim .of_match_table = exynos5433_decon_driver_dt_match, 724c8466a91SJoonyoung Shim }, 725c8466a91SJoonyoung Shim }; 726