/* * A note about interlacing. Let's consider HDMI 1920x1080i. * The timing parameters we have from X are: * Hact HsyA HsyI Htot Vact VsyA VsyI Vtot * 1920 2448 2492 2640 1080 1084 1094 1125 * Which get translated to: * Hact HsyA HsyI Htot Vact VsyA VsyI Vtot * 1920 2448 2492 2640 540 542 547 562 * * This is how it is defined by CEA-861-D - line and pixel numbers are * referenced to the rising edge of VSYNC and HSYNC. Total clocks per * line: 2640. The odd frame, the first active line is at line 21, and * the even frame, the first active line is 584. * * LN: 560 561 562 563 567 568 569 * DE: ~~~|____________________________//__________________________ * HSYNC: ____|~|_____|~|_____|~|_____|~|_//__|~|_____|~|_____|~|_____ * VSYNC: _________________________|~~~~~~//~~~~~~~~~~~~~~~|__________ * 22 blanking lines. VSYNC at 1320 (referenced to the HSYNC rising edge). * * LN: 1123 1124 1125 1 5 6 7 * DE: ~~~|____________________________//__________________________ * HSYNC: ____|~|_____|~|_____|~|_____|~|_//__|~|_____|~|_____|~|_____ * VSYNC: ____________________|~~~~~~~~~~~//~~~~~~~~~~|_______________ * 23 blanking lines * * The Armada LCD Controller line and pixel numbers are, like X timings, * referenced to the top left of the active frame. * * So, translating these to our LCD controller: * Odd frame, 563 total lines, VSYNC at line 543-548, pixel 1128. * Even frame, 562 total lines, VSYNC at line 542-547, pixel 2448. * Note: Vsync front porch remains constant! * * if (odd_frame) { * vtotal = mode->crtc_vtotal + 1; * vbackporch = mode->crtc_vsync_start - mode->crtc_vdisplay + 1; * vhorizpos = mode->crtc_hsync_start - mode->crtc_htotal / 2 * } else { * vtotal = mode->crtc_vtotal; * vbackporch = mode->crtc_vsync_start - mode->crtc_vdisplay; * vhorizpos = mode->crtc_hsync_start; * } * vfrontporch = mode->crtc_vtotal - mode->crtc_vsync_end; * * So, we need to reprogram these registers on each vsync event: * LCD_SPU_V_PORCH, LCD_SPU_ADV_REG, LCD_SPUT_V_H_TOTAL * * Note: we do not use the frame done interrupts because these appear * to happen too early, and lead to jitter on the display (presumably * they occur at the end of the last active line, before the vsync back * porch, which we're reprogramming.)
*/
/* * When the dumb interface isn't in DUMB24_RGB888_0 mode, it might * be using SPI or GPIO. If we set this to DUMB_BLANK, we will * force LCD_D[23:0] to output blank color, overriding the GPIO or * SPI usage. So leave it as-is unless in DUMB24_RGB888_0 mode.
*/ if (!enable && (dumb_ctrl & DUMB_MASK) == DUMB24_RGB888_0) {
dumb_ctrl &= ~DUMB_MASK;
dumb_ctrl |= DUMB_BLANK;
}
/* If we have an event, we need vblank events enabled */
event = xchg(&crtc->state->event, NULL); if (event) {
WARN_ON(drm_crtc_vblank_get(crtc) != 0);
dcrtc->event = event;
}
}
if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN;
if (mode->flags & DRM_MODE_FLAG_HSKEW) return MODE_H_ILLEGAL;
/* We can't do interlaced modes if we don't have the SPU_ADV_REG */ if (!dcrtc->variant->has_spu_adv_reg &&
mode->flags & DRM_MODE_FLAG_INTERLACE) return MODE_NO_INTERLACE;
if (mode->flags & (DRM_MODE_FLAG_BCAST | DRM_MODE_FLAG_PIXMUX |
DRM_MODE_FLAG_CLKDIV2)) return MODE_BAD;
return MODE_OK;
}
/* The mode_config.mutex will be held for this call */ staticbool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc, conststruct drm_display_mode *mode, struct drm_display_mode *adj)
{ struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); int ret;
/* * Set CRTC modesetting parameters for the adjusted mode. This is * applied after the connectors, bridges, and encoders have fixed up * this mode, as described above drm_atomic_helper_check_modeset().
*/
drm_mode_set_crtcinfo(adj, CRTC_INTERLACE_HALVE_V);
/* * Validate the adjusted mode in case an encoder/bridge has set * something we don't support.
*/ if (armada_drm_crtc_mode_valid(crtc, adj) != MODE_OK) returnfalse;
/* Check whether the display mode is possible */
ret = dcrtc->variant->compute_clock(dcrtc, adj, NULL); if (ret) returnfalse;
returntrue;
}
/* These are locked by dev->vbl_lock */ staticvoid armada_drm_crtc_disable_irq(struct armada_crtc *dcrtc, u32 mask)
{ if (dcrtc->irq_ena & mask) {
dcrtc->irq_ena &= ~mask;
writel(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA);
}
}
if (stat & DMA_FF_UNDERFLOW)
DRM_ERROR("video underflow on crtc %u\n", dcrtc->num); if (stat & GRA_FF_UNDERFLOW)
DRM_ERROR("graphics underflow on crtc %u\n", dcrtc->num);
if (stat & VSYNC_IRQ)
drm_crtc_handle_vblank(&dcrtc->crtc);
spin_lock(&dcrtc->irq_lock); if (stat & GRA_FRAME_IRQ && dcrtc->interlaced) { int i = stat & GRA_FRAME_IRQ0 ? 0 : 1;
uint32_t val;
writel_relaxed(dcrtc->v[i].spu_v_porch, base + LCD_SPU_V_PORCH);
writel_relaxed(dcrtc->v[i].spu_v_h_total,
base + LCD_SPUT_V_H_TOTAL);
val = readl_relaxed(base + LCD_SPU_ADV_REG);
val &= ~(ADV_VSYNC_L_OFF | ADV_VSYNC_H_OFF | ADV_VSYNCOFFEN);
val |= dcrtc->v[i].spu_adv_reg;
writel_relaxed(val, base + LCD_SPU_ADV_REG);
}
if (stat & dcrtc->irq_ena & DUMB_FRAMEDONE) { if (dcrtc->update_pending) {
armada_drm_crtc_update_regs(dcrtc, dcrtc->regs);
dcrtc->update_pending = false;
} if (dcrtc->cursor_update) {
writel_relaxed(dcrtc->cursor_hw_pos,
base + LCD_SPU_HWC_OVSA_HPXL_VLN);
writel_relaxed(dcrtc->cursor_hw_sz,
base + LCD_SPU_HWC_HPXL_VLN);
armada_updatel(CFG_HWC_ENA,
CFG_HWC_ENA | CFG_HWC_1BITMOD |
CFG_HWC_1BITENA,
base + LCD_SPU_DMA_CTRL0);
dcrtc->cursor_update = false;
}
armada_drm_crtc_disable_irq(dcrtc, DUMB_FRAMEDONE_ENA);
}
spin_unlock(&dcrtc->irq_lock);
/* * Reading the ISR appears to clear bits provided CLEAN_SPU_IRQ_ISR * is set. Writing has some other effect to acknowledge the IRQ - * without this, we only get a single IRQ.
*/
writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ISR);
trace_armada_drm_irq(&dcrtc->crtc, stat);
/* Mask out those interrupts we haven't enabled */
v = stat & dcrtc->irq_ena;
if (v & (VSYNC_IRQ|GRA_FRAME_IRQ|DUMB_FRAMEDONE)) {
armada_drm_crtc_irq(dcrtc, stat); return IRQ_HANDLED;
} return IRQ_NONE;
}
/* The mode_config.mutex will be held for this call */ staticvoid armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
{ struct drm_display_mode *adj = &crtc->state->adjusted_mode; struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); struct armada_regs regs[17];
uint32_t lm, rm, tm, bm, val, sclk; unsignedlong flags; unsigned i; bool interlaced = !!(adj->flags & DRM_MODE_FLAG_INTERLACE);
val = adj->crtc_vdisplay << 16 | adj->crtc_hdisplay;
armada_reg_queue_set(regs, i, val, LCD_SPU_V_H_ACTIVE);
armada_reg_queue_set(regs, i, (lm << 16) | rm, LCD_SPU_H_PORCH);
armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_porch, LCD_SPU_V_PORCH);
armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_h_total,
LCD_SPUT_V_H_TOTAL);
if (dcrtc->variant->has_spu_adv_reg)
armada_reg_queue_mod(regs, i, dcrtc->v[0].spu_adv_reg,
ADV_VSYNC_L_OFF | ADV_VSYNC_H_OFF |
ADV_VSYNCOFFEN, LCD_SPU_ADV_REG);
val = adj->flags & DRM_MODE_FLAG_NVSYNC ? CFG_VSYNC_INV : 0;
armada_reg_queue_mod(regs, i, val, CFG_VSYNC_INV, LCD_SPU_DMA_CTRL1);
/* * The documentation doesn't indicate what the normal state of * the sync signals are. Sebastian Hesselbart kindly probed * these signals on his board to determine their state. * * The non-inverted state of the sync signals is active high. * Setting these bits makes the appropriate signal active low.
*/
val = 0; if (adj->flags & DRM_MODE_FLAG_NCSYNC)
val |= CFG_INV_CSYNC; if (adj->flags & DRM_MODE_FLAG_NHSYNC)
val |= CFG_INV_HSYNC; if (adj->flags & DRM_MODE_FLAG_NVSYNC)
val |= CFG_INV_VSYNC;
armada_reg_queue_mod(regs, i, val, CFG_INV_CSYNC | CFG_INV_HSYNC |
CFG_INV_VSYNC, LCD_SPU_DUMB_CTRL);
armada_reg_queue_end(regs, i);
/* * If we aren't doing a full modeset, then we need to queue * the event here.
*/ if (!drm_atomic_crtc_needs_modeset(crtc_state)) {
dcrtc->update_pending = true;
armada_drm_crtc_queue_state_event(crtc);
spin_lock_irq(&dcrtc->irq_lock);
armada_drm_crtc_enable_irq(dcrtc, DUMB_FRAMEDONE_ENA);
spin_unlock_irq(&dcrtc->irq_lock);
} else {
spin_lock_irq(&dcrtc->irq_lock);
armada_drm_crtc_update_regs(dcrtc, dcrtc->regs);
spin_unlock_irq(&dcrtc->irq_lock);
}
}
if (!crtc->state->active) { /* * This modeset will be leaving the CRTC disabled, so * call the backend to disable upstream clocks etc.
*/ if (dcrtc->variant->disable)
dcrtc->variant->disable(dcrtc);
/* * We will not receive any further vblank events. * Send the flip_done event manually.
*/
event = crtc->state->event;
crtc->state->event = NULL; if (event) {
spin_lock_irq(&crtc->dev->event_lock);
drm_crtc_send_vblank_event(crtc, event);
spin_unlock_irq(&crtc->dev->event_lock);
}
}
}
if (!old_state->active) { /* * This modeset is enabling the CRTC after it having * been disabled. Reverse the call to ->disable in * the atomic_disable().
*/ if (dcrtc->variant->enable)
dcrtc->variant->enable(dcrtc, &crtc->state->adjusted_mode);
}
armada_drm_crtc_update(dcrtc, true);
drm_crtc_vblank_on(crtc);
if (crtc->state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
WARN_ON(drm_crtc_vblank_get(crtc));
addr = SRAM_HWC32_RAM1; for (y = 0; y < height; y++) {
uint32_t *p = &pix[y * stride]; unsigned x;
for (x = 0; x < width; x++, p++) {
uint32_t val = *p;
/* * In "ARGB888" (HWC32) mode, writing to the SRAM * requires these bits to contain: * 31:24 = alpha 23:16 = blue 15:8 = green 7:0 = red * So, it's actually ABGR8888. This is independent * of the SWAPRB bits in DMA control register 0.
*/
val = (val & 0xff00ff00) |
(val & 0x000000ff) << 16 |
(val & 0x00ff0000) >> 16;
writel_relaxed(val,
base + LCD_SPU_SRAM_WRDAT);
writel_relaxed(addr | SRAM_WRITE,
base + LCD_SPU_SRAM_CTRL);
readl_relaxed(base + LCD_SPU_HWC_OVSA_HPXL_VLN);
addr += 1; if ((addr & 0x00ff) == 0)
addr += 0xf00; if ((addr & 0x30ff) == 0)
addr = SRAM_HWC32_RAM2;
}
}
}
/* * Initialize the transparency if the SRAM was powered down. * We must also reload the cursor data as well.
*/ if (!(para1 & CFG_CSB_256x32)) {
armada_drm_crtc_cursor_tran(dcrtc->base);
reload = true;
}
if (dcrtc->cursor_hw_sz != (h << 16 | w)) {
spin_lock_irq(&dcrtc->irq_lock);
dcrtc->cursor_update = false;
armada_updatel(0, CFG_HWC_ENA, dcrtc->base + LCD_SPU_DMA_CTRL0);
spin_unlock_irq(&dcrtc->irq_lock);
reload = true;
} if (reload) { struct armada_gem_object *obj = dcrtc->cursor_obj;
uint32_t *pix; /* Set the top-left corner of the cursor image */
pix = obj->addr;
pix += yoff * s + xoff;
armada_load_cursor_argb(dcrtc->base, pix, s, w, h);
}
/* Reload the cursor position, size and enable in the IRQ handler */
spin_lock_irq(&dcrtc->irq_lock);
dcrtc->cursor_hw_pos = yscr << 16 | xscr;
dcrtc->cursor_hw_sz = h << 16 | w;
dcrtc->cursor_update = true;
armada_drm_crtc_enable_irq(dcrtc, DUMB_FRAMEDONE_ENA);
spin_unlock_irq(&dcrtc->irq_lock);
if (dcrtc->variant->disable)
dcrtc->variant->disable(dcrtc);
writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ENA);
of_node_put(dcrtc->crtc.port);
kfree(dcrtc);
}
staticint armada_drm_crtc_late_register(struct drm_crtc *crtc)
{ if (IS_ENABLED(CONFIG_DEBUG_FS))
armada_drm_crtc_debugfs_init(drm_to_armada_crtc(crtc));
return 0;
}
/* These are called under the vbl_lock. */ staticint armada_drm_crtc_enable_vblank(struct drm_crtc *crtc)
{ struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); unsignedlong flags;
/* If the clock can do exactly the desired rate, we're done */ if (real_clk_hz == desired_hz) {
real_hz = real_clk_hz;
div = 1; goto found;
}
/* Calculate the divider - if invalid, we can't do this rate */
div = DIV_ROUND_CLOSEST(real_clk_hz, desired_hz); if (div == 0 || div > params->div_max) continue;
/* Calculate the actual rate - HDMI requires -0.6%..+0.5% */
real_hz = DIV_ROUND_CLOSEST(real_clk_hz, div);
variant = device_get_match_data(dev); if (!variant) return -ENXIO;
if (parent) {
np = of_get_child_by_name(parent, "ports"); if (np)
parent = np;
port = of_get_child_by_name(parent, "port");
of_node_put(np); if (!port) {
dev_err(dev, "no port node found in %pOF\n", parent); return -ENXIO;
}
}
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.