Re: [PATCH v2 13/13] media: imx274: add SELECTION support for cropping

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Luca,

On Tue, Apr 24, 2018 at 04:30:38PM +0200, Luca Ceresoli wrote:
> Hi Sakari,
> 
> On 24/04/2018 11:59, Sakari Ailus wrote:
> > Hi Luca,
> > 
> > Thank you for the patchset.
> > 
> > Some comments below... what I propose is that I apply the rest of the
> > patches and then the comments to this one could be addressed separately.
> > Would that work for you?
> 
> Yes, but I suggest you only apply patches 1-6. I noticed a warning in
> patch 9, and patches 7-8 are not very useful without it. Will fix it in v3.

Ack. I'll apply 1--6 then.

> 
> I'll wait for the outcome of the discussion below before sending v3.
> Tell me if you prefer me to do it earlier.
> 
> > On Tue, Apr 24, 2018 at 10:24:18AM +0200, Luca Ceresoli wrote:
> >> Currently this driver does not support cropping. The supported modes
> >> are the following, all capturing the entire area:
> >>
> >>  - 3840x2160, 1:1 binning (native sensor resolution)
> >>  - 1920x1080, 2:1 binning
> >>  - 1280x720,  3:1 binning
> >>
> >> The set_fmt callback chooses among these 3 configurations the one that
> >> matches the requested format.
> >>
> >> Adding support to VIDIOC_SUBDEV_G_SELECTION and
> >> VIDIOC_SUBDEV_S_SELECTION involved a complete rewrite of set_fmt,
> >> which now chooses the most appropriate binning based on the ratio
> >> between the previously-set cropping size and the format size being
> >> requested.
> >>
> >> Note that the names in enum imx274_mode change from being
> >> resolution-based to being binning-based. Without cropping, the two
> >> naming are equivalent. With cropping, the resolution could be
> >> different, e.g. using 2:1 binning mode to crop 1200x960 and output a
> >> 600x480 format. Using binning in the names avoids anny
> >> misunderstanding.
> >>
> >> Signed-off-by: Luca Ceresoli <luca@xxxxxxxxxxxxxxxx>
> >>
> >> ---
> >> Changed v1 -> v2:
> >>  - add "media: " prefix to commit message
> >> ---
> >>  drivers/media/i2c/imx274.c | 266 ++++++++++++++++++++++++++++++++-------------
> >>  1 file changed, 192 insertions(+), 74 deletions(-)
> >>
> >> diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c
> >> index b6c54712f2aa..ceb5b3e498c6 100644
> >> --- a/drivers/media/i2c/imx274.c
> >> +++ b/drivers/media/i2c/imx274.c
> >> @@ -19,6 +19,7 @@
> >>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> >>   */
> >>  
> >> +#include <linux/kernel.h>
> >>  #include <linux/clk.h>
> >>  #include <linux/delay.h>
> >>  #include <linux/gpio.h>
> >> @@ -74,7 +75,7 @@
> >>   */
> >>  #define IMX274_MIN_EXPOSURE_TIME		(4 * 260 / 72)
> >>  
> >> -#define IMX274_DEFAULT_MODE			IMX274_MODE_3840X2160
> >> +#define IMX274_DEFAULT_MODE			IMX274_MODE_BINNING_OFF
> >>  #define IMX274_MAX_WIDTH			(3840)
> >>  #define IMX274_MAX_HEIGHT			(2160)
> >>  #define IMX274_MAX_FRAME_RATE			(120)
> >> @@ -111,6 +112,20 @@
> >>  #define IMX274_SHR_REG_LSB			0x300C /* SHR */
> >>  #define IMX274_SVR_REG_MSB			0x300F /* SVR */
> >>  #define IMX274_SVR_REG_LSB			0x300E /* SVR */
> >> +#define IMX274_HTRIM_EN_REG			0x3037
> >> +#define IMX274_HTRIM_START_REG_LSB		0x3038
> >> +#define IMX274_HTRIM_START_REG_MSB		0x3039
> >> +#define IMX274_HTRIM_END_REG_LSB		0x303A
> >> +#define IMX274_HTRIM_END_REG_MSB		0x303B
> >> +#define IMX274_VWIDCUTEN_REG			0x30DD
> >> +#define IMX274_VWIDCUT_REG_LSB			0x30DE
> >> +#define IMX274_VWIDCUT_REG_MSB			0x30DF
> >> +#define IMX274_VWINPOS_REG_LSB			0x30E0
> >> +#define IMX274_VWINPOS_REG_MSB			0x30E1
> >> +#define IMX274_WRITE_VSIZE_REG_LSB		0x3130
> >> +#define IMX274_WRITE_VSIZE_REG_MSB		0x3131
> >> +#define IMX274_Y_OUT_SIZE_REG_LSB		0x3132
> >> +#define IMX274_Y_OUT_SIZE_REG_MSB		0x3133
> >>  #define IMX274_VMAX_REG_1			0x30FA /* VMAX, MSB */
> >>  #define IMX274_VMAX_REG_2			0x30F9 /* VMAX */
> >>  #define IMX274_VMAX_REG_3			0x30F8 /* VMAX, LSB */
> >> @@ -141,9 +156,9 @@ static const struct regmap_config imx274_regmap_config = {
> >>  };
> >>  
> >>  enum imx274_mode {
> >> -	IMX274_MODE_3840X2160,
> >> -	IMX274_MODE_1920X1080,
> >> -	IMX274_MODE_1280X720,
> >> +	IMX274_MODE_BINNING_OFF,
> >> +	IMX274_MODE_BINNING_2_1,
> >> +	IMX274_MODE_BINNING_3_1,
> >>  };
> >>  
> >>  /*
> >> @@ -215,31 +230,14 @@ static const struct reg_8 imx274_mode1_3840x2160_raw10[] = {
> >>  	{0x3004, 0x01},
> >>  	{0x3005, 0x01},
> >>  	{0x3006, 0x00},
> >> -	{0x3007, 0x02},
> >> +	{0x3007, 0xa2},
> >>  
> >>  	{0x3018, 0xA2}, /* output XVS, HVS */
> >>  
> >>  	{0x306B, 0x05},
> >>  	{0x30E2, 0x01},
> >> -	{0x30F6, 0x07}, /* HMAX, 263 */
> >> -	{0x30F7, 0x01}, /* HMAX */
> >> -
> >> -	{0x30dd, 0x01}, /* crop to 2160 */
> >> -	{0x30de, 0x06},
> >> -	{0x30df, 0x00},
> >> -	{0x30e0, 0x12},
> >> -	{0x30e1, 0x00},
> >> -	{0x3037, 0x01}, /* to crop to 3840 */
> >> -	{0x3038, 0x0c},
> >> -	{0x3039, 0x00},
> >> -	{0x303a, 0x0c},
> >> -	{0x303b, 0x0f},
> >>  
> >>  	{0x30EE, 0x01},
> >> -	{0x3130, 0x86},
> >> -	{0x3131, 0x08},
> >> -	{0x3132, 0x7E},
> >> -	{0x3133, 0x08},
> >>  	{0x3342, 0x0A},
> >>  	{0x3343, 0x00},
> >>  	{0x3344, 0x16},
> >> @@ -273,7 +271,7 @@ static const struct reg_8 imx274_mode3_1920x1080_raw10[] = {
> >>  	{0x3004, 0x02},
> >>  	{0x3005, 0x21},
> >>  	{0x3006, 0x00},
> >> -	{0x3007, 0x11},
> >> +	{0x3007, 0xb1},
> >>  
> >>  	{0x3018, 0xA2}, /* output XVS, HVS */
> >>  
> >> @@ -283,22 +281,7 @@ static const struct reg_8 imx274_mode3_1920x1080_raw10[] = {
> >>  	{0x30F6, 0x04}, /* HMAX, 260 */
> >>  	{0x30F7, 0x01}, /* HMAX */
> >>  
> >> -	{0x30dd, 0x01}, /* to crop to 1920x1080 */
> >> -	{0x30de, 0x05},
> >> -	{0x30df, 0x00},
> >> -	{0x30e0, 0x04},
> >> -	{0x30e1, 0x00},
> >> -	{0x3037, 0x01},
> >> -	{0x3038, 0x0c},
> >> -	{0x3039, 0x00},
> >> -	{0x303a, 0x0c},
> >> -	{0x303b, 0x0f},
> >> -
> >>  	{0x30EE, 0x01},
> >> -	{0x3130, 0x4E},
> >> -	{0x3131, 0x04},
> >> -	{0x3132, 0x46},
> >> -	{0x3133, 0x04},
> >>  	{0x3342, 0x0A},
> >>  	{0x3343, 0x00},
> >>  	{0x3344, 0x1A},
> >> @@ -331,7 +314,7 @@ static const struct reg_8 imx274_mode5_1280x720_raw10[] = {
> >>  	{0x3004, 0x03},
> >>  	{0x3005, 0x31},
> >>  	{0x3006, 0x00},
> >> -	{0x3007, 0x09},
> >> +	{0x3007, 0xa9},
> >>  
> >>  	{0x3018, 0xA2}, /* output XVS, HVS */
> >>  
> >> @@ -341,21 +324,7 @@ static const struct reg_8 imx274_mode5_1280x720_raw10[] = {
> >>  	{0x30F6, 0x04}, /* HMAX, 260 */
> >>  	{0x30F7, 0x01}, /* HMAX */
> >>  
> >> -	{0x30DD, 0x01},
> >> -	{0x30DE, 0x07},
> >> -	{0x30DF, 0x00},
> >> -	{0x40E0, 0x04},
> >> -	{0x30E1, 0x00},
> >> -	{0x3030, 0xD4},
> >> -	{0x3031, 0x02},
> >> -	{0x3032, 0xD0},
> >> -	{0x3033, 0x02},
> >> -
> >>  	{0x30EE, 0x01},
> >> -	{0x3130, 0xE2},
> >> -	{0x3131, 0x02},
> >> -	{0x3132, 0xDE},
> >> -	{0x3133, 0x02},
> >>  	{0x3342, 0x0A},
> >>  	{0x3343, 0x00},
> >>  	{0x3344, 0x1B},
> >> @@ -561,6 +530,7 @@ struct stimx274 {
> >>  	struct imx274_ctrls ctrls;
> >>  	struct v4l2_mbus_framefmt format;
> >>  	struct v4l2_fract frame_interval;
> >> +	struct v4l2_rect crop;
> >>  	struct regmap *regmap;
> >>  	struct gpio_desc *reset_gpio;
> >>  	struct mutex lock; /* mutex lock for operations */
> >> @@ -901,36 +871,30 @@ static int imx274_set_fmt(struct v4l2_subdev *sd,
> >>  {
> >>  	struct v4l2_mbus_framefmt *fmt = &format->format;
> >>  	struct stimx274 *imx274 = to_imx274(sd);
> >> -	struct i2c_client *client = imx274->client;
> >> -	int index;
> >> +	struct device *dev = &imx274->client->dev;
> >> +	unsigned int ratio; /* Binning ratio */
> >>  
> >> -	dev_dbg(&client->dev,
> >> -		"%s: width = %d height = %d code = %d\n",
> >> -		__func__, fmt->width, fmt->height, fmt->code);
> >> +	dev_dbg(dev, "%s: request of  %dx%d (%s)\n",
> >> +		__func__, fmt->width, fmt->height,
> >> +		V4L2_SUBDEV_FORMAT_ACTIVE ? "ACTIVE" : "TRY");
> >>  
> >>  	mutex_lock(&imx274->lock);
> >>  
> >> -	for (index = 0; index < ARRAY_SIZE(imx274_formats); index++) {
> >> -		if (imx274_formats[index].size.width == fmt->width &&
> >> -		    imx274_formats[index].size.height == fmt->height)
> >> +	/* Find ratio (maximize output resolution). Fallback to 1:1. */
> >> +	for (ratio = 3; ratio > 1; ratio--)
> >> +		if (fmt->width <= DIV_ROUND_UP(imx274->crop.width, ratio) &&
> >> +		    fmt->height <= DIV_ROUND_UP(imx274->crop.height, ratio))
> >>  			break;
> >> -	}
> >> -
> >> -	if (index >= ARRAY_SIZE(imx274_formats)) {
> >> -		/* default to first format */
> >> -		index = 0;
> >> -	}
> >>  
> >> -	imx274->mode = &imx274_formats[index];
> >> +	imx274->mode = &imx274_formats[ratio - 1];
> >>  
> >> -	if (fmt->width > IMX274_MAX_WIDTH)
> >> -		fmt->width = IMX274_MAX_WIDTH;
> >> -	if (fmt->height > IMX274_MAX_HEIGHT)
> >> -		fmt->height = IMX274_MAX_HEIGHT;
> >> -	fmt->width = fmt->width & (~IMX274_MASK_LSB_2_BITS);
> >> -	fmt->height = fmt->height & (~IMX274_MASK_LSB_2_BITS);
> >> +	fmt->width = imx274->crop.width / ratio;
> >> +	fmt->height = imx274->crop.height / ratio;
> >>  	fmt->field = V4L2_FIELD_NONE;
> >>  
> >> +	dev_dbg(dev, "%s: adjusted to %dx%d (%d:1 binning)\n",
> >> +		__func__, fmt->width, fmt->height, ratio);
> >> +
> >>  	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
> >>  		cfg->try_fmt = *fmt;
> >>  	else
> >> @@ -940,6 +904,152 @@ static int imx274_set_fmt(struct v4l2_subdev *sd,
> >>  	return 0;
> >>  }
> >>  
> >> +static int imx274_get_selection(struct v4l2_subdev *sd,
> >> +				struct v4l2_subdev_pad_config *cfg,
> >> +				struct v4l2_subdev_selection *sel)
> >> +{
> >> +	struct stimx274 *imx274 = to_imx274(sd);
> >> +
> >> +	if (sel->pad != 0)
> >> +		return -EINVAL;
> >> +
> >> +	switch (sel->target) {
> >> +	case V4L2_SEL_TGT_CROP_BOUNDS:
> >> +		sel->r.left = 0;
> >> +		sel->r.top = 0;
> >> +		sel->r.width = IMX274_MAX_WIDTH;
> >> +		sel->r.height = IMX274_MAX_HEIGHT;
> >> +		return 0;
> >> +	case V4L2_SEL_TGT_CROP:
> >> +		if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
> >> +			mutex_lock(&imx274->lock);
> >> +			sel->r = imx274->crop;
> >> +			mutex_unlock(&imx274->lock);
> >> +		} else {
> >> +			sel->r = cfg->try_crop;
> >> +		}
> >> +		return 0;
> >> +	default:
> >> +		return -EINVAL;
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int imx274_set_selection(struct v4l2_subdev *sd,
> >> +				struct v4l2_subdev_pad_config *cfg,
> >> +				struct v4l2_subdev_selection *sel)
> >> +{
> >> +	struct stimx274 *imx274 = to_imx274(sd);
> >> +	struct device *dev = &imx274->client->dev;
> >> +	struct v4l2_mbus_framefmt *tgt_fmt;
> >> +	struct v4l2_rect *tgt_crop;
> >> +	struct v4l2_rect new_crop;
> >> +
> > 
> > A lot of sensor drivers use the format IOCTLs to configure the output size
> > of the sensor and that's what it must be: the get_fmt() pad op has to
> > return the format of the image produced by the sensor. The size set by the
> > set_fmt() also must be obtainable using get_fmt().
> > 
> > What I propose is to move also the binning configuration to use selections,
> > i.e. the COMPOSE selection target. The NATIVE_SIZE target is the sensor's
> > native size, the largest that can be accessed in its pixel array.
> > 
> > The size in format related IOCTLs is thus derived from the NATIVE_SIZE,
> > CROP and COMPOSE configuration, and is no longer settable directly.
> 
> I'm OK with making any improvement, but I'm afraid I'm not understanding
> what you mean. Do you mean we should stop responding to the VIDIOC_S_FMT
> ioctl, aka v4l2_subdev_pad_ops.set_selection? Wouldn't this break
> existing applications?

Hmm. The driver supports sub-device uAPI. Which bridge (or ISP) driver are
you using the sensor with?

> 
> Also the meaning of COMPOSE in the context of a sensor subdev is unclear
> to me. For a video node (which is typically paired with a DMA) it makes
> sense: the DMA can write a sub-area of the destination memory buffer.
> But the sensor subdev is the first element of a possibly long processing
> chain, and as such it only produces a stream. The sensor does not know
> what a "memory buffer" is.
> 
> What's wrong with my understanding?

The COMPOSE target is also used for configuring scaling:

<URL:https://hverkuil.home.xs4all.nl/spec/uapi/v4l/dev-subdev.html#selections-cropping-scaling-and-composition>

And binning is effectively scaling.

> 
> > Btw. the crop here, is that taking place after binning as it would seem
> > like? Then, I presume it is digital cropping, and the CROP rectangle is
> > related to the COMPOSE rectangle (binning configuration).
> 
> Logically speaking, cropping here happens before binning, i.e. the crop
> rectangle always refers to NATIVE_SIZE. The sensor just skips lines and
> columns outside of that rectangle and optionally bins what's inside.
> 
> Examples of how it is currently implemented:
> - native 3840x2160, crop 3840x2160, fmt 3840x2160 = don't crop,  1:1 bin
> - native 3840x2160, crop 1920x1080, fmt 1920x1080 = crop to 50%, 1:1 bin
> - native 3840x2160, crop 3840x2160, fmt 1920x1080 = don't crop,  2:1 bin
> - native 3840x2160, crop 1920x1080, fmt  960x 540 = crop to 50%, 2:1 bin
> 
> Can you provide similar examples of how it would work when setting CROP
> + COMPOSE, and without setting the format?
> 
> Regards,

-- 
Kind regards,

Sakari Ailus
e-mail: sakari.ailus@xxxxxx



[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux