Skip to content

Commit 576c474

Browse files
committed
media: i2c: imx477: Add support for 10 or 12 bit readout to all modes
FIXME: Dropping the default frame rate needs to be separated out. Switching between 10 and 12 bit mode only requires a couple of registers to change, and an associated change to the minimum HBLANK that can be supported in the mode based on how long it takes the CSI2 block to send each line of the image. Add suitable switching between the 2 for all modes.
1 parent 66fa175 commit 576c474

File tree

1 file changed

+65
-95
lines changed

1 file changed

+65
-95
lines changed

drivers/media/i2c/imx477.c

Lines changed: 65 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ MODULE_PARM_DESC(trigger_mode, "Set vsync trigger mode: 1=source, 2=sink");
4343

4444
#define IMX477_REG_ORIENTATION 0x101
4545

46+
#define IMX477_REG_CSI_DT_FMT_H 0x0112
47+
#define IMX477_REG_CSI_DT_FMT_L 0x0113
48+
4649
#define IMX477_XCLK_FREQ 24000000
4750

4851
#define IMX477_DEFAULT_LINK_FREQ 450000000
@@ -86,6 +89,7 @@ MODULE_PARM_DESC(trigger_mode, "Set vsync trigger mode: 1=source, 2=sink");
8689
#define IMX477_DGTL_GAIN_DEFAULT 0x0100
8790
#define IMX477_DGTL_GAIN_STEP 1
8891

92+
#define IMX477_REG_IOP_PXCK_DIV 0x0309
8993
#define IMX477_REG_DIV_IOP_PX 0x030b
9094

9195
/* Test Pattern Control */
@@ -156,8 +160,11 @@ struct imx477_mode {
156160
/* Frame height */
157161
unsigned int height;
158162

159-
/* H-timing in pixels when at 450MHz link freq */
160-
unsigned int line_length_pix;
163+
/*
164+
* H-timing in pixels when at 450MHz link freq
165+
* Index 0 is for 12bpp. Index 1 is for 10bpp.
166+
*/
167+
unsigned int line_length_pix[2];
161168

162169
/* Analog crop rectangle. */
163170
struct v4l2_rect crop;
@@ -605,8 +612,6 @@ static const struct imx477_reg mode_common_regs[] = {
605612

606613
/* 12 mpix 10fps */
607614
static const struct imx477_reg mode_4056x3040_regs[] = {
608-
{0x0112, 0x0c},
609-
{0x0113, 0x0c},
610615
{0x0344, 0x00},
611616
{0x0345, 0x00},
612617
{0x0346, 0x00},
@@ -661,7 +666,6 @@ static const struct imx477_reg mode_4056x3040_regs[] = {
661666
{0x0305, 0x04},
662667
{0x0306, 0x01},
663668
{0x0307, 0x5e},
664-
{0x0309, 0x0c},
665669
{0xe04c, 0x00},
666670
{0xe04d, 0x7f},
667671
{0xe04e, 0x00},
@@ -736,8 +740,6 @@ static const struct imx477_reg mode_4056x2160_regs[] = {
736740

737741
/* 2x2 binned. 40fps */
738742
static const struct imx477_reg mode_2028x1520_regs[] = {
739-
{0x0112, 0x0c},
740-
{0x0113, 0x0c},
741743
{0x0344, 0x00},
742744
{0x0345, 0x00},
743745
{0x0346, 0x00},
@@ -781,7 +783,6 @@ static const struct imx477_reg mode_2028x1520_regs[] = {
781783
{0x0305, 0x04},
782784
{0x0306, 0x01},
783785
{0x0307, 0x5e},
784-
{0x0309, 0x0c},
785786
{0xe04c, 0x00},
786787
{0xe04d, 0x7f},
787788
{0xe04e, 0x00},
@@ -792,8 +793,6 @@ static const struct imx477_reg mode_2028x1520_regs[] = {
792793

793794
/* 1080p cropped mode */
794795
static const struct imx477_reg mode_2028x1080_regs[] = {
795-
{0x0112, 0x0c},
796-
{0x0113, 0x0c},
797796
{0x0344, 0x00},
798797
{0x0345, 0x00},
799798
{0x0346, 0x01},
@@ -837,7 +836,6 @@ static const struct imx477_reg mode_2028x1080_regs[] = {
837836
{0x0305, 0x04},
838837
{0x0306, 0x01},
839838
{0x0307, 0x5e},
840-
{0x0309, 0x0c},
841839
{0xe04c, 0x00},
842840
{0xe04d, 0x7f},
843841
{0xe04e, 0x00},
@@ -848,8 +846,6 @@ static const struct imx477_reg mode_2028x1080_regs[] = {
848846

849847
/* 4x4 binned. 120fps */
850848
static const struct imx477_reg mode_1332x990_regs[] = {
851-
{0x0112, 0x0a},
852-
{0x0113, 0x0a},
853849
{0x420b, 0x01},
854850
{0x990c, 0x00},
855851
{0x990d, 0x08},
@@ -917,7 +913,6 @@ static const struct imx477_reg mode_1332x990_regs[] = {
917913
{0x0305, 0x02},
918914
{0x0306, 0x00},
919915
{0x0307, 0xaf},
920-
{0x0309, 0x0a},
921916
{0xe04c, 0x00},
922917
{0xe04d, 0x5f},
923918
{0xe04e, 0x00},
@@ -927,12 +922,12 @@ static const struct imx477_reg mode_1332x990_regs[] = {
927922
};
928923

929924
/* Mode configs */
930-
static const struct imx477_mode supported_modes_12bit[] = {
925+
static const struct imx477_mode supported_modes[] = {
931926
{
932927
/* 12MPix 10fps mode */
933928
.width = 4056,
934929
.height = 3040,
935-
.line_length_pix = 24000,
930+
.line_length_pix = { 24000, 20000 },
936931
.crop = {
937932
.left = IMX477_PIXEL_ARRAY_LEFT,
938933
.top = IMX477_PIXEL_ARRAY_TOP,
@@ -966,7 +961,7 @@ static const struct imx477_mode supported_modes_12bit[] = {
966961
/* 2x2 binned 40fps mode */
967962
.width = 2028,
968963
.height = 1520,
969-
.line_length_pix = 12740,
964+
.line_length_pix = { 12740, 10616 },
970965
.crop = {
971966
.left = IMX477_PIXEL_ARRAY_LEFT,
972967
.top = IMX477_PIXEL_ARRAY_TOP,
@@ -983,7 +978,7 @@ static const struct imx477_mode supported_modes_12bit[] = {
983978
/* 1080p 50fps cropped mode */
984979
.width = 2028,
985980
.height = 1080,
986-
.line_length_pix = 12740,
981+
.line_length_pix = { 12740, 10616 },
987982
.crop = {
988983
.left = IMX477_PIXEL_ARRAY_LEFT,
989984
.top = IMX477_PIXEL_ARRAY_TOP + 440,
@@ -995,15 +990,12 @@ static const struct imx477_mode supported_modes_12bit[] = {
995990
.num_of_regs = ARRAY_SIZE(mode_2028x1080_regs),
996991
.regs = mode_2028x1080_regs,
997992
},
998-
}
999-
};
1000-
1001-
static const struct imx477_mode supported_modes_10bit[] = {
993+
},
1002994
{
1003995
/* 120fps. 2x2 binned and cropped */
1004996
.width = 1332,
1005997
.height = 990,
1006-
.line_length_pix = 6664,
998+
.line_length_pix = { 7997, 6664 },
1007999
.crop = {
10081000
/*
10091001
* FIXME: the analog crop rectangle is actually
@@ -1155,33 +1147,6 @@ static inline struct imx477 *to_imx477(struct v4l2_subdev *_sd)
11551147
return container_of(_sd, struct imx477, sd);
11561148
}
11571149

1158-
static inline void get_mode_table(unsigned int code,
1159-
const struct imx477_mode **mode_list,
1160-
unsigned int *num_modes)
1161-
{
1162-
switch (code) {
1163-
/* 12-bit */
1164-
case MEDIA_BUS_FMT_SRGGB12_1X12:
1165-
case MEDIA_BUS_FMT_SGRBG12_1X12:
1166-
case MEDIA_BUS_FMT_SGBRG12_1X12:
1167-
case MEDIA_BUS_FMT_SBGGR12_1X12:
1168-
*mode_list = supported_modes_12bit;
1169-
*num_modes = ARRAY_SIZE(supported_modes_12bit);
1170-
break;
1171-
/* 10-bit */
1172-
case MEDIA_BUS_FMT_SRGGB10_1X10:
1173-
case MEDIA_BUS_FMT_SGRBG10_1X10:
1174-
case MEDIA_BUS_FMT_SGBRG10_1X10:
1175-
case MEDIA_BUS_FMT_SBGGR10_1X10:
1176-
*mode_list = supported_modes_10bit;
1177-
*num_modes = ARRAY_SIZE(supported_modes_10bit);
1178-
break;
1179-
default:
1180-
*mode_list = NULL;
1181-
*num_modes = 0;
1182-
}
1183-
}
1184-
11851150
/* Read registers up to 2 at a time */
11861151
static int imx477_read_reg(struct imx477 *imx477, u16 reg, u32 len, u32 *val)
11871152
{
@@ -1277,7 +1242,7 @@ static u32 imx477_get_format_code(struct imx477 *imx477, u32 code)
12771242
static void imx477_set_default_format(struct imx477 *imx477)
12781243
{
12791244
/* Set default mode to max resolution */
1280-
imx477->mode = &supported_modes_12bit[0];
1245+
imx477->mode = &supported_modes[0];
12811246
imx477->fmt_code = MEDIA_BUS_FMT_SRGGB12_1X12;
12821247
}
12831248

@@ -1293,8 +1258,8 @@ static int imx477_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
12931258
mutex_lock(&imx477->mutex);
12941259

12951260
/* Initialize try_fmt for the image pad */
1296-
try_fmt_img->width = supported_modes_12bit[0].width;
1297-
try_fmt_img->height = supported_modes_12bit[0].height;
1261+
try_fmt_img->width = supported_modes[0].width;
1262+
try_fmt_img->height = supported_modes[0].height;
12981263
try_fmt_img->code = imx477_get_format_code(imx477,
12991264
MEDIA_BUS_FMT_SRGGB12_1X12);
13001265
try_fmt_img->field = V4L2_FIELD_NONE;
@@ -1475,12 +1440,7 @@ static int imx477_enum_frame_size(struct v4l2_subdev *sd,
14751440
return -EINVAL;
14761441

14771442
if (fse->pad == IMAGE_PAD) {
1478-
const struct imx477_mode *mode_list;
1479-
unsigned int num_modes;
1480-
1481-
get_mode_table(fse->code, &mode_list, &num_modes);
1482-
1483-
if (fse->index >= num_modes)
1443+
if (fse->index >= ARRAY_SIZE(supported_modes))
14841444
return -EINVAL;
14851445

14861446
mutex_lock(&imx477->mutex);
@@ -1490,9 +1450,9 @@ static int imx477_enum_frame_size(struct v4l2_subdev *sd,
14901450
if (fse->code != code)
14911451
return -EINVAL;
14921452

1493-
fse->min_width = mode_list[fse->index].width;
1453+
fse->min_width = supported_modes[fse->index].width;
14941454
fse->max_width = fse->min_width;
1495-
fse->min_height = mode_list[fse->index].height;
1455+
fse->min_height = supported_modes[fse->index].height;
14961456
fse->max_height = fse->min_height;
14971457
} else {
14981458
if (fse->code != MEDIA_BUS_FMT_SENSOR_DATA || fse->index > 0)
@@ -1570,44 +1530,36 @@ static int imx477_get_pad_format(struct v4l2_subdev *sd,
15701530
return 0;
15711531
}
15721532

1573-
static
1574-
unsigned int imx477_get_frame_length(const struct imx477_mode *mode,
1575-
unsigned int framerate_default)
1576-
{
1577-
u64 frame_length;
1578-
1579-
frame_length = IMX477_PIXEL_RATE;
1580-
do_div(frame_length,
1581-
(u64)framerate_default * mode->line_length_pix);
1582-
1583-
if (WARN_ON(frame_length > IMX477_FRAME_LENGTH_MAX))
1584-
frame_length = IMX477_FRAME_LENGTH_MAX;
1585-
1586-
return max_t(unsigned int, frame_length, mode->height);
1587-
}
1588-
15891533
static void imx477_set_framing_limits(struct imx477 *imx477)
15901534
{
1591-
unsigned int frm_length_default, hblank_min;
1535+
unsigned int hblank_min;
15921536
const struct imx477_mode *mode = imx477->mode;
15931537
unsigned int line_length_pix;
15941538

1595-
frm_length_default =
1596-
imx477_get_frame_length(mode, mode->framerate_default);
1597-
15981539
/* Default to no long exposure multiplier. */
15991540
imx477->long_exp_shift = 0;
16001541

16011542
/* Update limits and set FPS to default */
16021543
__v4l2_ctrl_modify_range(imx477->vblank, 1,
16031544
((1 << IMX477_LONG_EXP_SHIFT_MAX) *
16041545
IMX477_FRAME_LENGTH_MAX) - mode->height,
1605-
IMX477_VBLANK_MIN, frm_length_default - mode->height);
1606-
1607-
/* Setting this will adjust the exposure limits as well. */
1608-
__v4l2_ctrl_s_ctrl(imx477->vblank, frm_length_default - mode->height);
1546+
IMX477_VBLANK_MIN, IMX477_VBLANK_MIN);
16091547

1610-
line_length_pix = mode->line_length_pix;
1548+
switch (imx477->fmt_code) {
1549+
case MEDIA_BUS_FMT_SRGGB12_1X12:
1550+
case MEDIA_BUS_FMT_SGRBG12_1X12:
1551+
case MEDIA_BUS_FMT_SGBRG12_1X12:
1552+
case MEDIA_BUS_FMT_SBGGR12_1X12:
1553+
line_length_pix = mode->line_length_pix[0];
1554+
break;
1555+
/* 10-bit */
1556+
case MEDIA_BUS_FMT_SRGGB10_1X10:
1557+
case MEDIA_BUS_FMT_SGRBG10_1X10:
1558+
case MEDIA_BUS_FMT_SGBRG10_1X10:
1559+
case MEDIA_BUS_FMT_SBGGR10_1X10:
1560+
line_length_pix = mode->line_length_pix[1];
1561+
break;
1562+
}
16111563
if (imx477->double_link_freq)
16121564
line_length_pix /= 2;
16131565
hblank_min = line_length_pix - mode->width;
@@ -1630,17 +1582,12 @@ static int imx477_set_pad_format(struct v4l2_subdev *sd,
16301582
mutex_lock(&imx477->mutex);
16311583

16321584
if (fmt->pad == IMAGE_PAD) {
1633-
const struct imx477_mode *mode_list;
1634-
unsigned int num_modes;
1635-
16361585
/* Bayer order varies with flips */
16371586
fmt->format.code = imx477_get_format_code(imx477,
16381587
fmt->format.code);
16391588

1640-
get_mode_table(fmt->format.code, &mode_list, &num_modes);
1641-
1642-
mode = v4l2_find_nearest_size(mode_list,
1643-
num_modes,
1589+
mode = v4l2_find_nearest_size(supported_modes,
1590+
ARRAY_SIZE(supported_modes),
16441591
width, height,
16451592
fmt->format.width,
16461593
fmt->format.height);
@@ -1649,7 +1596,8 @@ static int imx477_set_pad_format(struct v4l2_subdev *sd,
16491596
framefmt = v4l2_subdev_state_get_format(sd_state,
16501597
fmt->pad);
16511598
*framefmt = fmt->format;
1652-
} else if (imx477->mode != mode) {
1599+
} else if (imx477->mode != mode ||
1600+
fmt->format.code != imx477->fmt_code) {
16531601
imx477->mode = mode;
16541602
imx477->fmt_code = fmt->format.code;
16551603
imx477_set_framing_limits(imx477);
@@ -1728,7 +1676,7 @@ static int imx477_start_streaming(struct imx477 *imx477)
17281676
struct i2c_client *client = v4l2_get_subdevdata(&imx477->sd);
17291677
const struct imx477_reg_list *reg_list, *freq_regs;
17301678
const struct imx477_reg_list *extra_regs;
1731-
int ret, tm;
1679+
int ret, tm, val;
17321680

17331681
if (!imx477->common_regs_written) {
17341682
ret = imx477_write_regs(imx477, mode_common_regs,
@@ -1772,6 +1720,28 @@ static int imx477_start_streaming(struct imx477 *imx477)
17721720
return ret;
17731721
}
17741722

1723+
switch (imx477->fmt_code) {
1724+
case MEDIA_BUS_FMT_SRGGB12_1X12:
1725+
case MEDIA_BUS_FMT_SGRBG12_1X12:
1726+
case MEDIA_BUS_FMT_SGBRG12_1X12:
1727+
case MEDIA_BUS_FMT_SBGGR12_1X12:
1728+
val = 0x0c;
1729+
break;
1730+
/* 10-bit */
1731+
case MEDIA_BUS_FMT_SRGGB10_1X10:
1732+
case MEDIA_BUS_FMT_SGRBG10_1X10:
1733+
case MEDIA_BUS_FMT_SGBRG10_1X10:
1734+
case MEDIA_BUS_FMT_SBGGR10_1X10:
1735+
val = 0x0a;
1736+
break;
1737+
}
1738+
imx477_write_reg(imx477, IMX477_REG_CSI_DT_FMT_H,
1739+
IMX477_REG_VALUE_08BIT, val);
1740+
imx477_write_reg(imx477, IMX477_REG_CSI_DT_FMT_L,
1741+
IMX477_REG_VALUE_08BIT, val);
1742+
imx477_write_reg(imx477, IMX477_REG_IOP_PXCK_DIV,
1743+
IMX477_REG_VALUE_08BIT, val);
1744+
17751745
/* Set on-sensor DPC. */
17761746
imx477_write_reg(imx477, 0x0b05, IMX477_REG_VALUE_08BIT, !!dpc_enable);
17771747
imx477_write_reg(imx477, 0x0b06, IMX477_REG_VALUE_08BIT, !!dpc_enable);

0 commit comments

Comments
 (0)