Skip to content

media: rp1_cfe: Add LSB-aligned unpacked Bayer formats to the FE outputs - #7722

Open
bertouttier wants to merge 2 commits into
raspberrypi:rpi-6.18.yfrom
Spectricity:rp1-cfe-lsb-bayer-formats
Open

bertouttier wants to merge 2 commits into
raspberrypi:rpi-6.18.yfrom
Spectricity:rp1-cfe-lsb-bayer-formats

Conversation

@bertouttier

Copy link
Copy Markdown

The PiSP Front End can shift its 16-bit output right (PISP_FE_OUTPUT0_FORMAT.SHIFT, section 6.4.23 of the PiSP specification), which writes unpacked 10 and 12-bit samples aligned to the LSB. That is exactly the layout of the standard V4L2_PIX_FMT_S*10 and V4L2_PIX_FMT_S*12 formats.

The CFE FE output nodes don't offer these formats today, only the 16-bit (MSB-aligned) and the PiSP compressed ones. A userspace that wants LSB-aligned RAW (some RAW processing pipelines take 10/12-bit samples in 16-bit words as they are) has to keep the node at SBGGR16, program the shift into the FE config behind the format's back, and report a different format to the application. Or it shifts every frame on the CPU.

This series lets the FE output node carry the real format, the same way the compressed formats work today.

1. media: rp1_cfe: Factor out the remap lookup

No functional change. cfe_find_16bit_code() and cfe_find_compressed_code() do the same lookup with a different remap type. It is factored out into cfe_find_remap_fourcc() and cfe_find_remap_code(), so that a new remap type can use it.

2. media: rp1_cfe: Add LSB-aligned unpacked Bayer formats to the FE outputs

  • V4L2_PIX_FMT_S{BGGR,GBRG,GRBG,RGGB}{10,12} on the FE output nodes:
    • with the FE source pad's 16-bit media bus code and a stride of width * 2;
    • appended after the 16-bit entries, so that find_format_by_code() (first match) is unchanged.
  • A new CFE_REMAP_LSB16 remap of the 10/12-bit Bayer codes, next to CFE_REMAP_16BIT and CFE_REMAP_COMPRESSED. It names the LSB-aligned format the FE output can write for that code. The FE output shift of such a format is 16 - that code's bit depth (cfe_find_lsb16_shift()).
  • The new formats are kept off the CSI-2 nodes, whose REMAP unpacking is MSB-aligned. On those nodes, enum_fmt skips them and try_fmt falls back to the default.
  • cfe_video_link_validate() on an FE output node accepts them only if both hold:
    • they carry the FE source pad's code;
    • they are the CFE_REMAP_LSB16 remap of the code on the CSI-2 sink pad of the channel feeding the FE. So a 10-bit format can't silently drop bits of 12-bit data.
  • pisp_fe_validate_output() requires the FE config to match the node format: 16 bits per sample, uncompressed, SHIFT = 16 - bit depth.

Userspace that keeps using the 16-bit or compressed formats sees no change.

Testing

On a Raspberry Pi 5 (6.18.50+rpt-rpi-2712, module built out of tree with W=1: no warnings), with a 10-bit (RAW10) and a 12-bit (RAW12) CSI-2 Bayer sensor, through libcamera and with raw V4L2:

  • Formats:
    • fe_image0 lists BG10/BG12/GB10/GB12/BA10/BA12/RG10/RG12; csi2_ch0 doesn't.
    • VIDIOC_TRY_FMT BG10 on fe_image0 gives BG10 with bytesperline = width * 2.
    • On csi2_ch0 it falls back to the default.
  • RAW-only capture in BG10 (10-bit sensor) / BG12 (12-bit sensor): equal to the MSB-aligned 16-bit capture shifted down by 6 / 4, bit for bit (sensor test pattern).
  • RAW plus a Back End output. The BE input shifts back left (PISP_BE_INPUT_FORMAT.SHIFT), and the YUV output is bit-identical to the one from the 16-bit path.
  • Mismatched depth. BG10 behind the 12-bit sensor, and BG12 behind the 10-bit one, fail at STREAMON with -EINVAL, logging "Format ... doesn't match the CSI-2 input code ...".
  • Existing paths unchanged:
    • with patch 1 alone and with the whole series, captures through the existing 16-bit (BYR2) and compressed (PC1B) formats are bit-identical to the stock module, for RAW-only, RAW+ISP and ISP-only;
    • each patch builds on its own.

