MIPI CSI-2 from FPGA @ 896×896 90FPS — Deskew, nvcsi Clock Errors, Short Frames

Can’t acheive 90fps with the setup.

My Setup

Item Details
Board Jetson Orin Nano 4 GB (Custom carrier board), L4T 36.4.4
Source FPGA (MIPI CSI-2 transmitter)
Resolution 896 × 896
Frame Rate 90 FPS
Pixel Format YUV422 16-bit (UYVY)
Virtual Channel VC1
MIPI Tx Speed 1728 Mbps/Lane
Lane Count 2
Frame Blanking 929 µs
Line Blanking 7.17 µs

Issue 1 — Deskew: Is It Actually Enabled?

Looking at drivers/media/platform/tegra/camera/csi/csi.c (kernel-oot), deskew only activates when:

deskew_init_enable == true
pixel_clock_hz    >= 750,000,000 Hz

For my config (2-lane, YUV422 16bpp, 1728 Mbps/lane):

pixel_clock = (1728 Mbps × 2 lanes) / 16 bpp ≈ 216 MHz

That is well below the 750 MHz gate, so the kernel-oot path will never enable deskew for me. When I tried forcing it by overriding these values, I got a kernel panic on stream start.

From reading the logs I believe rtcpu handles deskew independently on its own firmware side. But I’m not sure.

My questions:

  • Does rtcpu enable deskew on its own at 1728 Mbps/lane, regardless of the kernel-oot threshold?

  • How do I actually confirm deskew is active? Is there a register, an rtcpu log tag, or a sysfs entry I can check?


Issue 2 — nvcsi Clock: Uncorrectable Errors Above a Specific Frequency

When I set nvcsi to its maximum clock, I get uncorrectable (uncorr) errors and the stream dies. Through trial and error I found there is a hard ceiling — even 1 Hz above a certain nvcsi frequency causes a freeze.

It seems like nvcsi needs to be clocked at a specific rate that matches the MIPI data rate, not just “as high as possible.”

My questions:

  • Is there a formula or table to find the correct nvcsi clock for a given MIPI data rate (1728 Mbps/lane in my case)?

  • Why does exceeding this ceiling cause uncorr errors — is it a PLL issue or a PHY sampling problem?

(Logs A and B attached below)


Issue 3 — Every Frame Is a Short Frame (chansel_short_frame)

Even at the working nvcsi clock where 90 FPS appears to be delivered, the rtcpu logs show every single frame is flagged as chansel_short_frame. Not one complete frame is being received.

Logs

Log A — nvcsi at max clock (uncorr errors, stream freezes)

dmesg.log (4.6 KB)

rtcpu.log (1.1 MB)

Log B — nvcsi at ceiling (1 Hz above → freeze)
clear test pattern acheived but can’t acheive 90fps

dmesg_logs.txt (5.8 KB)

rtcpu_logs.txt (1.6 MB)

**
Log C — nvcsi at working clock (90 FPS but short frames + strip artifact)**

What I see on screen,

The test pattern from the FPGA arrives, but there is a small incorrect strip at the very top of the image. Below that the rest of the frame looks like it could be a ghost/residual from a previous buffer — I’m not 100% sure. The rtcpu logs suggest only one line is actually being received per frame, so my guess is only that top strip is real data and everything below is leftover from the previous frame.

dmes.log (7.5 KB)

rtcpu.log (1.1 MB)

**
v4l2 logs for all cases:**

v4l2_logs.log (8.3 KB)

My questions:

  • What causes chansel_short_frame on every frame? Could this be my blanking timings (929 µs frame blanking, 7.17 µs line blanking)?

  • Is the single-strip artifact a result of only one line passing before the frame gets dropped?

  • Is there a way to tune or relax the short-frame threshold?

>> Q1
skew calibration is required if sensor or deserializer is using DPHY, and the output data rate is > 1.5Gbps. else the camera firmware will continue to wait for deskew signal from the sensor side. it’ll enable pixel parser when deskew calibration has completed.

>> Q2
you don’t need to configure nvcsi clock in general, please refer to Sensor Pixel Clock to review your pixel clock rate settings.

>> Q3
chansel_short_frame usually due to you’ve insufficient data coming from sensor.

