static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win, struct drm_framebuffer *fb) { unsigned long val; val = readl(ctx->addr + DECON_WINCONx(win)); val &= ~WINCONx_BPPMODE_MASK; switch (fb->pixel_format) { case DRM_FORMAT_XRGB1555: val |= WINCONx_BPPMODE_16BPP_I1555; val |= WINCONx_HAWSWP_F; val |= WINCONx_BURSTLEN_16WORD; break; case DRM_FORMAT_RGB565: val |= WINCONx_BPPMODE_16BPP_565; val |= WINCONx_HAWSWP_F; val |= WINCONx_BURSTLEN_16WORD; break; case DRM_FORMAT_XRGB8888: val |= WINCONx_BPPMODE_24BPP_888; val |= WINCONx_WSWP_F; val |= WINCONx_BURSTLEN_16WORD; break; case DRM_FORMAT_ARGB8888: val |= WINCONx_BPPMODE_32BPP_A8888; val |= WINCONx_WSWP_F | WINCONx_BLD_PIX_F | WINCONx_ALPHA_SEL_F; val |= WINCONx_BURSTLEN_16WORD; break; default: DRM_ERROR("Proper pixel format is not set\n"); return; } DRM_DEBUG_KMS("bpp = %u\n", fb->bits_per_pixel); /* * 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 plane size is not recommended as * plane size varies a lot towards the end of the screen and rapid * movement causes unstable DMA which results into iommu crash/tear. */ if (fb->width < MIN_FB_WIDTH_FOR_16WORD_BURST) { val &= ~WINCONx_BURSTLEN_MASK; val |= WINCONx_BURSTLEN_8WORD; } writel(val, ctx->addr + DECON_WINCONx(win)); }
static void decon_update_plane(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane) { struct decon_context *ctx = crtc->ctx; struct drm_plane_state *state = plane->base.state; unsigned int win = plane->zpos; unsigned int bpp = state->fb->bits_per_pixel >> 3; unsigned int pitch = state->fb->pitches[0]; u32 val; if (ctx->suspended) return; val = COORDINATE_X(plane->crtc_x) | COORDINATE_Y(plane->crtc_y); writel(val, ctx->addr + DECON_VIDOSDxA(win)); val = COORDINATE_X(plane->crtc_x + plane->crtc_w - 1) | COORDINATE_Y(plane->crtc_y + plane->crtc_h - 1); writel(val, ctx->addr + DECON_VIDOSDxB(win)); val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | VIDOSD_Wx_ALPHA_B_F(0x0); writel(val, ctx->addr + DECON_VIDOSDxC(win)); val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | VIDOSD_Wx_ALPHA_B_F(0x0); writel(val, ctx->addr + DECON_VIDOSDxD(win)); writel(plane->dma_addr[0], ctx->addr + DECON_VIDW0xADD0B0(win)); val = plane->dma_addr[0] + pitch * plane->crtc_h; writel(val, ctx->addr + DECON_VIDW0xADD1B0(win)); val = OFFSIZE(pitch - plane->crtc_w * bpp) | PAGEWIDTH(plane->crtc_w * bpp); writel(val, ctx->addr + DECON_VIDW0xADD2(win)); decon_win_set_pixfmt(ctx, win, state->fb); /* window enable */ val = readl(ctx->addr + DECON_WINCONx(win)); val |= WINCONx_ENWIN_F; writel(val, ctx->addr + DECON_WINCONx(win)); /* standalone update */ val = readl(ctx->addr + DECON_UPDATE); val |= STANDALONE_UPDATE_F; writel(val, ctx->addr + DECON_UPDATE); }
static void decon_clear_channels(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; int win, i, ret; DRM_DEBUG_KMS("%s\n", __FILE__); for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { ret = clk_prepare_enable(ctx->clks[i]); if (ret < 0) goto err; } for (win = 0; win < WINDOWS_NR; win++) { decon_shadow_protect_win(ctx, win, true); decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0); decon_shadow_protect_win(ctx, win, false); decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); } /* TODO: wait for possible vsync */ msleep(50); err: while (--i >= 0) clk_disable_unprepare(ctx->clks[i]); }
static void decon_clear_channels(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; int win, i, ret; u32 val; DRM_DEBUG_KMS("%s\n", __FILE__); for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { ret = clk_prepare_enable(ctx->clks[i]); if (ret < 0) goto err; } for (win = 0; win < WINDOWS_NR; win++) { /* shadow update disable */ val = readl(ctx->addr + DECON_SHADOWCON); val |= SHADOWCON_Wx_PROTECT(win); writel(val, ctx->addr + DECON_SHADOWCON); /* window disable */ val = readl(ctx->addr + DECON_WINCONx(win)); val &= ~WINCONx_ENWIN_F; writel(val, ctx->addr + DECON_WINCONx(win)); /* shadow update enable */ val = readl(ctx->addr + DECON_SHADOWCON); val &= ~SHADOWCON_Wx_PROTECT(win); writel(val, ctx->addr + DECON_SHADOWCON); /* standalone update */ val = readl(ctx->addr + DECON_UPDATE); val |= STANDALONE_UPDATE_F; writel(val, ctx->addr + DECON_UPDATE); } /* TODO: wait for possible vsync */ msleep(50); err: while (--i >= 0) clk_disable_unprepare(ctx->clks[i]); }
static void decon_disable_plane(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane) { struct decon_context *ctx = crtc->ctx; unsigned int win = plane->index; if (test_bit(BIT_SUSPENDED, &ctx->flags)) return; decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0); }
static void decon_update_plane(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane) { struct exynos_drm_plane_state *state = to_exynos_plane_state(plane->base.state); struct decon_context *ctx = crtc->ctx; struct drm_framebuffer *fb = state->base.fb; unsigned int win = plane->index; unsigned int bpp = fb->bits_per_pixel >> 3; unsigned int pitch = fb->pitches[0]; dma_addr_t dma_addr = exynos_drm_fb_dma_addr(fb, 0); u32 val; if (test_bit(BIT_SUSPENDED, &ctx->flags)) return; val = COORDINATE_X(state->crtc.x) | COORDINATE_Y(state->crtc.y); writel(val, ctx->addr + DECON_VIDOSDxA(win)); val = COORDINATE_X(state->crtc.x + state->crtc.w - 1) | COORDINATE_Y(state->crtc.y + state->crtc.h - 1); writel(val, ctx->addr + DECON_VIDOSDxB(win)); val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | VIDOSD_Wx_ALPHA_B_F(0x0); writel(val, ctx->addr + DECON_VIDOSDxC(win)); val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | VIDOSD_Wx_ALPHA_B_F(0x0); writel(val, ctx->addr + DECON_VIDOSDxD(win)); writel(dma_addr, ctx->addr + DECON_VIDW0xADD0B0(win)); val = dma_addr + pitch * state->src.h; writel(val, ctx->addr + DECON_VIDW0xADD1B0(win)); if (ctx->out_type != IFTYPE_HDMI) val = BIT_VAL(pitch - state->crtc.w * bpp, 27, 14) | BIT_VAL(state->crtc.w * bpp, 13, 0); else val = BIT_VAL(pitch - state->crtc.w * bpp, 29, 15) | BIT_VAL(state->crtc.w * bpp, 14, 0); writel(val, ctx->addr + DECON_VIDW0xADD2(win)); decon_win_set_pixfmt(ctx, win, fb); /* window enable */ decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, ~0); /* standalone update */ decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); }
static void decon_update_plane(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane) { struct decon_context *ctx = crtc->ctx; struct drm_plane_state *state = plane->base.state; unsigned int win = plane->zpos; unsigned int bpp = state->fb->bits_per_pixel >> 3; unsigned int pitch = state->fb->pitches[0]; u32 val; if (test_bit(BIT_SUSPENDED, &ctx->flags)) return; val = COORDINATE_X(plane->crtc_x) | COORDINATE_Y(plane->crtc_y); writel(val, ctx->addr + DECON_VIDOSDxA(win)); val = COORDINATE_X(plane->crtc_x + plane->crtc_w - 1) | COORDINATE_Y(plane->crtc_y + plane->crtc_h - 1); writel(val, ctx->addr + DECON_VIDOSDxB(win)); val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | VIDOSD_Wx_ALPHA_B_F(0x0); writel(val, ctx->addr + DECON_VIDOSDxC(win)); val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | VIDOSD_Wx_ALPHA_B_F(0x0); writel(val, ctx->addr + DECON_VIDOSDxD(win)); writel(plane->dma_addr[0], ctx->addr + DECON_VIDW0xADD0B0(win)); val = plane->dma_addr[0] + pitch * plane->crtc_h; writel(val, ctx->addr + DECON_VIDW0xADD1B0(win)); if (ctx->out_type != IFTYPE_HDMI) val = BIT_VAL(pitch - plane->crtc_w * bpp, 27, 14) | BIT_VAL(plane->crtc_w * bpp, 13, 0); else val = BIT_VAL(pitch - plane->crtc_w * bpp, 29, 15) | BIT_VAL(plane->crtc_w * bpp, 14, 0); writel(val, ctx->addr + DECON_VIDW0xADD2(win)); decon_win_set_pixfmt(ctx, win, state->fb); /* window enable */ decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, ~0); /* standalone update */ decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); }
static void decon_disable_plane(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane) { struct decon_context *ctx = crtc->ctx; unsigned int win = plane->zpos; u32 val; if (ctx->suspended) return; decon_shadow_protect_win(ctx, win, true); /* window disable */ val = readl(ctx->addr + DECON_WINCONx(win)); val &= ~WINCONx_ENWIN_F; writel(val, ctx->addr + DECON_WINCONx(win)); decon_shadow_protect_win(ctx, win, false); /* standalone update */ val = readl(ctx->addr + DECON_UPDATE); val |= STANDALONE_UPDATE_F; writel(val, ctx->addr + DECON_UPDATE); }
static void decon_disable_plane(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane) { struct decon_context *ctx = crtc->ctx; unsigned int win = plane->zpos; if (test_bit(BIT_SUSPENDED, &ctx->flags)) return; decon_shadow_protect_win(ctx, win, true); /* window disable */ decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0); decon_shadow_protect_win(ctx, win, false); /* standalone update */ decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); }