The matching libcamera change (PiSP pipeline handler: derive the FE output / BE input shift from the unpacked Bayer format in toPiSPImageFormat(), and use the format as the CFE device format when the CFE offers it) will follow as a separate PR to raspberrypi/libcamera. Without this kernel change it falls back to the 16-bit format as today.

Notes for review

  • cfe_video_link_validate() now takes the csi2 subdev's state lock (in cfe_fe_input_code()) while the FE subdev's state is held. The two subdevs come from separate v4l2_subdev_init_finalize() call sites, so they have separate lock classes, and nothing takes them in the opposite order. This was not checked with lockdep: the test kernel has CONFIG_PROVE_LOCKING off.
  • Only the downstream rp1_cfe driver is changed, not rp1-cfe.
  • Mono (Y10/Y12) isn't included. Its entries would need care around the Y16_1X16 first-match lookup.

Bert Outtier added 2 commits October 27, 2026 13:18
cfe_find_16bit_code() and cfe_find_compressed_code() do the same lookup
with a different remap type. Factor it out into cfe_find_remap_fourcc(),
which gives the remapped pixel format of a given type, and
cfe_find_remap_code(), which gives that format's code, so that other
remap types can use it.

No functional change.

Signed-off-by: Bert Outtier <bert.outtier@spectricity.com>
The PiSP Front End can shift its 16-bit output right
(PISP_FE_OUTPUT0_FORMAT.SHIFT), which writes unpacked 10 and 12-bit
samples aligned to the LSB: the layout of the standard V4L2_PIX_FMT_S*10
and V4L2_PIX_FMT_S*12 formats. Today the FE output nodes only offer the
16-bit and compressed formats, so userspace has to report SBGGR16 for
such a stream and carry the shift on the side.

Offer V4L2_PIX_FMT_S{BGGR,GBRG,GRBG,RGGB}{10,12} on the FE output nodes,
with the FE source pad's 16-bit media bus code and a stride of width * 2:

- a new CFE_REMAP_LSB16 remap of the 10 and 12-bit Bayer codes, next to
  the 16-bit and compressed ones, names the LSB-aligned format the FE
  output can write for that code; the FE output shift of such a format
  is 16 - the bit depth of that code (cfe_find_lsb16_shift());
- the new formats are kept off the CSI-2 nodes, whose REMAP unpacking
  is MSB-aligned;
- link validation on the FE output nodes accepts them for the 16-bit
  code of the FE source pad, and only if the format is the
  CFE_REMAP_LSB16 remap of the code on the CSI-2 sink pad of the channel
  that feeds the FE, so that a 10-bit format can't drop bits of 12-bit
  data;
- pisp_fe_validate_output() requires the FE config to match the node
  format: 16 bits per sample, uncompressed, shifted right by
  16 - bit depth.

The existing formats and lookups are unchanged: the new entries come
after the 16-bit ones, as find_format_by_code() returns the first match.

Tested on a Raspberry Pi 5 with a 10-bit and a 12-bit sensor through
libcamera: the LSB-aligned RAW stream equals the MSB-aligned one shifted
down, the Back End output from it is bit-identical, and a format of the
wrong bit depth fails to start streaming.

Signed-off-by: Bert Outtier <bert.outtier@spectricity.com>
@naushir

naushir commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

Please see my comment at raspberrypi/libcamera#365 (comment). I'm concerned about adding extra complexity with this change if it may not be needed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants