diff options
Diffstat (limited to 'target/linux/bcm27xx/patches-5.4/950-0654-media-imx219-Advertise-embedded-data-node-on-media-p.patch')
-rw-r--r-- | target/linux/bcm27xx/patches-5.4/950-0654-media-imx219-Advertise-embedded-data-node-on-media-p.patch | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/target/linux/bcm27xx/patches-5.4/950-0654-media-imx219-Advertise-embedded-data-node-on-media-p.patch b/target/linux/bcm27xx/patches-5.4/950-0654-media-imx219-Advertise-embedded-data-node-on-media-p.patch new file mode 100644 index 0000000000..c4c25d1512 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0654-media-imx219-Advertise-embedded-data-node-on-media-p.patch @@ -0,0 +1,335 @@ +From 372b138a6bc43b0fdff4e46ae4c799fd1b1f2785 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck <naush@raspberrypi.com> +Date: Thu, 12 Mar 2020 14:09:38 +0000 +Subject: [PATCH] media: imx219: Advertise embedded data node on media + pad 1 + +This commit updates the imx219 driver to adverise support for embedded +data streams. This can then be used by the bcm2835-unicam driver, which +has recently been updated to expose the embedded data stream to +userland. + +The imx219 sensor subdevice overloads the media pad to differentiate +between image stream (pad 0) and embedded data stream (pad 1) when +performing the v4l2_subdev_pad_ops functions. + +Signed-off-by: Naushir Patuck <naush@raspberrypi.com> +--- + drivers/media/i2c/imx219.c | 226 +++++++++++++++++++++++++------------ + 1 file changed, 155 insertions(+), 71 deletions(-) + +--- a/drivers/media/i2c/imx219.c ++++ b/drivers/media/i2c/imx219.c +@@ -112,6 +112,16 @@ + #define IMX219_TESTP_BLUE_DEFAULT 0 + #define IMX219_TESTP_GREENB_DEFAULT 0 + ++/* Embedded metadata stream structure */ ++#define IMX219_EMBEDDED_LINE_WIDTH 16384 ++#define IMX219_NUM_EMBEDDED_LINES 1 ++ ++enum pad_types { ++ IMAGE_PAD, ++ METADATA_PAD, ++ NUM_PADS ++}; ++ + struct imx219_reg { + u16 address; + u8 val; +@@ -503,7 +513,7 @@ static const struct imx219_mode supporte + + struct imx219 { + struct v4l2_subdev sd; +- struct media_pad pad; ++ struct media_pad pad[NUM_PADS]; + + struct v4l2_mbus_framefmt fmt; + +@@ -652,17 +662,25 @@ static void imx219_set_default_format(st + static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) + { + struct imx219 *imx219 = to_imx219(sd); +- struct v4l2_mbus_framefmt *try_fmt = +- v4l2_subdev_get_try_format(sd, fh->pad, 0); ++ struct v4l2_mbus_framefmt *try_fmt_img = ++ v4l2_subdev_get_try_format(sd, fh->pad, IMAGE_PAD); ++ struct v4l2_mbus_framefmt *try_fmt_meta = ++ v4l2_subdev_get_try_format(sd, fh->pad, METADATA_PAD); + + mutex_lock(&imx219->mutex); + +- /* Initialize try_fmt */ +- try_fmt->width = supported_modes[0].width; +- try_fmt->height = supported_modes[0].height; +- try_fmt->code = imx219_get_format_code(imx219, +- MEDIA_BUS_FMT_SRGGB10_1X10); +- try_fmt->field = V4L2_FIELD_NONE; ++ /* Initialize try_fmt for the image pad */ ++ try_fmt_img->width = supported_modes[0].width; ++ try_fmt_img->height = supported_modes[0].height; ++ try_fmt_img->code = imx219_get_format_code(imx219, ++ MEDIA_BUS_FMT_SRGGB10_1X10); ++ try_fmt_img->field = V4L2_FIELD_NONE; ++ ++ /* Initialize try_fmt for the embedded metadata pad */ ++ try_fmt_meta->width = IMX219_EMBEDDED_LINE_WIDTH; ++ try_fmt_meta->height = IMX219_NUM_EMBEDDED_LINES; ++ try_fmt_meta->code = MEDIA_BUS_FMT_SENSOR_DATA; ++ try_fmt_meta->field = V4L2_FIELD_NONE; + + mutex_unlock(&imx219->mutex); + +@@ -764,10 +782,21 @@ static int imx219_enum_mbus_code(struct + { + struct imx219 *imx219 = to_imx219(sd); + +- if (code->index >= (ARRAY_SIZE(codes) / 4)) ++ if (code->pad >= NUM_PADS) + return -EINVAL; + +- code->code = imx219_get_format_code(imx219, codes[code->index * 4]); ++ if (code->pad == IMAGE_PAD) { ++ if (code->index >= (ARRAY_SIZE(codes) / 4)) ++ return -EINVAL; ++ ++ code->code = imx219_get_format_code(imx219, ++ codes[code->index * 4]); ++ } else { ++ if (code->index > 0) ++ return -EINVAL; ++ ++ code->code = MEDIA_BUS_FMT_SENSOR_DATA; ++ } + + return 0; + } +@@ -778,16 +807,29 @@ static int imx219_enum_frame_size(struct + { + struct imx219 *imx219 = to_imx219(sd); + +- if (fse->index >= ARRAY_SIZE(supported_modes)) ++ if (fse->pad >= NUM_PADS) + return -EINVAL; + +- if (fse->code != imx219_get_format_code(imx219, fse->code)) +- return -EINVAL; ++ if (fse->pad == IMAGE_PAD) { ++ if (fse->index >= ARRAY_SIZE(supported_modes)) ++ return -EINVAL; ++ ++ if (fse->code != imx219_get_format_code(imx219, fse->code)) ++ return -EINVAL; ++ ++ fse->min_width = supported_modes[fse->index].width; ++ fse->max_width = fse->min_width; ++ fse->min_height = supported_modes[fse->index].height; ++ fse->max_height = fse->min_height; ++ } else { ++ if (fse->code != MEDIA_BUS_FMT_SENSOR_DATA || fse->index > 0) ++ return -EINVAL; + +- fse->min_width = supported_modes[fse->index].width; +- fse->max_width = fse->min_width; +- fse->min_height = supported_modes[fse->index].height; +- fse->max_height = fse->min_height; ++ fse->min_width = IMX219_EMBEDDED_LINE_WIDTH; ++ fse->max_width = fse->min_width; ++ fse->min_height = IMX219_NUM_EMBEDDED_LINES; ++ fse->max_height = fse->min_height; ++ } + + return 0; + } +@@ -802,9 +844,9 @@ static void imx219_reset_colorspace(stru + fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace); + } + +-static void imx219_update_pad_format(struct imx219 *imx219, +- const struct imx219_mode *mode, +- struct v4l2_subdev_format *fmt) ++static void imx219_update_image_pad_format(struct imx219 *imx219, ++ const struct imx219_mode *mode, ++ struct v4l2_subdev_format *fmt) + { + fmt->format.width = mode->width; + fmt->format.height = mode->height; +@@ -812,20 +854,38 @@ static void imx219_update_pad_format(str + imx219_reset_colorspace(&fmt->format); + } + ++static void imx219_update_metadata_pad_format(struct v4l2_subdev_format *fmt) ++{ ++ fmt->format.width = IMX219_EMBEDDED_LINE_WIDTH; ++ fmt->format.height = IMX219_NUM_EMBEDDED_LINES; ++ fmt->format.code = MEDIA_BUS_FMT_SENSOR_DATA; ++ fmt->format.field = V4L2_FIELD_NONE; ++} ++ + static int __imx219_get_pad_format(struct imx219 *imx219, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) + { ++ if (fmt->pad >= NUM_PADS) ++ return -EINVAL; ++ + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *try_fmt = + v4l2_subdev_get_try_format(&imx219->sd, cfg, fmt->pad); + /* update the code which could change due to vflip or hflip: */ +- try_fmt->code = imx219_get_format_code(imx219, try_fmt->code); ++ try_fmt->code = fmt->pad == IMAGE_PAD ? ++ imx219_get_format_code(imx219, try_fmt->code) : ++ MEDIA_BUS_FMT_SENSOR_DATA; + fmt->format = *try_fmt; + } else { +- imx219_update_pad_format(imx219, imx219->mode, fmt); +- fmt->format.code = imx219_get_format_code(imx219, +- imx219->fmt.code); ++ if (fmt->pad == IMAGE_PAD) { ++ imx219_update_image_pad_format(imx219, imx219->mode, ++ fmt); ++ fmt->format.code = imx219_get_format_code(imx219, ++ imx219->fmt.code); ++ } else { ++ imx219_update_metadata_pad_format(fmt); ++ } + } + + return 0; +@@ -855,51 +915,74 @@ static int imx219_set_pad_format(struct + int exposure_max, exposure_def, hblank; + unsigned int i; + +- mutex_lock(&imx219->mutex); +- +- for (i = 0; i < ARRAY_SIZE(codes); i++) +- if (codes[i] == fmt->format.code) +- break; +- if (i >= ARRAY_SIZE(codes)) +- i = 0; ++ if (fmt->pad >= NUM_PADS) ++ return -EINVAL; + +- /* Bayer order varies with flips */ +- fmt->format.code = imx219_get_format_code(imx219, codes[i]); ++ mutex_lock(&imx219->mutex); + +- mode = v4l2_find_nearest_size(supported_modes, +- ARRAY_SIZE(supported_modes), +- width, height, +- fmt->format.width, fmt->format.height); +- imx219_update_pad_format(imx219, mode, fmt); +- if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { +- framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); +- *framefmt = fmt->format; +- } else if (imx219->mode != mode || +- imx219->fmt.code != fmt->format.code) { +- imx219->fmt = fmt->format; +- imx219->mode = mode; +- /* Update limits and set FPS to default */ +- __v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN, +- IMX219_VTS_MAX - mode->height, 1, +- mode->vts_def - mode->height); +- __v4l2_ctrl_s_ctrl(imx219->vblank, +- mode->vts_def - mode->height); +- /* Update max exposure while meeting expected vblanking */ +- exposure_max = mode->vts_def - 4; +- exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ? +- exposure_max : IMX219_EXPOSURE_DEFAULT; +- __v4l2_ctrl_modify_range(imx219->exposure, +- imx219->exposure->minimum, +- exposure_max, imx219->exposure->step, +- exposure_def); +- /* +- * Currently PPL is fixed to IMX219_PPL_DEFAULT, so hblank +- * depends on mode->width only, and is not changeble in any +- * way other than changing the mode. +- */ +- hblank = IMX219_PPL_DEFAULT - mode->width; +- __v4l2_ctrl_modify_range(imx219->hblank, hblank, hblank, 1, +- hblank); ++ if (fmt->pad == IMAGE_PAD) { ++ for (i = 0; i < ARRAY_SIZE(codes); i++) ++ if (codes[i] == fmt->format.code) ++ break; ++ if (i >= ARRAY_SIZE(codes)) ++ i = 0; ++ ++ /* Bayer order varies with flips */ ++ fmt->format.code = imx219_get_format_code(imx219, codes[i]); ++ ++ mode = v4l2_find_nearest_size(supported_modes, ++ ARRAY_SIZE(supported_modes), ++ width, height, ++ fmt->format.width, ++ fmt->format.height); ++ imx219_update_image_pad_format(imx219, mode, fmt); ++ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { ++ framefmt = v4l2_subdev_get_try_format(sd, cfg, ++ fmt->pad); ++ *framefmt = fmt->format; ++ } else if (imx219->mode != mode || ++ imx219->fmt.code != fmt->format.code) { ++ imx219->fmt = fmt->format; ++ imx219->mode = mode; ++ /* Update limits and set FPS to default */ ++ __v4l2_ctrl_modify_range(imx219->vblank, ++ IMX219_VBLANK_MIN, ++ IMX219_VTS_MAX - mode->height, ++ 1, ++ mode->vts_def - mode->height); ++ __v4l2_ctrl_s_ctrl(imx219->vblank, ++ mode->vts_def - mode->height); ++ /* ++ * Update max exposure while meeting ++ * expected vblanking ++ */ ++ exposure_max = mode->vts_def - 4; ++ exposure_def = ++ (exposure_max < IMX219_EXPOSURE_DEFAULT) ? ++ exposure_max : IMX219_EXPOSURE_DEFAULT; ++ __v4l2_ctrl_modify_range(imx219->exposure, ++ imx219->exposure->minimum, ++ exposure_max, ++ imx219->exposure->step, ++ exposure_def); ++ /* ++ * Currently PPL is fixed to IMX219_PPL_DEFAULT, so ++ * hblank depends on mode->width only, and is not ++ * changeble in any way other than changing the mode. ++ */ ++ hblank = IMX219_PPL_DEFAULT - mode->width; ++ __v4l2_ctrl_modify_range(imx219->hblank, hblank, hblank, ++ 1, hblank); ++ } ++ } else { ++ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { ++ framefmt = v4l2_subdev_get_try_format(sd, cfg, ++ fmt->pad); ++ *framefmt = fmt->format; ++ } else { ++ /* Only one embedded data mode is supported */ ++ imx219_update_metadata_pad_format(fmt); ++ } + } + + mutex_unlock(&imx219->mutex); +@@ -1399,13 +1482,14 @@ static int imx219_probe(struct i2c_clien + imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + imx219->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + +- /* Initialize source pad */ +- imx219->pad.flags = MEDIA_PAD_FL_SOURCE; ++ /* Initialize source pads */ ++ imx219->pad[IMAGE_PAD].flags = MEDIA_PAD_FL_SOURCE; ++ imx219->pad[METADATA_PAD].flags = MEDIA_PAD_FL_SOURCE; + + /* Initialize default format */ + imx219_set_default_format(imx219); + +- ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad); ++ ret = media_entity_pads_init(&imx219->sd.entity, NUM_PADS, imx219->pad); + if (ret) { + dev_err(dev, "failed to init entity pads: %d\n", ret); + goto error_handler_free; |