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> 16b93c2e8bSAndrzej Hajda #include <linux/mfd/syscon.h> 17b8182832SAndrzej Hajda #include <linux/of_device.h> 18c8466a91SJoonyoung Shim #include <linux/of_gpio.h> 19c8466a91SJoonyoung Shim #include <linux/pm_runtime.h> 20b93c2e8bSAndrzej Hajda #include <linux/regmap.h> 21c8466a91SJoonyoung Shim 22c8466a91SJoonyoung Shim #include <video/exynos5433_decon.h> 23c8466a91SJoonyoung Shim 24c8466a91SJoonyoung Shim #include "exynos_drm_drv.h" 25c8466a91SJoonyoung Shim #include "exynos_drm_crtc.h" 260488f50eSMarek Szyprowski #include "exynos_drm_fb.h" 27c8466a91SJoonyoung Shim #include "exynos_drm_plane.h" 28c8466a91SJoonyoung Shim #include "exynos_drm_iommu.h" 29c8466a91SJoonyoung Shim 30b93c2e8bSAndrzej Hajda #define DSD_CFG_MUX 0x1004 31b93c2e8bSAndrzej Hajda #define DSD_CFG_MUX_TE_UNMASK_GLOBAL BIT(13) 32b93c2e8bSAndrzej Hajda 33c8466a91SJoonyoung Shim #define WINDOWS_NR 3 34c8466a91SJoonyoung Shim #define MIN_FB_WIDTH_FOR_16WORD_BURST 128 35c8466a91SJoonyoung Shim 369ac26de8SInki Dae #define IFTYPE_I80 (1 << 0) 379ac26de8SInki Dae #define I80_HW_TRG (1 << 1) 389ac26de8SInki Dae #define IFTYPE_HDMI (1 << 2) 399ac26de8SInki Dae 404f54f21cSAndrzej Hajda static const char * const decon_clks_name[] = { 414f54f21cSAndrzej Hajda "pclk", 424f54f21cSAndrzej Hajda "aclk_decon", 434f54f21cSAndrzej Hajda "aclk_smmu_decon0x", 444f54f21cSAndrzej Hajda "aclk_xiu_decon0x", 454f54f21cSAndrzej Hajda "pclk_smmu_decon0x", 464f54f21cSAndrzej Hajda "sclk_decon_vclk", 474f54f21cSAndrzej Hajda "sclk_decon_eclk", 484f54f21cSAndrzej Hajda }; 494f54f21cSAndrzej Hajda 507b6bb6edSAndrzej Hajda enum decon_flag_bits { 517b6bb6edSAndrzej Hajda BIT_CLKS_ENABLED, 527b6bb6edSAndrzej Hajda BIT_IRQS_ENABLED, 537b6bb6edSAndrzej Hajda BIT_WIN_UPDATED, 54821b40b7SAndrzej Hajda BIT_SUSPENDED, 55821b40b7SAndrzej Hajda BIT_REQUEST_UPDATE 567b6bb6edSAndrzej Hajda }; 577b6bb6edSAndrzej Hajda 58c8466a91SJoonyoung Shim struct decon_context { 59c8466a91SJoonyoung Shim struct device *dev; 60c8466a91SJoonyoung Shim struct drm_device *drm_dev; 61c8466a91SJoonyoung Shim struct exynos_drm_crtc *crtc; 62c8466a91SJoonyoung Shim struct exynos_drm_plane planes[WINDOWS_NR]; 63fd2d2fc2SMarek Szyprowski struct exynos_drm_plane_config configs[WINDOWS_NR]; 64c8466a91SJoonyoung Shim void __iomem *addr; 65b93c2e8bSAndrzej Hajda struct regmap *sysreg; 664f54f21cSAndrzej Hajda struct clk *clks[ARRAY_SIZE(decon_clks_name)]; 67c8466a91SJoonyoung Shim int pipe; 687b6bb6edSAndrzej Hajda unsigned long flags; 699ac26de8SInki Dae unsigned long out_type; 70b8182832SAndrzej Hajda int first_win; 71c8466a91SJoonyoung Shim }; 72c8466a91SJoonyoung Shim 73fbbb1e1aSMarek Szyprowski static const uint32_t decon_formats[] = { 74fbbb1e1aSMarek Szyprowski DRM_FORMAT_XRGB1555, 75fbbb1e1aSMarek Szyprowski DRM_FORMAT_RGB565, 76fbbb1e1aSMarek Szyprowski DRM_FORMAT_XRGB8888, 77fbbb1e1aSMarek Szyprowski DRM_FORMAT_ARGB8888, 78fbbb1e1aSMarek Szyprowski }; 79fbbb1e1aSMarek Szyprowski 80fd2d2fc2SMarek Szyprowski static const enum drm_plane_type decon_win_types[WINDOWS_NR] = { 81fd2d2fc2SMarek Szyprowski DRM_PLANE_TYPE_PRIMARY, 82fd2d2fc2SMarek Szyprowski DRM_PLANE_TYPE_OVERLAY, 83fd2d2fc2SMarek Szyprowski DRM_PLANE_TYPE_CURSOR, 84fd2d2fc2SMarek Szyprowski }; 85fd2d2fc2SMarek Szyprowski 86b2192073SAndrzej Hajda static inline void decon_set_bits(struct decon_context *ctx, u32 reg, u32 mask, 87b2192073SAndrzej Hajda u32 val) 88b2192073SAndrzej Hajda { 89b2192073SAndrzej Hajda val = (val & mask) | (readl(ctx->addr + reg) & ~mask); 90b2192073SAndrzej Hajda writel(val, ctx->addr + reg); 91b2192073SAndrzej Hajda } 92b2192073SAndrzej Hajda 93c8466a91SJoonyoung Shim static int decon_enable_vblank(struct exynos_drm_crtc *crtc) 94c8466a91SJoonyoung Shim { 95c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 96c8466a91SJoonyoung Shim u32 val; 97c8466a91SJoonyoung Shim 987b6bb6edSAndrzej Hajda if (test_bit(BIT_SUSPENDED, &ctx->flags)) 99c8466a91SJoonyoung Shim return -EPERM; 100c8466a91SJoonyoung Shim 101f3fb3d82SMarek Szyprowski if (!test_and_set_bit(BIT_IRQS_ENABLED, &ctx->flags)) { 102c8466a91SJoonyoung Shim val = VIDINTCON0_INTEN; 1039ac26de8SInki Dae if (ctx->out_type & IFTYPE_I80) 104c8466a91SJoonyoung Shim val |= VIDINTCON0_FRAMEDONE; 105c8466a91SJoonyoung Shim else 106c8466a91SJoonyoung Shim val |= VIDINTCON0_INTFRMEN; 107c8466a91SJoonyoung Shim 108c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDINTCON0); 109c8466a91SJoonyoung Shim } 110c8466a91SJoonyoung Shim 111c8466a91SJoonyoung Shim return 0; 112c8466a91SJoonyoung Shim } 113c8466a91SJoonyoung Shim 114c8466a91SJoonyoung Shim static void decon_disable_vblank(struct exynos_drm_crtc *crtc) 115c8466a91SJoonyoung Shim { 116c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 117c8466a91SJoonyoung Shim 1187b6bb6edSAndrzej Hajda if (test_bit(BIT_SUSPENDED, &ctx->flags)) 119c8466a91SJoonyoung Shim return; 120c8466a91SJoonyoung Shim 1217b6bb6edSAndrzej Hajda if (test_and_clear_bit(BIT_IRQS_ENABLED, &ctx->flags)) 122c8466a91SJoonyoung Shim writel(0, ctx->addr + DECON_VIDINTCON0); 123c8466a91SJoonyoung Shim } 124c8466a91SJoonyoung Shim 125c8466a91SJoonyoung Shim static void decon_setup_trigger(struct decon_context *ctx) 126c8466a91SJoonyoung Shim { 127b93c2e8bSAndrzej Hajda if (!(ctx->out_type & (IFTYPE_I80 | I80_HW_TRG))) 128b93c2e8bSAndrzej Hajda return; 129b93c2e8bSAndrzej Hajda 130b93c2e8bSAndrzej Hajda if (!(ctx->out_type & I80_HW_TRG)) { 131b93c2e8bSAndrzej Hajda writel(TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN 132b93c2e8bSAndrzej Hajda | TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN, 133b93c2e8bSAndrzej Hajda ctx->addr + DECON_TRIGCON); 134b93c2e8bSAndrzej Hajda return; 135b93c2e8bSAndrzej Hajda } 136b93c2e8bSAndrzej Hajda 137b93c2e8bSAndrzej Hajda writel(TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F | TRIGCON_HWTRIGMASK 138b93c2e8bSAndrzej Hajda | TRIGCON_HWTRIGEN, ctx->addr + DECON_TRIGCON); 139b93c2e8bSAndrzej Hajda 140b93c2e8bSAndrzej Hajda if (regmap_update_bits(ctx->sysreg, DSD_CFG_MUX, 141b93c2e8bSAndrzej Hajda DSD_CFG_MUX_TE_UNMASK_GLOBAL, ~0)) 142b93c2e8bSAndrzej Hajda DRM_ERROR("Cannot update sysreg.\n"); 143c8466a91SJoonyoung Shim } 144c8466a91SJoonyoung Shim 145c8466a91SJoonyoung Shim static void decon_commit(struct exynos_drm_crtc *crtc) 146c8466a91SJoonyoung Shim { 147c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 14885de275aSAndrzej Hajda struct drm_display_mode *m = &crtc->base.mode; 1495aa6c9acSAndrzej Hajda bool interlaced = false; 150c8466a91SJoonyoung Shim u32 val; 151c8466a91SJoonyoung Shim 1527b6bb6edSAndrzej Hajda if (test_bit(BIT_SUSPENDED, &ctx->flags)) 153c8466a91SJoonyoung Shim return; 154c8466a91SJoonyoung Shim 1559ac26de8SInki Dae if (ctx->out_type & IFTYPE_HDMI) { 156b8182832SAndrzej Hajda m->crtc_hsync_start = m->crtc_hdisplay + 10; 157b8182832SAndrzej Hajda m->crtc_hsync_end = m->crtc_htotal - 92; 158b8182832SAndrzej Hajda m->crtc_vsync_start = m->crtc_vdisplay + 1; 159b8182832SAndrzej Hajda m->crtc_vsync_end = m->crtc_vsync_start + 1; 1605aa6c9acSAndrzej Hajda if (m->flags & DRM_MODE_FLAG_INTERLACE) 1615aa6c9acSAndrzej Hajda interlaced = true; 162b8182832SAndrzej Hajda } 163b8182832SAndrzej Hajda 164dd65a686SAndrzej Hajda decon_setup_trigger(ctx); 165dd65a686SAndrzej Hajda 166c8466a91SJoonyoung Shim /* lcd on and use command if */ 167c8466a91SJoonyoung Shim val = VIDOUT_LCD_ON; 1685aa6c9acSAndrzej Hajda if (interlaced) 1695aa6c9acSAndrzej Hajda val |= VIDOUT_INTERLACE_EN_F; 1709ac26de8SInki Dae if (ctx->out_type & IFTYPE_I80) { 171c8466a91SJoonyoung Shim val |= VIDOUT_COMMAND_IF; 1729ac26de8SInki Dae } else { 173c8466a91SJoonyoung Shim val |= VIDOUT_RGB_IF; 1749ac26de8SInki Dae } 1759ac26de8SInki Dae 176c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDOUTCON0); 177c8466a91SJoonyoung Shim 1785aa6c9acSAndrzej Hajda if (interlaced) 1795aa6c9acSAndrzej Hajda val = VIDTCON2_LINEVAL(m->vdisplay / 2 - 1) | 1805aa6c9acSAndrzej Hajda VIDTCON2_HOZVAL(m->hdisplay - 1); 1815aa6c9acSAndrzej Hajda else 18285de275aSAndrzej Hajda val = VIDTCON2_LINEVAL(m->vdisplay - 1) | 18385de275aSAndrzej Hajda VIDTCON2_HOZVAL(m->hdisplay - 1); 184c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDTCON2); 185c8466a91SJoonyoung Shim 1869ac26de8SInki Dae if (!(ctx->out_type & IFTYPE_I80)) { 1875aa6c9acSAndrzej Hajda int vbp = m->crtc_vtotal - m->crtc_vsync_end; 1885aa6c9acSAndrzej Hajda int vfp = m->crtc_vsync_start - m->crtc_vdisplay; 1895aa6c9acSAndrzej Hajda 1905aa6c9acSAndrzej Hajda if (interlaced) 1915aa6c9acSAndrzej Hajda vbp = vbp / 2 - 1; 1925aa6c9acSAndrzej Hajda val = VIDTCON00_VBPD_F(vbp - 1) | VIDTCON00_VFPD_F(vfp - 1); 193c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDTCON00); 194c8466a91SJoonyoung Shim 195c8466a91SJoonyoung Shim val = VIDTCON01_VSPW_F( 19685de275aSAndrzej Hajda m->crtc_vsync_end - m->crtc_vsync_start - 1); 197c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDTCON01); 198c8466a91SJoonyoung Shim 199c8466a91SJoonyoung Shim val = VIDTCON10_HBPD_F( 20085de275aSAndrzej Hajda m->crtc_htotal - m->crtc_hsync_end - 1) | 201c8466a91SJoonyoung Shim VIDTCON10_HFPD_F( 20285de275aSAndrzej Hajda m->crtc_hsync_start - m->crtc_hdisplay - 1); 203c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDTCON10); 204c8466a91SJoonyoung Shim 205c8466a91SJoonyoung Shim val = VIDTCON11_HSPW_F( 20685de275aSAndrzej Hajda m->crtc_hsync_end - m->crtc_hsync_start - 1); 207c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDTCON11); 208c8466a91SJoonyoung Shim } 209c8466a91SJoonyoung Shim 210c8466a91SJoonyoung Shim /* enable output and display signal */ 211b8182832SAndrzej Hajda decon_set_bits(ctx, DECON_VIDCON0, VIDCON0_ENVID | VIDCON0_ENVID_F, ~0); 21292ead494SAndrzej Hajda 21392ead494SAndrzej Hajda decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); 214c8466a91SJoonyoung Shim } 215c8466a91SJoonyoung Shim 2162eeb2e5eSGustavo Padovan static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win, 2172eeb2e5eSGustavo Padovan struct drm_framebuffer *fb) 218c8466a91SJoonyoung Shim { 219c8466a91SJoonyoung Shim unsigned long val; 220c8466a91SJoonyoung Shim 221c8466a91SJoonyoung Shim val = readl(ctx->addr + DECON_WINCONx(win)); 222c8466a91SJoonyoung Shim val &= ~WINCONx_BPPMODE_MASK; 223c8466a91SJoonyoung Shim 224438b74a5SVille Syrjälä switch (fb->format->format) { 225c8466a91SJoonyoung Shim case DRM_FORMAT_XRGB1555: 226c8466a91SJoonyoung Shim val |= WINCONx_BPPMODE_16BPP_I1555; 227c8466a91SJoonyoung Shim val |= WINCONx_HAWSWP_F; 228c8466a91SJoonyoung Shim val |= WINCONx_BURSTLEN_16WORD; 229c8466a91SJoonyoung Shim break; 230c8466a91SJoonyoung Shim case DRM_FORMAT_RGB565: 231c8466a91SJoonyoung Shim val |= WINCONx_BPPMODE_16BPP_565; 232c8466a91SJoonyoung Shim val |= WINCONx_HAWSWP_F; 233c8466a91SJoonyoung Shim val |= WINCONx_BURSTLEN_16WORD; 234c8466a91SJoonyoung Shim break; 235c8466a91SJoonyoung Shim case DRM_FORMAT_XRGB8888: 236c8466a91SJoonyoung Shim val |= WINCONx_BPPMODE_24BPP_888; 237c8466a91SJoonyoung Shim val |= WINCONx_WSWP_F; 238c8466a91SJoonyoung Shim val |= WINCONx_BURSTLEN_16WORD; 239c8466a91SJoonyoung Shim break; 240c8466a91SJoonyoung Shim case DRM_FORMAT_ARGB8888: 241c8466a91SJoonyoung Shim val |= WINCONx_BPPMODE_32BPP_A8888; 242c8466a91SJoonyoung Shim val |= WINCONx_WSWP_F | WINCONx_BLD_PIX_F | WINCONx_ALPHA_SEL_F; 243c8466a91SJoonyoung Shim val |= WINCONx_BURSTLEN_16WORD; 244c8466a91SJoonyoung Shim break; 245c8466a91SJoonyoung Shim default: 246c8466a91SJoonyoung Shim DRM_ERROR("Proper pixel format is not set\n"); 247c8466a91SJoonyoung Shim return; 248c8466a91SJoonyoung Shim } 249c8466a91SJoonyoung Shim 250272725c7SVille Syrjälä DRM_DEBUG_KMS("bpp = %u\n", fb->format->cpp[0] * 8); 251c8466a91SJoonyoung Shim 252c8466a91SJoonyoung Shim /* 253c8466a91SJoonyoung Shim * In case of exynos, setting dma-burst to 16Word causes permanent 254c8466a91SJoonyoung Shim * tearing for very small buffers, e.g. cursor buffer. Burst Mode 255c8466a91SJoonyoung Shim * switching which is based on plane size is not recommended as 256c8466a91SJoonyoung Shim * plane size varies a lot towards the end of the screen and rapid 257c8466a91SJoonyoung Shim * movement causes unstable DMA which results into iommu crash/tear. 258c8466a91SJoonyoung Shim */ 259c8466a91SJoonyoung Shim 2602eeb2e5eSGustavo Padovan if (fb->width < MIN_FB_WIDTH_FOR_16WORD_BURST) { 261c8466a91SJoonyoung Shim val &= ~WINCONx_BURSTLEN_MASK; 262c8466a91SJoonyoung Shim val |= WINCONx_BURSTLEN_8WORD; 263c8466a91SJoonyoung Shim } 264c8466a91SJoonyoung Shim 265c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_WINCONx(win)); 266c8466a91SJoonyoung Shim } 267c8466a91SJoonyoung Shim 268c8466a91SJoonyoung Shim static void decon_shadow_protect_win(struct decon_context *ctx, int win, 269c8466a91SJoonyoung Shim bool protect) 270c8466a91SJoonyoung Shim { 271b2192073SAndrzej Hajda decon_set_bits(ctx, DECON_SHADOWCON, SHADOWCON_Wx_PROTECT(win), 272b2192073SAndrzej Hajda protect ? ~0 : 0); 273c8466a91SJoonyoung Shim } 274c8466a91SJoonyoung Shim 275d29c2c14SMarek Szyprowski static void decon_atomic_begin(struct exynos_drm_crtc *crtc) 276cc5a7b35SHyungwon Hwang { 277cc5a7b35SHyungwon Hwang struct decon_context *ctx = crtc->ctx; 278d29c2c14SMarek Szyprowski int i; 279cc5a7b35SHyungwon Hwang 2807b6bb6edSAndrzej Hajda if (test_bit(BIT_SUSPENDED, &ctx->flags)) 281cc5a7b35SHyungwon Hwang return; 282cc5a7b35SHyungwon Hwang 283d29c2c14SMarek Szyprowski for (i = ctx->first_win; i < WINDOWS_NR; i++) 284d29c2c14SMarek Szyprowski decon_shadow_protect_win(ctx, i, true); 285cc5a7b35SHyungwon Hwang } 286cc5a7b35SHyungwon Hwang 287b8182832SAndrzej Hajda #define BIT_VAL(x, e, s) (((x) & ((1 << ((e) - (s) + 1)) - 1)) << (s)) 288b8182832SAndrzej Hajda #define COORDINATE_X(x) BIT_VAL((x), 23, 12) 289b8182832SAndrzej Hajda #define COORDINATE_Y(x) BIT_VAL((x), 11, 0) 290b8182832SAndrzej Hajda 2911e1d1393SGustavo Padovan static void decon_update_plane(struct exynos_drm_crtc *crtc, 2921e1d1393SGustavo Padovan struct exynos_drm_plane *plane) 293c8466a91SJoonyoung Shim { 2940114f404SMarek Szyprowski struct exynos_drm_plane_state *state = 2950114f404SMarek Szyprowski to_exynos_plane_state(plane->base.state); 296c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 2970114f404SMarek Szyprowski struct drm_framebuffer *fb = state->base.fb; 29840bdfb0aSMarek Szyprowski unsigned int win = plane->index; 299272725c7SVille Syrjälä unsigned int bpp = fb->format->cpp[0]; 3000488f50eSMarek Szyprowski unsigned int pitch = fb->pitches[0]; 3010488f50eSMarek Szyprowski dma_addr_t dma_addr = exynos_drm_fb_dma_addr(fb, 0); 302c8466a91SJoonyoung Shim u32 val; 303c8466a91SJoonyoung Shim 3047b6bb6edSAndrzej Hajda if (test_bit(BIT_SUSPENDED, &ctx->flags)) 305c8466a91SJoonyoung Shim return; 306c8466a91SJoonyoung Shim 3075aa6c9acSAndrzej Hajda if (crtc->base.mode.flags & DRM_MODE_FLAG_INTERLACE) { 3085aa6c9acSAndrzej Hajda val = COORDINATE_X(state->crtc.x) | 3095aa6c9acSAndrzej Hajda COORDINATE_Y(state->crtc.y / 2); 3105aa6c9acSAndrzej Hajda writel(val, ctx->addr + DECON_VIDOSDxA(win)); 3115aa6c9acSAndrzej Hajda 3125aa6c9acSAndrzej Hajda val = COORDINATE_X(state->crtc.x + state->crtc.w - 1) | 3135aa6c9acSAndrzej Hajda COORDINATE_Y((state->crtc.y + state->crtc.h) / 2 - 1); 3145aa6c9acSAndrzej Hajda writel(val, ctx->addr + DECON_VIDOSDxB(win)); 3155aa6c9acSAndrzej Hajda } else { 3160114f404SMarek Szyprowski val = COORDINATE_X(state->crtc.x) | COORDINATE_Y(state->crtc.y); 317c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDOSDxA(win)); 318c8466a91SJoonyoung Shim 3190114f404SMarek Szyprowski val = COORDINATE_X(state->crtc.x + state->crtc.w - 1) | 3200114f404SMarek Szyprowski COORDINATE_Y(state->crtc.y + state->crtc.h - 1); 321c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDOSDxB(win)); 3225aa6c9acSAndrzej Hajda } 323c8466a91SJoonyoung Shim 324c8466a91SJoonyoung Shim val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | 325c8466a91SJoonyoung Shim VIDOSD_Wx_ALPHA_B_F(0x0); 326c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDOSDxC(win)); 327c8466a91SJoonyoung Shim 328c8466a91SJoonyoung Shim val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | 329c8466a91SJoonyoung Shim VIDOSD_Wx_ALPHA_B_F(0x0); 330c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDOSDxD(win)); 331c8466a91SJoonyoung Shim 3320488f50eSMarek Szyprowski writel(dma_addr, ctx->addr + DECON_VIDW0xADD0B0(win)); 333c8466a91SJoonyoung Shim 3340114f404SMarek Szyprowski val = dma_addr + pitch * state->src.h; 335c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDW0xADD1B0(win)); 336c8466a91SJoonyoung Shim 3379ac26de8SInki Dae if (!(ctx->out_type & IFTYPE_HDMI)) 3380114f404SMarek Szyprowski val = BIT_VAL(pitch - state->crtc.w * bpp, 27, 14) 3390114f404SMarek Szyprowski | BIT_VAL(state->crtc.w * bpp, 13, 0); 340b8182832SAndrzej Hajda else 3410114f404SMarek Szyprowski val = BIT_VAL(pitch - state->crtc.w * bpp, 29, 15) 3420114f404SMarek Szyprowski | BIT_VAL(state->crtc.w * bpp, 14, 0); 343c8466a91SJoonyoung Shim writel(val, ctx->addr + DECON_VIDW0xADD2(win)); 344c8466a91SJoonyoung Shim 3450488f50eSMarek Szyprowski decon_win_set_pixfmt(ctx, win, fb); 346c8466a91SJoonyoung Shim 347c8466a91SJoonyoung Shim /* window enable */ 348b2192073SAndrzej Hajda decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, ~0); 349821b40b7SAndrzej Hajda set_bit(BIT_REQUEST_UPDATE, &ctx->flags); 350c8466a91SJoonyoung Shim } 351c8466a91SJoonyoung Shim 3521e1d1393SGustavo Padovan static void decon_disable_plane(struct exynos_drm_crtc *crtc, 3531e1d1393SGustavo Padovan struct exynos_drm_plane *plane) 354c8466a91SJoonyoung Shim { 355c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 35640bdfb0aSMarek Szyprowski unsigned int win = plane->index; 357c8466a91SJoonyoung Shim 3587b6bb6edSAndrzej Hajda if (test_bit(BIT_SUSPENDED, &ctx->flags)) 359c8466a91SJoonyoung Shim return; 360c8466a91SJoonyoung Shim 361b2192073SAndrzej Hajda decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0); 362821b40b7SAndrzej Hajda set_bit(BIT_REQUEST_UPDATE, &ctx->flags); 363c8466a91SJoonyoung Shim } 364c8466a91SJoonyoung Shim 365d29c2c14SMarek Szyprowski static void decon_atomic_flush(struct exynos_drm_crtc *crtc) 366cc5a7b35SHyungwon Hwang { 367cc5a7b35SHyungwon Hwang struct decon_context *ctx = crtc->ctx; 368d29c2c14SMarek Szyprowski int i; 369cc5a7b35SHyungwon Hwang 3707b6bb6edSAndrzej Hajda if (test_bit(BIT_SUSPENDED, &ctx->flags)) 371cc5a7b35SHyungwon Hwang return; 372cc5a7b35SHyungwon Hwang 373d29c2c14SMarek Szyprowski for (i = ctx->first_win; i < WINDOWS_NR; i++) 374d29c2c14SMarek Szyprowski decon_shadow_protect_win(ctx, i, false); 375cc5a7b35SHyungwon Hwang 376821b40b7SAndrzej Hajda if (test_and_clear_bit(BIT_REQUEST_UPDATE, &ctx->flags)) 37792ead494SAndrzej Hajda decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); 37892ead494SAndrzej Hajda 3799ac26de8SInki Dae if (ctx->out_type & IFTYPE_I80) 3807b6bb6edSAndrzej Hajda set_bit(BIT_WIN_UPDATED, &ctx->flags); 381cc5a7b35SHyungwon Hwang } 382cc5a7b35SHyungwon Hwang 383c8466a91SJoonyoung Shim static void decon_swreset(struct decon_context *ctx) 384c8466a91SJoonyoung Shim { 385c8466a91SJoonyoung Shim unsigned int tries; 386c8466a91SJoonyoung Shim 387c8466a91SJoonyoung Shim writel(0, ctx->addr + DECON_VIDCON0); 388c8466a91SJoonyoung Shim for (tries = 2000; tries; --tries) { 389c8466a91SJoonyoung Shim if (~readl(ctx->addr + DECON_VIDCON0) & VIDCON0_STOP_STATUS) 390c8466a91SJoonyoung Shim break; 391c8466a91SJoonyoung Shim udelay(10); 392c8466a91SJoonyoung Shim } 393c8466a91SJoonyoung Shim 394c8466a91SJoonyoung Shim writel(VIDCON0_SWRESET, ctx->addr + DECON_VIDCON0); 395c8466a91SJoonyoung Shim for (tries = 2000; tries; --tries) { 396c8466a91SJoonyoung Shim if (~readl(ctx->addr + DECON_VIDCON0) & VIDCON0_SWRESET) 397c8466a91SJoonyoung Shim break; 398c8466a91SJoonyoung Shim udelay(10); 399c8466a91SJoonyoung Shim } 400c8466a91SJoonyoung Shim 401c8466a91SJoonyoung Shim WARN(tries == 0, "failed to software reset DECON\n"); 402b8182832SAndrzej Hajda 4039ac26de8SInki Dae if (!(ctx->out_type & IFTYPE_HDMI)) 404b8182832SAndrzej Hajda return; 405b8182832SAndrzej Hajda 406b8182832SAndrzej Hajda writel(VIDCON0_CLKVALUP | VIDCON0_VLCKFREE, ctx->addr + DECON_VIDCON0); 407b8182832SAndrzej Hajda decon_set_bits(ctx, DECON_CMU, 408b8182832SAndrzej Hajda CMU_CLKGAGE_MODE_SFR_F | CMU_CLKGAGE_MODE_MEM_F, ~0); 409b8182832SAndrzej Hajda writel(VIDCON1_VCLK_RUN_VDEN_DISABLE, ctx->addr + DECON_VIDCON1); 410b8182832SAndrzej Hajda writel(CRCCTRL_CRCEN | CRCCTRL_CRCSTART_F | CRCCTRL_CRCCLKEN, 411b8182832SAndrzej Hajda ctx->addr + DECON_CRCCTRL); 412c8466a91SJoonyoung Shim } 413c8466a91SJoonyoung Shim 414c8466a91SJoonyoung Shim static void decon_enable(struct exynos_drm_crtc *crtc) 415c8466a91SJoonyoung Shim { 416c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 417c8466a91SJoonyoung Shim 4187b6bb6edSAndrzej Hajda if (!test_and_clear_bit(BIT_SUSPENDED, &ctx->flags)) 419c8466a91SJoonyoung Shim return; 420c8466a91SJoonyoung Shim 421c8466a91SJoonyoung Shim pm_runtime_get_sync(ctx->dev); 422c8466a91SJoonyoung Shim 423c60230ebSAndrzej Hajda exynos_drm_pipe_clk_enable(crtc, true); 424c60230ebSAndrzej Hajda 4257b6bb6edSAndrzej Hajda set_bit(BIT_CLKS_ENABLED, &ctx->flags); 426c8466a91SJoonyoung Shim 427e87b3c62SAndrzej Hajda decon_swreset(ctx); 428e87b3c62SAndrzej Hajda 429c8466a91SJoonyoung Shim /* if vblank was enabled status, enable it again. */ 4307b6bb6edSAndrzej Hajda if (test_and_clear_bit(BIT_IRQS_ENABLED, &ctx->flags)) 431c8466a91SJoonyoung Shim decon_enable_vblank(ctx->crtc); 432c8466a91SJoonyoung Shim 433c8466a91SJoonyoung Shim decon_commit(ctx->crtc); 434c8466a91SJoonyoung Shim } 435c8466a91SJoonyoung Shim 436c8466a91SJoonyoung Shim static void decon_disable(struct exynos_drm_crtc *crtc) 437c8466a91SJoonyoung Shim { 438c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 439c8466a91SJoonyoung Shim int i; 440c8466a91SJoonyoung Shim 4417b6bb6edSAndrzej Hajda if (test_bit(BIT_SUSPENDED, &ctx->flags)) 442c8466a91SJoonyoung Shim return; 443c8466a91SJoonyoung Shim 444c8466a91SJoonyoung Shim /* 445c8466a91SJoonyoung Shim * We need to make sure that all windows are disabled before we 446c8466a91SJoonyoung Shim * suspend that connector. Otherwise we might try to scan from 447c8466a91SJoonyoung Shim * a destroyed buffer later. 448c8466a91SJoonyoung Shim */ 449b8182832SAndrzej Hajda for (i = ctx->first_win; i < WINDOWS_NR; i++) 4501e1d1393SGustavo Padovan decon_disable_plane(crtc, &ctx->planes[i]); 451c8466a91SJoonyoung Shim 452c8466a91SJoonyoung Shim decon_swreset(ctx); 453c8466a91SJoonyoung Shim 4547b6bb6edSAndrzej Hajda clear_bit(BIT_CLKS_ENABLED, &ctx->flags); 455c8466a91SJoonyoung Shim 456c60230ebSAndrzej Hajda exynos_drm_pipe_clk_enable(crtc, false); 457c60230ebSAndrzej Hajda 458c8466a91SJoonyoung Shim pm_runtime_put_sync(ctx->dev); 459c8466a91SJoonyoung Shim 4607b6bb6edSAndrzej Hajda set_bit(BIT_SUSPENDED, &ctx->flags); 461c8466a91SJoonyoung Shim } 462c8466a91SJoonyoung Shim 4639844d6ebSAndrzej Hajda static void decon_te_irq_handler(struct exynos_drm_crtc *crtc) 464c8466a91SJoonyoung Shim { 465c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 466c8466a91SJoonyoung Shim 4673f4c8e5cSAndrzej Hajda if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags) || 4683f4c8e5cSAndrzej Hajda (ctx->out_type & I80_HW_TRG)) 469c8466a91SJoonyoung Shim return; 470c8466a91SJoonyoung Shim 4717b6bb6edSAndrzej Hajda if (test_and_clear_bit(BIT_WIN_UPDATED, &ctx->flags)) 472b2192073SAndrzej Hajda decon_set_bits(ctx, DECON_TRIGCON, TRIGCON_SWTRIGCMD, ~0); 473c8466a91SJoonyoung Shim } 474c8466a91SJoonyoung Shim 475c8466a91SJoonyoung Shim static void decon_clear_channels(struct exynos_drm_crtc *crtc) 476c8466a91SJoonyoung Shim { 477c8466a91SJoonyoung Shim struct decon_context *ctx = crtc->ctx; 478c8466a91SJoonyoung Shim int win, i, ret; 479c8466a91SJoonyoung Shim 480c8466a91SJoonyoung Shim DRM_DEBUG_KMS("%s\n", __FILE__); 481c8466a91SJoonyoung Shim 482c8466a91SJoonyoung Shim for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { 483c8466a91SJoonyoung Shim ret = clk_prepare_enable(ctx->clks[i]); 484c8466a91SJoonyoung Shim if (ret < 0) 485c8466a91SJoonyoung Shim goto err; 486c8466a91SJoonyoung Shim } 487c8466a91SJoonyoung Shim 488c8466a91SJoonyoung Shim for (win = 0; win < WINDOWS_NR; win++) { 489b2192073SAndrzej Hajda decon_shadow_protect_win(ctx, win, true); 490b2192073SAndrzej Hajda decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0); 491b2192073SAndrzej Hajda decon_shadow_protect_win(ctx, win, false); 492c8466a91SJoonyoung Shim } 49392ead494SAndrzej Hajda 49492ead494SAndrzej Hajda decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); 49592ead494SAndrzej Hajda 496c8466a91SJoonyoung Shim /* TODO: wait for possible vsync */ 497c8466a91SJoonyoung Shim msleep(50); 498c8466a91SJoonyoung Shim 499c8466a91SJoonyoung Shim err: 500c8466a91SJoonyoung Shim while (--i >= 0) 501c8466a91SJoonyoung Shim clk_disable_unprepare(ctx->clks[i]); 502c8466a91SJoonyoung Shim } 503c8466a91SJoonyoung Shim 504fc36ec76SBhumika Goyal static const struct exynos_drm_crtc_ops decon_crtc_ops = { 505c8466a91SJoonyoung Shim .enable = decon_enable, 506c8466a91SJoonyoung Shim .disable = decon_disable, 507c8466a91SJoonyoung Shim .enable_vblank = decon_enable_vblank, 508c8466a91SJoonyoung Shim .disable_vblank = decon_disable_vblank, 509cc5a7b35SHyungwon Hwang .atomic_begin = decon_atomic_begin, 5109cc7610aSGustavo Padovan .update_plane = decon_update_plane, 5119cc7610aSGustavo Padovan .disable_plane = decon_disable_plane, 512cc5a7b35SHyungwon Hwang .atomic_flush = decon_atomic_flush, 513c8466a91SJoonyoung Shim .te_handler = decon_te_irq_handler, 514c8466a91SJoonyoung Shim }; 515c8466a91SJoonyoung Shim 516c8466a91SJoonyoung Shim static int decon_bind(struct device *dev, struct device *master, void *data) 517c8466a91SJoonyoung Shim { 518c8466a91SJoonyoung Shim struct decon_context *ctx = dev_get_drvdata(dev); 519c8466a91SJoonyoung Shim struct drm_device *drm_dev = data; 520c8466a91SJoonyoung Shim struct exynos_drm_private *priv = drm_dev->dev_private; 521c8466a91SJoonyoung Shim struct exynos_drm_plane *exynos_plane; 522b8182832SAndrzej Hajda enum exynos_drm_output_type out_type; 523b8182832SAndrzej Hajda unsigned int win; 524c8466a91SJoonyoung Shim int ret; 525c8466a91SJoonyoung Shim 526c8466a91SJoonyoung Shim ctx->drm_dev = drm_dev; 527c8466a91SJoonyoung Shim ctx->pipe = priv->pipe++; 528c8466a91SJoonyoung Shim 529b8182832SAndrzej Hajda for (win = ctx->first_win; win < WINDOWS_NR; win++) { 530b8182832SAndrzej Hajda int tmp = (win == ctx->first_win) ? 0 : win; 531b8182832SAndrzej Hajda 532fd2d2fc2SMarek Szyprowski ctx->configs[win].pixel_formats = decon_formats; 533fd2d2fc2SMarek Szyprowski ctx->configs[win].num_pixel_formats = ARRAY_SIZE(decon_formats); 534fd2d2fc2SMarek Szyprowski ctx->configs[win].zpos = win; 535fd2d2fc2SMarek Szyprowski ctx->configs[win].type = decon_win_types[tmp]; 536fd2d2fc2SMarek Szyprowski 53740bdfb0aSMarek Szyprowski ret = exynos_plane_init(drm_dev, &ctx->planes[win], win, 538fd2d2fc2SMarek Szyprowski 1 << ctx->pipe, &ctx->configs[win]); 539c8466a91SJoonyoung Shim if (ret) 540c8466a91SJoonyoung Shim return ret; 541c8466a91SJoonyoung Shim } 542c8466a91SJoonyoung Shim 543b8182832SAndrzej Hajda exynos_plane = &ctx->planes[ctx->first_win]; 5449ac26de8SInki Dae out_type = (ctx->out_type & IFTYPE_HDMI) ? EXYNOS_DISPLAY_TYPE_HDMI 545b8182832SAndrzej Hajda : EXYNOS_DISPLAY_TYPE_LCD; 546c8466a91SJoonyoung Shim ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, 547b8182832SAndrzej Hajda ctx->pipe, out_type, 548c8466a91SJoonyoung Shim &decon_crtc_ops, ctx); 549c8466a91SJoonyoung Shim if (IS_ERR(ctx->crtc)) { 550c8466a91SJoonyoung Shim ret = PTR_ERR(ctx->crtc); 551c8466a91SJoonyoung Shim goto err; 552c8466a91SJoonyoung Shim } 553c8466a91SJoonyoung Shim 554eb7a3fc7SJoonyoung Shim decon_clear_channels(ctx->crtc); 555eb7a3fc7SJoonyoung Shim 556eb7a3fc7SJoonyoung Shim ret = drm_iommu_attach_device(drm_dev, dev); 557c8466a91SJoonyoung Shim if (ret) 558c8466a91SJoonyoung Shim goto err; 559c8466a91SJoonyoung Shim 560c8466a91SJoonyoung Shim return ret; 561c8466a91SJoonyoung Shim err: 562c8466a91SJoonyoung Shim priv->pipe--; 563c8466a91SJoonyoung Shim return ret; 564c8466a91SJoonyoung Shim } 565c8466a91SJoonyoung Shim 566c8466a91SJoonyoung Shim static void decon_unbind(struct device *dev, struct device *master, void *data) 567c8466a91SJoonyoung Shim { 568c8466a91SJoonyoung Shim struct decon_context *ctx = dev_get_drvdata(dev); 569c8466a91SJoonyoung Shim 570c8466a91SJoonyoung Shim decon_disable(ctx->crtc); 571c8466a91SJoonyoung Shim 572c8466a91SJoonyoung Shim /* detach this sub driver from iommu mapping if supported. */ 573c8466a91SJoonyoung Shim drm_iommu_detach_device(ctx->drm_dev, ctx->dev); 574c8466a91SJoonyoung Shim } 575c8466a91SJoonyoung Shim 576c8466a91SJoonyoung Shim static const struct component_ops decon_component_ops = { 577c8466a91SJoonyoung Shim .bind = decon_bind, 578c8466a91SJoonyoung Shim .unbind = decon_unbind, 579c8466a91SJoonyoung Shim }; 580c8466a91SJoonyoung Shim 581b8182832SAndrzej Hajda static irqreturn_t decon_irq_handler(int irq, void *dev_id) 582c8466a91SJoonyoung Shim { 583c8466a91SJoonyoung Shim struct decon_context *ctx = dev_id; 584c8466a91SJoonyoung Shim u32 val; 585c8466a91SJoonyoung Shim 5867b6bb6edSAndrzej Hajda if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags)) 587c8466a91SJoonyoung Shim goto out; 588c8466a91SJoonyoung Shim 589c8466a91SJoonyoung Shim val = readl(ctx->addr + DECON_VIDINTCON1); 590b8182832SAndrzej Hajda val &= VIDINTCON1_INTFRMDONEPEND | VIDINTCON1_INTFRMPEND; 591b8182832SAndrzej Hajda 592b8182832SAndrzej Hajda if (val) { 593b8182832SAndrzej Hajda writel(val, ctx->addr + DECON_VIDINTCON1); 5941514d50bSAndrzej Hajda if (ctx->out_type & IFTYPE_HDMI) { 5951514d50bSAndrzej Hajda val = readl(ctx->addr + DECON_VIDOUTCON0); 5961514d50bSAndrzej Hajda val &= VIDOUT_INTERLACE_EN_F | VIDOUT_INTERLACE_FIELD_F; 5971514d50bSAndrzej Hajda if (val == 5981514d50bSAndrzej Hajda (VIDOUT_INTERLACE_EN_F | VIDOUT_INTERLACE_FIELD_F)) 5991514d50bSAndrzej Hajda return IRQ_HANDLED; 6001514d50bSAndrzej Hajda } 601b0bb3d07SAndrzej Hajda drm_crtc_handle_vblank(&ctx->crtc->base); 602c8466a91SJoonyoung Shim } 603c8466a91SJoonyoung Shim 604c8466a91SJoonyoung Shim out: 605c8466a91SJoonyoung Shim return IRQ_HANDLED; 606c8466a91SJoonyoung Shim } 607c8466a91SJoonyoung Shim 608ebf3fd40SGustavo Padovan #ifdef CONFIG_PM 609ebf3fd40SGustavo Padovan static int exynos5433_decon_suspend(struct device *dev) 610ebf3fd40SGustavo Padovan { 611ebf3fd40SGustavo Padovan struct decon_context *ctx = dev_get_drvdata(dev); 61292c96ff8SAndrzej Hajda int i = ARRAY_SIZE(decon_clks_name); 613ebf3fd40SGustavo Padovan 61492c96ff8SAndrzej Hajda while (--i >= 0) 615ebf3fd40SGustavo Padovan clk_disable_unprepare(ctx->clks[i]); 616ebf3fd40SGustavo Padovan 617ebf3fd40SGustavo Padovan return 0; 618ebf3fd40SGustavo Padovan } 619ebf3fd40SGustavo Padovan 620ebf3fd40SGustavo Padovan static int exynos5433_decon_resume(struct device *dev) 621ebf3fd40SGustavo Padovan { 622ebf3fd40SGustavo Padovan struct decon_context *ctx = dev_get_drvdata(dev); 623ebf3fd40SGustavo Padovan int i, ret; 624ebf3fd40SGustavo Padovan 625ebf3fd40SGustavo Padovan for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { 626ebf3fd40SGustavo Padovan ret = clk_prepare_enable(ctx->clks[i]); 627ebf3fd40SGustavo Padovan if (ret < 0) 628ebf3fd40SGustavo Padovan goto err; 629ebf3fd40SGustavo Padovan } 630ebf3fd40SGustavo Padovan 631ebf3fd40SGustavo Padovan return 0; 632ebf3fd40SGustavo Padovan 633ebf3fd40SGustavo Padovan err: 634ebf3fd40SGustavo Padovan while (--i >= 0) 635ebf3fd40SGustavo Padovan clk_disable_unprepare(ctx->clks[i]); 636ebf3fd40SGustavo Padovan 637ebf3fd40SGustavo Padovan return ret; 638ebf3fd40SGustavo Padovan } 639ebf3fd40SGustavo Padovan #endif 640ebf3fd40SGustavo Padovan 641ebf3fd40SGustavo Padovan static const struct dev_pm_ops exynos5433_decon_pm_ops = { 642ebf3fd40SGustavo Padovan SET_RUNTIME_PM_OPS(exynos5433_decon_suspend, exynos5433_decon_resume, 643ebf3fd40SGustavo Padovan NULL) 644ebf3fd40SGustavo Padovan }; 645ebf3fd40SGustavo Padovan 646b8182832SAndrzej Hajda static const struct of_device_id exynos5433_decon_driver_dt_match[] = { 647b8182832SAndrzej Hajda { 648b8182832SAndrzej Hajda .compatible = "samsung,exynos5433-decon", 6499ac26de8SInki Dae .data = (void *)I80_HW_TRG 650b8182832SAndrzej Hajda }, 651b8182832SAndrzej Hajda { 652b8182832SAndrzej Hajda .compatible = "samsung,exynos5433-decon-tv", 6539ac26de8SInki Dae .data = (void *)(I80_HW_TRG | IFTYPE_HDMI) 654b8182832SAndrzej Hajda }, 655b8182832SAndrzej Hajda {}, 656b8182832SAndrzej Hajda }; 657b8182832SAndrzej Hajda MODULE_DEVICE_TABLE(of, exynos5433_decon_driver_dt_match); 658b8182832SAndrzej Hajda 659c8466a91SJoonyoung Shim static int exynos5433_decon_probe(struct platform_device *pdev) 660c8466a91SJoonyoung Shim { 661c8466a91SJoonyoung Shim struct device *dev = &pdev->dev; 662c8466a91SJoonyoung Shim struct decon_context *ctx; 663c8466a91SJoonyoung Shim struct resource *res; 664c8466a91SJoonyoung Shim int ret; 665c8466a91SJoonyoung Shim int i; 666c8466a91SJoonyoung Shim 667c8466a91SJoonyoung Shim ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 668c8466a91SJoonyoung Shim if (!ctx) 669c8466a91SJoonyoung Shim return -ENOMEM; 670c8466a91SJoonyoung Shim 6717b6bb6edSAndrzej Hajda __set_bit(BIT_SUSPENDED, &ctx->flags); 672c8466a91SJoonyoung Shim ctx->dev = dev; 6739ac26de8SInki Dae ctx->out_type = (unsigned long)of_device_get_match_data(dev); 674b8182832SAndrzej Hajda 6759ac26de8SInki Dae if (ctx->out_type & IFTYPE_HDMI) { 676b8182832SAndrzej Hajda ctx->first_win = 1; 6779ac26de8SInki Dae } else if (of_get_child_by_name(dev->of_node, "i80-if-timings")) { 678dd65a686SAndrzej Hajda ctx->out_type |= IFTYPE_I80; 6799ac26de8SInki Dae } 680c8466a91SJoonyoung Shim 681b93c2e8bSAndrzej Hajda if (ctx->out_type | I80_HW_TRG) { 682b93c2e8bSAndrzej Hajda ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node, 683b93c2e8bSAndrzej Hajda "samsung,disp-sysreg"); 684b93c2e8bSAndrzej Hajda if (IS_ERR(ctx->sysreg)) { 685b93c2e8bSAndrzej Hajda dev_err(dev, "failed to get system register\n"); 686b93c2e8bSAndrzej Hajda return PTR_ERR(ctx->sysreg); 687b93c2e8bSAndrzej Hajda } 688b93c2e8bSAndrzej Hajda } 689b93c2e8bSAndrzej Hajda 690c8466a91SJoonyoung Shim for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { 691c8466a91SJoonyoung Shim struct clk *clk; 692c8466a91SJoonyoung Shim 693c8466a91SJoonyoung Shim clk = devm_clk_get(ctx->dev, decon_clks_name[i]); 694c8466a91SJoonyoung Shim if (IS_ERR(clk)) 695c8466a91SJoonyoung Shim return PTR_ERR(clk); 696c8466a91SJoonyoung Shim 697c8466a91SJoonyoung Shim ctx->clks[i] = clk; 698c8466a91SJoonyoung Shim } 699c8466a91SJoonyoung Shim 700c8466a91SJoonyoung Shim res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 701c8466a91SJoonyoung Shim if (!res) { 702c8466a91SJoonyoung Shim dev_err(dev, "cannot find IO resource\n"); 703c8466a91SJoonyoung Shim return -ENXIO; 704c8466a91SJoonyoung Shim } 705c8466a91SJoonyoung Shim 706c8466a91SJoonyoung Shim ctx->addr = devm_ioremap_resource(dev, res); 707c8466a91SJoonyoung Shim if (IS_ERR(ctx->addr)) { 708c8466a91SJoonyoung Shim dev_err(dev, "ioremap failed\n"); 709c8466a91SJoonyoung Shim return PTR_ERR(ctx->addr); 710c8466a91SJoonyoung Shim } 711c8466a91SJoonyoung Shim 712c8466a91SJoonyoung Shim res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, 7139ac26de8SInki Dae (ctx->out_type & IFTYPE_I80) ? "lcd_sys" : "vsync"); 714c8466a91SJoonyoung Shim if (!res) { 715c8466a91SJoonyoung Shim dev_err(dev, "cannot find IRQ resource\n"); 716c8466a91SJoonyoung Shim return -ENXIO; 717c8466a91SJoonyoung Shim } 718c8466a91SJoonyoung Shim 719b8182832SAndrzej Hajda ret = devm_request_irq(dev, res->start, decon_irq_handler, 0, 720c8466a91SJoonyoung Shim "drm_decon", ctx); 721c8466a91SJoonyoung Shim if (ret < 0) { 722c8466a91SJoonyoung Shim dev_err(dev, "lcd_sys irq request failed\n"); 723c8466a91SJoonyoung Shim return ret; 724c8466a91SJoonyoung Shim } 725c8466a91SJoonyoung Shim 726c8466a91SJoonyoung Shim platform_set_drvdata(pdev, ctx); 727c8466a91SJoonyoung Shim 728c8466a91SJoonyoung Shim pm_runtime_enable(dev); 729c8466a91SJoonyoung Shim 730c8466a91SJoonyoung Shim ret = component_add(dev, &decon_component_ops); 731c8466a91SJoonyoung Shim if (ret) 732c8466a91SJoonyoung Shim goto err_disable_pm_runtime; 733c8466a91SJoonyoung Shim 734c8466a91SJoonyoung Shim return 0; 735c8466a91SJoonyoung Shim 736c8466a91SJoonyoung Shim err_disable_pm_runtime: 737c8466a91SJoonyoung Shim pm_runtime_disable(dev); 738c8466a91SJoonyoung Shim 739c8466a91SJoonyoung Shim return ret; 740c8466a91SJoonyoung Shim } 741c8466a91SJoonyoung Shim 742c8466a91SJoonyoung Shim static int exynos5433_decon_remove(struct platform_device *pdev) 743c8466a91SJoonyoung Shim { 744c8466a91SJoonyoung Shim pm_runtime_disable(&pdev->dev); 745c8466a91SJoonyoung Shim 746c8466a91SJoonyoung Shim component_del(&pdev->dev, &decon_component_ops); 747c8466a91SJoonyoung Shim 748c8466a91SJoonyoung Shim return 0; 749c8466a91SJoonyoung Shim } 750c8466a91SJoonyoung Shim 751c8466a91SJoonyoung Shim struct platform_driver exynos5433_decon_driver = { 752c8466a91SJoonyoung Shim .probe = exynos5433_decon_probe, 753c8466a91SJoonyoung Shim .remove = exynos5433_decon_remove, 754c8466a91SJoonyoung Shim .driver = { 755c8466a91SJoonyoung Shim .name = "exynos5433-decon", 756ebf3fd40SGustavo Padovan .pm = &exynos5433_decon_pm_ops, 757c8466a91SJoonyoung Shim .of_match_table = exynos5433_decon_driver_dt_match, 758c8466a91SJoonyoung Shim }, 759c8466a91SJoonyoung Shim }; 760