summaryrefslogtreecommitdiffstats
path: root/kernel/drivers/gpu/drm/exynos/exynos_drm_fimd.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/drivers/gpu/drm/exynos/exynos_drm_fimd.c')
-rw-r--r--kernel/drivers/gpu/drm/exynos/exynos_drm_fimd.c516
1 files changed, 216 insertions, 300 deletions
diff --git a/kernel/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/kernel/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index a0edab833..bd75c1531 100644
--- a/kernel/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/kernel/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -41,7 +41,6 @@
* CPU Interface.
*/
-#define FIMD_DEFAULT_FRAMERATE 60
#define MIN_FB_WIDTH_FOR_16WORD_BURST 128
/* position control register for hardware window 0, 2 ~ 4.*/
@@ -59,6 +58,7 @@
#define VIDWnALPHA1(win) (VIDW_ALPHA + 0x04 + (win) * 8)
#define VIDWx_BUF_START(win, buf) (VIDW_BUF_START(buf) + (win) * 8)
+#define VIDWx_BUF_START_S(win, buf) (VIDW_BUF_START_S(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)
@@ -87,6 +87,7 @@
/* FIMD has totally five hardware windows. */
#define WINDOWS_NR 5
+#define CURSOR_WIN 4
struct fimd_driver_data {
unsigned int timing_base;
@@ -153,7 +154,6 @@ struct fimd_context {
struct clk *lcd_clk;
void __iomem *regs;
struct regmap *sysreg;
- unsigned int default_win;
unsigned long irq_flags;
u32 vidcon0;
u32 vidcon1;
@@ -169,7 +169,7 @@ struct fimd_context {
struct exynos_drm_panel_info panel;
struct fimd_driver_data *driver_data;
- struct exynos_drm_display *display;
+ struct drm_encoder *encoder;
};
static const struct of_device_id fimd_driver_dt_match[] = {
@@ -187,6 +187,14 @@ static const struct of_device_id fimd_driver_dt_match[] = {
};
MODULE_DEVICE_TABLE(of, fimd_driver_dt_match);
+static const uint32_t fimd_formats[] = {
+ DRM_FORMAT_C8,
+ DRM_FORMAT_XRGB1555,
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_ARGB8888,
+};
+
static inline struct fimd_driver_data *drm_fimd_get_driver_data(
struct platform_device *pdev)
{
@@ -196,6 +204,62 @@ static inline struct fimd_driver_data *drm_fimd_get_driver_data(
return (struct fimd_driver_data *)of_id->data;
}
+static int fimd_enable_vblank(struct exynos_drm_crtc *crtc)
+{
+ struct fimd_context *ctx = crtc->ctx;
+ u32 val;
+
+ if (ctx->suspended)
+ return -EPERM;
+
+ if (!test_and_set_bit(0, &ctx->irq_flags)) {
+ val = readl(ctx->regs + VIDINTCON0);
+
+ val |= VIDINTCON0_INT_ENABLE;
+
+ if (ctx->i80_if) {
+ val |= VIDINTCON0_INT_I80IFDONE;
+ val |= VIDINTCON0_INT_SYSMAINCON;
+ val &= ~VIDINTCON0_INT_SYSSUBCON;
+ } else {
+ val |= VIDINTCON0_INT_FRAME;
+
+ val &= ~VIDINTCON0_FRAMESEL0_MASK;
+ val |= VIDINTCON0_FRAMESEL0_VSYNC;
+ val &= ~VIDINTCON0_FRAMESEL1_MASK;
+ val |= VIDINTCON0_FRAMESEL1_NONE;
+ }
+
+ writel(val, ctx->regs + VIDINTCON0);
+ }
+
+ return 0;
+}
+
+static void fimd_disable_vblank(struct exynos_drm_crtc *crtc)
+{
+ struct fimd_context *ctx = crtc->ctx;
+ u32 val;
+
+ if (ctx->suspended)
+ return;
+
+ if (test_and_clear_bit(0, &ctx->irq_flags)) {
+ val = readl(ctx->regs + VIDINTCON0);
+
+ val &= ~VIDINTCON0_INT_ENABLE;
+
+ if (ctx->i80_if) {
+ val &= ~VIDINTCON0_INT_I80IFDONE;
+ val &= ~VIDINTCON0_INT_SYSMAINCON;
+ val &= ~VIDINTCON0_INT_SYSSUBCON;
+ } else
+ val &= ~VIDINTCON0_INT_FRAME;
+
+ writel(val, ctx->regs + VIDINTCON0);
+ }
+}
+
static void fimd_wait_for_vblank(struct exynos_drm_crtc *crtc)
{
struct fimd_context *ctx = crtc->ctx;
@@ -242,12 +306,19 @@ static void fimd_enable_shadow_channel_path(struct fimd_context *ctx,
writel(val, ctx->regs + SHADOWCON);
}
-static void fimd_clear_channel(struct fimd_context *ctx)
+static void fimd_clear_channels(struct exynos_drm_crtc *crtc)
{
+ struct fimd_context *ctx = crtc->ctx;
unsigned int win, ch_enabled = 0;
DRM_DEBUG_KMS("%s\n", __FILE__);
+ /* Hardware is in unknown state, so ensure it gets enabled properly */
+ pm_runtime_get_sync(ctx->dev);
+
+ clk_prepare_enable(ctx->bus_clk);
+ clk_prepare_enable(ctx->lcd_clk);
+
/* Check if any channel is enabled. */
for (win = 0; win < WINDOWS_NR; win++) {
u32 val = readl(ctx->regs + WINCON(win));
@@ -265,43 +336,24 @@ static void fimd_clear_channel(struct fimd_context *ctx)
/* Wait for vsync, as disable channel takes effect at next vsync */
if (ch_enabled) {
- unsigned int state = ctx->suspended;
+ int pipe = ctx->pipe;
- ctx->suspended = 0;
- fimd_wait_for_vblank(ctx->crtc);
- ctx->suspended = state;
- }
-}
-
-static int fimd_iommu_attach_devices(struct fimd_context *ctx,
- struct drm_device *drm_dev)
-{
-
- /* attach this sub driver to iommu mapping if supported. */
- if (is_drm_iommu_supported(ctx->drm_dev)) {
- int ret;
+ /* ensure that vblank interrupt won't be reported to core */
+ ctx->suspended = false;
+ ctx->pipe = -1;
- /*
- * If any channel is already active, iommu will throw
- * a PAGE FAULT when enabled. So clear any channel if enabled.
- */
- 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;
- }
+ fimd_enable_vblank(ctx->crtc);
+ fimd_wait_for_vblank(ctx->crtc);
+ fimd_disable_vblank(ctx->crtc);
+ ctx->suspended = true;
+ ctx->pipe = pipe;
}
- return 0;
-}
+ clk_disable_unprepare(ctx->lcd_clk);
+ clk_disable_unprepare(ctx->bus_clk);
-static void fimd_iommu_detach_devices(struct fimd_context *ctx)
-{
- /* 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);
+ pm_runtime_put(ctx->dev);
}
static u32 fimd_calc_clkdiv(struct fimd_context *ctx,
@@ -324,20 +376,10 @@ static u32 fimd_calc_clkdiv(struct fimd_context *ctx,
return (clkdiv < 0x100) ? clkdiv : 0xff;
}
-static bool fimd_mode_fixup(struct exynos_drm_crtc *crtc,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- if (adjusted_mode->vrefresh == 0)
- adjusted_mode->vrefresh = FIMD_DEFAULT_FRAMERATE;
-
- return true;
-}
-
static void fimd_commit(struct exynos_drm_crtc *crtc)
{
struct fimd_context *ctx = crtc->ctx;
- struct drm_display_mode *mode = &crtc->base.mode;
+ struct drm_display_mode *mode = &crtc->base.state->adjusted_mode;
struct fimd_driver_data *driver_data = ctx->driver_data;
void *timing_base = ctx->regs + driver_data->timing_base;
u32 val, clkdiv;
@@ -434,65 +476,10 @@ static void fimd_commit(struct exynos_drm_crtc *crtc)
writel(val, ctx->regs + VIDCON0);
}
-static int fimd_enable_vblank(struct exynos_drm_crtc *crtc)
-{
- struct fimd_context *ctx = crtc->ctx;
- u32 val;
-
- if (ctx->suspended)
- return -EPERM;
-
- if (!test_and_set_bit(0, &ctx->irq_flags)) {
- val = readl(ctx->regs + VIDINTCON0);
-
- val |= VIDINTCON0_INT_ENABLE;
- if (ctx->i80_if) {
- val |= VIDINTCON0_INT_I80IFDONE;
- val |= VIDINTCON0_INT_SYSMAINCON;
- val &= ~VIDINTCON0_INT_SYSSUBCON;
- } else {
- val |= VIDINTCON0_INT_FRAME;
-
- val &= ~VIDINTCON0_FRAMESEL0_MASK;
- val |= VIDINTCON0_FRAMESEL0_VSYNC;
- val &= ~VIDINTCON0_FRAMESEL1_MASK;
- val |= VIDINTCON0_FRAMESEL1_NONE;
- }
-
- writel(val, ctx->regs + VIDINTCON0);
- }
-
- return 0;
-}
-
-static void fimd_disable_vblank(struct exynos_drm_crtc *crtc)
+static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win,
+ struct drm_framebuffer *fb)
{
- struct fimd_context *ctx = crtc->ctx;
- u32 val;
-
- if (ctx->suspended)
- return;
-
- if (test_and_clear_bit(0, &ctx->irq_flags)) {
- val = readl(ctx->regs + VIDINTCON0);
-
- val &= ~VIDINTCON0_INT_ENABLE;
-
- if (ctx->i80_if) {
- val &= ~VIDINTCON0_INT_I80IFDONE;
- val &= ~VIDINTCON0_INT_SYSMAINCON;
- val &= ~VIDINTCON0_INT_SYSSUBCON;
- } else
- val &= ~VIDINTCON0_INT_FRAME;
-
- writel(val, ctx->regs + VIDINTCON0);
- }
-}
-
-static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
-{
- struct exynos_drm_plane *plane = &ctx->planes[win];
unsigned long val;
val = WINCONx_ENWIN;
@@ -502,11 +489,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 (plane->pixel_format == DRM_FORMAT_ARGB8888)
- plane->pixel_format = DRM_FORMAT_XRGB8888;
+ if (fb->pixel_format == DRM_FORMAT_ARGB8888)
+ fb->pixel_format = DRM_FORMAT_XRGB8888;
}
- switch (plane->pixel_format) {
+ switch (fb->pixel_format) {
case DRM_FORMAT_C8:
val |= WINCON0_BPPMODE_8BPP_PALETTE;
val |= WINCONx_BURSTLEN_8WORD;
@@ -542,7 +529,7 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
break;
}
- DRM_DEBUG_KMS("bpp = %d\n", plane->bpp);
+ DRM_DEBUG_KMS("bpp = %d\n", fb->bits_per_pixel);
/*
* In case of exynos, setting dma-burst to 16Word causes permanent
@@ -552,7 +539,7 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
* movement causes unstable DMA which results into iommu crash/tear.
*/
- if (plane->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) {
+ if (fb->width < MIN_FB_WIDTH_FOR_16WORD_BURST) {
val &= ~WINCONx_BURSTLEN_MASK;
val |= WINCONx_BURSTLEN_4WORD;
}
@@ -602,6 +589,16 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx,
{
u32 reg, bits, val;
+ /*
+ * SHADOWCON/PRTCON register is used for enabling timing.
+ *
+ * for example, once only width value of a register is set,
+ * if the dma is started then fimd hardware could malfunction so
+ * with protect window setting, the register fields with prefix '_F'
+ * wouldn't be updated at vsync also but updated once unprotect window
+ * is set.
+ */
+
if (ctx->driver_data->has_shadowcon) {
reg = SHADOWCON;
bits = SHADOWCON_WINx_PROTECT(win);
@@ -618,44 +615,45 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx,
writel(val, ctx->regs + reg);
}
-static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
+static void fimd_atomic_begin(struct exynos_drm_crtc *crtc,
+ struct exynos_drm_plane *plane)
{
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 < 0 || win >= WINDOWS_NR)
- return;
+ fimd_shadow_protect_win(ctx, plane->zpos, true);
+}
- plane = &ctx->planes[win];
+static void fimd_atomic_flush(struct exynos_drm_crtc *crtc,
+ struct exynos_drm_plane *plane)
+{
+ struct fimd_context *ctx = crtc->ctx;
- /* If suspended, enable this on resume */
- if (ctx->suspended) {
- plane->resume = true;
+ if (ctx->suspended)
return;
- }
- /*
- * SHADOWCON/PRTCON register is used for enabling timing.
- *
- * for example, once only width value of a register is set,
- * if the dma is started then fimd hardware could malfunction so
- * with protect window setting, the register fields with prefix '_F'
- * wouldn't be updated at vsync also but updated once unprotect window
- * is set.
- */
+ fimd_shadow_protect_win(ctx, plane->zpos, false);
+}
- /* protect windows */
- fimd_shadow_protect_win(ctx, win, true);
+static void fimd_update_plane(struct exynos_drm_crtc *crtc,
+ struct exynos_drm_plane *plane)
+{
+ struct fimd_context *ctx = crtc->ctx;
+ struct drm_plane_state *state = plane->base.state;
+ dma_addr_t dma_addr;
+ unsigned long val, size, offset;
+ unsigned int last_x, last_y, buf_offsize, line_size;
+ unsigned int win = plane->zpos;
+ unsigned int bpp = state->fb->bits_per_pixel >> 3;
+ unsigned int pitch = state->fb->pitches[0];
+ if (ctx->suspended)
+ return;
- offset = plane->src_x * (plane->bpp >> 3);
- offset += plane->src_y * plane->pitch;
+ offset = plane->src_x * bpp;
+ offset += plane->src_y * pitch;
/* buffer start address */
dma_addr = plane->dma_addr[0] + offset;
@@ -663,18 +661,18 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
writel(val, ctx->regs + VIDWx_BUF_START(win, 0));
/* buffer end address */
- size = plane->pitch * plane->crtc_height;
+ size = pitch * plane->crtc_h;
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)dma_addr, val, size);
DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
- plane->crtc_width, plane->crtc_height);
+ plane->crtc_w, plane->crtc_h);
/* buffer size */
- buf_offsize = plane->pitch - (plane->crtc_width * (plane->bpp >> 3));
- line_size = plane->crtc_width * (plane->bpp >> 3);
+ buf_offsize = pitch - (plane->crtc_w * bpp);
+ line_size = plane->crtc_w * bpp;
val = VIDW_BUF_SIZE_OFFSET(buf_offsize) |
VIDW_BUF_SIZE_PAGEWIDTH(line_size) |
VIDW_BUF_SIZE_OFFSET_E(buf_offsize) |
@@ -688,10 +686,10 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
VIDOSDxA_TOPLEFT_Y_E(plane->crtc_y);
writel(val, ctx->regs + VIDOSD_A(win));
- last_x = plane->crtc_x + plane->crtc_width;
+ last_x = plane->crtc_x + plane->crtc_w;
if (last_x)
last_x--;
- last_y = plane->crtc_y + plane->crtc_height;
+ last_y = plane->crtc_y + plane->crtc_h;
if (last_y)
last_y--;
@@ -708,13 +706,13 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
u32 offset = VIDOSD_D(win);
if (win == 0)
offset = VIDOSD_C(win);
- val = plane->crtc_width * plane->crtc_height;
+ val = plane->crtc_w * plane->crtc_h;
writel(val, ctx->regs + offset);
DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val);
}
- fimd_win_set_pixfmt(ctx, win);
+ fimd_win_set_pixfmt(ctx, win, state->fb);
/* hardware window 0 doesn't support color key. */
if (win != 0)
@@ -725,92 +723,32 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
if (ctx->driver_data->has_shadowcon)
fimd_enable_shadow_channel_path(ctx, win, true);
- /* Enable DMA channel and unprotect windows */
- fimd_shadow_protect_win(ctx, win, false);
-
- plane->enabled = true;
-
if (ctx->i80_if)
atomic_set(&ctx->win_updated, 1);
}
-static void fimd_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
+static void fimd_disable_plane(struct exynos_drm_crtc *crtc,
+ struct exynos_drm_plane *plane)
{
struct fimd_context *ctx = crtc->ctx;
- struct exynos_drm_plane *plane;
+ unsigned int win = plane->zpos;
- if (win < 0 || win >= WINDOWS_NR)
- return;
-
- plane = &ctx->planes[win];
-
- if (ctx->suspended) {
- /* do not resume this window*/
- plane->resume = false;
+ if (ctx->suspended)
return;
- }
-
- /* protect windows */
- fimd_shadow_protect_win(ctx, win, true);
fimd_enable_video_output(ctx, win, false);
if (ctx->driver_data->has_shadowcon)
fimd_enable_shadow_channel_path(ctx, win, false);
-
- /* unprotect windows */
- fimd_shadow_protect_win(ctx, win, false);
-
- plane->enabled = false;
-}
-
-static void fimd_window_suspend(struct fimd_context *ctx)
-{
- struct exynos_drm_plane *plane;
- int i;
-
- for (i = 0; i < WINDOWS_NR; i++) {
- plane = &ctx->planes[i];
- plane->resume = plane->enabled;
- if (plane->enabled)
- fimd_win_disable(ctx->crtc, i);
- }
-}
-
-static void fimd_window_resume(struct fimd_context *ctx)
-{
- struct exynos_drm_plane *plane;
- int i;
-
- for (i = 0; i < WINDOWS_NR; i++) {
- plane = &ctx->planes[i];
- plane->enabled = plane->resume;
- plane->resume = false;
- }
-}
-
-static void fimd_apply(struct fimd_context *ctx)
-{
- struct exynos_drm_plane *plane;
- int i;
-
- for (i = 0; i < WINDOWS_NR; i++) {
- plane = &ctx->planes[i];
- if (plane->enabled)
- fimd_win_commit(ctx->crtc, i);
- else
- fimd_win_disable(ctx->crtc, i);
- }
-
- fimd_commit(ctx->crtc);
}
-static int fimd_poweron(struct fimd_context *ctx)
+static void fimd_enable(struct exynos_drm_crtc *crtc)
{
+ struct fimd_context *ctx = crtc->ctx;
int ret;
if (!ctx->suspended)
- return 0;
+ return;
ctx->suspended = false;
@@ -819,50 +757,43 @@ static int fimd_poweron(struct fimd_context *ctx)
ret = clk_prepare_enable(ctx->bus_clk);
if (ret < 0) {
DRM_ERROR("Failed to prepare_enable the bus clk [%d]\n", ret);
- goto bus_clk_err;
+ return;
}
ret = clk_prepare_enable(ctx->lcd_clk);
if (ret < 0) {
DRM_ERROR("Failed to prepare_enable the lcd clk [%d]\n", ret);
- goto lcd_clk_err;
+ return;
}
/* if vblank was enabled status, enable it again. */
- if (test_and_clear_bit(0, &ctx->irq_flags)) {
- 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(ctx);
-
- fimd_apply(ctx);
-
- return 0;
+ if (test_and_clear_bit(0, &ctx->irq_flags))
+ fimd_enable_vblank(ctx->crtc);
-enable_vblank_err:
- clk_disable_unprepare(ctx->lcd_clk);
-lcd_clk_err:
- clk_disable_unprepare(ctx->bus_clk);
-bus_clk_err:
- ctx->suspended = true;
- return ret;
+ fimd_commit(ctx->crtc);
}
-static int fimd_poweroff(struct fimd_context *ctx)
+static void fimd_disable(struct exynos_drm_crtc *crtc)
{
+ struct fimd_context *ctx = crtc->ctx;
+ int i;
+
if (ctx->suspended)
- return 0;
+ return;
/*
* We need to make sure that all windows are disabled before we
* suspend that connector. Otherwise we might try to scan from
* a destroyed buffer later.
*/
- fimd_window_suspend(ctx);
+ for (i = 0; i < WINDOWS_NR; i++)
+ fimd_disable_plane(crtc, &ctx->planes[i]);
+
+ fimd_enable_vblank(crtc);
+ fimd_wait_for_vblank(crtc);
+ fimd_disable_vblank(crtc);
+
+ writel(0, ctx->regs + VIDCON0);
clk_disable_unprepare(ctx->lcd_clk);
clk_disable_unprepare(ctx->bus_clk);
@@ -870,26 +801,6 @@ static int fimd_poweroff(struct fimd_context *ctx)
pm_runtime_put_sync(ctx->dev);
ctx->suspended = true;
- return 0;
-}
-
-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(crtc->ctx);
- break;
- case DRM_MODE_DPMS_STANDBY:
- case DRM_MODE_DPMS_SUSPEND:
- case DRM_MODE_DPMS_OFF:
- fimd_poweroff(crtc->ctx);
- break;
- default:
- DRM_DEBUG_KMS("unspecified mode %d\n", mode);
- break;
- }
}
static void fimd_trigger(struct device *dev)
@@ -943,7 +854,7 @@ static void fimd_te_handler(struct exynos_drm_crtc *crtc)
}
if (test_bit(0, &ctx->irq_flags))
- drm_handle_vblank(ctx->drm_dev, ctx->pipe);
+ drm_crtc_handle_vblank(&ctx->crtc->base);
}
static void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable)
@@ -960,18 +871,20 @@ static void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable)
return;
val = enable ? DP_MIE_CLK_DP_ENABLE : DP_MIE_CLK_DISABLE;
- writel(DP_MIE_CLK_DP_ENABLE, ctx->regs + DP_MIE_CLKCON);
+ writel(val, ctx->regs + DP_MIE_CLKCON);
}
static const struct exynos_drm_crtc_ops fimd_crtc_ops = {
- .dpms = fimd_dpms,
- .mode_fixup = fimd_mode_fixup,
+ .enable = fimd_enable,
+ .disable = fimd_disable,
.commit = fimd_commit,
.enable_vblank = fimd_enable_vblank,
.disable_vblank = fimd_disable_vblank,
.wait_for_vblank = fimd_wait_for_vblank,
- .win_commit = fimd_win_commit,
- .win_disable = fimd_win_disable,
+ .atomic_begin = fimd_atomic_begin,
+ .update_plane = fimd_update_plane,
+ .disable_plane = fimd_disable_plane,
+ .atomic_flush = fimd_atomic_flush,
.te_handler = fimd_te_handler,
.clock_enable = fimd_dp_clock_enable,
};
@@ -979,7 +892,8 @@ static const struct exynos_drm_crtc_ops fimd_crtc_ops = {
static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
{
struct fimd_context *ctx = (struct fimd_context *)dev_id;
- u32 val, clear_bit;
+ u32 val, clear_bit, start, start_s;
+ int win;
val = readl(ctx->regs + VIDINTCON1);
@@ -991,15 +905,25 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
if (ctx->pipe < 0 || !ctx->drm_dev)
goto out;
- if (ctx->i80_if) {
- exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
+ if (!ctx->i80_if)
+ drm_crtc_handle_vblank(&ctx->crtc->base);
+
+ for (win = 0 ; win < WINDOWS_NR ; win++) {
+ struct exynos_drm_plane *plane = &ctx->planes[win];
+ if (!plane->pending_fb)
+ continue;
+
+ start = readl(ctx->regs + VIDWx_BUF_START(win, 0));
+ start_s = readl(ctx->regs + VIDWx_BUF_START_S(win, 0));
+ if (start == start_s)
+ exynos_drm_crtc_finish_update(ctx->crtc, plane);
+ }
+
+ if (ctx->i80_if) {
/* Exits triggering mode */
atomic_set(&ctx->triggering, 0);
} else {
- drm_handle_vblank(ctx->drm_dev, ctx->pipe);
- exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
-
/* set wait vsync event to zero and wake up queue. */
if (atomic_read(&ctx->wait_vsync_event)) {
atomic_set(&ctx->wait_vsync_event, 0);
@@ -1025,25 +949,32 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
ctx->pipe = priv->pipe++;
for (zpos = 0; zpos < WINDOWS_NR; zpos++) {
- type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY :
- DRM_PLANE_TYPE_OVERLAY;
+ type = exynos_plane_get_type(zpos, CURSOR_WIN);
ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
- 1 << ctx->pipe, type, zpos);
+ 1 << ctx->pipe, type, fimd_formats,
+ ARRAY_SIZE(fimd_formats), zpos);
if (ret)
return ret;
}
- exynos_plane = &ctx->planes[ctx->default_win];
+ exynos_plane = &ctx->planes[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);
- if (ctx->display)
- exynos_drm_create_enc_conn(drm_dev, ctx->display);
+ if (ctx->encoder)
+ exynos_dpi_bind(drm_dev, ctx->encoder);
+
+ if (is_drm_iommu_supported(drm_dev))
+ fimd_clear_channels(ctx->crtc);
+
+ ret = drm_iommu_attach_device(drm_dev, dev);
+ if (ret)
+ priv->pipe--;
- return fimd_iommu_attach_devices(ctx, drm_dev);
+ return ret;
}
static void fimd_unbind(struct device *dev, struct device *master,
@@ -1051,12 +982,12 @@ static void fimd_unbind(struct device *dev, struct device *master,
{
struct fimd_context *ctx = dev_get_drvdata(dev);
- fimd_dpms(ctx->crtc, DRM_MODE_DPMS_OFF);
+ fimd_disable(ctx->crtc);
- fimd_iommu_detach_devices(ctx);
+ drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
- if (ctx->display)
- exynos_dpi_remove(ctx->display);
+ if (ctx->encoder)
+ exynos_dpi_remove(ctx->encoder);
}
static const struct component_ops fimd_component_ops = {
@@ -1079,11 +1010,6 @@ static int fimd_probe(struct platform_device *pdev)
if (!ctx)
return -ENOMEM;
- ret = exynos_drm_component_add(dev, EXYNOS_DEVICE_TYPE_CRTC,
- EXYNOS_DISPLAY_TYPE_LCD);
- if (ret)
- return ret;
-
ctx->dev = dev;
ctx->suspended = true;
ctx->driver_data = drm_fimd_get_driver_data(pdev);
@@ -1134,38 +1060,33 @@ static int fimd_probe(struct platform_device *pdev)
ctx->bus_clk = devm_clk_get(dev, "fimd");
if (IS_ERR(ctx->bus_clk)) {
dev_err(dev, "failed to get bus clock\n");
- ret = PTR_ERR(ctx->bus_clk);
- goto err_del_component;
+ return PTR_ERR(ctx->bus_clk);
}
ctx->lcd_clk = devm_clk_get(dev, "sclk_fimd");
if (IS_ERR(ctx->lcd_clk)) {
dev_err(dev, "failed to get lcd clock\n");
- ret = PTR_ERR(ctx->lcd_clk);
- goto err_del_component;
+ return PTR_ERR(ctx->lcd_clk);
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ctx->regs = devm_ioremap_resource(dev, res);
- if (IS_ERR(ctx->regs)) {
- ret = PTR_ERR(ctx->regs);
- goto err_del_component;
- }
+ if (IS_ERR(ctx->regs))
+ return PTR_ERR(ctx->regs);
res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
ctx->i80_if ? "lcd_sys" : "vsync");
if (!res) {
dev_err(dev, "irq request failed.\n");
- ret = -ENXIO;
- goto err_del_component;
+ return -ENXIO;
}
ret = devm_request_irq(dev, res->start, fimd_irq_handler,
0, "drm_fimd", ctx);
if (ret) {
dev_err(dev, "irq request failed.\n");
- goto err_del_component;
+ return ret;
}
init_waitqueue_head(&ctx->wait_vsync_queue);
@@ -1173,11 +1094,9 @@ static int fimd_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ctx);
- ctx->display = exynos_dpi_probe(dev);
- if (IS_ERR(ctx->display)) {
- ret = PTR_ERR(ctx->display);
- goto err_del_component;
- }
+ ctx->encoder = exynos_dpi_probe(dev);
+ if (IS_ERR(ctx->encoder))
+ return PTR_ERR(ctx->encoder);
pm_runtime_enable(dev);
@@ -1190,8 +1109,6 @@ static int fimd_probe(struct platform_device *pdev)
err_disable_pm_runtime:
pm_runtime_disable(dev);
-err_del_component:
- exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CRTC);
return ret;
}
@@ -1200,7 +1117,6 @@ static int fimd_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
component_del(&pdev->dev, &fimd_component_ops);
- exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
return 0;
}