I am actually using a fpga to generate mipi test pattern frames. I tried to reduce the output data rate to 768mbps/lane (896x896 @3030303030303030 fps) (so skew calibration is not required), with this setup, I still get a single line instead of 896 lines with the correct nvcsi clock.
dmesg logs:
[ 1033.656928] tegra-camrtc-capture-vi tegra-capture-vi: corr_err: discarding frame 0, flags: 0, err_data 262144
[ 1033.689911] tegra-camrtc-capture-vi tegra-capture-vi: corr_err: discarding frame 0, flags: 0, err_data 262144
[ 1033.722821] tegra-camrtc-capture-vi tegra-capture-vi: corr_err: discarding frame 0, flags: 0, err_data 262144
[ 1033.755767] tegra-camrtc-capture-vi tegra-capture-vi: corr_err: discarding frame 0, flags: 0, err_data 262144
[ 1033.788785] tegra-camrtc-capture-vi tegra-capture-vi: corr_err: discarding frame 0, flags: 0, err_data 262144
[ 1033.821730] tegra-camrtc-capture-vi tegra-capture-vi: corr_err: discarding frame 0, flags: 0, err_data 262144
[ 1033.854620] tegra-camrtc-capture-vi tegra-capture-vi: corr_err: discarding frame 0, flags: 0, err_data 262144
[ 1033.874964] tegra-camrtc-capture-vi tegra-capture-vi: corr_err: discarding frame 0, flags: 0, err_data 262144

when i tried to push the max nvcsi clock, i get the first frame fully and it process it correctly, you can see the rtcpu logs below as a proof (so your claim that insufficient data from the sensor is false).
tag:CHANSEL_PXL_EOF channel:0x23 frame:0 vi_tstamp:940464752768 data:0x00000000037f0002
0x037f in the data payload is hex for 895 (0-895 so 896 lines properly received)

