Skip to content

Commit 67d793c

Browse files
authored
mipi_rx/isp: move MIPI_FS push from MIPI vsync IRQ to ISP FSTART (#199)
The original openipc_frame_ts MIPI_FS source (#155) unmasked the MIPI controller's vsync IRQ and W1C-cleared the bit inside the ISR top half. Empirically this desyncs the MIPI controller's row state machine on V4 (gk7205v300/hi3516ev300, see #195) and on cv500/av300 under sustained 4K30fps load (IMX415 on hi3516av300_lite: persistent magenta cast + intermittent `Timeout from venc channel 0` in majestic). #195 fixed V4 by gating the entire vsync block off — but that left V4 without any MIPI_FS event source, regressing the feature for that family. cv500's parallel block in kernel/mipi_rx/hi3516cv500/mipi_rx_hal.c carried the same hazard. Move the MIPI_FS push to the ISP front-end FSTART status bit instead, mirroring the existing FEND push added in #178: - kernel/mipi_rx/hi3516cv500/mipi_rx_hal.c drop the vsync block - kernel/mipi_rx/hi3516cv500/mipi_rx_hal.h revert mask to pre-#155 - kernel/isp/arch/hi3516cv500/mkp/src/isp.c + MIPI_FS push on isp_raw_int & FSTART - kernel/isp/mkp/src/isp.c + MIPI_FS push on u32IspRawIntStatus & FSTART (V4 path) The ISP front-end IRQ already fires twice per frame on these SoCs (once with FSTART set, once with FEND set; both W1C-cleared by the existing end-of-ISR ack). Edge-detect mirrors the FEND block above. No MIPI controller mask changes, no W1C in atomic context. cv200 retains its tasklet-deferred MIPI_FS push from #186 — its ISP IRQ doesn't expose a separate FEND, and its vsync-equivalent hook on VI_PT0_INT_FSTART has always been non-disruptive on V2/V2A. Verified on hardware against this branch's build of opensdk overlaid on the firmware nightly-20260527 master: cv500 av300 IMX415 4K30 | luma stdev 0.03 | MIPI_FS 188 + FEND 188 / 3 s V4 gk7205v300 IMX335 | luma stdev 0.01 | MIPI_FS 200 + FEND 201 / 3 s V2A hi3518ev200 soi_f22 | luma stdev 0.14 | MIPI_FS 89 + FEND 0 / 3 s (cv200 HW lacks FEND, expected) All three: 0 VENC timeouts in 90 s soak, 0 rt_mutex_trylock WARN. Reported-by: OpenIPC/firmware users — V4 sibling regression #195, V4A magenta cast on hi3516av300_lite (this PR), and V2A AE-runaway #197 (separate cv200 sensor_i2c fix). Closes: cv500/V4 MIPI_FS regression that #195 worked around by disabling rather than rerouting.
1 parent 073e6e8 commit 67d793c

4 files changed

Lines changed: 74 additions & 45 deletions

File tree

kernel/isp/arch/hi3516cv500/mkp/src/isp.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6865,6 +6865,47 @@ hi_s32 isp_drv_int_status_process(hi_vi_pipe vi_pipe, hi_s32 vi_dev, isp_drv_ctx
68656865
s_fend_was_set[vi_pipe] = fend_now;
68666866
}
68676867

6868+
/*
6869+
* openipc_frame_ts MIPI_FS push — hook on VI port FSTART, the
6870+
* same source cv200 already uses successfully. The original
6871+
* cv500 MIPI_FS source from #155 unmasked the MIPI controller's
6872+
* own vsync IRQ and W1C-cleared the bit inside the ISR top half.
6873+
* Empirically that desyncs the MIPI controller's row state
6874+
* machine under 4K30fps load (IMX415 on hi3516av300_lite:
6875+
* persistent magenta cast + intermittent `Timeout from venc
6876+
* channel 0`; the same hazard pattern as the V4 regression
6877+
* #195 fixed). port_int_f_start (VI_PT_INT_FSTART) is read in
6878+
* this exact ISR slot, is non-zero exactly when a frame is
6879+
* starting, and needs no mask changes or W1C in atomic context.
6880+
*
6881+
* Edge-detect with the same per-pipe latch as the FEND block
6882+
* since port_int is masked through VI_PT_INT_MASK and may
6883+
* remain set across multiple ISR rounds during the frame-
6884+
* start window.
6885+
*/
6886+
{
6887+
/*
6888+
* openipc_frame_ts MIPI_FS push — hook on ISP front-end FSTART.
6889+
* The cv500 ISP FE IRQ (g_isp_fe_irq) fires twice per frame:
6890+
* once with isp_raw_int & ISP_INT_FE_FSTART set (frame start),
6891+
* once with isp_raw_int & ISP_INT_FE_FEND set (frame end).
6892+
* Both bits are W1C-cleared by the existing
6893+
* `io_rw_fe_address(vi_pipe, ISP_INT_FE) = isp_raw_int;` at
6894+
* the end of this function — we just observe them here, no
6895+
* extra mask changes or W1C in atomic context. This is the
6896+
* non-disruptive replacement for the cv500 mipi_rx vsync
6897+
* hook from #155 that desynced the MIPI controller under
6898+
* sustained load (see OpenIPC/firmware#... and the V4
6899+
* sibling #195).
6900+
*/
6901+
static bool s_fstart_was_set[ISP_MAX_PIPE_NUM];
6902+
bool fstart_now = !!(isp_raw_int & ISP_INT_FE_FSTART);
6903+
6904+
if (fstart_now && !s_fstart_was_set[vi_pipe])
6905+
openipc_frame_ts_push(vi_pipe, OPENIPC_FT_EVT_MIPI_FS);
6906+
s_fstart_was_set[vi_pipe] = fstart_now;
6907+
}
6908+
68686909
int_sch.isp_int_status = isp_int_status;
68696910
int_sch.port_int_status = port_int_f_start;
68706911
int_sch.port_int_err = port_int_err;

kernel/isp/mkp/src/isp.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7938,6 +7938,37 @@ static inline int ISP_ISR(int irq, void *id)
79387938
s_fend_was_set[ViPipe] = fend_now;
79397939
}
79407940

7941+
/*
7942+
* openipc_frame_ts: push a MIPI_FS event from the
7943+
* ISP front-end FSTART status. The original V4 MIPI_FS
7944+
* source from #155 lived in
7945+
* kernel/mipi_rx/mipi_rx_hal.c's
7946+
* mipi_rx_interrupt_route — unmasking the MIPI
7947+
* controller's vsync IRQ and W1C-clearing it in the
7948+
* ISR top half. That desynced the MIPI controller's
7949+
* row state machine under sustained load (V4 nightly
7950+
* regression — torn frames, VENC timeouts; gated off
7951+
* by #195). ISP_INT_FE.FSTART fires once per frame
7952+
* in this same ISR, is W1C-cleared by the existing
7953+
* end-of-ISR ack, and needs no MIPI-controller mask
7954+
* changes — same fix pattern as cv500 in the sibling
7955+
* commit on this branch.
7956+
*
7957+
* Edge-detect mirrors the FEND block above: the raw
7958+
* FSTART bit is level-held across the frame-start
7959+
* window and the FE IRQ fires on both transitions.
7960+
*/
7961+
{
7962+
static bool s_fstart_was_set[ISP_MAX_PHY_PIPE_NUM];
7963+
bool fstart_now =
7964+
!!(u32IspRawIntStatus & ISP_INT_FE_FSTART);
7965+
7966+
if (fstart_now && !s_fstart_was_set[ViPipe])
7967+
openipc_frame_ts_push(ViPipe,
7968+
OPENIPC_FT_EVT_MIPI_FS);
7969+
s_fstart_was_set[ViPipe] = fstart_now;
7970+
}
7971+
79417972
pstDrvCtx->stIntSch.u32IspIntStatus = u32IspIntStatus;
79427973
pstDrvCtx->stIntSch.u32PortIntStatus = u32PortIntFStart;
79437974
pstDrvCtx->stIntSch.u32PortIntErr = u32PortIntErr;

kernel/mipi_rx/hi3516cv500/mipi_rx_hal.c

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2326,51 +2326,12 @@ static int mipi_rx_interrupt_route(int irq, void *dev_id)
23262326
{
23272327
volatile mipi_rx_sys_regs_t *mipi_rx_sys_regs = get_mipi_rx_sys_regs();
23282328
volatile lvds_ctrl_regs_t *lvds_ctrl_regs = NULL;
2329-
volatile mipi_ctrl_regs_t *mipi_ctrl_regs;
23302329
int i = 0;
23312330

23322331
for (i = 0; i < MIPI_RX_MAX_PHY_NUM; i++) {
23332332
mipi_rx_phy_cil_int_statis(i);
23342333
}
23352334

2336-
/*
2337-
* Frame-start dispatch (openipc_frame_ts). Runs outside the
2338-
* CHN_INT_RAW gate below because vsync IRQs alone don't set it.
2339-
* MIPI CSI-2 and LVDS vsync bits are W1C'd independently in case
2340-
* both are wired up, but openipc_frame_ts_push fires at most once
2341-
* per device per IRQ so consumers get one event per physical frame.
2342-
*/
2343-
/*
2344-
* Edge-detect on the raw vsync bits per device — see the
2345-
* matching comment in kernel/mipi_rx/mipi_rx_hal.c for the
2346-
* level-held-bit reasoning. cv500 also has the ~30–80 µs
2347-
* double-vsync quirk that the 1 ms openipc_frame_ts dedupe
2348-
* absorbs as a second line of defence.
2349-
*/
2350-
for (i = 0; i < MIPI_RX_MAX_DEV_NUM; i++) {
2351-
static bool s_vsync_was_set[MIPI_RX_MAX_DEV_NUM];
2352-
unsigned int mipi_int, lvds_int;
2353-
bool vsync_now = false;
2354-
2355-
mipi_ctrl_regs = get_mipi_ctrl_regs(i);
2356-
lvds_ctrl_regs = get_lvds_ctrl_regs(i);
2357-
2358-
mipi_int = mipi_ctrl_regs->MIPI_CTRL_INT.u32;
2359-
lvds_int = lvds_ctrl_regs->LVDS_CTRL_INT.u32;
2360-
2361-
if (mipi_int & MIPI_INT_VSYNC) {
2362-
vsync_now = true;
2363-
mipi_ctrl_regs->MIPI_CTRL_INT_RAW.u32 = MIPI_INT_VSYNC;
2364-
}
2365-
if (lvds_int & LVDS_INT_VSYNC) {
2366-
vsync_now = true;
2367-
lvds_ctrl_regs->LVDS_CTRL_INT_RAW.u32 = LVDS_INT_VSYNC;
2368-
}
2369-
if (vsync_now && !s_vsync_was_set[i])
2370-
openipc_frame_ts_push(i, OPENIPC_FT_EVT_MIPI_FS);
2371-
s_vsync_was_set[i] = vsync_now;
2372-
}
2373-
23742335
for (i = 0; i < MIPI_RX_MAX_DEV_NUM; i++) {
23752336
lvds_ctrl_regs = get_lvds_ctrl_regs(i);
23762337
if (lvds_ctrl_regs->CHN_INT_RAW.u32) {

kernel/mipi_rx/hi3516cv500/mipi_rx_hal.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,8 @@
1515
#define MIPI_RX_MIN_EXT_DATA_TYPE_BIT_WIDTH 8
1616

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

0 commit comments

Comments
 (0)