diff --git a/kernel/isp/arch/hi3516cv500/mkp/src/isp.c b/kernel/isp/arch/hi3516cv500/mkp/src/isp.c index 1a5fa66..6325810 100644 --- a/kernel/isp/arch/hi3516cv500/mkp/src/isp.c +++ b/kernel/isp/arch/hi3516cv500/mkp/src/isp.c @@ -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; diff --git a/kernel/isp/mkp/src/isp.c b/kernel/isp/mkp/src/isp.c index 7c0406e..ab61945 100644 --- a/kernel/isp/mkp/src/isp.c +++ b/kernel/isp/mkp/src/isp.c @@ -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; diff --git a/kernel/mipi_rx/hi3516cv500/mipi_rx_hal.c b/kernel/mipi_rx/hi3516cv500/mipi_rx_hal.c index 8303fa6..6b97037 100644 --- a/kernel/mipi_rx/hi3516cv500/mipi_rx_hal.c +++ b/kernel/mipi_rx/hi3516cv500/mipi_rx_hal.c @@ -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) { diff --git a/kernel/mipi_rx/hi3516cv500/mipi_rx_hal.h b/kernel/mipi_rx/hi3516cv500/mipi_rx_hal.h index 7812b39..c5b18ac 100644 --- a/kernel/mipi_rx/hi3516cv500/mipi_rx_hal.h +++ b/kernel/mipi_rx/hi3516cv500/mipi_rx_hal.h @@ -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