then while it tries to process the second frame, it gets a `CHANSEL_NOMATCH` error.

 kworker/2:1-48      [002] .......   916.682619: rtcpu_vinotify_event: tstamp:29388932626 cch:0 vi:0 tag:FS channel:0x01 frame:0 vi_tstamp:940444138432 data:0x0000000000000010
 kworker/2:1-48      [002] .......   916.682626: rtcpu_vinotify_event: tstamp:29388932889 cch:0 vi:0 tag:ATOMP_FS channel:0x00 frame:0 vi_tstamp:940444138528 data:0x0000000800000000
 kworker/2:1-48      [002] .......   916.682627: rtcpu_vinotify_event: tstamp:29388933179 cch:0 vi:0 tag:CHANSEL_PXL_SOF channel:0x23 frame:0 vi_tstamp:940444147936 data:0x0000000000000001
 kworker/2:1-48      [002] .......   916.682628: rtcpu_vinotify_event: tstamp:29388933436 cch:0 vi:0 tag:VIFALC_ACTIONLST channel:0x23 frame:0 vi_tstamp:940444179936 data:0x0000000008020001
 kworker/2:1-48      [002] .......   916.682629: rtcpu_vinotify_event: tstamp:29389535632 cch:0 vi:0 tag:CHANSEL_PXL_EOF channel:0x23 frame:0 vi_tstamp:940464752768 data:0x00000000037f0002
 kworker/2:1-48      [002] .......   916.682629: rtcpu_vinotify_event: tstamp:29389535892 cch:0 vi:0 tag:FE channel:0x01 frame:0 vi_tstamp:940464753696 data:0x0000000000000020
 kworker/2:1-48      [002] .......   916.682630: rtcpu_vinotify_event: tstamp:29389536181 cch:0 vi:0 tag:CHANSEL_SHORT_FRAME channel:0x41 frame:0 vi_tstamp:940464753728 data:0x0000200000000000
 kworker/2:1-48      [002] .......   916.682631: rtcpu_vinotify_event: tstamp:29389536434 cch:0 vi:0 tag:VIFALC_ACTIONLST channel:0x23 frame:0 vi_tstamp:940464830464 data:0x0000000001020001
 kworker/2:1-48      [002] .......   916.682634: rtcpu_vinotify_event: tstamp:29390017177 cch:0 vi:0 tag:ATOMP_FE channel:0x00 frame:0 vi_tstamp:940464753792 data:0x0000000800000000
 kworker/2:1-48      [002] .......   916.682635: rtcpu_vinotify_event: tstamp:29390017439 cch:0 vi:0 tag:ATOMP_FRAME_DONE channel:0x23 frame:0 vi_tstamp:940464754016 data:0x0000000000000000
 kworker/2:1-48      [002] .......   916.682635: rtcpu_vinotify_event: tstamp:29390017723 cch:0 vi:0 tag:FS channel:0x01 frame:0 vi_tstamp:940477091776 data:0x0000000000000010
 kworker/2:1-48      [002] .......   916.682636: rtcpu_vinotify_event: tstamp:29390017982 cch:0 vi:0 tag:ATOMP_FS channel:0x00 frame:0 vi_tstamp:940477091872 data:0x0000000800000000
 kworker/2:1-48      [002] .......   916.682637: rtcpu_vinotify_event: tstamp:29390018270 cch:0 vi:0 tag:CHANSEL_PXL_SOF channel:0x23 frame:0 vi_tstamp:940477101280 data:0x0000000000000001
      <idle>-0       [000] d..h1..   916.686083: host1x_syncpt_load_min: id=22, val=138114
 kworker/2:1-48      [002] .......   916.738868: rtcpu_vinotify_event: tstamp:29390561512 cch:0 vi:0 tag:CHANSEL_PXL_EOF channel:0x23 frame:0 vi_tstamp:940497706112 data:0x00000000037f0002
 kworker/2:1-48      [002] .......   916.738877: rtcpu_vinotify_event: tstamp:29390561801 cch:0 vi:0 tag:FE channel:0x01 frame:0 vi_tstamp:940497707008 data:0x0000000000000020
 kworker/2:1-48      [002] .......   916.738878: rtcpu_vinotify_event: tstamp:29390562059 cch:0 vi:0 tag:CHANSEL_SHORT_FRAME channel:0x41 frame:0 vi_tstamp:940497707040 data:0x0000200000000000
 kworker/2:1-48      [002] .......   916.738878: rtcpu_vinotify_event: tstamp:29390562348 cch:0 vi:0 tag:ATOMP_FE channel:0x00 frame:0 vi_tstamp:940497707136 data:0x0000000800000000
 kworker/2:1-48      [002] .......   916.738879: rtcpu_vinotify_event: tstamp:29390562602 cch:0 vi:0 tag:ATOMP_FRAME_DONE channel:0x23 frame:0 vi_tstamp:940497707328 data:0x0000000000000000
 kworker/2:1-48      [002] .......   916.738882: rtcpu_vinotify_error: tstamp:29390943716 cch:0 vi:0 tag:CHANSEL_NOMATCH channel:0x41 frame:0 vi_tstamp:940510054560 data:0x00000000000003c9
 kworker/2:1-48      [002] .......   916.738883: rtcpu_vinotify_event: tstamp:29391102333 cch:0 vi:0 tag:FS channel:0x01 frame:0 vi_tstamp:940510045088 data:0x0000000000000010
 kworker/2:1-48      [002] .......   916.738883: rtcpu_vinotify_event: tstamp:29391102588 cch:0 vi:0 tag:CHANSEL_NOMATCH channel:0x41 frame:0 vi_tstamp:940510054560 data:0x00000000000003c9
 kworker/2:1-48      [002] .......   916.738884: rtcpu_vinotify_event: tstamp:29391644509 cch:0 vi:0 tag:FE channel:0x01 frame:0 vi_tstamp:940530660352 data:0x0000000000000020
 kworker/2:1-48      [002] .......   916.738885: rtcpu_vinotify_error: tstamp:29391973496 cch:0 vi:0 tag:CHANSEL_NOMATCH channel:0x41 frame:0 vi_tstamp:940543007872 data:0x00000000000003c9
 kworker/2:1-48      [002] .......   916.794606: rtcpu_vinotify_event: tstamp:29392187665 cch:0 vi:0 tag:FS channel:0x01 frame:0 vi_tstamp:940542998400 data:0x0000000000000010
 kworker/2:1-48      [002] .......   916.794611: rtcpu_vinotify_event: tstamp:29392187955 cch:0 vi:0 tag:CHANSEL_NOMATCH channel:0x41 frame:0 vi_tstamp:940543007872 data:0x00000000000003c9
 kworker/2:1-48      [002] .......   916.794612: rtcpu_vinotify_event: tstamp:29392616404 cch:0 vi:0 tag:FE channel:0x01 frame:0 vi_tstamp:940563613664 data:0x0000000000000020
 kworker/2:1-48      [002] .......   916.794613: rtcpu_vinotify_error: tstamp:29393003290 cch:0 vi:0 tag:CHANSEL_NOMATCH channel:0x41 frame:0 vi_tstamp:940575961216 data:0x00000000000003c9
 kworker/2:1-48      [002] .......   916.794613: rtcpu_vinotify_event: tstamp:29393110311 cch:0 vi:0 tag:FS channel:0x01 frame:0 vi_tstamp:940575951744 data:0x0000000000000010
 kworker/2:1-48      [002] .......   916.794614: rtcpu_vinotify_event: tstamp:29393110569 cch:0 vi:0 tag:CHANSEL_NOMATCH channel:0x41 frame:0 vi_tstamp:940575961216 data:0x00000000000003c9

