Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions kernel/isp/arch/hi3516cv500/mkp/src/isp.c
Original file line number Diff line number Diff line change
Expand Up @@ -6865,6 +6865,47 @@ hi_s32 isp_drv_int_status_process(hi_vi_pipe vi_pipe, hi_s32 vi_dev, isp_drv_ctx
s_fend_was_set[vi_pipe] = fend_now;
}

/*
* openipc_frame_ts MIPI_FS push — hook on VI port FSTART, the
* same source cv200 already uses successfully. The original
* cv500 MIPI_FS source from #155 unmasked the MIPI controller's
* own vsync IRQ and W1C-cleared the bit inside the ISR top half.
* Empirically that desyncs the MIPI controller's row state
* machine under 4K30fps load (IMX415 on hi3516av300_lite:
* persistent magenta cast + intermittent `Timeout from venc
* channel 0`; the same hazard pattern as the V4 regression
* #195 fixed). port_int_f_start (VI_PT_INT_FSTART) is read in
* this exact ISR slot, is non-zero exactly when a frame is
* starting, and needs no mask changes or W1C in atomic context.
*
* Edge-detect with the same per-pipe latch as the FEND block
* since port_int is masked through VI_PT_INT_MASK and may
* remain set across multiple ISR rounds during the frame-
* start window.
*/
{
/*
* openipc_frame_ts MIPI_FS push — hook on ISP front-end FSTART.
* The cv500 ISP FE IRQ (g_isp_fe_irq) fires twice per frame:
* once with isp_raw_int & ISP_INT_FE_FSTART set (frame start),
* once with isp_raw_int & ISP_INT_FE_FEND set (frame end).
* Both bits are W1C-cleared by the existing
* `io_rw_fe_address(vi_pipe, ISP_INT_FE) = isp_raw_int;` at
* the end of this function — we just observe them here, no
* extra mask changes or W1C in atomic context. This is the
* non-disruptive replacement for the cv500 mipi_rx vsync
* hook from #155 that desynced the MIPI controller under
* sustained load (see OpenIPC/firmware#... and the V4
* sibling #195).
*/
static bool s_fstart_was_set[ISP_MAX_PIPE_NUM];
bool fstart_now = !!(isp_raw_int & ISP_INT_FE_FSTART);

if (fstart_now && !s_fstart_was_set[vi_pipe])
openipc_frame_ts_push(vi_pipe, OPENIPC_FT_EVT_MIPI_FS);
s_fstart_was_set[vi_pipe] = fstart_now;
}

int_sch.isp_int_status = isp_int_status;
int_sch.port_int_status = port_int_f_start;
int_sch.port_int_err = port_int_err;
Expand Down
31 changes: 31 additions & 0 deletions kernel/isp/mkp/src/isp.c
Original file line number Diff line number Diff line change
Expand Up @@ -7938,6 +7938,37 @@ static inline int ISP_ISR(int irq, void *id)
s_fend_was_set[ViPipe] = fend_now;
}

/*
* openipc_frame_ts: push a MIPI_FS event from the
* ISP front-end FSTART status. The original V4 MIPI_FS
* source from #155 lived in
* kernel/mipi_rx/mipi_rx_hal.c's
* mipi_rx_interrupt_route — unmasking the MIPI
* controller's vsync IRQ and W1C-clearing it in the
* ISR top half. That desynced the MIPI controller's
* row state machine under sustained load (V4 nightly
* regression — torn frames, VENC timeouts; gated off
* by #195). ISP_INT_FE.FSTART fires once per frame
* in this same ISR, is W1C-cleared by the existing
* end-of-ISR ack, and needs no MIPI-controller mask
* changes — same fix pattern as cv500 in the sibling
* commit on this branch.
*
* Edge-detect mirrors the FEND block above: the raw
* FSTART bit is level-held across the frame-start
* window and the FE IRQ fires on both transitions.
*/
{
static bool s_fstart_was_set[ISP_MAX_PHY_PIPE_NUM];
bool fstart_now =
!!(u32IspRawIntStatus & ISP_INT_FE_FSTART);

if (fstart_now && !s_fstart_was_set[ViPipe])
openipc_frame_ts_push(ViPipe,
OPENIPC_FT_EVT_MIPI_FS);
s_fstart_was_set[ViPipe] = fstart_now;
}

