end = start + (crtc->mode.vdisplay * fb->pitches[0]);
/* Write LCDC_DMA_FB_BASE_ADDR_0_REG and LCDC_DMA_FB_CEILING_ADDR_0_REG * with a single insruction, if available. This should make it more * unlikely that LCDC would fetch the DMA addresses in the middle of * an update.
*/ if (priv->rev == 1)
end -= 1;
/* * The driver currently only supports only true color formats. For * true color the palette block is bypassed, but a 32 byte palette * should still be loaded. The first 16-bit entry must be 0x4000 while * all other entries must be zeroed.
*/ staticvoid tilcdc_crtc_load_palette(struct drm_crtc *crtc)
{ struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); struct drm_device *dev = crtc->dev; struct tilcdc_drm_private *priv = dev->dev_private; int ret;
reinit_completion(&tilcdc_crtc->palette_loaded);
/* Tell the LCDC where the palette is located. */
tilcdc_write(dev, LCDC_DMA_FB_BASE_ADDR_0_REG,
tilcdc_crtc->palette_dma_handle);
tilcdc_write(dev, LCDC_DMA_FB_CEILING_ADDR_0_REG,
(u32) tilcdc_crtc->palette_dma_handle +
TILCDC_PALETTE_SIZE - 1);
/* Set dma load mode for palette loading only. */
tilcdc_write_mask(dev, LCDC_RASTER_CTRL_REG,
LCDC_PALETTE_LOAD_MODE(PALETTE_ONLY),
LCDC_PALETTE_LOAD_MODE_MASK);
/* Enable LCDC DMA and wait for palette to be loaded. */
tilcdc_clear_irqstatus(dev, 0xffffffff);
tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE);
ret = wait_for_completion_timeout(&tilcdc_crtc->palette_loaded,
msecs_to_jiffies(50)); if (ret == 0)
dev_err(dev->dev, "%s: Palette loading timeout", __func__);
/* * Calculate the percentage difference between the requested pixel clock rate * and the effective rate resulting from calculating the clock divider value.
*/ staticunsignedint tilcdc_pclk_diff(unsignedlong rate, unsignedlong real_rate)
{ int r = rate / 100, rr = real_rate / 100;
clkdiv = 2; /* first try using a standard divider of 2 */
/* mode.clock is in KHz, set_rate wants parameter in Hz */
pclk_rate = crtc->mode.clock * 1000;
ret = clk_set_rate(priv->clk, pclk_rate * clkdiv);
clk_rate = clk_get_rate(priv->clk);
real_pclk_rate = clk_rate / clkdiv; if (ret < 0 || tilcdc_pclk_diff(pclk_rate, real_pclk_rate) > 5) { /* * If we fail to set the clock rate (some architectures don't * use the common clock framework yet and may not implement * all the clk API calls for every clock), try the next best * thing: adjusting the clock divider, unless clk_get_rate() * failed as well.
*/ if (!clk_rate) { /* Nothing more we can do. Just bail out. */
dev_err(dev->dev, "failed to set the pixel clock - unable to read current lcdc clock rate\n"); return;
}
clkdiv = DIV_ROUND_CLOSEST(clk_rate, pclk_rate);
/* * Emit a warning if the real clock rate resulting from the * calculated divider differs much from the requested rate. * * 5% is an arbitrary value - LCDs are usually quite tolerant * about pixel clock rates.
*/
real_pclk_rate = clk_rate / clkdiv;
if (tilcdc_pclk_diff(pclk_rate, real_pclk_rate) > 5) {
dev_warn(dev->dev, "effective pixel clock rate (%luHz) differs from the requested rate (%luHz)\n",
real_pclk_rate, pclk_rate);
}
}
/* Set AC Bias Period and Number of Transitions per Interrupt: */
reg = tilcdc_read(dev, LCDC_RASTER_TIMING_2_REG) & ~0x000fff00;
reg |= LCDC_AC_BIAS_FREQUENCY(info->ac_bias) |
LCDC_AC_BIAS_TRANSITIONS_PER_INT(info->ac_bias_intrpt);
/* * subtract one from hfp, hbp, hsw because the hardware uses * a value of 0 as 1
*/ if (priv->rev == 2) { /* clear bits we're going to set */
reg &= ~0x78000033;
reg |= ((hfp-1) & 0x300) >> 8;
reg |= ((hbp-1) & 0x300) >> 4;
reg |= ((hsw-1) & 0x3c0) << 21;
}
tilcdc_write(dev, LCDC_RASTER_TIMING_2_REG, reg);
/* * be sure to set Bit 10 for the V2 LCDC controller, * otherwise limited to 1024 pixels width, stopping * 1920x1080 being supported.
*/ if (priv->rev == 2) { if ((mode->vdisplay - 1) & 0x400) {
tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG,
LCDC_LPP_B10);
} else {
tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG,
LCDC_LPP_B10);
}
}
/* Configure display type: */
reg = tilcdc_read(dev, LCDC_RASTER_CTRL_REG) &
~(LCDC_TFT_MODE | LCDC_MONO_8BIT_MODE | LCDC_MONOCHROME_MODE |
LCDC_V2_TFT_24BPP_MODE | LCDC_V2_TFT_24BPP_UNPACK |
0x000ff000 /* Palette Loading Delay bits */);
reg |= LCDC_TFT_MODE; /* no monochrome/passive support */ if (info->tft_alt_mode)
reg |= LCDC_TFT_ALT_ENABLE; if (priv->rev == 2) { switch (fb->format->format) { case DRM_FORMAT_BGR565: case DRM_FORMAT_RGB565: break; case DRM_FORMAT_XBGR8888: case DRM_FORMAT_XRGB8888:
reg |= LCDC_V2_TFT_24BPP_UNPACK;
fallthrough; case DRM_FORMAT_BGR888: case DRM_FORMAT_RGB888:
reg |= LCDC_V2_TFT_24BPP_MODE; break; default:
dev_err(dev->dev, "invalid pixel format\n"); return;
}
}
reg |= info->fdd << 12;
tilcdc_write(dev, LCDC_RASTER_CTRL_REG, reg);
if (info->invert_pxl_clk)
tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG, LCDC_INVERT_PIXEL_CLOCK); else
tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, LCDC_INVERT_PIXEL_CLOCK);
if (info->sync_ctrl)
tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG, LCDC_SYNC_CTRL); else
tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, LCDC_SYNC_CTRL);
if (info->sync_edge)
tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG, LCDC_SYNC_EDGE); else
tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, LCDC_SYNC_EDGE);
/* There is no real chance for a race here as the time stamp * is taken before the raster DMA is started. The spin-lock is * taken to have a memory barrier after taking the time-stamp * and to avoid a context switch between taking the stamp and * enabling the raster.
*/
spin_lock_irqsave(&tilcdc_crtc->irq_lock, flags);
tilcdc_crtc->last_vblank = ktime_get();
tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE);
spin_unlock_irqrestore(&tilcdc_crtc->irq_lock, flags);
mutex_lock(&tilcdc_crtc->enable_lock); if (shutdown)
tilcdc_crtc->shutdown = true; if (!tilcdc_crtc->enabled) {
mutex_unlock(&tilcdc_crtc->enable_lock); return;
}
tilcdc_crtc->frame_done = false;
tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE);
/* * Wait for framedone irq which will still come before putting * things to sleep..
*/
ret = wait_event_timeout(tilcdc_crtc->frame_done_wq,
tilcdc_crtc->frame_done,
msecs_to_jiffies(500)); if (ret == 0)
dev_err(dev->dev, "%s: timeout waiting for framedone\n",
__func__);
drm_crtc_vblank_off(crtc);
spin_lock_irq(&crtc->dev->event_lock);
if (crtc->state->event) {
drm_crtc_send_vblank_event(crtc, crtc->state->event);
crtc->state->event = NULL;
}
/* * tilcdc does not generate VESA-compliant sync but aligns * VS on the second edge of HS instead of first edge. * We use adjusted_mode, to fixup sync by aligning both rising * edges and add HSKEW offset to fix the sync.
*/
adjusted_mode->hskew = mode->hsync_end - mode->hsync_start;
adjusted_mode->flags |= DRM_MODE_FLAG_HSKEW;
staticint tilcdc_crtc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state)
{ struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
crtc); /* If we are not active we don't care */ if (!crtc_state->active) return 0;
if (state->planes[0].ptr != crtc->primary ||
state->planes[0].state == NULL ||
state->planes[0].state->crtc != crtc) {
dev_dbg(crtc->dev->dev, "CRTC primary plane must be present"); return -EINVAL;
}
/* Turn the raster off if it for some reason is on. */
pm_runtime_get_sync(dev->dev); if (tilcdc_read(dev, LCDC_RASTER_CTRL_REG) & LCDC_RASTER_ENABLE) { /* Enable DMA Frame Done Interrupt */
tilcdc_write(dev, LCDC_INT_ENABLE_SET_REG, LCDC_FRAME_DONE);
tilcdc_clear_irqstatus(dev, 0xffffffff);
/* * check to see if the width is within the range that * the LCD Controller physically supports
*/ if (mode->hdisplay > priv->max_width) return MODE_VIRTUAL_X;
/* width must be multiple of 16 */ if (mode->hdisplay & 0xf) return MODE_VIRTUAL_X;
if ((hbp-1) & ~0x3ff) {
DBG("Pruning mode: Horizontal Back Porch out of range"); return MODE_HBLANK_WIDE;
}
if ((hfp-1) & ~0x3ff) {
DBG("Pruning mode: Horizontal Front Porch out of range"); return MODE_HBLANK_WIDE;
}
if ((hsw-1) & ~0x3ff) {
DBG("Pruning mode: Horizontal Sync Width out of range"); return MODE_HSYNC_WIDE;
}
if (vbp & ~0xff) {
DBG("Pruning mode: Vertical Back Porch out of range"); return MODE_VBLANK_WIDE;
}
if (vfp & ~0xff) {
DBG("Pruning mode: Vertical Front Porch out of range"); return MODE_VBLANK_WIDE;
}
if ((vsw-1) & ~0x3f) {
DBG("Pruning mode: Vertical Sync Width out of range"); return MODE_VSYNC_WIDE;
}
/* * some devices have a maximum allowed pixel clock * configured from the DT
*/ if (mode->clock > priv->max_pixelclock) {
DBG("Pruning mode: pixel clock too high"); return MODE_CLOCK_HIGH;
}
/* * some devices further limit the max horizontal resolution * configured from the DT
*/ if (mode->hdisplay > priv->max_width) return MODE_BAD_WIDTH;
/* filter out modes that would require too much memory bandwidth: */
bandwidth = mode->hdisplay * mode->vdisplay *
drm_mode_vrefresh(mode); if (bandwidth > priv->max_bandwidth) {
DBG("Pruning mode: exceeds defined bandwidth limit"); return MODE_BAD;
}
if (stat & LCDC_FRAME_DONE) {
tilcdc_crtc->frame_done = true;
wake_up(&tilcdc_crtc->frame_done_wq); /* rev 1 lcdc appears to hang if irq is not disabled here */ if (priv->rev == 1)
tilcdc_clear(dev, LCDC_RASTER_CTRL_REG,
LCDC_V1_FRAME_DONE_INT_ENA);
}
/* For revision 2 only */ if (priv->rev == 2) { /* Indicate to LCDC that the interrupt service routine has * completed, see 13.3.6.1.6 in AM335x TRM.
*/
tilcdc_write(dev, LCDC_END_OF_INT_IND_REG, 0);
}
return IRQ_HANDLED;
}
int tilcdc_crtc_create(struct drm_device *dev)
{ struct tilcdc_drm_private *priv = dev->dev_private; struct tilcdc_crtc *tilcdc_crtc; struct drm_crtc *crtc; int ret;
tilcdc_crtc = devm_kzalloc(dev->dev, sizeof(*tilcdc_crtc), GFP_KERNEL); if (!tilcdc_crtc) return -ENOMEM;
if (priv->is_componentized) {
crtc->port = of_graph_get_port_by_id(dev->dev->of_node, 0); if (!crtc->port) { /* This should never happen */
dev_err(dev->dev, "Port node not found in %pOF\n",
dev->dev->of_node);
ret = -EINVAL; goto fail;
}
}
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.