[PATCH 7/8] media: atomisp: allow opt-in raw Bayer capture

From: Maurizio Casciano

Date: Wed Aug 26 2026 - 09:26:52 EST


AtomISP currently rejects all raw formats and silently substitutes
YUV420. This prevents userspace camera processing stacks from obtaining
unprocessed sensor frames.

Add an allow_raw_output module parameter, disabled by default. When it is
enabled, enumerate only the raw format matching the sensor media-bus code
and reconcile raw format requests with the code selected by the sensor.

Also apply the per-sensor padding discovered by the CSI-2 bridge when
enumerating and negotiating frame sizes. Existing systems retain the
global padding and raw-output defaults.

Tested on a Lenovo Yoga Book YB1-X91L with raw capture from its OV2740
and OV8858 sensors.

Signed-off-by: Maurizio Casciano <mauriziocasciano7@xxxxxxxxx>
Assisted-by: Codex:gpt-5.6-sol sparse
---
.../staging/media/atomisp/pci/atomisp_cmd.c | 24 ++++++++++++++-----
.../media/atomisp/pci/atomisp_internal.h | 6 +++++
.../staging/media/atomisp/pci/atomisp_ioctl.c | 13 ++++++----
.../staging/media/atomisp/pci/atomisp_v4l2.c | 15 ++++++++++++
4 files changed, 48 insertions(+), 10 deletions(-)

diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c
index 6cd500d9fd26..9e6387b662bc 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c
@@ -3572,10 +3572,14 @@ void atomisp_get_padding(struct atomisp_device *isp, u32 width, u32 height,
u32 min_pad_w = ISP2400_MIN_PAD_W;
u32 min_pad_h = ISP2400_MIN_PAD_H;
struct v4l2_mbus_framefmt *sink;
+ u32 input_padding_w = input->padding_override ?
+ input->padding_w : pad_w;
+ u32 input_padding_h = input->padding_override ?
+ input->padding_h : pad_h;

if (!input->crop_support) {
- *padding_w = pad_w;
- *padding_h = pad_h;
+ *padding_w = input_padding_w;
+ *padding_h = input_padding_h;
return;
}

@@ -3588,8 +3592,10 @@ void atomisp_get_padding(struct atomisp_device *isp, u32 width, u32 height,
native_rect.height /= 2;
}

- *padding_w = min_t(u32, (native_rect.width - width) & ~1, pad_w);
- *padding_h = min_t(u32, (native_rect.height - height) & ~1, pad_h);
+ *padding_w = min_t(u32, (native_rect.width - width) & ~1,
+ input_padding_w);
+ *padding_h = min_t(u32, (native_rect.height - height) & ~1,
+ input_padding_h);

/* The below minimum padding requirements are for BYT / ISP2400 only */
if (IS_ISP2401)
@@ -3804,8 +3810,9 @@ int atomisp_try_fmt(struct atomisp_device *isp, struct v4l2_pix_format *f,
int ret;

fmt = atomisp_get_format_bridge(f->pixelformat);
- /* Currently, raw formats are broken!!! */
- if (!fmt || fmt->sh_fmt == IA_CSS_FRAME_FORMAT_RAW) {
+ /* Raw output remains opt-in while the legacy CSS path is validated. */
+ if (!fmt || (fmt->sh_fmt == IA_CSS_FRAME_FORMAT_RAW &&
+ !atomisp_allow_raw_output)) {
f->pixelformat = V4L2_PIX_FMT_YUV420;

fmt = atomisp_get_format_bridge(f->pixelformat);
@@ -3846,6 +3853,11 @@ int atomisp_try_fmt(struct atomisp_device *isp, struct v4l2_pix_format *f,
ffmt.code);
return -EINVAL;
}
+ if (fmt->sh_fmt == IA_CSS_FRAME_FORMAT_RAW &&
+ fmt->mbus_code != snr_fmt->mbus_code) {
+ fmt = snr_fmt;
+ f->pixelformat = fmt->pixelformat;
+ }

f->width = ffmt.width - padding_w;
f->height = ffmt.height - padding_h;
diff --git a/drivers/staging/media/atomisp/pci/atomisp_internal.h b/drivers/staging/media/atomisp/pci/atomisp_internal.h
index 5a69580b8251..99a55297033e 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_internal.h
+++ b/drivers/staging/media/atomisp/pci/atomisp_internal.h
@@ -98,6 +98,9 @@
#define ATOMISP_CSS_SUPPORT_YUVPP 1

#define ATOMISP_CSS_OUTPUT_SECOND_INDEX 1
+
+extern bool atomisp_allow_raw_output;
+
#define ATOMISP_CSS_OUTPUT_DEFAULT_INDEX 0

/* ISP2401 */
@@ -116,6 +119,9 @@
struct atomisp_input_subdev {
enum atomisp_camera_port port;
u32 code; /* MEDIA_BUS_FMT_* */
+ u32 padding_w;
+ u32 padding_h;
+ bool padding_override;
bool binning_support;
bool crop_support;
bool sensor_on;
diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
index 50366bf10f32..e63b3e99e5fd 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
@@ -554,8 +554,10 @@ static int atomisp_enum_framesizes(struct file *file, void *priv,
return ret;

fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
- fsize->discrete.width = fse.max_width - pad_w;
- fsize->discrete.height = fse.max_height - pad_h;
+ fsize->discrete.width = fse.max_width -
+ (input->padding_override ? input->padding_w : pad_w);
+ fsize->discrete.height = fse.max_height -
+ (input->padding_override ? input->padding_h : pad_h);

return 0;
}
@@ -629,8 +631,11 @@ static int atomisp_enum_fmt_cap(struct file *file, void *fh,
*
* FIXME: fix the pipeline to allow sensor format too.
*/
- if (format->sh_fmt == IA_CSS_FRAME_FORMAT_RAW)
- continue;
+ if (format->sh_fmt == IA_CSS_FRAME_FORMAT_RAW) {
+ if (!atomisp_allow_raw_output ||
+ format->mbus_code != code.code)
+ continue;
+ }

/* Found a match. Now let's pick f->index'th one. */
if (fi < f->index) {
diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c
index 812230397409..d30f69f5a794 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c
@@ -25,6 +25,7 @@

#include "atomisp_cmd.h"
#include "atomisp_common.h"
+#include "atomisp_csi2.h"
#include "atomisp_fops.h"
#include "atomisp_ioctl.h"
#include "atomisp_internal.h"
@@ -72,6 +73,11 @@ int pad_h = 16;
module_param(pad_h, int, 0644);
MODULE_PARM_DESC(pad_h, "extra data for ISP processing");

+bool atomisp_allow_raw_output;
+module_param_named(allow_raw_output, atomisp_allow_raw_output, bool, 0644);
+MODULE_PARM_DESC(allow_raw_output,
+ "allow experimental raw Bayer output (default:false)");
+
/*
* FIXME: this is a hack to make easier to support ISP2401 variant.
* As a given system will either be ISP2401 or not, we can just use
@@ -889,6 +895,15 @@ static void atomisp_init_sensor(struct atomisp_input_subdev *input)
struct v4l2_subdev_state *try_sd_state, *act_sd_state;
int i, err;

+ input->padding_override =
+ atomisp_csi2_get_sensor_padding(input->sensor->dev,
+ &input->padding_w,
+ &input->padding_h);
+ if (input->padding_override)
+ dev_info(input->sensor->dev,
+ "using ISP input padding %ux%u\n",
+ input->padding_w, input->padding_h);
+
/*
* FIXME: Drivers are not supposed to use __v4l2_subdev_state_alloc()
* but atomisp needs this for try_fmt on its /dev/video# node since
--
2.53.0