i need to know why it causes CHANSEL_NOMATCH error while receiving the 2nd frame. it would be very useful so that i can check with the FPGA team. as a suspicion , does it have anything to do with the frame and line blanking duration setup ?

Also for the first frame, even though it received full lines , why it still complains CHANSEL_SHORT_FRAME on channel:0x41 with 0 lines receivied immediately after tag:FE, cause on channel:0x41 both CHANSEL_SHORT_FRAME and CHANSEL_NOMATCH ? .
Is channel:0x41 an error channel ?

I will paste my dtb mode entry here

mode0 {
	mclk_khz = "24000";
	num_lanes = "2";
	tegra_sinterface = TEGRA_SINTERFACE;
	vc_id = "1";
	lane_polarity = "6";
	phy_mode = "DPHY";
	discontinuous_clk = "yes";
	dpcm_enable = "false";
	cil_settletime = "0";
	dynamic_pixel_bit_depth = "16";
	csi_pixel_bit_depth = "16";
	mode_type = "yuv";
	pixel_phase = "uyvy";

	active_w = "896";
	active_h = "896";
	readout_orientation = "0";
	line_length = "1152";
	inherent_gain = "1";
	mclk_multiplier = "3.67";
	pix_clk_hz = "88000000";
	serdes_pix_clk_hz = "88000000";

	deskew_initial_enable = "false";
	min_hdr_ratio = "1";
	max_hdr_ratio = "1";

	gain_factor = "10";
	min_gain_val = "2"; /* dB */
	max_gain_val = "300"; /* dB */
	step_gain_val = "3";
	default_gain = "2";

	framerate_factor = "1000000";
	min_framerate = "100000";
	max_framerate = "90000000";
	step_framerate = "1";
	default_framerate = "90000000";

	exposure_factor = "1000000";
	min_exp_time = "1";
	max_exp_time = "11";
	step_exp_time = "1";
	default_exp_time = "11";
};


fpga_dts.txt (6.1 KB)

hello embed.arunkumar,

it still looks like incorrect settings from sensor side.

this report means VI/RCE dropped that frame because it saw a new SOF while the capture channel still considered the previous frame active. this usually due to sensor/CSI timing problems,
such as.. missing or late FE, wrong active_h, embedded metadata line mismatch, VC/port mismatch, unstable MIPI signal, or incorrect pixel clock/line timing.

you may dig into VI driver, vi5_formats.h entries for YUV422/16 with UYVY8_1X16
please refer to Topic 307355, please configure as YUV422-8-bit, which it’s 16-bpp (bits per pixel) formats, this is supported according to the list formats in the v4l2 VI/CSI driver.

Hi @JerryChang , thanks for the pointers. I’ve got the stream running at 90 fps now.
My DTB was only set up for VC1, but the FPGA was also sending stray data on VC0. Since that wasn’t configured, the system treated it as VC1 and dropped the fps. After I updated the DTB to include both channels, the issue cleared up.

Really appreciate your help !.

working_dts.txt (27.8 KB)