pstDrvCtx->stIntSch.u32IspIntStatus = u32IspIntStatus;
pstDrvCtx->stIntSch.u32PortIntStatus = u32PortIntFStart;
pstDrvCtx->stIntSch.u32PortIntErr = u32PortIntErr;
Expand Down
39 changes: 0 additions & 39 deletions kernel/mipi_rx/hi3516cv500/mipi_rx_hal.c
Original file line number Diff line number Diff line change
Expand Up @@ -2326,51 +2326,12 @@ static int mipi_rx_interrupt_route(int irq, void *dev_id)
{
volatile mipi_rx_sys_regs_t *mipi_rx_sys_regs = get_mipi_rx_sys_regs();
volatile lvds_ctrl_regs_t *lvds_ctrl_regs = NULL;
volatile mipi_ctrl_regs_t *mipi_ctrl_regs;
int i = 0;

for (i = 0; i < MIPI_RX_MAX_PHY_NUM; i++) {
mipi_rx_phy_cil_int_statis(i);
}

/*
* Frame-start dispatch (openipc_frame_ts). Runs outside the
* CHN_INT_RAW gate below because vsync IRQs alone don't set it.
* MIPI CSI-2 and LVDS vsync bits are W1C'd independently in case
* both are wired up, but openipc_frame_ts_push fires at most once
* per device per IRQ so consumers get one event per physical frame.
*/
/*
* Edge-detect on the raw vsync bits per device — see the
* matching comment in kernel/mipi_rx/mipi_rx_hal.c for the
* level-held-bit reasoning. cv500 also has the ~30–80 µs
* double-vsync quirk that the 1 ms openipc_frame_ts dedupe
* absorbs as a second line of defence.
*/
for (i = 0; i < MIPI_RX_MAX_DEV_NUM; i++) {
static bool s_vsync_was_set[MIPI_RX_MAX_DEV_NUM];
unsigned int mipi_int, lvds_int;
bool vsync_now = false;

mipi_ctrl_regs = get_mipi_ctrl_regs(i);
lvds_ctrl_regs = get_lvds_ctrl_regs(i);

mipi_int = mipi_ctrl_regs->MIPI_CTRL_INT.u32;
lvds_int = lvds_ctrl_regs->LVDS_CTRL_INT.u32;

if (mipi_int & MIPI_INT_VSYNC) {
vsync_now = true;
mipi_ctrl_regs->MIPI_CTRL_INT_RAW.u32 = MIPI_INT_VSYNC;
}
if (lvds_int & LVDS_INT_VSYNC) {
vsync_now = true;
lvds_ctrl_regs->LVDS_CTRL_INT_RAW.u32 = LVDS_INT_VSYNC;
}
if (vsync_now && !s_vsync_was_set[i])
openipc_frame_ts_push(i, OPENIPC_FT_EVT_MIPI_FS);
s_vsync_was_set[i] = vsync_now;
}

for (i = 0; i < MIPI_RX_MAX_DEV_NUM; i++) {
lvds_ctrl_regs = get_lvds_ctrl_regs(i);
if (lvds_ctrl_regs->CHN_INT_RAW.u32) {
Expand Down
8 changes: 2 additions & 6 deletions kernel/mipi_rx/hi3516cv500/mipi_rx_hal.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,8 @@
#define MIPI_RX_MIN_EXT_DATA_TYPE_BIT_WIDTH 8

#define MIPI_CIL_INT_MASK 0x00003f3f
/* Vsync bits unmasked so frame-start propagates to mipi_rx_interrupt_route,
* where openipc_frame_ts dispatches it. Error-stat bits unchanged. */
#define MIPI_INT_VSYNC (1u << 4) /* MIPI_CTRL_INT.int_vsync */
#define LVDS_INT_VSYNC (1u << 28) /* LVDS_CTRL_INT.lvds_vsync */
#define MIPI_CTRL_INT_MASK 0x00030013
#define LVDS_CTRL_INT_MASK 0x1f110000
#define MIPI_CTRL_INT_MASK 0x00030003
#define LVDS_CTRL_INT_MASK 0x0f110000 /* lvds_vsync_msk and lane0~3_sync_err_msk ignore, not err int */
#define MIPI_FRAME_INT_MASK 0x000f0000
#define MIPI_PKT_INT1_MASK 0x0001000f
#define MIPI_PKT_INT2_MASK 0x000f000f
Expand Down
Loading