static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc) { struct drm_crtc *crtc = &rcrtc->crtc; bool interlaced; if (rcrtc->started) return; /* Set display off and background to black */ rcar_du_crtc_write(rcrtc, DOOR, DOOR_RGB(0, 0, 0)); rcar_du_crtc_write(rcrtc, BPOR, BPOR_RGB(0, 0, 0)); /* Configure display timings and output routing */ rcar_du_crtc_set_display_timing(rcrtc); rcar_du_group_set_routing(rcrtc->group); /* Start with all planes disabled. */ rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0); /* Select master sync mode. This enables display operation in master * sync mode (with the HSYNC and VSYNC signals configured as outputs and * actively driven). */ interlaced = rcrtc->crtc.mode.flags & DRM_MODE_FLAG_INTERLACE; rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK | DSYSR_SCM_MASK, (interlaced ? DSYSR_SCM_INT_VIDEO : 0) | DSYSR_TVM_MASTER); rcar_du_group_start_stop(rcrtc->group, true); /* Turn vertical blanking interrupt reporting back on. */ drm_crtc_vblank_on(crtc); rcrtc->started = true; }
void rcar_du_crtc_enable_vblank(struct rcar_du_crtc *rcrtc, bool enable) { if (enable) { rcar_du_crtc_write(rcrtc, DSRCR, DSRCR_VBCL); rcar_du_crtc_set(rcrtc, DIER, DIER_VBE); } else { rcar_du_crtc_clr(rcrtc, DIER, DIER_VBE); } }
static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc) { struct drm_crtc *crtc = &rcrtc->crtc; unsigned int i; if (rcrtc->started) return; if (WARN_ON(rcrtc->plane->format == NULL)) return; /* Set display off and background to black */ rcar_du_crtc_write(rcrtc, DOOR, DOOR_RGB(0, 0, 0)); rcar_du_crtc_write(rcrtc, BPOR, BPOR_RGB(0, 0, 0)); /* Configure display timings and output routing */ rcar_du_crtc_set_display_timing(rcrtc); rcar_du_group_set_routing(rcrtc->group); mutex_lock(&rcrtc->group->planes.lock); rcrtc->plane->enabled = true; rcar_du_crtc_update_planes(crtc); mutex_unlock(&rcrtc->group->planes.lock); /* Setup planes. */ for (i = 0; i < ARRAY_SIZE(rcrtc->group->planes.planes); ++i) { struct rcar_du_plane *plane = &rcrtc->group->planes.planes[i]; if (plane->crtc != crtc || !plane->enabled) continue; rcar_du_plane_setup(plane); } /* Select master sync mode. This enables display operation in master * sync mode (with the HSYNC and VSYNC signals configured as outputs and * actively driven). */ rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_MASTER); rcar_du_group_start_stop(rcrtc->group, true); rcrtc->started = true; }
static irqreturn_t rcar_du_crtc_irq(int irq, void *arg) { struct rcar_du_crtc *rcrtc = arg; irqreturn_t ret = IRQ_NONE; u32 status; status = rcar_du_crtc_read(rcrtc, DSSR); rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK); if (status & DSSR_FRM) { drm_handle_vblank(rcrtc->crtc.dev, rcrtc->index); rcar_du_crtc_finish_page_flip(rcrtc); ret = IRQ_HANDLED; } return ret; }
static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) { const struct drm_display_mode *mode = &rcrtc->crtc.state->adjusted_mode; unsigned long mode_clock = mode->clock * 1000; unsigned long clk; u32 value; u32 escr; u32 div; /* Compute the clock divisor and select the internal or external dot * clock based on the requested frequency. */ clk = clk_get_rate(rcrtc->clock); div = DIV_ROUND_CLOSEST(clk, mode_clock); div = clamp(div, 1U, 64U) - 1; escr = div | ESCR_DCLKSEL_CLKS; if (rcrtc->extclock) { unsigned long extclk; unsigned long extrate; unsigned long rate; u32 extdiv; extclk = clk_get_rate(rcrtc->extclock); extdiv = DIV_ROUND_CLOSEST(extclk, mode_clock); extdiv = clamp(extdiv, 1U, 64U) - 1; rate = clk / (div + 1); extrate = extclk / (extdiv + 1); if (abs((long)extrate - (long)mode_clock) < abs((long)rate - (long)mode_clock)) { dev_dbg(rcrtc->group->dev->dev, "crtc%u: using external clock\n", rcrtc->index); escr = extdiv | ESCR_DCLKSEL_DCLKIN; } } rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? ESCR2 : ESCR, escr); rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0); /* Signal polarities */ value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : DSMR_VSL) | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : DSMR_HSL) | DSMR_DIPM_DE | DSMR_CSPM; rcar_du_crtc_write(rcrtc, DSMR, value); /* Display timings */ rcar_du_crtc_write(rcrtc, HDSR, mode->htotal - mode->hsync_start - 19); rcar_du_crtc_write(rcrtc, HDER, mode->htotal - mode->hsync_start + mode->hdisplay - 19); rcar_du_crtc_write(rcrtc, HSWR, mode->hsync_end - mode->hsync_start - 1); rcar_du_crtc_write(rcrtc, HCR, mode->htotal - 1); rcar_du_crtc_write(rcrtc, VDSR, mode->crtc_vtotal - mode->crtc_vsync_end - 2); rcar_du_crtc_write(rcrtc, VDER, mode->crtc_vtotal - mode->crtc_vsync_end + mode->crtc_vdisplay - 2); rcar_du_crtc_write(rcrtc, VSPR, mode->crtc_vtotal - mode->crtc_vsync_end + mode->crtc_vsync_start - 1); rcar_du_crtc_write(rcrtc, VCR, mode->crtc_vtotal - 1); rcar_du_crtc_write(rcrtc, DESR, mode->htotal - mode->hsync_start); rcar_du_crtc_write(rcrtc, DEWR, mode->hdisplay); }
static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) { const struct drm_display_mode *mode = &rcrtc->crtc.mode; unsigned long clk_in = 0, clk_ex = 0; u32 value; u32 div = 0, div_in = 0, div_ex = 0; u32 abs_in = 0, abs_ex = 0; u32 dclksel_bit = 0, dclkoinv_bit = 0; const struct rcar_du_crtc_data *pdata = &rcrtc->group->dev->pdata->crtcs[rcrtc->index]; /* Internal dot clock */ clk_in = clk_get_rate(rcrtc->clock); div_in = DIV_ROUND_CLOSEST(clk_in, mode->clock * 1000); if (pdata->exclk != 0) { /* External dot clock */ clk_ex = pdata->exclk; div_ex = DIV_ROUND_CLOSEST(clk_ex, mode->clock * 1000); /* Select recommand dot clock */ abs_ex = abs((mode->clock * 1000) - (clk_ex / div_ex)); abs_in = abs((mode->clock * 1000) - (clk_in / div_in)); if (abs_ex < abs_in) { div = div_ex; dclksel_bit = ESCR_DCLKSEL_DCLKIN; } else { div = div_in; dclksel_bit = ESCR_DCLKSEL_CLKS; } } else { div = div_in; dclksel_bit = ESCR_DCLKSEL_CLKS; } div = clamp(div, 1U, 64U) - 1; rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? ESCR2 : ESCR, dclksel_bit | dclkoinv_bit | div); rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0); /* Signal polarities */ value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : DSMR_VSL) | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : DSMR_HSL) | DSMR_DIPM_DE; rcar_du_crtc_write(rcrtc, DSMR, value | DSMR_CSPM); /* for HDMI */ /* Display timings */ rcar_du_crtc_write(rcrtc, HDSR, mode->htotal - mode->hsync_start - 19); rcar_du_crtc_write(rcrtc, HDER, mode->htotal - mode->hsync_start + mode->hdisplay - 19); rcar_du_crtc_write(rcrtc, HSWR, mode->hsync_end - mode->hsync_start - 1); rcar_du_crtc_write(rcrtc, HCR, mode->htotal - 1); if (mode->flags & DRM_MODE_FLAG_INTERLACE) { rcar_du_crtc_write(rcrtc, VDSR, (mode->vtotal / 2) - (mode->vsync_end / 2) - 2); rcar_du_crtc_write(rcrtc, VDER, (mode->vtotal / 2) - (mode->vsync_end / 2) + (mode->vdisplay / 2) - 2); rcar_du_crtc_write(rcrtc, VSPR, (mode->vtotal / 2) - (mode->vsync_end / 2) + (mode->vsync_start / 2) - 1); rcar_du_crtc_write(rcrtc, VCR, (mode->vtotal / 2) - 1); } else { rcar_du_crtc_write(rcrtc, VDSR, mode->vtotal - mode->vsync_end - 2); rcar_du_crtc_write(rcrtc, VDER, mode->vtotal - mode->vsync_end + mode->vdisplay - 2); rcar_du_crtc_write(rcrtc, VSPR, mode->vtotal - mode->vsync_end + mode->vsync_start - 1); rcar_du_crtc_write(rcrtc, VCR, mode->vtotal - 1); } rcar_du_crtc_write(rcrtc, DESR, mode->htotal - mode->hsync_start); rcar_du_crtc_write(rcrtc, DEWR, mode->hdisplay); }
static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) { const struct drm_display_mode *mode = &rcrtc->crtc.mode; unsigned long clk; u32 value; u32 div; /* Dot clock */ clk = clk_get_rate(rcrtc->clock); div = DIV_ROUND_CLOSEST(clk, mode->clock * 1000); div = clamp(div, 1U, 64U) - 1; rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? ESCR2 : ESCR, ESCR_DCLKSEL_CLKS | div); rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0); /* Signal polarities */ value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : DSMR_VSL) | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : DSMR_HSL) | DSMR_DIPM_DE; rcar_du_crtc_write(rcrtc, DSMR, value); /* Display timings */ rcar_du_crtc_write(rcrtc, HDSR, mode->htotal - mode->hsync_start - 19); rcar_du_crtc_write(rcrtc, HDER, mode->htotal - mode->hsync_start + mode->hdisplay - 19); rcar_du_crtc_write(rcrtc, HSWR, mode->hsync_end - mode->hsync_start - 1); rcar_du_crtc_write(rcrtc, HCR, mode->htotal - 1); rcar_du_crtc_write(rcrtc, VDSR, mode->vtotal - mode->vsync_end - 2); rcar_du_crtc_write(rcrtc, VDER, mode->vtotal - mode->vsync_end + mode->vdisplay - 2); rcar_du_crtc_write(rcrtc, VSPR, mode->vtotal - mode->vsync_end + mode->vsync_start - 1); rcar_du_crtc_write(rcrtc, VCR, mode->vtotal - 1); rcar_du_crtc_write(rcrtc, DESR, mode->htotal - mode->hsync_start); rcar_du_crtc_write(rcrtc, DEWR, mode->hdisplay); }