diff options
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_fimd.c')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fimd.c | 390 |
1 files changed, 177 insertions, 213 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index e5810d13bf9c..9819fa6a9e2a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -31,7 +31,9 @@ #include "exynos_drm_drv.h" #include "exynos_drm_fbdev.h" #include "exynos_drm_crtc.h" +#include "exynos_drm_plane.h" #include "exynos_drm_iommu.h" +#include "exynos_drm_fimd.h" /* * FIMD stands for Fully Interactive Mobile Display and @@ -54,6 +56,9 @@ /* size control register for hardware windows 1 ~ 2. */ #define VIDOSD_D(win) (VIDOSD_BASE + 0x0C + (win) * 16) +#define VIDWnALPHA0(win) (VIDW_ALPHA + 0x00 + (win) * 8) +#define VIDWnALPHA1(win) (VIDW_ALPHA + 0x04 + (win) * 8) + #define VIDWx_BUF_START(win, buf) (VIDW_BUF_START(buf) + (win) * 8) #define VIDWx_BUF_END(win, buf) (VIDW_BUF_END(buf) + (win) * 8) #define VIDWx_BUF_SIZE(win, buf) (VIDW_BUF_SIZE(buf) + (win) * 4) @@ -140,32 +145,15 @@ static struct fimd_driver_data exynos5_fimd_driver_data = { .has_vtsel = 1, }; -struct fimd_win_data { - unsigned int offset_x; - unsigned int offset_y; - unsigned int ovl_width; - unsigned int ovl_height; - unsigned int fb_width; - unsigned int fb_height; - unsigned int bpp; - unsigned int pixel_format; - dma_addr_t dma_addr; - unsigned int buf_offsize; - unsigned int line_size; /* bytes */ - bool enabled; - bool resume; -}; - struct fimd_context { - struct exynos_drm_manager manager; struct device *dev; struct drm_device *drm_dev; + struct exynos_drm_crtc *crtc; + struct exynos_drm_plane planes[WINDOWS_NR]; struct clk *bus_clk; struct clk *lcd_clk; void __iomem *regs; struct regmap *sysreg; - struct drm_display_mode mode; - struct fimd_win_data win_data[WINDOWS_NR]; unsigned int default_win; unsigned long irq_flags; u32 vidcon0; @@ -185,11 +173,6 @@ struct fimd_context { struct exynos_drm_display *display; }; -static inline struct fimd_context *mgr_to_fimd(struct exynos_drm_manager *mgr) -{ - return container_of(mgr, struct fimd_context, manager); -} - static const struct of_device_id fimd_driver_dt_match[] = { { .compatible = "samsung,s3c6400-fimd", .data = &s3c64xx_fimd_driver_data }, @@ -214,9 +197,9 @@ static inline struct fimd_driver_data *drm_fimd_get_driver_data( return (struct fimd_driver_data *)of_id->data; } -static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr) +static void fimd_wait_for_vblank(struct exynos_drm_crtc *crtc) { - struct fimd_context *ctx = mgr_to_fimd(mgr); + struct fimd_context *ctx = crtc->ctx; if (ctx->suspended) return; @@ -259,9 +242,8 @@ static void fimd_enable_shadow_channel_path(struct fimd_context *ctx, int win, writel(val, ctx->regs + SHADOWCON); } -static void fimd_clear_channel(struct exynos_drm_manager *mgr) +static void fimd_clear_channel(struct fimd_context *ctx) { - struct fimd_context *ctx = mgr_to_fimd(mgr); int win, ch_enabled = 0; DRM_DEBUG_KMS("%s\n", __FILE__); @@ -286,38 +268,37 @@ static void fimd_clear_channel(struct exynos_drm_manager *mgr) unsigned int state = ctx->suspended; ctx->suspended = 0; - fimd_wait_for_vblank(mgr); + fimd_wait_for_vblank(ctx->crtc); ctx->suspended = state; } } -static int fimd_mgr_initialize(struct exynos_drm_manager *mgr, +static int fimd_iommu_attach_devices(struct fimd_context *ctx, struct drm_device *drm_dev) { - struct fimd_context *ctx = mgr_to_fimd(mgr); - struct exynos_drm_private *priv; - priv = drm_dev->dev_private; - - mgr->drm_dev = ctx->drm_dev = drm_dev; - mgr->pipe = ctx->pipe = priv->pipe++; /* attach this sub driver to iommu mapping if supported. */ if (is_drm_iommu_supported(ctx->drm_dev)) { + int ret; + /* * If any channel is already active, iommu will throw * a PAGE FAULT when enabled. So clear any channel if enabled. */ - fimd_clear_channel(mgr); - drm_iommu_attach_device(ctx->drm_dev, ctx->dev); + fimd_clear_channel(ctx); + ret = drm_iommu_attach_device(ctx->drm_dev, ctx->dev); + if (ret) { + DRM_ERROR("drm_iommu_attach failed.\n"); + return ret; + } + } return 0; } -static void fimd_mgr_remove(struct exynos_drm_manager *mgr) +static void fimd_iommu_detach_devices(struct fimd_context *ctx) { - struct fimd_context *ctx = mgr_to_fimd(mgr); - /* detach this sub driver from iommu mapping if supported. */ if (is_drm_iommu_supported(ctx->drm_dev)) drm_iommu_detach_device(ctx->drm_dev, ctx->dev); @@ -343,7 +324,7 @@ static u32 fimd_calc_clkdiv(struct fimd_context *ctx, return (clkdiv < 0x100) ? clkdiv : 0xff; } -static bool fimd_mode_fixup(struct exynos_drm_manager *mgr, +static bool fimd_mode_fixup(struct exynos_drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { @@ -353,18 +334,10 @@ static bool fimd_mode_fixup(struct exynos_drm_manager *mgr, return true; } -static void fimd_mode_set(struct exynos_drm_manager *mgr, - const struct drm_display_mode *in_mode) +static void fimd_commit(struct exynos_drm_crtc *crtc) { - struct fimd_context *ctx = mgr_to_fimd(mgr); - - drm_mode_copy(&ctx->mode, in_mode); -} - -static void fimd_commit(struct exynos_drm_manager *mgr) -{ - struct fimd_context *ctx = mgr_to_fimd(mgr); - struct drm_display_mode *mode = &ctx->mode; + struct fimd_context *ctx = crtc->ctx; + struct drm_display_mode *mode = &crtc->base.mode; struct fimd_driver_data *driver_data = ctx->driver_data; void *timing_base = ctx->regs + driver_data->timing_base; u32 val, clkdiv; @@ -461,9 +434,9 @@ static void fimd_commit(struct exynos_drm_manager *mgr) writel(val, ctx->regs + VIDCON0); } -static int fimd_enable_vblank(struct exynos_drm_manager *mgr) +static int fimd_enable_vblank(struct exynos_drm_crtc *crtc) { - struct fimd_context *ctx = mgr_to_fimd(mgr); + struct fimd_context *ctx = crtc->ctx; u32 val; if (ctx->suspended) @@ -493,9 +466,9 @@ static int fimd_enable_vblank(struct exynos_drm_manager *mgr) return 0; } -static void fimd_disable_vblank(struct exynos_drm_manager *mgr) +static void fimd_disable_vblank(struct exynos_drm_crtc *crtc) { - struct fimd_context *ctx = mgr_to_fimd(mgr); + struct fimd_context *ctx = crtc->ctx; u32 val; if (ctx->suspended) @@ -517,58 +490,9 @@ static void fimd_disable_vblank(struct exynos_drm_manager *mgr) } } -static void fimd_win_mode_set(struct exynos_drm_manager *mgr, - struct exynos_drm_overlay *overlay) -{ - struct fimd_context *ctx = mgr_to_fimd(mgr); - struct fimd_win_data *win_data; - int win; - unsigned long offset; - - if (!overlay) { - DRM_ERROR("overlay is NULL\n"); - return; - } - - win = overlay->zpos; - if (win == DEFAULT_ZPOS) - win = ctx->default_win; - - if (win < 0 || win >= WINDOWS_NR) - return; - - offset = overlay->fb_x * (overlay->bpp >> 3); - offset += overlay->fb_y * overlay->pitch; - - DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch); - - win_data = &ctx->win_data[win]; - - win_data->offset_x = overlay->crtc_x; - win_data->offset_y = overlay->crtc_y; - win_data->ovl_width = overlay->crtc_width; - win_data->ovl_height = overlay->crtc_height; - win_data->fb_width = overlay->fb_width; - win_data->fb_height = overlay->fb_height; - win_data->dma_addr = overlay->dma_addr[0] + offset; - win_data->bpp = overlay->bpp; - win_data->pixel_format = overlay->pixel_format; - win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) * - (overlay->bpp >> 3); - win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3); - - DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n", - win_data->offset_x, win_data->offset_y); - DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n", - win_data->ovl_width, win_data->ovl_height); - DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr); - DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n", - overlay->fb_width, overlay->crtc_width); -} - static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) { - struct fimd_win_data *win_data = &ctx->win_data[win]; + struct exynos_drm_plane *plane = &ctx->planes[win]; unsigned long val; val = WINCONx_ENWIN; @@ -578,11 +502,11 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) * So the request format is ARGB8888 then change it to XRGB8888. */ if (ctx->driver_data->has_limited_fmt && !win) { - if (win_data->pixel_format == DRM_FORMAT_ARGB8888) - win_data->pixel_format = DRM_FORMAT_XRGB8888; + if (plane->pixel_format == DRM_FORMAT_ARGB8888) + plane->pixel_format = DRM_FORMAT_XRGB8888; } - switch (win_data->pixel_format) { + switch (plane->pixel_format) { case DRM_FORMAT_C8: val |= WINCON0_BPPMODE_8BPP_PALETTE; val |= WINCONx_BURSTLEN_8WORD; @@ -618,22 +542,40 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) break; } - DRM_DEBUG_KMS("bpp = %d\n", win_data->bpp); + DRM_DEBUG_KMS("bpp = %d\n", plane->bpp); /* * In case of exynos, setting dma-burst to 16Word causes permanent * tearing for very small buffers, e.g. cursor buffer. Burst Mode - * switching which is based on overlay size is not recommended as - * overlay size varies alot towards the end of the screen and rapid + * switching which is based on plane size is not recommended as + * plane size varies alot towards the end of the screen and rapid * movement causes unstable DMA which results into iommu crash/tear. */ - if (win_data->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) { + if (plane->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) { val &= ~WINCONx_BURSTLEN_MASK; val |= WINCONx_BURSTLEN_4WORD; } writel(val, ctx->regs + WINCON(win)); + + /* hardware window 0 doesn't support alpha channel. */ + if (win != 0) { + /* OSD alpha */ + val = VIDISD14C_ALPHA0_R(0xf) | + VIDISD14C_ALPHA0_G(0xf) | + VIDISD14C_ALPHA0_B(0xf) | + VIDISD14C_ALPHA1_R(0xf) | + VIDISD14C_ALPHA1_G(0xf) | + VIDISD14C_ALPHA1_B(0xf); + + writel(val, ctx->regs + VIDOSD_C(win)); + + val = VIDW_ALPHA_R(0xf) | VIDW_ALPHA_G(0xf) | + VIDW_ALPHA_G(0xf); + writel(val, ctx->regs + VIDWnALPHA0(win)); + writel(val, ctx->regs + VIDWnALPHA1(win)); + } } static void fimd_win_set_colkey(struct fimd_context *ctx, unsigned int win) @@ -656,7 +598,7 @@ static void fimd_win_set_colkey(struct fimd_context *ctx, unsigned int win) * @protect: 1 to protect (disable updates) */ static void fimd_shadow_protect_win(struct fimd_context *ctx, - int win, bool protect) + unsigned int win, bool protect) { u32 reg, bits, val; @@ -676,29 +618,25 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx, writel(val, ctx->regs + reg); } -static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos) +static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) { - struct fimd_context *ctx = mgr_to_fimd(mgr); - struct fimd_win_data *win_data; - int win = zpos; - unsigned long val, alpha, size; - unsigned int last_x; - unsigned int last_y; + struct fimd_context *ctx = crtc->ctx; + struct exynos_drm_plane *plane; + dma_addr_t dma_addr; + unsigned long val, size, offset; + unsigned int last_x, last_y, buf_offsize, line_size; if (ctx->suspended) return; - if (win == DEFAULT_ZPOS) - win = ctx->default_win; - if (win < 0 || win >= WINDOWS_NR) return; - win_data = &ctx->win_data[win]; + plane = &ctx->planes[win]; /* If suspended, enable this on resume */ if (ctx->suspended) { - win_data->resume = true; + plane->resume = true; return; } @@ -715,38 +653,45 @@ static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos) /* protect windows */ fimd_shadow_protect_win(ctx, win, true); + + offset = plane->src_x * (plane->bpp >> 3); + offset += plane->src_y * plane->pitch; + /* buffer start address */ - val = (unsigned long)win_data->dma_addr; + dma_addr = plane->dma_addr[0] + offset; + val = (unsigned long)dma_addr; writel(val, ctx->regs + VIDWx_BUF_START(win, 0)); /* buffer end address */ - size = win_data->fb_width * win_data->ovl_height * (win_data->bpp >> 3); - val = (unsigned long)(win_data->dma_addr + size); + size = plane->pitch * plane->crtc_height; + val = (unsigned long)(dma_addr + size); writel(val, ctx->regs + VIDWx_BUF_END(win, 0)); DRM_DEBUG_KMS("start addr = 0x%lx, end addr = 0x%lx, size = 0x%lx\n", - (unsigned long)win_data->dma_addr, val, size); + (unsigned long)dma_addr, val, size); DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n", - win_data->ovl_width, win_data->ovl_height); + plane->crtc_width, plane->crtc_height); /* buffer size */ - val = VIDW_BUF_SIZE_OFFSET(win_data->buf_offsize) | - VIDW_BUF_SIZE_PAGEWIDTH(win_data->line_size) | - VIDW_BUF_SIZE_OFFSET_E(win_data->buf_offsize) | - VIDW_BUF_SIZE_PAGEWIDTH_E(win_data->line_size); + buf_offsize = plane->pitch - (plane->crtc_width * (plane->bpp >> 3)); + line_size = plane->crtc_width * (plane->bpp >> 3); + val = VIDW_BUF_SIZE_OFFSET(buf_offsize) | + VIDW_BUF_SIZE_PAGEWIDTH(line_size) | + VIDW_BUF_SIZE_OFFSET_E(buf_offsize) | + VIDW_BUF_SIZE_PAGEWIDTH_E(line_size); writel(val, ctx->regs + VIDWx_BUF_SIZE(win, 0)); /* OSD position */ - val = VIDOSDxA_TOPLEFT_X(win_data->offset_x) | - VIDOSDxA_TOPLEFT_Y(win_data->offset_y) | - VIDOSDxA_TOPLEFT_X_E(win_data->offset_x) | - VIDOSDxA_TOPLEFT_Y_E(win_data->offset_y); + val = VIDOSDxA_TOPLEFT_X(plane->crtc_x) | + VIDOSDxA_TOPLEFT_Y(plane->crtc_y) | + VIDOSDxA_TOPLEFT_X_E(plane->crtc_x) | + VIDOSDxA_TOPLEFT_Y_E(plane->crtc_y); writel(val, ctx->regs + VIDOSD_A(win)); - last_x = win_data->offset_x + win_data->ovl_width; + last_x = plane->crtc_x + plane->crtc_width; if (last_x) last_x--; - last_y = win_data->offset_y + win_data->ovl_height; + last_y = plane->crtc_y + plane->crtc_height; if (last_y) last_y--; @@ -756,24 +701,14 @@ static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos) writel(val, ctx->regs + VIDOSD_B(win)); DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %d\n", - win_data->offset_x, win_data->offset_y, last_x, last_y); - - /* hardware window 0 doesn't support alpha channel. */ - if (win != 0) { - /* OSD alpha */ - alpha = VIDISD14C_ALPHA1_R(0xf) | - VIDISD14C_ALPHA1_G(0xf) | - VIDISD14C_ALPHA1_B(0xf); - - writel(alpha, ctx->regs + VIDOSD_C(win)); - } + plane->crtc_x, plane->crtc_y, last_x, last_y); /* OSD size */ if (win != 3 && win != 4) { u32 offset = VIDOSD_D(win); if (win == 0) offset = VIDOSD_C(win); - val = win_data->ovl_width * win_data->ovl_height; + val = plane->crtc_width * plane->crtc_height; writel(val, ctx->regs + offset); DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val); @@ -793,29 +728,25 @@ static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos) /* Enable DMA channel and unprotect windows */ fimd_shadow_protect_win(ctx, win, false); - win_data->enabled = true; + plane->enabled = true; if (ctx->i80_if) atomic_set(&ctx->win_updated, 1); } -static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos) +static void fimd_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) { - struct fimd_context *ctx = mgr_to_fimd(mgr); - struct fimd_win_data *win_data; - int win = zpos; - - if (win == DEFAULT_ZPOS) - win = ctx->default_win; + struct fimd_context *ctx = crtc->ctx; + struct exynos_drm_plane *plane; if (win < 0 || win >= WINDOWS_NR) return; - win_data = &ctx->win_data[win]; + plane = &ctx->planes[win]; if (ctx->suspended) { /* do not resume this window*/ - win_data->resume = false; + plane->resume = false; return; } @@ -830,56 +761,52 @@ static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos) /* unprotect windows */ fimd_shadow_protect_win(ctx, win, false); - win_data->enabled = false; + plane->enabled = false; } -static void fimd_window_suspend(struct exynos_drm_manager *mgr) +static void fimd_window_suspend(struct fimd_context *ctx) { - struct fimd_context *ctx = mgr_to_fimd(mgr); - struct fimd_win_data *win_data; + struct exynos_drm_plane *plane; int i; for (i = 0; i < WINDOWS_NR; i++) { - win_data = &ctx->win_data[i]; - win_data->resume = win_data->enabled; - if (win_data->enabled) - fimd_win_disable(mgr, i); + plane = &ctx->planes[i]; + plane->resume = plane->enabled; + if (plane->enabled) + fimd_win_disable(ctx->crtc, i); } } -static void fimd_window_resume(struct exynos_drm_manager *mgr) +static void fimd_window_resume(struct fimd_context *ctx) { - struct fimd_context *ctx = mgr_to_fimd(mgr); - struct fimd_win_data *win_data; + struct exynos_drm_plane *plane; int i; for (i = 0; i < WINDOWS_NR; i++) { - win_data = &ctx->win_data[i]; - win_data->enabled = win_data->resume; - win_data->resume = false; + plane = &ctx->planes[i]; + plane->enabled = plane->resume; + plane->resume = false; } } -static void fimd_apply(struct exynos_drm_manager *mgr) +static void fimd_apply(struct fimd_context *ctx) { - struct fimd_context *ctx = mgr_to_fimd(mgr); - struct fimd_win_data *win_data; + struct exynos_drm_plane *plane; int i; for (i = 0; i < WINDOWS_NR; i++) { - win_data = &ctx->win_data[i]; - if (win_data->enabled) - fimd_win_commit(mgr, i); + plane = &ctx->planes[i]; + if (plane->enabled) + fimd_win_commit(ctx->crtc, i); else - fimd_win_disable(mgr, i); + fimd_win_disable(ctx->crtc, i); } - fimd_commit(mgr); + fimd_commit(ctx->crtc); } -static int fimd_poweron(struct exynos_drm_manager *mgr) +static int fimd_poweron(struct fimd_context *ctx) { - struct fimd_context *ctx = mgr_to_fimd(mgr); int ret; if (!ctx->suspended) @@ -903,16 +830,16 @@ static int fimd_poweron(struct exynos_drm_manager *mgr) /* if vblank was enabled status, enable it again. */ if (test_and_clear_bit(0, &ctx->irq_flags)) { - ret = fimd_enable_vblank(mgr); + ret = fimd_enable_vblank(ctx->crtc); if (ret) { DRM_ERROR("Failed to re-enable vblank [%d]\n", ret); goto enable_vblank_err; } } - fimd_window_resume(mgr); + fimd_window_resume(ctx); - fimd_apply(mgr); + fimd_apply(ctx); return 0; @@ -925,10 +852,8 @@ bus_clk_err: return ret; } -static int fimd_poweroff(struct exynos_drm_manager *mgr) +static int fimd_poweroff(struct fimd_context *ctx) { - struct fimd_context *ctx = mgr_to_fimd(mgr); - if (ctx->suspended) return 0; @@ -937,7 +862,7 @@ static int fimd_poweroff(struct exynos_drm_manager *mgr) * suspend that connector. Otherwise we might try to scan from * a destroyed buffer later. */ - fimd_window_suspend(mgr); + fimd_window_suspend(ctx); clk_disable_unprepare(ctx->lcd_clk); clk_disable_unprepare(ctx->bus_clk); @@ -948,18 +873,18 @@ static int fimd_poweroff(struct exynos_drm_manager *mgr) return 0; } -static void fimd_dpms(struct exynos_drm_manager *mgr, int mode) +static void fimd_dpms(struct exynos_drm_crtc *crtc, int mode) { DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode); switch (mode) { case DRM_MODE_DPMS_ON: - fimd_poweron(mgr); + fimd_poweron(crtc->ctx); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - fimd_poweroff(mgr); + fimd_poweroff(crtc->ctx); break; default: DRM_DEBUG_KMS("unspecified mode %d\n", mode); @@ -996,9 +921,9 @@ static void fimd_trigger(struct device *dev) atomic_set(&ctx->triggering, 0); } -static void fimd_te_handler(struct exynos_drm_manager *mgr) +static void fimd_te_handler(struct exynos_drm_crtc *crtc) { - struct fimd_context *ctx = mgr_to_fimd(mgr); + struct fimd_context *ctx = crtc->ctx; /* Checks the crtc is detached already from encoder */ if (ctx->pipe < 0 || !ctx->drm_dev) @@ -1021,15 +946,13 @@ static void fimd_te_handler(struct exynos_drm_manager *mgr) drm_handle_vblank(ctx->drm_dev, ctx->pipe); } -static struct exynos_drm_manager_ops fimd_manager_ops = { +static struct exynos_drm_crtc_ops fimd_crtc_ops = { .dpms = fimd_dpms, .mode_fixup = fimd_mode_fixup, - .mode_set = fimd_mode_set, .commit = fimd_commit, .enable_vblank = fimd_enable_vblank, .disable_vblank = fimd_disable_vblank, .wait_for_vblank = fimd_wait_for_vblank, - .win_mode_set = fimd_win_mode_set, .win_commit = fimd_win_commit, .win_disable = fimd_win_disable, .te_handler = fimd_te_handler, @@ -1074,12 +997,38 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) { struct fimd_context *ctx = dev_get_drvdata(dev); struct drm_device *drm_dev = data; + struct exynos_drm_private *priv = drm_dev->dev_private; + struct exynos_drm_plane *exynos_plane; + enum drm_plane_type type; + unsigned int zpos; + int ret; + + ctx->drm_dev = drm_dev; + ctx->pipe = priv->pipe++; + + for (zpos = 0; zpos < WINDOWS_NR; zpos++) { + type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY : + DRM_PLANE_TYPE_OVERLAY; + ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], + 1 << ctx->pipe, type, zpos); + if (ret) + return ret; + } + + exynos_plane = &ctx->planes[ctx->default_win]; + ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, + ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD, + &fimd_crtc_ops, ctx); + if (IS_ERR(ctx->crtc)) + return PTR_ERR(ctx->crtc); - fimd_mgr_initialize(&ctx->manager, drm_dev); - exynos_drm_crtc_create(&ctx->manager); if (ctx->display) exynos_drm_create_enc_conn(drm_dev, ctx->display); + ret = fimd_iommu_attach_devices(ctx, drm_dev); + if (ret) + return ret; + return 0; } @@ -1089,12 +1038,12 @@ static void fimd_unbind(struct device *dev, struct device *master, { struct fimd_context *ctx = dev_get_drvdata(dev); - fimd_dpms(&ctx->manager, DRM_MODE_DPMS_OFF); + fimd_dpms(ctx->crtc, DRM_MODE_DPMS_OFF); + + fimd_iommu_detach_devices(ctx); if (ctx->display) exynos_dpi_remove(ctx->display); - - fimd_mgr_remove(&ctx->manager); } static const struct component_ops fimd_component_ops = { @@ -1108,7 +1057,7 @@ static int fimd_probe(struct platform_device *pdev) struct fimd_context *ctx; struct device_node *i80_if_timings; struct resource *res; - int ret = -EINVAL; + int ret; if (!dev->of_node) return -ENODEV; @@ -1117,11 +1066,8 @@ static int fimd_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; - ctx->manager.type = EXYNOS_DISPLAY_TYPE_LCD; - ctx->manager.ops = &fimd_manager_ops; - ret = exynos_drm_component_add(dev, EXYNOS_DEVICE_TYPE_CRTC, - ctx->manager.type); + EXYNOS_DISPLAY_TYPE_LCD); if (ret) return ret; @@ -1246,6 +1192,24 @@ static int fimd_remove(struct platform_device *pdev) return 0; } +void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable) +{ + struct fimd_context *ctx = crtc->ctx; + u32 val; + + /* + * Only Exynos 5250, 5260, 5410 and 542x requires enabling DP/MIE + * clock. On these SoCs the bootloader may enable it but any + * power domain off/on will reset it to disable state. + */ + if (ctx->driver_data != &exynos5_fimd_driver_data) + return; + + val = enable ? DP_MIE_CLK_DP_ENABLE : DP_MIE_CLK_DISABLE; + writel(DP_MIE_CLK_DP_ENABLE, ctx->regs + DP_MIE_CLKCON); +} +EXPORT_SYMBOL_GPL(fimd_dp_clock_enable); + struct platform_driver fimd_driver = { .probe = fimd_probe, .remove = fimd_remove, |