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_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_swreset(struct decon_context *ctx) { unsigned int tries; writel(0, ctx->addr + DECON_VIDCON0); for (tries = 2000; tries; --tries) { if (~readl(ctx->addr + DECON_VIDCON0) & VIDCON0_STOP_STATUS) break; udelay(10); } WARN(tries == 0, "failed to disable DECON\n"); writel(VIDCON0_SWRESET, ctx->addr + DECON_VIDCON0); for (tries = 2000; tries; --tries) { if (~readl(ctx->addr + DECON_VIDCON0) & VIDCON0_SWRESET) break; udelay(10); } WARN(tries == 0, "failed to software reset DECON\n"); if (ctx->out_type != IFTYPE_HDMI) return; writel(VIDCON0_CLKVALUP | VIDCON0_VLCKFREE, ctx->addr + DECON_VIDCON0); decon_set_bits(ctx, DECON_CMU, CMU_CLKGAGE_MODE_SFR_F | CMU_CLKGAGE_MODE_MEM_F, ~0); writel(VIDCON1_VCLK_RUN_VDEN_DISABLE, ctx->addr + DECON_VIDCON1); writel(CRCCTRL_CRCEN | CRCCTRL_CRCSTART_F | CRCCTRL_CRCCLKEN, ctx->addr + DECON_CRCCTRL); decon_setup_trigger(ctx); }
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); }
static void decon_te_irq_handler(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags) || (ctx->out_type & I80_HW_TRG)) return; if (test_and_clear_bit(BIT_WIN_UPDATED, &ctx->flags)) decon_set_bits(ctx, DECON_TRIGCON, TRIGCON_SWTRIGCMD, ~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->index; if (test_bit(BIT_SUSPENDED, &ctx->flags)) return; decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0); }
void decon_te_irq_handler(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags)) return; if (test_and_clear_bit(BIT_WIN_UPDATED, &ctx->flags)) decon_set_bits(ctx, DECON_TRIGCON, TRIGCON_SWTRIGCMD, ~0); drm_crtc_handle_vblank(&ctx->crtc->base); }
static void decon_atomic_flush(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; int i; if (test_bit(BIT_SUSPENDED, &ctx->flags)) return; for (i = ctx->first_win; i < WINDOWS_NR; i++) decon_shadow_protect_win(ctx, i, false); /* standalone update */ decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); if (ctx->out_type & IFTYPE_I80) set_bit(BIT_WIN_UPDATED, &ctx->flags); }
static void decon_shadow_protect_win(struct decon_context *ctx, int win, bool protect) { decon_set_bits(ctx, DECON_SHADOWCON, SHADOWCON_Wx_PROTECT(win), protect ? ~0 : 0); }
static void decon_commit(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; struct drm_display_mode *m = &crtc->base.mode; u32 val; if (test_bit(BIT_SUSPENDED, &ctx->flags)) return; if (ctx->out_type == IFTYPE_HDMI) { m->crtc_hsync_start = m->crtc_hdisplay + 10; m->crtc_hsync_end = m->crtc_htotal - 92; m->crtc_vsync_start = m->crtc_vdisplay + 1; m->crtc_vsync_end = m->crtc_vsync_start + 1; } decon_set_bits(ctx, DECON_VIDCON0, VIDCON0_ENVID, 0); /* enable clock gate */ val = CMU_CLKGAGE_MODE_SFR_F | CMU_CLKGAGE_MODE_MEM_F; writel(val, ctx->addr + DECON_CMU); /* lcd on and use command if */ val = VIDOUT_LCD_ON; if (ctx->out_type == IFTYPE_I80) val |= VIDOUT_COMMAND_IF; else val |= VIDOUT_RGB_IF; writel(val, ctx->addr + DECON_VIDOUTCON0); val = VIDTCON2_LINEVAL(m->vdisplay - 1) | VIDTCON2_HOZVAL(m->hdisplay - 1); writel(val, ctx->addr + DECON_VIDTCON2); if (ctx->out_type != IFTYPE_I80) { val = VIDTCON00_VBPD_F( m->crtc_vtotal - m->crtc_vsync_end - 1) | VIDTCON00_VFPD_F( m->crtc_vsync_start - m->crtc_vdisplay - 1); writel(val, ctx->addr + DECON_VIDTCON00); val = VIDTCON01_VSPW_F( m->crtc_vsync_end - m->crtc_vsync_start - 1); writel(val, ctx->addr + DECON_VIDTCON01); val = VIDTCON10_HBPD_F( m->crtc_htotal - m->crtc_hsync_end - 1) | VIDTCON10_HFPD_F( m->crtc_hsync_start - m->crtc_hdisplay - 1); writel(val, ctx->addr + DECON_VIDTCON10); val = VIDTCON11_HSPW_F( m->crtc_hsync_end - m->crtc_hsync_start - 1); writel(val, ctx->addr + DECON_VIDTCON11); } decon_setup_trigger(ctx); /* enable output and display signal */ decon_set_bits(ctx, DECON_VIDCON0, VIDCON0_ENVID | VIDCON0_ENVID_F, ~0); }