if (!(ctx->out_type & I80_HW_TRG))
disable_irq_nosync(ctx->te_irq);
disable_irq_nosync(ctx->irq);
writel(0, ctx->addr + DECON_VIDINTCON0);
}
/* return number of starts/ends of frame transmissions since reset */ static u32 decon_get_frame_count(struct decon_context *ctx, bool end)
{
u32 frm, pfrm, status, cnt = 2;
/* To get consistent result repeat read until frame id is stable. * Usually the loop will be executed once, in rare cases when the loop * is executed at frame change time 2nd pass will be needed.
*/
frm = readl(ctx->addr + DECON_CRFMID); do {
status = readl(ctx->addr + DECON_VIDCON1);
pfrm = frm;
frm = readl(ctx->addr + DECON_CRFMID);
} while (frm != pfrm && --cnt);
/* CRFMID is incremented on BPORCH in case of I80 and on VSYNC in case * of RGB, it should be taken into account.
*/ if (!frm) return 0;
switch (status & (VIDCON1_VSTATUS_MASK | VIDCON1_I80_ACTIVE)) { case VIDCON1_VSTATUS_VS: if (!(ctx->crtc->i80_mode))
--frm; break; case VIDCON1_VSTATUS_BP:
--frm; break; case VIDCON1_I80_ACTIVE: case VIDCON1_VSTATUS_AC: if (end)
--frm; break; default: break;
}
/* lcd on and use command if */
val = VIDOUT_LCD_ON; if (interlaced)
val |= VIDOUT_INTERLACE_EN_F; if (crtc->i80_mode) {
val |= VIDOUT_COMMAND_IF;
} else {
val |= VIDOUT_RGB_IF;
}
writel(val, ctx->addr + DECON_VIDOUTCON0);
if (interlaced)
val = VIDTCON2_LINEVAL(m->vdisplay / 2 - 1) |
VIDTCON2_HOZVAL(m->hdisplay - 1); else
val = VIDTCON2_LINEVAL(m->vdisplay - 1) |
VIDTCON2_HOZVAL(m->hdisplay - 1);
writel(val, ctx->addr + DECON_VIDTCON2);
if (!crtc->i80_mode) { int vbp = m->crtc_vtotal - m->crtc_vsync_end; int vfp = m->crtc_vsync_start - m->crtc_vdisplay;
switch (pixel_alpha) { case DRM_MODE_BLEND_PIXEL_NONE: case DRM_MODE_BLEND_COVERAGE:
val |= BLENDERQ_A_FUNC_F(BLENDERQ_ALPHA_A);
val |= BLENDERQ_B_FUNC_F(BLENDERQ_ONE_MINUS_ALPHA_A); break; case DRM_MODE_BLEND_PREMULTI: default: if (alpha != DRM_BLEND_ALPHA_OPAQUE) {
val |= BLENDERQ_A_FUNC_F(BLENDERQ_ALPHA0);
val |= BLENDERQ_B_FUNC_F(BLENDERQ_ONE_MINUS_ALPHA_A);
} else {
val |= BLENDERQ_A_FUNC_F(BLENDERQ_ONE);
val |= BLENDERQ_B_FUNC_F(BLENDERQ_ONE_MINUS_ALPHA_A);
} break;
}
decon_set_bits(ctx, DECON_BLENDERQx(win), mask, val);
}
switch (pixel_alpha) { case DRM_MODE_BLEND_PIXEL_NONE: break; case DRM_MODE_BLEND_COVERAGE: case DRM_MODE_BLEND_PREMULTI: default:
val |= WINCONx_ALPHA_SEL_F;
val |= WINCONx_BLD_PIX_F;
val |= WINCONx_ALPHA_MUL_F; break;
}
decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_BLEND_MODE_MASK, val);
if (fb->format->has_alpha)
pixel_alpha = state->base.pixel_blend_mode; else
pixel_alpha = DRM_MODE_BLEND_PIXEL_NONE;
val = readl(ctx->addr + DECON_WINCONx(win));
val &= WINCONx_ENWIN_F;
switch (fb->format->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: default:
val |= WINCONx_BPPMODE_32BPP_A8888;
val |= WINCONx_WSWP_F;
val |= WINCONx_BURSTLEN_16WORD; break;
}
/* * 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;
}
decon_set_bits(ctx, DECON_WINCONx(win), ~WINCONx_BLEND_MODE_MASK, val);
if (!(ctx->out_type & I80_HW_TRG))
synchronize_irq(ctx->te_irq);
synchronize_irq(ctx->irq);
/* * 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.
*/ for (i = ctx->first_win; i < WINDOWS_NR; i++)
decon_disable_plane(crtc, &ctx->planes[i]);
if (frm != ctx->frame_id) { /* handle only if incremented, take care of wrap-around */ if ((s32)(frm - ctx->frame_id) > 0)
drm_crtc_handle_vblank(&ctx->crtc->base);
ctx->frame_id = frm;
}
if (ctx->out_type & IFTYPE_HDMI)
ctx->first_win = 1;
for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { struct clk *clk;
clk = devm_clk_get(ctx->dev, decon_clks_name[i]); if (IS_ERR(clk)) return PTR_ERR(clk);
ctx->clks[i] = clk;
}
ctx->addr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ctx->addr)) return PTR_ERR(ctx->addr);
ret = decon_conf_irq(ctx, "vsync", decon_irq_handler, 0); if (ret < 0) return ret;
ctx->irq_vsync = ret;
ret = decon_conf_irq(ctx, "lcd_sys", decon_irq_handler, 0); if (ret < 0) return ret;
ctx->irq_lcd_sys = ret;
ret = decon_conf_irq(ctx, "te", decon_te_irq_handler,
IRQF_TRIGGER_RISING); if (ret < 0) return ret; if (ret) {
ctx->te_irq = ret;
ctx->out_type &= ~I80_HW_TRG;
}
if (ctx->out_type & I80_HW_TRG) {
ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node, "samsung,disp-sysreg"); if (IS_ERR(ctx->sysreg)) {
dev_err(dev, "failed to get system register\n"); return PTR_ERR(ctx->sysreg);
}
}
platform_set_drvdata(pdev, ctx);
pm_runtime_enable(dev);
ret = component_add(dev, &decon_component_ops); if (ret) goto err_disable_pm_runtime;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.