/* * maximum number of dwords the buffer will hold.
*/ unsignedint size;
/* * free_pos will point the first free dword and * help in calculating tail of command buffer.
*/ unsignedint free_pos;
/* * Previously emitted DSB instruction. Used to * identify/adjust the instruction for indexed * register writes.
*/
u32 ins[2];
/* * Start of the previously emitted DSB instruction. * Used to adjust the instruction for indexed * register writes.
*/ unsignedint ins_start_offset;
u32 chicken; int hw_dewake_scanline;
};
/** * DOC: DSB * * A DSB (Display State Buffer) is a queue of MMIO instructions in the memory * which can be offloaded to DSB HW in Display Controller. DSB HW is a DMA * engine that can be programmed to download the DSB from memory. * It allows driver to batch submit display HW programming. This helps to * reduce loading time and CPU activity, thereby making the context switch * faster. DSB Support added from Gen12 Intel graphics based platform. * * DSB's can access only the pipe, plane, and transcoder Data Island Packet * registers. * * DSB HW can support only register writes (both indexed and direct MMIO * writes). There are no registers reads possible with DSB HW engine.
*/
if (pre_commit_is_vrr_active(state, crtc)) /* * When the push is sent during vblank it will trigger * on the next scanline, hence we have up to one extra * scanline until the delayed vblank occurs after * TRANS_PUSH has been written.
*/ return intel_vrr_vblank_delay(crtc_state) + 1; else return intel_mode_vblank_delay(&crtc_state->hw.adjusted_mode);
}
/* * Bspec suggests that we should always set DSB_SKIP_WAITS_EN. We have approach * different from what is explained in Bspec on how flip is considered being * complete. We are waiting for vblank in DSB and generate interrupt when it * happens and this interrupt is considered as indication of completion -> we * definitely do not want to skip vblank wait. We also have concern what comes * to skipping vblank evasion. I.e. arming registers are latched before we have * managed writing them. Due to these reasons we are not setting * DSB_SKIP_WAITS_EN.
*/ static u32 dsb_chicken(struct intel_atomic_state *state, struct intel_crtc *crtc)
{ if (pre_commit_is_vrr_active(state, crtc)) return DSB_CTRL_WAIT_SAFE_WINDOW |
DSB_CTRL_NO_WAIT_VBLANK |
DSB_INST_WAIT_SAFE_WINDOW |
DSB_INST_NO_WAIT_VBLANK; else return 0;
}
staticvoid intel_dsb_ins_align(struct intel_dsb *dsb)
{ /* * Every instruction should be 8 byte aligned. * * The only way to get unaligned free_pos is via * intel_dsb_reg_write_indexed() which already * makes sure the next dword is zeroed, so no need * to clear it here.
*/
dsb->free_pos = ALIGN(dsb->free_pos, 2);
}
/* * Nothing emitted yet? Must check before looking * at the actual data since i915_gem_object_create_internal() * does *not* give you zeroed memory!
*/ if (dsb->free_pos == 0) returnfalse;
/** * intel_dsb_reg_write_indexed() - Emit indexed register write to the DSB context * @dsb: DSB context * @reg: register address. * @val: value. * * This function is used for writing register-value pair in command * buffer of DSB. * * Note that indexed writes are slower than normal MMIO writes * for a small number (less than 5 or so) of writes to the same * register.
*/ void intel_dsb_reg_write_indexed(struct intel_dsb *dsb,
i915_reg_t reg, u32 val)
{ /* * For example the buffer will look like below for 3 dwords for auto * increment register: * +--------------------------------------------------------+ * | size = 3 | offset &| value1 | value2 | value3 | zero | * | | opcode | | | | | * +--------------------------------------------------------+ * + + + + + + + * 0 4 8 12 16 20 24 * Byte * * As every instruction is 8 byte aligned the index of dsb instruction * will start always from even number while dealing with u32 array. If * we are writing odd no of dwords, Zeros will be added in the end for * padding.
*/ if (!intel_dsb_prev_ins_is_indexed_write(dsb, reg))
intel_dsb_emit(dsb, 0, /* count */
(DSB_OPCODE_INDEXED_WRITE << DSB_OPCODE_SHIFT) |
i915_mmio_reg_offset(reg));
intel_dsb_buffer_write(&dsb->dsb_buf, dsb->free_pos++, val); /* if number of data words is odd, then the last dword should be 0.*/ if (dsb->free_pos & 0x1)
intel_dsb_buffer_write(&dsb->dsb_buf, dsb->free_pos, 0);
}
void intel_dsb_wait_usec(struct intel_dsb *dsb, int count)
{ /* +1 to make sure we never wait less time than asked for */
intel_dsb_emit(dsb, count + 1,
DSB_OPCODE_WAIT_USEC << DSB_OPCODE_SHIFT);
}
if (drm_WARN_ON(display->drm, dsb->id != sub_dsb->id)) return;
if (!assert_dsb_tail_is_aligned(sub_dsb)) return;
intel_dsb_gosub_align(dsb);
head = intel_dsb_head(sub_dsb);
tail = intel_dsb_tail(sub_dsb);
/* * The GOSUB instruction has the following memory layout. * * +------------------------------------------------------------+ * | Opcode | Rsvd | Head Ptr | Tail Ptr | * | 0x0c | | | | * +------------------------------------------------------------+ * |<- 8bits->|<- 4bits ->|<-- 26bits -->|<-- 26bits -->| * * We have only 26 bits each to represent the head and tail * pointers even though the addresses itself are of 32 bit. However, this * is not a problem because the addresses are 64 bit aligned and therefore * the last 6 bits are always Zero's. Therefore, we right shift the address * by 6 before embedding it into the GOSUB instruction.
*/
/* * All the non-existing status bits operate as * normal r/w bits, so any attempt to clear them * will just end up setting them. Never do that so * we won't mistake them for actual error interrupts.
*/ if (DISPLAY_VER(display) >= 14)
errors |= DSB_ATS_FAULT_INT_STATUS;
if (DISPLAY_VER(display) >= 30)
errors |= DSB_GOSUB_INT_STATUS;
/* * FIXME calibrate these sensibly, ideally compute based on * the number of regisetrs to be written. But that requires * measuring the actual DSB execution speed on each platform * (and the speed also depends on CDCLK and memory clock)...
*/ staticint intel_dsb_noarm_exec_time_us(void)
{ return 80;
}
/* * PIPEDSL is reading as 0 when in SRDENT(PSR1) or DEEP_SLEEP(PSR2). On * wake-up scanline counting starts from vblank_start - 1. We don't know * if wake-up is already ongoing when evasion starts. In worst case * PIPEDSL could start reading valid value right after checking the * scanline. In this scenario we wouldn't have enough time to write all * registers. To tackle this evade scanline 0 as well. As a drawback we * have 1 frame delay in flip when waking up.
*/ if (crtc_state->has_psr)
intel_dsb_emit_wait_dsl(dsb, DSB_OPCODE_WAIT_DSL_OUT, 0, 0);
if (pre_commit_is_vrr_active(state, crtc)) { int vblank_delay = intel_vrr_vblank_delay(crtc_state);
end = intel_vrr_vmin_vblank_start(crtc_state);
start = end - vblank_delay - latency;
intel_dsb_wait_scanline_out(state, dsb, start, end);
end = intel_vrr_vmax_vblank_start(crtc_state);
start = end - vblank_delay - latency;
intel_dsb_wait_scanline_out(state, dsb, start, end);
} else { int vblank_delay = intel_mode_vblank_delay(&crtc_state->hw.adjusted_mode);
end = intel_mode_vblank_start(&crtc_state->hw.adjusted_mode);
start = end - vblank_delay - latency;
intel_dsb_wait_scanline_out(state, dsb, start, end);
}
}
if (ctrl & DSB_WAIT_FOR_VBLANK) { /* * Keep DEwake alive via the first DSB, in * case we're already past dewake_scanline, * and thus DSB_ENABLE_DEWAKE on the second * DSB won't do its job.
*/
intel_dsb_reg_write_masked(dsb, DSB_PMCTRL_2(pipe, dsb->id),
DSB_FORCE_DEWAKE, DSB_FORCE_DEWAKE);
/* * DSB_FORCE_DEWAKE remains active even after DSB is * disabled, so make sure to clear it.
*/
intel_dsb_reg_write_masked(dsb, DSB_PMCTRL_2(crtc->pipe, dsb->id),
DSB_FORCE_DEWAKE, 0);
}
}
/** * intel_dsb_commit() - Trigger workload execution of DSB. * @dsb: DSB context * * This function is used to do actual write to hardware using DSB.
*/ void intel_dsb_commit(struct intel_dsb *dsb)
{ struct intel_crtc *crtc = dsb->crtc; struct intel_display *display = to_intel_display(crtc->base.dev); enum pipe pipe = crtc->pipe;
if (!assert_dsb_tail_is_aligned(dsb)) return;
if (is_dsb_busy(display, pipe, dsb->id)) {
drm_err(display->drm, "[CRTC:%d:%s] DSB %d is busy\n",
crtc->base.base.id, crtc->base.name, dsb->id); return;
}
/** * intel_dsb_prepare() - Allocate, pin and map the DSB command buffer. * @state: the atomic state * @crtc: the CRTC * @dsb_id: the DSB engine to use * @max_cmds: number of commands we need to fit into command buffer * * This function prepare the command buffer which is used to store dsb * instructions with data. * * Returns: * DSB context, NULL on failure
*/ struct intel_dsb *intel_dsb_prepare(struct intel_atomic_state *state, struct intel_crtc *crtc, enum intel_dsb_id dsb_id, unsignedint max_cmds)
{ struct intel_display *display = to_intel_display(state); struct ref_tracker *wakeref; struct intel_dsb *dsb; unsignedint size;
if (!HAS_DSB(display)) return NULL;
if (!display->params.enable_dsb) return NULL;
dsb = kzalloc(sizeof(*dsb), GFP_KERNEL); if (!dsb) goto out;
wakeref = intel_display_rpm_get(display);
/* ~1 qword per instruction, full cachelines */
size = ALIGN(max_cmds * 8, CACHELINE_BYTES);
if (!intel_dsb_buffer_create(crtc, &dsb->dsb_buf, size)) goto out_put_rpm;
out_put_rpm:
intel_display_rpm_put(display, wakeref);
kfree(dsb);
out:
drm_info_once(display->drm, "[CRTC:%d:%s] DSB %d queue setup failed, will fallback to MMIO for display HW programming\n",
crtc->base.base.id, crtc->base.name, dsb_id);
return NULL;
}
/** * intel_dsb_cleanup() - To cleanup DSB context. * @dsb: DSB context * * This function cleanup the DSB context by unpinning and releasing * the VMA object associated with it.
*/ void intel_dsb_cleanup(struct intel_dsb *dsb)
{
intel_dsb_buffer_cleanup(&dsb->dsb_buf);
kfree(dsb);
}
if (tmp & DSB_PROG_INT_STATUS) {
spin_lock(&display->drm->event_lock);
if (crtc->dsb_event) { /* * Update vblank counter/timestamp in case it * hasn't been done yet for this frame.
*/
drm_crtc_accurate_vblank_count(&crtc->base);
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.