media: imx477: Compute line_length_pix based on link frequency

As we now support variable link frequency, compute the minimum
line_length value that the sensor will work with, and set
V4L2_CID_HBLANK based on that number.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
This commit is contained in:
Dave Stevenson
2025-09-18 19:28:48 +01:00
committed by Dom Cobley
parent 7a555e96ea
commit bc384b07d5

View File

@@ -170,9 +170,6 @@ struct imx477_mode {
/* Frame height */
unsigned int height;
/* H-timing in pixels */
unsigned int line_length_pix;
/* Analog crop rectangle. */
struct v4l2_rect crop;
@@ -873,7 +870,6 @@ static const struct imx477_mode supported_modes_12bit[] = {
/* 12MPix 10fps mode */
.width = 4056,
.height = 3040,
.line_length_pix = 24000,
.crop = {
.left = IMX477_PIXEL_ARRAY_LEFT,
.top = IMX477_PIXEL_ARRAY_TOP,
@@ -890,7 +886,6 @@ static const struct imx477_mode supported_modes_12bit[] = {
/* 12MPix cropped 16:9 mode */
.width = 4056,
.height = 2160,
.line_length_pix = 24000,
.crop = {
.left = IMX477_PIXEL_ARRAY_LEFT,
.top = IMX477_PIXEL_ARRAY_TOP + 440,
@@ -907,7 +902,6 @@ static const struct imx477_mode supported_modes_12bit[] = {
/* 2x2 binned 40fps mode */
.width = 2028,
.height = 1520,
.line_length_pix = 12740,
.crop = {
.left = IMX477_PIXEL_ARRAY_LEFT,
.top = IMX477_PIXEL_ARRAY_TOP,
@@ -924,7 +918,6 @@ static const struct imx477_mode supported_modes_12bit[] = {
/* 1080p 50fps cropped mode */
.width = 2028,
.height = 1080,
.line_length_pix = 12740,
.crop = {
.left = IMX477_PIXEL_ARRAY_LEFT,
.top = IMX477_PIXEL_ARRAY_TOP + 440,
@@ -944,7 +937,6 @@ static const struct imx477_mode supported_modes_10bit[] = {
/* 120fps. 2x2 binned and cropped */
.width = 1332,
.height = 990,
.line_length_pix = 6664,
.crop = {
/*
* FIXME: the analog crop rectangle is actually
@@ -1141,6 +1133,24 @@ static void imx477_set_default_format(struct imx477 *imx477)
imx477->fmt_code = MEDIA_BUS_FMT_SRGGB12_1X12;
}
static int imx477_get_bpp(unsigned int code)
{
switch (code) {
default:
case MEDIA_BUS_FMT_SRGGB12_1X12:
case MEDIA_BUS_FMT_SGRBG12_1X12:
case MEDIA_BUS_FMT_SGBRG12_1X12:
case MEDIA_BUS_FMT_SBGGR12_1X12:
return 12;
case MEDIA_BUS_FMT_SRGGB10_1X10:
case MEDIA_BUS_FMT_SGRBG10_1X10:
case MEDIA_BUS_FMT_SGBRG10_1X10:
case MEDIA_BUS_FMT_SBGGR10_1X10:
return 10;
}
}
static int imx477_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct imx477 *imx477 = to_imx477(sd);
@@ -1428,6 +1438,8 @@ static int imx477_get_pad_format(struct v4l2_subdev *sd,
static void imx477_set_framing_limits(struct imx477 *imx477)
{
unsigned int hblank_min;
u64 line_length_min;
int bpp;
const struct imx477_mode *mode = imx477->mode;
/* Default to no long exposure multiplier. */
@@ -1444,7 +1456,14 @@ static void imx477_set_framing_limits(struct imx477 *imx477)
__v4l2_ctrl_s_ctrl(imx477->vblank,
mode->frm_length_default - mode->height);
hblank_min = mode->line_length_pix - mode->width;
bpp = imx477_get_bpp(imx477->fmt_code);
line_length_min = mode->width * bpp * (u64)IMX477_PIXEL_RATE;
do_div(line_length_min, imx477->link_freq_value * 2 * 2 /*LANES*/);
/* Allow 500pixel clocks for HS<>LP transitions (approx 0.6usecs) */
line_length_min += 500;
hblank_min = line_length_min - mode->width;
__v4l2_ctrl_modify_range(imx477->hblank, hblank_min,
IMX477_LINE_LENGTH_MAX, 1, hblank_min);
__v4l2_ctrl_s_ctrl(imx477->hblank, hblank_min);