vimc: Virtual Media Control VPU's
cover vimc: Virtual Media Control VPU's
* This patch series add to the vimc driver video processing units ad a debayer and a scaler.
* The test pattern generator from vivid driver was exported as a module, as it is used by the vimc driver as well.
* The debayer transforms the bayer format image received in its sink pad to a bayer format by avaraging the pixels within a mean window
* The scaler only scales up the image for now.
* The ioctls to configure the format in the pads were implemented to allow testing the pipe from the user space
The patch series is based on 'vimc/review/video-pipe' branch, it goes on top of the patch named "[media] vimc: Virtual Media Controller core, capture and sensor" and is available at
https://github.com/helen-fornazier/opw-staging vimc/review/vpu
Helen Fornazier (7):
[media] tpg: Export the tpg code from vivid as a module [media] vimc: sen: Integrate the tpg on the sensor [media] vimc: Add vimc_ent_sd_init/cleanup helper functions [media] vimc: Add vimc_pipeline_s_stream in the core [media] vimc: deb: Add debayer filter
[media] vimc: sca: Add scaler subdevice
[media] vimc: Implement set format in the nodes
drivers/media/platform/Kconfig | 2 + drivers/media/platform/Makefile | 1 + drivers/media/platform/tpg/Kconfig | 5 + drivers/media/platform/tpg/Makefile | 3 + drivers/media/platform/tpg/tpg-colors.c | 1181 ++++++++++++ drivers/media/platform/tpg/tpg-core.c | 2211 +++++++++++++++++++++++ drivers/media/platform/vimc/Kconfig | 1 + drivers/media/platform/vimc/Makefile | 3 +- drivers/media/platform/vimc/vimc-capture.c | 88 +- drivers/media/platform/vimc/vimc-core.c | 196 +- drivers/media/platform/vimc/vimc-core.h | 29 + drivers/media/platform/vimc/vimc-debayer.c | 503 ++++++ drivers/media/platform/vimc/vimc-debayer.h | 28 + drivers/media/platform/vimc/vimc-scaler.c | 362 ++++ drivers/media/platform/vimc/vimc-scaler.h | 28 + drivers/media/platform/vimc/vimc-sensor.c | 175 +- drivers/media/platform/vivid/Kconfig | 1 + drivers/media/platform/vivid/Makefile | 2 +- drivers/media/platform/vivid/vivid-core.h | 2 +- drivers/media/platform/vivid/vivid-tpg-colors.c | 1182 ------------ drivers/media/platform/vivid/vivid-tpg-colors.h | 68 - drivers/media/platform/vivid/vivid-tpg.c | 2191 ---------------------- drivers/media/platform/vivid/vivid-tpg.h | 596 ------ include/media/tpg-colors.h | 68 + include/media/tpg.h | 595 ++++++ 25 files changed, 5345 insertions(+), 4176 deletions(-) create mode 100644 drivers/media/platform/tpg/Kconfig create mode 100644 drivers/media/platform/tpg/Makefile create mode 100644 drivers/media/platform/tpg/tpg-colors.c create mode 100644 drivers/media/platform/tpg/tpg-core.c create mode 100644 drivers/media/platform/vimc/vimc-debayer.c create mode 100644 drivers/media/platform/vimc/vimc-debayer.h create mode 100644 drivers/media/platform/vimc/vimc-scaler.c create mode 100644 drivers/media/platform/vimc/vimc-scaler.h delete mode 100644 drivers/media/platform/vivid/vivid-tpg-colors.c delete mode 100644 drivers/media/platform/vivid/vivid-tpg-colors.h delete mode 100644 drivers/media/platform/vivid/vivid-tpg.c delete mode 100644 drivers/media/platform/vivid/vivid-tpg.h create mode 100644 include/media/tpg-colors.h create mode 100644 include/media/tpg.h
Signature · 1 line
1.9.1
PATCH 2/7 vimc: sen: Integrate the tpg on the sensor
Initialize the test pattern generator on the sensor Generate a colored bar image instead of a grey one
--- drivers/media/platform/vimc/Kconfig | 1 + drivers/media/platform/vimc/vimc-sensor.c | 44 +++++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 2 deletions(-)
drivers/media/platform/vimc/Kconfig +1 -0
@@ -1,6 +1,7 @@ config VIDEO_VIMC tristate "Virtual Media Controller Driver (VIMC)" select VIDEO_V4L2_SUBDEV_API + select VIDEO_TPG default n ---help--- Skeleton driver for Virtual Media Controller
drivers/media/platform/vimc/vimc-sensor.c +42 -2
93 lines not on this page · raw message
Signature · 1 line
1.9.1
Re: [PATCH 2/7] [media] vimc: sen: Integrate the tpg on the sensor
Hi Helen,
Thank you for the patch.
Quoted 8 lines · On Thursday 06 August 2015 17:26:09 Helen Fornazier wrote:
Initialize the test pattern generator on the sensor Generate a colored bar image instead of a grey one
Signed-off-by Helen Fornazier <[email protected]>--- drivers/media/platform/vimc/Kconfig | 1 + drivers/media/platform/vimc/vimc-sensor.c | 44 ++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 2 deletions(-)
[snip]
drivers/media/platform/vimc/vimc-sensor.c line 21
Quoted 11 lines
(quoted diff) +0
-0
b/drivers/media/platform/vimc/vimc-sensor.cindex d613792..a2879ad 100644drivers/media/platform/vimc/vimc-sensor.c +1
-0@@ -16,15 +16,19 @@*/ #include <linux/freezer.h> +#include <media/tpg.h> #include <linux/vmalloc.h> #include <linux/v4l2-mediabus.h>
media/tpg.h should have been inserted here.
Quoted 3 lines
drivers/media/platform/vimc/vimc-sensor.c +0
-0#include <media/v4l2-subdev.h> #include "vimc-sensor.h"
[snip]
drivers/media/platform/vimc/vimc-sensor.c static int vimc_sen_get_fmt(struct v4l2_subdev *sd, · line 101
Quoted 8 lines
drivers/media/platform/vimc/vimc-sensor.c +8
-0+static void vimc_sen_tpg_s_format (struct vimc_sen_device *vsen) +{ +const struct vimc_pix_map *vpix; + + vpix =vimc_pix_map_by_code (vsen->mbus_format.code); +/* This should never be NULL, as we won't allow any format other then +* the ones in the vimc_pix_map_list table */ +BUG_ON (!vpix);
BUG_ON() is quite harsh, it will stop the machine. If the condition can never happen then you can remove the check. If you're worried it might happen I'd use a WARN_ON() and return.
Quoted 13 lines
drivers/media/platform/vimc/vimc-sensor.c +13
-0+tpg_s_bytesperline (&vsen->tpg,0 , + vsen->mbus_format.width * vpix->bpp); +tpg_s_buf_height (&vsen->tpg, vsen->mbus_format.height); +tpg_s_fourcc (&vsen->tpg, vpix->pixelformat); +/* TODO: check why the tpg_s_field need this third argument if +* it is already receiving the field */ +tpg_s_field (&vsen->tpg, vsen->mbus_format.field, + vsen->mbus_format.field ==V4L2_FIELD_ALTERNATE ); +tpg_s_colorspace (&vsen->tpg, vsen->mbus_format.colorspace); +tpg_s_ycbcr_enc (&vsen->tpg, vsen->mbus_format.ycbcr_enc); +tpg_s_quantization (&vsen->tpg, vsen->mbus_format.quantization); +tpg_s_xfer_func (&vsen->tpg, vsen->mbus_format.xfer_func); +}
Signature · 3 lines
Regards, Laurent Pinchart
Re: [PATCH 2/7] [media] vimc: sen: Integrate the tpg on the sensor
In reply to Helen FornazierQuoted 2 lines · Helen Fornazier
Initialize the test pattern generator on the sensor Generate a colored bar image instead of a grey one
You don't want to put the tpg in every sensor and have all the blocks in between process the video. This is all virtual, so all that is necessary is to put the tpg in every DMA engine (video node) but have the subdevs modify the tpg setting when you start the pipeline.
So the source would set the width/height to the sensor resolution, and it will initialize the crop/compose rectangles. Every other entity in the pipeline will continue modifying according to what they do. E.g. a scaler will just change the compose rectangle.
When you start streaming the tpg will generate the image based on all those settings as if all the entities would actually do the work.
Of course, this assumes the processing the entities do map to what the tpg can do, but that's true for vimc.
An additional advantage is that the entities can use a wide range of mediabus formats since the tpg can generate basically anything. Implementing multiplanar is similarly easy. This would be much harder if you had to write the image processing code for the entities since you'd either have to support lots of different formats (impractical) or limit yourself to just a few.
Quoted 54 lines
Signed-off-by Helen Fornazier <[email protected]>--- drivers/media/platform/vimc/Kconfig | 1 + drivers/media/platform/vimc/vimc-sensor.c | 44 +++++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 2 deletions(-)drivers/media/platform/vimc/Kconfig +1
-0@@ -1,6 +1,7 @@ config VIDEO_VIMC tristate "Virtual Media Controller Driver (VIMC)" select VIDEO_V4L2_SUBDEV_API + select VIDEO_TPG default n ---help--- Skeleton driver for Virtual Media Controllerdrivers/media/platform/vimc/vimc-sensor.c +11
-0@@ -16,15 +16,19 @@*/ #include <linux/freezer.h> +#include <media/tpg.h> #include <linux/vmalloc.h> #include <linux/v4l2-mediabus.h> #include <media/v4l2-subdev.h> #include "vimc-sensor.h" +#define VIMC_SEN_FRAME_MAX_WIDTH 4096 +struct vimc_sen_device {struct vimc_ent_device ved;struct v4l2_subdev sd; +struct tpg_data tpg;struct v4l2_device *v4l2_dev;struct device *dev;struct task_struct *kthread_sen;@@ -87,6 +91,29 @@ static int vimc_sen_get_fmt(struct v4l2_subdev *sd,return 0 ; } +static void vimc_sen_tpg_s_format (struct vimc_sen_device *vsen) +{ +const struct vimc_pix_map *vpix; + + vpix =vimc_pix_map_by_code (vsen->mbus_format.code); +/* This should never be NULL, as we won't allow any format other then +* the ones in the vimc_pix_map_list table */
drivers/media/platform/vimc/vimc-sensor.c static int vimc_sen_get_fmt(struct v4l2_subdev *sd, · line 110
Quoted 10 lines
drivers/media/platform/vimc/vimc-sensor.c +10
-0+BUG_ON (!vpix); + +tpg_s_bytesperline (&vsen->tpg,0 , + vsen->mbus_format.width * vpix->bpp); +tpg_s_buf_height (&vsen->tpg, vsen->mbus_format.height); +tpg_s_fourcc (&vsen->tpg, vpix->pixelformat); +/* TODO: check why the tpg_s_field need this third argument if +* it is already receiving the field */ +tpg_s_field (&vsen->tpg, vsen->mbus_format.field, + vsen->mbus_format.field ==V4L2_FIELD_ALTERNATE );
Actually the second argument argument cannot be FIELD_ALTERNATE. If it is field ALTERNATE, then the second argument must be either FIELD_TOP orFIELD_BOTTOM: i.e. it tells the generator which field comes first in the FIELD_ALTERNATE case.
And in case you are wondering: it's always FIELD_TOP except for 60 Hz SDTV formats where it is FIELD_BOTTOM.
Quoted 49 lines
drivers/media/platform/vimc/vimc-sensor.c +18
-2+tpg_s_colorspace (&vsen->tpg, vsen->mbus_format.colorspace); +tpg_s_ycbcr_enc (&vsen->tpg, vsen->mbus_format.ycbcr_enc); +tpg_s_quantization (&vsen->tpg, vsen->mbus_format.quantization); +tpg_s_xfer_func (&vsen->tpg, vsen->mbus_format.xfer_func); +} +static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = { .enum_mbus_code = vimc_sen_enum_mbus_code, .enum_frame_size = vimc_sen_enum_frame_size,@@ -112,7 +139,7 @@ static int vimc_thread_sen(void *data)if (kthread_should_stop ())break ; -memset (vsen->frame,100 , vsen->frame_size); +tpg_fill_plane_buffer (&vsen->tpg,V4L2_STD_PAL ,0 , vsen->frame);/* Send the frame to all source pads */ for (i =0 ; i < vsen->sd.entity.num_pads; i++)@@ -192,6 +219,7 @@ static void vimc_sen_destroy(struct vimc_ent_device *ved)struct vimc_sen_device *vsen =container_of (ved, struct vimc_sen_device, ved); +tpg_free (&vsen->tpg);media_entity_cleanup (ved->ent);v4l2_device_unregister_subdev (&vsen->sd);kfree (vsen);@@ -242,6 +270,16 @@ struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, vsen->mbus_format.quantization =V4L2_QUANTIZATION_FULL_RANGE ; vsen->mbus_format.xfer_func =V4L2_XFER_FUNC_SRGB ; +/* Initialize the test pattern generator */ +tpg_init (&vsen->tpg, vsen->mbus_format.width, + vsen->mbus_format.height); + ret =tpg_alloc (&vsen->tpg,VIMC_SEN_FRAME_MAX_WIDTH ); +if (ret) + goto err_clean_m_ent; + +/* Configure the tpg */ +vimc_sen_tpg_s_format (vsen); +/* Fill the vimc_ent_device struct */ vsen->ved.destroy = vimc_sen_destroy; vsen->ved.ent = &vsen->sd.entity;@@ -261,11 +299,13 @@ struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev,if (ret) {dev_err (vsen->dev,"subdev register failed (err=%d)\n" , ret); - goto err_clean_m_ent;
drivers/media/platform/vimc/vimc-sensor.c struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, · line 311
Quoted 10 lines
drivers/media/platform/vimc/vimc-sensor.c +3
-0+ goto err_free_tpg; }return &vsen->ved; +err_free_tpg: +tpg_free (&vsen->tpg); err_clean_m_ent:media_entity_cleanup (&vsen->sd.entity); err_clean_pads:
Regards,
Hans
Re: [PATCH 2/7] [media] vimc: sen: Integrate the tpg on the sensor
Hi Hans,
Quoted 14 lines · On Friday 14 August 2015 14:15:58 Hans Verkuil wrote:
Quoted 2 lines · Helen Fornazier
Initialize the test pattern generator on the sensor Generate a colored bar image instead of a grey one
You don't want to put the tpg in every sensor and have all the blocks in between process the video. This is all virtual, so all that is necessary is to put the tpg in every DMA engine (video node) but have the subdevs modify the tpg setting when you start the pipeline.
So the source would set the width/height to the sensor resolution, and it will initialize the crop/compose rectangles. Every other entity in the pipeline will continue modifying according to what they do. E.g. a scaler will just change the compose rectangle.
Quoted 5 lines
When you start streaming the tpg will generate the image based on all those settings as if all the entities would actually do the work.
Of course, this assumes the processing the entities do map to what the tpg can do, but that's true for vimc.
There will be small differences, as generating a YUV image won't be exactly the same as debayering a bayer image. It probably doesn't matter much though.
A bigger problem is that the driver aims at supporting output video device nodes at some point in mem-to-mem pipelines. For that the debayer, color space conversion and scaler subdevs need to perform real image processing.
Quoted 6 lines
An additional advantage is that the entities can use a wide range of mediabus formats since the tpg can generate basically anything. Implementing multiplanar is similarly easy. This would be much harder if you had to write the image processing code for the entities since you'd either have to support lots of different formats (impractical) or limit yourself to just a few.
Signature · 3 lines
Regards, Laurent Pinchart
Re: [PATCH 2/7] [media] vimc: sen: Integrate the tpg on the sensor
In reply to Hans VerkuilHi, thank you all for your review
Quoted 96 lines · Hans Verkuil
Quoted 2 lines · Helen Fornazier
Initialize the test pattern generator on the sensor Generate a colored bar image instead of a grey one
You don't want to put the tpg in every sensor and have all the blocks in between process the video. This is all virtual, so all that is necessary is to put the tpg in every DMA engine (video node) but have the subdevs modify the tpg setting when you start the pipeline.
So the source would set the width/height to the sensor resolution, and it will initialize the crop/compose rectangles. Every other entity in the pipeline will continue modifying according to what they do. E.g. a scaler will just change the compose rectangle.
When you start streaming the tpg will generate the image based on all those settings as if all the entities would actually do the work.
Of course, this assumes the processing the entities do map to what the tpg can do, but that's true for vimc.
An additional advantage is that the entities can use a wide range of mediabus formats since the tpg can generate basically anything. Implementing multiplanar is similarly easy. This would be much harder if you had to write the image processing code for the entities since you'd either have to support lots of different formats (impractical) or limit yourself to just a few.
Quoted 54 lines
Signed-off-by Helen Fornazier <[email protected]>--- drivers/media/platform/vimc/Kconfig | 1 + drivers/media/platform/vimc/vimc-sensor.c | 44 +++++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 2 deletions(-)drivers/media/platform/vimc/Kconfig +1
-0@@ -1,6 +1,7 @@ config VIDEO_VIMC tristate "Virtual Media Controller Driver (VIMC)" select VIDEO_V4L2_SUBDEV_API + select VIDEO_TPG default n ---help--- Skeleton driver for Virtual Media Controllerdrivers/media/platform/vimc/vimc-sensor.c +11
-0@@ -16,15 +16,19 @@*/ #include <linux/freezer.h> +#include <media/tpg.h> #include <linux/vmalloc.h> #include <linux/v4l2-mediabus.h> #include <media/v4l2-subdev.h> #include "vimc-sensor.h" +#define VIMC_SEN_FRAME_MAX_WIDTH 4096 +struct vimc_sen_device {struct vimc_ent_device ved;struct v4l2_subdev sd; +struct tpg_data tpg;struct v4l2_device *v4l2_dev;struct device *dev;struct task_struct *kthread_sen;@@ -87,6 +91,29 @@ static int vimc_sen_get_fmt(struct v4l2_subdev *sd,return 0 ; } +static void vimc_sen_tpg_s_format (struct vimc_sen_device *vsen) +{ +const struct vimc_pix_map *vpix; + + vpix =vimc_pix_map_by_code (vsen->mbus_format.code); +/* This should never be NULL, as we won't allow any format other then +* the ones in the vimc_pix_map_list table */ drivers/media/platform/vimc/vimc-sensor.c static int vimc_sen_get_fmt(struct v4l2_subdev *sd, · line 110
Quoted 10 lines
drivers/media/platform/vimc/vimc-sensor.c +10
-0+BUG_ON (!vpix); + +tpg_s_bytesperline (&vsen->tpg,0 , + vsen->mbus_format.width * vpix->bpp); +tpg_s_buf_height (&vsen->tpg, vsen->mbus_format.height); +tpg_s_fourcc (&vsen->tpg, vpix->pixelformat); +/* TODO: check why the tpg_s_field need this third argument if +* it is already receiving the field */ +tpg_s_field (&vsen->tpg, vsen->mbus_format.field, + vsen->mbus_format.field ==V4L2_FIELD_ALTERNATE );Actually the second argument argument cannot be
FIELD_ALTERNATE. If it is field ALTERNATE, then the second argument must be eitherFIELD_TOPorFIELD_BOTTOM: i.e. it tells the generator which field comes first in theFIELD_ALTERNATEcase.
Quoted 2 lines
And in case you are wondering: it's always
FIELD_TOPexcept for 60 Hz SDTV formats where it isFIELD_BOTTOM.
I am not really familiar to SDTV, but it seems to me to be a different structure API. Thus can I put FIELD_TOP directly in the second argument?
tpg_s_field(&vsen->tpg, V4L2_FIELD_TOP,
vsen->mbus_format.field == V4L2_FIELD_ALTERNATE);
Or is there a way to check if the format is SDTV? I didn't find it defined on V4L2_PIX_FMT_
Quoted 64 lines
Quoted 50 lines
drivers/media/platform/vimc/vimc-sensor.c +18
-2+tpg_s_colorspace (&vsen->tpg, vsen->mbus_format.colorspace); +tpg_s_ycbcr_enc (&vsen->tpg, vsen->mbus_format.ycbcr_enc); +tpg_s_quantization (&vsen->tpg, vsen->mbus_format.quantization); +tpg_s_xfer_func (&vsen->tpg, vsen->mbus_format.xfer_func); +} +static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = { .enum_mbus_code = vimc_sen_enum_mbus_code, .enum_frame_size = vimc_sen_enum_frame_size,@@ -112,7 +139,7 @@ static int vimc_thread_sen(void *data)if (kthread_should_stop ())break ; -memset (vsen->frame,100 , vsen->frame_size); +tpg_fill_plane_buffer (&vsen->tpg,V4L2_STD_PAL ,0 , vsen->frame);/* Send the frame to all source pads */ for (i =0 ; i < vsen->sd.entity.num_pads; i++)@@ -192,6 +219,7 @@ static void vimc_sen_destroy(struct vimc_ent_device *ved)struct vimc_sen_device *vsen =container_of (ved, struct vimc_sen_device, ved); +tpg_free (&vsen->tpg);media_entity_cleanup (ved->ent);v4l2_device_unregister_subdev (&vsen->sd);kfree (vsen);@@ -242,6 +270,16 @@ struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, vsen->mbus_format.quantization =V4L2_QUANTIZATION_FULL_RANGE ; vsen->mbus_format.xfer_func =V4L2_XFER_FUNC_SRGB ; +/* Initialize the test pattern generator */ +tpg_init (&vsen->tpg, vsen->mbus_format.width, + vsen->mbus_format.height); + ret =tpg_alloc (&vsen->tpg,VIMC_SEN_FRAME_MAX_WIDTH ); +if (ret) + goto err_clean_m_ent; + +/* Configure the tpg */ +vimc_sen_tpg_s_format (vsen); +/* Fill the vimc_ent_device struct */ vsen->ved.destroy = vimc_sen_destroy; vsen->ved.ent = &vsen->sd.entity;@@ -261,11 +299,13 @@ struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev,if (ret) {dev_err (vsen->dev,"subdev register failed (err=%d)\n" , ret); - goto err_clean_m_ent;drivers/media/platform/vimc/vimc-sensor.c struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, · line 311
Quoted 10 lines
drivers/media/platform/vimc/vimc-sensor.c +3
-0+ goto err_free_tpg; }return &vsen->ved; +err_free_tpg: +tpg_free (&vsen->tpg); err_clean_m_ent:media_entity_cleanup (&vsen->sd.entity); err_clean_pads:Regards,
Hans
Signature · 1 line
Helen Fornazier
PATCH 3/7 vimc: Add vimc_ent_sd_init/cleanup helper functions
In reply to Helen FornazierAs all the subdevices in the topology will be initialized in the same way, to avoid code repetition the vimc_ent_sd_init/cleanup helper functions were created
--- drivers/media/platform/vimc/vimc-core.c | 76 ++++++++++++++++++++++ drivers/media/platform/vimc/vimc-core.h | 17 +++++ drivers/media/platform/vimc/vimc-sensor.c | 104 +++++++++--------------------- 3 files changed, 123 insertions(+), 74 deletions(-)
drivers/media/platform/vimc/vimc-core.c +76 -0
@@ -332,6 +332,82 @@ struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag)return pads; } +/* media operations */ +static const struct media_entity_operations vimc_ent_sd_mops = { + .link_validate = v4l2_subdev_link_validate, +}; + +void vimc_ent_sd_cleanup (struct vimc_ent_subdevice *vsd) +{ +media_entity_cleanup (vsd->ved.ent); +v4l2_device_unregister_subdev (&vsd->sd); +kfree (vsd); +} + +struct vimc_ent_subdevice *vimc_ent_sd_init (size_t struct_size, +struct v4l2_device *v4l2_dev, +const char *const name, +u16 num_pads, +const unsigned long *pads_flag, +const struct v4l2_subdev_ops *sd_ops, +void (*sd_destroy)(struct vimc_ent_device *)) +{ +int ret; +struct vimc_ent_subdevice *vsd; + +if (!v4l2_dev || !v4l2_dev->dev || !name || (num_pads && !pads_flag)) +return ERR_PTR (-EINVAL ); + +/* Allocate the vsd struct */ + vsd =kzalloc (struct_size,GFP_KERNEL ); +if (!vsd) +return ERR_PTR (-ENOMEM ); + +/* Link the vimc_deb_device struct with the v4l2 parent */ + vsd->v4l2_dev = v4l2_dev; +/* Link the vimc_deb_device struct with the dev parent */ + vsd->dev = v4l2_dev->dev; + +/* Allocate the pads */ + vsd->ved.pads =vimc_pads_init (num_pads, pads_flag); +if (IS_ERR (vsd->ved.pads)) { + ret =PTR_ERR (vsd->ved.pads); + goto err_free_vsd; + } + +/* Initialize the media entity */ + vsd->sd.entity.name = name; + vsd->sd.entity.type =MEDIA_ENT_T_V4L2_SUBDEV ; + ret =media_entity_init (&vsd->sd.entity, num_pads, + vsd->ved.pads, num_pads); +if (ret) + goto err_clean_pads; + +/* Fill the vimc_ent_device struct */ + vsd->ved.destroy = sd_destroy; + vsd->ved.ent = &vsd->sd.entity; + +/* Initialize the subdev */ +v4l2_subdev_init (&vsd->sd, sd_ops); + vsd->sd.entity.ops = &vimc_ent_sd_mops; + vsd->sd.owner =THIS_MODULE ; +strlcpy (vsd->sd.name, name,sizeof (vsd->sd.name)); +v4l2_set_subdevdata (&vsd->sd, vsd); + +/* Expose this subdev to user space */ + vsd->sd.flags =V4L2_SUBDEV_FL_HAS_DEVNODE ; + +/* return the created vimc subdevice*/ +return vsd; + +err_clean_pads: +vimc_pads_cleanup (vsd->ved.pads); +err_free_vsd: +kfree (vsd); + +return ERR_PTR (ret); +} +/* TODO: remove this function when all the * entities specific code are implemented */ static void vimc_raw_destroy (struct vimc_ent_device *ved)
drivers/media/platform/vimc/vimc-core.h +17 -0
@@ -37,6 +37,13 @@ struct vimc_ent_device { struct media_pad *sink, const void *frame); }; +struct vimc_ent_subdevice { +struct vimc_ent_device ved; +struct v4l2_subdev sd; +struct v4l2_device *v4l2_dev; +struct device *dev; +}; +int vimc_propagate_frame (struct device *dev,struct media_pad *src,const void *frame);
@@ -48,6 +55,16 @@ static inline void vimc_pads_cleanup(struct media_pad *pads)kfree (pads); } +/* Helper function to initialize/cleanup a subdevice used */ +struct vimc_ent_subdevice *vimc_ent_sd_init (size_t struct_size, +struct v4l2_device *v4l2_dev, +const char *const name, +u16 num_pads, +const unsigned long *pads_flag, +const struct v4l2_subdev_ops *sd_ops, +void (*sd_destroy)(struct vimc_ent_device *)); +void vimc_ent_sd_cleanup (struct vimc_ent_subdevice *vsd); +const struct vimc_pix_map *vimc_pix_map_by_code (u32 code);const struct vimc_pix_map *vimc_pix_map_by_pixelformat (u32 pixelformat);
drivers/media/platform/vimc/vimc-sensor.c +30 -74
177 lines not on this page · raw message
Signature · 1 line
1.9.1
Re: [PATCH 3/7] [media] vimc: Add vimc_ent_sd_init/cleanup helper functions
Hi Helen,
Thank you for the patch.
Quoted 18 lines · On Thursday 06 August 2015 17:26:10 Helen Fornazier wrote:
As all the subdevices in the topology will be initialized in the same way, to avoid code repetition the vimc_ent_sd_init/cleanup helper functions were created
Signed-off-by Helen Fornazier <[email protected]>--- drivers/media/platform/vimc/vimc-core.c | 76 ++++++++++++++++++++++ drivers/media/platform/vimc/vimc-core.h | 17 +++++ drivers/media/platform/vimc/vimc-sensor.c | 104 ++++++++------------------ 3 files changed, 123 insertions(+), 74 deletions(-)(quoted diff) +0
-0
b/drivers/media/platform/vimc/vimc-core.cindex 3ef9b51..96d53fd 100644drivers/media/platform/vimc/vimc-core.c +0
-0@@ -332,6 +332,82 @@ struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag) return pads; }
drivers/media/platform/vimc/vimc-core.c struct media_pad *vimc_pads_init(u16 num_pads, const · line 343
Quoted 10 lines
drivers/media/platform/vimc/vimc-core.c +9
-0+/* media operations */ +static const struct media_entity_operations vimc_ent_sd_mops = { + .link_validate = v4l2_subdev_link_validate, +}; + +void vimc_ent_sd_cleanup (struct vimc_ent_subdevice *vsd) +{ +media_entity_cleanup (vsd->ved.ent); +v4l2_device_unregister_subdev (&vsd->sd);
v4l2_device_unregister_subdev() calls media_entity_remove_links() and media_device_unregister_entity(), so it would be better to call media_entity_cleanup() after v4l2_device_unregister_subdev().
Quoted 9 lines
drivers/media/platform/vimc/vimc-core.c +9
-0+kfree (vsd); +} + +struct vimc_ent_subdevice *vimc_ent_sd_init(size_t struct_size, + struct v4l2_device *v4l2_dev, + const char *const name, + u16 num_pads, + const unsigned long *pads_flag, + const struct v4l2_subdev_ops *sd_ops,
drivers/media/platform/vimc/vimc-core.c struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag) · line 362
Quoted 10 lines
drivers/media/platform/vimc/vimc-core.c +10
-0+ void (*sd_destroy)(struct vimc_ent_device *)) +{ +int ret; +struct vimc_ent_subdevice *vsd; + +if (!v4l2_dev || !v4l2_dev->dev || !name || (num_pads && !pads_flag)) +return ERR_PTR (-EINVAL ); + +/* Allocate the vsd struct */ + vsd =kzalloc (struct_size,GFP_KERNEL );
This requires vimc_ent_subdevice being embedded as the first field of the parent structure, which restricts options for the code using this API. If you were implementing a subsystem API I'd ask for the allocation to happen outside of this function, with the vimc_ent_subdevice pointer being passed to the function. However, as this is local to the vimc driver, if you believe it won't be an issue in the foreseeable future then I'm fine with the implementation.
By the way, such core functions should really be documented with a kerneldoc comment block. Requirements such as the embedding field position isn't very apparent when you glance at the code and would benefit from being documented.
Quoted 56 lines
drivers/media/platform/vimc/vimc-core.c +48
-0+if (!vsd) +return ERR_PTR (-ENOMEM ); + +/* Link the vimc_deb_device struct with the v4l2 parent */ + vsd->v4l2_dev = v4l2_dev; +/* Link the vimc_deb_device struct with the dev parent */ + vsd->dev = v4l2_dev->dev; + +/* Allocate the pads */ + vsd->ved.pads =vimc_pads_init (num_pads, pads_flag); +if (IS_ERR (vsd->ved.pads)) { + ret =PTR_ERR (vsd->ved.pads); + goto err_free_vsd; + } + +/* Initialize the media entity */ + vsd->sd.entity.name = name; + vsd->sd.entity.type =MEDIA_ENT_T_V4L2_SUBDEV ; + ret =media_entity_init (&vsd->sd.entity, num_pads, + vsd->ved.pads, num_pads); +if (ret) + goto err_clean_pads; + +/* Fill the vimc_ent_device struct */ + vsd->ved.destroy = sd_destroy; + vsd->ved.ent = &vsd->sd.entity; + +/* Initialize the subdev */ +v4l2_subdev_init (&vsd->sd, sd_ops); + vsd->sd.entity.ops = &vimc_ent_sd_mops; + vsd->sd.owner =THIS_MODULE ; +strlcpy (vsd->sd.name, name,sizeof (vsd->sd.name)); +v4l2_set_subdevdata (&vsd->sd, vsd); + +/* Expose this subdev to user space */ + vsd->sd.flags =V4L2_SUBDEV_FL_HAS_DEVNODE ; + +/* return the created vimc subdevice*/ +return vsd; + +err_clean_pads: +vimc_pads_cleanup (vsd->ved.pads); +err_free_vsd: +kfree (vsd); + +return ERR_PTR (ret); +} +/* TODO: remove this function when all the * entities specific code are implemented */ static void vimc_raw_destroy (struct vimc_ent_device *ved)(quoted diff) +0
-0
b/drivers/media/platform/vimc/vimc-core.hindex be05469..295a554 100644
drivers/media/platform/vimc/vimc-core.h struct vimc_ent_device { · line 43
Quoted 7 lines
drivers/media/platform/vimc/vimc-core.h +4
-0@@ -37,6 +37,13 @@ struct vimc_ent_device { struct media_pad *sink, const void *frame); }; +struct vimc_ent_subdevice { +struct vimc_ent_device ved; +struct v4l2_subdev sd; +struct v4l2_device *v4l2_dev;
Given that struct v4l2_subdev stores a pointer to the same struct v4l2_device, can't you get rid of this field and use the one inside v4l2_subdev instead ?
drivers/media/platform/vimc/vimc-core.h struct vimc_ent_device { · line 44
Quoted 1 line
drivers/media/platform/vimc/vimc-core.h +1
-0+struct device *dev;
Similarly you could get the struct device from sd.v4l2_dev->mdev->dev. That might become a bit long though, so I'm fine keeping the field here for now.
Quoted 213 lines
drivers/media/platform/vimc/vimc-core.h +12
-0+}; +int vimc_propagate_frame (struct device *dev,struct media_pad *src,const void *frame);@@ -48,6 +55,16 @@ static inline void vimc_pads_cleanup(struct media_pad *pads) kfree(pads); } +/* Helper function to initialize/cleanup a subdevice used */ +struct vimc_ent_subdevice *vimc_ent_sd_init (size_t struct_size, +struct v4l2_device *v4l2_dev, +const char *const name, +u16 num_pads, +const unsigned long *pads_flag, +const struct v4l2_subdev_ops *sd_ops, +void (*sd_destroy)(struct vimc_ent_device *)); +void vimc_ent_sd_cleanup (struct vimc_ent_subdevice *vsd); +const struct vimc_pix_map *vimc_pix_map_by_code (u32 code);const struct vimc_pix_map *vimc_pix_map_by_pixelformat (u32 pixelformat);(quoted diff) +0
-0
b/drivers/media/platform/vimc/vimc-sensor.cindex a2879ad..319bebb 100644drivers/media/platform/vimc/vimc-sensor.c +14
-19@@ -26,11 +26,8 @@#define VIMC_SEN_FRAME_MAX_WIDTH 4096struct vimc_sen_device { -struct vimc_ent_device ved; -struct v4l2_subdev sd; +struct vimc_ent_subdevice vsd;struct tpg_data tpg; -struct v4l2_device *v4l2_dev; -struct device *dev;struct task_struct *kthread_sen;u8 *frame;/* The active format */ @@ -45,7 +42,7 @@ static int vimc_sen_enum_mbus_code(struct v4l2_subdev *sd,struct vimc_sen_device *vsen =v4l2_get_subdevdata (sd);/* Check if it is a valid pad */ -if (code->pad >= vsen->sd.entity.num_pads) +if (code->pad >= vsen->vsd.sd.entity.num_pads)return -EINVAL ; code->code = vsen->mbus_format.code;@@ -60,8 +57,8 @@ static int vimc_sen_enum_frame_size(struct v4l2_subdev *sd, struct vimc_sen_device *vsen = v4l2_get_subdevdata(sd);/* Check if it is a valid pad */ -if (fse->pad >= vsen->sd.entity.num_pads || - !(vsen->sd.entity.pads[fse->pad].flags &MEDIA_PAD_FL_SOURCE )) +if (fse->pad >= vsen->vsd.sd.entity.num_pads || + !(vsen->vsd.sd.entity.pads[fse->pad].flags &MEDIA_PAD_FL_SOURCE ))return -EINVAL ;/* TODO: Add support to other formats */ @@ -122,11 +119,6 @@ static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = { .set_fmt = vimc_sen_get_fmt, }; -/* media operations */ -static const struct media_entity_operations vimc_sen_mops = { - .link_validate = v4l2_subdev_link_validate, -}; -static int vimc_thread_sen (void *data) {unsigned int i;@@ -142,11 +134,13 @@ static int vimc_thread_sen(void *data)tpg_fill_plane_buffer (&vsen->tpg,V4L2_STD_PAL ,0 , vsen->frame);/* Send the frame to all source pads */ -for (i =0 ; i < vsen->sd.entity.num_pads; i++) -if (vsen->sd.entity.pads[i].flags &MEDIA_PAD_FL_SOURCE ) -vimc_propagate_frame (vsen->dev, - &vsen->sd.entity.pads[i], - vsen->frame); +for (i =0 ; i < vsen->vsd.sd.entity.num_pads; i++) { +struct media_pad *pad = &vsen->vsd.sd.entity.pads[i]; + +if (pad->flags &MEDIA_PAD_FL_SOURCE ) +vimc_propagate_frame (vsen->vsd.dev, + pad, vsen->frame); + }/* Wait one second */ schedule_timeout_interruptible (HZ );@@ -182,9 +176,10 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable)/* Initialize the image generator thread */ vsen->kthread_sen = kthread_run(vimc_thread_sen, vsen, -"%s-sen" , vsen->v4l2_dev->name); +"%s-sen" , vsen->vsd.v4l2_dev->name);if (IS_ERR (vsen->kthread_sen)) { -v4l2_err (vsen->v4l2_dev,"kernel_thread() failed\n" ); +v4l2_err (vsen->vsd.v4l2_dev, +"kernel_thread() failed\n" );vfree (vsen->frame); vsen->frame =NULL ;drivers/media/platform/vimc/vimc-sensor.c +16
-55return PTR_ERR (vsen->kthread_sen);@@ -216,13 +211,11 @@ static const struct v4l2_subdev_ops vimc_sen_ops = {static void vimc_sen_destroy (struct vimc_ent_device *ved) { -struct vimc_sen_device *vsen =container_of (ved, - struct vimc_sen_device, ved); + struct vimc_sen_device *vsen = container_of(ved, struct vimc_sen_device, + vsd.ved);tpg_free (&vsen->tpg); -media_entity_cleanup (ved->ent); -v4l2_device_unregister_subdev (&vsen->sd); -kfree (vsen); +vimc_ent_sd_cleanup (&vsen->vsd); } struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev,@@ -232,34 +225,15 @@ struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, { int ret;struct vimc_sen_device *vsen; +struct vimc_ent_subdevice *vsd; -if (!v4l2_dev || !v4l2_dev->dev || !name || (num_pads && !pads_flag)) -return ERR_PTR (-EINVAL ); - -/* Allocate the vsen struct */ - vsen =kzalloc (sizeof (*vsen),GFP_KERNEL ); -if (!vsen) -return ERR_PTR (-ENOMEM ); - -/* Link the vimc_sen_device struct with the v4l2 parent */ - vsen->v4l2_dev = v4l2_dev; -/* Link the vimc_sen_device struct with the dev parent */ - vsen->dev = v4l2_dev->dev; + vsd =vimc_ent_sd_init (sizeof (struct vimc_sen_device ), + v4l2_dev, name, num_pads, pads_flag, + &vimc_sen_ops, vimc_sen_destroy); +if (IS_ERR (vsd)) +return (struct vimc_ent_device *)vsd; -/* Allocate the pads */ - vsen->ved.pads =vimc_pads_init (num_pads, pads_flag); -if (IS_ERR (vsen->ved.pads)) { - ret =PTR_ERR (vsen->ved.pads); - goto err_free_vsen; - } - -/* Initialize the media entity */ - vsen->sd.entity.name = name; - vsen->sd.entity.type =MEDIA_ENT_T_V4L2_SUBDEV ; - ret =media_entity_init (&vsen->sd.entity, num_pads, - vsen->ved.pads, num_pads); -if (ret) - goto err_clean_pads; + vsen = container_of(vsd, struct vimc_sen_device, vsd);/* Set the active frame format (this is hardcoded for now) */ vsen->mbus_format.width =640 ;@@ -275,43 +249,25 @@ struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, vsen->mbus_format.height); ret =tpg_alloc (&vsen->tpg,VIMC_SEN_FRAME_MAX_WIDTH );if (ret) - goto err_clean_m_ent; + goto err_clean_vsd;/* Configure the tpg */ vimc_sen_tpg_s_format (vsen); -/* Fill the vimc_ent_device struct */ - vsen->ved.destroy = vimc_sen_destroy; - vsen->ved.ent = &vsen->sd.entity; - -/* Initialize the subdev */ -v4l2_subdev_init (&vsen->sd, &vimc_sen_ops); - vsen->sd.entity.ops = &vimc_sen_mops; - vsen->sd.owner =THIS_MODULE ; -strlcpy (vsen->sd.name, name,sizeof (vsen->sd.name)); -v4l2_set_subdevdata (&vsen->sd, vsen); - -/* Expose this subdev to user space */ - vsen->sd.flags =V4L2_SUBDEV_FL_HAS_DEVNODE ; -/* Register the subdev with the v4l2 and the media framework */ - ret =v4l2_device_register_subdev (vsen->v4l2_dev, &vsen->sd); + ret =v4l2_device_register_subdev (vsen->vsd.v4l2_dev, &vsen->vsd.sd);if (ret) { -dev_err (vsen->dev, +dev_err (vsen->vsd.dev,"subdev register failed (err=%d)\n" , ret); goto err_free_tpg; } -return &vsen->ved; +return &vsen->vsd.ved; err_free_tpg:tpg_free (&vsen->tpg); -err_clean_m_ent: -media_entity_cleanup (&vsen->sd.entity); -err_clean_pads: -vimc_pads_cleanup (vsen->ved.pads); -err_free_vsen: -kfree (vsen); +err_clean_vsd: +vimc_ent_sd_cleanup (vsd);return ERR_PTR (ret); }
Signature · 3 lines
Regards, Laurent Pinchart
PATCH 4/7 vimc: Add vimc_pipeline_s_stream in the core
In reply to Helen FornazierMove the vimc_cap_pipeline_s_stream from the vimc-cap.c to vimc-core.c as this core will be reused by other subdevices to activate the stream in their directly connected nodes
--- drivers/media/platform/vimc/vimc-capture.c | 32 ++---------------------------- drivers/media/platform/vimc/vimc-core.c | 27 +++++++++++++++++++++++++ drivers/media/platform/vimc/vimc-core.h | 4 ++++ 3 files changed, 33 insertions(+), 30 deletions(-)
drivers/media/platform/vimc/vimc-capture.c +2 -30
@@ -163,34 +163,6 @@ static void vimc_cap_return_all_buffers(struct vimc_cap_device *vcap,spin_unlock (&vcap->qlock); } -static int vimc_cap_pipeline_s_stream (struct vimc_cap_device *vcap,int enable) -{ -int ret; -struct media_pad *pad; -struct media_entity *entity; -struct v4l2_subdev *sd; - -/* Start the stream in the subdevice direct connected */ - entity = &vcap->vdev.entity; - pad =media_entity_remote_pad (&entity->pads[0 ]); - -/* If we are not connected to any subdev node, it means there is nothing -* to activate on the pipe (e.g. we can be connected with an input -* device or we are not connected at all)*/ -if (pad ==NULL || -media_entity_type (pad->entity) !=MEDIA_ENT_T_V4L2_SUBDEV ) -return 0 ; - - entity = pad->entity; - sd =media_entity_to_v4l2_subdev (entity); - - ret =v4l2_subdev_call (sd, video, s_stream, enable); -if (ret && ret != -ENOIOCTLCMD ) -return ret; - -return 0 ; -} -static int vimc_cap_start_streaming (struct vb2_queue *vq,unsigned int count) {struct vimc_cap_device *vcap =vb2_get_drv_priv (vq);
@@ -208,7 +180,7 @@ static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count) }/* Enable streaming from the pipe */ - ret =vimc_cap_pipeline_s_stream (vcap,1 ); + ret =vimc_pipeline_s_stream (&vcap->vdev.entity,1 );if (ret) {vimc_cap_return_all_buffers (vcap,VB2_BUF_STATE_QUEUED );return ret;
@@ -226,7 +198,7 @@ static void vimc_cap_stop_streaming(struct vb2_queue *vq)struct vimc_cap_device *vcap =vb2_get_drv_priv (vq);/* Disable streaming from the pipe */ -vimc_cap_pipeline_s_stream (vcap,0 ); +vimc_pipeline_s_stream (&vcap->vdev.entity,0 );/* Stop the media pipeline */ media_entity_pipeline_stop (&vcap->vdev.entity);
drivers/media/platform/vimc/vimc-core.c +27 -0
@@ -312,6 +312,33 @@ static void vimc_device_unregister(struct vimc_device *vimc) } } +int vimc_pipeline_s_stream (struct media_entity *entity,int enable) +{ +int ret; +struct media_pad *pad; +struct v4l2_subdev *sd; + +/* Start the stream in the subdevice direct connected */ +/* TODO: do this to all pads */ + pad =media_entity_remote_pad (&entity->pads[0 ]); + +/* If we are not connected to any subdev node, it means there is nothing +* to activate on the pipe (e.g. we can be connected with an input +* device or we are not connected at all)*/ +if (pad ==NULL || +media_entity_type (pad->entity) !=MEDIA_ENT_T_V4L2_SUBDEV ) +return 0 ; + + entity = pad->entity; + sd =media_entity_to_v4l2_subdev (entity); + + ret =v4l2_subdev_call (sd, video, s_stream, enable); +if (ret && ret != -ENOIOCTLCMD ) +return ret; + +return 0 ; +} +/* Helper function to allocate and initialize pads */ struct media_pad *vimc_pads_init (u16 num_pads,const unsigned long *pads_flag) {
drivers/media/platform/vimc/vimc-core.h +4 -0
@@ -65,6 +65,10 @@ struct vimc_ent_subdevice *vimc_ent_sd_init(size_t struct_size, void (*sd_destroy)(struct vimc_ent_device *));void vimc_ent_sd_cleanup (struct vimc_ent_subdevice *vsd); +/* Helper function to call the s_stream of the subdevice +* directly connected with entity*/ +int vimc_pipeline_s_stream (struct media_entity *entity,int enable); +const struct vimc_pix_map *vimc_pix_map_by_code (u32 code);const struct vimc_pix_map *vimc_pix_map_by_pixelformat (u32 pixelformat);
Signature · 1 line
1.9.1
Re: [PATCH 4/7] [media] vimc: Add vimc_pipeline_s_stream in the core
Hi Helen,
Thank you for the patch.
Quoted 80 lines · On Thursday 06 August 2015 17:26:11 Helen Fornazier wrote:
Move the
vimc_cap_pipeline_s_streamfrom thevimc-cap.ctovimc-core.cas this core will be reused by other subdevices to activate the stream in their directly connected nodesSigned-off-by Helen Fornazier <[email protected]>--- drivers/media/platform/vimc/vimc-capture.c | 32 ++------------------------ drivers/media/platform/vimc/vimc-core.c | 27 +++++++++++++++++++++++++ drivers/media/platform/vimc/vimc-core.h | 4 ++++ 3 files changed, 33 insertions(+), 30 deletions(-)(quoted diff) +0
-0
b/drivers/media/platform/vimc/vimc-capture.cindex 161ddc9..7d21966 100644drivers/media/platform/vimc/vimc-capture.c +0
-28@@ -163,34 +163,6 @@ static void vimc_cap_return_all_buffers(struct vimc_cap_device *vcap,spin_unlock (&vcap->qlock); } -static int vimc_cap_pipeline_s_stream (struct vimc_cap_device *vcap,int enable) -{ -int ret; -struct media_pad *pad; -struct media_entity *entity; -struct v4l2_subdev *sd; - -/* Start the stream in the subdevice direct connected */ - entity = &vcap->vdev.entity; - pad =media_entity_remote_pad (&entity->pads[0 ]); - -/* If we are not connected to any subdev node, it means there is nothing -* to activate on the pipe (e.g. we can be connected with an input -* device or we are not connected at all)*/ -if (pad ==NULL || -media_entity_type (pad->entity) !=MEDIA_ENT_T_V4L2_SUBDEV ) -return 0 ; - - entity = pad->entity; - sd =media_entity_to_v4l2_subdev (entity); - - ret =v4l2_subdev_call (sd, video, s_stream, enable); -if (ret && ret != -ENOIOCTLCMD ) -return ret; - -return 0 ; -} - static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count) {drivers/media/platform/vimc/vimc-capture.c +2
-2struct vimc_cap_device *vcap =vb2_get_drv_priv (vq);@@ -208,7 +180,7 @@ static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count) }/* Enable streaming from the pipe */ - ret =vimc_cap_pipeline_s_stream (vcap,1 ); + ret =vimc_pipeline_s_stream (&vcap->vdev.entity,1 );if (ret) {vimc_cap_return_all_buffers (vcap,VB2_BUF_STATE_QUEUED );return ret;@@ -226,7 +198,7 @@ static void vimc_cap_stop_streaming(struct vb2_queue *vq) struct vimc_cap_device *vcap = vb2_get_drv_priv(vq);/* Disable streaming from the pipe */ -vimc_cap_pipeline_s_stream (vcap,0 ); +vimc_pipeline_s_stream (&vcap->vdev.entity,0 );/* Stop the media pipeline */ media_entity_pipeline_stop (&vcap->vdev.entity);(quoted diff) +0
-0
b/drivers/media/platform/vimc/vimc-core.cindex 96d53fd..a824b31 100644drivers/media/platform/vimc/vimc-core.c +3
-0@@ -312,6 +312,33 @@ static void vimc_device_unregister(struct vimc_device *vimc) } } +int vimc_pipeline_s_stream (struct media_entity *entity,int enable) +{ +int ret;
drivers/media/platform/vimc/vimc-core.c static void vimc_device_unregister(struct vimc_device · line 327
Quoted 10 lines
drivers/media/platform/vimc/vimc-core.c +10
-0+struct media_pad *pad; +struct v4l2_subdev *sd; + +/* Start the stream in the subdevice direct connected */ +/* TODO: do this to all pads */ + pad =media_entity_remote_pad (&entity->pads[0 ]); + +/* If we are not connected to any subdev node, it means there is nothing +* to activate on the pipe (e.g. we can be connected with an input +* device or we are not connected at all)*/
I know this patch just moves code, but I still want to point out that the kernel coding style closes comment blocks on a separate line
/*
* ...
* ...
*/
Quoted 22 lines
drivers/media/platform/vimc/vimc-core.c +14
-0+if (pad ==NULL || +media_entity_type (pad->entity) !=MEDIA_ENT_T_V4L2_SUBDEV ) +return 0 ; + + entity = pad->entity; + sd =media_entity_to_v4l2_subdev (entity); + + ret =v4l2_subdev_call (sd, video, s_stream, enable); +if (ret && ret != -ENOIOCTLCMD ) +return ret; + +return 0 ; +} +/* Helper function to allocate and initialize pads */ struct media_pad *vimc_pads_init (u16 num_pads,const unsigned long *pads_flag) {(quoted diff) +0
-0
b/drivers/media/platform/vimc/vimc-core.hindex 295a554..38d4855 100644
drivers/media/platform/vimc/vimc-core.h struct vimc_ent_subdevice *vimc_ent_sd_init(size_t · line 69
Quoted 5 lines
drivers/media/platform/vimc/vimc-core.h +2
-0@@ -65,6 +65,10 @@ struct vimc_ent_subdevice *vimc_ent_sd_init(size_t struct_size, void (*sd_destroy)(struct vimc_ent_device *));void vimc_ent_sd_cleanup (struct vimc_ent_subdevice *vsd); +/* Helper function to call the s_stream of the subdevice +* directly connected with entity*/
This belongs to a kerneldoc comment block right above the function definition in vimc-core.c.
Quoted 5 lines
drivers/media/platform/vimc/vimc-core.h +2
-0+int vimc_pipeline_s_stream (struct media_entity *entity,int enable); +const struct vimc_pix_map *vimc_pix_map_by_code (u32 code);const struct vimc_pix_map *vimc_pix_map_by_pixelformat (u32 pixelformat);
Signature · 3 lines
Regards, Laurent Pinchart
PATCH 5/7 vimc: deb: Add debayer filter
In reply to Helen FornazierImplement the debayer filter and integrate it with the core
--- drivers/media/platform/vimc/Makefile | 2 +- drivers/media/platform/vimc/vimc-core.c | 6 +- drivers/media/platform/vimc/vimc-core.h | 2 + drivers/media/platform/vimc/vimc-debayer.c | 471 +++++++++++++++++++++++++++++ drivers/media/platform/vimc/vimc-debayer.h | 28 ++ 5 files changed, 507 insertions(+), 2 deletions(-) create mode 100644 drivers/media/platform/vimc/vimc-debayer.c create mode 100644 drivers/media/platform/vimc/vimc-debayer.h
drivers/media/platform/vimc/Makefile +1 -1
@@ -1,3 +1,3 @@ -vimc-objs := vimc-core.o vimc-capture.o vimc-sensor.o +vimc-objs := vimc-core.o vimc-capture.o vimc-debayer.o vimc-sensor.o obj-$(CONFIG_VIDEO_VIMC) += vimc.o
drivers/media/platform/vimc/vimc-core.c +5 -1
@@ -24,6 +24,7 @@#include "vimc-capture.h" #include "vimc-core.h" +#include "vimc-debayer.h" #include "vimc-sensor.h" #define VIMC_PDEV_NAME "vimc"
@@ -552,9 +553,12 @@ static int vimc_device_register(struct vimc_device *vimc) create_func = vimc_cap_create;break ; +case VIMC_ENT_NODE_DEBAYER : + create_func = vimc_deb_create; +break ; +/* TODO: Instantiate the specific topology node */ case VIMC_ENT_NODE_INPUT : -case VIMC_ENT_NODE_DEBAYER :case VIMC_ENT_NODE_SCALER :default :/* TODO: remove this when all the entities specific
drivers/media/platform/vimc/vimc-core.h +2 -0
@@ -20,6 +20,8 @@#include <media/v4l2-device.h> +#define VIMC_FRAME_INDEX (lin, col, width, bpp) ((lin * width + col) * bpp) +/* Struct which matches the MEDIA_BUS_FMT_ codes with the corresponding * V4L2_PIX_FMT_ fourcc pixelformat and its bytes per pixel (bpp) */ struct vimc_pix_map {
drivers/media/platform/vimc/vimc-debayer.c new file +471 -0
471 lines not on this page · raw message
drivers/media/platform/vimc/vimc-debayer.h new file +28 -0
@@ -0,0 +1,28 @@ +/* +* vimc-debayer.h Virtual Media Controller Driver +* +* Copyright (C) 2015 Helen Fornazier <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#ifndef _VIMC_DEBAYER_H_ +#define _VIMC_DEBAYER_H_ + +#include "vimc-core.h" + +struct vimc_ent_device *vimc_deb_create (struct v4l2_device *v4l2_dev, +const char *const name, +u16 num_pads, +const unsigned long *pads_flag); + +#endif
Signature · 1 line
1.9.1
Re: [PATCH 5/7] [media] vimc: deb: Add debayer filter
Hi Helen,
Thank you for the patch.
Quoted 82 lines · On Thursday 06 August 2015 17:26:12 Helen Fornazier wrote:
Implement the debayer filter and integrate it with the core
Signed-off-by Helen Fornazier <[email protected]>--- drivers/media/platform/vimc/Makefile | 2 +- drivers/media/platform/vimc/vimc-core.c | 6 +- drivers/media/platform/vimc/vimc-core.h | 2 + drivers/media/platform/vimc/vimc-debayer.c | 471 ++++++++++++++++++++++++++ drivers/media/platform/vimc/vimc-debayer.h | 28 ++ 5 files changed, 507 insertions(+), 2 deletions(-) create mode 100644 drivers/media/platform/vimc/vimc-debayer.c create mode 100644 drivers/media/platform/vimc/vimc-debayer.h(quoted diff) +0
-0b/drivers/media/platform/vimc/Makefile index c45195e..a6708f9 100644
drivers/media/platform/vimc/Makefile +1
-1@@ -1,3 +1,3 @@ -vimc-objs := vimc-core.o vimc-capture.o vimc-sensor.o +vimc-objs := vimc-core.o vimc-capture.o vimc-debayer.o vimc-sensor.o obj-$(CONFIG_VIDEO_VIMC) += vimc.o(quoted diff) +0
-0
b/drivers/media/platform/vimc/vimc-core.cindex a824b31..373ea9c 100644drivers/media/platform/vimc/vimc-core.c +5
-1@@ -24,6 +24,7 @@#include "vimc-capture.h" #include "vimc-core.h" +#include "vimc-debayer.h" #include "vimc-sensor.h" #define VIMC_PDEV_NAME "vimc"@@ -552,9 +553,12 @@ static int vimc_device_register(struct vimc_device *vimc) create_func = vimc_cap_create;break ; +case VIMC_ENT_NODE_DEBAYER : + create_func = vimc_deb_create; +break ; +/* TODO: Instantiate the specific topology node */ case VIMC_ENT_NODE_INPUT : -case VIMC_ENT_NODE_DEBAYER :case VIMC_ENT_NODE_SCALER :default :/* TODO: remove this when all the entities specific (quoted diff) +0
-0
b/drivers/media/platform/vimc/vimc-core.hindex 38d4855..892341a 100644drivers/media/platform/vimc/vimc-core.h +2
-0@@ -20,6 +20,8 @@#include <media/v4l2-device.h> +#define VIMC_FRAME_INDEX (lin, col, width, bpp) ((lin * width + col) * bpp) +/* Struct which matches the MEDIA_BUS_FMT_ codes with the corresponding * V4L2_PIX_FMT_ fourcc pixelformat and its bytes per pixel (bpp) */ struct vimc_pix_map {(quoted diff) +0
-0
b/drivers/media/platform/vimc/vimc-debayer.cnew file mode 100644 index 0000000..470b336drivers/media/platform/vimc/vimc-debayer.c new file +15
-0@@ -0,0 +1,471 @@ +/* +* vimc-debayer.c Virtual Media Controller Driver +* +* Copyright (C) 2015 Helen Fornazier <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*
drivers/media/platform/vimc/vimc-debayer.c line 25
Quoted 10 lines
drivers/media/platform/vimc/vimc-debayer.c new file +10
-0+*/ + +#include <linux/freezer.h> +#include <linux/vmalloc.h> +#include <linux/v4l2-mediabus.h> +#include <media/v4l2-subdev.h> + +#include "vimc-debayer.h" + +/* TODO: add this as a parameter of this module
How about making it a V4L2 subdev control instead ? It can be left as a TODO item for now of course.
Quoted 12 lines
drivers/media/platform/vimc/vimc-debayer.c new file +1
-0+* NOTE: the window size need to be an odd number, as the main pixel stays in
+ * the center of it, otherwise the next odd number is considered */drivers/media/platform/vimc/vimc-debayer.c new file +9
-0+#define VIMC_DEB_MEAN_WINDOW_SIZE 3 + +enum vimc_deb_rgb_colors { +VIMC_DEB_RED =0 , +VIMC_DEB_GREEN =1 , +VIMC_DEB_BLUE =2 , +}; + +struct vimc_deb_pix_map {
drivers/media/platform/vimc/vimc-debayer.c line 46
Quoted 10 lines
drivers/media/platform/vimc/vimc-debayer.c new file +10
-0+u32 code; +enum vimc_deb_rgb_colors order[2 ][2 ]; +}; + +struct vimc_deb_device { +struct vimc_ent_subdevice vsd; +unsigned int mean_win_size; +/* The active format */ +struct v4l2_mbus_framefmt src_mbus_fmt; +struct v4l2_mbus_framefmt sink_mbus_fmt;
Given that all format fields but the code are identical between the sink and source pads, and that the source code is always RGB using the same number of bits as the sink code, I would only store the sink format and would name the field format.
Quoted 5 lines
drivers/media/platform/vimc/vimc-debayer.c new file +5
-0+void (*set_rgb_src)(struct vimc_deb_device *vdeb,unsigned int lin, +unsigned int col,unsigned int rgb[3 ]); +/* Values calculated when the stream starts */ +u8 *src_frame; +unsigned int src_frame_size;
drivers/media/platform/vimc/vimc-debayer.c line 61
Quoted 10 lines
drivers/media/platform/vimc/vimc-debayer.c new file +10
-0+const struct vimc_deb_pix_map *sink_pix_map; +unsigned int sink_bpp; +}; + + +static const struct vimc_deb_pix_map vimc_deb_pix_map_list[] = { + { + .code =MEDIA_BUS_FMT_SBGGR8_1X8 , + .order = { {VIMC_DEB_BLUE ,VIMC_DEB_GREEN }, + {VIMC_DEB_GREEN ,VIMC_DEB_RED } }
Nitpicking, the kernel coding style adds a space after { and before }.
Quoted 77 lines
drivers/media/platform/vimc/vimc-debayer.c new file +77
-0+ }, + { + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .order = { {VIMC_DEB_GREEN, VIMC_DEB_BLUE}, + {VIMC_DEB_RED, VIMC_DEB_GREEN} } + }, + { + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .order = { {VIMC_DEB_GREEN, VIMC_DEB_RED}, + {VIMC_DEB_BLUE, VIMC_DEB_GREEN} } + }, + { + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .order = { {VIMC_DEB_RED, VIMC_DEB_GREEN}, + {VIMC_DEB_GREEN, VIMC_DEB_BLUE} } + }, + { + .code = MEDIA_BUS_FMT_SBGGR10_1X10, + .order = { {VIMC_DEB_BLUE, VIMC_DEB_GREEN}, + {VIMC_DEB_GREEN, VIMC_DEB_RED} } + }, + { + .code = MEDIA_BUS_FMT_SGBRG10_1X10, + .order = { {VIMC_DEB_GREEN, VIMC_DEB_BLUE}, + {VIMC_DEB_RED, VIMC_DEB_GREEN} } + }, + { + .code = MEDIA_BUS_FMT_SGRBG10_1X10, + .order = { {VIMC_DEB_GREEN, VIMC_DEB_RED}, + {VIMC_DEB_BLUE, VIMC_DEB_GREEN} } + }, + { + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .order = { {VIMC_DEB_RED, VIMC_DEB_GREEN}, + {VIMC_DEB_GREEN, VIMC_DEB_BLUE} } + }, + { + .code = MEDIA_BUS_FMT_SBGGR12_1X12, + .order = { {VIMC_DEB_BLUE, VIMC_DEB_GREEN}, + {VIMC_DEB_GREEN, VIMC_DEB_RED} } + }, + { + .code = MEDIA_BUS_FMT_SGBRG12_1X12, + .order = { {VIMC_DEB_GREEN, VIMC_DEB_BLUE}, + {VIMC_DEB_RED, VIMC_DEB_GREEN} } + }, + { + .code = MEDIA_BUS_FMT_SGRBG12_1X12, + .order = { {VIMC_DEB_GREEN, VIMC_DEB_RED}, + {VIMC_DEB_BLUE, VIMC_DEB_GREEN} } + }, + { + .code = MEDIA_BUS_FMT_SRGGB12_1X12, + .order = { {VIMC_DEB_RED, VIMC_DEB_GREEN}, + {VIMC_DEB_GREEN, VIMC_DEB_BLUE} } + }, +}; + +static const struct vimc_deb_pix_map *vimc_deb_pix_map_by_code (u32 code) +{ +unsigned int i; + +for (i =0 ; i <ARRAY_SIZE (vimc_deb_pix_map_list); i++) +if (vimc_deb_pix_map_list[i].code == code) +return &vimc_deb_pix_map_list[i]; + +return NULL ; +} + +static int vimc_deb_enum_mbus_code (struct v4l2_subdev *sd, +struct v4l2_subdev_pad_config *cfg, +struct v4l2_subdev_mbus_code_enum *code) +{ +struct vimc_deb_device *vdeb =v4l2_get_subdevdata (sd); +struct media_pad *pad; + +/* Check if it is a valid pad */
drivers/media/platform/vimc/vimc-debayer.c line 148
Quoted 10 lines
drivers/media/platform/vimc/vimc-debayer.c new file +10
-0+if (code->pad >= vdeb->vsd.sd.entity.num_pads) +return -EINVAL ; + + pad = &vdeb->vsd.sd.entity.pads[code->pad]; +if ((pad->flags &MEDIA_PAD_FL_SOURCE )) + code->code = vdeb->src_mbus_fmt.code; +else if ((pad->flags &MEDIA_PAD_FL_SINK )) + code->code = vdeb->sink_mbus_fmt.code; +else +return -EINVAL ;
The else clause is redundant with the pad number check above. I'd use the pad number only here, with a hardcoded number of pads. Something like
#define VIMC_DEB_PAD_SINK 0
#define VIMC_DEB_PAD_SOURCE 1
(at the beginning of the file)
...
if (code->pad == VIMC_DEB_PAD_SINK) code->code = vdeb->sink_mbus_fmt.code; else if (code->pad == VIMC_DEB_PAD_SOURCE) code->code = vdeb->src_mbus_fmt.code; else return -EINVAL;
Same for the functions below.
You also need to return -EINVAL if code->index is > 0 as that how the driver signals the end of enumeration.
Quoted 81 lines
drivers/media/platform/vimc/vimc-debayer.c new file +64
-0+return 0 ; +} + +static int vimc_deb_enum_frame_size (struct v4l2_subdev *sd, +struct v4l2_subdev_pad_config *cfg, +struct v4l2_subdev_frame_size_enum *fse) +{ +struct vimc_deb_device *vdeb =v4l2_get_subdevdata (sd); +struct media_pad *pad; + +/* Check if it is a valid pad */ +if (fse->pad >= vdeb->vsd.sd.entity.num_pads) +return -EINVAL ; + +/* TODO: Add support to other formats sizes */ + + pad = &vdeb->vsd.sd.entity.pads[fse->pad]; +if ((pad->flags &MEDIA_PAD_FL_SOURCE )) { + fse->min_width = vdeb->src_mbus_fmt.width; + fse->max_width = vdeb->src_mbus_fmt.width; + fse->min_height = vdeb->src_mbus_fmt.height; + fse->max_height = vdeb->src_mbus_fmt.height; + }else if ((pad->flags &MEDIA_PAD_FL_SINK )) { + fse->min_width = vdeb->sink_mbus_fmt.width; + fse->max_width = vdeb->sink_mbus_fmt.width; + fse->min_height = vdeb->sink_mbus_fmt.height; + fse->max_height = vdeb->sink_mbus_fmt.height; + }else +return -EINVAL ; + +return 0 ; +} + +static int vimc_deb_get_fmt (struct v4l2_subdev *sd, +struct v4l2_subdev_pad_config *cfg, +struct v4l2_subdev_format *format) +{ +struct vimc_deb_device *vdeb =v4l2_get_subdevdata (sd); +struct media_pad *pad; + +/* Check if it is a valid pad */ +if (format->pad >= vdeb->vsd.sd.entity.num_pads) +return -EINVAL ; + + pad = &vdeb->vsd.sd.entity.pads[format->pad]; +if ((pad->flags &MEDIA_PAD_FL_SOURCE )) + format->format = vdeb->src_mbus_fmt; +else if ((pad->flags &MEDIA_PAD_FL_SINK )) + format->format = vdeb->sink_mbus_fmt; +else +return -EINVAL ; + +return 0 ; +} + +static const struct v4l2_subdev_pad_ops vimc_deb_pad_ops = { + .enum_mbus_code = vimc_deb_enum_mbus_code, + .enum_frame_size = vimc_deb_enum_frame_size, + .get_fmt = vimc_deb_get_fmt, +/* TODO: Add support to other formats */ + .set_fmt = vimc_deb_get_fmt, +}; + +static void vimc_deb_set_rgb_mbus_fmt_rgb888_1x24(struct vimc_deb_device*vdeb,
drivers/media/platform/vimc/vimc-debayer.c new file +16
-0+unsigned int lin, + unsigned int col, + unsigned int rgb[3]) +{ + unsigned int i, index; + + index =VIMC_FRAME_INDEX (lin, col, vdeb->src_mbus_fmt.width,3 ); +for (i =0 ; i <3 ; i++) + vdeb->src_frame[index + i] = rgb[i]; +} + +static int vimc_deb_s_stream (struct v4l2_subdev *sd,int enable) +{ +struct vimc_deb_device *vdeb =v4l2_get_subdevdata (sd); + +if (enable) {
drivers/media/platform/vimc/vimc-debayer.c line 239
Quoted 10 lines
drivers/media/platform/vimc/vimc-debayer.c new file +10
-0+const struct vimc_pix_map *vpix; + +if (vdeb->src_frame) +return -EINVAL ; + +/* Calculate the frame size of the source pad */ + vpix =vimc_pix_map_by_code (vdeb->src_mbus_fmt.code); +/* This should never be NULL, as we won't allow any format +* other then the ones in the vimc_pix_map_list table */ +BUG_ON (!vpix);
As explained in a comment to a previous patch BUG_ON should be avoided. Its only valid use case is when a problem is so serious than continuing running would become a risk for system integrity and halting the machine is the only solution.
Quoted 103 lines
drivers/media/platform/vimc/vimc-debayer.c new file +103
-0+ vdeb->src_frame_size = vdeb->src_mbus_fmt.width * + vpix->bpp * vdeb->src_mbus_fmt.height; + +/* Save the bytes per pixel of the sink */ + vpix =vimc_pix_map_by_code (vdeb->sink_mbus_fmt.code); +/* This should never be NULL, as we won't allow any format +* other then the ones in the vimc_pix_map_list table */ +BUG_ON (!vpix); + vdeb->sink_bpp = vpix->bpp; + +/* Get the corresponding pixel map from the table */ + vdeb->sink_pix_map =vimc_deb_pix_map_by_code ( + vdeb->sink_mbus_fmt.code); +/* This should never be NULL, as we won't allow any format +* in sink pad other then the ones in the +* vimc_deb_pix_map_list table */ +BUG_ON (!vdeb->sink_pix_map); + +/* Allocate the frame buffer. Use vmalloc to be able to +* allocate a large amount of memory*/ + vdeb->src_frame =vmalloc (vdeb->src_frame_size); +if (!vdeb->src_frame) +return -ENOMEM ; + +/* Turn the stream on in the subdevices directly connected */ +if (vimc_pipeline_s_stream (&vdeb->vsd.sd.entity,1 )) { +vfree (vdeb->src_frame); + vdeb->src_frame =NULL ; +return -EINVAL ; + } + + }else { +if (!vdeb->src_frame) +return -EINVAL ; +vfree (vdeb->src_frame); + vdeb->src_frame =NULL ; +vimc_pipeline_s_stream (&vdeb->vsd.sd.entity,0 ); + } + +return 0 ; +} + +struct v4l2_subdev_video_ops vimc_deb_video_ops = { + .s_stream = vimc_deb_s_stream, +}; + +static const struct v4l2_subdev_ops vimc_deb_ops = { + .pad = &vimc_deb_pad_ops, + .video = &vimc_deb_video_ops, +}; + +static unsigned int vimc_deb_get_val (const u8 *bytes, +const unsigned int n_bytes) +{ +unsigned int i; +unsigned int acc =0 ; + +for (i =0 ; i < n_bytes; i++) + acc = acc + (bytes[i] << (8 * i)); + +return acc; +} + +static void vimc_deb_calc_rgb_sink (struct vimc_deb_device *vdeb, +const u8 *frame, +const unsigned int lin, +const unsigned int col, +unsigned int rgb[3 ]) +{ +unsigned int i, seek, wlin, wcol; +unsigned int n_rgb[3 ] = {0 ,0 ,0 }; + +for (i =0 ; i <3 ; i++) + rgb[i] =0 ; + +/* Calculate how many we need to subtract to get to the pixel in +* the top left corner of the mean window (considering the current +* pixel as the center) */ + seek = vdeb->mean_win_size /2 ; + +/* Sum the values of the colors in the mean window */ + +dev_dbg (vdeb->vsd.dev, +"deb: %s: --- Calc pixel %dx%d, window mean %d, seek %d ---\n" , + vdeb->vsd.sd.name, lin, col, vdeb->sink_mbus_fmt.height, seek); + +/* Iterate through all the lines in the mean window, start +* with zero if the pixel is outside the frame and don't pass +* the height when the pixel is in the bottom border of the +* frame */ +for (wlin = seek > lin ?0 : lin - seek; + wlin < lin + seek +1 && wlin < vdeb->sink_mbus_fmt.height; + wlin++) { + +/* Iterate through all the columns in the mean window, start +* with zero if the pixel is outside the frame and don't pass +* the width when the pixel is in the right border of the +* frame */ +for (wcol = seek > col ?0 : col - seek; + wcol < col + seek +1 && wcol < vdeb->sink_mbus_fmt.width; + wcol++) { +enum vimc_deb_rgb_colors color; +unsigned int index;
drivers/media/platform/vimc/vimc-debayer.c
Quoted 10 lines
drivers/media/platform/vimc/vimc-debayer.c new file +10
-0+ +/* Check which color this pixel is */ + color = vdeb->sink_pix_map->order[wlin %2 ][wcol %2 ]; + + index =VIMC_FRAME_INDEX (wlin, wcol, + vdeb->sink_mbus_fmt.width, + vdeb->sink_bpp); + + dev_dbg(vdeb->vsd.dev, + "deb: %s: RGB CALC: frame index %d, win pos %dx%d, color
%d\n",
Quoted 19 lines
drivers/media/platform/vimc/vimc-debayer.c new file +18
-0+ vdeb->vsd.sd.name, index, wlin, wcol, color); + +/* Get its value */ + rgb[color] = rgb[color] + +vimc_deb_get_val (&frame[index], vdeb->sink_bpp); + +/* Save how many values we already added */ + n_rgb[color]++; + +dev_dbg (vdeb->vsd.dev, +"deb: %s: RGB CALC: val %d, n %d\n" , + vdeb->vsd.sd.name, rgb[color], n_rgb[color]); + } + } + +/* Calculate the mean */ +for (i =0 ; i <3 ; i++) { + dev_dbg(vdeb->vsd.dev, "deb: %s: PRE CALC: %dx%d Color %d, val %d, n%d\n", +
vdeb->vsd.sd.name, lin, col, i, rgb[i], n_rgb[i]);
drivers/media/platform/vimc/vimc-debayer.c
Quoted 5 lines
drivers/media/platform/vimc/vimc-debayer.c new file +5
-0+ +if (n_rgb[i]) + rgb[i] = rgb[i] / n_rgb[i]; + + dev_dbg(vdeb->vsd.dev, "deb: %s: FINAL CALC: %dx%d Color %d, val
%d\n",
Quoted 51 lines
drivers/media/platform/vimc/vimc-debayer.c new file +51
-0+ vdeb->vsd.sd.name, lin, col, i, rgb[i]); + } +} + +static void vimc_deb_process_frame (struct vimc_ent_device *ved, +struct media_pad *sink, +const void *sink_frame) +{ +struct vimc_deb_device *vdeb =container_of (ved, + struct vimc_deb_device, vsd.ved); +unsigned int rgb[3 ]; +unsigned int i, j; + +/* If the stream in this node is not active, just return */ +if (!vdeb->src_frame) +return ; + +for (i =0 ; i < vdeb->src_mbus_fmt.height; i++) +for (j =0 ; j < vdeb->src_mbus_fmt.width; j++) { +vimc_deb_calc_rgb_sink (vdeb, sink_frame, i, j, rgb); + vdeb->set_rgb_src (vdeb, i, j, rgb); + } + +/* Propagate the frame thought all source pads */ +for (i =0 ; i < vdeb->vsd.sd.entity.num_pads; i++) { +struct media_pad *pad = &vdeb->vsd.sd.entity.pads[i]; + +if (pad->flags &MEDIA_PAD_FL_SOURCE ) +vimc_propagate_frame (vdeb->vsd.dev, + pad, vdeb->src_frame); + } +} + +static void vimc_deb_destroy (struct vimc_ent_device *ved) +{ + struct vimc_deb_device *vdeb = container_of(ved, struct vimc_deb_device, + vsd.ved); + +vimc_ent_sd_cleanup (&vdeb->vsd); +} + +struct vimc_ent_device *vimc_deb_create (struct v4l2_device *v4l2_dev, +const char *const name, +u16 num_pads, +const unsigned long *pads_flag) +{ +int ret; +struct vimc_deb_device *vdeb; +struct vimc_ent_subdevice *vsd; + + vsd = vimc_ent_sd_init(sizeof(struct vimc_deb_device),
drivers/media/platform/vimc/vimc-debayer.c line 437
Quoted 10 lines
drivers/media/platform/vimc/vimc-debayer.c new file +10
-0+ v4l2_dev, name, num_pads, pads_flag, + &vimc_deb_ops, vimc_deb_destroy); +if (IS_ERR (vsd)) +return (struct vimc_ent_device *)vsd; + + vdeb = container_of(vsd, struct vimc_deb_device, vsd); + +/* Set the default active frame format (this is hardcoded for now) */ + vdeb->sink_mbus_fmt.width =64 ; + vdeb->sink_mbus_fmt.height =64 ;
64x64 ? Aren't the sink and source sizes supposed to be the same ?
Quoted 68 lines
drivers/media/platform/vimc/vimc-debayer.c new file +34
-0+ vdeb->sink_mbus_fmt.field =V4L2_FIELD_NONE ; + vdeb->sink_mbus_fmt.colorspace =V4L2_COLORSPACE_SRGB ; + vdeb->sink_mbus_fmt.quantization =V4L2_QUANTIZATION_FULL_RANGE ; + vdeb->sink_mbus_fmt.xfer_func =V4L2_XFER_FUNC_SRGB ; + vdeb->sink_mbus_fmt.code =MEDIA_BUS_FMT_SRGGB8_1X8 ; + + vdeb->src_mbus_fmt.width =640 ; + vdeb->src_mbus_fmt.height =480 ; + vdeb->src_mbus_fmt.field =V4L2_FIELD_NONE ; + vdeb->src_mbus_fmt.colorspace =V4L2_COLORSPACE_SRGB ; + vdeb->src_mbus_fmt.quantization =V4L2_QUANTIZATION_FULL_RANGE ; + vdeb->src_mbus_fmt.xfer_func =V4L2_XFER_FUNC_SRGB ; + vdeb->src_mbus_fmt.code =MEDIA_BUS_FMT_RGB888_1X24 ; + vdeb->set_rgb_src = vimc_deb_set_rgb_mbus_fmt_rgb888_1x24; + +/* Set the window size to calculate the mean */ + vdeb->mean_win_size =VIMC_DEB_MEAN_WINDOW_SIZE ; + +/* Set the process frame callback */ + vdeb->vsd.ved.process_frame = vimc_deb_process_frame; + +/* Register the subdev with the v4l2 and the media framework */ + ret =v4l2_device_register_subdev (vdeb->vsd.v4l2_dev, &vdeb->vsd.sd); +if (ret) { +dev_err (vdeb->vsd.dev, +"subdev register failed (err=%d)\n" , ret); + +vimc_ent_sd_cleanup (vsd); + +return ERR_PTR (ret); + } + +return &vdeb->vsd.ved; +}(quoted diff) +0
-0
b/drivers/media/platform/vimc/vimc-debayer.hnew file mode 100644 index 0000000..bc00c97drivers/media/platform/vimc/vimc-debayer.h new file +28
-0@@ -0,0 +1,28 @@ +/* +* vimc-debayer.h Virtual Media Controller Driver +* +* Copyright (C) 2015 Helen Fornazier <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#ifndef _VIMC_DEBAYER_H_ +#define _VIMC_DEBAYER_H_ + +#include "vimc-core.h" + +struct vimc_ent_device *vimc_deb_create (struct v4l2_device *v4l2_dev, +const char *const name, +u16 num_pads, +const unsigned long *pads_flag); + +#endif
Signature · 3 lines
Regards, Laurent Pinchart
PATCH 6/7 vimc: sca: Add scaler subdevice
In reply to Helen FornazierImplement scaler and integrated with the core
--- drivers/media/platform/vimc/Makefile | 3 +- drivers/media/platform/vimc/vimc-core.c | 6 +- drivers/media/platform/vimc/vimc-scaler.c | 321 ++++++++++++++++++++++++++++++ drivers/media/platform/vimc/vimc-scaler.h | 28 +++ 4 files changed, 356 insertions(+), 2 deletions(-) create mode 100644 drivers/media/platform/vimc/vimc-scaler.c create mode 100644 drivers/media/platform/vimc/vimc-scaler.h
drivers/media/platform/vimc/Makefile +2 -1
@@ -1,3 +1,4 @@ -vimc-objs := vimc-core.o vimc-capture.o vimc-debayer.o vimc-sensor.o +vimc-objs := vimc-core.o vimc-capture.o vimc-debayer.o vimc-scaler.o \ + vimc-sensor.o obj-$(CONFIG_VIDEO_VIMC) += vimc.o
drivers/media/platform/vimc/vimc-core.c +5 -1
@@ -25,6 +25,7 @@#include "vimc-capture.h" #include "vimc-core.h" #include "vimc-debayer.h" +#include "vimc-scaler.h" #include "vimc-sensor.h" #define VIMC_PDEV_NAME "vimc"
@@ -557,9 +558,12 @@ static int vimc_device_register(struct vimc_device *vimc) create_func = vimc_deb_create;break ; +case VIMC_ENT_NODE_SCALER : + create_func = vimc_sca_create; +break ; +/* TODO: Instantiate the specific topology node */ case VIMC_ENT_NODE_INPUT : -case VIMC_ENT_NODE_SCALER :default :/* TODO: remove this when all the entities specific * code are implemented */
drivers/media/platform/vimc/vimc-scaler.c new file +321 -0
321 lines not on this page · raw message
drivers/media/platform/vimc/vimc-scaler.h new file +28 -0
@@ -0,0 +1,28 @@ +/* +* vimc-scaler.h Virtual Media Controller Driver +* +* Copyright (C) 2015 Helen Fornazier <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#ifndef _VIMC_SCALER_H_ +#define _VIMC_SCALER_H_ + +#include "vimc-core.h" + +struct vimc_ent_device *vimc_sca_create (struct v4l2_device *v4l2_dev, +const char *const name, +u16 num_pads, +const unsigned long *pads_flag); + +#endif
Signature · 1 line
1.9.1
Re: [PATCH 6/7] [media] vimc: sca: Add scaler subdevice
Hi Helen,
Thank you for the patch.
Quoted 11 lines · On Thursday 06 August 2015 17:26:13 Helen Fornazier wrote:
Implement scaler and integrated with the core
Signed-off-by Helen Fornazier <[email protected]>--- drivers/media/platform/vimc/Makefile | 3 +- drivers/media/platform/vimc/vimc-core.c | 6 +- drivers/media/platform/vimc/vimc-scaler.c | 321 +++++++++++++++++++++++++++ drivers/media/platform/vimc/vimc-scaler.h | 28 +++ 4 files changed, 356 insertions(+), 2 deletions(-) create mode 100644 drivers/media/platform/vimc/vimc-scaler.c create mode 100644 drivers/media/platform/vimc/vimc-scaler.h
[snip]
Quoted 14 lines
(quoted diff) +0
-0
b/drivers/media/platform/vimc/vimc-scaler.cnew file mode 100644 index 0000000..ea26930drivers/media/platform/vimc/vimc-scaler.c new file +8
-0@@ -0,0 +1,321 @@ +/* +* vimc-scaler.c Virtual Media Controller Driver +* +* Copyright (C) 2015 Helen Fornazier <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or
drivers/media/platform/vimc/vimc-scaler.c line 18
Quoted 10 lines
drivers/media/platform/vimc/vimc-scaler.c new file +10
-0+* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include <linux/freezer.h>
I don't think this header is needed. Same for patch 5/7.
Quoted 22 lines
drivers/media/platform/vimc/vimc-scaler.c new file +22
-0+#include <linux/vmalloc.h> +#include <linux/v4l2-mediabus.h> +#include <media/v4l2-subdev.h> + +#include "vimc-scaler.h" + +/* TODO: add this as a parameter of this module */ +#define VIMC_SCA_MULTIPLIER 3 + +struct vimc_sca_device { +struct vimc_ent_subdevice vsd; +unsigned int mult; +/* The active format */ +struct v4l2_mbus_framefmt sink_mbus_fmt; +unsigned int src_width; +unsigned int src_height; +/* Values calculated when the stream starts */ +u8 *src_frame; +unsigned int src_frame_size; +unsigned int src_line_size; +unsigned int bpp; +};
drivers/media/platform/vimc/vimc-scaler.c line 50
Quoted 10 lines
drivers/media/platform/vimc/vimc-scaler.c new file +10
-0+ +static int vimc_sca_enum_mbus_code (struct v4l2_subdev *sd, +struct v4l2_subdev_pad_config *cfg, +struct v4l2_subdev_mbus_code_enum *code) +{ +struct vimc_sca_device *vsca =v4l2_get_subdevdata (sd); + +/* Check if it is a valid pad */ +if (code->pad >= vsca->vsd.sd.entity.num_pads) +return -EINVAL ;
You should check code->index (here and in enum_frame_size) as explained in my reply to patch 5/7. Please also consider the other comments I made for that patch when they're applicable here.
Quoted 305 lines
drivers/media/platform/vimc/vimc-scaler.c new file +178
-0+ code->code = vsca->sink_mbus_fmt.code; + +return 0 ; +} + +static int vimc_sca_enum_frame_size (struct v4l2_subdev *sd, +struct v4l2_subdev_pad_config *cfg, +struct v4l2_subdev_frame_size_enum *fse) +{ +struct vimc_sca_device *vsca =v4l2_get_subdevdata (sd); +struct media_pad *pad; + +/* Check if it is a valid pad */ +if (fse->pad >= vsca->vsd.sd.entity.num_pads) +return -EINVAL ; + +/* TODO: Add support to other formats sizes */ + + pad = &vsca->vsd.sd.entity.pads[fse->pad]; +if ((pad->flags &MEDIA_PAD_FL_SOURCE )) { + fse->min_width = vsca->src_width; + fse->max_width = vsca->src_width; + fse->min_height = vsca->src_height; + fse->max_height = vsca->src_height; + }else if ((pad->flags &MEDIA_PAD_FL_SINK )) { + fse->min_width = vsca->sink_mbus_fmt.width; + fse->max_width = vsca->sink_mbus_fmt.width; + fse->min_height = vsca->sink_mbus_fmt.height; + fse->max_height = vsca->sink_mbus_fmt.height; + }else +return -EINVAL ; + +return 0 ; +} + +static int vimc_sca_get_fmt (struct v4l2_subdev *sd, +struct v4l2_subdev_pad_config *cfg, +struct v4l2_subdev_format *format) +{ +struct vimc_sca_device *vsca =v4l2_get_subdevdata (sd); +struct media_pad *pad; + +/* Check if it is a valid pad */ +if (format->pad >= vsca->vsd.sd.entity.num_pads) +return -EINVAL ; + + pad = &vsca->vsd.sd.entity.pads[format->pad]; +if ((pad->flags &MEDIA_PAD_FL_SOURCE )) { + format->format = vsca->sink_mbus_fmt; + format->format.width = vsca->src_width; + format->format.height = vsca->src_height; + }else if ((pad->flags &MEDIA_PAD_FL_SINK )) + format->format = vsca->sink_mbus_fmt; +else +return -EINVAL ; + +return 0 ; +} + +static const struct v4l2_subdev_pad_ops vimc_sca_pad_ops = { + .enum_mbus_code = vimc_sca_enum_mbus_code, + .enum_frame_size = vimc_sca_enum_frame_size, + .get_fmt = vimc_sca_get_fmt, +/* TODO: Add support to other formats */ + .set_fmt = vimc_sca_get_fmt, +}; + +static int vimc_sca_s_stream (struct v4l2_subdev *sd,int enable) +{ +struct vimc_sca_device *vsca =v4l2_get_subdevdata (sd); + +if (enable) { +const struct vimc_pix_map *vpix; + +if (vsca->src_frame) +return -EINVAL ; + +/* Save the bytes per pixel of the sink */ + vpix =vimc_pix_map_by_code (vsca->sink_mbus_fmt.code); +/* This should never be NULL, as we won't allow any format +* other then the ones in the vimc_pix_map_list table */ +BUG_ON (!vpix); + vsca->bpp = vpix->bpp; + +/* Calculate the width in bytes of the src frame */ + vsca->src_line_size = vsca->src_width * vsca->bpp; + +/* Calculate the frame size of the source pad */ + vsca->src_frame_size = vsca->src_line_size * vsca->src_height; + +/* Allocate the frame buffer. Use vmalloc to be able to +* allocate a large amount of memory*/ + vsca->src_frame =vmalloc (vsca->src_frame_size); +if (!vsca->src_frame) +return -ENOMEM ; + +/* Turn the stream on in the subdevices directly connected */ +if (vimc_pipeline_s_stream (&vsca->vsd.sd.entity,1 )) { +vfree (vsca->src_frame); + vsca->src_frame =NULL ; +return -EINVAL ; + } + }else { +if (!vsca->src_frame) +return -EINVAL ; +vfree (vsca->src_frame); + vsca->src_frame =NULL ; +vimc_pipeline_s_stream (&vsca->vsd.sd.entity,0 ); + } + +return 0 ; +} + +struct v4l2_subdev_video_ops vimc_sca_video_ops = { + .s_stream = vimc_sca_s_stream, +}; + +static const struct v4l2_subdev_ops vimc_sca_ops = { + .pad = &vimc_sca_pad_ops, + .video = &vimc_sca_video_ops, +}; + +static void vimc_sca_fill_pix (u8 *const ptr, +const u8 *const pixel, +const unsigned int bpp) +{ +unsigned int i; + +/* copy the pixel to the pointer */ +for (i =0 ; i < bpp; i++) + ptr[i] = pixel[i]; +} + +static void vimc_sca_scale_pix (const struct vimc_sca_device *const vsca, +const unsigned int lin,const unsigned int col, +const u8 *const sink_frame) +{ +unsigned int i, j, index; +const u8 *pixel; + +/* Point to the pixel value in position (lin, col) in the sink frame */ + index =VIMC_FRAME_INDEX (lin, col, + vsca->sink_mbus_fmt.width, + vsca->bpp); + pixel = &sink_frame[index]; + +dev_dbg (vsca->vsd.dev, +"sca: %s: --- scale_pix sink pos %dx%d, index %d ---\n" , + vsca->vsd.sd.name, lin, col, index); + +/* point to the place we are going to put the first pixel +* in the scaled src frame */ + index =VIMC_FRAME_INDEX (lin * vsca->mult, col * vsca->mult, + vsca->src_width, vsca->bpp); + +dev_dbg (vsca->vsd.dev,"sca: %s: scale_pix src pos %dx%d, index %d\n" , + vsca->vsd.sd.name, lin * vsca->mult, col * vsca->mult, index); + +/* Repeat this pixel mult times */ +for (i =0 ; i < vsca->mult; i++) { +/* Iterate though each beginning of a +* pixel repetition in a line */ +for (j =0 ; j < vsca->mult * vsca->bpp; j += vsca->bpp) { +dev_dbg (vsca->vsd.dev, +"sca: %s: sca: scale_pix src pos %d\n" , + vsca->vsd.sd.name, index + j); + +/* copy the pixel to the position index + j */ +vimc_sca_fill_pix (&vsca->src_frame[index + j], + pixel, vsca->bpp); + } + +/* move the index to the next line */ + index += vsca->src_line_size; + } +} + +static void vimc_sca_fill_src_frame(const struct vimc_sca_device *constvsca,
drivers/media/platform/vimc/vimc-scaler.c new file +92
-0+ const u8 *const sink_frame) +{ +unsigned int i, j; + +/* Scale each pixel from the original sink frame */ +/* TODO: implement scale down, only scale up is supported for now */ +for (i =0 ; i < vsca->sink_mbus_fmt.height; i++) +for (j =0 ; j < vsca->sink_mbus_fmt.width; j++) +vimc_sca_scale_pix (vsca, i, j, sink_frame); +} + +static void vimc_sca_process_frame (struct vimc_ent_device *ved, +struct media_pad *sink, +const void *sink_frame) +{ +unsigned int i; + struct vimc_sca_device *vsca = container_of(ved, struct vimc_sca_device, + vsd.ved); + +/* If the stream in this node is not active, just return */ +if (!vsca->src_frame) +return ; + +vimc_sca_fill_src_frame (vsca, sink_frame); + +/* Propagate the frame thought all source pads */ +for (i =0 ; i < vsca->vsd.sd.entity.num_pads; i++) { +struct media_pad *pad = &vsca->vsd.sd.entity.pads[i]; + +if (pad->flags &MEDIA_PAD_FL_SOURCE ) +vimc_propagate_frame (vsca->vsd.dev, + pad, vsca->src_frame); + } +}; + +static void vimc_sca_destroy (struct vimc_ent_device *ved) +{ + struct vimc_sca_device *vsca = container_of(ved, struct vimc_sca_device, + vsd.ved); + +vimc_ent_sd_cleanup (&vsca->vsd); +} + +struct vimc_ent_device *vimc_sca_create (struct v4l2_device *v4l2_dev, +const char *const name, +u16 num_pads, +const unsigned long *pads_flag) +{ +int ret; +struct vimc_sca_device *vsca; +struct vimc_ent_subdevice *vsd; + + vsd =vimc_ent_sd_init (sizeof (struct vimc_sca_device ), + v4l2_dev, name, num_pads, pads_flag, + &vimc_sca_ops, vimc_sca_destroy); +if (IS_ERR (vsd)) +return (struct vimc_ent_device *)vsd; + + vsca = container_of(vsd, struct vimc_sca_device, vsd); + +/* Set the default active frame format (this is hardcoded for now) */ + vsca->sink_mbus_fmt.width =640 ; + vsca->sink_mbus_fmt.height =480 ; + vsca->sink_mbus_fmt.code =MEDIA_BUS_FMT_RGB888_1X24 ; + vsca->sink_mbus_fmt.field =V4L2_FIELD_NONE ; + vsca->sink_mbus_fmt.colorspace =V4L2_COLORSPACE_SRGB ; + vsca->sink_mbus_fmt.quantization =V4L2_QUANTIZATION_FULL_RANGE ; + vsca->sink_mbus_fmt.xfer_func =V4L2_XFER_FUNC_SRGB ; + +/* Set the scaler multiplier factor */ + vsca->mult =VIMC_SCA_MULTIPLIER ; + +/* Calculate the width and the height of the src frame */ + vsca->src_width = vsca->sink_mbus_fmt.width * vsca->mult; + vsca->src_height = vsca->sink_mbus_fmt.height * vsca->mult; + +/* Set the process frame callback */ + vsca->vsd.ved.process_frame = vimc_sca_process_frame; + +/* Register the subdev with the v4l2 and the media framework */ + ret =v4l2_device_register_subdev (vsca->vsd.v4l2_dev, &vsca->vsd.sd); +if (ret) { +dev_err (vsca->vsd.dev, +"subdev register failed (err=%d)\n" , ret); + +vimc_ent_sd_cleanup (vsd); + +return ERR_PTR (ret); + } + +return &vsca->vsd.ved; +}(quoted diff) +0
-0
b/drivers/media/platform/vimc/vimc-scaler.hnew file mode 100644 index 0000000..863278fdrivers/media/platform/vimc/vimc-scaler.h new file +28
-0@@ -0,0 +1,28 @@ +/* +* vimc-scaler.h Virtual Media Controller Driver +* +* Copyright (C) 2015 Helen Fornazier <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#ifndef _VIMC_SCALER_H_ +#define _VIMC_SCALER_H_ + +#include "vimc-core.h" + +struct vimc_ent_device *vimc_sca_create (struct v4l2_device *v4l2_dev, +const char *const name, +u16 num_pads, +const unsigned long *pads_flag); + +#endif
Signature · 3 lines
Regards, Laurent Pinchart
Re: [PATCH 6/7] [media] vimc: sca: Add scaler subdevice
In reply to Helen FornazierQuoted 1 line · Helen Fornazier
Implement scaler and integrated with the core
As per my suggestion in patch 2/7, you don't actually need (or want) to do image processing here. All you need to do is to tell the tpg how it should look like. That way you get scaling for free!
Ditto for the debayer module, that actually doesn't have to do anything. The only thing that you need to keep in mind for the debayer is that video nodes pre-debayer entity should only support the bayer fourcc pixelformats, and the video nodes post-debayer entity shouldn't support the bayer fourccs.
Regards,
Hans
Quoted 409 lines
Signed-off-by Helen Fornazier <[email protected]>--- drivers/media/platform/vimc/Makefile | 3 +- drivers/media/platform/vimc/vimc-core.c | 6 +- drivers/media/platform/vimc/vimc-scaler.c | 321 ++++++++++++++++++++++++++++++ drivers/media/platform/vimc/vimc-scaler.h | 28 +++ 4 files changed, 356 insertions(+), 2 deletions(-) create mode 100644 drivers/media/platform/vimc/vimc-scaler.c create mode 100644 drivers/media/platform/vimc/vimc-scaler.hdrivers/media/platform/vimc/Makefile +2
-1@@ -1,3 +1,4 @@ -vimc-objs := vimc-core.o vimc-capture.o vimc-debayer.o vimc-sensor.o +vimc-objs := vimc-core.o vimc-capture.o vimc-debayer.o vimc-scaler.o \ + vimc-sensor.o obj-$(CONFIG_VIDEO_VIMC) += vimc.odrivers/media/platform/vimc/vimc-core.c +5
-1@@ -25,6 +25,7 @@#include "vimc-capture.h" #include "vimc-core.h" #include "vimc-debayer.h" +#include "vimc-scaler.h" #include "vimc-sensor.h" #define VIMC_PDEV_NAME "vimc"@@ -557,9 +558,12 @@ static int vimc_device_register(struct vimc_device *vimc) create_func = vimc_deb_create;break ; +case VIMC_ENT_NODE_SCALER : + create_func = vimc_sca_create; +break ; +/* TODO: Instantiate the specific topology node */ case VIMC_ENT_NODE_INPUT : -case VIMC_ENT_NODE_SCALER :default :/* TODO: remove this when all the entities specific * code are implemented */ drivers/media/platform/vimc/vimc-scaler.c new file +321
-0@@ -0,0 +1,321 @@ +/* +* vimc-scaler.c Virtual Media Controller Driver +* +* Copyright (C) 2015 Helen Fornazier <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include <linux/freezer.h> +#include <linux/vmalloc.h> +#include <linux/v4l2-mediabus.h> +#include <media/v4l2-subdev.h> + +#include "vimc-scaler.h" + +/* TODO: add this as a parameter of this module */ +#define VIMC_SCA_MULTIPLIER 3 + +struct vimc_sca_device { +struct vimc_ent_subdevice vsd; +unsigned int mult; +/* The active format */ +struct v4l2_mbus_framefmt sink_mbus_fmt; +unsigned int src_width; +unsigned int src_height; +/* Values calculated when the stream starts */ +u8 *src_frame; +unsigned int src_frame_size; +unsigned int src_line_size; +unsigned int bpp; +}; + +static int vimc_sca_enum_mbus_code (struct v4l2_subdev *sd, +struct v4l2_subdev_pad_config *cfg, +struct v4l2_subdev_mbus_code_enum *code) +{ +struct vimc_sca_device *vsca =v4l2_get_subdevdata (sd); + +/* Check if it is a valid pad */ +if (code->pad >= vsca->vsd.sd.entity.num_pads) +return -EINVAL ; + + code->code = vsca->sink_mbus_fmt.code; + +return 0 ; +} + +static int vimc_sca_enum_frame_size (struct v4l2_subdev *sd, +struct v4l2_subdev_pad_config *cfg, +struct v4l2_subdev_frame_size_enum *fse) +{ +struct vimc_sca_device *vsca =v4l2_get_subdevdata (sd); +struct media_pad *pad; + +/* Check if it is a valid pad */ +if (fse->pad >= vsca->vsd.sd.entity.num_pads) +return -EINVAL ; + +/* TODO: Add support to other formats sizes */ + + pad = &vsca->vsd.sd.entity.pads[fse->pad]; +if ((pad->flags &MEDIA_PAD_FL_SOURCE )) { + fse->min_width = vsca->src_width; + fse->max_width = vsca->src_width; + fse->min_height = vsca->src_height; + fse->max_height = vsca->src_height; + }else if ((pad->flags &MEDIA_PAD_FL_SINK )) { + fse->min_width = vsca->sink_mbus_fmt.width; + fse->max_width = vsca->sink_mbus_fmt.width; + fse->min_height = vsca->sink_mbus_fmt.height; + fse->max_height = vsca->sink_mbus_fmt.height; + }else +return -EINVAL ; + +return 0 ; +} + +static int vimc_sca_get_fmt (struct v4l2_subdev *sd, +struct v4l2_subdev_pad_config *cfg, +struct v4l2_subdev_format *format) +{ +struct vimc_sca_device *vsca =v4l2_get_subdevdata (sd); +struct media_pad *pad; + +/* Check if it is a valid pad */ +if (format->pad >= vsca->vsd.sd.entity.num_pads) +return -EINVAL ; + + pad = &vsca->vsd.sd.entity.pads[format->pad]; +if ((pad->flags &MEDIA_PAD_FL_SOURCE )) { + format->format = vsca->sink_mbus_fmt; + format->format.width = vsca->src_width; + format->format.height = vsca->src_height; + }else if ((pad->flags &MEDIA_PAD_FL_SINK )) + format->format = vsca->sink_mbus_fmt; +else +return -EINVAL ; + +return 0 ; +} + +static const struct v4l2_subdev_pad_ops vimc_sca_pad_ops = { + .enum_mbus_code = vimc_sca_enum_mbus_code, + .enum_frame_size = vimc_sca_enum_frame_size, + .get_fmt = vimc_sca_get_fmt, +/* TODO: Add support to other formats */ + .set_fmt = vimc_sca_get_fmt, +}; + +static int vimc_sca_s_stream (struct v4l2_subdev *sd,int enable) +{ +struct vimc_sca_device *vsca =v4l2_get_subdevdata (sd); + +if (enable) { +const struct vimc_pix_map *vpix; + +if (vsca->src_frame) +return -EINVAL ; + +/* Save the bytes per pixel of the sink */ + vpix =vimc_pix_map_by_code (vsca->sink_mbus_fmt.code); +/* This should never be NULL, as we won't allow any format +* other then the ones in the vimc_pix_map_list table */ +BUG_ON (!vpix); + vsca->bpp = vpix->bpp; + +/* Calculate the width in bytes of the src frame */ + vsca->src_line_size = vsca->src_width * vsca->bpp; + +/* Calculate the frame size of the source pad */ + vsca->src_frame_size = vsca->src_line_size * vsca->src_height; + +/* Allocate the frame buffer. Use vmalloc to be able to +* allocate a large amount of memory*/ + vsca->src_frame =vmalloc (vsca->src_frame_size); +if (!vsca->src_frame) +return -ENOMEM ; + +/* Turn the stream on in the subdevices directly connected */ +if (vimc_pipeline_s_stream (&vsca->vsd.sd.entity,1 )) { +vfree (vsca->src_frame); + vsca->src_frame =NULL ; +return -EINVAL ; + } + }else { +if (!vsca->src_frame) +return -EINVAL ; +vfree (vsca->src_frame); + vsca->src_frame =NULL ; +vimc_pipeline_s_stream (&vsca->vsd.sd.entity,0 ); + } + +return 0 ; +} + +struct v4l2_subdev_video_ops vimc_sca_video_ops = { + .s_stream = vimc_sca_s_stream, +}; + +static const struct v4l2_subdev_ops vimc_sca_ops = { + .pad = &vimc_sca_pad_ops, + .video = &vimc_sca_video_ops, +}; + +static void vimc_sca_fill_pix (u8 *const ptr, +const u8 *const pixel, +const unsigned int bpp) +{ +unsigned int i; + +/* copy the pixel to the pointer */ +for (i =0 ; i < bpp; i++) + ptr[i] = pixel[i]; +} + +static void vimc_sca_scale_pix (const struct vimc_sca_device *const vsca, +const unsigned int lin,const unsigned int col, +const u8 *const sink_frame) +{ +unsigned int i, j, index; +const u8 *pixel; + +/* Point to the pixel value in position (lin, col) in the sink frame */ + index =VIMC_FRAME_INDEX (lin, col, + vsca->sink_mbus_fmt.width, + vsca->bpp); + pixel = &sink_frame[index]; + +dev_dbg (vsca->vsd.dev, +"sca: %s: --- scale_pix sink pos %dx%d, index %d ---\n" , + vsca->vsd.sd.name, lin, col, index); + +/* point to the place we are going to put the first pixel +* in the scaled src frame */ + index =VIMC_FRAME_INDEX (lin * vsca->mult, col * vsca->mult, + vsca->src_width, vsca->bpp); + +dev_dbg (vsca->vsd.dev,"sca: %s: scale_pix src pos %dx%d, index %d\n" , + vsca->vsd.sd.name, lin * vsca->mult, col * vsca->mult, index); + +/* Repeat this pixel mult times */ +for (i =0 ; i < vsca->mult; i++) { +/* Iterate though each beginning of a +* pixel repetition in a line */ +for (j =0 ; j < vsca->mult * vsca->bpp; j += vsca->bpp) { +dev_dbg (vsca->vsd.dev, +"sca: %s: sca: scale_pix src pos %d\n" , + vsca->vsd.sd.name, index + j); + +/* copy the pixel to the position index + j */ +vimc_sca_fill_pix (&vsca->src_frame[index + j], + pixel, vsca->bpp); + } + +/* move the index to the next line */ + index += vsca->src_line_size; + } +} + +static void vimc_sca_fill_src_frame (const struct vimc_sca_device *const vsca, +const u8 *const sink_frame) +{ +unsigned int i, j; + +/* Scale each pixel from the original sink frame */ +/* TODO: implement scale down, only scale up is supported for now */ +for (i =0 ; i < vsca->sink_mbus_fmt.height; i++) +for (j =0 ; j < vsca->sink_mbus_fmt.width; j++) +vimc_sca_scale_pix (vsca, i, j, sink_frame); +} + +static void vimc_sca_process_frame (struct vimc_ent_device *ved, +struct media_pad *sink, +const void *sink_frame) +{ +unsigned int i; + struct vimc_sca_device *vsca = container_of(ved, struct vimc_sca_device, + vsd.ved); + +/* If the stream in this node is not active, just return */ +if (!vsca->src_frame) +return ; + +vimc_sca_fill_src_frame (vsca, sink_frame); + +/* Propagate the frame thought all source pads */ +for (i =0 ; i < vsca->vsd.sd.entity.num_pads; i++) { +struct media_pad *pad = &vsca->vsd.sd.entity.pads[i]; + +if (pad->flags &MEDIA_PAD_FL_SOURCE ) +vimc_propagate_frame (vsca->vsd.dev, + pad, vsca->src_frame); + } +}; + +static void vimc_sca_destroy (struct vimc_ent_device *ved) +{ + struct vimc_sca_device *vsca = container_of(ved, struct vimc_sca_device, + vsd.ved); + +vimc_ent_sd_cleanup (&vsca->vsd); +} + +struct vimc_ent_device *vimc_sca_create (struct v4l2_device *v4l2_dev, +const char *const name, +u16 num_pads, +const unsigned long *pads_flag) +{ +int ret; +struct vimc_sca_device *vsca; +struct vimc_ent_subdevice *vsd; + + vsd =vimc_ent_sd_init (sizeof (struct vimc_sca_device ), + v4l2_dev, name, num_pads, pads_flag, + &vimc_sca_ops, vimc_sca_destroy); +if (IS_ERR (vsd)) +return (struct vimc_ent_device *)vsd; + + vsca = container_of(vsd, struct vimc_sca_device, vsd); + +/* Set the default active frame format (this is hardcoded for now) */ + vsca->sink_mbus_fmt.width =640 ; + vsca->sink_mbus_fmt.height =480 ; + vsca->sink_mbus_fmt.code =MEDIA_BUS_FMT_RGB888_1X24 ; + vsca->sink_mbus_fmt.field =V4L2_FIELD_NONE ; + vsca->sink_mbus_fmt.colorspace =V4L2_COLORSPACE_SRGB ; + vsca->sink_mbus_fmt.quantization =V4L2_QUANTIZATION_FULL_RANGE ; + vsca->sink_mbus_fmt.xfer_func =V4L2_XFER_FUNC_SRGB ; + +/* Set the scaler multiplier factor */ + vsca->mult =VIMC_SCA_MULTIPLIER ; + +/* Calculate the width and the height of the src frame */ + vsca->src_width = vsca->sink_mbus_fmt.width * vsca->mult; + vsca->src_height = vsca->sink_mbus_fmt.height * vsca->mult; + +/* Set the process frame callback */ + vsca->vsd.ved.process_frame = vimc_sca_process_frame; + +/* Register the subdev with the v4l2 and the media framework */ + ret =v4l2_device_register_subdev (vsca->vsd.v4l2_dev, &vsca->vsd.sd); +if (ret) { +dev_err (vsca->vsd.dev, +"subdev register failed (err=%d)\n" , ret); + +vimc_ent_sd_cleanup (vsd); + +return ERR_PTR (ret); + } + +return &vsca->vsd.ved; +}drivers/media/platform/vimc/vimc-scaler.h new file +28
-0@@ -0,0 +1,28 @@ +/* +* vimc-scaler.h Virtual Media Controller Driver +* +* Copyright (C) 2015 Helen Fornazier <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#ifndef _VIMC_SCALER_H_ +#define _VIMC_SCALER_H_ + +#include "vimc-core.h" + +struct vimc_ent_device *vimc_sca_create (struct v4l2_device *v4l2_dev, +const char *const name, +u16 num_pads, +const unsigned long *pads_flag); + +#endif
PATCH 7/7 vimc: Implement set format in the nodes
In reply to Helen FornazierImplement set format in the topology nodes capture, debayer, sensor and scaler
Allow user space to change the frame size and the pixel format
--- drivers/media/platform/vimc/vimc-capture.c | 56 ++++++++++++++++++++- drivers/media/platform/vimc/vimc-core.c | 81 +++++++++++++++++++----------- drivers/media/platform/vimc/vimc-core.h | 6 +++ drivers/media/platform/vimc/vimc-debayer.c | 36 ++++++++++++- drivers/media/platform/vimc/vimc-scaler.c | 45 ++++++++++++++++- drivers/media/platform/vimc/vimc-sensor.c | 33 +++++++++++- 6 files changed, 222 insertions(+), 35 deletions(-)
drivers/media/platform/vimc/vimc-capture.c +55 -1
@@ -102,6 +102,59 @@ static int vimc_cap_g_fmt_vid_cap(struct file *file, void *priv,return 0 ; } +static int vimc_cap_s_fmt_vid_cap (struct file *file,void *priv, +struct v4l2_format *f) +{ +struct vimc_cap_device *vcap =video_drvdata (file); +const struct vimc_pix_map *vpix; + +/* Do not change the format while stream is on */ +if (vb2_is_busy (&vcap->queue)) +return -EINVAL ; + +/* Accept all non-zero width and height sizes */ +if (f->fmt.pix.width) + vcap->format.width = f->fmt.pix.width; +else + f->fmt.pix.width = vcap->format.width; +if (f->fmt.pix.height) + vcap->format.height = f->fmt.pix.height; +else + f->fmt.pix.height = vcap->format.height; + +/* Don't accept a pixelformat that is not on the table */ + vpix =vimc_pix_map_by_pixelformat (f->fmt.pix.pixelformat); +if (vpix) + vcap->format.pixelformat = f->fmt.pix.pixelformat; +else { + f->fmt.pix.pixelformat = vcap->format.pixelformat; + vpix =vimc_pix_map_by_pixelformat (f->fmt.pix.pixelformat); + } + + vcap->format.field = f->fmt.pix.field; + +/* Check if bytesperline has the minimum size */ +if (f->fmt.pix.bytesperline >= vcap->format.width * vpix->bpp) + vcap->format.bytesperline = f->fmt.pix.bytesperline; +else + f->fmt.pix.bytesperline = vcap->format.bytesperline; + +/* Set the size of the image and the flags */ + f->fmt.pix.sizeimage = vcap->format.width * + vcap->format.height * vpix->bpp; + vcap->format.sizeimage = f->fmt.pix.sizeimage; + vcap->format.flags = f->fmt.pix.flags; + +/* We don't support changing the colorspace for now */ +/* TODO: add support for others colorspaces */ + f->fmt.pix.colorspace = vcap->format.colorspace; + f->fmt.pix.ycbcr_enc = vcap->format.ycbcr_enc; + f->fmt.pix.quantization = vcap->format.quantization; + f->fmt.pix.xfer_func = vcap->format.xfer_func; + +return 0 ; +} +static int vimc_cap_enum_fmt_vid_cap (struct file *file,void *priv,struct v4l2_fmtdesc *f) {
@@ -134,7 +187,8 @@ static const struct v4l2_ioctl_ops vimc_cap_ioctl_ops = { .vidioc_s_input = vimc_cap_s_input, .vidioc_g_fmt_vid_cap = vimc_cap_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vimc_cap_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vimc_cap_s_fmt_vid_cap, +/* TODO: Add support to try format */ .vidioc_try_fmt_vid_cap = vimc_cap_g_fmt_vid_cap, .vidioc_enum_fmt_vid_cap = vimc_cap_enum_fmt_vid_cap,
drivers/media/platform/vimc/vimc-core.c +53 -28
105 lines not on this page · raw message
drivers/media/platform/vimc/vimc-core.h +6 -0
@@ -28,6 +28,7 @@ struct vimc_pix_map {unsigned int code;unsigned int bpp;u32 pixelformat; +bool bayer; };extern const struct vimc_pix_map vimc_pix_map_list[];
@@ -67,6 +68,11 @@ struct vimc_ent_subdevice *vimc_ent_sd_init(size_t struct_size, void (*sd_destroy)(struct vimc_ent_device *));void vimc_ent_sd_cleanup (struct vimc_ent_subdevice *vsd); +/* Herper function to set the format of a subdevice node */ +void vimc_ent_sd_set_fsize (struct v4l2_mbus_framefmt *active_fmt, +struct v4l2_subdev_pad_config *cfg, +struct v4l2_subdev_format *format); +/* Helper function to call the s_stream of the subdevice * directly connected with entity*/ int vimc_pipeline_s_stream (struct media_entity *entity,int enable);
drivers/media/platform/vimc/vimc-debayer.c +34 -2
@@ -202,12 +202,44 @@ static int vimc_deb_get_fmt(struct v4l2_subdev *sd,return 0 ; } +static int vimc_deb_set_fmt (struct v4l2_subdev *sd, +struct v4l2_subdev_pad_config *cfg, +struct v4l2_subdev_format *format) +{ +struct vimc_deb_device *vdeb =v4l2_get_subdevdata (sd); +const struct vimc_deb_pix_map *vpix; + +/* TODO: Add support for try format */ +if (format->which ==V4L2_SUBDEV_FORMAT_TRY ) +return -EINVAL ; + +/* Do not change the format while stream is on */ +if (vdeb->src_frame) +return -EINVAL ; + +if (vdeb->vsd.sd.entity.pads[format->pad].flags &MEDIA_PAD_FL_SINK ) { +/* Don't accept a code that is not on the debayer table */ + vpix =vimc_deb_pix_map_by_code (format->format.code); +if (vpix) + vdeb->sink_mbus_fmt.code = format->format.code; +else + format->format.code = vdeb->sink_mbus_fmt.code; + +vimc_ent_sd_set_fsize (&vdeb->sink_mbus_fmt, cfg, format); + }else +/* We only support one SRC format for now +* don't change the code +* TODO: chage here when adding more src formats */ +vimc_ent_sd_set_fsize (&vdeb->src_mbus_fmt, cfg, format); + +return 0 ; +} +static const struct v4l2_subdev_pad_ops vimc_deb_pad_ops = { .enum_mbus_code = vimc_deb_enum_mbus_code, .enum_frame_size = vimc_deb_enum_frame_size, .get_fmt = vimc_deb_get_fmt, -/* TODO: Add support to other formats */ - .set_fmt = vimc_deb_get_fmt, + .set_fmt = vimc_deb_set_fmt, }; static void vimc_deb_set_rgb_mbus_fmt_rgb888_1x24(struct vimc_deb_device *vdeb,
drivers/media/platform/vimc/vimc-scaler.c +43 -2
55 lines not on this page · raw message
drivers/media/platform/vimc/vimc-sensor.c +31 -2
@@ -111,12 +111,41 @@ static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen)tpg_s_xfer_func (&vsen->tpg, vsen->mbus_format.xfer_func); } +static int vimc_sen_set_fmt (struct v4l2_subdev *sd, +struct v4l2_subdev_pad_config *cfg, +struct v4l2_subdev_format *format) +{ +struct vimc_sen_device *vsen =v4l2_get_subdevdata (sd); +const struct vimc_pix_map *vpix; + +/* TODO: Add support for try format */ +if (format->which ==V4L2_SUBDEV_FORMAT_TRY ) +return -EINVAL ; + +/* Do not change the format while stream is on */ +if (vsen->frame) +return -EINVAL ; + +/* Don't accept a code that is not on the table */ + vpix =vimc_pix_map_by_code (format->format.code); +if (vpix) + vsen->mbus_format.code = format->format.code; +else + format->format.code = vsen->mbus_format.code; + +vimc_ent_sd_set_fsize (&vsen->mbus_format, cfg, format); + +/* Re-configure the test pattern generator */ +vimc_sen_tpg_s_format (vsen); + +return 0 ; +} +static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = { .enum_mbus_code = vimc_sen_enum_mbus_code, .enum_frame_size = vimc_sen_enum_frame_size, .get_fmt = vimc_sen_get_fmt, -/* TODO: Add support to other formats */ - .set_fmt = vimc_sen_get_fmt, + .set_fmt = vimc_sen_set_fmt, };static int vimc_thread_sen (void *data)
Signature · 1 line
1.9.1
Re: [PATCH 7/7] [media] vimc: Implement set format in the nodes
Hi Helen,
Thank you for the patch.
I would have moved this patch before 5/7 and 6/7 as it would ease review by making 7/7 smaller and by making the debayer and scaler implementation fully contained in 5/7 and 6/7.
Quoted 23 lines · On Thursday 06 August 2015 17:26:14 Helen Fornazier wrote:
Implement set format in the topology nodes capture, debayer, sensor and scaler
Allow user space to change the frame size and the pixel formatSigned-off-by Helen Fornazier <[email protected]>--- drivers/media/platform/vimc/vimc-capture.c | 56 ++++++++++++++++++++- drivers/media/platform/vimc/vimc-core.c | 81 +++++++++++++++++---------- drivers/media/platform/vimc/vimc-core.h | 6 +++ drivers/media/platform/vimc/vimc-debayer.c | 36 ++++++++++++- drivers/media/platform/vimc/vimc-scaler.c | 45 ++++++++++++++++- drivers/media/platform/vimc/vimc-sensor.c | 33 +++++++++++- 6 files changed, 222 insertions(+), 35 deletions(-)(quoted diff) +0
-0
b/drivers/media/platform/vimc/vimc-capture.cindex 7d21966..3b92a35 100644drivers/media/platform/vimc/vimc-capture.c +1
-0@@ -102,6 +102,59 @@ static int vimc_cap_g_fmt_vid_cap(struct file *file, void *priv, return 0; } +static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv,
drivers/media/platform/vimc/vimc-capture.c static int vimc_cap_g_fmt_vid_cap(struct file *file, · line 115
Quoted 10 lines
drivers/media/platform/vimc/vimc-capture.c +10
-0+ struct v4l2_format *f) +{ +struct vimc_cap_device *vcap =video_drvdata (file); +const struct vimc_pix_map *vpix; + +/* Do not change the format while stream is on */ +if (vb2_is_busy (&vcap->queue)) +return -EINVAL ; + +/* Accept all non-zero width and height sizes */
I would set a maximum as there's no point in accepting values larger than what subdevs can handle. Something like
f->fmt.pix.width = clamp(f->fmt.pix.width, MIN, MAX); f->fmt.pix.height = clamp(f->fmt.pix.height, MIN, MAX);
Quoted 28 lines
drivers/media/platform/vimc/vimc-capture.c +28
-0+if (f->fmt.pix.width) + vcap->format.width = f->fmt.pix.width; +else + f->fmt.pix.width = vcap->format.width; +if (f->fmt.pix.height) + vcap->format.height = f->fmt.pix.height; +else + f->fmt.pix.height = vcap->format.height; + +/* Don't accept a pixelformat that is not on the table */ + vpix =vimc_pix_map_by_pixelformat (f->fmt.pix.pixelformat); +if (vpix) + vcap->format.pixelformat = f->fmt.pix.pixelformat; +else { + f->fmt.pix.pixelformat = vcap->format.pixelformat; + vpix =vimc_pix_map_by_pixelformat (f->fmt.pix.pixelformat); + } + + vcap->format.field = f->fmt.pix.field; + +/* Check if bytesperline has the minimum size */ +if (f->fmt.pix.bytesperline >= vcap->format.width * vpix->bpp) + vcap->format.bytesperline = f->fmt.pix.bytesperline; +else + f->fmt.pix.bytesperline = vcap->format.bytesperline; + +/* Set the size of the image and the flags */ + f->fmt.pix.sizeimage = vcap->format.width *
drivers/media/platform/vimc/vimc-capture.c static int vimc_cap_g_fmt_vid_cap(struct file *file, void *priv, · line 153
Quoted 10 lines
drivers/media/platform/vimc/vimc-capture.c +10
-0+ vcap->format.height * vpix->bpp; + vcap->format.sizeimage = f->fmt.pix.sizeimage; + vcap->format.flags = f->fmt.pix.flags; + +/* We don't support changing the colorspace for now */ +/* TODO: add support for others colorspaces */ + f->fmt.pix.colorspace = vcap->format.colorspace; + f->fmt.pix.ycbcr_enc = vcap->format.ycbcr_enc; + f->fmt.pix.quantization = vcap->format.quantization; + f->fmt.pix.xfer_func = vcap->format.xfer_func;
I think the code would be clearer if you first just adjust f->fmt.pix to ensure that all fields have acceptable values, and then store the format in vcap in one go with
vcap->format = f->fmt.pix;
drivers/media/platform/vimc/vimc-capture.c static const struct v4l2_ioctl_ops vimc_cap_ioctl_ops = · line 191
Quoted 13 lines
drivers/media/platform/vimc/vimc-capture.c +5
-1+return 0 ; +} +static int vimc_cap_enum_fmt_vid_cap (struct file *file,void *priv,struct v4l2_fmtdesc *f) {@@ -134,7 +187,8 @@ static const struct v4l2_ioctl_ops vimc_cap_ioctl_ops = { .vidioc_s_input = vimc_cap_s_input, .vidioc_g_fmt_vid_cap = vimc_cap_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vimc_cap_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vimc_cap_s_fmt_vid_cap, +/* TODO: Add support to try format */
Please add it :-) It's important enough to be done now.
Quoted 96 lines
drivers/media/platform/vimc/vimc-capture.c +0
-0.vidioc_try_fmt_vid_cap = vimc_cap_g_fmt_vid_cap, .vidioc_enum_fmt_vid_cap = vimc_cap_enum_fmt_vid_cap,(quoted diff) +0
-0
b/drivers/media/platform/vimc/vimc-core.cindex 8342732..bf2148a 100644drivers/media/platform/vimc/vimc-core.c +20
-17@@ -39,10 +39,11 @@ .flags = link_flags, \ } -#define VIMC_PIX_MAP (_code, _bpp, _pixelformat) { \ - .code = _code, \ - .pixelformat = _pixelformat, \ - .bpp = _bpp, \ +#define VIMC_PIX_MAP (_code, _bpp, _pixelformat, _bayer) { \ + .code = _code, \ + .pixelformat = _pixelformat, \ + .bpp = _bpp, \ + .bayer = _bayer, \ }struct vimc_device {@@ -216,36 +217,36 @@ const struct vimc_pix_map vimc_pix_map_list[] = {/* TODO: add all missing formats */ /* RGB formats */ -VIMC_PIX_MAP (MEDIA_BUS_FMT_BGR888_1X24 ,3 ,V4L2_PIX_FMT_BGR24 ), -VIMC_PIX_MAP (MEDIA_BUS_FMT_RGB888_1X24 ,3 ,V4L2_PIX_FMT_RGB24 ), -VIMC_PIX_MAP (MEDIA_BUS_FMT_ARGB8888_1X32 ,4 ,V4L2_PIX_FMT_ARGB32 ), + VIMC_PIX_MAP(MEDIA_BUS_FMT_BGR888_1X24, 3, V4L2_PIX_FMT_BGR24, false), + VIMC_PIX_MAP(MEDIA_BUS_FMT_RGB888_1X24, 3, V4L2_PIX_FMT_RGB24, false), + VIMC_PIX_MAP(MEDIA_BUS_FMT_ARGB8888_1X32, 4, V4L2_PIX_FMT_ARGB32, false), /* Bayer formats */ -VIMC_PIX_MAP (MEDIA_BUS_FMT_SBGGR8_1X8 ,1 ,V4L2_PIX_FMT_SBGGR8 ), -VIMC_PIX_MAP (MEDIA_BUS_FMT_SGBRG8_1X8 ,1 ,V4L2_PIX_FMT_SGBRG8 ), -VIMC_PIX_MAP (MEDIA_BUS_FMT_SGRBG8_1X8 ,1 ,V4L2_PIX_FMT_SGRBG8 ), -VIMC_PIX_MAP (MEDIA_BUS_FMT_SRGGB8_1X8 ,1 ,V4L2_PIX_FMT_SRGGB8 ), -VIMC_PIX_MAP (MEDIA_BUS_FMT_SBGGR10_1X10 ,2 ,V4L2_PIX_FMT_SBGGR10 ), -VIMC_PIX_MAP (MEDIA_BUS_FMT_SGBRG10_1X10 ,2 ,V4L2_PIX_FMT_SGBRG10 ), -VIMC_PIX_MAP (MEDIA_BUS_FMT_SGRBG10_1X10 ,2 ,V4L2_PIX_FMT_SGRBG10 ), -VIMC_PIX_MAP (MEDIA_BUS_FMT_SRGGB10_1X10 ,2 ,V4L2_PIX_FMT_SRGGB10 ), + VIMC_PIX_MAP(MEDIA_BUS_FMT_SBGGR8_1X8, 1, V4L2_PIX_FMT_SBGGR8, true), + VIMC_PIX_MAP(MEDIA_BUS_FMT_SGBRG8_1X8, 1, V4L2_PIX_FMT_SGBRG8, true), + VIMC_PIX_MAP(MEDIA_BUS_FMT_SGRBG8_1X8, 1, V4L2_PIX_FMT_SGRBG8, true), + VIMC_PIX_MAP(MEDIA_BUS_FMT_SRGGB8_1X8, 1, V4L2_PIX_FMT_SRGGB8, true), + VIMC_PIX_MAP(MEDIA_BUS_FMT_SBGGR10_1X10, 2, V4L2_PIX_FMT_SBGGR10, true), + VIMC_PIX_MAP(MEDIA_BUS_FMT_SGBRG10_1X10, 2, V4L2_PIX_FMT_SGBRG10, true), + VIMC_PIX_MAP(MEDIA_BUS_FMT_SGRBG10_1X10, 2, V4L2_PIX_FMT_SGRBG10, true), + VIMC_PIX_MAP(MEDIA_BUS_FMT_SRGGB10_1X10, 2, V4L2_PIX_FMT_SRGGB10, true), /* 10bit raw bayer a-law compressed to 8 bits */ -VIMC_PIX_MAP (MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8 ,1 , V4L2_PIX_FMT_SBGGR10ALAW8), - VIMC_PIX_MAP(MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8, 1, V4L2_PIX_FMT_SGBRG10ALAW8), -VIMC_PIX_MAP (MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8 ,1 , V4L2_PIX_FMT_SGRBG10ALAW8), - VIMC_PIX_MAP(MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8,1 ,V4L2_PIX_FMT_SRGGB10ALAW8 ), +VIMC_PIX_MAP (MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8 ,1 ,V4L2_PIX_FMT_SBGGR10ALAW8 , true), +VIMC_PIX_MAP (MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8 ,1 ,V4L2_PIX_FMT_SGBRG10ALAW8 , true), +VIMC_PIX_MAP (MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8 ,1 ,V4L2_PIX_FMT_SGRBG10ALAW8 , true), + VIMC_PIX_MAP(MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8, 1,
V4L2_PIX_FMT_SRGGB10ALAW8, true), /* 10bit raw bayer DPCM compressed to 8 bits */drivers/media/platform/vimc/vimc-core.c +0
-1- VIMC_PIX_MAP(MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, 1,
V4L2_PIX_FMT_SBGGR10DPCM8), - VIMC_PIX_MAP(MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8,
1,V4L2_PIX_FMT_SGBRG10DPCM8),drivers/media/platform/vimc/vimc-core.c +0
-1- VIMC_PIX_MAP(MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, 1,
V4L2_PIX_FMT_SGRBG10DPCM8), - VIMC_PIX_MAP(MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8,
1,V4L2_PIX_FMT_SRGGB10DPCM8), - VIMC_PIX_MAP(MEDIA_BUS_FMT_SBGGR12_1X12,
2,V4L2_PIX_FMT_SBGGR12), - VIMC_PIX_MAP(MEDIA_BUS_FMT_SGBRG12_1X12, 2,V4L2_PIX_FMT_SGBRG12), - VIMC_PIX_MAP(MEDIA_BUS_FMT_SGRBG12_1X12, 2,V4L2_PIX_FMT_SGRBG12), - VIMC_PIX_MAP(MEDIA_BUS_FMT_SRGGB12_1X12, 2,V4L2_PIX_FMT_SRGGB12), + VIMC_PIX_MAP(MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, 1,V4L2_PIX_FMT_SBGGR10DPCM8, true),drivers/media/platform/vimc/vimc-core.c +1
-0+ VIMC_PIX_MAP(MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, 1,
V4L2_PIX_FMT_SGBRG10DPCM8, true),drivers/media/platform/vimc/vimc-core.c +1
-0+ VIMC_PIX_MAP(MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, 1,
V4L2_PIX_FMT_SGRBG10DPCM8, true),drivers/media/platform/vimc/vimc-core.c +1
-0+ VIMC_PIX_MAP(MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, 1,
V4L2_PIX_FMT_SRGGB10DPCM8, true),drivers/media/platform/vimc/vimc-core.c +5
-1+VIMC_PIX_MAP (MEDIA_BUS_FMT_SBGGR12_1X12 ,2 ,V4L2_PIX_FMT_SBGGR12 , true), +VIMC_PIX_MAP (MEDIA_BUS_FMT_SGBRG12_1X12 ,2 ,V4L2_PIX_FMT_SGBRG12 , true), +VIMC_PIX_MAP (MEDIA_BUS_FMT_SGRBG12_1X12 ,2 ,V4L2_PIX_FMT_SGRBG12 , true), +VIMC_PIX_MAP (MEDIA_BUS_FMT_SRGGB12_1X12 ,2 ,V4L2_PIX_FMT_SRGGB12 , true),/* End */ - {0, 0, 0} + {0, 0, 0, 0} };const struct vimc_pix_map *vimc_pix_map_by_code (u32 code)
drivers/media/platform/vimc/vimc-core.c err_free_vsd: · line 439
Quoted 2 lines
drivers/media/platform/vimc/vimc-core.c +0
-0@@ -437,6 +438,30 @@ err_free_vsd:return ERR_PTR (ret); }
Documentation please, otherwise it's hard to know exactly what you intended to implement :-)
Quoted 40 lines
drivers/media/platform/vimc/vimc-core.c +24
-0+void vimc_ent_sd_set_fsize (struct v4l2_mbus_framefmt *active_fmt, +struct v4l2_subdev_pad_config *cfg, +struct v4l2_subdev_format *format) +{ +/* Accept all non-zero width and height sizes */ +if (format->format.width) + active_fmt->width = format->format.width; +else + format->format.width = active_fmt->width; +if (format->format.height) + active_fmt->height = format->format.height; +else + format->format.height = active_fmt->height; + + active_fmt->field = format->format.field; + +/* We don't support changing the colorspace for now */ +/* TODO: add support for others */ + format->format.colorspace = active_fmt->colorspace; + format->format.ycbcr_enc = active_fmt->ycbcr_enc; + format->format.quantization = active_fmt->quantization; + format->format.xfer_func = active_fmt->xfer_func; +} +/* TODO: remove this function when all the * entities specific code are implemented */ static void vimc_raw_destroy (struct vimc_ent_device *ved)(quoted diff) +0
-0
b/drivers/media/platform/vimc/vimc-core.hindex 892341a..311be04 100644drivers/media/platform/vimc/vimc-core.h +1
-0@@ -28,6 +28,7 @@ struct vimc_pix_map {unsigned int code;unsigned int bpp;u32 pixelformat; +bool bayer; };extern const struct vimc_pix_map vimc_pix_map_list[];
drivers/media/platform/vimc/vimc-core.h struct vimc_ent_subdevice *vimc_ent_sd_init(size_t · line 71
Quoted 4 lines
drivers/media/platform/vimc/vimc-core.h +1
-0@@ -67,6 +68,11 @@ struct vimc_ent_subdevice *vimc_ent_sd_init(size_t struct_size, void (*sd_destroy)(struct vimc_ent_device *));void vimc_ent_sd_cleanup (struct vimc_ent_subdevice *vsd); +/* Herper function to set the format of a subdevice node */
s/Herper/Helper/
Quoted 7 lines
drivers/media/platform/vimc/vimc-core.h +4
-0+void vimc_ent_sd_set_fsize (struct v4l2_mbus_framefmt *active_fmt, +struct v4l2_subdev_pad_config *cfg, +struct v4l2_subdev_format *format); +/* Helper function to call the s_stream of the subdevice * directly connected with entity*/ int vimc_pipeline_s_stream (struct media_entity *entity,int enable);
[snip]
drivers/media/platform/vimc/vimc-sensor.c static void vimc_sen_tpg_s_format(struct · line 113
Quoted 9 lines
static int
vimc_sca_s_stream(struct v4l2_subdev *sd, int enable)(quoted diff) +0
-0
b/drivers/media/platform/vimc/vimc-sensor.cindex 319bebb..a1cd348 100644drivers/media/platform/vimc/vimc-sensor.c +0
-0@@ -111,12 +111,41 @@ static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen) tpg_s_xfer_func(&vsen->tpg, vsen->mbus_format.xfer_func); }
Most of the comments below apply to the scaler and debayer as well.
drivers/media/platform/vimc/vimc-sensor.c static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen) · line 121
Quoted 8 lines
drivers/media/platform/vimc/vimc-sensor.c +8
-0+static int vimc_sen_set_fmt (struct v4l2_subdev *sd, +struct v4l2_subdev_pad_config *cfg, +struct v4l2_subdev_format *format) +{ +struct vimc_sen_device *vsen =v4l2_get_subdevdata (sd); +const struct vimc_pix_map *vpix; + +/* TODO: Add support for try format */
TRY formats are a core feature of the MC-enabled drivers, I believe they should be implemented in this patch already.
drivers/media/platform/vimc/vimc-sensor.c static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen) · line 134
Quoted 13 lines
drivers/media/platform/vimc/vimc-sensor.c +13
-0+if (format->which ==V4L2_SUBDEV_FORMAT_TRY ) +return -EINVAL ; + +/* Do not change the format while stream is on */ +if (vsen->frame) +return -EINVAL ; + +/* Don't accept a code that is not on the table */ + vpix =vimc_pix_map_by_code (format->format.code); +if (vpix) + vsen->mbus_format.code = format->format.code; +else + format->format.code = vsen->mbus_format.code;
This will result in a variable (as in equal to the last set format) default format when the requested format is not supported. To make the driver's beaviour more consistent you should pick a hardcoded default instead.
drivers/media/platform/vimc/vimc-sensor.c static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen) · line 139
Quoted 4 lines
drivers/media/platform/vimc/vimc-sensor.c +4
-0+vimc_ent_sd_set_fsize (&vsen->mbus_format, cfg, format); + +/* Re-configure the test pattern generator */ +vimc_sen_tpg_s_format (vsen);
How about configuring it as streamon time only, as the format can't be changed during streaming ?
drivers/media/platform/vimc/vimc-sensor.c static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen) · line 146
Quoted 7 lines
drivers/media/platform/vimc/vimc-sensor.c +4
-0+ +return 0 ; +} +static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = { .enum_mbus_code = vimc_sen_enum_mbus_code, .enum_frame_size = vimc_sen_enum_frame_size,
You need to patch enum_mbus_code and enum_frame_size too.
Quoted 7 lines
drivers/media/platform/vimc/vimc-sensor.c +1
-2.get_fmt = vimc_sen_get_fmt, - /* TODO: Add support to other formats */ - .set_fmt = vimc_sen_get_fmt, + .set_fmt = vimc_sen_set_fmt, };static int vimc_thread_sen (void *data)
Signature · 3 lines
Regards, Laurent Pinchart
A message that is not in the archive (sent off-list or not yet received): c6b24212e7473fb6132ff2118a87fdb53e077457.1438891530.git.helen.fornazier@gmail.com
Re: [PATCH 1/7] [media] tpg: Export the tpg code from vivid as a module
Hi Helen,
Thank you for the patch. I just have a couple of small comments.
Quoted 31 lines · On Thursday 06 August 2015 17:26:08 Helen Fornazier wrote:
The test pattern generator will be used by other drivers as the virtual media controller (vimc)
Signed-off-by Helen Fornazier <[email protected]>--- drivers/media/platform/Kconfig | 2 + drivers/media/platform/Makefile | 1 + drivers/media/platform/tpg/Kconfig | 5 + drivers/media/platform/tpg/Makefile | 3 + drivers/media/platform/tpg/tpg-colors.c | 1181 ++++++++++++ drivers/media/platform/tpg/tpg-core.c | 2211 ++++++++++++++++++++ drivers/media/platform/vivid/Kconfig | 1 + drivers/media/platform/vivid/Makefile | 2 +- drivers/media/platform/vivid/vivid-core.h | 2 +- drivers/media/platform/vivid/vivid-tpg-colors.c | 1182 ------------ drivers/media/platform/vivid/vivid-tpg-colors.h | 68 - drivers/media/platform/vivid/vivid-tpg.c | 2191 -------------------- drivers/media/platform/vivid/vivid-tpg.h | 596 ------ include/media/tpg-colors.h | 68 + include/media/tpg.h | 595 ++++++ 15 files changed, 4069 insertions(+), 4039 deletions(-) create mode 100644 drivers/media/platform/tpg/Kconfig create mode 100644 drivers/media/platform/tpg/Makefile create mode 100644 drivers/media/platform/tpg/tpg-colors.c create mode 100644 drivers/media/platform/tpg/tpg-core.c delete mode 100644 drivers/media/platform/vivid/vivid-tpg-colors.c delete mode 100644 drivers/media/platform/vivid/vivid-tpg-colors.h delete mode 100644 drivers/media/platform/vivid/vivid-tpg.c delete mode 100644 drivers/media/platform/vivid/vivid-tpg.h create mode 100644 include/media/tpg-colors.h create mode 100644 include/media/tpg.h
[snip]
drivers/media/platform/tpg/Makefile line 3
Quoted 9 lines
drivers diff --git a/drivers/media/platform/tpg/Makefile b/drivers/media/platform/tpg/Makefile new file mode 100644 index 0000000..01f2212
drivers/media/platform/tpg/Makefile new file +3
-0@@ -0,0 +1,3 @@ +tpg-objs := tpg-core.o tpg-colors.o + +obj-$(CONFIG_VIDEO_TPG) += tpg.o
I would call the module video-tpg, just tpg is a bit too generic.
[snip]
Quoted 25 lines
include/media/tpg.h new file +4
-0@@ -0,0 +1,595 @@ +/* +* tpg.h - Test Pattern Generator +* +* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
include/media/tpg.h
Quoted 3 lines
include/media/tpg.h new file +3
-0+ +#ifndef _TPG_H_ +#define _TPG_H_
For the same reason I'd use _MEDIA_TPG_H_ here, and for consistency, _MEDIA_TPG_COLORS_H_ for tpg-colors.h.
Signature · 3 lines
Regards, Laurent Pinchart
Quoted 10 lines · Helen Fornazier
* This patch series add to the vimc driver video processing units ad a debayer and a scaler.
* The test pattern generator from vivid driver was exported as a module, as it is used by the vimc driver as well.
* The debayer transforms the bayer format image received in its sink pad to a bayer format by avaraging the pixels within a mean window
* The scaler only scales up the image for now.
* The ioctls to configure the format in the pads were implemented to allow testing the pipe from the user space
Quoted 6 lines
The patch series is based on 'vimc/review/video-pipe' branch, it goes on top of the patch named "[media] vimc: Virtual Media Controller core, capture and sensor" and is available at
https://github.com/helen-fornazier/opw-staging vimc/review/vpuHelen Fornazier (7):
[media] tpg: Export the tpg code from vivid as a module
Hmm, this one is missing.
When you move files you should use 'git mv' to do that and when creating the patch series use the -M flag with format-patch. That will make git smart about such moves and avoids a diff where the old file is fully deleted and the new file fully added. The diff got too large because of that, causing this patch to be dropped.
Regards,
Hans
Quoted 48 lines
[media] vimc: sen: Integrate the tpg on the sensor [media] vimc: Add vimc_ent_sd_init/cleanup helper functions [media] vimc: Add
vimc_pipeline_s_streamin the core [media] vimc: deb: Add debayer filter
[media] vimc: sca: Add scaler subdevice
[media] vimc: Implement set format in the nodesdrivers/media/platform/Kconfig | 2 + drivers/media/platform/Makefile | 1 + drivers/media/platform/tpg/Kconfig | 5 + drivers/media/platform/tpg/Makefile | 3 + drivers/media/platform/tpg/tpg-colors.c | 1181 ++++++++++++ drivers/media/platform/tpg/tpg-core.c | 2211 +++++++++++++++++++++++ drivers/media/platform/vimc/Kconfig | 1 + drivers/media/platform/vimc/Makefile | 3 +- drivers/media/platform/vimc/vimc-capture.c | 88 +- drivers/media/platform/vimc/vimc-core.c | 196 +- drivers/media/platform/vimc/vimc-core.h | 29 + drivers/media/platform/vimc/vimc-debayer.c | 503 ++++++ drivers/media/platform/vimc/vimc-debayer.h | 28 + drivers/media/platform/vimc/vimc-scaler.c | 362 ++++ drivers/media/platform/vimc/vimc-scaler.h | 28 + drivers/media/platform/vimc/vimc-sensor.c | 175 +- drivers/media/platform/vivid/Kconfig | 1 + drivers/media/platform/vivid/Makefile | 2 +- drivers/media/platform/vivid/vivid-core.h | 2 +- drivers/media/platform/vivid/vivid-tpg-colors.c | 1182 ------------ drivers/media/platform/vivid/vivid-tpg-colors.h | 68 - drivers/media/platform/vivid/vivid-tpg.c | 2191 ---------------------- drivers/media/platform/vivid/vivid-tpg.h | 596 ------ include/media/tpg-colors.h | 68 + include/media/tpg.h | 595 ++++++ 25 files changed, 5345 insertions(+), 4176 deletions(-) create mode 100644 drivers/media/platform/tpg/Kconfig create mode 100644 drivers/media/platform/tpg/Makefile create mode 100644 drivers/media/platform/tpg/tpg-colors.c create mode 100644 drivers/media/platform/tpg/tpg-core.c create mode 100644 drivers/media/platform/vimc/vimc-debayer.c create mode 100644 drivers/media/platform/vimc/vimc-debayer.h create mode 100644 drivers/media/platform/vimc/vimc-scaler.c create mode 100644 drivers/media/platform/vimc/vimc-scaler.h delete mode 100644 drivers/media/platform/vivid/vivid-tpg-colors.c delete mode 100644 drivers/media/platform/vivid/vivid-tpg-colors.h delete mode 100644 drivers/media/platform/vivid/vivid-tpg.c delete mode 100644 drivers/media/platform/vivid/vivid-tpg.h create mode 100644 include/media/tpg-colors.h create mode 100644 include/media/tpg.h
v2 cover : vimc: Virtual Media Control VPU's
In reply to Helen FornazierThis patch series improves the current video processing units in vimc (by adding more controls to the sensor and capture node, allowing the user to configure different frame formats) and also adds a debayer and a scaler node.
The debayer transforms the bayer format image received in its sink pad to a bayer format by averaging the pixels within a mean window. The scaler only scales up the image for now.
This patch series depends on commit "[media] vimc: Virtual Media Controller core, capture and sensor" and it is available at:
https://github.com/helen-fornazier/opw-staging/tree/z/sent/vimc/vpu/v2
Changes in v2:
[media] vimc: sen: Integrate the tpg on the sensor
- Fix include location
- Select V4L2_TPG in Kconfig
- configure tpg on streamon only
- rm BUG_ON
- coding style
[media] vimc: Add vimc_ent_sd_* helper functions
- Comments in vimc_ent_sd_init
- Update vimc_ent_sd_init with upstream code as media_entity_pads_init (instead of media_entity_init), entity->function intead of entity->type
- Add missing vimc_pads_cleanup in vimc_ent_sd_cleanup
- remove subdevice v4l2_dev and dev fields
- change unregister order in vimc_ent_sd_cleanup
- rename vimc_ent_sd_{init,cleanup} to vimc_ent_sd_{register,unregister}
- remove struct vimc_ent_subdevice, use ved and sd directly
- don't impose struct vimc_sen_device to declare ved and sd struct first
- add kernel docs
[media] vimc: Add vimc_pipeline_s_stream in the core
- Use is_media_entity_v4l2_subdev instead of comparing with the old entity->type
- Fix comments style
- add kernel-docs
- call s_stream across all sink pads
[media] vimc: sen: Support several image formats
- this is a new commit in the serie (the old one was splitted in two)
- add init_cfg to initialize try_fmt
- reorder code in vimc_sen_set_fmt
- allow user space to change all fields from struct v4l2_mbus_framefmt
(e.g. colospace, quantization, field, xfer_func, ycbcr_enc)
- merge with patch for the enum_mbus_code and enum_frame_size
- change commit message
- add vimc_pix_map_by_index
- rename MIN/MAX macros
- check set_fmt default parameters for quantization, colorspace ...
[media] vimc: cap: Support several image formats
- this is a new commit in the serie (the old one was splitted in two)
- allow user space to change all fields from struct v4l2_pix_format
(e.g. colospace, quantization, field, xfer_func, ycbcr_enc)
- link_validate and try_fmt: also checks colospace, quantization, field, xfer_func, ycbcr_enc
- add struct v4l2_pix_format fmt_default
- add enum_framesizes
- enum_fmt_vid_cap: enumerate all formats from vimc_pix_map_table
- add mode dev_dbg
[media] vimc: deb: Add debayer filter
- Using MEDIA_ENT_F_ATV_DECODER in function
- remove v4l2_dev and dev from vimc_deb_device struct
- src fmt propagates from the sink
- coding style
- remove redundant else if statements
- check end of enum and remove BUG_ON
- enum frame size with min and max values
- set/try fmt
- remove unecessary include freezer.h
- check pad types on create
- return EBUSY when trying to set the format while stream is on
- remove vsd struct
- add IS_SRC and IS_SINK macros
- add deb_mean_win_size as a parameter of the module
- check set_fmt default parameters for quantization, colorspace ...
- add more dev_dbg
[media] vimc: sca: Add scaler
- Add function MEDIA_ENT_F_IO_V4L
- remove v4l2_dev and dev
- s/sink_mbus_fmt/sink_fmt
- remove BUG_ON, remove redundant if else, rewrite TODO, check end of enum
- rm src_width/height, enum fsize with min and max values
- set/try fmt
- remove unecessary include freezer.h
- core: add bayer boolean in pixel table
- coding style
- fix bug in enum frame size
- check pad types on create
- return EBUSY when trying to set the format while stream is on
- remove vsd struct
- add IS_SRC and IS_SINK macros
- add sca_mult as a parameter of the module
- check set_fmt default parameters for quantization, colorspace ...
- add more dev_dbg
Helen Koike (7):
[media] vimc: sen: Integrate the tpg on the sensor [media] vimc: Add vimc_ent_sd_* helper functions [media] vimc: Add vimc_pipeline_s_stream in the core [media] vimc: sen: Support several image formats [media] vimc: cap: Support several image formats [media] vimc: deb: Add debayer filter [media] vimc: sca: Add scaler
drivers/media/platform/vimc/Kconfig | 1 + drivers/media/platform/vimc/Makefile | 3 +- drivers/media/platform/vimc/vimc-capture.c | 196 +++++++--- drivers/media/platform/vimc/vimc-core.c | 145 +++++++- drivers/media/platform/vimc/vimc-core.h | 65 ++++ drivers/media/platform/vimc/vimc-debayer.c | 573 +++++++++++++++++++++++++++++ drivers/media/platform/vimc/vimc-debayer.h | 28 ++ drivers/media/platform/vimc/vimc-scaler.c | 426 +++++++++++++++++++++ drivers/media/platform/vimc/vimc-scaler.h | 28 ++ drivers/media/platform/vimc/vimc-sensor.c | 226 ++++++++---- 10 files changed, 1562 insertions(+), 129 deletions(-) create mode 100644 drivers/media/platform/vimc/vimc-debayer.c create mode 100644 drivers/media/platform/vimc/vimc-debayer.h create mode 100644 drivers/media/platform/vimc/vimc-scaler.c create mode 100644 drivers/media/platform/vimc/vimc-scaler.h
Signature · 1 line
2.7.4
PATCH v2 1/7 vimc: sen: Integrate the tpg on the sensor
Initialize the test pattern generator on the sensor Generate a colored bar image instead of a grey one
---
Changes in v2:
[media] vimc: sen: Integrate the tpg on the sensor
- Fix include location
- Select V4L2_TPG in Kconfig
- configure tpg on streamon only
- rm BUG_ON
- coding style
--- drivers/media/platform/vimc/Kconfig | 1 + drivers/media/platform/vimc/vimc-sensor.c | 43 +++++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 2 deletions(-)
drivers/media/platform/vimc/Kconfig +1 -0
@@ -2,6 +2,7 @@ config VIDEO_VIMC tristate "Virtual Media Controller Driver (VIMC)" depends on VIDEO_DEV && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_VMALLOC + select VIDEO_V4L2_TPG default n ---help--- Skeleton driver for Virtual Media Controller
drivers/media/platform/vimc/vimc-sensor.c +41 -2
95 lines not on this page · raw message
Signature · 1 line
2.7.4
Re: [PATCH v2 1/7] [media] vimc: sen: Integrate the tpg on the sensor
Hi Helen,
A quick review:
Quoted 64 lines · Helen Koike
Initialize the test pattern generator on the sensor Generate a colored bar image instead of a grey one
Signed-off-by Helen Koike <[email protected]>---
Changes in v2:
[media] vimc: sen: Integrate the tpg on the sensor
- Fix include location
- SelectV4L2_TPGinKconfig
- configure tpg on streamon only
- rmBUG_ON
- coding style--- drivers/media/platform/vimc/Kconfig | 1 + drivers/media/platform/vimc/vimc-sensor.c | 43 +++++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 2 deletions(-)drivers/media/platform/vimc/Kconfig +1
-0@@ -2,6 +2,7 @@ config VIDEO_VIMC tristate "Virtual Media Controller Driver (VIMC)" depends on VIDEO_DEV && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_VMALLOC + select VIDEO_V4L2_TPG default n ---help--- Skeleton driver for Virtual Media Controllerdrivers/media/platform/vimc/vimc-sensor.c +10
-0@@ -20,12 +20,16 @@#include <linux/v4l2-mediabus.h> #include <linux/vmalloc.h> #include <media/v4l2-subdev.h> +#include <media/v4l2-tpg.h> #include "vimc-sensor.h" +#define VIMC_SEN_FRAME_MAX_WIDTH 4096 +struct vimc_sen_device {struct vimc_ent_device ved;struct v4l2_subdev sd; +struct tpg_data tpg;struct task_struct *kthread_sen;u8 *frame;/* The active format */ @@ -84,6 +88,28 @@ static int vimc_sen_get_fmt(struct v4l2_subdev *sd,return 0 ; } +static void vimc_sen_tpg_s_format (struct vimc_sen_device *vsen) +{ +const struct vimc_pix_map *vpix = +vimc_pix_map_by_code (vsen->mbus_format.code); + + tpg_reset_source(&vsen->tpg, vsen->mbus_format.width,
drivers/media/platform/vimc/vimc-sensor.c static int vimc_sen_get_fmt(struct v4l2_subdev *sd, · line 106
Quoted 10 lines
drivers/media/platform/vimc/vimc-sensor.c +10
-0+ vsen->mbus_format.height, vsen->mbus_format.field); +tpg_s_bytesperline (&vsen->tpg,0 , + vsen->mbus_format.width * vpix->bpp); +tpg_s_buf_height (&vsen->tpg, vsen->mbus_format.height); +tpg_s_fourcc (&vsen->tpg, vpix->pixelformat); +/* TODO: check why the tpg_s_field need this third argument if +* it is already receiving the field +*/ +tpg_s_field (&vsen->tpg, vsen->mbus_format.field, + vsen->mbus_format.field ==V4L2_FIELD_ALTERNATE );
V4L2_FIELD_ALTERNATE means that the driver will produce alternating top and bottom fields. The test pattern generator needs to know that, so the third argument here tells the tpg that this is indeed an alternating pattern.
The second argument tells it whether to generate a top or a bottom field, so this argument cannot be V4L2_FIELD_ALTERNATE.
Supporting FIELD_ALTERNATE is tricky. The best place to look at for how to use it is the vivid driver.
When you start generating frames you start off with the TOP field first.
The only exception to that is 60 Hz SDTV formats, but we're not supporting those in this vimc driver.
Quoted 10 lines
drivers/media/platform/vimc/vimc-sensor.c +6
-0+tpg_s_colorspace (&vsen->tpg, vsen->mbus_format.colorspace); +tpg_s_ycbcr_enc (&vsen->tpg, vsen->mbus_format.ycbcr_enc); +tpg_s_quantization (&vsen->tpg, vsen->mbus_format.quantization); +tpg_s_xfer_func (&vsen->tpg, vsen->mbus_format.xfer_func); +} +static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = { .enum_mbus_code = vimc_sen_enum_mbus_code, .enum_frame_size = vimc_sen_enum_frame_size,
drivers/media/platform/vimc/vimc-sensor.c static int vimc_thread_sen(void *data) · line 139
Quoted 5 lines
drivers/media/platform/vimc/vimc-sensor.c +1
-1@@ -110,7 +136,7 @@ static int vimc_thread_sen(void *data)if (kthread_should_stop ())break ; -memset (vsen->frame,100 , vsen->frame_size); +tpg_fill_plane_buffer (&vsen->tpg,V4L2_STD_PAL ,0 , vsen->frame);
Use 0 instead of V4L2_STD_PAL. We're not emulating a SDTV receiver here.
Quoted 40 lines
drivers/media/platform/vimc/vimc-sensor.c +11
-1/* Send the frame to all source pads */ for (i =0 ; i < vsen->sd.entity.num_pads; i++)@@ -159,6 +185,9 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) vsen->frame =NULL ;return PTR_ERR (vsen->kthread_sen); } + +/* configure the test pattern generator */ +vimc_sen_tpg_s_format (vsen); }else {if (!vsen->kthread_sen)return -EINVAL ;@@ -189,6 +218,7 @@ static void vimc_sen_destroy(struct vimc_ent_device *ved)struct vimc_sen_device *vsen = container_of(ved, struct vimc_sen_device, ved); +tpg_free (&vsen->tpg);v4l2_device_unregister_subdev (&vsen->sd);media_entity_cleanup (ved->ent);kfree (vsen);@@ -254,17 +284,26 @@ struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, vsen->mbus_format.quantization =V4L2_QUANTIZATION_FULL_RANGE ; vsen->mbus_format.xfer_func =V4L2_XFER_FUNC_SRGB ; +/* Initialize the test pattern generator */ +tpg_init (&vsen->tpg, vsen->mbus_format.width, + vsen->mbus_format.height); + ret =tpg_alloc (&vsen->tpg,VIMC_SEN_FRAME_MAX_WIDTH ); +if (ret) + goto err_clean_m_ent; +/* Register the subdev with the v4l2 and the media framework */ ret =v4l2_device_register_subdev (v4l2_dev, &vsen->sd);if (ret) {dev_err (vsen->sd.v4l2_dev->dev,"%s: subdev register failed (err=%d)\n" , vsen->sd.name, ret); - goto err_clean_m_ent;
drivers/media/platform/vimc/vimc-sensor.c struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, · line 309
Quoted 10 lines
drivers/media/platform/vimc/vimc-sensor.c +3
-0+ goto err_free_tpg; }return &vsen->ved; +err_free_tpg: +tpg_free (&vsen->tpg); err_clean_m_ent:media_entity_cleanup (&vsen->sd.entity); err_clean_pads:
Regards,
Hans
PATCH v2 2/7 vimc: Add vimc_ent_sd_* helper functions
In reply to Helen KoikeAs all the subdevices in the topology will be initialized in the same way, to avoid code repetition the vimc_ent_sd_{register, unregister} helper functions were created
---
Changes in v2:
[media] vimc: Add vimc_ent_sd_* helper functions
- Comments in vimc_ent_sd_init
- Update vimc_ent_sd_init with upstream code as media_entity_pads_init (instead of media_entity_init), entity->function intead of entity->type
- Add missing vimc_pads_cleanup in vimc_ent_sd_cleanup
- remove subdevice v4l2_dev and dev fields
- change unregister order in vimc_ent_sd_cleanup
- rename vimc_ent_sd_{init,cleanup} to vimc_ent_sd_{register,unregister}
- remove struct vimc_ent_subdevice, use ved and sd directly
- don't impose struct vimc_sen_device to declare ved and sd struct first
- add kernel docs
--- drivers/media/platform/vimc/vimc-core.c | 66 +++++++++++++++++++++++++++++++ drivers/media/platform/vimc/vimc-core.h | 39 ++++++++++++++++++ drivers/media/platform/vimc/vimc-sensor.c | 58 +++++---------------------- 3 files changed, 114 insertions(+), 49 deletions(-)
drivers/media/platform/vimc/vimc-core.c +66 -0
@@ -416,6 +416,72 @@ struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag)return pads; } +static const struct media_entity_operations vimc_ent_sd_mops = { + .link_validate = v4l2_subdev_link_validate, +}; + +int vimc_ent_sd_register (struct vimc_ent_device *ved, +struct v4l2_subdev *sd, +struct v4l2_device *v4l2_dev, +const char *const name, +u32 function, +u16 num_pads, +const unsigned long *pads_flag, +const struct v4l2_subdev_ops *sd_ops, +void (*sd_destroy)(struct vimc_ent_device *)) +{ +int ret; + +/* Allocate the pads */ + ved->pads =vimc_pads_init (num_pads, pads_flag); +if (IS_ERR (ved->pads)) +return PTR_ERR (ved->pads); + +/* Fill the vimc_ent_device struct */ + ved->destroy = sd_destroy; + ved->ent = &sd->entity; + +/* Initialize the subdev */ +v4l2_subdev_init (sd, sd_ops); + sd->entity.function =MEDIA_ENT_F_CAM_SENSOR ; + sd->entity.ops = &vimc_ent_sd_mops; + sd->owner =THIS_MODULE ; +strlcpy (sd->name, name,sizeof (sd->name)); +v4l2_set_subdevdata (sd, ved); + +/* Expose this subdev to user space */ + sd->flags =V4L2_SUBDEV_FL_HAS_DEVNODE ; + +/* Initialize the media entity */ + ret =media_entity_pads_init (&sd->entity, num_pads, ved->pads); +if (ret) + goto err_clean_pads; + +/* Register the subdev with the v4l2 and the media framework */ + ret =v4l2_device_register_subdev (v4l2_dev, sd); +if (ret) { +dev_err (v4l2_dev->dev, +"%s: subdev register failed (err=%d)\n" , + name, ret); + goto err_clean_m_ent; + } + +return 0 ; + +err_clean_m_ent: +media_entity_cleanup (&sd->entity); +err_clean_pads: +vimc_pads_cleanup (ved->pads); +return ret; +} + +void vimc_ent_sd_unregister (struct vimc_ent_device *ved,struct v4l2_subdev *sd) +{ +v4l2_device_unregister_subdev (sd); +media_entity_cleanup (ved->ent); +vimc_pads_cleanup (ved->pads); +} +/* * TODO: remove this function when all the * entities specific code are implemented
drivers/media/platform/vimc/vimc-core.h +39 -0
@@ -109,4 +109,43 @@ const struct vimc_pix_map *vimc_pix_map_by_code(u32 code);*/ const struct vimc_pix_map *vimc_pix_map_by_pixelformat (u32 pixelformat); +/** +* vimc_ent_sd_register - initialize and register a subdev node +* +* @ved: the vimc_ent_device struct to be initialize +* @sd: the v4l2_subdev struct to be initialize and registered +* @v4l2_dev: the v4l2 device to register the v4l2_subdev +* @name: name of the sub-device. Please notice that the name must be +* unique. +* @function: media entity function defined by MEDIA_ENT_F_* macros +* @num_pads: number of pads to initialize +* @pads_flag: flags to use in each pad +* @sd_ops: pointer to &struct v4l2_subdev_ops. +* @sd_destroy: callback to destroy the node +* +* Helper function initialize and register the struct vimc_ent_device and struct +* v4l2_subdev which represents a subdev node in the topology +*/ +int vimc_ent_sd_register (struct vimc_ent_device *ved, +struct v4l2_subdev *sd, +struct v4l2_device *v4l2_dev, +const char *const name, +u32 function, +u16 num_pads, +const unsigned long *pads_flag, +const struct v4l2_subdev_ops *sd_ops, +void (*sd_destroy)(struct vimc_ent_device *)); + +/** +* vimc_ent_sd_register - initialize and register a subdev node +* +* @ved: the vimc_ent_device struct to be initialize +* @sd: the v4l2_subdev struct to be initialize and registered +* +* Helper function cleanup and unregister the struct vimc_ent_device and struct +* v4l2_subdev which represents a subdev node in the topology +*/ +void vimc_ent_sd_unregister (struct vimc_ent_device *ved, +struct v4l2_subdev *sd); +#endif
drivers/media/platform/vimc/vimc-sensor.c +9 -49
87 lines not on this page · raw message
Signature · 1 line
2.7.4
Re: [PATCH v2 2/7] [media] vimc: Add vimc_ent_sd_* helper functions
Quoted 54 lines · Helen Koike
As all the subdevices in the topology will be initialized in the same way, to avoid code repetition the vimc_ent_sd_{register, unregister} helper functions were created
Signed-off-by Helen Koike <[email protected]>---
Changes in v2:
[media] vimc: Add vimc_ent_sd_* helper functions
- Comments invimc_ent_sd_init
- Updatevimc_ent_sd_initwith upstream code asmedia_entity_pads_init(instead ofmedia_entity_init),entity->functionintead ofentity->type
- Add missingvimc_pads_cleanupinvimc_ent_sd_cleanup
- remove subdevicev4l2_devand dev fields
- change unregister order invimc_ent_sd_cleanup
- rename vimc_ent_sd_{init,cleanup} to vimc_ent_sd_{register,unregister}
- remove structvimc_ent_subdevice, use ved and sd directly
- don't impose structvimc_sen_deviceto declare ved and sd struct first
- add kernel docs--- drivers/media/platform/vimc/vimc-core.c | 66 +++++++++++++++++++++++++++++++ drivers/media/platform/vimc/vimc-core.h | 39 ++++++++++++++++++ drivers/media/platform/vimc/vimc-sensor.c | 58 +++++---------------------- 3 files changed, 114 insertions(+), 49 deletions(-)drivers/media/platform/vimc/vimc-core.c +18
-0@@ -416,6 +416,72 @@ struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag)return pads; } +static const struct media_entity_operations vimc_ent_sd_mops = { + .link_validate = v4l2_subdev_link_validate, +}; + +int vimc_ent_sd_register (struct vimc_ent_device *ved, +struct v4l2_subdev *sd, +struct v4l2_device *v4l2_dev, +const char *const name, +u32 function, +u16 num_pads, +const unsigned long *pads_flag, +const struct v4l2_subdev_ops *sd_ops, +void (*sd_destroy)(struct vimc_ent_device *)) +{ +int ret; + +/* Allocate the pads */ + ved->pads =vimc_pads_init (num_pads, pads_flag);
drivers/media/platform/vimc/vimc-core.c struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag) · line 446
Quoted 10 lines
drivers/media/platform/vimc/vimc-core.c +10
-0+if (IS_ERR (ved->pads)) +return PTR_ERR (ved->pads); + +/* Fill the vimc_ent_device struct */ + ved->destroy = sd_destroy; + ved->ent = &sd->entity; + +/* Initialize the subdev */ +v4l2_subdev_init (sd, sd_ops); + sd->entity.function =MEDIA_ENT_F_CAM_SENSOR ;
Huh? Shouldn't this be:
sd->entity.function = function;
Quoted 175 lines
drivers/media/platform/vimc/vimc-core.c +38
-0+ sd->entity.ops = &vimc_ent_sd_mops; + sd->owner =THIS_MODULE ; +strlcpy (sd->name, name,sizeof (sd->name)); +v4l2_set_subdevdata (sd, ved); + +/* Expose this subdev to user space */ + sd->flags =V4L2_SUBDEV_FL_HAS_DEVNODE ; + +/* Initialize the media entity */ + ret =media_entity_pads_init (&sd->entity, num_pads, ved->pads); +if (ret) + goto err_clean_pads; + +/* Register the subdev with the v4l2 and the media framework */ + ret =v4l2_device_register_subdev (v4l2_dev, sd); +if (ret) { +dev_err (v4l2_dev->dev, +"%s: subdev register failed (err=%d)\n" , + name, ret); + goto err_clean_m_ent; + } + +return 0 ; + +err_clean_m_ent: +media_entity_cleanup (&sd->entity); +err_clean_pads: +vimc_pads_cleanup (ved->pads); +return ret; +} + +void vimc_ent_sd_unregister (struct vimc_ent_device *ved,struct v4l2_subdev *sd) +{ +v4l2_device_unregister_subdev (sd); +media_entity_cleanup (ved->ent); +vimc_pads_cleanup (ved->pads); +} +/* * TODO: remove this function when all the * entities specific code are implemented drivers/media/platform/vimc/vimc-core.h +39
-0@@ -109,4 +109,43 @@ const struct vimc_pix_map *vimc_pix_map_by_code(u32 code);*/ const struct vimc_pix_map *vimc_pix_map_by_pixelformat (u32 pixelformat); +/** +* vimc_ent_sd_register - initialize and register a subdev node +* +* @ved: the vimc_ent_device struct to be initialize +* @sd: the v4l2_subdev struct to be initialize and registered +* @v4l2_dev: the v4l2 device to register the v4l2_subdev +* @name: name of the sub-device. Please notice that the name must be +* unique. +* @function: media entity function defined by MEDIA_ENT_F_* macros +* @num_pads: number of pads to initialize +* @pads_flag: flags to use in each pad +* @sd_ops: pointer to &struct v4l2_subdev_ops. +* @sd_destroy: callback to destroy the node +* +* Helper function initialize and register the struct vimc_ent_device and struct +* v4l2_subdev which represents a subdev node in the topology +*/ +int vimc_ent_sd_register (struct vimc_ent_device *ved, +struct v4l2_subdev *sd, +struct v4l2_device *v4l2_dev, +const char *const name, +u32 function, +u16 num_pads, +const unsigned long *pads_flag, +const struct v4l2_subdev_ops *sd_ops, +void (*sd_destroy)(struct vimc_ent_device *)); + +/** +* vimc_ent_sd_register - initialize and register a subdev node +* +* @ved: the vimc_ent_device struct to be initialize +* @sd: the v4l2_subdev struct to be initialize and registered +* +* Helper function cleanup and unregister the struct vimc_ent_device and struct +* v4l2_subdev which represents a subdev node in the topology +*/ +void vimc_ent_sd_unregister (struct vimc_ent_device *ved, +struct v4l2_subdev *sd); +#endif drivers/media/platform/vimc/vimc-sensor.c +7
-44@@ -118,11 +118,6 @@ static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = { .set_fmt = vimc_sen_get_fmt, }; -/* media operations */ -static const struct media_entity_operations vimc_sen_mops = { - .link_validate = v4l2_subdev_link_validate, -}; -static int vimc_thread_sen (void *data) {struct vimc_sen_device *vsen = data;@@ -218,9 +213,8 @@ static void vimc_sen_destroy(struct vimc_ent_device *ved)struct vimc_sen_device *vsen = container_of(ved, struct vimc_sen_device, ved); +vimc_ent_sd_unregister (ved, &vsen->sd);tpg_free (&vsen->tpg); -v4l2_device_unregister_subdev (&vsen->sd); -media_entity_cleanup (ved->ent);kfree (vsen); }@@ -247,33 +241,12 @@ struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev,if (!vsen)return ERR_PTR (-ENOMEM ); -/* Allocate the pads */ - vsen->ved.pads =vimc_pads_init (num_pads, pads_flag); -if (IS_ERR (vsen->ved.pads)) { - ret =PTR_ERR (vsen->ved.pads); - goto err_free_vsen; - } - -/* Fill the vimc_ent_device struct */ - vsen->ved.destroy = vimc_sen_destroy; - vsen->ved.ent = &vsen->sd.entity; - -/* Initialize the subdev */ -v4l2_subdev_init (&vsen->sd, &vimc_sen_ops); - vsen->sd.entity.function =MEDIA_ENT_F_CAM_SENSOR ; - vsen->sd.entity.ops = &vimc_sen_mops; - vsen->sd.owner =THIS_MODULE ; -strlcpy (vsen->sd.name, name,sizeof (vsen->sd.name)); -v4l2_set_subdevdata (&vsen->sd, &vsen->ved); - -/* Expose this subdev to user space */ - vsen->sd.flags =V4L2_SUBDEV_FL_HAS_DEVNODE ; - -/* Initialize the media entity */ - ret =media_entity_pads_init (&vsen->sd.entity, - num_pads, vsen->ved.pads); +/* Initialize ved and sd */ + ret =vimc_ent_sd_register (&vsen->ved, &vsen->sd, v4l2_dev, name, +MEDIA_ENT_F_CAM_SENSOR , num_pads, pads_flag, + &vimc_sen_ops, vimc_sen_destroy);if (ret) - goto err_clean_pads; + goto err_free_vsen;/* Set the active frame format (this is hardcoded for now) */ vsen->mbus_format.width =640 ;@@ -289,25 +262,12 @@ struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, vsen->mbus_format.height); ret =tpg_alloc (&vsen->tpg,VIMC_SEN_FRAME_MAX_WIDTH );if (ret) - goto err_clean_m_ent; - -/* Register the subdev with the v4l2 and the media framework */ - ret =v4l2_device_register_subdev (v4l2_dev, &vsen->sd); -if (ret) { -dev_err (vsen->sd.v4l2_dev->dev, -"%s: subdev register failed (err=%d)\n" , - vsen->sd.name, ret); - goto err_free_tpg; - } + goto err_unregister_ent_sd;return &vsen->ved; -err_free_tpg:
drivers/media/platform/vimc/vimc-sensor.c struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, · line 273
Quoted 10 lines
drivers/media/platform/vimc/vimc-sensor.c +2
-5-tpg_free (&vsen->tpg); -err_clean_m_ent: -media_entity_cleanup (&vsen->sd.entity); -err_clean_pads: -vimc_pads_cleanup (vsen->ved.pads); +err_unregister_ent_sd: +vimc_ent_sd_unregister (&vsen->ved, &vsen->sd); err_free_vsen:kfree (vsen);
Regards,
Hans
PATCH v2 3/7 vimc: Add vimc_pipeline_s_stream in the core
In reply to Helen KoikeMove the vimc_cap_pipeline_s_stream from the vimc-cap.c to vimc-core.c as this core will be reused by other subdevices to activate the stream in their directly connected nodes
---
Changes in v2:
[media] vimc: Add vimc_pipeline_s_stream in the core
- Use is_media_entity_v4l2_subdev instead of comparing with the old entity->type
- Fix comments style
- add kernel-docs
- call s_stream across all sink pads
--- drivers/media/platform/vimc/vimc-capture.c | 29 ++------------------------- drivers/media/platform/vimc/vimc-core.c | 32 ++++++++++++++++++++++++++++++ drivers/media/platform/vimc/vimc-core.h | 11 ++++++++++ 3 files changed, 45 insertions(+), 27 deletions(-)
drivers/media/platform/vimc/vimc-capture.c +2 -27
@@ -132,31 +132,6 @@ static void vimc_cap_return_all_buffers(struct vimc_cap_device *vcap,spin_unlock (&vcap->qlock); } -static int vimc_cap_pipeline_s_stream (struct vimc_cap_device *vcap,int enable) -{ -struct v4l2_subdev *sd; -struct media_pad *pad; -int ret; - -/* Start the stream in the subdevice direct connected */ - pad =media_entity_remote_pad (&vcap->vdev.entity.pads[0 ]); - -/* -* if it is a raw node from vimc-core, there is nothing to activate -* TODO: remove this when there are no more raw nodes in the -* core and return error instead -*/ -if (pad->entity->obj_type ==MEDIA_ENTITY_TYPE_BASE ) -return 0 ; - - sd =media_entity_to_v4l2_subdev (pad->entity); - ret =v4l2_subdev_call (sd, video, s_stream, enable); -if (ret && ret != -ENOIOCTLCMD ) -return ret; - -return 0 ; -} -static int vimc_cap_start_streaming (struct vb2_queue *vq,unsigned int count) {struct vimc_cap_device *vcap =vb2_get_drv_priv (vq);
@@ -173,7 +148,7 @@ static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count) }/* Enable streaming from the pipe */ - ret =vimc_cap_pipeline_s_stream (vcap,1 ); + ret =vimc_pipeline_s_stream (&vcap->vdev.entity,1 );if (ret) {media_pipeline_stop (entity);vimc_cap_return_all_buffers (vcap,VB2_BUF_STATE_QUEUED );
@@ -192,7 +167,7 @@ static void vimc_cap_stop_streaming(struct vb2_queue *vq)struct vimc_cap_device *vcap =vb2_get_drv_priv (vq);/* Disable streaming from the pipe */ -vimc_cap_pipeline_s_stream (vcap,0 ); +vimc_pipeline_s_stream (&vcap->vdev.entity,0 );/* Stop the media pipeline */ media_pipeline_stop (&vcap->vdev.entity);
drivers/media/platform/vimc/vimc-core.c +32 -0
@@ -396,6 +396,38 @@ static void vimc_device_unregister(struct vimc_device *vimc)media_device_cleanup (&vimc->mdev); } +int vimc_pipeline_s_stream (struct media_entity *ent,int enable) +{ +struct v4l2_subdev *sd; +struct media_pad *pad; +unsigned int i; +int ret; + +for (i =0 ; i < ent->num_pads; i++) { +if (ent->pads[i].flags &MEDIA_PAD_FL_SOURCE ) +continue ; + +/* Start the stream in the subdevice direct connected */ + pad =media_entity_remote_pad (&ent->pads[i]); + +/* +* if this is a raw node from vimc-core, then there is +* nothing to activate +* TODO: remove this when there are no more raw nodes in the +* core and return error instead +*/ +if (pad->entity->obj_type ==MEDIA_ENTITY_TYPE_BASE ) +continue ; + + sd =media_entity_to_v4l2_subdev (pad->entity); + ret =v4l2_subdev_call (sd, video, s_stream, enable); +if (ret && ret != -ENOIOCTLCMD ) +return ret; + } + +return 0 ; +} +/* Helper function to allocate and initialize pads */ struct media_pad *vimc_pads_init (u16 num_pads,const unsigned long *pads_flag) {
drivers/media/platform/vimc/vimc-core.h +11 -0
@@ -96,6 +96,17 @@ static inline void vimc_pads_cleanup(struct media_pad *pads) }/** +* vimc_pipeline_s_stream - start stream through the pipeline +* +* @ent: the pointer to struct media_entity for the node +* @enable: 1 to start the stream and 0 to stop +* +* Helper function to call the s_stream of the subdevices connected +* in all the sink pads of the entity +*/ +int vimc_pipeline_s_stream (struct media_entity *ent,int enable); + +/** * vimc_pix_map_by_code - get vimc_pix_map struct by media bus code * * @code: media bus format code defined by MEDIA_BUS_FMT_* macros
Signature · 1 line
2.7.4
PATCH v2 4/7 vimc: sen: Support several image formats
In reply to Helen KoikeAllow user space to change the image format as the frame size, the media bus pixel format, colorspace, quantization, field YCbCr encoding and the transfer function
---
Changes in v2:
[media] vimc: sen: Support several image formats
- this is a new commit in the serie (the old one was splitted in two)
- add init_cfg to initialize try_fmt
- reorder code in vimc_sen_set_fmt
- allow user space to change all fields from struct v4l2_mbus_framefmt (e.g. colospace, quantization, field, xfer_func, ycbcr_enc)
- merge with patch for the enum_mbus_code and enum_frame_size
- change commit message
- add vimc_pix_map_by_index
- rename MIN/MAX macros
- check set_fmt default parameters for quantization, colorspace ...
--- drivers/media/platform/vimc/vimc-core.c | 8 ++ drivers/media/platform/vimc/vimc-core.h | 12 +++ drivers/media/platform/vimc/vimc-sensor.c | 143 ++++++++++++++++++++++++------ 3 files changed, 134 insertions(+), 29 deletions(-)
drivers/media/platform/vimc/vimc-core.c +8 -0
@@ -324,6 +324,14 @@ static const struct vimc_pix_map vimc_pix_map_list[] = { }, }; +const struct vimc_pix_map *vimc_pix_map_by_index (unsigned int i) +{ +if (i >=ARRAY_SIZE (vimc_pix_map_list)) +return NULL ; + +return &vimc_pix_map_list[i]; +} +const struct vimc_pix_map *vimc_pix_map_by_code (u32 code) {unsigned int i;
drivers/media/platform/vimc/vimc-core.h +12 -0
@@ -21,6 +21,11 @@#include <linux/slab.h> #include <media/v4l2-device.h> +#define VIMC_FRAME_MAX_WIDTH 4096 +#define VIMC_FRAME_MAX_HEIGHT 2160 +#define VIMC_FRAME_MIN_WIDTH 16 +#define VIMC_FRAME_MIN_HEIGHT 16 +/** * struct vimc_pix_map - maps media bus code with v4l2 pixel format *
@@ -107,6 +112,13 @@ static inline void vimc_pads_cleanup(struct media_pad *pads)int vimc_pipeline_s_stream (struct media_entity *ent,int enable);/** +* vimc_pix_map_by_index - get vimc_pix_map struct by its index +* +* @i: index of the vimc_pix_map struct in vimc_pix_map_list +*/ +const struct vimc_pix_map *vimc_pix_map_by_index (unsigned int i); + +/** * vimc_pix_map_by_code - get vimc_pix_map struct by media bus code * * @code: media bus format code defined by MEDIA_BUS_FMT_* macros
drivers/media/platform/vimc/vimc-sensor.c +114 -29
204 lines not on this page · raw message
Signature · 1 line
2.7.4
Re: [PATCH v2 4/7] [media] vimc: sen: Support several image formats
Quoted 190 lines · Helen Koike
Allow user space to change the image format as the frame size, the media bus pixel format, colorspace, quantization, field YCbCr encoding and the transfer function
Signed-off-by Helen Koike <[email protected]>---
Changes in v2:
[media] vimc: sen: Support several image formats
- this is a new commit in the serie (the old one was splitted in two)
- addinit_cfgto initializetry_fmt
- reorder code invimc_sen_set_fmt
- allow user space to change all fields from structv4l2_mbus_framefmt(e.g. colospace, quantization, field,xfer_func,ycbcr_enc)
- merge with patch for theenum_mbus_codeandenum_frame_size
- change commit message
- addvimc_pix_map_by_index
- rename MIN/MAX macros
- checkset_fmtdefault parameters for quantization, colorspace ...--- drivers/media/platform/vimc/vimc-core.c | 8 ++ drivers/media/platform/vimc/vimc-core.h | 12 +++ drivers/media/platform/vimc/vimc-sensor.c | 143 ++++++++++++++++++++++++------ 3 files changed, 134 insertions(+), 29 deletions(-)drivers/media/platform/vimc/vimc-core.c +8
-0@@ -324,6 +324,14 @@ static const struct vimc_pix_map vimc_pix_map_list[] = { }, }; +const struct vimc_pix_map *vimc_pix_map_by_index (unsigned int i) +{ +if (i >=ARRAY_SIZE (vimc_pix_map_list)) +return NULL ; + +return &vimc_pix_map_list[i]; +} +const struct vimc_pix_map *vimc_pix_map_by_code (u32 code) {unsigned int i;drivers/media/platform/vimc/vimc-core.h +12
-0@@ -21,6 +21,11 @@#include <linux/slab.h> #include <media/v4l2-device.h> +#define VIMC_FRAME_MAX_WIDTH 4096 +#define VIMC_FRAME_MAX_HEIGHT 2160 +#define VIMC_FRAME_MIN_WIDTH 16 +#define VIMC_FRAME_MIN_HEIGHT 16 +/** * struct vimc_pix_map - maps media bus code with v4l2 pixel format * @@ -107,6 +112,13 @@ static inline void vimc_pads_cleanup(struct media_pad *pads)int vimc_pipeline_s_stream (struct media_entity *ent,int enable);/** +* vimc_pix_map_by_index - get vimc_pix_map struct by its index +* +* @i: index of the vimc_pix_map struct in vimc_pix_map_list +*/ +const struct vimc_pix_map *vimc_pix_map_by_index (unsigned int i); + +/** * vimc_pix_map_by_code - get vimc_pix_map struct by media bus code * * @code: media bus format code defined by MEDIA_BUS_FMT_* macros drivers/media/platform/vimc/vimc-sensor.c +43
-18@@ -24,8 +24,6 @@#include "vimc-sensor.h" -#define VIMC_SEN_FRAME_MAX_WIDTH 4096 -struct vimc_sen_device {struct vimc_ent_device ved;struct v4l2_subdev sd;@@ -37,18 +35,41 @@ struct vimc_sen_device {int frame_size; }; +static const struct v4l2_mbus_framefmt fmt_default = { + .width =640 , + .height =480 , + .code =MEDIA_BUS_FMT_RGB888_1X24 , + .field =V4L2_FIELD_NONE , + .colorspace =V4L2_COLORSPACE_SRGB , + .quantization =V4L2_QUANTIZATION_FULL_RANGE , + .xfer_func =V4L2_XFER_FUNC_SRGB , +}; + +static int vimc_sen_init_cfg (struct v4l2_subdev *sd, +struct v4l2_subdev_pad_config *cfg) +{ +unsigned int i; + +for (i =0 ; i < sd->entity.num_pads; i++) { +struct v4l2_mbus_framefmt *mf; + + mf =v4l2_subdev_get_try_format (sd, cfg, i); + *mf = fmt_default; + } + +return 0 ; +} +static int vimc_sen_enum_mbus_code (struct v4l2_subdev *sd,struct v4l2_subdev_pad_config *cfg,struct v4l2_subdev_mbus_code_enum *code) { -struct vimc_sen_device *vsen = - container_of(sd, struct vimc_sen_device, sd); +const struct vimc_pix_map *vpix =vimc_pix_map_by_index (code->index); -/* TODO: Add support for other codes */ -if (code->index) +if (!vpix)return -EINVAL ; - code->code = vsen->mbus_format.code; + code->code = vpix->code;return 0 ; }@@ -57,33 +78,34 @@ static int vimc_sen_enum_frame_size(struct v4l2_subdev *sd,struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { - struct vimc_sen_device *vsen = - container_of(sd, struct vimc_sen_device, sd); + const struct vimc_pix_map *vpix; -/* TODO: Add support to other formats */ if (fse->index)return -EINVAL ; -/* TODO: Add support for other codes */ -if (fse->code != vsen->mbus_format.code) +/* Only accept code in the pix map table */ + vpix =vimc_pix_map_by_code (fse->code); +if (!vpix)return -EINVAL ; - fse->min_width = vsen->mbus_format.width; - fse->max_width = vsen->mbus_format.width; - fse->min_height = vsen->mbus_format.height; - fse->max_height = vsen->mbus_format.height; + fse->min_width =VIMC_FRAME_MIN_WIDTH ; + fse->max_width =VIMC_FRAME_MAX_WIDTH ; + fse->min_height =VIMC_FRAME_MIN_HEIGHT ; + fse->max_height =VIMC_FRAME_MAX_HEIGHT ;return 0 ; }static int vimc_sen_get_fmt (struct v4l2_subdev *sd,struct v4l2_subdev_pad_config *cfg, -struct v4l2_subdev_format *format) +struct v4l2_subdev_format *fmt) {struct vimc_sen_device *vsen = container_of(sd, struct vimc_sen_device, sd); - format->format = vsen->mbus_format; + fmt->format = fmt->which ==V4L2_SUBDEV_FORMAT_TRY ? + *v4l2_subdev_get_try_format (sd, cfg, fmt->pad) : + vsen->mbus_format;return 0 ; }@@ -110,12 +132,81 @@ static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen)tpg_s_xfer_func (&vsen->tpg, vsen->mbus_format.xfer_func); } +static void vimc_sen_adjust_fmt (struct v4l2_mbus_framefmt *fmt) +{ +const struct vimc_pix_map *vpix;
drivers/media/platform/vimc/vimc-sensor.c static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen) · line 147
Quoted 10 lines
drivers/media/platform/vimc/vimc-sensor.c +10
-0+ +/* Only accept code in the pix map table */ + vpix =vimc_pix_map_by_code (fmt->code); +if (!vpix) + fmt->code = fmt_default.code; + + fmt->width =clamp_t (u32, fmt->width,VIMC_FRAME_MIN_WIDTH , +VIMC_FRAME_MAX_WIDTH ); + fmt->height =clamp_t (u32, fmt->height,VIMC_FRAME_MIN_HEIGHT , +VIMC_FRAME_MAX_HEIGHT );
I would expect that width and height need to be multiple of some value. Height needs to be a multiple of 2 (otherwise you can never support interlaced formats). Width needs to be a multiple of 2 at minimum as well.
drivers/media/platform/vimc/vimc-sensor.c static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen) · line 155
Quoted 8 lines
drivers/media/platform/vimc/vimc-sensor.c +8
-0+ +if (fmt->field ==V4L2_FIELD_ANY ) + fmt->field = fmt_default.field; + +/* Check if values are out of range */ +if (fmt->colorspace ==V4L2_COLORSPACE_DEFAULT + || fmt->colorspace >V4L2_COLORSPACE_DCI_P3 ) + fmt->colorspace = fmt_default.colorspace;
If the colorspace is invalid, then set all four fields to their defaults.
drivers/media/platform/vimc/vimc-sensor.c static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen) · line 164
Quoted 9 lines
drivers/media/platform/vimc/vimc-sensor.c +9
-0+if (fmt->ycbcr_enc ==V4L2_YCBCR_ENC_DEFAULT + || fmt->ycbcr_enc >V4L2_YCBCR_ENC_SMPTE240M ) + fmt->ycbcr_enc = fmt_default.ycbcr_enc; +if (fmt->quantization ==V4L2_QUANTIZATION_DEFAULT + || fmt->quantization >V4L2_QUANTIZATION_LIM_RANGE ) + fmt->quantization = fmt_default.quantization; +if (fmt->xfer_func ==V4L2_XFER_FUNC_DEFAULT + || fmt->xfer_func >V4L2_XFER_FUNC_SMPTE2084 ) + fmt->xfer_func = fmt_default.xfer_func;
The _DEFAULT values are all valid for these three fields. If they have an unknown value, then just reset them to the _DEFAULT value.
Quoted 64 lines
drivers/media/platform/vimc/vimc-sensor.c +42
-10+} + +static int vimc_sen_set_fmt (struct v4l2_subdev *sd, +struct v4l2_subdev_pad_config *cfg, +struct v4l2_subdev_format *fmt) +{ +struct vimc_sen_device *vsen =v4l2_get_subdevdata (sd); +struct v4l2_mbus_framefmt *mf; + +if (fmt->which ==V4L2_SUBDEV_FORMAT_ACTIVE ) { +/* Do not change the format while stream is on */ +if (vsen->frame) +return -EBUSY ; + + mf = &vsen->mbus_format; + }else { + mf =v4l2_subdev_get_try_format (sd, cfg, fmt->pad); + } + +/* Set the new format */ +vimc_sen_adjust_fmt (&fmt->format); + +dev_dbg (vsen->sd.v4l2_dev->mdev->dev,"%s: format update: " +"old:%dx%d (0x%x, %d, %d, %d, %d) " +"new:%dx%d (0x%x, %d, %d, %d, %d)\n" , vsen->sd.name, +/* old */ + mf->width, mf->height, mf->code, + mf->colorspace, mf->quantization, + mf->xfer_func, mf->ycbcr_enc, +/* new */ + fmt->format.width, fmt->format.height, fmt->format.code, + fmt->format.colorspace, fmt->format.quantization, + fmt->format.xfer_func, fmt->format.ycbcr_enc); + + *mf = fmt->format; + +return 0 ; +} +static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = { + .init_cfg = vimc_sen_init_cfg, .enum_mbus_code = vimc_sen_enum_mbus_code, .enum_frame_size = vimc_sen_enum_frame_size, .get_fmt = vimc_sen_get_fmt, -/* TODO: Add support to other formats */ - .set_fmt = vimc_sen_get_fmt, + .set_fmt = vimc_sen_set_fmt, };static int vimc_thread_sen (void *data)@@ -248,19 +339,13 @@ struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev,if (ret) goto err_free_vsen; -/* Set the active frame format (this is hardcoded for now) */ - vsen->mbus_format.width =640 ; - vsen->mbus_format.height =480 ; - vsen->mbus_format.code =MEDIA_BUS_FMT_RGB888_1X24 ; - vsen->mbus_format.field =V4L2_FIELD_NONE ; - vsen->mbus_format.colorspace =V4L2_COLORSPACE_SRGB ; - vsen->mbus_format.quantization =V4L2_QUANTIZATION_FULL_RANGE ; - vsen->mbus_format.xfer_func =V4L2_XFER_FUNC_SRGB ; +/* Initialize the frame format */
drivers/media/platform/vimc/vimc-sensor.c struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, · line 351
Quoted 10 lines
drivers/media/platform/vimc/vimc-sensor.c +2
-1+ vsen->mbus_format = fmt_default;/* Initialize the test pattern generator */ tpg_init (&vsen->tpg, vsen->mbus_format.width, vsen->mbus_format.height); - ret =tpg_alloc (&vsen->tpg,VIMC_SEN_FRAME_MAX_WIDTH ); + ret =tpg_alloc (&vsen->tpg,VIMC_FRAME_MAX_WIDTH );if (ret) goto err_unregister_ent_sd;
Regards,
Hans
PATCH v2 5/7 vimc: cap: Support several image formats
In reply to Helen KoikeAllow user space to change the image format as the frame size, the pixel format, colorspace, quantization, field YCbCr encoding and the transfer function
---
Changes in v2:
[media] vimc: cap: Support several image formats
- this is a new commit in the serie (the old one was splitted in two)
- allow user space to change all fields from struct v4l2_pix_format
(e.g. colospace, quantization, field, xfer_func, ycbcr_enc)
- link_validate and try_fmt: also checks colospace, quantization, field, xfer_func, ycbcr_enc
- add struct v4l2_pix_format fmt_default
- add enum_framesizes
- enum_fmt_vid_cap: enumerate all formats from vimc_pix_map_table
- add mode dev_dbg
--- drivers/media/platform/vimc/vimc-capture.c | 167 ++++++++++++++++++++++++----- 1 file changed, 139 insertions(+), 28 deletions(-)
drivers/media/platform/vimc/vimc-capture.c +139 -28
@@ -40,6 +40,16 @@ struct vimc_cap_device {struct media_pipeline pipe; }; +static const struct v4l2_pix_format fmt_default = { + .width =640 , + .height =480 , + .pixelformat =V4L2_PIX_FMT_RGB24 , + .field =V4L2_FIELD_NONE , + .colorspace =V4L2_COLORSPACE_SRGB , + .quantization =V4L2_QUANTIZATION_FULL_RANGE , + .xfer_func =V4L2_XFER_FUNC_SRGB , +}; +struct vimc_cap_buffer {/* * struct vb2_v4l2_buffer must be the first element
@@ -64,7 +74,7 @@ static int vimc_cap_querycap(struct file *file, void *priv,return 0 ; } -static int vimc_cap_fmt_vid_cap (struct file *file,void *priv, +static int vimc_cap_g_fmt_vid_cap (struct file *file,void *priv,struct v4l2_format *f) {struct vimc_cap_device *vcap =video_drvdata (file);
@@ -74,16 +84,112 @@ static int vimc_cap_fmt_vid_cap(struct file *file, void *priv,return 0 ; } +static int vimc_cap_try_fmt_vid_cap (struct file *file,void *priv, +struct v4l2_format *f) +{ +struct v4l2_pix_format *format = &f->fmt.pix; +const struct vimc_pix_map *vpix; + + format->width =clamp_t (u32, format->width,VIMC_FRAME_MIN_WIDTH , +VIMC_FRAME_MAX_WIDTH ); + format->height =clamp_t (u32, format->height,VIMC_FRAME_MIN_HEIGHT , +VIMC_FRAME_MAX_HEIGHT ); + +/* Don't accept a pixelformat that is not on the table */ + vpix =vimc_pix_map_by_pixelformat (format->pixelformat); +if (!vpix) { + format->pixelformat = fmt_default.pixelformat; + vpix =vimc_pix_map_by_pixelformat (format->pixelformat); + } +/* TODO: Add support for custom bytesperline values */ + format->bytesperline = format->width * vpix->bpp; + format->sizeimage = format->bytesperline * format->height; + +if (format->field ==V4L2_FIELD_ANY ) + format->field = fmt_default.field; + +/* Check if values are out of range */ +if (format->colorspace ==V4L2_COLORSPACE_DEFAULT + || format->colorspace >V4L2_COLORSPACE_DCI_P3 ) + format->colorspace = fmt_default.colorspace; +if (format->ycbcr_enc ==V4L2_YCBCR_ENC_DEFAULT + || format->ycbcr_enc >V4L2_YCBCR_ENC_SMPTE240M ) + format->ycbcr_enc = fmt_default.ycbcr_enc; +if (format->quantization ==V4L2_QUANTIZATION_DEFAULT + || format->quantization >V4L2_QUANTIZATION_LIM_RANGE ) + format->quantization = fmt_default.quantization; +if (format->xfer_func ==V4L2_XFER_FUNC_DEFAULT + || format->xfer_func >V4L2_XFER_FUNC_SMPTE2084 ) + format->xfer_func = fmt_default.xfer_func; + +return 0 ; +} + +static int vimc_cap_s_fmt_vid_cap (struct file *file,void *priv, +struct v4l2_format *f) +{ +struct vimc_cap_device *vcap =video_drvdata (file); + +/* Do not change the format while stream is on */ +if (vb2_is_busy (&vcap->queue)) +return -EBUSY ; + +vimc_cap_try_fmt_vid_cap (file, priv, f); + +dev_dbg (vcap->vdev.v4l2_dev->dev,"%s: format update: " +"old:%dx%d (0x%x, %d, %d, %d, %d) " +"new:%dx%d (0x%x, %d, %d, %d, %d)\n" , vcap->vdev.name, +/* old */ + vcap->format.width, vcap->format.height, + vcap->format.pixelformat, vcap->format.colorspace, + vcap->format.quantization, vcap->format.xfer_func, + vcap->format.ycbcr_enc, +/* new */ + f->fmt.pix.width, f->fmt.pix.height, + f->fmt.pix.pixelformat, f->fmt.pix.colorspace, + f->fmt.pix.quantization, f->fmt.pix.xfer_func, + f->fmt.pix.ycbcr_enc); + + vcap->format = f->fmt.pix; + +return 0 ; +} +static int vimc_cap_enum_fmt_vid_cap (struct file *file,void *priv,struct v4l2_fmtdesc *f) { -struct vimc_cap_device *vcap =video_drvdata (file); +const struct vimc_pix_map *vpix =vimc_pix_map_by_index (f->index); -if (f->index >0 ) +if (!vpix)return -EINVAL ; -/* We only support one format for now */ - f->pixelformat = vcap->format.pixelformat; + f->pixelformat = vpix->pixelformat; + f->flags =V4L2_FMT_FLAG_COMPRESSED ; + f->type =V4L2_BUF_TYPE_VIDEO_CAPTURE ; + +return 0 ; +} + +static int vimc_cap_enum_framesizes (struct file *file,void *fh, +struct v4l2_frmsizeenum *fsize) +{ +const struct vimc_pix_map *vpix; + +if (fsize->index) +return -EINVAL ; + +/* Only accept code in the pix map table */ + vpix =vimc_pix_map_by_code (fsize->pixel_format); +if (!vpix) +return -EINVAL ; + + fsize->type =V4L2_FRMSIZE_TYPE_CONTINUOUS ; + fsize->stepwise.min_width =VIMC_FRAME_MIN_WIDTH ; + fsize->stepwise.max_width =VIMC_FRAME_MAX_WIDTH ; + fsize->stepwise.min_height =VIMC_FRAME_MIN_HEIGHT ; + fsize->stepwise.max_height =VIMC_FRAME_MAX_HEIGHT ; + fsize->stepwise.step_width =1 ; + fsize->stepwise.step_height =1 ;return 0 ; }
@@ -101,10 +207,11 @@ static const struct v4l2_file_operations vimc_cap_fops = {static const struct v4l2_ioctl_ops vimc_cap_ioctl_ops = { .vidioc_querycap = vimc_cap_querycap, - .vidioc_g_fmt_vid_cap = vimc_cap_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vimc_cap_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vimc_cap_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vimc_cap_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vimc_cap_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vimc_cap_try_fmt_vid_cap, .vidioc_enum_fmt_vid_cap = vimc_cap_enum_fmt_vid_cap, + .vidioc_enum_framesizes = vimc_cap_enum_framesizes, .vidioc_reqbufs = vb2_ioctl_reqbufs, .vidioc_create_bufs = vb2_ioctl_create_bufs,
@@ -270,20 +377,21 @@ static int vimc_cap_link_validate(struct media_link *link)if (ret)return ret; -dev_dbg (vcap->vdev.v4l2_dev->dev, -"%s: link validate formats src:%dx%d %d sink:%dx%d %d\n" , - vcap->vdev.name, + vpix =vimc_pix_map_by_pixelformat (sink_fmt->pixelformat); + +dev_dbg (vcap->vdev.v4l2_dev->dev,"%s: link validate formats: " +"src:%dx%d (0x%x, %d, %d, %d, %d) " +"snk:%dx%d (0x%x, %d, %d, %d, %d)\n" , vcap->vdev.name, +/* src */ source_fmt.format.width, source_fmt.format.height, - source_fmt.format.code, + source_fmt.format.code, source_fmt.format.colorspace, + source_fmt.format.quantization, source_fmt.format.xfer_func, + source_fmt.format.ycbcr_enc, +/* sink */ sink_fmt->width, sink_fmt->height, - sink_fmt->pixelformat); - -/* The width, height and code must match. */ - vpix =vimc_pix_map_by_pixelformat (sink_fmt->pixelformat); -if (source_fmt.format.width != sink_fmt->width - || source_fmt.format.height != sink_fmt->height - || vpix->code != source_fmt.format.code) -return -EPIPE ; + vpix->code, sink_fmt->colorspace, + sink_fmt->quantization, sink_fmt->xfer_func, + sink_fmt->ycbcr_enc);/* * The field order must match, or the sink field order must be NONE
@@ -294,6 +402,15 @@ static int vimc_cap_link_validate(struct media_link *link) sink_fmt->field != V4L2_FIELD_NONE)return -EPIPE ; +if (source_fmt.format.width != sink_fmt->width + || source_fmt.format.height != sink_fmt->height + || source_fmt.format.colorspace != sink_fmt->colorspace + || source_fmt.format.quantization != sink_fmt->quantization + || source_fmt.format.xfer_func != sink_fmt->xfer_func + || source_fmt.format.ycbcr_enc != sink_fmt->ycbcr_enc + || vpix->code != source_fmt.format.code) +return -EPIPE ; +return 0 ; }
@@ -417,15 +534,9 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev,INIT_LIST_HEAD (&vcap->buf_list);spin_lock_init (&vcap->qlock); -/* Set the frame format (this is hardcoded for now) */ - vcap->format.width =640 ; - vcap->format.height =480 ; - vcap->format.pixelformat =V4L2_PIX_FMT_RGB24 ; - vcap->format.field =V4L2_FIELD_NONE ; - vcap->format.colorspace =V4L2_COLORSPACE_SRGB ; - +/* Set default frame format */ + vcap->format = fmt_default; vpix =vimc_pix_map_by_pixelformat (vcap->format.pixelformat); - vcap->format.bytesperline = vcap->format.width * vpix->bpp; vcap->format.sizeimage = vcap->format.bytesperline * vcap->format.height;
Signature · 1 line
2.7.4
Re: [PATCH v2 5/7] [media] vimc: cap: Support several image formats
Quoted 30 lines · Helen Koike
Allow user space to change the image format as the frame size, the pixel format, colorspace, quantization, field YCbCr encoding and the transfer function
Signed-off-by Helen Koike <[email protected]>---
Changes in v2:
[media] vimc: cap: Support several image formats
- this is a new commit in the serie (the old one was splitted in two)
- allow user space to change all fields from structv4l2_pix_format
(e.g. colospace, quantization, field,xfer_func,ycbcr_enc)
-link_validateandtry_fmt: also checks colospace, quantization, field,xfer_func,ycbcr_enc
- add structv4l2_pix_formatfmt_default
- addenum_framesizes
-enum_fmt_vid_cap: enumerate all formats fromvimc_pix_map_table
- add modedev_dbg--- drivers/media/platform/vimc/vimc-capture.c | 167 ++++++++++++++++++++++++----- 1 file changed, 139 insertions(+), 28 deletions(-)drivers/media/platform/vimc/vimc-capture.c +0
-0@@ -40,6 +40,16 @@ struct vimc_cap_device {struct media_pipeline pipe;
drivers/media/platform/vimc/vimc-capture.c struct vimc_cap_device { · line 50
Quoted 10 lines
drivers/media/platform/vimc/vimc-capture.c +8
-0}; +static const struct v4l2_pix_format fmt_default = { + .width =640 , + .height =480 , + .pixelformat =V4L2_PIX_FMT_RGB24 , + .field =V4L2_FIELD_NONE , + .colorspace =V4L2_COLORSPACE_SRGB , + .quantization =V4L2_QUANTIZATION_FULL_RANGE , + .xfer_func =V4L2_XFER_FUNC_SRGB ,
I actually think we should keep .quantization and .xfer_func to 0 (DEFAULT). It's what most drivers will do. Same for the previous patch (I didn't mention it there).
Quoted 45 lines
drivers/media/platform/vimc/vimc-capture.c +30
-1+}; +struct vimc_cap_buffer {/* * struct vb2_v4l2_buffer must be the first element @@ -64,7 +74,7 @@ static int vimc_cap_querycap(struct file *file, void *priv,return 0 ; } -static int vimc_cap_fmt_vid_cap (struct file *file,void *priv, +static int vimc_cap_g_fmt_vid_cap (struct file *file,void *priv,struct v4l2_format *f) {struct vimc_cap_device *vcap =video_drvdata (file);@@ -74,16 +84,112 @@ static int vimc_cap_fmt_vid_cap(struct file *file, void *priv,return 0 ; } +static int vimc_cap_try_fmt_vid_cap (struct file *file,void *priv, +struct v4l2_format *f) +{ +struct v4l2_pix_format *format = &f->fmt.pix; +const struct vimc_pix_map *vpix; + + format->width =clamp_t (u32, format->width,VIMC_FRAME_MIN_WIDTH , +VIMC_FRAME_MAX_WIDTH ); + format->height =clamp_t (u32, format->height,VIMC_FRAME_MIN_HEIGHT , +VIMC_FRAME_MAX_HEIGHT ); + +/* Don't accept a pixelformat that is not on the table */ + vpix =vimc_pix_map_by_pixelformat (format->pixelformat); +if (!vpix) { + format->pixelformat = fmt_default.pixelformat; + vpix =vimc_pix_map_by_pixelformat (format->pixelformat); + } +/* TODO: Add support for custom bytesperline values */ + format->bytesperline = format->width * vpix->bpp; + format->sizeimage = format->bytesperline * format->height; + +if (format->field ==V4L2_FIELD_ANY ) + format->field = fmt_default.field; + +/* Check if values are out of range */ +if (format->colorspace ==V4L2_COLORSPACE_DEFAULT + || format->colorspace >V4L2_COLORSPACE_DCI_P3 )
drivers/media/platform/vimc/vimc-capture.c static int vimc_cap_fmt_vid_cap(struct file *file, void *priv, · line 123
Quoted 10 lines
drivers/media/platform/vimc/vimc-capture.c +10
-0+ format->colorspace = fmt_default.colorspace; +if (format->ycbcr_enc ==V4L2_YCBCR_ENC_DEFAULT + || format->ycbcr_enc >V4L2_YCBCR_ENC_SMPTE240M ) + format->ycbcr_enc = fmt_default.ycbcr_enc; +if (format->quantization ==V4L2_QUANTIZATION_DEFAULT + || format->quantization >V4L2_QUANTIZATION_LIM_RANGE ) + format->quantization = fmt_default.quantization; +if (format->xfer_func ==V4L2_XFER_FUNC_DEFAULT + || format->xfer_func >V4L2_XFER_FUNC_SMPTE2084 ) + format->xfer_func = fmt_default.xfer_func;
Same comments in the previous patch regarding width/height and the colorspace information apply here as well.
Quoted 38 lines
drivers/media/platform/vimc/vimc-capture.c +34
-1+ +return 0 ; +} + +static int vimc_cap_s_fmt_vid_cap (struct file *file,void *priv, +struct v4l2_format *f) +{ +struct vimc_cap_device *vcap =video_drvdata (file); + +/* Do not change the format while stream is on */ +if (vb2_is_busy (&vcap->queue)) +return -EBUSY ; + +vimc_cap_try_fmt_vid_cap (file, priv, f); + +dev_dbg (vcap->vdev.v4l2_dev->dev,"%s: format update: " +"old:%dx%d (0x%x, %d, %d, %d, %d) " +"new:%dx%d (0x%x, %d, %d, %d, %d)\n" , vcap->vdev.name, +/* old */ + vcap->format.width, vcap->format.height, + vcap->format.pixelformat, vcap->format.colorspace, + vcap->format.quantization, vcap->format.xfer_func, + vcap->format.ycbcr_enc, +/* new */ + f->fmt.pix.width, f->fmt.pix.height, + f->fmt.pix.pixelformat, f->fmt.pix.colorspace, + f->fmt.pix.quantization, f->fmt.pix.xfer_func, + f->fmt.pix.ycbcr_enc); + + vcap->format = f->fmt.pix; + +return 0 ; +} +static int vimc_cap_enum_fmt_vid_cap (struct file *file,void *priv,struct v4l2_fmtdesc *f) { -struct vimc_cap_device *vcap =video_drvdata (file);
drivers/media/platform/vimc/vimc-capture.c static int vimc_cap_fmt_vid_cap(struct file *file, void *priv, · line 167
Quoted 10 lines
drivers/media/platform/vimc/vimc-capture.c +4
-3+const struct vimc_pix_map *vpix =vimc_pix_map_by_index (f->index); -if (f->index >0 ) +if (!vpix)return -EINVAL ; -/* We only support one format for now */ - f->pixelformat = vcap->format.pixelformat; + f->pixelformat = vpix->pixelformat; + f->flags =V4L2_FMT_FLAG_COMPRESSED ;
Why set this to COMPRESSED? The flag is set by the v4l2 core anyway, but the format we support here isn't a compressed format at all. Perhaps a left-over from an earlier version?
drivers/media/platform/vimc/vimc-capture.c static int vimc_cap_fmt_vid_cap(struct file *file, void *priv, · line 168
Quoted 1 line
drivers/media/platform/vimc/vimc-capture.c +1
-0+ f->type =V4L2_BUF_TYPE_VIDEO_CAPTURE ;
No need for this, this op can only be called for such types anyway.
Quoted 14 lines
drivers/media/platform/vimc/vimc-capture.c +14
-0+ +return 0 ; +} + +static int vimc_cap_enum_framesizes (struct file *file,void *fh, +struct v4l2_frmsizeenum *fsize) +{ +const struct vimc_pix_map *vpix; + +if (fsize->index) +return -EINVAL ; + +/* Only accept code in the pix map table */ + vpix =vimc_pix_map_by_code (fsize->pixel_format);
drivers/media/platform/vimc/vimc-capture.c static int vimc_cap_fmt_vid_cap(struct file *file, void *priv, · line 192
Quoted 10 lines
drivers/media/platform/vimc/vimc-capture.c +10
-0+if (!vpix) +return -EINVAL ; + + fsize->type =V4L2_FRMSIZE_TYPE_CONTINUOUS ; + fsize->stepwise.min_width =VIMC_FRAME_MIN_WIDTH ; + fsize->stepwise.max_width =VIMC_FRAME_MAX_WIDTH ; + fsize->stepwise.min_height =VIMC_FRAME_MIN_HEIGHT ; + fsize->stepwise.max_height =VIMC_FRAME_MAX_HEIGHT ; + fsize->stepwise.step_width =1 ; + fsize->stepwise.step_height =1 ;
I think the step should be at least 2.
Quoted 53 lines
drivers/media/platform/vimc/vimc-capture.c +17
-15return 0 ; }@@ -101,10 +207,11 @@ static const struct v4l2_file_operations vimc_cap_fops = {static const struct v4l2_ioctl_ops vimc_cap_ioctl_ops = { .vidioc_querycap = vimc_cap_querycap, - .vidioc_g_fmt_vid_cap = vimc_cap_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vimc_cap_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vimc_cap_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vimc_cap_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vimc_cap_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vimc_cap_try_fmt_vid_cap, .vidioc_enum_fmt_vid_cap = vimc_cap_enum_fmt_vid_cap, + .vidioc_enum_framesizes = vimc_cap_enum_framesizes, .vidioc_reqbufs = vb2_ioctl_reqbufs, .vidioc_create_bufs = vb2_ioctl_create_bufs,@@ -270,20 +377,21 @@ static int vimc_cap_link_validate(struct media_link *link)if (ret)return ret; -dev_dbg (vcap->vdev.v4l2_dev->dev, -"%s: link validate formats src:%dx%d %d sink:%dx%d %d\n" , - vcap->vdev.name, + vpix =vimc_pix_map_by_pixelformat (sink_fmt->pixelformat); + +dev_dbg (vcap->vdev.v4l2_dev->dev,"%s: link validate formats: " +"src:%dx%d (0x%x, %d, %d, %d, %d) " +"snk:%dx%d (0x%x, %d, %d, %d, %d)\n" , vcap->vdev.name, +/* src */ source_fmt.format.width, source_fmt.format.height, - source_fmt.format.code, + source_fmt.format.code, source_fmt.format.colorspace, + source_fmt.format.quantization, source_fmt.format.xfer_func, + source_fmt.format.ycbcr_enc, +/* sink */ sink_fmt->width, sink_fmt->height, - sink_fmt->pixelformat); - -/* The width, height and code must match. */ - vpix =vimc_pix_map_by_pixelformat (sink_fmt->pixelformat); -if (source_fmt.format.width != sink_fmt->width - || source_fmt.format.height != sink_fmt->height - || vpix->code != source_fmt.format.code) -return -EPIPE ; + vpix->code, sink_fmt->colorspace, + sink_fmt->quantization, sink_fmt->xfer_func, + sink_fmt->ycbcr_enc);/* * The field order must match, or the sink field order must be NONE
drivers/media/platform/vimc/vimc-capture.c static int vimc_cap_link_validate(struct media_link *link) · line 410
Quoted 9 lines
drivers/media/platform/vimc/vimc-capture.c +6
-0@@ -294,6 +402,15 @@ static int vimc_cap_link_validate(struct media_link *link) sink_fmt->field != V4L2_FIELD_NONE)return -EPIPE ; +if (source_fmt.format.width != sink_fmt->width + || source_fmt.format.height != sink_fmt->height + || source_fmt.format.colorspace != sink_fmt->colorspace + || source_fmt.format.quantization != sink_fmt->quantization + || source_fmt.format.xfer_func != sink_fmt->xfer_func + || source_fmt.format.ycbcr_enc != sink_fmt->ycbcr_enc
You can't just compare this. I just discussed this with Philipp Zabel as well, and I don't think this should be included in the link validation, unless the hardware block can do actual colorspace conversions.
In most cases this is irrelevant to the link validation.
And if this has to be validated, then we need a helper function for this. Since one side can set quantization to the DEFAULT value while the other side sets it explicitly. Then you need to use the V4L2_MAP_QUANTIZATION_DEFAULT macro to figure out what the DEFAULT value really maps to before you compare the two sides.
That requires a helper function, otherwise the driver code would become too complex.
But the reality is that there really is no need to compare the two sides since none of this matters for how the data is processed.
Quoted 15 lines
drivers/media/platform/vimc/vimc-capture.c +3
-4+ || vpix->code != source_fmt.format.code) +return -EPIPE ; +return 0 ; }@@ -417,15 +534,9 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev,INIT_LIST_HEAD (&vcap->buf_list);spin_lock_init (&vcap->qlock); -/* Set the frame format (this is hardcoded for now) */ - vcap->format.width =640 ; - vcap->format.height =480 ; - vcap->format.pixelformat =V4L2_PIX_FMT_RGB24 ;
drivers/media/platform/vimc/vimc-capture.c struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, · line 542
Quoted 10 lines
drivers/media/platform/vimc/vimc-capture.c +2
-4- vcap->format.field =V4L2_FIELD_NONE ; - vcap->format.colorspace =V4L2_COLORSPACE_SRGB ; - +/* Set default frame format */ + vcap->format = fmt_default; vpix =vimc_pix_map_by_pixelformat (vcap->format.pixelformat); - vcap->format.bytesperline = vcap->format.width * vpix->bpp; vcap->format.sizeimage = vcap->format.bytesperline * vcap->format.height;
Regards,
Hans
Re: [PATCH v2 5/7] [media] vimc: cap: Support several image formats
Hi Hans,
Thank you for your review. I just have a question for this one.
Quoted 256 lines · Hans Verkuil
Quoted 30 lines · Helen Koike
Allow user space to change the image format as the frame size, the pixel format, colorspace, quantization, field YCbCr encoding and the transfer function
Signed-off-by Helen Koike <[email protected]>---
Changes in v2:
[media] vimc: cap: Support several image formats
- this is a new commit in the serie (the old one was splitted in two)
- allow user space to change all fields from structv4l2_pix_format
(e.g. colospace, quantization, field,xfer_func,ycbcr_enc)
-link_validateandtry_fmt: also checks colospace, quantization, field,xfer_func,ycbcr_enc
- add structv4l2_pix_formatfmt_default
- addenum_framesizes
-enum_fmt_vid_cap: enumerate all formats fromvimc_pix_map_table
- add modedev_dbg--- drivers/media/platform/vimc/vimc-capture.c | 167 ++++++++++++++++++++++++----- 1 file changed, 139 insertions(+), 28 deletions(-)drivers/media/platform/vimc/vimc-capture.c +0
-0@@ -40,6 +40,16 @@ struct vimc_cap_device {struct media_pipeline pipe;drivers/media/platform/vimc/vimc-capture.c struct vimc_cap_device { · line 50
Quoted 10 lines
drivers/media/platform/vimc/vimc-capture.c +8
-0}; +static const struct v4l2_pix_format fmt_default = { + .width =640 , + .height =480 , + .pixelformat =V4L2_PIX_FMT_RGB24 , + .field =V4L2_FIELD_NONE , + .colorspace =V4L2_COLORSPACE_SRGB , + .quantization =V4L2_QUANTIZATION_FULL_RANGE , + .xfer_func =V4L2_XFER_FUNC_SRGB ,I actually think we should keep .quantization and .xfer_func to 0 (DEFAULT). It's what most drivers will do. Same for the previous patch (I didn't mention it there).
Quoted 45 lines
drivers/media/platform/vimc/vimc-capture.c +30
-1+}; +struct vimc_cap_buffer {/* * struct vb2_v4l2_buffer must be the first element @@ -64,7 +74,7 @@ static int vimc_cap_querycap(struct file *file, void *priv,return 0 ; } -static int vimc_cap_fmt_vid_cap (struct file *file,void *priv, +static int vimc_cap_g_fmt_vid_cap (struct file *file,void *priv,struct v4l2_format *f) {struct vimc_cap_device *vcap =video_drvdata (file);@@ -74,16 +84,112 @@ static int vimc_cap_fmt_vid_cap(struct file *file, void *priv,return 0 ; } +static int vimc_cap_try_fmt_vid_cap (struct file *file,void *priv, +struct v4l2_format *f) +{ +struct v4l2_pix_format *format = &f->fmt.pix; +const struct vimc_pix_map *vpix; + + format->width =clamp_t (u32, format->width,VIMC_FRAME_MIN_WIDTH , +VIMC_FRAME_MAX_WIDTH ); + format->height =clamp_t (u32, format->height,VIMC_FRAME_MIN_HEIGHT , +VIMC_FRAME_MAX_HEIGHT ); + +/* Don't accept a pixelformat that is not on the table */ + vpix =vimc_pix_map_by_pixelformat (format->pixelformat); +if (!vpix) { + format->pixelformat = fmt_default.pixelformat; + vpix =vimc_pix_map_by_pixelformat (format->pixelformat); + } +/* TODO: Add support for custom bytesperline values */ + format->bytesperline = format->width * vpix->bpp; + format->sizeimage = format->bytesperline * format->height; + +if (format->field ==V4L2_FIELD_ANY ) + format->field = fmt_default.field; + +/* Check if values are out of range */ +if (format->colorspace ==V4L2_COLORSPACE_DEFAULT + || format->colorspace >V4L2_COLORSPACE_DCI_P3 )drivers/media/platform/vimc/vimc-capture.c static int vimc_cap_fmt_vid_cap(struct file *file, void *priv, · line 123
Quoted 10 lines
drivers/media/platform/vimc/vimc-capture.c +10
-0+ format->colorspace = fmt_default.colorspace; +if (format->ycbcr_enc ==V4L2_YCBCR_ENC_DEFAULT + || format->ycbcr_enc >V4L2_YCBCR_ENC_SMPTE240M ) + format->ycbcr_enc = fmt_default.ycbcr_enc; +if (format->quantization ==V4L2_QUANTIZATION_DEFAULT + || format->quantization >V4L2_QUANTIZATION_LIM_RANGE ) + format->quantization = fmt_default.quantization; +if (format->xfer_func ==V4L2_XFER_FUNC_DEFAULT + || format->xfer_func >V4L2_XFER_FUNC_SMPTE2084 ) + format->xfer_func = fmt_default.xfer_func;Same comments in the previous patch regarding width/height and the colorspace information apply here as well.
Quoted 38 lines
drivers/media/platform/vimc/vimc-capture.c +34
-1+ +return 0 ; +} + +static int vimc_cap_s_fmt_vid_cap (struct file *file,void *priv, +struct v4l2_format *f) +{ +struct vimc_cap_device *vcap =video_drvdata (file); + +/* Do not change the format while stream is on */ +if (vb2_is_busy (&vcap->queue)) +return -EBUSY ; + +vimc_cap_try_fmt_vid_cap (file, priv, f); + +dev_dbg (vcap->vdev.v4l2_dev->dev,"%s: format update: " +"old:%dx%d (0x%x, %d, %d, %d, %d) " +"new:%dx%d (0x%x, %d, %d, %d, %d)\n" , vcap->vdev.name, +/* old */ + vcap->format.width, vcap->format.height, + vcap->format.pixelformat, vcap->format.colorspace, + vcap->format.quantization, vcap->format.xfer_func, + vcap->format.ycbcr_enc, +/* new */ + f->fmt.pix.width, f->fmt.pix.height, + f->fmt.pix.pixelformat, f->fmt.pix.colorspace, + f->fmt.pix.quantization, f->fmt.pix.xfer_func, + f->fmt.pix.ycbcr_enc); + + vcap->format = f->fmt.pix; + +return 0 ; +} +static int vimc_cap_enum_fmt_vid_cap (struct file *file,void *priv,struct v4l2_fmtdesc *f) { -struct vimc_cap_device *vcap =video_drvdata (file);drivers/media/platform/vimc/vimc-capture.c static int vimc_cap_fmt_vid_cap(struct file *file, void *priv, · line 167
Quoted 10 lines
drivers/media/platform/vimc/vimc-capture.c +4
-3+const struct vimc_pix_map *vpix =vimc_pix_map_by_index (f->index); -if (f->index >0 ) +if (!vpix)return -EINVAL ; -/* We only support one format for now */ - f->pixelformat = vcap->format.pixelformat; + f->pixelformat = vpix->pixelformat; + f->flags =V4L2_FMT_FLAG_COMPRESSED ;Why set this to COMPRESSED? The flag is set by the v4l2 core anyway, but the format we support here isn't a compressed format at all. Perhaps a left-over from an earlier version?
drivers/media/platform/vimc/vimc-capture.c static int vimc_cap_fmt_vid_cap(struct file *file, void *priv, · line 168
Quoted 1 line
drivers/media/platform/vimc/vimc-capture.c +1
-0+ f->type =V4L2_BUF_TYPE_VIDEO_CAPTURE ;No need for this, this op can only be called for such types anyway.
Quoted 14 lines
drivers/media/platform/vimc/vimc-capture.c +14
-0+ +return 0 ; +} + +static int vimc_cap_enum_framesizes (struct file *file,void *fh, +struct v4l2_frmsizeenum *fsize) +{ +const struct vimc_pix_map *vpix; + +if (fsize->index) +return -EINVAL ; + +/* Only accept code in the pix map table */ + vpix =vimc_pix_map_by_code (fsize->pixel_format);drivers/media/platform/vimc/vimc-capture.c static int vimc_cap_fmt_vid_cap(struct file *file, void *priv, · line 192
Quoted 10 lines
drivers/media/platform/vimc/vimc-capture.c +10
-0+if (!vpix) +return -EINVAL ; + + fsize->type =V4L2_FRMSIZE_TYPE_CONTINUOUS ; + fsize->stepwise.min_width =VIMC_FRAME_MIN_WIDTH ; + fsize->stepwise.max_width =VIMC_FRAME_MAX_WIDTH ; + fsize->stepwise.min_height =VIMC_FRAME_MIN_HEIGHT ; + fsize->stepwise.max_height =VIMC_FRAME_MAX_HEIGHT ; + fsize->stepwise.step_width =1 ; + fsize->stepwise.step_height =1 ;I think the step should be at least 2.
Quoted 53 lines
drivers/media/platform/vimc/vimc-capture.c +17
-15return 0 ; }@@ -101,10 +207,11 @@ static const struct v4l2_file_operations vimc_cap_fops = {static const struct v4l2_ioctl_ops vimc_cap_ioctl_ops = { .vidioc_querycap = vimc_cap_querycap, - .vidioc_g_fmt_vid_cap = vimc_cap_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vimc_cap_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vimc_cap_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vimc_cap_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vimc_cap_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vimc_cap_try_fmt_vid_cap, .vidioc_enum_fmt_vid_cap = vimc_cap_enum_fmt_vid_cap, + .vidioc_enum_framesizes = vimc_cap_enum_framesizes, .vidioc_reqbufs = vb2_ioctl_reqbufs, .vidioc_create_bufs = vb2_ioctl_create_bufs,@@ -270,20 +377,21 @@ static int vimc_cap_link_validate(struct media_link *link)if (ret)return ret; -dev_dbg (vcap->vdev.v4l2_dev->dev, -"%s: link validate formats src:%dx%d %d sink:%dx%d %d\n" , - vcap->vdev.name, + vpix =vimc_pix_map_by_pixelformat (sink_fmt->pixelformat); + +dev_dbg (vcap->vdev.v4l2_dev->dev,"%s: link validate formats: " +"src:%dx%d (0x%x, %d, %d, %d, %d) " +"snk:%dx%d (0x%x, %d, %d, %d, %d)\n" , vcap->vdev.name, +/* src */ source_fmt.format.width, source_fmt.format.height, - source_fmt.format.code, + source_fmt.format.code, source_fmt.format.colorspace, + source_fmt.format.quantization, source_fmt.format.xfer_func, + source_fmt.format.ycbcr_enc, +/* sink */ sink_fmt->width, sink_fmt->height, - sink_fmt->pixelformat); - -/* The width, height and code must match. */ - vpix =vimc_pix_map_by_pixelformat (sink_fmt->pixelformat); -if (source_fmt.format.width != sink_fmt->width - || source_fmt.format.height != sink_fmt->height - || vpix->code != source_fmt.format.code) -return -EPIPE ; + vpix->code, sink_fmt->colorspace, + sink_fmt->quantization, sink_fmt->xfer_func, + sink_fmt->ycbcr_enc);/* * The field order must match, or the sink field order must be NONE drivers/media/platform/vimc/vimc-capture.c static int vimc_cap_link_validate(struct media_link *link) · line 410
Quoted 9 lines
drivers/media/platform/vimc/vimc-capture.c +6
-0@@ -294,6 +402,15 @@ static int vimc_cap_link_validate(struct media_link *link) sink_fmt->field != V4L2_FIELD_NONE)return -EPIPE ; +if (source_fmt.format.width != sink_fmt->width + || source_fmt.format.height != sink_fmt->height + || source_fmt.format.colorspace != sink_fmt->colorspace + || source_fmt.format.quantization != sink_fmt->quantization + || source_fmt.format.xfer_func != sink_fmt->xfer_func + || source_fmt.format.ycbcr_enc != sink_fmt->ycbcr_encYou can't just compare this. I just discussed this with Philipp Zabel as well, and I don't think this should be included in the link validation, unless the hardware block can do actual colorspace conversions.
Quoted 1 line
In most cases this is irrelevant to the link validation.
If it is irrelevant, then what it means to have different entities with different colorspaces?
If I have a topology like [sensor]0->0[scaler]1->0[video cap] for example, the user can configure different colorspaces in each pad no? Should these configuration just be ignored ?
Quoted 39 lines
And if this has to be validated, then we need a helper function for this. Since one side can set quantization to the DEFAULT value while the other side sets it explicitly. Then you need to use the
V4L2_MAP_QUANTIZATION_DEFAULTmacro to figure out what the DEFAULT value really maps to before you compare the two sides.That requires a helper function, otherwise the driver code would become too complex.
But the reality is that there really is no need to compare the two sides since none of this matters for how the data is processed.
Quoted 15 lines
drivers/media/platform/vimc/vimc-capture.c +3
-4+ || vpix->code != source_fmt.format.code) +return -EPIPE ; +return 0 ; }@@ -417,15 +534,9 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev,INIT_LIST_HEAD (&vcap->buf_list);spin_lock_init (&vcap->qlock); -/* Set the frame format (this is hardcoded for now) */ - vcap->format.width =640 ; - vcap->format.height =480 ; - vcap->format.pixelformat =V4L2_PIX_FMT_RGB24 ;drivers/media/platform/vimc/vimc-capture.c struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, · line 542
Quoted 10 lines
drivers/media/platform/vimc/vimc-capture.c +2
-4- vcap->format.field =V4L2_FIELD_NONE ; - vcap->format.colorspace =V4L2_COLORSPACE_SRGB ; - +/* Set default frame format */ + vcap->format = fmt_default; vpix =vimc_pix_map_by_pixelformat (vcap->format.pixelformat); - vcap->format.bytesperline = vcap->format.width * vpix->bpp; vcap->format.sizeimage = vcap->format.bytesperline * vcap->format.height;Regards,
Quoted 2 lines
Hans
Thanks
LN
Re: [PATCH v2 5/7] [media] vimc: cap: Support several image formats
Quoted 264 lines · Helen Koike
Hi Hans,
Thank you for your review. I just have a question for this one.
Quoted 256 lines · Hans Verkuil
Quoted 30 lines · Helen Koike
Allow user space to change the image format as the frame size, the pixel format, colorspace, quantization, field YCbCr encoding and the transfer function
Signed-off-by Helen Koike <[email protected]>---
Changes in v2:
[media] vimc: cap: Support several image formats
- this is a new commit in the serie (the old one was splitted in two)
- allow user space to change all fields from structv4l2_pix_format
(e.g. colospace, quantization, field,xfer_func,ycbcr_enc)
-link_validateandtry_fmt: also checks colospace, quantization, field,xfer_func,ycbcr_enc
- add structv4l2_pix_formatfmt_default
- addenum_framesizes
-enum_fmt_vid_cap: enumerate all formats fromvimc_pix_map_table
- add modedev_dbg--- drivers/media/platform/vimc/vimc-capture.c | 167 ++++++++++++++++++++++++----- 1 file changed, 139 insertions(+), 28 deletions(-)drivers/media/platform/vimc/vimc-capture.c +0
-0@@ -40,6 +40,16 @@ struct vimc_cap_device {struct media_pipeline pipe;drivers/media/platform/vimc/vimc-capture.c struct vimc_cap_device { · line 50
Quoted 10 lines
drivers/media/platform/vimc/vimc-capture.c +8
-0}; +static const struct v4l2_pix_format fmt_default = { + .width =640 , + .height =480 , + .pixelformat =V4L2_PIX_FMT_RGB24 , + .field =V4L2_FIELD_NONE , + .colorspace =V4L2_COLORSPACE_SRGB , + .quantization =V4L2_QUANTIZATION_FULL_RANGE , + .xfer_func =V4L2_XFER_FUNC_SRGB ,I actually think we should keep .quantization and .xfer_func to 0 (DEFAULT). It's what most drivers will do. Same for the previous patch (I didn't mention it there).
Quoted 45 lines
drivers/media/platform/vimc/vimc-capture.c +30
-1+}; +struct vimc_cap_buffer {/* * struct vb2_v4l2_buffer must be the first element @@ -64,7 +74,7 @@ static int vimc_cap_querycap(struct file *file, void *priv,return 0 ; } -static int vimc_cap_fmt_vid_cap (struct file *file,void *priv, +static int vimc_cap_g_fmt_vid_cap (struct file *file,void *priv,struct v4l2_format *f) {struct vimc_cap_device *vcap =video_drvdata (file);@@ -74,16 +84,112 @@ static int vimc_cap_fmt_vid_cap(struct file *file, void *priv,return 0 ; } +static int vimc_cap_try_fmt_vid_cap (struct file *file,void *priv, +struct v4l2_format *f) +{ +struct v4l2_pix_format *format = &f->fmt.pix; +const struct vimc_pix_map *vpix; + + format->width =clamp_t (u32, format->width,VIMC_FRAME_MIN_WIDTH , +VIMC_FRAME_MAX_WIDTH ); + format->height =clamp_t (u32, format->height,VIMC_FRAME_MIN_HEIGHT , +VIMC_FRAME_MAX_HEIGHT ); + +/* Don't accept a pixelformat that is not on the table */ + vpix =vimc_pix_map_by_pixelformat (format->pixelformat); +if (!vpix) { + format->pixelformat = fmt_default.pixelformat; + vpix =vimc_pix_map_by_pixelformat (format->pixelformat); + } +/* TODO: Add support for custom bytesperline values */ + format->bytesperline = format->width * vpix->bpp; + format->sizeimage = format->bytesperline * format->height; + +if (format->field ==V4L2_FIELD_ANY ) + format->field = fmt_default.field; + +/* Check if values are out of range */ +if (format->colorspace ==V4L2_COLORSPACE_DEFAULT + || format->colorspace >V4L2_COLORSPACE_DCI_P3 )drivers/media/platform/vimc/vimc-capture.c static int vimc_cap_fmt_vid_cap(struct file *file, void *priv, · line 123
Quoted 10 lines
drivers/media/platform/vimc/vimc-capture.c +10
-0+ format->colorspace = fmt_default.colorspace; +if (format->ycbcr_enc ==V4L2_YCBCR_ENC_DEFAULT + || format->ycbcr_enc >V4L2_YCBCR_ENC_SMPTE240M ) + format->ycbcr_enc = fmt_default.ycbcr_enc; +if (format->quantization ==V4L2_QUANTIZATION_DEFAULT + || format->quantization >V4L2_QUANTIZATION_LIM_RANGE ) + format->quantization = fmt_default.quantization; +if (format->xfer_func ==V4L2_XFER_FUNC_DEFAULT + || format->xfer_func >V4L2_XFER_FUNC_SMPTE2084 ) + format->xfer_func = fmt_default.xfer_func;Same comments in the previous patch regarding width/height and the colorspace information apply here as well.
Quoted 38 lines
drivers/media/platform/vimc/vimc-capture.c +34
-1+ +return 0 ; +} + +static int vimc_cap_s_fmt_vid_cap (struct file *file,void *priv, +struct v4l2_format *f) +{ +struct vimc_cap_device *vcap =video_drvdata (file); + +/* Do not change the format while stream is on */ +if (vb2_is_busy (&vcap->queue)) +return -EBUSY ; + +vimc_cap_try_fmt_vid_cap (file, priv, f); + +dev_dbg (vcap->vdev.v4l2_dev->dev,"%s: format update: " +"old:%dx%d (0x%x, %d, %d, %d, %d) " +"new:%dx%d (0x%x, %d, %d, %d, %d)\n" , vcap->vdev.name, +/* old */ + vcap->format.width, vcap->format.height, + vcap->format.pixelformat, vcap->format.colorspace, + vcap->format.quantization, vcap->format.xfer_func, + vcap->format.ycbcr_enc, +/* new */ + f->fmt.pix.width, f->fmt.pix.height, + f->fmt.pix.pixelformat, f->fmt.pix.colorspace, + f->fmt.pix.quantization, f->fmt.pix.xfer_func, + f->fmt.pix.ycbcr_enc); + + vcap->format = f->fmt.pix; + +return 0 ; +} +static int vimc_cap_enum_fmt_vid_cap (struct file *file,void *priv,struct v4l2_fmtdesc *f) { -struct vimc_cap_device *vcap =video_drvdata (file);drivers/media/platform/vimc/vimc-capture.c static int vimc_cap_fmt_vid_cap(struct file *file, void *priv, · line 167
Quoted 10 lines
drivers/media/platform/vimc/vimc-capture.c +4
-3+const struct vimc_pix_map *vpix =vimc_pix_map_by_index (f->index); -if (f->index >0 ) +if (!vpix)return -EINVAL ; -/* We only support one format for now */ - f->pixelformat = vcap->format.pixelformat; + f->pixelformat = vpix->pixelformat; + f->flags =V4L2_FMT_FLAG_COMPRESSED ;Why set this to COMPRESSED? The flag is set by the v4l2 core anyway, but the format we support here isn't a compressed format at all. Perhaps a left-over from an earlier version?
drivers/media/platform/vimc/vimc-capture.c static int vimc_cap_fmt_vid_cap(struct file *file, void *priv, · line 168
Quoted 1 line
drivers/media/platform/vimc/vimc-capture.c +1
-0+ f->type =V4L2_BUF_TYPE_VIDEO_CAPTURE ;No need for this, this op can only be called for such types anyway.
Quoted 14 lines
drivers/media/platform/vimc/vimc-capture.c +14
-0+ +return 0 ; +} + +static int vimc_cap_enum_framesizes (struct file *file,void *fh, +struct v4l2_frmsizeenum *fsize) +{ +const struct vimc_pix_map *vpix; + +if (fsize->index) +return -EINVAL ; + +/* Only accept code in the pix map table */ + vpix =vimc_pix_map_by_code (fsize->pixel_format);drivers/media/platform/vimc/vimc-capture.c static int vimc_cap_fmt_vid_cap(struct file *file, void *priv, · line 192
Quoted 10 lines
drivers/media/platform/vimc/vimc-capture.c +10
-0+if (!vpix) +return -EINVAL ; + + fsize->type =V4L2_FRMSIZE_TYPE_CONTINUOUS ; + fsize->stepwise.min_width =VIMC_FRAME_MIN_WIDTH ; + fsize->stepwise.max_width =VIMC_FRAME_MAX_WIDTH ; + fsize->stepwise.min_height =VIMC_FRAME_MIN_HEIGHT ; + fsize->stepwise.max_height =VIMC_FRAME_MAX_HEIGHT ; + fsize->stepwise.step_width =1 ; + fsize->stepwise.step_height =1 ;I think the step should be at least 2.
Quoted 53 lines
drivers/media/platform/vimc/vimc-capture.c +17
-15return 0 ; }@@ -101,10 +207,11 @@ static const struct v4l2_file_operations vimc_cap_fops = {static const struct v4l2_ioctl_ops vimc_cap_ioctl_ops = { .vidioc_querycap = vimc_cap_querycap, - .vidioc_g_fmt_vid_cap = vimc_cap_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vimc_cap_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vimc_cap_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vimc_cap_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vimc_cap_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vimc_cap_try_fmt_vid_cap, .vidioc_enum_fmt_vid_cap = vimc_cap_enum_fmt_vid_cap, + .vidioc_enum_framesizes = vimc_cap_enum_framesizes, .vidioc_reqbufs = vb2_ioctl_reqbufs, .vidioc_create_bufs = vb2_ioctl_create_bufs,@@ -270,20 +377,21 @@ static int vimc_cap_link_validate(struct media_link *link)if (ret)return ret; -dev_dbg (vcap->vdev.v4l2_dev->dev, -"%s: link validate formats src:%dx%d %d sink:%dx%d %d\n" , - vcap->vdev.name, + vpix =vimc_pix_map_by_pixelformat (sink_fmt->pixelformat); + +dev_dbg (vcap->vdev.v4l2_dev->dev,"%s: link validate formats: " +"src:%dx%d (0x%x, %d, %d, %d, %d) " +"snk:%dx%d (0x%x, %d, %d, %d, %d)\n" , vcap->vdev.name, +/* src */ source_fmt.format.width, source_fmt.format.height, - source_fmt.format.code, + source_fmt.format.code, source_fmt.format.colorspace, + source_fmt.format.quantization, source_fmt.format.xfer_func, + source_fmt.format.ycbcr_enc, +/* sink */ sink_fmt->width, sink_fmt->height, - sink_fmt->pixelformat); - -/* The width, height and code must match. */ - vpix =vimc_pix_map_by_pixelformat (sink_fmt->pixelformat); -if (source_fmt.format.width != sink_fmt->width - || source_fmt.format.height != sink_fmt->height - || vpix->code != source_fmt.format.code) -return -EPIPE ; + vpix->code, sink_fmt->colorspace, + sink_fmt->quantization, sink_fmt->xfer_func, + sink_fmt->ycbcr_enc);/* * The field order must match, or the sink field order must be NONE drivers/media/platform/vimc/vimc-capture.c static int vimc_cap_link_validate(struct media_link *link) · line 410
Quoted 9 lines
drivers/media/platform/vimc/vimc-capture.c +6
-0@@ -294,6 +402,15 @@ static int vimc_cap_link_validate(struct media_link *link) sink_fmt->field != V4L2_FIELD_NONE)return -EPIPE ; +if (source_fmt.format.width != sink_fmt->width + || source_fmt.format.height != sink_fmt->height + || source_fmt.format.colorspace != sink_fmt->colorspace + || source_fmt.format.quantization != sink_fmt->quantization + || source_fmt.format.xfer_func != sink_fmt->xfer_func + || source_fmt.format.ycbcr_enc != sink_fmt->ycbcr_encYou can't just compare this. I just discussed this with Philipp Zabel as well, and I don't think this should be included in the link validation, unless the hardware block can do actual colorspace conversions.
Quoted 1 line
In most cases this is irrelevant to the link validation.
Quoted 6 lines
If it is irrelevant, then what it means to have different entities with different colorspaces?
If I have a topology like [sensor]0->0[scaler]1->0[video cap] for example, the user can configure different colorspaces in each pad no? Should these configuration just be ignored ?
Yes.
To be honest, this is something we need to clarify. It certainly shouldn't be used in the validation check, but it is not really defined what should be done when userspace sets these fields to non-0 values. Right now I think most drivers just set it and do not otherwise touch it.
I looked at this with Philipp Zabel recently for the imx6 driver:
https://patchwork.linuxtv.org/patch/41451/
What is done there is probably the best solution.
Regards,
Hans
PATCH v2 6/7 vimc: deb: Add debayer filter
In reply to Helen KoikeImplement the debayer filter and integrate it with the core
---
Changes in v2:
[media] vimc: deb: Add debayer filter
- Using MEDIA_ENT_F_ATV_DECODER in function
- remove v4l2_dev and dev from vimc_deb_device struct
- src fmt propagates from the sink
- coding style
- remove redundant else if statements
- check end of enum and remove BUG_ON
- enum frame size with min and max values
- set/try fmt
- remove unecessary include freezer.h
- check pad types on create
- return EBUSY when trying to set the format while stream is on
- remove vsd struct
- add IS_SRC and IS_SINK macros
- add deb_mean_win_size as a parameter of the module
- check set_fmt default parameters for quantization, colorspace ...
- add more dev_dbg
--- drivers/media/platform/vimc/Makefile | 2 +- drivers/media/platform/vimc/vimc-core.c | 6 +- drivers/media/platform/vimc/vimc-core.h | 2 + drivers/media/platform/vimc/vimc-debayer.c | 573 +++++++++++++++++++++++++++++ drivers/media/platform/vimc/vimc-debayer.h | 28 ++ 5 files changed, 609 insertions(+), 2 deletions(-) create mode 100644 drivers/media/platform/vimc/vimc-debayer.c create mode 100644 drivers/media/platform/vimc/vimc-debayer.h
drivers/media/platform/vimc/Makefile +1 -1
@@ -1,3 +1,3 @@ -vimc-objs := vimc-core.o vimc-capture.o vimc-sensor.o +vimc-objs := vimc-core.o vimc-capture.o vimc-debayer.o vimc-sensor.o obj-$(CONFIG_VIDEO_VIMC) += vimc.o
drivers/media/platform/vimc/vimc-core.c +5 -1
@@ -23,6 +23,7 @@#include "vimc-capture.h" #include "vimc-core.h" +#include "vimc-debayer.h" #include "vimc-sensor.h" #define VIMC_PDEV_NAME "vimc"
@@ -637,9 +638,12 @@ static int vimc_device_register(struct vimc_device *vimc) create_func = vimc_cap_create;break ; +case VIMC_ENT_NODE_DEBAYER : + create_func = vimc_deb_create; +break ; +/* TODO: Instantiate the specific topology node */ case VIMC_ENT_NODE_INPUT : -case VIMC_ENT_NODE_DEBAYER :case VIMC_ENT_NODE_SCALER :default :/*
drivers/media/platform/vimc/vimc-core.h +2 -0
@@ -26,6 +26,8 @@#define VIMC_FRAME_MIN_WIDTH 16#define VIMC_FRAME_MIN_HEIGHT 16 +#define VIMC_FRAME_INDEX (lin, col, width, bpp) ((lin * width + col) * bpp) +/** * struct vimc_pix_map - maps media bus code with v4l2 pixel format *
drivers/media/platform/vimc/vimc-debayer.c new file +573 -0
573 lines not on this page · raw message
drivers/media/platform/vimc/vimc-debayer.h new file +28 -0
@@ -0,0 +1,28 @@ +/* +* vimc-debayer.h Virtual Media Controller Driver +* +* Copyright (C) 2015-2017 Helen Koike <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#ifndef _VIMC_DEBAYER_H_ +#define _VIMC_DEBAYER_H_ + +#include "vimc-core.h" + +struct vimc_ent_device *vimc_deb_create (struct v4l2_device *v4l2_dev, +const char *const name, +u16 num_pads, +const unsigned long *pads_flag); + +#endif
Signature · 1 line
2.7.4
Re: [PATCH v2 6/7] [media] vimc: deb: Add debayer filter
Quoted 341 lines · Helen Koike
Implement the debayer filter and integrate it with the core
Signed-off-by Helen Koike <[email protected]>---
Changes in v2:
[media] vimc: deb: Add debayer filter
- UsingMEDIA_ENT_F_ATV_DECODERin function
- removev4l2_devand dev fromvimc_deb_devicestruct
- src fmt propagates from the sink
- coding style
- remove redundant else if statements
- check end of enum and removeBUG_ON
- enum frame size with min and max values
- set/try fmt
- remove unecessary includefreezer.h
- check pad types on create
- return EBUSY when trying to set the format while stream is on
- remove vsd struct
- addIS_SRCandIS_SINKmacros
- adddeb_mean_win_sizeas a parameter of the module
- checkset_fmtdefault parameters for quantization, colorspace ...
- add moredev_dbg--- drivers/media/platform/vimc/Makefile | 2 +- drivers/media/platform/vimc/vimc-core.c | 6 +- drivers/media/platform/vimc/vimc-core.h | 2 + drivers/media/platform/vimc/vimc-debayer.c | 573 +++++++++++++++++++++++++++++ drivers/media/platform/vimc/vimc-debayer.h | 28 ++ 5 files changed, 609 insertions(+), 2 deletions(-) create mode 100644 drivers/media/platform/vimc/vimc-debayer.c create mode 100644 drivers/media/platform/vimc/vimc-debayer.hdrivers/media/platform/vimc/Makefile +1
-1@@ -1,3 +1,3 @@ -vimc-objs := vimc-core.o vimc-capture.o vimc-sensor.o +vimc-objs := vimc-core.o vimc-capture.o vimc-debayer.o vimc-sensor.o obj-$(CONFIG_VIDEO_VIMC) += vimc.odrivers/media/platform/vimc/vimc-core.c +5
-1@@ -23,6 +23,7 @@#include "vimc-capture.h" #include "vimc-core.h" +#include "vimc-debayer.h" #include "vimc-sensor.h" #define VIMC_PDEV_NAME "vimc"@@ -637,9 +638,12 @@ static int vimc_device_register(struct vimc_device *vimc) create_func = vimc_cap_create;break ; +case VIMC_ENT_NODE_DEBAYER : + create_func = vimc_deb_create; +break ; +/* TODO: Instantiate the specific topology node */ case VIMC_ENT_NODE_INPUT : -case VIMC_ENT_NODE_DEBAYER :case VIMC_ENT_NODE_SCALER :default :/* drivers/media/platform/vimc/vimc-core.h +2
-0@@ -26,6 +26,8 @@#define VIMC_FRAME_MIN_WIDTH 16#define VIMC_FRAME_MIN_HEIGHT 16 +#define VIMC_FRAME_INDEX (lin, col, width, bpp) ((lin * width + col) * bpp) +/** * struct vimc_pix_map - maps media bus code with v4l2 pixel format * drivers/media/platform/vimc/vimc-debayer.c new file +251
-0@@ -0,0 +1,573 @@ +/* +* vimc-debayer.c Virtual Media Controller Driver +* +* Copyright (C) 2015-2017 Helen Koike <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include <linux/module.h> +#include <linux/vmalloc.h> +#include <linux/v4l2-mediabus.h> +#include <media/v4l2-subdev.h> + +#include "vimc-debayer.h" + +static unsigned int deb_mean_win_size =3 ; +module_param (deb_mean_win_size, uint,0000 ); +MODULE_PARM_DESC (deb_mean_win_size," the window size to calculate the mean.\n" +"NOTE: the window size need to be an odd number, as the main pixel " +"stays in the center of the window, otherwise the next odd number " +"is considered" ); + +#define IS_SINK (pad) (!pad) +#define IS_SRC (pad) (pad) + +enum vimc_deb_rgb_colors { +VIMC_DEB_RED =0 , +VIMC_DEB_GREEN =1 , +VIMC_DEB_BLUE =2 , +}; + +struct vimc_deb_pix_map { +u32 code; +enum vimc_deb_rgb_colors order[2 ][2 ]; +}; + +struct vimc_deb_device { +struct vimc_ent_device ved; +struct v4l2_subdev sd; +/* The active format */ +struct v4l2_mbus_framefmt sink_fmt; +u32 src_code; +void (*set_rgb_src)(struct vimc_deb_device *vdeb,unsigned int lin, +unsigned int col,unsigned int rgb[3 ]); +/* Values calculated when the stream starts */ +u8 *src_frame; +unsigned int src_frame_size; +const struct vimc_deb_pix_map *sink_pix_map; +unsigned int sink_bpp; +}; + +static const struct v4l2_mbus_framefmt sink_fmt_default = { + .width =640 , + .height =480 , + .code =MEDIA_BUS_FMT_RGB888_1X24 , + .field =V4L2_FIELD_NONE , + .colorspace =V4L2_COLORSPACE_SRGB , + .quantization =V4L2_QUANTIZATION_FULL_RANGE , + .xfer_func =V4L2_XFER_FUNC_SRGB , +}; + +static const struct vimc_deb_pix_map vimc_deb_pix_map_list[] = { + { + .code =MEDIA_BUS_FMT_SBGGR8_1X8 , + .order = { {VIMC_DEB_BLUE ,VIMC_DEB_GREEN }, + {VIMC_DEB_GREEN ,VIMC_DEB_RED } } + }, + { + .code =MEDIA_BUS_FMT_SGBRG8_1X8 , + .order = { {VIMC_DEB_GREEN ,VIMC_DEB_BLUE }, + {VIMC_DEB_RED ,VIMC_DEB_GREEN } } + }, + { + .code =MEDIA_BUS_FMT_SGRBG8_1X8 , + .order = { {VIMC_DEB_GREEN ,VIMC_DEB_RED }, + {VIMC_DEB_BLUE ,VIMC_DEB_GREEN } } + }, + { + .code =MEDIA_BUS_FMT_SRGGB8_1X8 , + .order = { {VIMC_DEB_RED ,VIMC_DEB_GREEN }, + {VIMC_DEB_GREEN ,VIMC_DEB_BLUE } } + }, + { + .code =MEDIA_BUS_FMT_SBGGR10_1X10 , + .order = { {VIMC_DEB_BLUE ,VIMC_DEB_GREEN }, + {VIMC_DEB_GREEN ,VIMC_DEB_RED } } + }, + { + .code =MEDIA_BUS_FMT_SGBRG10_1X10 , + .order = { {VIMC_DEB_GREEN ,VIMC_DEB_BLUE }, + {VIMC_DEB_RED ,VIMC_DEB_GREEN } } + }, + { + .code =MEDIA_BUS_FMT_SGRBG10_1X10 , + .order = { {VIMC_DEB_GREEN ,VIMC_DEB_RED }, + {VIMC_DEB_BLUE ,VIMC_DEB_GREEN } } + }, + { + .code =MEDIA_BUS_FMT_SRGGB10_1X10 , + .order = { {VIMC_DEB_RED ,VIMC_DEB_GREEN }, + {VIMC_DEB_GREEN ,VIMC_DEB_BLUE } } + }, + { + .code =MEDIA_BUS_FMT_SBGGR12_1X12 , + .order = { {VIMC_DEB_BLUE ,VIMC_DEB_GREEN }, + {VIMC_DEB_GREEN ,VIMC_DEB_RED } } + }, + { + .code =MEDIA_BUS_FMT_SGBRG12_1X12 , + .order = { {VIMC_DEB_GREEN ,VIMC_DEB_BLUE }, + {VIMC_DEB_RED ,VIMC_DEB_GREEN } } + }, + { + .code =MEDIA_BUS_FMT_SGRBG12_1X12 , + .order = { {VIMC_DEB_GREEN ,VIMC_DEB_RED }, + {VIMC_DEB_BLUE ,VIMC_DEB_GREEN } } + }, + { + .code =MEDIA_BUS_FMT_SRGGB12_1X12 , + .order = { {VIMC_DEB_RED ,VIMC_DEB_GREEN }, + {VIMC_DEB_GREEN ,VIMC_DEB_BLUE } } + }, +}; + +static const struct vimc_deb_pix_map *vimc_deb_pix_map_by_code (u32 code) +{ +unsigned int i; + +for (i =0 ; i <ARRAY_SIZE (vimc_deb_pix_map_list); i++) +if (vimc_deb_pix_map_list[i].code == code) +return &vimc_deb_pix_map_list[i]; + +return NULL ; +} + +static int vimc_deb_init_cfg (struct v4l2_subdev *sd, +struct v4l2_subdev_pad_config *cfg) +{ +struct vimc_deb_device *vdeb =v4l2_get_subdevdata (sd); +struct v4l2_mbus_framefmt *mf; +unsigned int i; + + mf =v4l2_subdev_get_try_format (sd, cfg,0 ); + *mf = sink_fmt_default; + +for (i =1 ; i < sd->entity.num_pads; i++) { + mf =v4l2_subdev_get_try_format (sd, cfg, i); + *mf = sink_fmt_default; + mf->code = vdeb->src_code; + } + +return 0 ; +} + +static int vimc_deb_enum_mbus_code (struct v4l2_subdev *sd, +struct v4l2_subdev_pad_config *cfg, +struct v4l2_subdev_mbus_code_enum *code) +{ +/* We only support one format for source pads */ +if (IS_SRC (code->pad)) { +struct vimc_deb_device *vdeb =v4l2_get_subdevdata (sd); + +if (code->index) +return -EINVAL ; + + code->code = vdeb->src_code; + }else { +if (code->index >=ARRAY_SIZE (vimc_deb_pix_map_list)) +return -EINVAL ; + + code->code = vimc_deb_pix_map_list[code->index].code; + } + +return 0 ; +} + +static int vimc_deb_enum_frame_size (struct v4l2_subdev *sd, +struct v4l2_subdev_pad_config *cfg, +struct v4l2_subdev_frame_size_enum *fse) +{ +struct vimc_deb_device *vdeb =v4l2_get_subdevdata (sd); + +if (fse->index) +return -EINVAL ; + +if (IS_SINK (fse->pad)) { +const struct vimc_deb_pix_map *vpix = +vimc_deb_pix_map_by_code (fse->code); + +if (!vpix) +return -EINVAL ; + }else if (fse->code != vdeb->src_code) { +return -EINVAL ; + } + + fse->min_width =VIMC_FRAME_MIN_WIDTH ; + fse->max_width =VIMC_FRAME_MAX_WIDTH ; + fse->min_height =VIMC_FRAME_MIN_HEIGHT ; + fse->max_height =VIMC_FRAME_MAX_HEIGHT ; + +return 0 ; +} + +static int vimc_deb_get_fmt (struct v4l2_subdev *sd, +struct v4l2_subdev_pad_config *cfg, +struct v4l2_subdev_format *fmt) +{ +struct vimc_deb_device *vdeb =v4l2_get_subdevdata (sd); + +/* Get the current sink format */ + fmt->format = fmt->which ==V4L2_SUBDEV_FORMAT_TRY ? + *v4l2_subdev_get_try_format (sd, cfg,0 ) : + vdeb->sink_fmt; + +/* Set the right code for the source pad */ +if (IS_SRC (fmt->pad)) + fmt->format.code = vdeb->src_code; + +return 0 ; +} + +static void vimc_deb_adjust_sink_fmt (struct v4l2_mbus_framefmt *fmt) +{ +const struct vimc_deb_pix_map *vpix; + +/* Don't accept a code that is not on the debayer table */ + vpix =vimc_deb_pix_map_by_code (fmt->code); +if (!vpix) + fmt->code = sink_fmt_default.code; + + fmt->width =clamp_t (u32, fmt->width,VIMC_FRAME_MIN_WIDTH , +VIMC_FRAME_MAX_WIDTH ); + fmt->height =clamp_t (u32, fmt->height,VIMC_FRAME_MIN_HEIGHT , +VIMC_FRAME_MAX_HEIGHT ); + +if (fmt->field ==V4L2_FIELD_ANY ) + fmt->field = sink_fmt_default.field; + +/* Check if values are out of range */ +if (fmt->colorspace ==V4L2_COLORSPACE_DEFAULT + || fmt->colorspace >V4L2_COLORSPACE_DCI_P3 ) + fmt->colorspace = sink_fmt_default.colorspace;
drivers/media/platform/vimc/vimc-debayer.c line 261
Quoted 10 lines
drivers/media/platform/vimc/vimc-debayer.c new file +10
-0+if (fmt->ycbcr_enc ==V4L2_YCBCR_ENC_DEFAULT + || fmt->ycbcr_enc >V4L2_YCBCR_ENC_SMPTE240M ) + fmt->ycbcr_enc = sink_fmt_default.ycbcr_enc; +if (fmt->quantization ==V4L2_QUANTIZATION_DEFAULT + || fmt->quantization >V4L2_QUANTIZATION_LIM_RANGE ) + fmt->quantization = sink_fmt_default.quantization; +if (fmt->xfer_func ==V4L2_XFER_FUNC_DEFAULT + || fmt->xfer_func >V4L2_XFER_FUNC_SMPTE2084 ) + fmt->xfer_func = sink_fmt_default.xfer_func; +}
Same comments as from the previous patches apply here as well.
Quoted 236 lines
drivers/media/platform/vimc/vimc-debayer.c new file +236
-0+ +static int vimc_deb_set_fmt (struct v4l2_subdev *sd, +struct v4l2_subdev_pad_config *cfg, +struct v4l2_subdev_format *fmt) +{ +struct vimc_deb_device *vdeb =v4l2_get_subdevdata (sd); +struct v4l2_mbus_framefmt *sink_fmt; + +if (fmt->which ==V4L2_SUBDEV_FORMAT_ACTIVE ) { +/* Do not change the format while stream is on */ +if (vdeb->src_frame) +return -EBUSY ; + + sink_fmt = &vdeb->sink_fmt; + }else { + sink_fmt =v4l2_subdev_get_try_format (sd, cfg,0 ); + } + +/* +* Do not change the format of the source pad, +* it is propagated from the sink +*/ +if (IS_SRC (fmt->pad)) { + fmt->format = *sink_fmt; +/* TODO: Add support for other formats */ + fmt->format.code = vdeb->src_code; + }else { +/* Set the new format in the sink pad */ +vimc_deb_adjust_sink_fmt (&fmt->format); + +dev_dbg (vdeb->sd.v4l2_dev->mdev->dev,"%s: sink format update: " +"old:%dx%d (0x%x, %d, %d, %d, %d) " +"new:%dx%d (0x%x, %d, %d, %d, %d)\n" , vdeb->sd.name, +/* old */ + sink_fmt->width, sink_fmt->height, sink_fmt->code, + sink_fmt->colorspace, sink_fmt->quantization, + sink_fmt->xfer_func, sink_fmt->ycbcr_enc, +/* new */ + fmt->format.width, fmt->format.height, fmt->format.code, + fmt->format.colorspace, fmt->format.quantization, + fmt->format.xfer_func, fmt->format.ycbcr_enc); + + *sink_fmt = fmt->format; + } + +return 0 ; +} + +static const struct v4l2_subdev_pad_ops vimc_deb_pad_ops = { + .init_cfg = vimc_deb_init_cfg, + .enum_mbus_code = vimc_deb_enum_mbus_code, + .enum_frame_size = vimc_deb_enum_frame_size, + .get_fmt = vimc_deb_get_fmt, + .set_fmt = vimc_deb_set_fmt, +}; + +static void vimc_deb_set_rgb_mbus_fmt_rgb888_1x24 (struct vimc_deb_device *vdeb, +unsigned int lin, +unsigned int col, +unsigned int rgb[3 ]) +{ +unsigned int i, index; + + index =VIMC_FRAME_INDEX (lin, col, vdeb->sink_fmt.width,3 ); +for (i =0 ; i <3 ; i++) + vdeb->src_frame[index + i] = rgb[i]; +} + +static int vimc_deb_s_stream (struct v4l2_subdev *sd,int enable) +{ +struct vimc_deb_device *vdeb =v4l2_get_subdevdata (sd); + +if (enable) { +const struct vimc_pix_map *vpix; + +if (vdeb->src_frame) +return -EINVAL ; + +/* Calculate the frame size of the source pad */ + vpix =vimc_pix_map_by_code (vdeb->src_code); + vdeb->src_frame_size = vdeb->sink_fmt.width * + vpix->bpp * vdeb->sink_fmt.height; + +/* Save the bytes per pixel of the sink */ + vpix =vimc_pix_map_by_code (vdeb->sink_fmt.code); + vdeb->sink_bpp = vpix->bpp; + +/* Get the corresponding pixel map from the table */ + vdeb->sink_pix_map = +vimc_deb_pix_map_by_code (vdeb->sink_fmt.code); + +/* +* Allocate the frame buffer. Use vmalloc to be able to +* allocate a large amount of memory +*/ + vdeb->src_frame =vmalloc (vdeb->src_frame_size); +if (!vdeb->src_frame) +return -ENOMEM ; + +/* Turn the stream on in the subdevices directly connected */ +if (vimc_pipeline_s_stream (&vdeb->sd.entity,1 )) { +vfree (vdeb->src_frame); + vdeb->src_frame =NULL ; +return -EINVAL ; + } + + }else { +if (!vdeb->src_frame) +return -EINVAL ; + +/* Disable streaming from the pipe */ +vimc_pipeline_s_stream (&vdeb->sd.entity,0 ); +vfree (vdeb->src_frame); + vdeb->src_frame =NULL ; + } + +return 0 ; +} + +struct v4l2_subdev_video_ops vimc_deb_video_ops = { + .s_stream = vimc_deb_s_stream, +}; + +static const struct v4l2_subdev_ops vimc_deb_ops = { + .pad = &vimc_deb_pad_ops, + .video = &vimc_deb_video_ops, +}; + +static unsigned int vimc_deb_get_val (const u8 *bytes, +const unsigned int n_bytes) +{ +unsigned int i; +unsigned int acc =0 ; + +for (i =0 ; i < n_bytes; i++) + acc = acc + (bytes[i] << (8 * i)); + +return acc; +} + +static void vimc_deb_calc_rgb_sink (struct vimc_deb_device *vdeb, +const u8 *frame, +const unsigned int lin, +const unsigned int col, +unsigned int rgb[3 ]) +{ +unsigned int i, seek, wlin, wcol; +unsigned int n_rgb[3 ] = {0 ,0 ,0 }; + +for (i =0 ; i <3 ; i++) + rgb[i] =0 ; + +/* +* Calculate how many we need to subtract to get to the pixel in +* the top left corner of the mean window (considering the current +* pixel as the center) +*/ + seek = deb_mean_win_size /2 ; + +/* Sum the values of the colors in the mean window */ + +dev_dbg (vdeb->sd.v4l2_dev->mdev->dev, +"deb: %s: --- Calc pixel %dx%d, window mean %d, seek %d ---\n" , + vdeb->sd.name, lin, col, vdeb->sink_fmt.height, seek); + +/* +* Iterate through all the lines in the mean window, start +* with zero if the pixel is outside the frame and don't pass +* the height when the pixel is in the bottom border of the +* frame +*/ +for (wlin = seek > lin ?0 : lin - seek; + wlin < lin + seek +1 && wlin < vdeb->sink_fmt.height; + wlin++) { + +/* +* Iterate through all the columns in the mean window, start +* with zero if the pixel is outside the frame and don't pass +* the width when the pixel is in the right border of the +* frame +*/ +for (wcol = seek > col ?0 : col - seek; + wcol < col + seek +1 && wcol < vdeb->sink_fmt.width; + wcol++) { +enum vimc_deb_rgb_colors color; +unsigned int index; + +/* Check which color this pixel is */ + color = vdeb->sink_pix_map->order[wlin %2 ][wcol %2 ]; + + index =VIMC_FRAME_INDEX (wlin, wcol, + vdeb->sink_fmt.width, + vdeb->sink_bpp); + +dev_dbg (vdeb->sd.v4l2_dev->mdev->dev, +"deb: %s: RGB CALC: frame index %d, win pos %dx%d, color %d\n" , + vdeb->sd.name, index, wlin, wcol, color); + +/* Get its value */ + rgb[color] = rgb[color] + +vimc_deb_get_val (&frame[index], vdeb->sink_bpp); + +/* Save how many values we already added */ + n_rgb[color]++; + +dev_dbg (vdeb->sd.v4l2_dev->mdev->dev, +"deb: %s: RGB CALC: val %d, n %d\n" , + vdeb->sd.name, rgb[color], n_rgb[color]); + } + } + +/* Calculate the mean */ +for (i =0 ; i <3 ; i++) { +dev_dbg (vdeb->sd.v4l2_dev->mdev->dev, +"deb: %s: PRE CALC: %dx%d Color %d, val %d, n %d\n" , + vdeb->sd.name, lin, col, i, rgb[i], n_rgb[i]); + +if (n_rgb[i]) + rgb[i] = rgb[i] / n_rgb[i]; + +dev_dbg (vdeb->sd.v4l2_dev->mdev->dev, +"deb: %s: FINAL CALC: %dx%d Color %d, val %d\n" , + vdeb->sd.name, lin, col, i, rgb[i]); + } +} + +static void vimc_deb_process_frame (struct vimc_ent_device *ved, +struct media_pad *sink, +const void *sink_frame) +{ + struct vimc_deb_device *vdeb = container_of(ved, struct vimc_deb_device, + ved); +unsigned int rgb[3 ]; +unsigned int i, j; + +/* If the stream in this node is not active, just return */
drivers/media/platform/vimc/vimc-debayer.c line 507
Quoted 10 lines
drivers/media/platform/vimc/vimc-debayer.c new file +10
-0+if (!vdeb->src_frame) +return ; + +for (i =0 ; i < vdeb->sink_fmt.height; i++) +for (j =0 ; j < vdeb->sink_fmt.width; j++) { +vimc_deb_calc_rgb_sink (vdeb, sink_frame, i, j, rgb); + vdeb->set_rgb_src (vdeb, i, j, rgb); + } + +/* Propagate the frame thought all source pads */
thought -> through
Quoted 45 lines
drivers/media/platform/vimc/vimc-debayer.c new file +45
-0+for (i =1 ; i < vdeb->sd.entity.num_pads; i++) { +struct media_pad *pad = &vdeb->sd.entity.pads[i]; + +vimc_propagate_frame (pad, vdeb->src_frame); + } +} + +static void vimc_deb_destroy (struct vimc_ent_device *ved) +{ + struct vimc_deb_device *vdeb = container_of(ved, struct vimc_deb_device, + ved); + +vimc_ent_sd_unregister (ved, &vdeb->sd); +kfree (vdeb); +} + +struct vimc_ent_device *vimc_deb_create (struct v4l2_device *v4l2_dev, +const char *const name, +u16 num_pads, +const unsigned long *pads_flag) +{ +struct vimc_deb_device *vdeb; +unsigned int i; +int ret; + +/* check pads types +* NOTE: we support a single sink pad and multiple source pads +* the sink pad must be the first +*/ +if (num_pads <2 || !(pads_flag[0 ] &MEDIA_PAD_FL_SINK )) +return ERR_PTR (-EINVAL ); + +/* check if the rest of pads are sources */ +for (i =1 ; i < num_pads; i++) +if (!(pads_flag[i] &MEDIA_PAD_FL_SOURCE )) +return ERR_PTR (-EINVAL ); + +/* Allocate the vdeb struct */ + vdeb =kzalloc (sizeof (*vdeb),GFP_KERNEL ); +if (!vdeb) +return ERR_PTR (-ENOMEM ); + +/* Initialize ved and sd */ + ret = vimc_ent_sd_register(&vdeb->ved, &vdeb->sd, v4l2_dev, name, + MEDIA_ENT_F_ATV_DECODER, num_pads, pads_flag,
drivers/media/platform/vimc/vimc-debayer.c line 562
Quoted 10 lines
drivers/media/platform/vimc/vimc-debayer.c new file +10
-0+ &vimc_deb_ops, vimc_deb_destroy); +if (ret) { +kfree (vdeb); +return ERR_PTR (ret); + } + +/* Initialize the frame format */ + vdeb->sink_fmt = sink_fmt_default; +/* TODO: Add support for more output formats, we only support +* RGB8888 for now
RGB888, not 8888.
Quoted 36 lines
drivers/media/platform/vimc/vimc-debayer.c new file +11
-0+* NOTE: the src format is always the same as the sink, except +* for the code +*/ + vdeb->src_code =MEDIA_BUS_FMT_RGB888_1X24 ; + vdeb->set_rgb_src = vimc_deb_set_rgb_mbus_fmt_rgb888_1x24; + +/* Set the process frame callback */ + vdeb->ved.process_frame = vimc_deb_process_frame; + +return &vdeb->ved; +}drivers/media/platform/vimc/vimc-debayer.h new file +18
-0@@ -0,0 +1,28 @@ +/* +* vimc-debayer.h Virtual Media Controller Driver +* +* Copyright (C) 2015-2017 Helen Koike <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#ifndef _VIMC_DEBAYER_H_
drivers/media/platform/vimc/vimc-debayer.h line 28
Quoted 10 lines
drivers/media/platform/vimc/vimc-debayer.h new file +10
-0+#define _VIMC_DEBAYER_H_ + +#include "vimc-core.h" + +struct vimc_ent_device *vimc_deb_create (struct v4l2_device *v4l2_dev, +const char *const name, +u16 num_pads, +const unsigned long *pads_flag); + +#endif
Regards,
Hans
PATCH v2 7/7 vimc: sca: Add scaler
In reply to Helen KoikeImplement scaler and integrated with the core
---
Changes in v2:
[media] vimc: sca: Add scaler
- Add function MEDIA_ENT_F_IO_V4L
- remove v4l2_dev and dev
- s/sink_mbus_fmt/sink_fmt
- remove BUG_ON, remove redundant if else, rewrite TODO, check end of enum
- rm src_width/height, enum fsize with min and max values
- set/try fmt
- remove unecessary include freezer.h
- core: add bayer boolean in pixel table
- coding style
- fix bug in enum frame size
- check pad types on create
- return EBUSY when trying to set the format while stream is on
- remove vsd struct
- add IS_SRC and IS_SINK macros
- add sca_mult as a parameter of the module
- check set_fmt default parameters for quantization, colorspace ...
- add more dev_dbg
--- drivers/media/platform/vimc/Makefile | 3 +- drivers/media/platform/vimc/vimc-core.c | 33 ++- drivers/media/platform/vimc/vimc-core.h | 1 + drivers/media/platform/vimc/vimc-scaler.c | 426 ++++++++++++++++++++++++++++++ drivers/media/platform/vimc/vimc-scaler.h | 28 ++ 5 files changed, 489 insertions(+), 2 deletions(-) create mode 100644 drivers/media/platform/vimc/vimc-scaler.c create mode 100644 drivers/media/platform/vimc/vimc-scaler.h
drivers/media/platform/vimc/Makefile +2 -1
@@ -1,3 +1,4 @@ -vimc-objs := vimc-core.o vimc-capture.o vimc-debayer.o vimc-sensor.o +vimc-objs := vimc-core.o vimc-capture.o vimc-debayer.o vimc-scaler.o \ + vimc-sensor.o obj-$(CONFIG_VIDEO_VIMC) += vimc.o
drivers/media/platform/vimc/vimc-core.c +32 -1
@@ -24,6 +24,7 @@#include "vimc-capture.h" #include "vimc-core.h" #include "vimc-debayer.h" +#include "vimc-scaler.h" #include "vimc-sensor.h" #define VIMC_PDEV_NAME "vimc"
@@ -198,6 +199,10 @@ static const struct vimc_pipeline_config pipe_cfg = {/* -------------------------------------------------------------------------- */ +/* +* NOTE: non-bayer formats need to come first (necessary for enum_mbus_code +* in the scaler) +*/ static const struct vimc_pix_map vimc_pix_map_list[] = {/* TODO: add all missing formats */
@@ -206,16 +211,19 @@ static const struct vimc_pix_map vimc_pix_map_list[] = { .code = MEDIA_BUS_FMT_BGR888_1X24, .pixelformat = V4L2_PIX_FMT_BGR24, .bpp = 3, + .bayer = false, }, { .code = MEDIA_BUS_FMT_RGB888_1X24, .pixelformat = V4L2_PIX_FMT_RGB24, .bpp = 3, + .bayer = false, }, { .code = MEDIA_BUS_FMT_ARGB8888_1X32, .pixelformat = V4L2_PIX_FMT_ARGB32, .bpp = 4, + .bayer = false, }, /* Bayer formats */
@@ -223,41 +231,49 @@ static const struct vimc_pix_map vimc_pix_map_list[] = { .code = MEDIA_BUS_FMT_SBGGR8_1X8, .pixelformat = V4L2_PIX_FMT_SBGGR8, .bpp = 1, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SGBRG8_1X8, .pixelformat = V4L2_PIX_FMT_SGBRG8, .bpp = 1, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SGRBG8_1X8, .pixelformat = V4L2_PIX_FMT_SGRBG8, .bpp = 1, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SRGGB8_1X8, .pixelformat = V4L2_PIX_FMT_SRGGB8, .bpp = 1, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SBGGR10_1X10, .pixelformat = V4L2_PIX_FMT_SBGGR10, .bpp = 2, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SGBRG10_1X10, .pixelformat = V4L2_PIX_FMT_SGBRG10, .bpp = 2, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SGRBG10_1X10, .pixelformat = V4L2_PIX_FMT_SGRBG10, .bpp = 2, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SRGGB10_1X10, .pixelformat = V4L2_PIX_FMT_SRGGB10, .bpp = 2, + .bayer = true, }, /* 10bit raw bayer a-law compressed to 8 bits */
@@ -265,21 +281,25 @@ static const struct vimc_pix_map vimc_pix_map_list[] = { .code = MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8, .pixelformat = V4L2_PIX_FMT_SBGGR10ALAW8, .bpp = 1, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8, .pixelformat = V4L2_PIX_FMT_SGBRG10ALAW8, .bpp = 1, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, .pixelformat = V4L2_PIX_FMT_SGRBG10ALAW8, .bpp = 1, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8, .pixelformat = V4L2_PIX_FMT_SRGGB10ALAW8, .bpp = 1, + .bayer = true, }, /* 10bit raw bayer DPCM compressed to 8 bits */
@@ -287,41 +307,49 @@ static const struct vimc_pix_map vimc_pix_map_list[] = { .code = MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, .pixelformat = V4L2_PIX_FMT_SBGGR10DPCM8, .bpp = 1, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, .pixelformat = V4L2_PIX_FMT_SGBRG10DPCM8, .bpp = 1, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8, .bpp = 1, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, .pixelformat = V4L2_PIX_FMT_SRGGB10DPCM8, .bpp = 1, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SBGGR12_1X12, .pixelformat = V4L2_PIX_FMT_SBGGR12, .bpp = 2, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SGBRG12_1X12, .pixelformat = V4L2_PIX_FMT_SGBRG12, .bpp = 2, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SGRBG12_1X12, .pixelformat = V4L2_PIX_FMT_SGRBG12, .bpp = 2, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SRGGB12_1X12, .pixelformat = V4L2_PIX_FMT_SRGGB12, .bpp = 2, + .bayer = true, }, };
@@ -642,9 +670,12 @@ static int vimc_device_register(struct vimc_device *vimc) create_func = vimc_deb_create;break ; +case VIMC_ENT_NODE_SCALER : + create_func = vimc_sca_create; +break ; +/* TODO: Instantiate the specific topology node */ case VIMC_ENT_NODE_INPUT : -case VIMC_ENT_NODE_SCALER :default :/* * TODO: remove this when all the entities specific
drivers/media/platform/vimc/vimc-core.h +1 -0
@@ -42,6 +42,7 @@ struct vimc_pix_map {unsigned int code;unsigned int bpp;u32 pixelformat; +bool bayer; };/**
drivers/media/platform/vimc/vimc-scaler.c new file +426 -0
426 lines not on this page · raw message
drivers/media/platform/vimc/vimc-scaler.h new file +28 -0
@@ -0,0 +1,28 @@ +/* +* vimc-scaler.h Virtual Media Controller Driver +* +* Copyright (C) 2015-2017 Helen Koike <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#ifndef _VIMC_SCALER_H_ +#define _VIMC_SCALER_H_ + +#include "vimc-core.h" + +struct vimc_ent_device *vimc_sca_create (struct v4l2_device *v4l2_dev, +const char *const name, +u16 num_pads, +const unsigned long *pads_flag); + +#endif
Signature · 1 line
2.7.4
Re: [PATCH v2 0/7] [media]: vimc: Virtual Media Control VPU's
In reply to Helen KoikeHi Helen,
Quoted 11 lines · Helen Koike
This patch series improves the current video processing units in vimc (by adding more controls to the sensor and capture node, allowing the user to configure different frame formats) and also adds a debayer and a scaler node.
The debayer transforms the bayer format image received in its sink pad to a bayer format by averaging the pixels within a mean window. The scaler only scales up the image for now.This patch series depends on commit "[media] vimc: Virtual Media Controller core, capture and sensor" and it is available at:
https://github.com/helen-fornazier/opw-staging/tree/z/sent/vimc/vpu/v2
As you saw, I had some comments, but nothing major.
One thing I was wondering about: the since the sensor is using the tpg anyway, we can in theory use the tpg as well to generate the output of the debayer and scaler blocks.
It won't be quite the same since it is not actually processing the frame, but it is efficient. It might need additional work in the tpg though. I'm not sure how worthwhile this is, and it probably shouldn't be done now. But it is an idea since I suspect doing a debayer + scaling of a 1920x1080 picture will be very slow.
Regards,
Hans
Quoted 106 lines
Changes in v2:
[media] vimc: sen: Integrate the tpg on the sensor
- Fix include location
- SelectV4L2_TPGinKconfig
- configure tpg on streamon only
- rmBUG_ON
- coding style
[media] vimc: Add vimc_ent_sd_* helper functions
- Comments invimc_ent_sd_init
- Updatevimc_ent_sd_initwith upstream code asmedia_entity_pads_init(instead ofmedia_entity_init),entity->functionintead ofentity->type
- Add missingvimc_pads_cleanupinvimc_ent_sd_cleanup
- remove subdevicev4l2_devand dev fields
- change unregister order invimc_ent_sd_cleanup
- rename vimc_ent_sd_{init,cleanup} to vimc_ent_sd_{register,unregister}
- remove structvimc_ent_subdevice, use ved and sd directly
- don't impose structvimc_sen_deviceto declare ved and sd struct first
- add kernel docs
[media] vimc: Addvimc_pipeline_s_streamin the core
- Useis_media_entity_v4l2_subdevinstead of comparing with the oldentity->type
- Fix comments style
- add kernel-docs
- calls_streamacross all sink pads
[media] vimc: sen: Support several image formats
- this is a new commit in the serie (the old one was splitted in two)
- addinit_cfgto initializetry_fmt
- reorder code invimc_sen_set_fmt
- allow user space to change all fields from structv4l2_mbus_framefmt
(e.g. colospace, quantization, field,xfer_func,ycbcr_enc)
- merge with patch for theenum_mbus_codeandenum_frame_size
- change commit message
- addvimc_pix_map_by_index
- rename MIN/MAX macros
- checkset_fmtdefault parameters for quantization, colorspace ...
[media] vimc: cap: Support several image formats
- this is a new commit in the serie (the old one was splitted in two)
- allow user space to change all fields from structv4l2_pix_format
(e.g. colospace, quantization, field,xfer_func,ycbcr_enc)
-link_validateandtry_fmt: also checks colospace, quantization, field,xfer_func,ycbcr_enc
- add structv4l2_pix_formatfmt_default
- addenum_framesizes
-enum_fmt_vid_cap: enumerate all formats fromvimc_pix_map_table
- add modedev_dbg
[media] vimc: deb: Add debayer filter
- UsingMEDIA_ENT_F_ATV_DECODERin function
- removev4l2_devand dev fromvimc_deb_devicestruct
- src fmt propagates from the sink
- coding style
- remove redundant else if statements
- check end of enum and removeBUG_ON
- enum frame size with min and max values
- set/try fmt
- remove unecessary includefreezer.h
- check pad types on create
- return EBUSY when trying to set the format while stream is on
- remove vsd struct
- addIS_SRCandIS_SINKmacros
- adddeb_mean_win_sizeas a parameter of the module
- checkset_fmtdefault parameters for quantization, colorspace ...
- add moredev_dbg
[media] vimc: sca: Add scaler
- Add functionMEDIA_ENT_F_IO_V4L
- removev4l2_devand dev
- s/sink_mbus_fmt/sink_fmt
- removeBUG_ON, remove redundant if else, rewrite TODO, check end of enum
- rm src_width/height, enum fsize with min and max values
- set/try fmt
- remove unecessary includefreezer.h
- core: add bayer boolean in pixel table
- coding style
- fix bug in enum frame size
- check pad types on create
- return EBUSY when trying to set the format while stream is on
- remove vsd struct
- addIS_SRCandIS_SINKmacros
- addsca_multas a parameter of the module
- checkset_fmtdefault parameters for quantization, colorspace ...
- add moredev_dbgHelen Koike (7):
[media] vimc: sen: Integrate the tpg on the sensor [media] vimc: Add vimc_ent_sd_* helper functions [media] vimc: Addvimc_pipeline_s_streamin the core [media] vimc: sen: Support several image formats [media] vimc: cap: Support several image formats [media] vimc: deb: Add debayer filter [media] vimc: sca: Add scalerdrivers/media/platform/vimc/Kconfig | 1 + drivers/media/platform/vimc/Makefile | 3 +- drivers/media/platform/vimc/vimc-capture.c | 196 +++++++--- drivers/media/platform/vimc/vimc-core.c | 145 +++++++- drivers/media/platform/vimc/vimc-core.h | 65 ++++ drivers/media/platform/vimc/vimc-debayer.c | 573 +++++++++++++++++++++++++++++ drivers/media/platform/vimc/vimc-debayer.h | 28 ++ drivers/media/platform/vimc/vimc-scaler.c | 426 +++++++++++++++++++++ drivers/media/platform/vimc/vimc-scaler.h | 28 ++ drivers/media/platform/vimc/vimc-sensor.c | 226 ++++++++---- 10 files changed, 1562 insertions(+), 129 deletions(-) create mode 100644 drivers/media/platform/vimc/vimc-debayer.c create mode 100644 drivers/media/platform/vimc/vimc-debayer.h create mode 100644 drivers/media/platform/vimc/vimc-scaler.c create mode 100644 drivers/media/platform/vimc/vimc-scaler.h
v3 cover : vimc: Virtual Media Control VPU's
In reply to Helen KoikeThis patch series improves the current video processing units in vimc (by adding more controls to the sensor and capture node, allowing the user to configure different frame formats) and also adds a debayer and a scaler node.
The debayer transforms the bayer format image received in its sink pad to a bayer format by averaging the pixels within a mean window. The scaler only scales up the image for now.
In this version I added an optimization where the image can be generated direct in the capture device instead of being generated in the sensor and processed by each node in the topology.
I also changed the approach to implement each node of the topology as a submodule to make the code component oriented, where new components won't need to touch vimc-core and won't need a header file. Please, let me know your view regarding this new approach.
Changes in v3:
[media] vimc: sen: Integrate the tpg on the sensor
- Declare frame_size as a local variable
- Set tpg frame format before starting kthread
- s_stream(sd, 1): return 0 if stream is already enabled
- s_stream(sd, 0): return 0 if stream is already disabled
- s_stream: propagate error from kthread_stop
- coding style when calling tpg_s_bytesperline
- s/vimc_thread_sen/vimc_sen_tpg_thread
- fix multiline comment
[media] vimc: Move common code from the core
- This is a new patch in the series
[media] vimc: Add vimc_ent_sd_* helper functions
- add it in vimc-common.c instead in vimc-core.c
- fix vimc_ent_sd_register, use function parameter to assign sd->entity.function instead of using a fixed value
- rename commit to add the "common" tag
[media] vimc: Add vimc_pipeline_s_stream in the core
- add it in vimc-common instead of vimc-core
- rename commit with "common" tag
[media] vimc: common: Add vimc_link_validate
- this is a new patch in the series
[media] vimc: sen: Support several image formats
- remove support for V4L2_FIELD_ALTERNATE (left as TODO for now)
- clamp image size to an even dimension for height and width
- set default values for colorimetry using _DEFAULT macro
- reset all values of colorimetry to _DEFAULT if user tries to set an invalid colorspace
[media] vimc: cap: Support several image formats
- use *_DEFAULT macros for colorimetry in the default format
- clamp height and width of the image by an even value
- is user try to set colorspace to an invalid format, set all colorimetry parameters to _DEFAULT
- remove V4L2_FMT_FLAG_COMPRESSED from vimc_cap_enum_fmt_vid_cap
- remove V4L2_BUF_TYPE_VIDEO_CAPTURE from vimc_cap_enum_fmt_vid_cap
- increase step_width and step_height to 2 instead of 1
- remove link validate function, use the one in vimc-common.c
[media] vimc: Optimize frame generation through the pipe
- This is a new patch in the series
[media] vimc: Subdevices as modules
- This is a new patch in the series
[media] vimc: deb: Add debayer filter
- Declare frame_size as a local variable
- s_stream(sd, 1): return 0 if stream is already enabled
- s_stream(sd, 0): return 0 if stream is already disabled
- s_stream: add ret variable to propagate return errors
- structure code to be a module, use platform_driver and component system
- fix multiline comment
- s/thought/through
- s/RGB8888/RGB888
- clamp height and width of the image by an even value
- if user try to set colorspace to an invalid format, set all colorimetry parameters to _DEFAULT
- uset _DEFAULT for colorimetry in the default format
[media] vimc: sca: Add scaler
- Declare frame_size as a local variable
- s_stream(sd, 1): return 0 if stream is already enabled
- s_stream(sd, 0): return 0 if stream is already disabled
- s_stream: add ret variable to propagate return errors
- structure code to be a module, use platform_driver and component system
- s/thought/through
- clamp height and width of the image by an even value
- if user try to set colorspace to an invalid format, set all colorimetry parameters to _DEFAULT
- uset _DEFAULT for colorimetry in the default format
Changes in v2:
[media] vimc: sen: Integrate the tpg on the sensor
- Fix include location
- Select V4L2_TPG in Kconfig
- configure tpg on streamon only
- rm BUG_ON
- coding style
- remove V4L2_FIELD_ALTERNATE from tpg_s_field
- remove V4L2_STD_PAL from tpg_fill_plane_buffer
[media] vimc: Add vimc_ent_sd_* helper functions
- Comments in vimc_ent_sd_init
- Update vimc_ent_sd_init with upstream code as media_entity_pads_init
(instead of media_entity_init), entity->function intead of entity->type
- Add missing vimc_pads_cleanup in vimc_ent_sd_cleanup
- remove subdevice v4l2_dev and dev fields
- change unregister order in vimc_ent_sd_cleanup
- rename vimc_ent_sd_{init,cleanup} to vimc_ent_sd_{register,unregister}
- remove struct vimc_ent_subdevice, use ved and sd directly
- don't impose struct vimc_sen_device to declare ved and sd struct first
- add kernel docs
[media] vimc: Add vimc_pipeline_s_stream in the core
- Use is_media_entity_v4l2_subdev instead of comparing with the old
entity->type
- Fix comments style
- add kernel-docs
- call s_stream across all sink pads
[media] vimc: sen: Support several image formats
- this is a new commit in the serie (the old one was splitted in two)
- add init_cfg to initialize try_fmt
- reorder code in vimc_sen_set_fmt
- allow user space to change all fields from struct v4l2_mbus_framefmt
(e.g. colospace, quantization, field, xfer_func, ycbcr_enc)
- merge with patch for the enum_mbus_code and enum_frame_size
- change commit message
- add vimc_pix_map_by_index
- rename MIN/MAX macros
- check set_fmt default parameters for quantization, colorspace ...media] vimc: sen: Support several image formats
[media] vimc: cap: Support several image formats
- this is a new commit in the serie (the old one was splitted in two)
- allow user space to change all fields from struct v4l2_pix_format
(e.g. colospace, quantization, field, xfer_func, ycbcr_enc)
- link_validate and try_fmt: also checks colospace, quantization, field, xfer_func, ycbcr_enc
- add struct v4l2_pix_format fmt_default
- add enum_framesizes
- enum_fmt_vid_cap: enumerate all formats from vimc_pix_map_table
- add mode dev_dbg
[media] vimc: deb: Add debayer filter
- Using MEDIA_ENT_F_ATV_DECODER in function
- remove v4l2_dev and dev from vimc_deb_device struct
- src fmt propagates from the sink
- coding style
- remove redundant else if statements
- check end of enum and remove BUG_ON
- enum frame size with min and max values
- set/try fmt
- remove unecessary include freezer.h
- check pad types on create
- return EBUSY when trying to set the format while stream is on
- remove vsd struct
- add IS_SRC and IS_SINK macros
- add deb_mean_win_size as a parameter of the module
- check set_fmt default parameters for quantization, colorspace ...
- add more dev_dbg
[media] vimc: sca: Add scaler
- Add function MEDIA_ENT_F_IO_V4L
- remove v4l2_dev and dev
- s/sink_mbus_fmt/sink_fmt
- remove BUG_ON, remove redundant if else, rewrite TODO, check end of enum
- rm src_width/height, enum fsize with min and max values
- set/try fmt
- remove unecessary include freezer.h
- core: add bayer boolean in pixel table
- coding style
- fix bug in enum frame size
- check pad types on create
- return EBUSY when trying to set the format while stream is on
- remove vsd struct
- add IS_SRC and IS_SINK macros
- add sca_mult as a parameter of the module
- check set_fmt default parameters for quantization, colorspace ...
- add more dev_dbg
Helen Koike (11):
[media] vimc: sen: Integrate the tpg on the sensor [media] vimc: Move common code from the core [media] vimc: common: Add vimc_ent_sd_* helper [media] vimc: common: Add vimc_pipeline_s_stream helper [media] vimc: common: Add vimc_link_validate [media] vimc: sen: Support several image formats [media] vimc: cap: Support several image formats [media] vimc: Optimize frame generation through the pipe [media] vimc: Subdevices as modules
[media] vimc: deb: Add debayer filter
[media] vimc: sca: Add scaler
drivers/media/platform/vimc/Kconfig | 1 +
drivers/media/platform/vimc/Makefile | 10 +-
drivers/media/platform/vimc/vimc-capture.c | 488 ++++++++++------
drivers/media/platform/vimc/vimc-capture.h | 28 -
drivers/media/platform/vimc/vimc-common.c | 475 ++++++++++++++++
.../platform/vimc/{vimc-core.h => vimc-common.h} | 88 ++-
drivers/media/platform/vimc/vimc-core.c | 611 ++++++--------------
drivers/media/platform/vimc/vimc-debayer.c | 615 +++++++++++++++++++++
drivers/media/platform/vimc/vimc-scaler.c | 469 ++++++++++++++++
drivers/media/platform/vimc/vimc-sensor.c | 348 ++++++++----
drivers/media/platform/vimc/vimc-sensor.h | 28 -
11 files changed, 2370 insertions(+), 791 deletions(-)
delete mode 100644 drivers/media/platform/vimc/vimc-capture.h
create mode 100644 drivers/media/platform/vimc/vimc-common.c
rename drivers/media/platform/vimc/{vimc-core.h => vimc-common.h} (54%)
create mode 100644 drivers/media/platform/vimc/vimc-debayer.c
create mode 100644 drivers/media/platform/vimc/vimc-scaler.c
delete mode 100644 drivers/media/platform/vimc/vimc-sensor.hSignature · 1 line
2.7.4
RFC PATCH v3 1/11 vimc: sen: Integrate the tpg on the sensor
Initialize the test pattern generator on the sensor Generate a colored bar image instead of a grey one
---
Changes in v3:
[media] vimc: sen: Integrate the tpg on the sensor
- Declare frame_size as a local variable
- Set tpg frame format before starting kthread
- s_stream(sd, 1): return 0 if stream is already enabled
- s_stream(sd, 0): return 0 if stream is already disabled
- s_stream: propagate error from kthread_stop
- coding style when calling tpg_s_bytesperline
- s/vimc_thread_sen/vimc_sen_tpg_thread
- fix multiline comment
Changes in v2:
[media] vimc: sen: Integrate the tpg on the sensor
- Fix include location
- Select V4L2_TPG in Kconfig
- configure tpg on streamon only
- rm BUG_ON
- coding style
- remove V4L2_FIELD_ALTERNATE from tpg_s_field
- remove V4L2_STD_PAL from tpg_fill_plane_buffer
--- drivers/media/platform/vimc/Kconfig | 1 + drivers/media/platform/vimc/vimc-sensor.c | 64 ++++++++++++++++++++++++------- 2 files changed, 52 insertions(+), 13 deletions(-)
drivers/media/platform/vimc/Kconfig +1 -0
@@ -2,6 +2,7 @@ config VIDEO_VIMC tristate "Virtual Media Controller Driver (VIMC)" depends on VIDEO_DEV && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_VMALLOC + select VIDEO_V4L2_TPG default n ---help--- Skeleton driver for Virtual Media Controller
drivers/media/platform/vimc/vimc-sensor.c +51 -13
152 lines not on this page · raw message
Signature · 1 line
2.7.4
RFC PATCH v3 2/11 vimc: Move common code from the core
In reply to Helen KoikeRemove helper functions from vimc-core and add it in vimc-common to clean up the core.
---
Changes in v3:
[media] vimc: Move common code from the core
- This is a new patch in the series
Changes in v2: None
---
drivers/media/platform/vimc/Makefile | 2 +-
drivers/media/platform/vimc/vimc-capture.h | 2 +-
drivers/media/platform/vimc/vimc-common.c | 221 +++++++++++++++++++++
.../platform/vimc/{vimc-core.h => vimc-common.h} | 7 +-
drivers/media/platform/vimc/vimc-core.c | 205 +------------------
drivers/media/platform/vimc/vimc-sensor.h | 2 +-
6 files changed, 229 insertions(+), 210 deletions(-)
create mode 100644 drivers/media/platform/vimc/vimc-common.c
rename drivers/media/platform/vimc/{vimc-core.h => vimc-common.h} (96%)drivers/media/platform/vimc/Makefile +1 -1
@@ -1,3 +1,3 @@ -vimc-objs := vimc-core.o vimc-capture.o vimc-sensor.o +vimc-objs := vimc-core.o vimc-capture.o vimc-common.o vimc-sensor.o obj-$(CONFIG_VIDEO_VIMC) += vimc.o
drivers/media/platform/vimc/vimc-capture.h +1 -1
@@ -18,7 +18,7 @@#ifndef _VIMC_CAPTURE_H_#define _VIMC_CAPTURE_H_ -#include "vimc-core.h" +#include "vimc-common.h" struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, const char *const name,
drivers/media/platform/vimc/vimc-common.c new file +221 -0
221 lines not on this page · raw message
drivers/media/platform/vimc/vimc-common.h renamed from drivers/media/platform/vimc/vimc-core.h +4 -3
@@ -1,5 +1,5 @@/* -* vimc-core.h Virtual Media Controller Driver +* vimc-ccommon.h Virtual Media Controller Driver * * Copyright (C) 2015-2017 Helen Koike <[email protected]> *
@@ -15,10 +15,11 @@* */ -#ifndef _VIMC_CORE_H_ -#define _VIMC_CORE_H_ +#ifndef _VIMC_COMMON_H_ +#define _VIMC_COMMON_H_#include <linux/slab.h> +#include <media/media-device.h> #include <media/v4l2-device.h> /**
drivers/media/platform/vimc/vimc-core.c +1 -204
223 lines not on this page · raw message
drivers/media/platform/vimc/vimc-sensor.h +1 -1
@@ -18,7 +18,7 @@#ifndef _VIMC_SENSOR_H_#define _VIMC_SENSOR_H_ -#include "vimc-core.h" +#include "vimc-common.h" struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, const char *const name,
Signature · 1 line
2.7.4
RFC PATCH v3 3/11 vimc: common: Add vimc_ent_sd_* helper
In reply to Helen KoikeAs all the subdevices in the topology will be initialized in the same way, to avoid code repetition the vimc_ent_sd_{register, unregister} helper functions were created
---
Changes in v3:
[media] vimc: Add vimc_ent_sd_* helper functions
- add it in vimc-common.c instead in vimc-core.c
- fix vimc_ent_sd_register, use function parameter to assign sd->entity.function instead of using a fixed value
- rename commit to add the "common" tag
Changes in v2:
[media] vimc: Add vimc_ent_sd_* helper functions
- Comments in vimc_ent_sd_init
- Update vimc_ent_sd_init with upstream code as media_entity_pads_init (instead of media_entity_init), entity->function intead of entity->type
- Add missing vimc_pads_cleanup in vimc_ent_sd_cleanup
- remove subdevice v4l2_dev and dev fields
- change unregister order in vimc_ent_sd_cleanup
- rename vimc_ent_sd_{init,cleanup} to vimc_ent_sd_{register,unregister}
- remove struct vimc_ent_subdevice, use ved and sd directly
- don't impose struct vimc_sen_device to declare ved and sd struct first
- add kernel docs
--- drivers/media/platform/vimc/vimc-common.c | 66 +++++++++++++++++++++++++++++++ drivers/media/platform/vimc/vimc-common.h | 39 ++++++++++++++++++ drivers/media/platform/vimc/vimc-sensor.c | 58 +++++---------------------- 3 files changed, 114 insertions(+), 49 deletions(-)
drivers/media/platform/vimc/vimc-common.c +66 -0
@@ -219,3 +219,69 @@ struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag)return pads; } + +static const struct media_entity_operations vimc_ent_sd_mops = { + .link_validate = v4l2_subdev_link_validate, +}; + +int vimc_ent_sd_register (struct vimc_ent_device *ved, +struct v4l2_subdev *sd, +struct v4l2_device *v4l2_dev, +const char *const name, +u32 function, +u16 num_pads, +const unsigned long *pads_flag, +const struct v4l2_subdev_ops *sd_ops, +void (*sd_destroy)(struct vimc_ent_device *)) +{ +int ret; + +/* Allocate the pads */ + ved->pads =vimc_pads_init (num_pads, pads_flag); +if (IS_ERR (ved->pads)) +return PTR_ERR (ved->pads); + +/* Fill the vimc_ent_device struct */ + ved->destroy = sd_destroy; + ved->ent = &sd->entity; + +/* Initialize the subdev */ +v4l2_subdev_init (sd, sd_ops); + sd->entity.function = function; + sd->entity.ops = &vimc_ent_sd_mops; + sd->owner =THIS_MODULE ; +strlcpy (sd->name, name,sizeof (sd->name)); +v4l2_set_subdevdata (sd, ved); + +/* Expose this subdev to user space */ + sd->flags =V4L2_SUBDEV_FL_HAS_DEVNODE ; + +/* Initialize the media entity */ + ret =media_entity_pads_init (&sd->entity, num_pads, ved->pads); +if (ret) + goto err_clean_pads; + +/* Register the subdev with the v4l2 and the media framework */ + ret =v4l2_device_register_subdev (v4l2_dev, sd); +if (ret) { +dev_err (v4l2_dev->dev, +"%s: subdev register failed (err=%d)\n" , + name, ret); + goto err_clean_m_ent; + } + +return 0 ; + +err_clean_m_ent: +media_entity_cleanup (&sd->entity); +err_clean_pads: +vimc_pads_cleanup (ved->pads); +return ret; +} + +void vimc_ent_sd_unregister (struct vimc_ent_device *ved,struct v4l2_subdev *sd) +{ +v4l2_device_unregister_subdev (sd); +media_entity_cleanup (ved->ent); +vimc_pads_cleanup (ved->pads); +}
drivers/media/platform/vimc/vimc-common.h +39 -0
@@ -110,4 +110,43 @@ const struct vimc_pix_map *vimc_pix_map_by_code(u32 code);*/ const struct vimc_pix_map *vimc_pix_map_by_pixelformat (u32 pixelformat); +/** +* vimc_ent_sd_register - initialize and register a subdev node +* +* @ved: the vimc_ent_device struct to be initialize +* @sd: the v4l2_subdev struct to be initialize and registered +* @v4l2_dev: the v4l2 device to register the v4l2_subdev +* @name: name of the sub-device. Please notice that the name must be +* unique. +* @function: media entity function defined by MEDIA_ENT_F_* macros +* @num_pads: number of pads to initialize +* @pads_flag: flags to use in each pad +* @sd_ops: pointer to &struct v4l2_subdev_ops. +* @sd_destroy: callback to destroy the node +* +* Helper function initialize and register the struct vimc_ent_device and struct +* v4l2_subdev which represents a subdev node in the topology +*/ +int vimc_ent_sd_register (struct vimc_ent_device *ved, +struct v4l2_subdev *sd, +struct v4l2_device *v4l2_dev, +const char *const name, +u32 function, +u16 num_pads, +const unsigned long *pads_flag, +const struct v4l2_subdev_ops *sd_ops, +void (*sd_destroy)(struct vimc_ent_device *)); + +/** +* vimc_ent_sd_register - initialize and register a subdev node +* +* @ved: the vimc_ent_device struct to be initialize +* @sd: the v4l2_subdev struct to be initialize and registered +* +* Helper function cleanup and unregister the struct vimc_ent_device and struct +* v4l2_subdev which represents a subdev node in the topology +*/ +void vimc_ent_sd_unregister (struct vimc_ent_device *ved, +struct v4l2_subdev *sd); +#endif
drivers/media/platform/vimc/vimc-sensor.c +9 -49
87 lines not on this page · raw message
Signature · 1 line
2.7.4
RFC PATCH v3 4/11 vimc: common: Add vimc_pipeline_s_stream helper
In reply to Helen KoikeMove the vimc_cap_pipeline_s_stream from the vimc-cap.c to vimc-common.c as this core will be reused by other subdevices to activate the stream in their directly connected nodes
---
Changes in v3:
[media] vimc: Add vimc_pipeline_s_stream in the core
- add it in vimc-common instead of vimc-core
- rename commit with "common" tag
Changes in v2:
[media] vimc: Add vimc_pipeline_s_stream in the core
- Use is_media_entity_v4l2_subdev instead of comparing with the old entity->type
- Fix comments style
- add kernel-docs
- call s_stream across all sink pads
--- drivers/media/platform/vimc/vimc-capture.c | 29 ++------------------------- drivers/media/platform/vimc/vimc-common.c | 32 ++++++++++++++++++++++++++++++ drivers/media/platform/vimc/vimc-common.h | 11 ++++++++++ 3 files changed, 45 insertions(+), 27 deletions(-)
drivers/media/platform/vimc/vimc-capture.c +2 -27
@@ -132,31 +132,6 @@ static void vimc_cap_return_all_buffers(struct vimc_cap_device *vcap,spin_unlock (&vcap->qlock); } -static int vimc_cap_pipeline_s_stream (struct vimc_cap_device *vcap,int enable) -{ -struct v4l2_subdev *sd; -struct media_pad *pad; -int ret; - -/* Start the stream in the subdevice direct connected */ - pad =media_entity_remote_pad (&vcap->vdev.entity.pads[0 ]); - -/* -* if it is a raw node from vimc-core, there is nothing to activate -* TODO: remove this when there are no more raw nodes in the -* core and return error instead -*/ -if (pad->entity->obj_type ==MEDIA_ENTITY_TYPE_BASE ) -return 0 ; - - sd =media_entity_to_v4l2_subdev (pad->entity); - ret =v4l2_subdev_call (sd, video, s_stream, enable); -if (ret && ret != -ENOIOCTLCMD ) -return ret; - -return 0 ; -} -static int vimc_cap_start_streaming (struct vb2_queue *vq,unsigned int count) {struct vimc_cap_device *vcap =vb2_get_drv_priv (vq);
@@ -173,7 +148,7 @@ static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count) }/* Enable streaming from the pipe */ - ret =vimc_cap_pipeline_s_stream (vcap,1 ); + ret =vimc_pipeline_s_stream (&vcap->vdev.entity,1 );if (ret) {media_pipeline_stop (entity);vimc_cap_return_all_buffers (vcap,VB2_BUF_STATE_QUEUED );
@@ -192,7 +167,7 @@ static void vimc_cap_stop_streaming(struct vb2_queue *vq)struct vimc_cap_device *vcap =vb2_get_drv_priv (vq);/* Disable streaming from the pipe */ -vimc_cap_pipeline_s_stream (vcap,0 ); +vimc_pipeline_s_stream (&vcap->vdev.entity,0 );/* Stop the media pipeline */ media_pipeline_stop (&vcap->vdev.entity);
drivers/media/platform/vimc/vimc-common.c +32 -0
@@ -220,6 +220,38 @@ struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag)return pads; } +int vimc_pipeline_s_stream (struct media_entity *ent,int enable) +{ +struct v4l2_subdev *sd; +struct media_pad *pad; +unsigned int i; +int ret; + +for (i =0 ; i < ent->num_pads; i++) { +if (ent->pads[i].flags &MEDIA_PAD_FL_SOURCE ) +continue ; + +/* Start the stream in the subdevice direct connected */ + pad =media_entity_remote_pad (&ent->pads[i]); + +/* +* if this is a raw node from vimc-core, then there is +* nothing to activate +* TODO: remove this when there are no more raw nodes in the +* core and return error instead +*/ +if (pad->entity->obj_type ==MEDIA_ENTITY_TYPE_BASE ) +continue ; + + sd =media_entity_to_v4l2_subdev (pad->entity); + ret =v4l2_subdev_call (sd, video, s_stream, enable); +if (ret && ret != -ENOIOCTLCMD ) +return ret; + } + +return 0 ; +} +static const struct media_entity_operations vimc_ent_sd_mops = { .link_validate = v4l2_subdev_link_validate, };
drivers/media/platform/vimc/vimc-common.h +11 -0
@@ -97,6 +97,17 @@ static inline void vimc_pads_cleanup(struct media_pad *pads) }/** +* vimc_pipeline_s_stream - start stream through the pipeline +* +* @ent: the pointer to struct media_entity for the node +* @enable: 1 to start the stream and 0 to stop +* +* Helper function to call the s_stream of the subdevices connected +* in all the sink pads of the entity +*/ +int vimc_pipeline_s_stream (struct media_entity *ent,int enable); + +/** * vimc_pix_map_by_code - get vimc_pix_map struct by media bus code * * @code: media bus format code defined by MEDIA_BUS_FMT_* macros
Signature · 1 line
2.7.4
RFC PATCH v3 5/11 vimc: common: Add vimc_link_validate
In reply to Helen KoikeAll links will be checked in the same way. Adding a helper function for that
---
Changes in v3:
[media] vimc: common: Add vimc_link_validate
- this is a new patch in the series
Changes in v2: None
--- drivers/media/platform/vimc/vimc-capture.c | 78 +++--------------- drivers/media/platform/vimc/vimc-common.c | 124 ++++++++++++++++++++++++++++- drivers/media/platform/vimc/vimc-common.h | 14 ++++ 3 files changed, 148 insertions(+), 68 deletions(-)
drivers/media/platform/vimc/vimc-capture.c +11 -67
@@ -64,6 +64,15 @@ static int vimc_cap_querycap(struct file *file, void *priv,return 0 ; } +static void vimc_cap_get_format (struct vimc_ent_device *ved, +struct v4l2_pix_format *fmt) +{ + struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, + ved); + + *fmt = vcap->format; +} +static int vimc_cap_fmt_vid_cap (struct file *file,void *priv,struct v4l2_format *f) {
@@ -231,74 +240,8 @@ static const struct vb2_ops vimc_cap_qops = { .wait_finish = vb2_ops_wait_finish, }; -/* -* NOTE: this function is a copy of v4l2_subdev_link_validate_get_format -* maybe the v4l2 function should be public -*/ -static int vimc_cap_v4l2_subdev_link_validate_get_format (struct media_pad *pad, -struct v4l2_subdev_format *fmt) -{ -struct v4l2_subdev *sd =media_entity_to_v4l2_subdev (pad->entity); - - fmt->which =V4L2_SUBDEV_FORMAT_ACTIVE ; - fmt->pad = pad->index; - -return v4l2_subdev_call (sd, pad, get_fmt,NULL , fmt); -} - -static int vimc_cap_link_validate (struct media_link *link) -{ -struct v4l2_subdev_format source_fmt; -const struct vimc_pix_map *vpix; -struct vimc_cap_device *vcap =container_of (link->sink->entity, - struct vimc_cap_device, - vdev.entity); -struct v4l2_pix_format *sink_fmt = &vcap->format; -int ret; - -/* -* if it is a raw node from vimc-core, ignore the link for now -* TODO: remove this when there are no more raw nodes in the -* core and return error instead -*/ -if (link->source->entity->obj_type ==MEDIA_ENTITY_TYPE_BASE ) -return 0 ; - -/* Get the the format of the subdev */ - ret =vimc_cap_v4l2_subdev_link_validate_get_format (link->source, - &source_fmt); -if (ret) -return ret; - -dev_dbg (vcap->vdev.v4l2_dev->dev, -"%s: link validate formats src:%dx%d %d sink:%dx%d %d\n" , - vcap->vdev.name, - source_fmt.format.width, source_fmt.format.height, - source_fmt.format.code, - sink_fmt->width, sink_fmt->height, - sink_fmt->pixelformat); - -/* The width, height and code must match. */ - vpix =vimc_pix_map_by_pixelformat (sink_fmt->pixelformat); -if (source_fmt.format.width != sink_fmt->width - || source_fmt.format.height != sink_fmt->height - || vpix->code != source_fmt.format.code) -return -EPIPE ; - -/* -* The field order must match, or the sink field order must be NONE -* to support interlaced hardware connected to bridges that support -* progressive formats only. -*/ -if (source_fmt.format.field != sink_fmt->field && - sink_fmt->field !=V4L2_FIELD_NONE ) -return -EPIPE ; - -return 0 ; -} -static const struct media_entity_operations vimc_cap_mops = { - .link_validate = vimc_cap_link_validate, + .link_validate = vimc_link_validate, };static void vimc_cap_destroy (struct vimc_ent_device *ved)
@@ -434,6 +377,7 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, vcap->ved.destroy = vimc_cap_destroy; vcap->ved.ent = &vcap->vdev.entity; vcap->ved.process_frame = vimc_cap_process_frame; + vcap->ved.vdev_get_format = vimc_cap_get_format;/* Initialize the video_device struct */ vdev = &vcap->vdev;
drivers/media/platform/vimc/vimc-common.c +123 -1
131 lines not on this page · raw message
drivers/media/platform/vimc/vimc-common.h +14 -0
@@ -45,6 +45,9 @@ struct vimc_pix_map {* @pads: the list of pads of the node * @destroy: callback to destroy the node * @process_frame: callback send a frame to that node +* @vdev_get_format: callback that returns the current format a pad, used +* only when is_media_entity_v4l2_video_device(ent) returns +* true * * Each node of the topology must create a vimc_ent_device struct. Depending on * the node it will be of an instance of v4l2_subdev or video_device struct
@@ -60,6 +63,8 @@ struct vimc_ent_device {void (*destroy)(struct vimc_ent_device *);void (*process_frame)(struct vimc_ent_device *ved,struct media_pad *sink,const void *frame); +void (*vdev_get_format)(struct vimc_ent_device *ved, +struct v4l2_pix_format *fmt); };/**
@@ -160,4 +165,13 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,void vimc_ent_sd_unregister (struct vimc_ent_device *ved,struct v4l2_subdev *sd); +/** +* vimc_link_validate - validates a media link +* +* @link: pointer to &struct media_link +* +* This function calls validates if a media link is valid for streaming. +*/ +int vimc_link_validate (struct media_link *link); +#endif
Signature · 1 line
2.7.4
Re: [RFC PATCH v3 05/11] [media] vimc: common: Add vimc_link_validate
Quoted 136 lines · Helen Koike
All links will be checked in the same way. Adding a helper function for that
Signed-off-by Helen Koike <[email protected]>---
Changes in v3:
[media] vimc: common: Addvimc_link_validate
- this is a new patch in the seriesChanges in v2: None
--- drivers/media/platform/vimc/vimc-capture.c | 78 +++--------------- drivers/media/platform/vimc/vimc-common.c | 124 ++++++++++++++++++++++++++++- drivers/media/platform/vimc/vimc-common.h | 14 ++++ 3 files changed, 148 insertions(+), 68 deletions(-)drivers/media/platform/vimc/vimc-capture.c +11
-67@@ -64,6 +64,15 @@ static int vimc_cap_querycap(struct file *file, void *priv,return 0 ; } +static void vimc_cap_get_format (struct vimc_ent_device *ved, +struct v4l2_pix_format *fmt) +{ + struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, + ved); + + *fmt = vcap->format; +} +static int vimc_cap_fmt_vid_cap (struct file *file,void *priv,struct v4l2_format *f) {@@ -231,74 +240,8 @@ static const struct vb2_ops vimc_cap_qops = { .wait_finish = vb2_ops_wait_finish, }; -/* -* NOTE: this function is a copy of v4l2_subdev_link_validate_get_format -* maybe the v4l2 function should be public -*/ -static int vimc_cap_v4l2_subdev_link_validate_get_format (struct media_pad *pad, -struct v4l2_subdev_format *fmt) -{ -struct v4l2_subdev *sd =media_entity_to_v4l2_subdev (pad->entity); - - fmt->which =V4L2_SUBDEV_FORMAT_ACTIVE ; - fmt->pad = pad->index; - -return v4l2_subdev_call (sd, pad, get_fmt,NULL , fmt); -} - -static int vimc_cap_link_validate (struct media_link *link) -{ -struct v4l2_subdev_format source_fmt; -const struct vimc_pix_map *vpix; -struct vimc_cap_device *vcap =container_of (link->sink->entity, - struct vimc_cap_device, - vdev.entity); -struct v4l2_pix_format *sink_fmt = &vcap->format; -int ret; - -/* -* if it is a raw node from vimc-core, ignore the link for now -* TODO: remove this when there are no more raw nodes in the -* core and return error instead -*/ -if (link->source->entity->obj_type ==MEDIA_ENTITY_TYPE_BASE ) -return 0 ; - -/* Get the the format of the subdev */ - ret =vimc_cap_v4l2_subdev_link_validate_get_format (link->source, - &source_fmt); -if (ret) -return ret; - -dev_dbg (vcap->vdev.v4l2_dev->dev, -"%s: link validate formats src:%dx%d %d sink:%dx%d %d\n" , - vcap->vdev.name, - source_fmt.format.width, source_fmt.format.height, - source_fmt.format.code, - sink_fmt->width, sink_fmt->height, - sink_fmt->pixelformat); - -/* The width, height and code must match. */ - vpix =vimc_pix_map_by_pixelformat (sink_fmt->pixelformat); -if (source_fmt.format.width != sink_fmt->width - || source_fmt.format.height != sink_fmt->height - || vpix->code != source_fmt.format.code) -return -EPIPE ; - -/* -* The field order must match, or the sink field order must be NONE -* to support interlaced hardware connected to bridges that support -* progressive formats only. -*/ -if (source_fmt.format.field != sink_fmt->field && - sink_fmt->field !=V4L2_FIELD_NONE ) -return -EPIPE ; - -return 0 ; -} -static const struct media_entity_operations vimc_cap_mops = { - .link_validate = vimc_cap_link_validate, + .link_validate = vimc_link_validate, };static void vimc_cap_destroy (struct vimc_ent_device *ved)@@ -434,6 +377,7 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, vcap->ved.destroy = vimc_cap_destroy; vcap->ved.ent = &vcap->vdev.entity; vcap->ved.process_frame = vimc_cap_process_frame; + vcap->ved.vdev_get_format = vimc_cap_get_format;/* Initialize the video_device struct */ vdev = &vcap->vdev;drivers/media/platform/vimc/vimc-common.c +4
-0@@ -252,8 +252,130 @@ int vimc_pipeline_s_stream(struct media_entity *ent, int enable)return 0 ; } +static void vimc_fmt_pix_to_mbus (struct v4l2_mbus_framefmt *mfmt, +struct v4l2_pix_format *pfmt) +{ + const struct vimc_pix_map *vpix =
drivers/media/platform/vimc/vimc-common.c int vimc_pipeline_s_stream(struct media_entity *ent, int enable) · line 268
Quoted 10 lines
drivers/media/platform/vimc/vimc-common.c +10
-0+vimc_pix_map_by_pixelformat (pfmt->pixelformat); + + mfmt->width = pfmt->width; + mfmt->height = pfmt->height; + mfmt->code = vpix->code; + mfmt->field = pfmt->field; + mfmt->colorspace = pfmt->colorspace; + mfmt->ycbcr_enc = pfmt->ycbcr_enc; + mfmt->quantization = pfmt->quantization; + mfmt->xfer_func = pfmt->xfer_func;
You can use v4l2_fill_mbus_format() here.
Quoted 68 lines
drivers/media/platform/vimc/vimc-common.c +68
-0+} + +static int vimc_get_mbus_format (struct media_pad *pad, +struct v4l2_subdev_format *fmt) +{ +if (is_media_entity_v4l2_subdev (pad->entity)) { +struct v4l2_subdev *sd = +media_entity_to_v4l2_subdev (pad->entity); +int ret; + + fmt->which =V4L2_SUBDEV_FORMAT_ACTIVE ; + fmt->pad = pad->index; + + ret =v4l2_subdev_call (sd, pad, get_fmt,NULL , fmt); +if (ret) +return ret; + + }else if (is_media_entity_v4l2_video_device (pad->entity)) { +struct video_device *vdev =container_of (pad->entity, + struct video_device, + entity); +struct vimc_ent_device *ved =video_get_drvdata (vdev); +struct v4l2_pix_format vdev_fmt; + +if (!ved->vdev_get_format) +return -ENOIOCTLCMD ; + + ved->vdev_get_format (ved, &vdev_fmt); +vimc_fmt_pix_to_mbus (&fmt->format, &vdev_fmt); + }else { +return -EINVAL ; + } + +return 0 ; +} + +int vimc_link_validate (struct media_link *link) +{ +struct v4l2_subdev_format source_fmt, sink_fmt; +int ret; + +/* +* if it is a raw node from vimc-core, ignore the link for now +* TODO: remove this when there are no more raw nodes in the +* core and return error instead +*/ +if (link->source->entity->obj_type ==MEDIA_ENTITY_TYPE_BASE ) +return 0 ; + + ret =vimc_get_mbus_format (link->source, &source_fmt); +if (ret) +return ret; + + ret =vimc_get_mbus_format (link->sink, &sink_fmt); +if (ret) +return ret; + + pr_info("vimc link validate: " + "%s:src:%dx%d (0x%x, %d, %d, %d, %d) " + "%s:snk:%dx%d (0x%x, %d, %d, %d, %d)\n", + /* src */ + link->source->entity->name, + source_fmt.format.width, source_fmt.format.height, + source_fmt.format.code, source_fmt.format.colorspace, + source_fmt.format.quantization, source_fmt.format.xfer_func, + source_fmt.format.ycbcr_enc, + /* sink */ + link->sink->entity->name,
drivers/media/platform/vimc/vimc-common.c int vimc_pipeline_s_stream(struct media_entity *ent, int enable) · line 346
Quoted 10 lines
drivers/media/platform/vimc/vimc-common.c +10
-0+ sink_fmt.format.width, sink_fmt.format.height, + sink_fmt.format.code, sink_fmt.format.colorspace, + sink_fmt.format.quantization, sink_fmt.format.xfer_func, + sink_fmt.format.ycbcr_enc); + +/* The width, height, code and colorspace must match. */ +if (source_fmt.format.width != sink_fmt.format.width + || source_fmt.format.height != sink_fmt.format.height + || source_fmt.format.code != sink_fmt.format.code + || source_fmt.format.colorspace != sink_fmt.format.colorspace)
Source and/or Sink may be COLORSPACE_DEFAULT. If that's the case, then you should skip comparing ycbcr_enc, quantization or xfer_func. If colorspace is DEFAULT, then that implies that the other fields are DEFAULT as well. Nothing else makes sense in that case.
Quoted 64 lines
drivers/media/platform/vimc/vimc-common.c +31
-1+return -EPIPE ; + +/* Colorimetry must match if they are not set to DEFAULT */ +if (source_fmt.format.ycbcr_enc !=V4L2_YCBCR_ENC_DEFAULT + && sink_fmt.format.ycbcr_enc !=V4L2_YCBCR_ENC_DEFAULT + && source_fmt.format.ycbcr_enc != sink_fmt.format.ycbcr_enc) +return -EPIPE ; + +if (source_fmt.format.quantization !=V4L2_QUANTIZATION_DEFAULT + && sink_fmt.format.quantization !=V4L2_QUANTIZATION_DEFAULT + && source_fmt.format.quantization != sink_fmt.format.quantization) +return -EPIPE ; + +if (source_fmt.format.xfer_func !=V4L2_XFER_FUNC_DEFAULT + && sink_fmt.format.xfer_func !=V4L2_XFER_FUNC_DEFAULT + && source_fmt.format.xfer_func != sink_fmt.format.xfer_func) +return -EPIPE ; + +/* The field order must match, or the sink field order must be NONE +* to support interlaced hardware connected to bridges that support +* progressive formats only. +*/ +if (source_fmt.format.field != sink_fmt.format.field && + sink_fmt.format.field !=V4L2_FIELD_NONE ) +return -EPIPE ; + +return 0 ; +} +EXPORT_SYMBOL (vimc_link_validate); +static const struct media_entity_operations vimc_ent_sd_mops = { - .link_validate = v4l2_subdev_link_validate, + .link_validate = vimc_link_validate, }; int vimc_ent_sd_register(struct vimc_ent_device *ved,drivers/media/platform/vimc/vimc-common.h +5
-0@@ -45,6 +45,9 @@ struct vimc_pix_map {* @pads: the list of pads of the node * @destroy: callback to destroy the node * @process_frame: callback send a frame to that node +* @vdev_get_format: callback that returns the current format a pad, used +* only when is_media_entity_v4l2_video_device(ent) returns +* true * * Each node of the topology must create a vimc_ent_device struct. Depending on * the node it will be of an instance of v4l2_subdev or video_device struct @@ -60,6 +63,8 @@ struct vimc_ent_device {void (*destroy)(struct vimc_ent_device *);void (*process_frame)(struct vimc_ent_device *ved,struct media_pad *sink,const void *frame); +void (*vdev_get_format)(struct vimc_ent_device *ved, +struct v4l2_pix_format *fmt); };/** @@ -160,4 +165,13 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,void vimc_ent_sd_unregister (struct vimc_ent_device *ved,struct v4l2_subdev *sd);
drivers/media/platform/vimc/vimc-common.h int vimc_ent_sd_register(struct vimc_ent_device *ved, · line 177
Quoted 10 lines
drivers/media/platform/vimc/vimc-common.h +9
-0+/** +* vimc_link_validate - validates a media link +* +* @link: pointer to &struct media_link +* +* This function calls validates if a media link is valid for streaming. +*/ +int vimc_link_validate (struct media_link *link); +#endif
Regards,
Hans
Re: [RFC PATCH v3 05/11] [media] vimc: common: Add vimc_link_validate
Hi Hans,
Thanks for your review, just a question below
Quoted 230 lines · Hans Verkuil
Quoted 139 lines · Helen Koike
All links will be checked in the same way. Adding a helper function for that
Signed-off-by Helen Koike <[email protected]>---
Changes in v3:
[media] vimc: common: Addvimc_link_validate
- this is a new patch in the seriesChanges in v2: None
--- drivers/media/platform/vimc/vimc-capture.c | 78 +++--------------- drivers/media/platform/vimc/vimc-common.c | 124 ++++++++++++++++++++++++++++- drivers/media/platform/vimc/vimc-common.h | 14 ++++ 3 files changed, 148 insertions(+), 68 deletions(-)drivers/media/platform/vimc/vimc-capture.c +10
-66@@ -64,6 +64,15 @@ static int vimc_cap_querycap(struct file *file,void *priv, return 0; } +static void vimc_cap_get_format(struct vimc_ent_device *ved, +struct v4l2_pix_format *fmt) +{ + struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, + ved); + + *fmt = vcap->format; +} +static int vimc_cap_fmt_vid_cap (struct file *file,void *priv,struct v4l2_format *f) {@@ -231,74 +240,8 @@ static const struct vb2_ops vimc_cap_qops = { .wait_finish = vb2_ops_wait_finish, }; -/* -* NOTE: this function is a copy of v4l2_subdev_link_validate_get_format -* maybe the v4l2 function should be public -*/ -static int vimc_cap_v4l2_subdev_link_validate_get_format(structmedia_pad *pad, -struct v4l2_subdev_format *fmt) -{ -struct v4l2_subdev *sd =media_entity_to_v4l2_subdev (pad->entity); - - fmt->which =V4L2_SUBDEV_FORMAT_ACTIVE ; - fmt->pad = pad->index; - -return v4l2_subdev_call (sd, pad, get_fmt,NULL , fmt); -} - -static int vimc_cap_link_validate (struct media_link *link) -{ -struct v4l2_subdev_format source_fmt; -const struct vimc_pix_map *vpix; -struct vimc_cap_device *vcap =container_of (link->sink->entity, - struct vimc_cap_device, - vdev.entity); -struct v4l2_pix_format *sink_fmt = &vcap->format; -int ret; - -/* -* if it is a raw node from vimc-core, ignore the link for now -* TODO: remove this when there are no more raw nodes in the -* core and return error instead -*/ -if (link->source->entity->obj_type ==MEDIA_ENTITY_TYPE_BASE ) -return 0 ; - -/* Get the the format of the subdev */ - ret =vimc_cap_v4l2_subdev_link_validate_get_format (link->source, - &source_fmt); -if (ret) -return ret; - -dev_dbg (vcap->vdev.v4l2_dev->dev, -"%s: link validate formats src:%dx%d %d sink:%dx%d %d\n" , - vcap->vdev.name, - source_fmt.format.width, source_fmt.format.height, - source_fmt.format.code, - sink_fmt->width, sink_fmt->height, - sink_fmt->pixelformat); - -/* The width, height and code must match. */ - vpix =vimc_pix_map_by_pixelformat (sink_fmt->pixelformat); -if (source_fmt.format.width != sink_fmt->width - || source_fmt.format.height != sink_fmt->height - || vpix->code != source_fmt.format.code) -return -EPIPE ; - -/* -* The field order must match, or the sink field order must be NONE -* to support interlaced hardware connected to bridges that support -* progressive formats only. -*/ -if (source_fmt.format.field != sink_fmt->field && - sink_fmt->field !=V4L2_FIELD_NONE ) -return -EPIPE ; - -return 0 ; -} -static const struct media_entity_operations vimc_cap_mops = { - .link_validate = vimc_cap_link_validate, +.link_validate = vimc_link_validate, }; static void vimc_cap_destroy(struct vimc_ent_device *ved) @@ -434,6 +377,7 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, vcap->ved.destroy = vimc_cap_destroy; vcap->ved.ent = &vcap->vdev.entity; vcap->ved.process_frame = vimc_cap_process_frame; + vcap->ved.vdev_get_format = vimc_cap_get_format;/* Initialize the video_device struct */ vdev = &vcap->vdev;drivers/media/platform/vimc/vimc-common.c +3
-0@@ -252,8 +252,130 @@ int vimc_pipeline_s_stream(struct media_entity *ent, int enable)return 0 ; } +static void vimc_fmt_pix_to_mbus(struct v4l2_mbus_framefmt *mfmt, +struct v4l2_pix_format *pfmt) +{ + const struct vimc_pix_map *vpix =drivers/media/platform/vimc/vimc-common.c int vimc_pipeline_s_stream(struct media_entity · line 268
Quoted 10 lines
drivers/media/platform/vimc/vimc-common.c +10
-0+vimc_pix_map_by_pixelformat (pfmt->pixelformat); + + mfmt->width = pfmt->width; + mfmt->height = pfmt->height; + mfmt->code = vpix->code; + mfmt->field = pfmt->field; + mfmt->colorspace = pfmt->colorspace; + mfmt->ycbcr_enc = pfmt->ycbcr_enc; + mfmt->quantization = pfmt->quantization; + mfmt->xfer_func = pfmt->xfer_func;You can use
v4l2_fill_mbus_format()here.Quoted 77 lines
drivers/media/platform/vimc/vimc-common.c +77
-0+} + +static int vimc_get_mbus_format (struct media_pad *pad, +struct v4l2_subdev_format *fmt) +{ +if (is_media_entity_v4l2_subdev (pad->entity)) { +struct v4l2_subdev *sd = +media_entity_to_v4l2_subdev (pad->entity); +int ret; + + fmt->which =V4L2_SUBDEV_FORMAT_ACTIVE ; + fmt->pad = pad->index; + + ret =v4l2_subdev_call (sd, pad, get_fmt,NULL , fmt); +if (ret) +return ret; + + }else if (is_media_entity_v4l2_video_device (pad->entity)) { +struct video_device *vdev =container_of (pad->entity, + struct video_device, + entity); +struct vimc_ent_device *ved =video_get_drvdata (vdev); +struct v4l2_pix_format vdev_fmt; + +if (!ved->vdev_get_format) +return -ENOIOCTLCMD ; + + ved->vdev_get_format (ved, &vdev_fmt); +vimc_fmt_pix_to_mbus (&fmt->format, &vdev_fmt); + }else { +return -EINVAL ; + } + +return 0 ; +} + +int vimc_link_validate (struct media_link *link) +{ +struct v4l2_subdev_format source_fmt, sink_fmt; +int ret; + +/* +* if it is a raw node from vimc-core, ignore the link for now +* TODO: remove this when there are no more raw nodes in the +* core and return error instead +*/ +if (link->source->entity->obj_type ==MEDIA_ENTITY_TYPE_BASE ) +return 0 ; + + ret =vimc_get_mbus_format (link->source, &source_fmt); +if (ret) +return ret; + + ret =vimc_get_mbus_format (link->sink, &sink_fmt); +if (ret) +return ret; + +pr_info ("vimc link validate: " +"%s:src:%dx%d (0x%x, %d, %d, %d, %d) " +"%s:snk:%dx%d (0x%x, %d, %d, %d, %d)\n" , +/* src */ + link->source->entity->name, + source_fmt.format.width, source_fmt.format.height, + source_fmt.format.code, source_fmt.format.colorspace, + source_fmt.format.quantization, source_fmt.format.xfer_func, + source_fmt.format.ycbcr_enc, +/* sink */ + link->sink->entity->name, + sink_fmt.format.width, sink_fmt.format.height, + sink_fmt.format.code, sink_fmt.format.colorspace, + sink_fmt.format.quantization, sink_fmt.format.xfer_func, + sink_fmt.format.ycbcr_enc); + +/* The width, height, code and colorspace must match. */ +if (source_fmt.format.width != sink_fmt.format.width + || source_fmt.format.height != sink_fmt.format.height + || source_fmt.format.code != sink_fmt.format.code
Quoted 8 lines
drivers/media/platform/vimc/vimc-common.c int vimc_pipeline_s_stream(struct media_entity *ent, int enable) · line 346
Quoted 1 line
drivers/media/platform/vimc/vimc-common.c +1
-0+ || source_fmt.format.colorspace != sink_fmt.format.colorspace)Source and/or Sink may be
COLORSPACE_DEFAULT. If that's the case, then you should skip comparingycbcr_enc, quantization orxfer_func. If colorspace
is DEFAULT, then that implies that the other fields are DEFAULT as well. Nothing
else makes sense in that case.
I thought that the colorspace couldn't be COLORSPACE_DEFAULT, in the documentation it is written "The default colorspace. This can be used by applications to let the driver fill in the colorspace.", so the colorspace is always set to something different from default no ? I thought that the COLORSPACE_DEFAULT was only used by the userspace in VIDIOC_{SUBDEV}_S_FMT so say "driver, use wherever colorspace you want", but if usespace calls VIDIOC_{SUBDEV}_G_FMT, it would return which exact colorspace the driver is using, no?
Quoted 81 lines
Quoted 68 lines
drivers/media/platform/vimc/vimc-common.c +31
-1+return -EPIPE ; + +/* Colorimetry must match if they are not set to DEFAULT */ +if (source_fmt.format.ycbcr_enc !=V4L2_YCBCR_ENC_DEFAULT + && sink_fmt.format.ycbcr_enc !=V4L2_YCBCR_ENC_DEFAULT + && source_fmt.format.ycbcr_enc != sink_fmt.format.ycbcr_enc) +return -EPIPE ; + +if (source_fmt.format.quantization !=V4L2_QUANTIZATION_DEFAULT + && sink_fmt.format.quantization !=V4L2_QUANTIZATION_DEFAULT + && source_fmt.format.quantization != sink_fmt.format.quantization) +return -EPIPE ; + +if (source_fmt.format.xfer_func !=V4L2_XFER_FUNC_DEFAULT + && sink_fmt.format.xfer_func !=V4L2_XFER_FUNC_DEFAULT + && source_fmt.format.xfer_func != sink_fmt.format.xfer_func) +return -EPIPE ; + +/* The field order must match, or the sink field order must be NONE +* to support interlaced hardware connected to bridges that support +* progressive formats only. +*/ +if (source_fmt.format.field != sink_fmt.format.field && + sink_fmt.format.field !=V4L2_FIELD_NONE ) +return -EPIPE ; + +return 0 ; +} +EXPORT_SYMBOL (vimc_link_validate); +static const struct media_entity_operations vimc_ent_sd_mops = { - .link_validate = v4l2_subdev_link_validate, + .link_validate = vimc_link_validate, }; int vimc_ent_sd_register(struct vimc_ent_device *ved,drivers/media/platform/vimc/vimc-common.h +1
-0@@ -45,6 +45,9 @@ struct vimc_pix_map {* @pads: the list of pads of the node * @destroy: callback to destroy the node * @process_frame: callback send a frame to that node +* @vdev_get_format: callback that returns the current format a pad, used
+ * only whenis_media_entity_v4l2_video_device(ent)returns
+ * true
*
* Each node of the topology must create avimc_ent_devicestruct.
Depending on
* the node it will be of an instance ofv4l2_subdevorvideo_device
structdrivers/media/platform/vimc/vimc-common.h +2
-0@@ -60,6 +63,8 @@ struct vimc_ent_device {void (*destroy)(struct vimc_ent_device *);void (*process_frame)(struct vimc_ent_device *ved,struct media_pad *sink,const void *frame); +void (*vdev_get_format)(struct vimc_ent_device *ved, +struct v4l2_pix_format *fmt); };/** @@ -160,4 +165,13 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,void vimc_ent_sd_unregister (struct vimc_ent_device *ved,struct v4l2_subdev *sd);drivers/media/platform/vimc/vimc-common.h int vimc_ent_sd_register(struct vimc_ent_device · line 177
Quoted 10 lines
drivers/media/platform/vimc/vimc-common.h +8
-0+/** +* vimc_link_validate - validates a media link +* +* @link: pointer to &struct media_link +* +* This function calls validates if a media link is valid for streaming. +*/ +int vimc_link_validate(struct media_link *link); +#endif Regards,
Quoted 1 line
Hans
Thanks,
Helen
Re: [RFC PATCH v3 05/11] [media] vimc: common: Add vimc_link_validate
Quoted 19 lines · Helen Koike
Hi Hans,
Thanks for your review, just a question below
Quoted 7 lines · Hans Verkuil
drivers/media/platform/vimc/vimc-common.c int vimc_pipeline_s_stream(struct media_entity *ent, int enable) · line 346
Quoted 5 lines · Helen Koike
drivers/media/platform/vimc/vimc-common.c +5
-0+/* The width, height, code and colorspace must match. */ +if (source_fmt.format.width != sink_fmt.format.width + || source_fmt.format.height != sink_fmt.format.height + || source_fmt.format.code != sink_fmt.format.code + || source_fmt.format.colorspace != sink_fmt.format.colorspace)Quoted 6 lines
Source and/or Sink may be
COLORSPACE_DEFAULT. If that's the case, then you should skip comparingycbcr_enc, quantization orxfer_func. If colorspace
is DEFAULT, then that implies that the other fields are DEFAULT as well. Nothing
else makes sense in that case.
Quoted 8 lines
I thought that the colorspace couldn't be
COLORSPACE_DEFAULT, in the documentation it is written "The default colorspace. This can be used by applications to let the driver fill in the colorspace.", so the colorspace is always set to something different from default no ? I thought that theCOLORSPACE_DEFAULTwas only used by the userspace in VIDIOC_{SUBDEV}_S_FMT so say "driver, use wherever colorspace you want", but if usespace calls VIDIOC_{SUBDEV}_G_FMT, it would return which exact colorspace the driver is using, no?
I don't think this rule works for the MC. For regular v4l2 devices the bridge driver knows what colorspace it receives so it can replace the colorspace DEFAULT with the real one.
But a e.g. scaler subdev does not actually touch on the colorspace. And it doesn't know what colorspace it will receive or transmit.
I don't feel it makes sense to require userspace to set and propagate the colorspace information throughout the pipeline. Allowing it to be set to DEFAULT (i.e. 'don't care') makes sense to me.
I might change my mind later on this. The simple fact is that the spec isn't clear what to do with MC devices. That's also where this vimc driver comes in, so we can try this out without requiring specialized hardware.
Regards,
Hans
RFC PATCH v3 6/11 vimc: sen: Support several image formats
In reply to Helen KoikeAllow user space to change the image format as the frame size, the media bus pixel format, colorspace, quantization, field YCbCr encoding and the transfer function
---
Changes in v3:
[media] vimc: sen: Support several image formats
- remove support for V4L2_FIELD_ALTERNATE (left as TODO for now)
- clamp image size to an even dimension for height and width
- set default values for colorimetry using _DEFAULT macro
- reset all values of colorimetry to _DEFAULT if user tries to set an invalid colorspace
Changes in v2:
[media] vimc: sen: Support several image formats
- this is a new commit in the serie (the old one was splitted in two)
- add init_cfg to initialize try_fmt
- reorder code in vimc_sen_set_fmt
- allow user space to change all fields from struct v4l2_mbus_framefmt
(e.g. colospace, quantization, field, xfer_func, ycbcr_enc)
- merge with patch for the enum_mbus_code and enum_frame_size
- change commit message
- add vimc_pix_map_by_index
- rename MIN/MAX macros
- check set_fmt default parameters for quantization, colorspace ...media] vimc: sen: Support several image formats
--- drivers/media/platform/vimc/vimc-common.c | 8 ++ drivers/media/platform/vimc/vimc-common.h | 12 +++ drivers/media/platform/vimc/vimc-sensor.c | 145 ++++++++++++++++++++++++------ 3 files changed, 136 insertions(+), 29 deletions(-)
drivers/media/platform/vimc/vimc-common.c +8 -0
@@ -144,6 +144,14 @@ static const struct vimc_pix_map vimc_pix_map_list[] = { }, }; +const struct vimc_pix_map *vimc_pix_map_by_index (unsigned int i) +{ +if (i >=ARRAY_SIZE (vimc_pix_map_list)) +return NULL ; + +return &vimc_pix_map_list[i]; +} +const struct vimc_pix_map *vimc_pix_map_by_code (u32 code) {unsigned int i;
drivers/media/platform/vimc/vimc-common.h +12 -0
@@ -22,6 +22,11 @@#include <media/media-device.h> #include <media/v4l2-device.h> +#define VIMC_FRAME_MAX_WIDTH 4096 +#define VIMC_FRAME_MAX_HEIGHT 2160 +#define VIMC_FRAME_MIN_WIDTH 16 +#define VIMC_FRAME_MIN_HEIGHT 16 +/** * struct vimc_pix_map - maps media bus code with v4l2 pixel format *
@@ -113,6 +118,13 @@ static inline void vimc_pads_cleanup(struct media_pad *pads)int vimc_pipeline_s_stream (struct media_entity *ent,int enable);/** +* vimc_pix_map_by_index - get vimc_pix_map struct by its index +* +* @i: index of the vimc_pix_map struct in vimc_pix_map_list +*/ +const struct vimc_pix_map *vimc_pix_map_by_index (unsigned int i); + +/** * vimc_pix_map_by_code - get vimc_pix_map struct by media bus code * * @code: media bus format code defined by MEDIA_BUS_FMT_* macros
drivers/media/platform/vimc/vimc-sensor.c +116 -29
206 lines not on this page · raw message
Signature · 1 line
2.7.4
RFC PATCH v3 7/11 vimc: cap: Support several image formats
In reply to Helen KoikeAllow user space to change the image format as the frame size, the pixel format, colorspace, quantization, field YCbCr encoding and the transfer function
---
Changes in v3:
[media] vimc: cap: Support several image formats
- use *_DEFAULT macros for colorimetry in the default format
- clamp height and width of the image by an even value
- is user try to set colorspace to an invalid format, set all colorimetry parameters to _DEFAULT
- remove V4L2_FMT_FLAG_COMPRESSED from vimc_cap_enum_fmt_vid_cap
- remove V4L2_BUF_TYPE_VIDEO_CAPTURE from vimc_cap_enum_fmt_vid_cap
- increase step_width and step_height to 2 instead of 1
- remove link validate function, use the one in vimc-common.c
Changes in v2:
[media] vimc: cap: Support several image formats
- this is a new commit in the serie (the old one was splitted in two)
- allow user space to change all fields from struct v4l2_pix_format
(e.g. colospace, quantization, field, xfer_func, ycbcr_enc)
- link_validate and try_fmt: also checks colospace, quantization, field, xfer_func, ycbcr_enc
- add struct v4l2_pix_format fmt_default
- add enum_framesizes
- enum_fmt_vid_cap: enumerate all formats from vimc_pix_map_table
- add mode dev_dbg
--- drivers/media/platform/vimc/vimc-capture.c | 131 +++++++++++++++++++++++++---- 1 file changed, 115 insertions(+), 16 deletions(-)
drivers/media/platform/vimc/vimc-capture.c +115 -16
@@ -40,6 +40,14 @@ struct vimc_cap_device {struct media_pipeline pipe; }; +static const struct v4l2_pix_format fmt_default = { + .width =640 , + .height =480 , + .pixelformat =V4L2_PIX_FMT_RGB24 , + .field =V4L2_FIELD_NONE , + .colorspace =V4L2_COLORSPACE_SRGB , +}; +struct vimc_cap_buffer {/* * struct vb2_v4l2_buffer must be the first element
@@ -73,7 +81,7 @@ static void vimc_cap_get_format(struct vimc_ent_device *ved, *fmt = vcap->format; } -static int vimc_cap_fmt_vid_cap (struct file *file,void *priv, +static int vimc_cap_g_fmt_vid_cap (struct file *file,void *priv,struct v4l2_format *f) {struct vimc_cap_device *vcap =video_drvdata (file);
@@ -83,16 +91,112 @@ static int vimc_cap_fmt_vid_cap(struct file *file, void *priv,return 0 ; } +static int vimc_cap_try_fmt_vid_cap (struct file *file,void *priv, +struct v4l2_format *f) +{ +struct v4l2_pix_format *format = &f->fmt.pix; +const struct vimc_pix_map *vpix; + + format->width =clamp_t (u32, format->width,VIMC_FRAME_MIN_WIDTH , +VIMC_FRAME_MAX_WIDTH ) & ~1 ; + format->height =clamp_t (u32, format->height,VIMC_FRAME_MIN_HEIGHT , +VIMC_FRAME_MAX_HEIGHT ) & ~1 ; + +/* Don't accept a pixelformat that is not on the table */ + vpix =vimc_pix_map_by_pixelformat (format->pixelformat); +if (!vpix) { + format->pixelformat = fmt_default.pixelformat; + vpix =vimc_pix_map_by_pixelformat (format->pixelformat); + } +/* TODO: Add support for custom bytesperline values */ + format->bytesperline = format->width * vpix->bpp; + format->sizeimage = format->bytesperline * format->height; + +if (format->field ==V4L2_FIELD_ANY ) + format->field = fmt_default.field; + +if (format->colorspace ==V4L2_COLORSPACE_DEFAULT ) + format->colorspace = fmt_default.colorspace; + +/* Check if values are out of range */ +if (format->colorspace >V4L2_COLORSPACE_DCI_P3 ) { + format->colorspace = fmt_default.colorspace; + format->ycbcr_enc =V4L2_YCBCR_ENC_DEFAULT ; + format->quantization =V4L2_QUANTIZATION_DEFAULT ; + format->xfer_func =V4L2_XFER_FUNC_DEFAULT ; + } +if (format->ycbcr_enc >V4L2_YCBCR_ENC_SMPTE240M ) + format->ycbcr_enc =V4L2_YCBCR_ENC_DEFAULT ; +if (format->quantization >V4L2_QUANTIZATION_LIM_RANGE ) + format->quantization =V4L2_QUANTIZATION_DEFAULT ; +if (format->xfer_func >V4L2_XFER_FUNC_SMPTE2084 ) + format->xfer_func =V4L2_XFER_FUNC_DEFAULT ; +return 0 ; +} + +static int vimc_cap_s_fmt_vid_cap (struct file *file,void *priv, +struct v4l2_format *f) +{ +struct vimc_cap_device *vcap =video_drvdata (file); + +/* Do not change the format while stream is on */ +if (vb2_is_busy (&vcap->queue)) +return -EBUSY ; + +vimc_cap_try_fmt_vid_cap (file, priv, f); + +dev_dbg (vcap->vdev.v4l2_dev->dev,"%s: format update: " +"old:%dx%d (0x%x, %d, %d, %d, %d) " +"new:%dx%d (0x%x, %d, %d, %d, %d)\n" , vcap->vdev.name, +/* old */ + vcap->format.width, vcap->format.height, + vcap->format.pixelformat, vcap->format.colorspace, + vcap->format.quantization, vcap->format.xfer_func, + vcap->format.ycbcr_enc, +/* new */ + f->fmt.pix.width, f->fmt.pix.height, + f->fmt.pix.pixelformat, f->fmt.pix.colorspace, + f->fmt.pix.quantization, f->fmt.pix.xfer_func, + f->fmt.pix.ycbcr_enc); + + vcap->format = f->fmt.pix; + +return 0 ; +} +static int vimc_cap_enum_fmt_vid_cap (struct file *file,void *priv,struct v4l2_fmtdesc *f) { -struct vimc_cap_device *vcap =video_drvdata (file); +const struct vimc_pix_map *vpix =vimc_pix_map_by_index (f->index); + +if (!vpix) +return -EINVAL ; + + f->pixelformat = vpix->pixelformat; + +return 0 ; +} + +static int vimc_cap_enum_framesizes (struct file *file,void *fh, +struct v4l2_frmsizeenum *fsize) +{ +const struct vimc_pix_map *vpix; -if (f->index >0 ) +if (fsize->index)return -EINVAL ; -/* We only support one format for now */ - f->pixelformat = vcap->format.pixelformat; +/* Only accept code in the pix map table */ + vpix =vimc_pix_map_by_code (fsize->pixel_format); +if (!vpix) +return -EINVAL ; + + fsize->type =V4L2_FRMSIZE_TYPE_CONTINUOUS ; + fsize->stepwise.min_width =VIMC_FRAME_MIN_WIDTH ; + fsize->stepwise.max_width =VIMC_FRAME_MAX_WIDTH ; + fsize->stepwise.min_height =VIMC_FRAME_MIN_HEIGHT ; + fsize->stepwise.max_height =VIMC_FRAME_MAX_HEIGHT ; + fsize->stepwise.step_width =2 ; + fsize->stepwise.step_height =2 ;return 0 ; }
@@ -110,10 +214,11 @@ static const struct v4l2_file_operations vimc_cap_fops = {static const struct v4l2_ioctl_ops vimc_cap_ioctl_ops = { .vidioc_querycap = vimc_cap_querycap, - .vidioc_g_fmt_vid_cap = vimc_cap_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vimc_cap_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vimc_cap_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vimc_cap_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vimc_cap_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vimc_cap_try_fmt_vid_cap, .vidioc_enum_fmt_vid_cap = vimc_cap_enum_fmt_vid_cap, + .vidioc_enum_framesizes = vimc_cap_enum_framesizes, .vidioc_reqbufs = vb2_ioctl_reqbufs, .vidioc_create_bufs = vb2_ioctl_create_bufs,
@@ -360,15 +465,9 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev,INIT_LIST_HEAD (&vcap->buf_list);spin_lock_init (&vcap->qlock); -/* Set the frame format (this is hardcoded for now) */ - vcap->format.width =640 ; - vcap->format.height =480 ; - vcap->format.pixelformat =V4L2_PIX_FMT_RGB24 ; - vcap->format.field =V4L2_FIELD_NONE ; - vcap->format.colorspace =V4L2_COLORSPACE_SRGB ; - +/* Set default frame format */ + vcap->format = fmt_default; vpix =vimc_pix_map_by_pixelformat (vcap->format.pixelformat); - vcap->format.bytesperline = vcap->format.width * vpix->bpp; vcap->format.sizeimage = vcap->format.bytesperline * vcap->format.height;
Signature · 1 line
2.7.4
Re: [RFC PATCH v3 07/11] [media] vimc: cap: Support several image formats
Quoted 97 lines · Helen Koike
Allow user space to change the image format as the frame size, the pixel format, colorspace, quantization, field YCbCr encoding and the transfer function
Signed-off-by Helen Koike <[email protected]>---
Changes in v3:
[media] vimc: cap: Support several image formats
- use*_DEFAULTmacros for colorimetry in the default format
- clamp height and width of the image by an even value
- is user try to set colorspace to an invalid format, set all colorimetry parameters to_DEFAULT
- removeV4L2_FMT_FLAG_COMPRESSEDfromvimc_cap_enum_fmt_vid_cap
- removeV4L2_BUF_TYPE_VIDEO_CAPTUREfromvimc_cap_enum_fmt_vid_cap
- increasestep_widthandstep_heightto 2 instead of 1
- remove link validate function, use the one invimc-common.cChanges in v2:
[media] vimc: cap: Support several image formats
- this is a new commit in the serie (the old one was splitted in two)
- allow user space to change all fields from structv4l2_pix_format
(e.g. colospace, quantization, field,xfer_func,ycbcr_enc)
-link_validateandtry_fmt: also checks colospace, quantization, field,xfer_func,ycbcr_enc
- add structv4l2_pix_formatfmt_default
- addenum_framesizes
-enum_fmt_vid_cap: enumerate all formats fromvimc_pix_map_table
- add modedev_dbg--- drivers/media/platform/vimc/vimc-capture.c | 131 +++++++++++++++++++++++++---- 1 file changed, 115 insertions(+), 16 deletions(-)drivers/media/platform/vimc/vimc-capture.c +39
-1@@ -40,6 +40,14 @@ struct vimc_cap_device {struct media_pipeline pipe; }; +static const struct v4l2_pix_format fmt_default = { + .width =640 , + .height =480 , + .pixelformat =V4L2_PIX_FMT_RGB24 , + .field =V4L2_FIELD_NONE , + .colorspace =V4L2_COLORSPACE_SRGB , +}; +struct vimc_cap_buffer {/* * struct vb2_v4l2_buffer must be the first element @@ -73,7 +81,7 @@ static void vimc_cap_get_format(struct vimc_ent_device *ved, *fmt = vcap->format; } -static int vimc_cap_fmt_vid_cap (struct file *file,void *priv, +static int vimc_cap_g_fmt_vid_cap (struct file *file,void *priv,struct v4l2_format *f) {struct vimc_cap_device *vcap =video_drvdata (file);@@ -83,16 +91,112 @@ static int vimc_cap_fmt_vid_cap(struct file *file, void *priv,return 0 ; } +static int vimc_cap_try_fmt_vid_cap (struct file *file,void *priv, +struct v4l2_format *f) +{ +struct v4l2_pix_format *format = &f->fmt.pix; +const struct vimc_pix_map *vpix; + + format->width =clamp_t (u32, format->width,VIMC_FRAME_MIN_WIDTH , +VIMC_FRAME_MAX_WIDTH ) & ~1 ; + format->height =clamp_t (u32, format->height,VIMC_FRAME_MIN_HEIGHT , +VIMC_FRAME_MAX_HEIGHT ) & ~1 ; + +/* Don't accept a pixelformat that is not on the table */ + vpix =vimc_pix_map_by_pixelformat (format->pixelformat); +if (!vpix) { + format->pixelformat = fmt_default.pixelformat; + vpix =vimc_pix_map_by_pixelformat (format->pixelformat); + } +/* TODO: Add support for custom bytesperline values */ + format->bytesperline = format->width * vpix->bpp; + format->sizeimage = format->bytesperline * format->height; + +if (format->field ==V4L2_FIELD_ANY ) + format->field = fmt_default.field; + +if (format->colorspace ==V4L2_COLORSPACE_DEFAULT ) + format->colorspace = fmt_default.colorspace; + +/* Check if values are out of range */ +if (format->colorspace >V4L2_COLORSPACE_DCI_P3 ) { + format->colorspace = fmt_default.colorspace;
drivers/media/platform/vimc/vimc-capture.c static int vimc_cap_fmt_vid_cap(struct file *file, void *priv, · line 133
Quoted 10 lines
drivers/media/platform/vimc/vimc-capture.c +10
-0+ format->ycbcr_enc =V4L2_YCBCR_ENC_DEFAULT ; + format->quantization =V4L2_QUANTIZATION_DEFAULT ; + format->xfer_func =V4L2_XFER_FUNC_DEFAULT ; + } +if (format->ycbcr_enc >V4L2_YCBCR_ENC_SMPTE240M ) + format->ycbcr_enc =V4L2_YCBCR_ENC_DEFAULT ; +if (format->quantization >V4L2_QUANTIZATION_LIM_RANGE ) + format->quantization =V4L2_QUANTIZATION_DEFAULT ; +if (format->xfer_func >V4L2_XFER_FUNC_SMPTE2084 ) + format->xfer_func =V4L2_XFER_FUNC_DEFAULT ;
You might want to move this to common, since the sensor has the same code.
Quoted 97 lines
drivers/media/platform/vimc/vimc-capture.c +64
-11+return 0 ; +} + +static int vimc_cap_s_fmt_vid_cap (struct file *file,void *priv, +struct v4l2_format *f) +{ +struct vimc_cap_device *vcap =video_drvdata (file); + +/* Do not change the format while stream is on */ +if (vb2_is_busy (&vcap->queue)) +return -EBUSY ; + +vimc_cap_try_fmt_vid_cap (file, priv, f); + +dev_dbg (vcap->vdev.v4l2_dev->dev,"%s: format update: " +"old:%dx%d (0x%x, %d, %d, %d, %d) " +"new:%dx%d (0x%x, %d, %d, %d, %d)\n" , vcap->vdev.name, +/* old */ + vcap->format.width, vcap->format.height, + vcap->format.pixelformat, vcap->format.colorspace, + vcap->format.quantization, vcap->format.xfer_func, + vcap->format.ycbcr_enc, +/* new */ + f->fmt.pix.width, f->fmt.pix.height, + f->fmt.pix.pixelformat, f->fmt.pix.colorspace, + f->fmt.pix.quantization, f->fmt.pix.xfer_func, + f->fmt.pix.ycbcr_enc); + + vcap->format = f->fmt.pix; + +return 0 ; +} +static int vimc_cap_enum_fmt_vid_cap (struct file *file,void *priv,struct v4l2_fmtdesc *f) { -struct vimc_cap_device *vcap =video_drvdata (file); +const struct vimc_pix_map *vpix =vimc_pix_map_by_index (f->index); + +if (!vpix) +return -EINVAL ; + + f->pixelformat = vpix->pixelformat; + +return 0 ; +} + +static int vimc_cap_enum_framesizes (struct file *file,void *fh, +struct v4l2_frmsizeenum *fsize) +{ +const struct vimc_pix_map *vpix; -if (f->index >0 ) +if (fsize->index)return -EINVAL ; -/* We only support one format for now */ - f->pixelformat = vcap->format.pixelformat; +/* Only accept code in the pix map table */ + vpix =vimc_pix_map_by_code (fsize->pixel_format); +if (!vpix) +return -EINVAL ; + + fsize->type =V4L2_FRMSIZE_TYPE_CONTINUOUS ; + fsize->stepwise.min_width =VIMC_FRAME_MIN_WIDTH ; + fsize->stepwise.max_width =VIMC_FRAME_MAX_WIDTH ; + fsize->stepwise.min_height =VIMC_FRAME_MIN_HEIGHT ; + fsize->stepwise.max_height =VIMC_FRAME_MAX_HEIGHT ; + fsize->stepwise.step_width =2 ; + fsize->stepwise.step_height =2 ;return 0 ; }@@ -110,10 +214,11 @@ static const struct v4l2_file_operations vimc_cap_fops = {static const struct v4l2_ioctl_ops vimc_cap_ioctl_ops = { .vidioc_querycap = vimc_cap_querycap, - .vidioc_g_fmt_vid_cap = vimc_cap_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vimc_cap_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vimc_cap_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vimc_cap_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vimc_cap_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vimc_cap_try_fmt_vid_cap, .vidioc_enum_fmt_vid_cap = vimc_cap_enum_fmt_vid_cap, + .vidioc_enum_framesizes = vimc_cap_enum_framesizes, .vidioc_reqbufs = vb2_ioctl_reqbufs, .vidioc_create_bufs = vb2_ioctl_create_bufs,@@ -360,15 +465,9 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev,INIT_LIST_HEAD (&vcap->buf_list);spin_lock_init (&vcap->qlock); -/* Set the frame format (this is hardcoded for now) */ - vcap->format.width =640 ; - vcap->format.height =480 ; - vcap->format.pixelformat =V4L2_PIX_FMT_RGB24 ;
drivers/media/platform/vimc/vimc-capture.c struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, · line 473
Quoted 10 lines
drivers/media/platform/vimc/vimc-capture.c +2
-4- vcap->format.field =V4L2_FIELD_NONE ; - vcap->format.colorspace =V4L2_COLORSPACE_SRGB ; - +/* Set default frame format */ + vcap->format = fmt_default; vpix =vimc_pix_map_by_pixelformat (vcap->format.pixelformat); - vcap->format.bytesperline = vcap->format.width * vpix->bpp; vcap->format.sizeimage = vcap->format.bytesperline * vcap->format.height;
Regards,
Hans
RFC PATCH v3 8/11 vimc: Optimize frame generation through the pipe
In reply to Helen KoikeAdd a parameter called vsen_tpg, if true then vimc will work as before:
frames will be generated in the sensor nodes then propagated through the pipe and processed by each node until a capture node is reached. If vsen_tpg is false, then the frame is not generated by the sensor, but directly from the capture node, thus saving intermediate memory buffers and process time, allowing a higher frame rate.
---
Changes in v3:
[media] vimc: Optimize frame generation through the pipe
- This is a new patch in the series
Changes in v2: None
--- drivers/media/platform/vimc/vimc-capture.c | 178 +++++++++++++++++++++-------- drivers/media/platform/vimc/vimc-common.h | 2 + drivers/media/platform/vimc/vimc-sensor.c | 30 ++++- 3 files changed, 156 insertions(+), 54 deletions(-)
drivers/media/platform/vimc/vimc-capture.c +130 -48
@@ -15,7 +15,10 @@* */ +#include <linux/freezer.h> +#include <linux/kthread.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-tpg.h> #include <media/videobuf2-core.h> #include <media/videobuf2-vmalloc.h>
@@ -38,6 +41,8 @@ struct vimc_cap_device {struct mutex lock;u32 sequence;struct media_pipeline pipe; +struct tpg_data tpg; +struct task_struct *kthread_cap; };static const struct v4l2_pix_format fmt_default = {
@@ -246,6 +251,91 @@ static void vimc_cap_return_all_buffers(struct vimc_cap_device *vcap,spin_unlock (&vcap->qlock); } +static void vimc_cap_process_frame (struct vimc_ent_device *ved, +struct media_pad *sink,const void *frame) +{ + struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, + ved); +struct vimc_cap_buffer *vimc_buf; +void *vbuf; + +spin_lock (&vcap->qlock); + +/* Get the first entry of the list */ + vimc_buf =list_first_entry_or_null (&vcap->buf_list, +typeof (*vimc_buf), list); +if (!vimc_buf) { +spin_unlock (&vcap->qlock); +return ; + } + +/* Remove this entry from the list */ +list_del (&vimc_buf->list); + +spin_unlock (&vcap->qlock); + +/* Fill the buffer */ + vimc_buf->vb2.vb2_buf.timestamp =ktime_get_ns (); + vimc_buf->vb2.sequence = vcap->sequence++; + vimc_buf->vb2.field = vcap->format.field; + + vbuf =vb2_plane_vaddr (&vimc_buf->vb2.vb2_buf,0 ); + +if (sink) +memcpy (vbuf, frame, vcap->format.sizeimage); +else +tpg_fill_plane_buffer (&vcap->tpg,V4L2_STD_PAL ,0 , vbuf); + +/* Set it as ready */ +vb2_set_plane_payload (&vimc_buf->vb2.vb2_buf,0 , + vcap->format.sizeimage); +vb2_buffer_done (&vimc_buf->vb2.vb2_buf,VB2_BUF_STATE_DONE ); +} + + +static int vimc_cap_tpg_thread (void *data) +{ +struct vimc_cap_device *vcap = data; + +set_freezable (); +set_current_state (TASK_UNINTERRUPTIBLE ); + +for (;;) { +try_to_freeze (); +if (kthread_should_stop ()) +break ; + +vimc_cap_process_frame (&vcap->ved,NULL ,NULL ); + +/* 60 frames per second */ +schedule_timeout (HZ /60 ); + } + +return 0 ; +} + +static void vimc_cap_tpg_s_format (struct vimc_cap_device *vcap) +{ +const struct vimc_pix_map *vpix = +vimc_pix_map_by_pixelformat (vcap->format.pixelformat); + +tpg_reset_source (&vcap->tpg, vcap->format.width, vcap->format.height, + vcap->format.field); +tpg_s_bytesperline (&vcap->tpg,0 , vcap->format.width * vpix->bpp); +tpg_s_buf_height (&vcap->tpg, vcap->format.height); +tpg_s_fourcc (&vcap->tpg, vpix->pixelformat); +/* +* TODO: check why the tpg_s_field need this third argument if +* it is already receiving the field +*/ +tpg_s_field (&vcap->tpg, vcap->format.field, + vcap->format.field ==V4L2_FIELD_ALTERNATE ); +tpg_s_colorspace (&vcap->tpg, vcap->format.colorspace); +tpg_s_ycbcr_enc (&vcap->tpg, vcap->format.ycbcr_enc); +tpg_s_quantization (&vcap->tpg, vcap->format.quantization); +tpg_s_xfer_func (&vcap->tpg, vcap->format.xfer_func); +} +static int vimc_cap_start_streaming (struct vb2_queue *vq,unsigned int count) {struct vimc_cap_device *vcap =vb2_get_drv_priv (vq);
@@ -256,20 +346,43 @@ static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count)/* Start the media pipeline */ ret =media_pipeline_start (entity, &vcap->pipe); -if (ret) { -vimc_cap_return_all_buffers (vcap,VB2_BUF_STATE_QUEUED ); -return ret; - } +if (ret) + goto err_ret_all_buffs;/* Enable streaming from the pipe */ ret =vimc_pipeline_s_stream (&vcap->vdev.entity,1 ); -if (ret) { -media_pipeline_stop (entity); -vimc_cap_return_all_buffers (vcap,VB2_BUF_STATE_QUEUED ); -return ret; +if (ret <0 ) + goto err_mpipe_stop; + +if (ret ==VIMC_PIPE_OPT ) { +tpg_init (&vcap->tpg, vcap->format.width, vcap->format.height); + ret =tpg_alloc (&vcap->tpg,VIMC_FRAME_MAX_WIDTH ); +if (ret) +/* We don't need to call vimc_pipeline_s_stream(e, 0) */ + goto err_mpipe_stop; + +vimc_cap_tpg_s_format (vcap); + vcap->kthread_cap =kthread_run (vimc_cap_tpg_thread, vcap, +"%s-cap" , vcap->vdev.v4l2_dev->name); +if (IS_ERR (vcap->kthread_cap)) { +dev_err (vcap->vdev.v4l2_dev->dev, +"%s: kernel_thread() failed\n" , + vcap->vdev.name); + ret =PTR_ERR (vcap->kthread_cap); + goto err_tpg_free; + } }return 0 ; + +err_tpg_free: +tpg_free (&vcap->tpg); +err_mpipe_stop: +media_pipeline_stop (entity); +err_ret_all_buffs: +vimc_cap_return_all_buffers (vcap,VB2_BUF_STATE_QUEUED ); + +return ret; }/*
@@ -280,8 +393,15 @@ static void vimc_cap_stop_streaming(struct vb2_queue *vq) {struct vimc_cap_device *vcap =vb2_get_drv_priv (vq); -/* Disable streaming from the pipe */ -vimc_pipeline_s_stream (&vcap->vdev.entity,0 ); +if (vcap->kthread_cap) { +/* Stop image generator */ +kthread_stop (vcap->kthread_cap); + vcap->kthread_cap =NULL ; +tpg_free (&vcap->tpg); + }else { +/* Disable streaming from the pipe */ +vimc_pipeline_s_stream (&vcap->vdev.entity,0 ); + }/* Stop the media pipeline */ media_pipeline_stop (&vcap->vdev.entity);
@@ -361,44 +481,6 @@ static void vimc_cap_destroy(struct vimc_ent_device *ved)kfree (vcap); } -static void vimc_cap_process_frame (struct vimc_ent_device *ved, -struct media_pad *sink,const void *frame) -{ - struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, - ved); -struct vimc_cap_buffer *vimc_buf; -void *vbuf; - -spin_lock (&vcap->qlock); - -/* Get the first entry of the list */ - vimc_buf =list_first_entry_or_null (&vcap->buf_list, -typeof (*vimc_buf), list); -if (!vimc_buf) { -spin_unlock (&vcap->qlock); -return ; - } - -/* Remove this entry from the list */ -list_del (&vimc_buf->list); - -spin_unlock (&vcap->qlock); - -/* Fill the buffer */ - vimc_buf->vb2.vb2_buf.timestamp =ktime_get_ns (); - vimc_buf->vb2.sequence = vcap->sequence++; - vimc_buf->vb2.field = vcap->format.field; - - vbuf =vb2_plane_vaddr (&vimc_buf->vb2.vb2_buf,0 ); - -memcpy (vbuf, frame, vcap->format.sizeimage); - -/* Set it as ready */ -vb2_set_plane_payload (&vimc_buf->vb2.vb2_buf,0 , - vcap->format.sizeimage); -vb2_buffer_done (&vimc_buf->vb2.vb2_buf,VB2_BUF_STATE_DONE ); -} - struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, const char *const name, u16 num_pads,
drivers/media/platform/vimc/vimc-common.h +2 -0
@@ -27,6 +27,8 @@#define VIMC_FRAME_MIN_WIDTH 16#define VIMC_FRAME_MIN_HEIGHT 16 +#define VIMC_PIPE_OPT 1 +/** * struct vimc_pix_map - maps media bus code with v4l2 pixel format *
drivers/media/platform/vimc/vimc-sensor.c +24 -6
@@ -15,6 +15,7 @@* */ +#include <linux/module.h> #include <linux/freezer.h> #include <linux/kthread.h> #include <linux/v4l2-mediabus.h>
@@ -24,6 +25,13 @@#include "vimc-sensor.h" +static bool vsen_tpg; +module_param (vsen_tpg, bool,0000 ); +MODULE_PARM_DESC (vsen_tpg," generate image from sensor node\n" +"If set to false, then the pipe will be optimized and image will be " +"generated directly in the capture node instead of going through " +"the whole pipe" ); +struct vimc_sen_device {struct vimc_ent_device ved;struct v4l2_subdev sd;
@@ -239,6 +247,13 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) container_of(sd, struct vimc_sen_device, sd);int ret; +if (!vsen_tpg) +/* +* If we are not generating the frames, then inform the caller +* to generate the frame in shallow level of the pipe +*/ +return VIMC_PIPE_OPT ; +if (enable) {const struct vimc_pix_map *vpix;unsigned int frame_size;
@@ -306,7 +321,8 @@ static void vimc_sen_destroy(struct vimc_ent_device *ved) container_of(ved, struct vimc_sen_device, ved);vimc_ent_sd_unregister (ved, &vsen->sd); -tpg_free (&vsen->tpg); +if (vsen_tpg) +tpg_free (&vsen->tpg);kfree (vsen); }
@@ -344,11 +360,13 @@ struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, vsen->mbus_format = fmt_default;/* Initialize the test pattern generator */ -tpg_init (&vsen->tpg, vsen->mbus_format.width, - vsen->mbus_format.height); - ret =tpg_alloc (&vsen->tpg,VIMC_FRAME_MAX_WIDTH ); -if (ret) - goto err_unregister_ent_sd; +if (vsen_tpg) { +tpg_init (&vsen->tpg, vsen->mbus_format.width, + vsen->mbus_format.height); + ret =tpg_alloc (&vsen->tpg,VIMC_FRAME_MAX_WIDTH ); +if (ret) + goto err_unregister_ent_sd; + }return &vsen->ved;
Signature · 1 line
2.7.4
Re: [RFC PATCH v3 08/11] [media] vimc: Optimize frame generation through the pipe
Quoted 328 lines · Helen Koike
Add a parameter called
vsen_tpg, if true then vimc will work as before:
frames will be generated in the sensor nodes then propagated through the pipe and processed by each node until a capture node is reached. Ifvsen_tpgis false, then the frame is not generated by the sensor, but directly from the capture node, thus saving intermediate memory buffers and process time, allowing a higher frame rate.Signed-off-by Helen Koike <[email protected]>---
Changes in v3:
[media] vimc: Optimize frame generation through the pipe
- This is a new patch in the seriesChanges in v2: None
--- drivers/media/platform/vimc/vimc-capture.c | 178 +++++++++++++++++++++-------- drivers/media/platform/vimc/vimc-common.h | 2 + drivers/media/platform/vimc/vimc-sensor.c | 30 ++++- 3 files changed, 156 insertions(+), 54 deletions(-)drivers/media/platform/vimc/vimc-capture.c +130
-48@@ -15,7 +15,10 @@* */ +#include <linux/freezer.h> +#include <linux/kthread.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-tpg.h> #include <media/videobuf2-core.h> #include <media/videobuf2-vmalloc.h> @@ -38,6 +41,8 @@ struct vimc_cap_device {struct mutex lock;u32 sequence;struct media_pipeline pipe; +struct tpg_data tpg; +struct task_struct *kthread_cap; };static const struct v4l2_pix_format fmt_default = {@@ -246,6 +251,91 @@ static void vimc_cap_return_all_buffers(struct vimc_cap_device *vcap,spin_unlock (&vcap->qlock); } +static void vimc_cap_process_frame (struct vimc_ent_device *ved, +struct media_pad *sink,const void *frame) +{ + struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, + ved); +struct vimc_cap_buffer *vimc_buf; +void *vbuf; + +spin_lock (&vcap->qlock); + +/* Get the first entry of the list */ + vimc_buf =list_first_entry_or_null (&vcap->buf_list, +typeof (*vimc_buf), list); +if (!vimc_buf) { +spin_unlock (&vcap->qlock); +return ; + } + +/* Remove this entry from the list */ +list_del (&vimc_buf->list); + +spin_unlock (&vcap->qlock); + +/* Fill the buffer */ + vimc_buf->vb2.vb2_buf.timestamp =ktime_get_ns (); + vimc_buf->vb2.sequence = vcap->sequence++; + vimc_buf->vb2.field = vcap->format.field; + + vbuf =vb2_plane_vaddr (&vimc_buf->vb2.vb2_buf,0 ); + +if (sink) +memcpy (vbuf, frame, vcap->format.sizeimage); +else +tpg_fill_plane_buffer (&vcap->tpg,V4L2_STD_PAL ,0 , vbuf); + +/* Set it as ready */ +vb2_set_plane_payload (&vimc_buf->vb2.vb2_buf,0 , + vcap->format.sizeimage); +vb2_buffer_done (&vimc_buf->vb2.vb2_buf,VB2_BUF_STATE_DONE ); +} + + +static int vimc_cap_tpg_thread (void *data) +{ +struct vimc_cap_device *vcap = data; + +set_freezable (); +set_current_state (TASK_UNINTERRUPTIBLE ); + +for (;;) { +try_to_freeze (); +if (kthread_should_stop ()) +break ; + +vimc_cap_process_frame (&vcap->ved,NULL ,NULL ); + +/* 60 frames per second */ +schedule_timeout (HZ /60 ); + } + +return 0 ; +} + +static void vimc_cap_tpg_s_format (struct vimc_cap_device *vcap) +{ +const struct vimc_pix_map *vpix = +vimc_pix_map_by_pixelformat (vcap->format.pixelformat); + +tpg_reset_source (&vcap->tpg, vcap->format.width, vcap->format.height, + vcap->format.field); +tpg_s_bytesperline (&vcap->tpg,0 , vcap->format.width * vpix->bpp); +tpg_s_buf_height (&vcap->tpg, vcap->format.height); +tpg_s_fourcc (&vcap->tpg, vpix->pixelformat); +/* +* TODO: check why the tpg_s_field need this third argument if +* it is already receiving the field +*/ +tpg_s_field (&vcap->tpg, vcap->format.field, + vcap->format.field ==V4L2_FIELD_ALTERNATE ); +tpg_s_colorspace (&vcap->tpg, vcap->format.colorspace); +tpg_s_ycbcr_enc (&vcap->tpg, vcap->format.ycbcr_enc); +tpg_s_quantization (&vcap->tpg, vcap->format.quantization); +tpg_s_xfer_func (&vcap->tpg, vcap->format.xfer_func); +} +static int vimc_cap_start_streaming (struct vb2_queue *vq,unsigned int count) {struct vimc_cap_device *vcap =vb2_get_drv_priv (vq);@@ -256,20 +346,43 @@ static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count)/* Start the media pipeline */ ret =media_pipeline_start (entity, &vcap->pipe); -if (ret) { -vimc_cap_return_all_buffers (vcap,VB2_BUF_STATE_QUEUED ); -return ret; - } +if (ret) + goto err_ret_all_buffs;/* Enable streaming from the pipe */ ret =vimc_pipeline_s_stream (&vcap->vdev.entity,1 ); -if (ret) { -media_pipeline_stop (entity); -vimc_cap_return_all_buffers (vcap,VB2_BUF_STATE_QUEUED ); -return ret; +if (ret <0 ) + goto err_mpipe_stop; + +if (ret ==VIMC_PIPE_OPT ) { +tpg_init (&vcap->tpg, vcap->format.width, vcap->format.height); + ret =tpg_alloc (&vcap->tpg,VIMC_FRAME_MAX_WIDTH ); +if (ret) +/* We don't need to call vimc_pipeline_s_stream(e, 0) */ + goto err_mpipe_stop; + +vimc_cap_tpg_s_format (vcap); + vcap->kthread_cap =kthread_run (vimc_cap_tpg_thread, vcap, +"%s-cap" , vcap->vdev.v4l2_dev->name); +if (IS_ERR (vcap->kthread_cap)) { +dev_err (vcap->vdev.v4l2_dev->dev, +"%s: kernel_thread() failed\n" , + vcap->vdev.name); + ret =PTR_ERR (vcap->kthread_cap); + goto err_tpg_free; + } }return 0 ; + +err_tpg_free: +tpg_free (&vcap->tpg); +err_mpipe_stop: +media_pipeline_stop (entity); +err_ret_all_buffs: +vimc_cap_return_all_buffers (vcap,VB2_BUF_STATE_QUEUED ); + +return ret; }/* @@ -280,8 +393,15 @@ static void vimc_cap_stop_streaming(struct vb2_queue *vq) {struct vimc_cap_device *vcap =vb2_get_drv_priv (vq); -/* Disable streaming from the pipe */ -vimc_pipeline_s_stream (&vcap->vdev.entity,0 ); +if (vcap->kthread_cap) { +/* Stop image generator */ +kthread_stop (vcap->kthread_cap); + vcap->kthread_cap =NULL ; +tpg_free (&vcap->tpg); + }else { +/* Disable streaming from the pipe */ +vimc_pipeline_s_stream (&vcap->vdev.entity,0 ); + }/* Stop the media pipeline */ media_pipeline_stop (&vcap->vdev.entity);@@ -361,44 +481,6 @@ static void vimc_cap_destroy(struct vimc_ent_device *ved)kfree (vcap); } -static void vimc_cap_process_frame (struct vimc_ent_device *ved, -struct media_pad *sink,const void *frame) -{ - struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, - ved); -struct vimc_cap_buffer *vimc_buf; -void *vbuf; - -spin_lock (&vcap->qlock); - -/* Get the first entry of the list */ - vimc_buf =list_first_entry_or_null (&vcap->buf_list, -typeof (*vimc_buf), list); -if (!vimc_buf) { -spin_unlock (&vcap->qlock); -return ; - } - -/* Remove this entry from the list */ -list_del (&vimc_buf->list); - -spin_unlock (&vcap->qlock); - -/* Fill the buffer */ - vimc_buf->vb2.vb2_buf.timestamp =ktime_get_ns (); - vimc_buf->vb2.sequence = vcap->sequence++; - vimc_buf->vb2.field = vcap->format.field; - - vbuf =vb2_plane_vaddr (&vimc_buf->vb2.vb2_buf,0 ); - -memcpy (vbuf, frame, vcap->format.sizeimage); - -/* Set it as ready */ -vb2_set_plane_payload (&vimc_buf->vb2.vb2_buf,0 , - vcap->format.sizeimage); -vb2_buffer_done (&vimc_buf->vb2.vb2_buf,VB2_BUF_STATE_DONE ); -} - struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, const char *const name, u16 num_pads,drivers/media/platform/vimc/vimc-common.h +2
-0@@ -27,6 +27,8 @@#define VIMC_FRAME_MIN_WIDTH 16#define VIMC_FRAME_MIN_HEIGHT 16 +#define VIMC_PIPE_OPT 1 +/** * struct vimc_pix_map - maps media bus code with v4l2 pixel format * drivers/media/platform/vimc/vimc-sensor.c +17
-6@@ -15,6 +15,7 @@* */ +#include <linux/module.h> #include <linux/freezer.h> #include <linux/kthread.h> #include <linux/v4l2-mediabus.h> @@ -24,6 +25,13 @@#include "vimc-sensor.h" +static bool vsen_tpg; +module_param (vsen_tpg, bool,0000 ); +MODULE_PARM_DESC (vsen_tpg," generate image from sensor node\n" +"If set to false, then the pipe will be optimized and image will be " +"generated directly in the capture node instead of going through " +"the whole pipe" ); +struct vimc_sen_device {struct vimc_ent_device ved;struct v4l2_subdev sd;@@ -239,6 +247,13 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) container_of(sd, struct vimc_sen_device, sd);int ret; +if (!vsen_tpg) +/* +* If we are not generating the frames, then inform the caller +* to generate the frame in shallow level of the pipe +*/ +return VIMC_PIPE_OPT ; +if (enable) {const struct vimc_pix_map *vpix;unsigned int frame_size;@@ -306,7 +321,8 @@ static void vimc_sen_destroy(struct vimc_ent_device *ved) container_of(ved, struct vimc_sen_device, ved);vimc_ent_sd_unregister (ved, &vsen->sd); -tpg_free (&vsen->tpg); +if (vsen_tpg) +tpg_free (&vsen->tpg);kfree (vsen); }@@ -344,11 +360,13 @@ struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, vsen->mbus_format = fmt_default;/* Initialize the test pattern generator */ -tpg_init (&vsen->tpg, vsen->mbus_format.width, - vsen->mbus_format.height); - ret =tpg_alloc (&vsen->tpg,VIMC_FRAME_MAX_WIDTH ); -if (ret) - goto err_unregister_ent_sd;
drivers/media/platform/vimc/vimc-sensor.c struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, · line 372
Quoted 10 lines
drivers/media/platform/vimc/vimc-sensor.c +7
-0+if (vsen_tpg) { +tpg_init (&vsen->tpg, vsen->mbus_format.width, + vsen->mbus_format.height); + ret =tpg_alloc (&vsen->tpg,VIMC_FRAME_MAX_WIDTH ); +if (ret) + goto err_unregister_ent_sd; + }return &vsen->ved;
Hi,
There is a bug in this patch as I didn't consider we could have more then one link enabled for a single sink pad. Please, ignore this patch in this series, I'll re-work on it and send it in a different patch series latter. I'll will re-send this series without this patch after your comments in the other patches.
Thanks
LN Koike
Re: [RFC PATCH v3 08/11] [media] vimc: Optimize frame generation through the pipe
In reply to Helen KoikeQuoted 121 lines · Helen Koike
Add a parameter called
vsen_tpg, if true then vimc will work as before:
frames will be generated in the sensor nodes then propagated through the pipe and processed by each node until a capture node is reached. Ifvsen_tpgis false, then the frame is not generated by the sensor, but directly from the capture node, thus saving intermediate memory buffers and process time, allowing a higher frame rate.Signed-off-by Helen Koike <[email protected]>---
Changes in v3:
[media] vimc: Optimize frame generation through the pipe
- This is a new patch in the seriesChanges in v2: None
--- drivers/media/platform/vimc/vimc-capture.c | 178 +++++++++++++++++++++-------- drivers/media/platform/vimc/vimc-common.h | 2 + drivers/media/platform/vimc/vimc-sensor.c | 30 ++++- 3 files changed, 156 insertions(+), 54 deletions(-)drivers/media/platform/vimc/vimc-capture.c +74
-0@@ -15,7 +15,10 @@* */ +#include <linux/freezer.h> +#include <linux/kthread.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-tpg.h> #include <media/videobuf2-core.h> #include <media/videobuf2-vmalloc.h> @@ -38,6 +41,8 @@ struct vimc_cap_device {struct mutex lock;u32 sequence;struct media_pipeline pipe; +struct tpg_data tpg; +struct task_struct *kthread_cap; };static const struct v4l2_pix_format fmt_default = {@@ -246,6 +251,91 @@ static void vimc_cap_return_all_buffers(struct vimc_cap_device *vcap,spin_unlock (&vcap->qlock); } +static void vimc_cap_process_frame (struct vimc_ent_device *ved, +struct media_pad *sink,const void *frame) +{ + struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, + ved); +struct vimc_cap_buffer *vimc_buf; +void *vbuf; + +spin_lock (&vcap->qlock); + +/* Get the first entry of the list */ + vimc_buf =list_first_entry_or_null (&vcap->buf_list, +typeof (*vimc_buf), list); +if (!vimc_buf) { +spin_unlock (&vcap->qlock); +return ; + } + +/* Remove this entry from the list */ +list_del (&vimc_buf->list); + +spin_unlock (&vcap->qlock); + +/* Fill the buffer */ + vimc_buf->vb2.vb2_buf.timestamp =ktime_get_ns (); + vimc_buf->vb2.sequence = vcap->sequence++; + vimc_buf->vb2.field = vcap->format.field; + + vbuf =vb2_plane_vaddr (&vimc_buf->vb2.vb2_buf,0 ); + +if (sink) +memcpy (vbuf, frame, vcap->format.sizeimage); +else +tpg_fill_plane_buffer (&vcap->tpg,V4L2_STD_PAL ,0 , vbuf); + +/* Set it as ready */ +vb2_set_plane_payload (&vimc_buf->vb2.vb2_buf,0 , + vcap->format.sizeimage); +vb2_buffer_done (&vimc_buf->vb2.vb2_buf,VB2_BUF_STATE_DONE ); +} + + +static int vimc_cap_tpg_thread (void *data) +{ +struct vimc_cap_device *vcap = data; + +set_freezable (); +set_current_state (TASK_UNINTERRUPTIBLE ); + +for (;;) { +try_to_freeze (); +if (kthread_should_stop ()) +break ; + +vimc_cap_process_frame (&vcap->ved,NULL ,NULL ); + +/* 60 frames per second */ +schedule_timeout (HZ /60 ); + } + +return 0 ; +} + +static void vimc_cap_tpg_s_format (struct vimc_cap_device *vcap) +{ +const struct vimc_pix_map *vpix = +vimc_pix_map_by_pixelformat (vcap->format.pixelformat); + + tpg_reset_source(&vcap->tpg, vcap->format.width, vcap->format.height,
drivers/media/platform/vimc/vimc-capture.c static void vimc_cap_return_all_buffers(struct vimc_cap_device *vcap, · line 332
Quoted 10 lines
drivers/media/platform/vimc/vimc-capture.c +10
-0+ vcap->format.field); +tpg_s_bytesperline (&vcap->tpg,0 , vcap->format.width * vpix->bpp); +tpg_s_buf_height (&vcap->tpg, vcap->format.height); +tpg_s_fourcc (&vcap->tpg, vpix->pixelformat); +/* +* TODO: check why the tpg_s_field need this third argument if +* it is already receiving the field +*/ +tpg_s_field (&vcap->tpg, vcap->format.field, + vcap->format.field ==V4L2_FIELD_ALTERNATE );
I thought I explained that earlier? When in alternate field mode the format.field value will be TOP or BOTTOM, but never ALTERNATE. So tpg_s_field needs to know if it will create TOP or BOTTOM fields only, or if they will be alternating.
Since we don't support ALTERNATE anyway, just pass false as the third argument and drop the comment.
Quoted 197 lines
drivers/media/platform/vimc/vimc-capture.c +46
-48+tpg_s_colorspace (&vcap->tpg, vcap->format.colorspace); +tpg_s_ycbcr_enc (&vcap->tpg, vcap->format.ycbcr_enc); +tpg_s_quantization (&vcap->tpg, vcap->format.quantization); +tpg_s_xfer_func (&vcap->tpg, vcap->format.xfer_func); +} +static int vimc_cap_start_streaming (struct vb2_queue *vq,unsigned int count) {struct vimc_cap_device *vcap =vb2_get_drv_priv (vq);@@ -256,20 +346,43 @@ static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count)/* Start the media pipeline */ ret =media_pipeline_start (entity, &vcap->pipe); -if (ret) { -vimc_cap_return_all_buffers (vcap,VB2_BUF_STATE_QUEUED ); -return ret; - } +if (ret) + goto err_ret_all_buffs;/* Enable streaming from the pipe */ ret =vimc_pipeline_s_stream (&vcap->vdev.entity,1 ); -if (ret) { -media_pipeline_stop (entity); -vimc_cap_return_all_buffers (vcap,VB2_BUF_STATE_QUEUED ); -return ret; +if (ret <0 ) + goto err_mpipe_stop; + +if (ret ==VIMC_PIPE_OPT ) { +tpg_init (&vcap->tpg, vcap->format.width, vcap->format.height); + ret =tpg_alloc (&vcap->tpg,VIMC_FRAME_MAX_WIDTH ); +if (ret) +/* We don't need to call vimc_pipeline_s_stream(e, 0) */ + goto err_mpipe_stop; + +vimc_cap_tpg_s_format (vcap); + vcap->kthread_cap =kthread_run (vimc_cap_tpg_thread, vcap, +"%s-cap" , vcap->vdev.v4l2_dev->name); +if (IS_ERR (vcap->kthread_cap)) { +dev_err (vcap->vdev.v4l2_dev->dev, +"%s: kernel_thread() failed\n" , + vcap->vdev.name); + ret =PTR_ERR (vcap->kthread_cap); + goto err_tpg_free; + } }return 0 ; + +err_tpg_free: +tpg_free (&vcap->tpg); +err_mpipe_stop: +media_pipeline_stop (entity); +err_ret_all_buffs: +vimc_cap_return_all_buffers (vcap,VB2_BUF_STATE_QUEUED ); + +return ret; }/* @@ -280,8 +393,15 @@ static void vimc_cap_stop_streaming(struct vb2_queue *vq) {struct vimc_cap_device *vcap =vb2_get_drv_priv (vq); -/* Disable streaming from the pipe */ -vimc_pipeline_s_stream (&vcap->vdev.entity,0 ); +if (vcap->kthread_cap) { +/* Stop image generator */ +kthread_stop (vcap->kthread_cap); + vcap->kthread_cap =NULL ; +tpg_free (&vcap->tpg); + }else { +/* Disable streaming from the pipe */ +vimc_pipeline_s_stream (&vcap->vdev.entity,0 ); + }/* Stop the media pipeline */ media_pipeline_stop (&vcap->vdev.entity);@@ -361,44 +481,6 @@ static void vimc_cap_destroy(struct vimc_ent_device *ved)kfree (vcap); } -static void vimc_cap_process_frame (struct vimc_ent_device *ved, -struct media_pad *sink,const void *frame) -{ - struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, - ved); -struct vimc_cap_buffer *vimc_buf; -void *vbuf; - -spin_lock (&vcap->qlock); - -/* Get the first entry of the list */ - vimc_buf =list_first_entry_or_null (&vcap->buf_list, -typeof (*vimc_buf), list); -if (!vimc_buf) { -spin_unlock (&vcap->qlock); -return ; - } - -/* Remove this entry from the list */ -list_del (&vimc_buf->list); - -spin_unlock (&vcap->qlock); - -/* Fill the buffer */ - vimc_buf->vb2.vb2_buf.timestamp =ktime_get_ns (); - vimc_buf->vb2.sequence = vcap->sequence++; - vimc_buf->vb2.field = vcap->format.field; - - vbuf =vb2_plane_vaddr (&vimc_buf->vb2.vb2_buf,0 ); - -memcpy (vbuf, frame, vcap->format.sizeimage); - -/* Set it as ready */ -vb2_set_plane_payload (&vimc_buf->vb2.vb2_buf,0 , - vcap->format.sizeimage); -vb2_buffer_done (&vimc_buf->vb2.vb2_buf,VB2_BUF_STATE_DONE ); -} - struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, const char *const name, u16 num_pads,drivers/media/platform/vimc/vimc-common.h +2
-0@@ -27,6 +27,8 @@#define VIMC_FRAME_MIN_WIDTH 16#define VIMC_FRAME_MIN_HEIGHT 16 +#define VIMC_PIPE_OPT 1 +/** * struct vimc_pix_map - maps media bus code with v4l2 pixel format * drivers/media/platform/vimc/vimc-sensor.c +17
-6@@ -15,6 +15,7 @@* */ +#include <linux/module.h> #include <linux/freezer.h> #include <linux/kthread.h> #include <linux/v4l2-mediabus.h> @@ -24,6 +25,13 @@#include "vimc-sensor.h" +static bool vsen_tpg; +module_param (vsen_tpg, bool,0000 ); +MODULE_PARM_DESC (vsen_tpg," generate image from sensor node\n" +"If set to false, then the pipe will be optimized and image will be " +"generated directly in the capture node instead of going through " +"the whole pipe" ); +struct vimc_sen_device {struct vimc_ent_device ved;struct v4l2_subdev sd;@@ -239,6 +247,13 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) container_of(sd, struct vimc_sen_device, sd);int ret; +if (!vsen_tpg) +/* +* If we are not generating the frames, then inform the caller +* to generate the frame in shallow level of the pipe +*/ +return VIMC_PIPE_OPT ; +if (enable) {const struct vimc_pix_map *vpix;unsigned int frame_size;@@ -306,7 +321,8 @@ static void vimc_sen_destroy(struct vimc_ent_device *ved) container_of(ved, struct vimc_sen_device, ved);vimc_ent_sd_unregister (ved, &vsen->sd); -tpg_free (&vsen->tpg); +if (vsen_tpg) +tpg_free (&vsen->tpg);kfree (vsen); }@@ -344,11 +360,13 @@ struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, vsen->mbus_format = fmt_default;/* Initialize the test pattern generator */ -tpg_init (&vsen->tpg, vsen->mbus_format.width, - vsen->mbus_format.height); - ret =tpg_alloc (&vsen->tpg,VIMC_FRAME_MAX_WIDTH ); -if (ret) - goto err_unregister_ent_sd;
drivers/media/platform/vimc/vimc-sensor.c struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, · line 372
Quoted 10 lines
drivers/media/platform/vimc/vimc-sensor.c +7
-0+if (vsen_tpg) { +tpg_init (&vsen->tpg, vsen->mbus_format.width, + vsen->mbus_format.height); + ret =tpg_alloc (&vsen->tpg,VIMC_FRAME_MAX_WIDTH ); +if (ret) + goto err_unregister_ent_sd; + }return &vsen->ved;
Regards,
Hans
Re: [RFC PATCH v3 08/11] [media] vimc: Optimize frame generation through the pipe
Hi Hans,
Thank you for your review
Quoted 131 lines · Hans Verkuil
Quoted 130 lines · Helen Koike
Add a parameter called
vsen_tpg, if true then vimc will work as before:
frames will be generated in the sensor nodes then propagated through the pipe and processed by each node until a capture node is reached. Ifvsen_tpgis false, then the frame is not generated by the sensor, but directly from the capture node, thus saving intermediate memory buffers and process time, allowing a higher frame rate.Signed-off-by Helen Koike <[email protected]>---
Changes in v3:
[media] vimc: Optimize frame generation through the pipe
- This is a new patch in the seriesChanges in v2: None
--- drivers/media/platform/vimc/vimc-capture.c | 178 +++++++++++++++++++++-------- drivers/media/platform/vimc/vimc-common.h | 2 + drivers/media/platform/vimc/vimc-sensor.c | 30 ++++- 3 files changed, 156 insertions(+), 54 deletions(-)drivers/media/platform/vimc/vimc-capture.c +80
-0@@ -15,7 +15,10 @@* */ +#include <linux/freezer.h> +#include <linux/kthread.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-tpg.h> #include <media/videobuf2-core.h> #include <media/videobuf2-vmalloc.h> @@ -38,6 +41,8 @@ struct vimc_cap_device {struct mutex lock;u32 sequence;struct media_pipeline pipe; +struct tpg_data tpg; +struct task_struct *kthread_cap; };static const struct v4l2_pix_format fmt_default = {@@ -246,6 +251,91 @@ static void vimc_cap_return_all_buffers(struct vimc_cap_device *vcap,spin_unlock (&vcap->qlock); } +static void vimc_cap_process_frame(struct vimc_ent_device *ved, +struct media_pad *sink,const void *frame) +{ + struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, + ved); +struct vimc_cap_buffer *vimc_buf; +void *vbuf; + +spin_lock (&vcap->qlock); + +/* Get the first entry of the list */ + vimc_buf =list_first_entry_or_null (&vcap->buf_list, +typeof (*vimc_buf), list); +if (!vimc_buf) { +spin_unlock (&vcap->qlock); +return ; + } + +/* Remove this entry from the list */ +list_del (&vimc_buf->list); + +spin_unlock (&vcap->qlock); + +/* Fill the buffer */ + vimc_buf->vb2.vb2_buf.timestamp =ktime_get_ns (); + vimc_buf->vb2.sequence = vcap->sequence++; + vimc_buf->vb2.field = vcap->format.field; + + vbuf =vb2_plane_vaddr (&vimc_buf->vb2.vb2_buf,0 ); + +if (sink) +memcpy (vbuf, frame, vcap->format.sizeimage); +else +tpg_fill_plane_buffer (&vcap->tpg,V4L2_STD_PAL ,0 , vbuf); + +/* Set it as ready */ +vb2_set_plane_payload (&vimc_buf->vb2.vb2_buf,0 , + vcap->format.sizeimage); +vb2_buffer_done (&vimc_buf->vb2.vb2_buf,VB2_BUF_STATE_DONE ); +} + + +static int vimc_cap_tpg_thread (void *data) +{ +struct vimc_cap_device *vcap = data; + +set_freezable (); +set_current_state (TASK_UNINTERRUPTIBLE ); + +for (;;) { +try_to_freeze (); +if (kthread_should_stop ()) +break ; + +vimc_cap_process_frame (&vcap->ved,NULL ,NULL ); + +/* 60 frames per second */ +schedule_timeout (HZ /60 ); + } + +return 0 ; +} + +static void vimc_cap_tpg_s_format (struct vimc_cap_device *vcap) +{ +const struct vimc_pix_map *vpix = +vimc_pix_map_by_pixelformat (vcap->format.pixelformat); + +tpg_reset_source (&vcap->tpg, vcap->format.width, vcap->format.height, + vcap->format.field); +tpg_s_bytesperline (&vcap->tpg,0 , vcap->format.width * vpix->bpp); +tpg_s_buf_height (&vcap->tpg, vcap->format.height); +tpg_s_fourcc (&vcap->tpg, vpix->pixelformat); +/* +* TODO: check why the tpg_s_field need this third argument if +* it is already receiving the field +*/
Quoted 8 lines
drivers/media/platform/vimc/vimc-capture.c static void vimc_cap_return_all_buffers(struct vimc_cap_device *vcap, · line 332
Quoted 2 lines
drivers/media/platform/vimc/vimc-capture.c +2
-0+tpg_s_field (&vcap->tpg, vcap->format.field, + vcap->format.field ==V4L2_FIELD_ALTERNATE );I thought I explained that earlier? When in alternate field mode the format.field
value will be TOP or BOTTOM, but never ALTERNATE. Sotpg_s_fieldneeds to know if
it will create TOP or BOTTOM fields only, or if they will be alternating.
Yes, sorry about that. I removed from the vimc_sensor but I forgot it here. I am dropping this patch in the series as I found another bug when multiple links are enabled going to the same sink pad. I'll re-work in this optimization and re-send another version in the future in a different patch series.
Quoted 209 lines
Since we don't support ALTERNATE anyway, just pass false as the third argument and
drop the comment.Quoted 191 lines
drivers/media/platform/vimc/vimc-capture.c +6
-0+tpg_s_colorspace (&vcap->tpg, vcap->format.colorspace); +tpg_s_ycbcr_enc (&vcap->tpg, vcap->format.ycbcr_enc); +tpg_s_quantization (&vcap->tpg, vcap->format.quantization); +tpg_s_xfer_func (&vcap->tpg, vcap->format.xfer_func); +} + static int vimc_cap_start_streaming(struct vb2_queue *vq, unsignedint count)
{ struct vimc_cap_device *vcap = vb2_get_drv_priv(vq);drivers/media/platform/vimc/vimc-capture.c +40
-46@@ -256,20 +346,43 @@ static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count)/* Start the media pipeline */ ret =media_pipeline_start (entity, &vcap->pipe); -if (ret) { -vimc_cap_return_all_buffers (vcap,VB2_BUF_STATE_QUEUED ); -return ret; - } +if (ret) + goto err_ret_all_buffs;/* Enable streaming from the pipe */ ret =vimc_pipeline_s_stream (&vcap->vdev.entity,1 ); -if (ret) { -media_pipeline_stop (entity); -vimc_cap_return_all_buffers (vcap,VB2_BUF_STATE_QUEUED ); -return ret; +if (ret <0 ) + goto err_mpipe_stop; + +if (ret ==VIMC_PIPE_OPT ) { +tpg_init (&vcap->tpg, vcap->format.width, vcap->format.height); + ret =tpg_alloc (&vcap->tpg,VIMC_FRAME_MAX_WIDTH ); +if (ret) +/* We don't need to call vimc_pipeline_s_stream(e, 0) */ + goto err_mpipe_stop; + +vimc_cap_tpg_s_format (vcap); + vcap->kthread_cap =kthread_run (vimc_cap_tpg_thread, vcap, +"%s-cap" , vcap->vdev.v4l2_dev->name); +if (IS_ERR (vcap->kthread_cap)) { +dev_err (vcap->vdev.v4l2_dev->dev, +"%s: kernel_thread() failed\n" , + vcap->vdev.name); + ret =PTR_ERR (vcap->kthread_cap); + goto err_tpg_free; + } }return 0 ; + +err_tpg_free: +tpg_free (&vcap->tpg); +err_mpipe_stop: +media_pipeline_stop (entity); +err_ret_all_buffs: +vimc_cap_return_all_buffers (vcap,VB2_BUF_STATE_QUEUED ); + +return ret; }/* @@ -280,8 +393,15 @@ static void vimc_cap_stop_streaming(struct vb2_queue *vq) {struct vimc_cap_device *vcap =vb2_get_drv_priv (vq); -/* Disable streaming from the pipe */ -vimc_pipeline_s_stream (&vcap->vdev.entity,0 ); + if (vcap->kthread_cap) { +/* Stop image generator */ +kthread_stop (vcap->kthread_cap); + vcap->kthread_cap =NULL ; +tpg_free (&vcap->tpg); + } else { +/* Disable streaming from the pipe */ +vimc_pipeline_s_stream (&vcap->vdev.entity,0 ); + }/* Stop the media pipeline */ media_pipeline_stop (&vcap->vdev.entity);@@ -361,44 +481,6 @@ static void vimc_cap_destroy(struct vimc_ent_device *ved)kfree (vcap ); } -static void vimc_cap_process_frame(struct vimc_ent_device *ved, -struct media_pad *sink,const void *frame) -{ - struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, - ved); -struct vimc_cap_buffer *vimc_buf; -void *vbuf; - -spin_lock (&vcap->qlock); - -/* Get the first entry of the list */ - vimc_buf =list_first_entry_or_null (&vcap->buf_list, -typeof (*vimc_buf), list); -if (!vimc_buf) { -spin_unlock (&vcap->qlock); -return ; - } - -/* Remove this entry from the list */ -list_del (&vimc_buf->list); - -spin_unlock (&vcap->qlock); - -/* Fill the buffer */ - vimc_buf->vb2.vb2_buf.timestamp =ktime_get_ns (); - vimc_buf->vb2.sequence = vcap->sequence++; - vimc_buf->vb2.field = vcap->format.field; - - vbuf =vb2_plane_vaddr (&vimc_buf->vb2.vb2_buf,0 ); - -memcpy (vbuf, frame, vcap->format.sizeimage); - -/* Set it as ready */ -vb2_set_plane_payload (&vimc_buf->vb2.vb2_buf,0 , - vcap->format.sizeimage); -vb2_buffer_done (&vimc_buf->vb2.vb2_buf,VB2_BUF_STATE_DONE ); -} - struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, const char *const name, u16 num_pads,drivers/media/platform/vimc/vimc-common.h +1
-0@@ -27,6 +27,8 @@#define VIMC_FRAME_MIN_WIDTH 16#define VIMC_FRAME_MIN_HEIGHT 16 +#define VIMC_PIPE_OPT 1 +/** * struct vimc_pix_map - maps media bus code with v4l2 pixel format * drivers/media/platform/vimc/vimc-sensor.c +3
-0@@ -15,6 +15,7 @@* */ +#include <linux/module.h>#include <linux/freezer.h> #include <linux/kthread.h> #include <linux/v4l2-mediabus.h> @@ -24,6 +25,13 @@#include "vimc-sensor.h" +static bool vsen_tpg; +module_param (vsen_tpg, bool,0000 ); +MODULE_PARM_DESC (vsen_tpg," generate image from sensor node\n" + "If set to false, then the pipe will be optimized and image willbe "
drivers/media/platform/vimc/vimc-sensor.c +11
-1+"generated directly in the capture node instead of going through " + "the whole pipe"); +struct vimc_sen_device {struct vimc_ent_device ved;struct v4l2_subdev sd;@@ -239,6 +247,13 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable)container_of (sd ,struct vimc_sen_device ,sd );int ret; + if (!vsen_tpg) +/* +* If we are not generating the frames, then inform the caller +* to generate the frame in shallow level of the pipe + */ +return VIMC_PIPE_OPT ; +if (enable) {const struct vimc_pix_map *vpix;unsigned int frame_size;@@ -306,7 +321,8 @@ static void vimc_sen_destroy(struct vimc_ent_device *ved)container_of (ved ,struct vimc_sen_device ,ved );vimc_ent_sd_unregister (ved, &vsen->sd); -tpg_free (&vsen->tpg); +if (vsen_tpg) +tpg_free (&vsen->tpg);kfree (vsen); } @@ -344,11 +360,13 @@ struct vimc_ent_device *vimc_sen_create(struct
v4l2_device*v4l2_dev,vsen->mbus_format = fmt_default; /* Initialize the test pattern generator */drivers/media/platform/vimc/vimc-sensor.c +0
-3-tpg_init (&vsen->tpg, vsen->mbus_format.width, - vsen->mbus_format.height); - ret =tpg_alloc (&vsen->tpg,VIMC_FRAME_MAX_WIDTH );drivers/media/platform/vimc/vimc-sensor.c struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, · line 371
Quoted 10 lines
drivers/media/platform/vimc/vimc-sensor.c +7
-2-if (ret) - goto err_unregister_ent_sd; +if (vsen_tpg) { +tpg_init (&vsen->tpg, vsen->mbus_format.width, + vsen->mbus_format.height); + ret =tpg_alloc (&vsen->tpg,VIMC_FRAME_MAX_WIDTH ); +if (ret) + goto err_unregister_ent_sd; + }return &vsen->ved;Regards,
Quoted 1 line
Hans
Thanks,
Helen
RFC PATCH v3 9/11 vimc: Subdevices as modules
In reply to Helen KoikeChange the core structure for adding subdevices in the topology. Instead of calling the specific create function for each subdevice, inject a child platform_device with the driver's name.
Each type of node in the topology (sensor, capture, debayer, scaler) will register a platform_driver with the corresponding name through the component subsystem.
Implementing a new subdevice type doesn't require vimc-core to be altered.
This facilitates future implementation of dynamic entities, where hotpluging an entity in the topology is just a matter of registering/unregistering a platform_device in the system. It also facilitates other implementations of different nodes without touching the core code and remove the need of a header file for each type of node.
---
Changes in v3:
[media] vimc: Subdevices as modules
- This is a new patch in the series
Changes in v2: None
--- drivers/media/platform/vimc/Makefile | 7 +- drivers/media/platform/vimc/vimc-capture.c | 96 ++++--- drivers/media/platform/vimc/vimc-capture.h | 28 -- drivers/media/platform/vimc/vimc-common.c | 37 ++- drivers/media/platform/vimc/vimc-common.h | 14 +- drivers/media/platform/vimc/vimc-core.c | 406 +++++++++++------------------ drivers/media/platform/vimc/vimc-sensor.c | 91 +++++-- drivers/media/platform/vimc/vimc-sensor.h | 28 -- 8 files changed, 320 insertions(+), 387 deletions(-) delete mode 100644 drivers/media/platform/vimc/vimc-capture.h delete mode 100644 drivers/media/platform/vimc/vimc-sensor.h
drivers/media/platform/vimc/Makefile +5 -2
@@ -1,3 +1,6 @@ -vimc-objs := vimc-core.o vimc-capture.o vimc-common.o vimc-sensor.o +vimc-objs := vimc-core.o +vimc_capture-objs := vimc-capture.o +vimc_common-objs := vimc-common.o +vimc_sensor-objs := vimc-sensor.o -obj-$(CONFIG_VIDEO_VIMC) += vimc.o +obj-$(CONFIG_VIDEO_VIMC) += vimc.o vimc_capture.o vimc_common.o vimc_sensor.o
drivers/media/platform/vimc/vimc-capture.c +67 -29
191 lines not on this page · raw message
drivers/media/platform/vimc/vimc-capture.h deleted +0 -28
@@ -1,28 +0,0 @@ -/* -* vimc-capture.h Virtual Media Controller Driver -* -* Copyright (C) 2015-2017 Helen Koike <[email protected]> -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -*/ - -#ifndef _VIMC_CAPTURE_H_ -#define _VIMC_CAPTURE_H_ - -#include "vimc-common.h" - -struct vimc_ent_device *vimc_cap_create (struct v4l2_device *v4l2_dev, -const char *const name, -u16 num_pads, -const unsigned long *pads_flag); - -#endif
drivers/media/platform/vimc/vimc-common.c +18 -19
@@ -15,6 +15,9 @@* */ +#include <linux/init.h> +#include <linux/module.h> +#include "vimc-common.h" static const struct vimc_pix_map vimc_pix_map_list[] = {
@@ -151,6 +154,7 @@ const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i)return &vimc_pix_map_list[i]; } +EXPORT_SYMBOL (vimc_pix_map_by_index);const struct vimc_pix_map *vimc_pix_map_by_code (u32 code) {
@@ -162,6 +166,7 @@ const struct vimc_pix_map *vimc_pix_map_by_code(u32 code) }return NULL ; } +EXPORT_SYMBOL (vimc_pix_map_by_code);const struct vimc_pix_map *vimc_pix_map_by_pixelformat (u32 pixelformat) {
@@ -173,6 +178,7 @@ const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat) }return NULL ; } +EXPORT_SYMBOL (vimc_pix_map_by_pixelformat);int vimc_propagate_frame (struct media_pad *src,const void *frame) {
@@ -207,6 +213,7 @@ int vimc_propagate_frame(struct media_pad *src, const void *frame)return 0 ; } +EXPORT_SYMBOL (vimc_propagate_frame);/* Helper function to allocate and initialize pads */ struct media_pad *vimc_pads_init (u16 num_pads,const unsigned long *pads_flag)
@@ -227,6 +234,7 @@ struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag)return pads; } +EXPORT_SYMBOL (vimc_pads_init);int vimc_pipeline_s_stream (struct media_entity *ent,int enable) {
@@ -242,14 +250,8 @@ int vimc_pipeline_s_stream(struct media_entity *ent, int enable)/* Start the stream in the subdevice direct connected */ pad =media_entity_remote_pad (&ent->pads[i]); -/* -* if this is a raw node from vimc-core, then there is -* nothing to activate -* TODO: remove this when there are no more raw nodes in the -* core and return error instead -*/ -if (pad->entity->obj_type ==MEDIA_ENTITY_TYPE_BASE ) -continue ; +if (!is_media_entity_v4l2_subdev (pad->entity)) +return -EINVAL ; sd =media_entity_to_v4l2_subdev (pad->entity); ret =v4l2_subdev_call (sd, video, s_stream, enable);
@@ -259,6 +261,7 @@ int vimc_pipeline_s_stream(struct media_entity *ent, int enable)return 0 ; } +EXPORT_SYMBOL (vimc_pipeline_s_stream);static void vimc_fmt_pix_to_mbus (struct v4l2_mbus_framefmt *mfmt,struct v4l2_pix_format *pfmt)
@@ -315,14 +318,6 @@ int vimc_link_validate(struct media_link *link)struct v4l2_subdev_format source_fmt, sink_fmt;int ret; -/* -* if it is a raw node from vimc-core, ignore the link for now -* TODO: remove this when there are no more raw nodes in the -* core and return error instead -*/ -if (link->source->entity->obj_type ==MEDIA_ENTITY_TYPE_BASE ) -return 0 ; - ret =vimc_get_mbus_format (link->source, &source_fmt);if (ret)return ret;
@@ -393,8 +388,7 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,u32 function, u16 num_pads, const unsigned long *pads_flag, - const struct v4l2_subdev_ops *sd_ops, - void (*sd_destroy)(struct vimc_ent_device *)) + const struct v4l2_subdev_ops *sd_ops) { int ret;
@@ -404,7 +398,6 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,return PTR_ERR (ved->pads);/* Fill the vimc_ent_device struct */ - ved->destroy = sd_destroy; ved->ent = &sd->entity;/* Initialize the subdev */
@@ -440,6 +433,7 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,vimc_pads_cleanup (ved->pads);return ret; } +EXPORT_SYMBOL (vimc_ent_sd_register);void vimc_ent_sd_unregister (struct vimc_ent_device *ved,struct v4l2_subdev *sd) {
@@ -447,3 +441,8 @@ void vimc_ent_sd_unregister(struct vimc_ent_device *ved, struct v4l2_subdev *sd)media_entity_cleanup (ved->ent);vimc_pads_cleanup (ved->pads); } +EXPORT_SYMBOL (vimc_ent_sd_unregister); + +MODULE_DESCRIPTION ("Virtual Media Controller Driver (VIMC) Common" ); +MODULE_AUTHOR ("Helen Koike <[email protected]>" ); +MODULE_LICENSE ("GPL" );
drivers/media/platform/vimc/vimc-common.h +5 -9
@@ -1,5 +1,5 @@/* -* vimc-ccommon.h Virtual Media Controller Driver +* vimc-common.h Virtual Media Controller Driver * * Copyright (C) 2015-2017 Helen Koike <[email protected]> *
@@ -50,7 +50,6 @@ struct vimc_pix_map {* * @ent: the pointer to struct media_entity for the node * @pads: the list of pads of the node -* @destroy: callback to destroy the node * @process_frame: callback send a frame to that node * @vdev_get_format: callback that returns the current format a pad, used * only when is_media_entity_v4l2_video_device(ent) returns
@@ -67,7 +66,6 @@ struct vimc_pix_map {struct vimc_ent_device {struct media_entity *ent;struct media_pad *pads; -void (*destroy)(struct vimc_ent_device *);void (*process_frame)(struct vimc_ent_device *ved,struct media_pad *sink,const void *frame); void (*vdev_get_format)(struct vimc_ent_device *ved,
@@ -152,7 +150,6 @@ const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat);* @num_pads: number of pads to initialize * @pads_flag: flags to use in each pad * @sd_ops: pointer to &struct v4l2_subdev_ops. -* @sd_destroy: callback to destroy the node * * Helper function initialize and register the struct vimc_ent_device and struct * v4l2_subdev which represents a subdev node in the topology
@@ -164,14 +161,13 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,u32 function, u16 num_pads, const unsigned long *pads_flag, - const struct v4l2_subdev_ops *sd_ops, - void (*sd_destroy)(struct vimc_ent_device *)); + const struct v4l2_subdev_ops *sd_ops);/** -* vimc_ent_sd_register - initialize and register a subdev node +* vimc_ent_sd_unregister - cleanup and unregister a subdev node * -* @ved: the vimc_ent_device struct to be initialize -* @sd: the v4l2_subdev struct to be initialize and registered +* @ved: the vimc_ent_device struct to be cleaned up +* @sd: the v4l2_subdev struct to be unregistered * * Helper function cleanup and unregister the struct vimc_ent_device and struct * v4l2_subdev which represents a subdev node in the topology
drivers/media/platform/vimc/vimc-core.c +159 -247
562 lines not on this page · raw message
drivers/media/platform/vimc/vimc-sensor.c +66 -25
158 lines not on this page · raw message
drivers/media/platform/vimc/vimc-sensor.h deleted +0 -28
@@ -1,28 +0,0 @@ -/* -* vimc-sensor.h Virtual Media Controller Driver -* -* Copyright (C) 2015-2017 Helen Koike <[email protected]> -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -*/ - -#ifndef _VIMC_SENSOR_H_ -#define _VIMC_SENSOR_H_ - -#include "vimc-common.h" - -struct vimc_ent_device *vimc_sen_create (struct v4l2_device *v4l2_dev, -const char *const name, -u16 num_pads, -const unsigned long *pads_flag); - -#endif
Signature · 1 line
2.7.4
Re: [RFC PATCH v3 09/11] [media] vimc: Subdevices as modules
Quoted 307 lines · Helen Koike
Change the core structure for adding subdevices in the topology. Instead of calling the specific create function for each subdevice, inject a child
platform_devicewith the driver's name.
Each type of node in the topology (sensor, capture, debayer, scaler) will register aplatform_driverwith the corresponding name through the component subsystem.
Implementing a new subdevice type doesn't require vimc-core to be altered.This facilitates future implementation of dynamic entities, where hotpluging an entity in the topology is just a matter of registering/unregistering a
platform_devicein the system. It also facilitates other implementations of different nodes without touching the core code and remove the need of a header file for each type of node.Signed-off-by Helen Koike <[email protected]>---
Changes in v3:
[media] vimc: Subdevices as modules
- This is a new patch in the seriesChanges in v2: None
--- drivers/media/platform/vimc/Makefile | 7 +- drivers/media/platform/vimc/vimc-capture.c | 96 ++++--- drivers/media/platform/vimc/vimc-capture.h | 28 -- drivers/media/platform/vimc/vimc-common.c | 37 ++- drivers/media/platform/vimc/vimc-common.h | 14 +- drivers/media/platform/vimc/vimc-core.c | 406 +++++++++++------------------ drivers/media/platform/vimc/vimc-sensor.c | 91 +++++-- drivers/media/platform/vimc/vimc-sensor.h | 28 -- 8 files changed, 320 insertions(+), 387 deletions(-)delete mode 100644
drivers/media/platform/vimc/vimc-capture.hdelete mode 100644drivers/media/platform/vimc/vimc-sensor.hdrivers/media/platform/vimc/Makefile +5
-2@@ -1,3 +1,6 @@ -vimc-objs := vimc-core.o vimc-capture.o vimc-common.o vimc-sensor.o +vimc-objs := vimc-core.o +vimc_capture-objs := vimc-capture.o +vimc_common-objs := vimc-common.o +vimc_sensor-objs := vimc-sensor.o -obj-$(CONFIG_VIDEO_VIMC) += vimc.o +obj-$(CONFIG_VIDEO_VIMC) += vimc.o vimc_capture.o vimc_common.o vimc_sensor.odrivers/media/platform/vimc/vimc-capture.c +67
-29@@ -15,18 +15,24 @@* */ +#include <linux/component.h> #include <linux/freezer.h> #include <linux/kthread.h> +#include <linux/module.h> +#include <linux/platform_device.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-tpg.h> #include <media/videobuf2-core.h> #include <media/videobuf2-vmalloc.h> -#include "vimc-capture.h" +#include "vimc-common.h" + +#define VIMC_CAP_DRV_NAME "vimc-capture"struct vimc_cap_device {struct vimc_ent_device ved;struct video_device vdev; +struct device *dev;struct v4l2_pix_format format;struct vb2_queue queue;struct list_head buf_list;@@ -150,7 +156,7 @@ static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv,vimc_cap_try_fmt_vid_cap (file, priv, f); - dev_dbg(vcap->vdev.v4l2_dev->dev, "%s: format update: " + dev_dbg(vcap->dev, "%s: format update: " "old:%dx%d (0x%x, %d, %d, %d, %d) " "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vcap->vdev.name,/* old */ @@ -365,8 +371,7 @@ static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count) vcap->kthread_cap =kthread_run (vimc_cap_tpg_thread, vcap,"%s-cap" , vcap->vdev.v4l2_dev->name);if (IS_ERR (vcap->kthread_cap)) { -dev_err (vcap->vdev.v4l2_dev->dev, -"%s: kernel_thread() failed\n" , +dev_err (vcap->dev,"%s: kernel_thread() failed\n" , vcap->vdev.name); ret =PTR_ERR (vcap->kthread_cap); goto err_tpg_free;@@ -443,8 +448,7 @@ static int vimc_cap_buffer_prepare(struct vb2_buffer *vb)unsigned long size = vcap->format.sizeimage;if (vb2_plane_size (vb,0 ) < size) { -dev_err (vcap->vdev.v4l2_dev->dev, -"%s: buffer too small (%lu < %lu)\n" , +dev_err (vcap->dev,"%s: buffer too small (%lu < %lu)\n" , vcap->vdev.name,vb2_plane_size (vb,0 ), size);return -EINVAL ; }@@ -469,8 +473,10 @@ static const struct media_entity_operations vimc_cap_mops = { .link_validate = vimc_link_validate, }; -static void vimc_cap_destroy (struct vimc_ent_device *ved) +static void vimc_cap_comp_unbind (struct device *comp,struct device *master, +void *master_data) { +struct vimc_ent_device *ved =dev_get_drvdata (comp); struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, ved);@@ -481,32 +487,25 @@ static void vimc_cap_destroy(struct vimc_ent_device *ved)kfree (vcap); } -struct vimc_ent_device *vimc_cap_create (struct v4l2_device *v4l2_dev, -const char *const name, -u16 num_pads, -const unsigned long *pads_flag) +static int vimc_cap_comp_bind (struct device *comp,struct device *master, +void *master_data) { +struct v4l2_device *v4l2_dev = master_data; +char *name = comp->platform_data;const struct vimc_pix_map *vpix;struct vimc_cap_device *vcap;struct video_device *vdev;struct vb2_queue *q;int ret; -/* -* Check entity configuration params -* NOTE: we only support a single sink pad -*/ -if (!name || num_pads !=1 || !pads_flag || - !(pads_flag[0 ] &MEDIA_PAD_FL_SINK )) -return ERR_PTR (-EINVAL ); -/* Allocate the vimc_cap_device struct */ vcap =kzalloc (sizeof (*vcap),GFP_KERNEL );if (!vcap) -return ERR_PTR (-ENOMEM ); +return -ENOMEM ;/* Allocate the pads */ - vcap->ved.pads =vimc_pads_init (num_pads, pads_flag); + vcap->ved.pads = +vimc_pads_init (1 , (const unsigned long [1 ]) {MEDIA_PAD_FL_SINK });if (IS_ERR (vcap->ved.pads)) { ret =PTR_ERR (vcap->ved.pads); goto err_free_vcap;@@ -516,7 +515,7 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, vcap->vdev.entity.name = name; vcap->vdev.entity.function =MEDIA_ENT_F_IO_V4L ; ret =media_entity_pads_init (&vcap->vdev.entity, - num_pads, vcap->ved.pads); +1 , vcap->ved.pads);if (ret) goto err_clean_pads;@@ -537,8 +536,7 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, ret =vb2_queue_init (q);if (ret) { -dev_err (vcap->vdev.v4l2_dev->dev, -"%s: vb2 queue init failed (err=%d)\n" , +dev_err (comp,"%s: vb2 queue init failed (err=%d)\n" , vcap->vdev.name, ret); goto err_clean_m_ent; }@@ -555,10 +553,11 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, vcap->format.height;/* Fill the vimc_ent_device struct */ - vcap->ved.destroy = vimc_cap_destroy; vcap->ved.ent = &vcap->vdev.entity; vcap->ved.process_frame = vimc_cap_process_frame; vcap->ved.vdev_get_format = vimc_cap_get_format; +dev_set_drvdata (comp, &vcap->ved); + vcap->dev = comp;/* Initialize the video_device struct */ vdev = &vcap->vdev;@@ -577,13 +576,12 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev,/* Register the video_device with the v4l2 and the media framework */ ret =video_register_device (vdev,VFL_TYPE_GRABBER ,-1 );if (ret) { -dev_err (vcap->vdev.v4l2_dev->dev, -"%s: video register failed (err=%d)\n" , +dev_err (comp,"%s: video register failed (err=%d)\n" , vcap->vdev.name, ret); goto err_release_queue; } -return &vcap->ved; +return 0 ; err_release_queue:vb2_queue_release (q);@@ -594,5 +592,45 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, err_free_vcap:kfree (vcap); -return ERR_PTR (ret); +return ret; +} + +static const struct component_ops vimc_cap_comp_ops = { + .bind = vimc_cap_comp_bind, + .unbind = vimc_cap_comp_unbind, +}; + +static int vimc_cap_probe (struct platform_device *pdev) +{ +return component_add (&pdev->dev, &vimc_cap_comp_ops); } + +static int vimc_cap_remove (struct platform_device *pdev) +{ +component_del (&pdev->dev, &vimc_cap_comp_ops); + +return 0 ; +} + +static struct platform_driver vimc_cap_pdrv = { + .probe = vimc_cap_probe, + .remove = vimc_cap_remove, + .driver = { + .name =VIMC_CAP_DRV_NAME , + }, +}; + +static const struct platform_device_id vimc_cap_driver_ids[] = { + { + .name =VIMC_CAP_DRV_NAME , + }, + { } +}; + +module_platform_driver (vimc_cap_pdrv); + +MODULE_DEVICE_TABLE (platform, vimc_cap_driver_ids); + +MODULE_DESCRIPTION ("Virtual Media Controller Driver (VIMC) Capture" ); +MODULE_AUTHOR ("Helen Mae Koike Fornazier <[email protected]>" ); +MODULE_LICENSE ("GPL" );drivers/media/platform/vimc/vimc-capture.h deleted +0
-28@@ -1,28 +0,0 @@ -/* -* vimc-capture.h Virtual Media Controller Driver -* -* Copyright (C) 2015-2017 Helen Koike <[email protected]> -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -*/ - -#ifndef _VIMC_CAPTURE_H_ -#define _VIMC_CAPTURE_H_ - -#include "vimc-common.h" - -struct vimc_ent_device *vimc_cap_create (struct v4l2_device *v4l2_dev, -const char *const name, -u16 num_pads, -const unsigned long *pads_flag); - -#endif drivers/media/platform/vimc/vimc-common.c +3
-0@@ -15,6 +15,9 @@* */ +#include <linux/init.h> +#include <linux/module.h> +#include "vimc-common.h" static const struct vimc_pix_map vimc_pix_map_list[] = {
drivers/media/platform/vimc/vimc-common.c const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i) · line 157
Quoted 4 lines
drivers/media/platform/vimc/vimc-common.c +1
-0@@ -151,6 +154,7 @@ const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i)return &vimc_pix_map_list[i]; } +EXPORT_SYMBOL (vimc_pix_map_by_index);
I would recommend using EXPORT_SYMBOL_GPL.
Quoted 290 lines
drivers/media/platform/vimc/vimc-common.c +14
-19const struct vimc_pix_map *vimc_pix_map_by_code (u32 code) {@@ -162,6 +166,7 @@ const struct vimc_pix_map *vimc_pix_map_by_code(u32 code) }return NULL ; } +EXPORT_SYMBOL (vimc_pix_map_by_code);const struct vimc_pix_map *vimc_pix_map_by_pixelformat (u32 pixelformat) {@@ -173,6 +178,7 @@ const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat) }return NULL ; } +EXPORT_SYMBOL (vimc_pix_map_by_pixelformat);int vimc_propagate_frame (struct media_pad *src,const void *frame) {@@ -207,6 +213,7 @@ int vimc_propagate_frame(struct media_pad *src, const void *frame)return 0 ; } +EXPORT_SYMBOL (vimc_propagate_frame);/* Helper function to allocate and initialize pads */ struct media_pad *vimc_pads_init (u16 num_pads,const unsigned long *pads_flag)@@ -227,6 +234,7 @@ struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag)return pads; } +EXPORT_SYMBOL (vimc_pads_init);int vimc_pipeline_s_stream (struct media_entity *ent,int enable) {@@ -242,14 +250,8 @@ int vimc_pipeline_s_stream(struct media_entity *ent, int enable)/* Start the stream in the subdevice direct connected */ pad =media_entity_remote_pad (&ent->pads[i]); -/* -* if this is a raw node from vimc-core, then there is -* nothing to activate -* TODO: remove this when there are no more raw nodes in the -* core and return error instead -*/ -if (pad->entity->obj_type ==MEDIA_ENTITY_TYPE_BASE ) -continue ; +if (!is_media_entity_v4l2_subdev (pad->entity)) +return -EINVAL ; sd =media_entity_to_v4l2_subdev (pad->entity); ret =v4l2_subdev_call (sd, video, s_stream, enable);@@ -259,6 +261,7 @@ int vimc_pipeline_s_stream(struct media_entity *ent, int enable)return 0 ; } +EXPORT_SYMBOL (vimc_pipeline_s_stream);static void vimc_fmt_pix_to_mbus (struct v4l2_mbus_framefmt *mfmt,struct v4l2_pix_format *pfmt)@@ -315,14 +318,6 @@ int vimc_link_validate(struct media_link *link)struct v4l2_subdev_format source_fmt, sink_fmt;int ret; -/* -* if it is a raw node from vimc-core, ignore the link for now -* TODO: remove this when there are no more raw nodes in the -* core and return error instead -*/ -if (link->source->entity->obj_type ==MEDIA_ENTITY_TYPE_BASE ) -return 0 ; - ret =vimc_get_mbus_format (link->source, &source_fmt);if (ret)return ret;@@ -393,8 +388,7 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,u32 function, u16 num_pads, const unsigned long *pads_flag, - const struct v4l2_subdev_ops *sd_ops, - void (*sd_destroy)(struct vimc_ent_device *)) + const struct v4l2_subdev_ops *sd_ops) { int ret;@@ -404,7 +398,6 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,return PTR_ERR (ved->pads);/* Fill the vimc_ent_device struct */ - ved->destroy = sd_destroy; ved->ent = &sd->entity;/* Initialize the subdev */ @@ -440,6 +433,7 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,vimc_pads_cleanup (ved->pads);return ret; } +EXPORT_SYMBOL (vimc_ent_sd_register);void vimc_ent_sd_unregister (struct vimc_ent_device *ved,struct v4l2_subdev *sd) {@@ -447,3 +441,8 @@ void vimc_ent_sd_unregister(struct vimc_ent_device *ved, struct v4l2_subdev *sd)media_entity_cleanup (ved->ent);vimc_pads_cleanup (ved->pads); } +EXPORT_SYMBOL (vimc_ent_sd_unregister); + +MODULE_DESCRIPTION ("Virtual Media Controller Driver (VIMC) Common" ); +MODULE_AUTHOR ("Helen Koike <[email protected]>" ); +MODULE_LICENSE ("GPL" );drivers/media/platform/vimc/vimc-common.h +5
-9@@ -1,5 +1,5 @@/* -* vimc-ccommon.h Virtual Media Controller Driver +* vimc-common.h Virtual Media Controller Driver * * Copyright (C) 2015-2017 Helen Koike <[email protected]> * @@ -50,7 +50,6 @@ struct vimc_pix_map {* * @ent: the pointer to struct media_entity for the node * @pads: the list of pads of the node -* @destroy: callback to destroy the node * @process_frame: callback send a frame to that node * @vdev_get_format: callback that returns the current format a pad, used * only when is_media_entity_v4l2_video_device(ent) returns @@ -67,7 +66,6 @@ struct vimc_pix_map {struct vimc_ent_device {struct media_entity *ent;struct media_pad *pads; -void (*destroy)(struct vimc_ent_device *);void (*process_frame)(struct vimc_ent_device *ved,struct media_pad *sink,const void *frame); void (*vdev_get_format)(struct vimc_ent_device *ved,@@ -152,7 +150,6 @@ const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat);* @num_pads: number of pads to initialize * @pads_flag: flags to use in each pad * @sd_ops: pointer to &struct v4l2_subdev_ops. -* @sd_destroy: callback to destroy the node * * Helper function initialize and register the struct vimc_ent_device and struct * v4l2_subdev which represents a subdev node in the topology @@ -164,14 +161,13 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,u32 function, u16 num_pads, const unsigned long *pads_flag, - const struct v4l2_subdev_ops *sd_ops, - void (*sd_destroy)(struct vimc_ent_device *)); + const struct v4l2_subdev_ops *sd_ops);/** -* vimc_ent_sd_register - initialize and register a subdev node +* vimc_ent_sd_unregister - cleanup and unregister a subdev node * -* @ved: the vimc_ent_device struct to be initialize -* @sd: the v4l2_subdev struct to be initialize and registered +* @ved: the vimc_ent_device struct to be cleaned up +* @sd: the v4l2_subdev struct to be unregistered * * Helper function cleanup and unregister the struct vimc_ent_device and struct * v4l2_subdev which represents a subdev node in the topology drivers/media/platform/vimc/vimc-core.c +13
-57@@ -15,15 +15,14 @@* */ +#include <linux/component.h> #include <linux/init.h> #include <linux/module.h> #include <linux/platform_device.h> #include <media/media-device.h> #include <media/v4l2-device.h> -#include "vimc-capture.h" #include "vimc-common.h" -#include "vimc-sensor.h" #define VIMC_PDEV_NAME "vimc"#define VIMC_MDEV_MODEL_NAME "VIMC MDEV"@@ -37,10 +36,10 @@ }struct vimc_device { -/* -* The pipeline configuration -* (filled before calling vimc_device_register) -*/ +/* The platform device */ +struct platform_device pdev; + +/* The pipeline configuration */ const struct vimc_pipeline_config *pipe_cfg;/* The Associated media_device parent */ @@ -49,43 +48,14 @@ struct vimc_device {/* Internal v4l2 parent device*/ struct v4l2_device v4l2_dev; -/* Internal topology */ -struct vimc_ent_device **ved; -}; - -/** -* enum vimc_ent_node - Select the functionality of a node in the topology -* @VIMC_ENT_NODE_SENSOR: A node of type SENSOR simulates a camera sensor -* generating internal images in bayer format and -* propagating those images through the pipeline -* @VIMC_ENT_NODE_CAPTURE: A node of type CAPTURE is a v4l2 video_device -* that exposes the received image from the -* pipeline to the user space -* @VIMC_ENT_NODE_INPUT: A node of type INPUT is a v4l2 video_device that -* receives images from the user space and -* propagates them through the pipeline -* @VIMC_ENT_NODE_DEBAYER: A node type DEBAYER expects to receive a frame -* in bayer format converts it to RGB -* @VIMC_ENT_NODE_SCALER: A node of type SCALER scales the received image -* by a given multiplier -* -* This enum is used in the entity configuration struct to allow the definition -* of a custom topology specifying the role of each node on it. -*/ -enum vimc_ent_node { -VIMC_ENT_NODE_SENSOR , -VIMC_ENT_NODE_CAPTURE , -VIMC_ENT_NODE_INPUT , -VIMC_ENT_NODE_DEBAYER , -VIMC_ENT_NODE_SCALER , +/* Subdevices */ +struct platform_device **subdevs; };/* Structure which describes individual configuration for each entity */ struct vimc_ent_config {const char *name; -size_t pads_qty; -const unsigned long *pads_flag; -enum vimc_ent_node node; +const char *drv; };/* Structure which describes links between entities */ @@ -112,60 +82,40 @@ struct vimc_pipeline_config {static const struct vimc_ent_config ent_config[] = { { .name ="Sensor A" , - .pads_qty =1 , - .pads_flag = (const unsigned long []){MEDIA_PAD_FL_SOURCE }, - .node =VIMC_ENT_NODE_SENSOR , + .drv ="vimc-sensor" , }, { .name ="Sensor B" , - .pads_qty =1 , - .pads_flag = (const unsigned long []){MEDIA_PAD_FL_SOURCE }, - .node =VIMC_ENT_NODE_SENSOR , + .drv ="vimc-sensor" , }, { .name ="Debayer A" , - .pads_qty =2 , - .pads_flag = (const unsigned long []){MEDIA_PAD_FL_SINK , -MEDIA_PAD_FL_SOURCE }, - .node =VIMC_ENT_NODE_DEBAYER , + .drv ="vimc-debayer" , }, { .name ="Debayer B" , - .pads_qty =2 , - .pads_flag = (const unsigned long []){MEDIA_PAD_FL_SINK , -MEDIA_PAD_FL_SOURCE }, - .node =VIMC_ENT_NODE_DEBAYER , + .drv ="vimc-debayer" , }, { .name ="Raw Capture 0" , - .pads_qty =1 , - .pads_flag = (const unsigned long []){MEDIA_PAD_FL_SINK }, - .node =VIMC_ENT_NODE_CAPTURE , + .drv ="vimc-capture" , }, { .name ="Raw Capture 1" , - .pads_qty =1 , - .pads_flag = (const unsigned long []){MEDIA_PAD_FL_SINK },
drivers/media/platform/vimc/vimc-core.c struct vimc_pipeline_config { · line 110
Quoted 10 lines
drivers/media/platform/vimc/vimc-core.c +3
-4- .node = VIMC_ENT_NODE_CAPTURE, + .drv = "vimc-capture", }, { .name = "RGB/YUV Input", - .pads_qty = 1, - .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SOURCE}, - .node = VIMC_ENT_NODE_INPUT, + /* TODO: change to vimc-output when output is implemented */ + .drv = "vimc-sensor",
This is confusing: the name indicates an input, but the TODO indicates an output. I assume this is supposed to emulate e.g. an HDMI input? I'm not sure the TODO text makes sense here.
Quoted 276 lines
drivers/media/platform/vimc/vimc-core.c +65
-158}, { .name = "Scaler", - .pads_qty = 2, - .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SINK, - MEDIA_PAD_FL_SOURCE}, - .node = VIMC_ENT_NODE_SCALER, + .drv = "vimc-scaler", }, { .name = "RGB/YUV Capture", - .pads_qty = 1, - .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SINK}, - .node = VIMC_ENT_NODE_CAPTURE, + .drv = "vimc-capture", }, };@@ -197,111 +147,40 @@ static const struct vimc_pipeline_config pipe_cfg = {/* -------------------------------------------------------------------------- */ -static void vimc_device_unregister (struct vimc_device *vimc) +static int vimc_create_links (struct vimc_device *vimc) {unsigned int i; - -media_device_unregister (&vimc->mdev); -/* Cleanup (only initialized) entities */ -for (i =0 ; i < vimc->pipe_cfg->num_ents; i++) { -if (vimc->ved[i] && vimc->ved[i]->destroy) - vimc->ved[i]->destroy (vimc->ved[i]); - - vimc->ved[i] =NULL ; - } -v4l2_device_unregister (&vimc->v4l2_dev); -media_device_cleanup (&vimc->mdev); -} - -/* -* TODO: remove this function when all the -* entities specific code are implemented -*/ -static void vimc_raw_destroy (struct vimc_ent_device *ved) -{ -media_device_unregister_entity (ved->ent); - -media_entity_cleanup (ved->ent); - -vimc_pads_cleanup (ved->pads); - -kfree (ved->ent); - -kfree (ved); -} - -/* -* TODO: remove this function when all the -* entities specific code are implemented -*/ -static struct vimc_ent_device *vimc_raw_create (struct v4l2_device *v4l2_dev, -const char *const name, -u16 num_pads, -const unsigned long *pads_flag) -{ -struct vimc_ent_device *ved;int ret; -/* Allocate the main ved struct */ - ved =kzalloc (sizeof (*ved),GFP_KERNEL ); -if (!ved) -return ERR_PTR (-ENOMEM ); - -/* Allocate the media entity */ - ved->ent =kzalloc (sizeof (*ved->ent),GFP_KERNEL ); -if (!ved->ent) { - ret = -ENOMEM ; - goto err_free_ved; - } - -/* Allocate the pads */ - ved->pads =vimc_pads_init (num_pads, pads_flag); -if (IS_ERR (ved->pads)) { - ret =PTR_ERR (ved->pads); - goto err_free_ent; +/* Initialize the links between entities */ +for (i =0 ; i < vimc->pipe_cfg->num_links; i++) { +const struct vimc_ent_link *link = &vimc->pipe_cfg->links[i]; +/* +* TODO: Check another way of retrieving ved struct without +* relying on platform_get_drvdata +*/ +struct vimc_ent_device *ved_src = +platform_get_drvdata (vimc->subdevs[link->src_ent]); +struct vimc_ent_device *ved_sink = +platform_get_drvdata (vimc->subdevs[link->sink_ent]); + + ret =media_create_pad_link (ved_src->ent, link->src_pad, + ved_sink->ent, link->sink_pad, + link->flags); +if (ret) +return ret; } -/* Initialize the media entity */ - ved->ent->name = name; - ved->ent->function =MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN ; - ret =media_entity_pads_init (ved->ent, num_pads, ved->pads); -if (ret) - goto err_cleanup_pads; - -/* Register the media entity */ - ret =media_device_register_entity (v4l2_dev->mdev, ved->ent); -if (ret) - goto err_cleanup_entity; - -/* Fill out the destroy function and return */ - ved->destroy = vimc_raw_destroy; -return ved; - -err_cleanup_entity: -media_entity_cleanup (ved->ent); -err_cleanup_pads: -vimc_pads_cleanup (ved->pads); -err_free_ent: -kfree (ved->ent); -err_free_ved: -kfree (ved); - -return ERR_PTR (ret); +return 0 ; } -static int vimc_device_register (struct vimc_device *vimc) +static int vimc_comp_bind (struct device *master) { -unsigned int i; +struct vimc_device *vimc =container_of (to_platform_device (master), + struct vimc_device, pdev);int ret; -/* Allocate memory for the vimc_ent_devices pointers */ - vimc->ved =devm_kcalloc (vimc->mdev.dev, vimc->pipe_cfg->num_ents, -sizeof (*vimc->ved),GFP_KERNEL ); -if (!vimc->ved) -return -ENOMEM ; - -/* Link the media device within the v4l2_device */ - vimc->v4l2_dev.mdev = &vimc->mdev; +dev_dbg (master,"bind" );/* Register the v4l2 struct */ ret =v4l2_device_register (vimc->mdev.dev, &vimc->v4l2_dev);@@ -311,66 +190,22 @@ static int vimc_device_register(struct vimc_device *vimc)return ret; } -/* Initialize entities */ -for (i =0 ; i < vimc->pipe_cfg->num_ents; i++) { -struct vimc_ent_device *(*create_func)(struct v4l2_device *, -const char *const , -u16 , -const unsigned long *); - -/* Register the specific node */ -switch (vimc->pipe_cfg->ents[i].node) { -case VIMC_ENT_NODE_SENSOR : - create_func = vimc_sen_create; -break ; - -case VIMC_ENT_NODE_CAPTURE : - create_func = vimc_cap_create; -break ; - -/* TODO: Instantiate the specific topology node */ -case VIMC_ENT_NODE_INPUT : -case VIMC_ENT_NODE_DEBAYER : -case VIMC_ENT_NODE_SCALER : -default : -/* -* TODO: remove this when all the entities specific -* code are implemented -*/ - create_func = vimc_raw_create; -break ; - } - - vimc->ved[i] =create_func (&vimc->v4l2_dev, - vimc->pipe_cfg->ents[i].name, - vimc->pipe_cfg->ents[i].pads_qty, - vimc->pipe_cfg->ents[i].pads_flag); -if (IS_ERR (vimc->ved[i])) { - ret =PTR_ERR (vimc->ved[i]); - vimc->ved[i] =NULL ; - goto err; - } - } - -/* Initialize the links between entities */ -for (i =0 ; i < vimc->pipe_cfg->num_links; i++) { -const struct vimc_ent_link *link = &vimc->pipe_cfg->links[i]; +/* Bind subdevices */ + ret =component_bind_all (master, &vimc->v4l2_dev); +if (ret) + goto err_v4l2_unregister; - ret =media_create_pad_link (vimc->ved[link->src_ent]->ent, - link->src_pad, - vimc->ved[link->sink_ent]->ent, - link->sink_pad, - link->flags); -if (ret) - goto err; - } +/* Initialize links */ + ret =vimc_create_links (vimc); +if (ret) + goto err_comp_unbind_all;/* Register the media device */ ret =media_device_register (&vimc->mdev);if (ret) {dev_err (vimc->mdev.dev,"media device register failed (err=%d)\n" , ret); -return ret; + goto err_comp_unbind_all; }/* Expose all subdev's nodes*/ @@ -379,32 +214,107 @@ static int vimc_device_register(struct vimc_device *vimc)dev_err (vimc->mdev.dev,"vimc subdev nodes registration failed (err=%d)\n" , ret); - goto err; + goto err_mdev_unregister; }return 0 ; -err: -/* Destroy the so far created topology */ -vimc_device_unregister (vimc); +err_mdev_unregister: +media_device_unregister (&vimc->mdev); +err_comp_unbind_all: +component_unbind_all (master,NULL ); +err_v4l2_unregister: +v4l2_device_unregister (&vimc->v4l2_dev);return ret; } +static void vimc_comp_unbind (struct device *master) +{ +struct vimc_device *vimc =container_of (to_platform_device (master), + struct vimc_device, pdev); + +dev_dbg (master,"unbind" ); + +media_device_unregister (&vimc->mdev); +component_unbind_all (master,NULL ); +v4l2_device_unregister (&vimc->v4l2_dev); +} + +static int vimc_comp_compare (struct device *comp,void *data) +{ +const struct platform_device *pdev =to_platform_device (comp); +const char *name = data; + +return !strcmp (pdev->dev.platform_data, name); +} + +static struct component_match *vimc_add_subdevs (struct vimc_device *vimc) +{ +struct component_match *match =NULL ; +unsigned int i;
drivers/media/platform/vimc/vimc-core.c static int vimc_device_register(struct vimc_device *vimc) · line 265
Quoted 10 lines
drivers/media/platform/vimc/vimc-core.c +10
-0+ +for (i =0 ; i < vimc->pipe_cfg->num_ents; i++) { +dev_dbg (&vimc->pdev.dev,"new pdev for %s\n" , + vimc->pipe_cfg->ents[i].drv); + +/* +* TODO: check if using platform_data is indeed the best way to +* pass the name to the driver or if we should add the drv name +* in the platform_device_id table +*/
Didn't you set the drv name in the platform_device_id table already?
Using platform_data feels like an abuse to be honest.
Creating these components here makes sense. Wouldn't it also make sense to use v4l2_async to wait until they have all been bound? It would more closely emulate standard drivers. Apologies if I misunderstand what is happening here.
Quoted 348 lines
drivers/media/platform/vimc/vimc-core.c +68
-28+ vimc->subdevs[i] =platform_device_register_data (&vimc->pdev.dev, + vimc->pipe_cfg->ents[i].drv, +PLATFORM_DEVID_AUTO , + vimc->pipe_cfg->ents[i].name, +strlen (vimc->pipe_cfg->ents[i].name) +1 ); +if (!vimc->subdevs[i]) { +while (--i >=0 ) +platform_device_unregister (vimc->subdevs[i]); + +return ERR_PTR (-ENOMEM ); + } + +component_match_add (&vimc->pdev.dev, &match, vimc_comp_compare, + (void *)vimc->pipe_cfg->ents[i].name); + } + +return match; +} + +static void vimc_rm_subdevs (struct vimc_device *vimc) +{ +unsigned int i; + +for (i =0 ; i < vimc->pipe_cfg->num_ents; i++) +platform_device_unregister (vimc->subdevs[i]); +} + +static const struct component_master_ops vimc_comp_ops = { + .bind = vimc_comp_bind, + .unbind = vimc_comp_unbind, +}; +static int vimc_probe (struct platform_device *pdev) { -struct vimc_device *vimc; + struct vimc_device *vimc = container_of(pdev, struct vimc_device, pdev); +struct component_match *match =NULL ;int ret; -/* Prepare the vimc topology structure */ +dev_dbg (&pdev->dev,"probe" ); -/* Allocate memory for the vimc structure */ - vimc =kzalloc (sizeof (*vimc),GFP_KERNEL ); -if (!vimc) +/* Create platform_device for each entity in the topology*/ + vimc->subdevs =devm_kcalloc (&vimc->pdev.dev, vimc->pipe_cfg->num_ents, +sizeof (*vimc->subdevs),GFP_KERNEL ); +if (!vimc->subdevs)return -ENOMEM ; -/* Set the pipeline configuration struct */ - vimc->pipe_cfg = &pipe_cfg; + match =vimc_add_subdevs (vimc); +if (IS_ERR (match)) +return PTR_ERR (match); + +/* Link the media device within the v4l2_device */ + vimc->v4l2_dev.mdev = &vimc->mdev;/* Initialize media device */ strlcpy(vimc->mdev.model, VIMC_MDEV_MODEL_NAME,@@ -412,28 +322,27 @@ static int vimc_probe(struct platform_device *pdev) vimc->mdev.dev = &pdev->dev;media_device_init (&vimc->mdev); -/* Create vimc topology */ - ret =vimc_device_register (vimc); +/* Add self to the component system */ + ret =component_master_add_with_match (&pdev->dev, &vimc_comp_ops, + match);if (ret) { -dev_err (vimc->mdev.dev, -"vimc device registration failed (err=%d)\n" , ret); +media_device_cleanup (&vimc->mdev); +vimc_rm_subdevs (vimc);kfree (vimc);return ret; } -/* Link the topology object with the platform device object */ -platform_set_drvdata (pdev, vimc); -return 0 ; }static int vimc_remove (struct platform_device *pdev) { -struct vimc_device *vimc =platform_get_drvdata (pdev); + struct vimc_device *vimc = container_of(pdev, struct vimc_device, pdev); -/* Destroy all the topology */ -vimc_device_unregister (vimc); -kfree (vimc); +dev_dbg (&pdev->dev,"remove" ); + +component_master_del (&pdev->dev, &vimc_comp_ops); +vimc_rm_subdevs (vimc);return 0 ; }@@ -442,9 +351,12 @@ static void vimc_dev_release(struct device *dev) { } -static struct platform_device vimc_pdev = { - .name =VIMC_PDEV_NAME , - .dev.release = vimc_dev_release, +static struct vimc_device vimc_dev = { + .pipe_cfg = &pipe_cfg, + .pdev = { + .name =VIMC_PDEV_NAME , + .dev.release = vimc_dev_release, + } };static struct platform_driver vimc_pdrv = {@@ -459,29 +371,29 @@ static int __init vimc_init(void) {int ret; - ret =platform_device_register (&vimc_pdev); + ret =platform_device_register (&vimc_dev.pdev);if (ret) { -dev_err (&vimc_pdev.dev, +dev_err (&vimc_dev.pdev.dev,"platform device registration failed (err=%d)\n" , ret);return ret; } ret =platform_driver_register (&vimc_pdrv);if (ret) { -dev_err (&vimc_pdev.dev, +dev_err (&vimc_dev.pdev.dev,"platform driver registration failed (err=%d)\n" , ret); - -platform_device_unregister (&vimc_pdev); +platform_driver_unregister (&vimc_pdrv); +return ret; } -return ret; +return 0 ; } static void __exit vimc_exit(void) {platform_driver_unregister (&vimc_pdrv); -platform_device_unregister (&vimc_pdev); +platform_device_unregister (&vimc_dev.pdev); }module_init (vimc_init);drivers/media/platform/vimc/vimc-sensor.c +66
-25@@ -15,15 +15,19 @@* */ -#include <linux/module.h> +#include <linux/component.h> #include <linux/freezer.h> #include <linux/kthread.h> +#include <linux/module.h> +#include <linux/platform_device.h> #include <linux/v4l2-mediabus.h> #include <linux/vmalloc.h> #include <media/v4l2-subdev.h> #include <media/v4l2-tpg.h> -#include "vimc-sensor.h" +#include "vimc-common.h" + +#define VIMC_SEN_DRV_NAME "vimc-sensor"static bool vsen_tpg;module_param (vsen_tpg, bool,0000 );@@ -35,6 +39,7 @@ MODULE_PARM_DESC(vsen_tpg, " generate image from sensor node\n"struct vimc_sen_device {struct vimc_ent_device ved;struct v4l2_subdev sd; +struct device *dev;struct tpg_data tpg;struct task_struct *kthread_sen;u8 *frame;@@ -189,7 +194,7 @@ static int vimc_sen_set_fmt(struct v4l2_subdev *sd,/* Set the new format */ vimc_sen_adjust_fmt (&fmt->format); - dev_dbg(vsen->sd.v4l2_dev->mdev->dev, "%s: format update: " + dev_dbg(vsen->dev, "%s: format update: " "old:%dx%d (0x%x, %d, %d, %d, %d) " "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsen->sd.name,/* old */ @@ -282,8 +287,8 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) vsen->kthread_sen =kthread_run (vimc_sen_tpg_thread, vsen,"%s-sen" , vsen->sd.v4l2_dev->name);if (IS_ERR (vsen->kthread_sen)) { -dev_err (vsen->sd.v4l2_dev->dev, -"%s: kernel_thread() failed\n" , vsen->sd.name); +dev_err (vsen->dev,"%s: kernel_thread() failed\n" , + vsen->sd.name);vfree (vsen->frame); vsen->frame =NULL ;return PTR_ERR (vsen->kthread_sen);@@ -315,8 +320,10 @@ static const struct v4l2_subdev_ops vimc_sen_ops = { .video = &vimc_sen_video_ops, }; -static void vimc_sen_destroy (struct vimc_ent_device *ved) +static void vimc_sen_comp_unbind (struct device *comp,struct device *master, +void *master_data) { +struct vimc_ent_device *ved =dev_get_drvdata (comp);struct vimc_sen_device *vsen = container_of(ved, struct vimc_sen_device, ved);@@ -326,36 +333,30 @@ static void vimc_sen_destroy(struct vimc_ent_device *ved)kfree (vsen); } -struct vimc_ent_device *vimc_sen_create (struct v4l2_device *v4l2_dev, -const char *const name, -u16 num_pads, -const unsigned long *pads_flag) +static int vimc_sen_comp_bind (struct device *comp,struct device *master, +void *master_data) { +struct v4l2_device *v4l2_dev = master_data; +char *name = comp->platform_data;struct vimc_sen_device *vsen; -unsigned int i;int ret; -/* NOTE: a sensor node may be created with more then one pad */ -if (!name || !num_pads || !pads_flag) -return ERR_PTR (-EINVAL ); - -/* check if all pads are sources */ -for (i =0 ; i < num_pads; i++) -if (!(pads_flag[i] &MEDIA_PAD_FL_SOURCE )) -return ERR_PTR (-EINVAL ); -/* Allocate the vsen struct */ vsen =kzalloc (sizeof (*vsen),GFP_KERNEL );if (!vsen) -return ERR_PTR (-ENOMEM ); +return -ENOMEM ;/* Initialize ved and sd */ ret =vimc_ent_sd_register (&vsen->ved, &vsen->sd, v4l2_dev, name, -MEDIA_ENT_F_CAM_SENSOR , num_pads, pads_flag, - &vimc_sen_ops, vimc_sen_destroy); +MEDIA_ENT_F_ATV_DECODER ,1 , + (const unsigned long [1 ]) {MEDIA_PAD_FL_SOURCE }, + &vimc_sen_ops);if (ret) goto err_free_vsen; +dev_set_drvdata (comp, &vsen->ved); + vsen->dev = comp; +/* Initialize the frame format */ vsen->mbus_format = fmt_default;@@ -368,12 +369,52 @@ struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, goto err_unregister_ent_sd; } -return &vsen->ved; +return 0 ; err_unregister_ent_sd:vimc_ent_sd_unregister (&vsen->ved, &vsen->sd); err_free_vsen:kfree (vsen); -return ERR_PTR (ret); +return ret; +} + +static const struct component_ops vimc_sen_comp_ops = { + .bind = vimc_sen_comp_bind, + .unbind = vimc_sen_comp_unbind, +}; + +static int vimc_sen_probe (struct platform_device *pdev) +{ +return component_add (&pdev->dev, &vimc_sen_comp_ops); } + +static int vimc_sen_remove (struct platform_device *pdev) +{ +component_del (&pdev->dev, &vimc_sen_comp_ops); + +return 0 ; +} + +static struct platform_driver vimc_sen_pdrv = { + .probe = vimc_sen_probe, + .remove = vimc_sen_remove, + .driver = { + .name =VIMC_SEN_DRV_NAME , + }, +}; + +static const struct platform_device_id vimc_sen_driver_ids[] = { + { + .name =VIMC_SEN_DRV_NAME , + }, + { } +}; + +module_platform_driver (vimc_sen_pdrv); + +MODULE_DEVICE_TABLE (platform, vimc_sen_driver_ids); + +MODULE_DESCRIPTION ("Virtual Media Controller Driver (VIMC) Sensor" ); +MODULE_AUTHOR ("Helen Mae Koike Fornazier <[email protected]>" ); +MODULE_LICENSE ("GPL" );drivers/media/platform/vimc/vimc-sensor.h deleted +0
-18@@ -1,28 +0,0 @@ -/* -* vimc-sensor.h Virtual Media Controller Driver -* -* Copyright (C) 2015-2017 Helen Koike <[email protected]> -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -*/ - -#ifndef _VIMC_SENSOR_H_
drivers/media/platform/vimc/vimc-sensor.h line 28
Quoted 10 lines
drivers/media/platform/vimc/vimc-sensor.h deleted +0
-10-#define _VIMC_SENSOR_H_ - -#include "vimc-common.h" - -struct vimc_ent_device *vimc_sen_create (struct v4l2_device *v4l2_dev, -const char *const name, -u16 num_pads, -const unsigned long *pads_flag); - -#endif
Regards,
Hans
Re: [RFC PATCH v3 09/11] [media] vimc: Subdevices as modules
Hi Hans,
Thank you for your review. Please check my comments below
Quoted 613 lines · Hans Verkuil
Quoted 307 lines · Helen Koike
Change the core structure for adding subdevices in the topology. Instead of calling the specific create function for each subdevice, inject a child
platform_devicewith the driver's name.
Each type of node in the topology (sensor, capture, debayer, scaler) will register aplatform_driverwith the corresponding name through the component subsystem.
Implementing a new subdevice type doesn't require vimc-core to be altered.This facilitates future implementation of dynamic entities, where hotpluging an entity in the topology is just a matter of registering/unregistering a
platform_devicein the system. It also facilitates other implementations of different nodes without touching the core code and remove the need of a header file for each type of node.Signed-off-by Helen Koike <[email protected]>---
Changes in v3:
[media] vimc: Subdevices as modules
- This is a new patch in the seriesChanges in v2: None
--- drivers/media/platform/vimc/Makefile | 7 +- drivers/media/platform/vimc/vimc-capture.c | 96 ++++--- drivers/media/platform/vimc/vimc-capture.h | 28 -- drivers/media/platform/vimc/vimc-common.c | 37 ++- drivers/media/platform/vimc/vimc-common.h | 14 +- drivers/media/platform/vimc/vimc-core.c | 406 +++++++++++------------------ drivers/media/platform/vimc/vimc-sensor.c | 91 +++++-- drivers/media/platform/vimc/vimc-sensor.h | 28 -- 8 files changed, 320 insertions(+), 387 deletions(-)delete mode 100644
drivers/media/platform/vimc/vimc-capture.hdelete mode 100644drivers/media/platform/vimc/vimc-sensor.hdrivers/media/platform/vimc/Makefile +5
-1@@ -1,3 +1,6 @@ -vimc-objs := vimc-core.o vimc-capture.o vimc-common.o vimc-sensor.o +vimc-objs := vimc-core.o +vimc_capture-objs := vimc-capture.o +vimc_common-objs := vimc-common.o +vimc_sensor-objs := vimc-sensor.o -obj-$(CONFIG_VIDEO_VIMC) += vimc.o +obj-$(CONFIG_VIDEO_VIMC) += vimc.o vimc_capture.o vimc_common.ovimc_sensor.o
drivers/media/platform/vimc/vimc-capture.c +8
-2@@ -15,18 +15,24 @@* */ +#include <linux/component.h>#include <linux/freezer.h> #include <linux/kthread.h> +#include <linux/module.h> +#include <linux/platform_device.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-tpg.h> #include <media/videobuf2-core.h> #include <media/videobuf2-vmalloc.h> -#include "vimc-capture.h" +#include "vimc-common.h" + +#define VIMC_CAP_DRV_NAME "vimc-capture"struct vimc_cap_device {struct vimc_ent_device ved;struct video_device vdev; +struct device *dev;struct v4l2_pix_format format;struct vb2_queue queue;struct list_head buf_list;@@ -150,7 +156,7 @@ static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv,vimc_cap_try_fmt_vid_cap (file, priv, f); - dev_dbg(vcap->vdev.v4l2_dev->dev, "%s: format update: " + dev_dbg(vcap->dev, "%s: format update: " "old:%dx%d (0x%x, %d, %d, %d, %d) " "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vcap->vdev.name,/* old */ @@ -365,8 +371,7 @@ static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count) vcap->kthread_cap = kthread_run(vimc_cap_tpg_thread, vcap,"%s-cap" , vcap->vdev.v4l2_dev->name);if (IS_ERR (vcap->kthread_cap)) { -dev_err (vcap->vdev.v4l2_dev->dev, -"%s: kernel_thread() failed\n" , +dev_err (vcap->dev,"%s: kernel_thread() failed\n" , vcap->vdev.name); ret =PTR_ERR (vcap->kthread_cap);goto err_tpg_free;drivers/media/platform/vimc/vimc-capture.c +4
-2@@ -443,8 +448,7 @@ static int vimc_cap_buffer_prepare(struct vb2_buffer *vb)unsigned long size = vcap->format.sizeimage;if (vb2_plane_size (vb,0 ) < size) { -dev_err (vcap->vdev.v4l2_dev->dev, -"%s: buffer too small (%lu < %lu)\n" , +dev_err (vcap->dev,"%s: buffer too small (%lu < %lu)\n" , vcap->vdev.name,vb2_plane_size (vb,0 ), size);return -EINVAL ; }@@ -469,8 +473,10 @@ static const struct media_entity_operations vimc_cap_mops = { .link_validate = vimc_link_validate, }; -static void vimc_cap_destroy(struct vimc_ent_device *ved) +static void vimc_cap_comp_unbind(struct device *comp, struct device *master, + void *master_data) { +struct vimc_ent_device *ved =dev_get_drvdata (comp); struct vimc_cap_device *vcap = container_of(ved, struct
vimc_cap_device,ved); @@ -481,32 +487,25 @@ static void vimc_cap_destroy(struct vimc_ent_device *ved) kfree(vcap);}
-structvimc_ent_device*vimc_cap_create(structv4l2_device*v4l2_dev,drivers/media/platform/vimc/vimc-capture.c +1
-3-const char *const name, - u16 num_pads, - const unsigned long *pads_flag) +static int vimc_cap_comp_bind(struct device *comp, struct device*master,
drivers/media/platform/vimc/vimc-capture.c +7
-10+ void *master_data) { +struct v4l2_device *v4l2_dev = master_data; +char *name = comp->platform_data;const struct vimc_pix_map *vpix;struct vimc_cap_device *vcap;struct video_device *vdev;struct vb2_queue *q;int ret; -/* -* Check entity configuration params -* NOTE: we only support a single sink pad -*/ - if (!name || num_pads != 1 || !pads_flag || - !(pads_flag[0] & MEDIA_PAD_FL_SINK)) -return ERR_PTR (-EINVAL ); -/* Allocate the vimc_cap_device struct */ vcap =kzalloc (sizeof (*vcap),GFP_KERNEL );if (!vcap) -return ERR_PTR (-ENOMEM ); +return -ENOMEM ;/* Allocate the pads */ - vcap->ved.pads =vimc_pads_init (num_pads, pads_flag); + vcap->ved.pads = +vimc_pads_init (1 , (const unsigned long [1 ]) {MEDIA_PAD_FL_SINK });if (IS_ERR (vcap->ved.pads)) { ret =PTR_ERR (vcap->ved.pads); goto err_free_vcap;@@ -516,7 +515,7 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, vcap->vdev.entity.name = name; vcap->vdev.entity.function =MEDIA_ENT_F_IO_V4L ; ret =media_entity_pads_init (&vcap->vdev.entity, - num_pads, vcap->ved.pads); +1 , vcap->ved.pads);if (ret) goto err_clean_pads;@@ -537,8 +536,7 @@ struct
vimc_ent_device*vimc_cap_create(structv4l2_device*v4l2_dev,ret = vb2_queue_init(q); if (ret) {drivers/media/platform/vimc/vimc-capture.c +3
-3-dev_err (vcap->vdev.v4l2_dev->dev, -"%s: vb2 queue init failed (err=%d)\n" , +dev_err (comp,"%s: vb2 queue init failed (err=%d)\n" , vcap->vdev.name, ret); goto err_clean_m_ent; }@@ -555,10 +553,11 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, vcap->format.height;/* Fill the vimc_ent_device struct */ - vcap->ved.destroy = vimc_cap_destroy; vcap->ved.ent = &vcap->vdev.entity; vcap->ved.process_frame = vimc_cap_process_frame; vcap->ved.vdev_get_format = vimc_cap_get_format; +dev_set_drvdata (comp, &vcap->ved); + vcap->dev = comp;/* Initialize the video_device struct */ vdev = &vcap->vdev;@@ -577,13 +576,12 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev,/* Register the video_device with the v4l2 and the media framework */
ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); if (ret) {drivers/media/platform/vimc/vimc-capture.c +43
-2-dev_err (vcap->vdev.v4l2_dev->dev, -"%s: video register failed (err=%d)\n" , +dev_err (comp,"%s: video register failed (err=%d)\n" , vcap->vdev.name, ret); goto err_release_queue; } - return &vcap->ved; +return 0 ; err_release_queue:vb2_queue_release (q);@@ -594,5 +592,45 @@ struct vimc_ent_device *vimc_cap_create(structv4l2_device *v4l2_dev, err_free_vcap:kfree (vcap ); - return ERR_PTR(ret); +return ret; +} + +static const struct component_ops vimc_cap_comp_ops = { + .bind = vimc_cap_comp_bind, + .unbind = vimc_cap_comp_unbind, +}; + +static int vimc_cap_probe (struct platform_device *pdev) +{ +return component_add (&pdev->dev, &vimc_cap_comp_ops); } + +static int vimc_cap_remove (struct platform_device *pdev) +{ +component_del (&pdev->dev, &vimc_cap_comp_ops); + +return 0 ; +} + +static struct platform_driver vimc_cap_pdrv = { + .probe = vimc_cap_probe, + .remove = vimc_cap_remove, + .driver = { + .name =VIMC_CAP_DRV_NAME , + }, +}; + +static const struct platform_device_id vimc_cap_driver_ids[] = { + { + .name =VIMC_CAP_DRV_NAME , + }, + { } +}; + +module_platform_driver (vimc_cap_pdrv); + +MODULE_DEVICE_TABLE (platform, vimc_cap_driver_ids); + +MODULE_DESCRIPTION ("Virtual Media Controller Driver (VIMC) Capture" ); +MODULE_AUTHOR ("Helen Mae Koike Fornazier <[email protected]>" ); +MODULE_LICENSE ("GPL" );drivers/media/platform/vimc/vimc-capture.h deleted +0
-28@@ -1,28 +0,0 @@ -/* -* vimc-capture.h Virtual Media Controller Driver -* -* Copyright (C) 2015-2017 Helen Koike <[email protected]> -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -*/ - -#ifndef _VIMC_CAPTURE_H_ -#define _VIMC_CAPTURE_H_ - -#include "vimc-common.h" - -struct vimc_ent_device *vimc_cap_create (struct v4l2_device *v4l2_dev, -const char *const name, -u16 num_pads, -const unsigned long *pads_flag); - -#endif drivers/media/platform/vimc/vimc-common.c +2
-0@@ -15,6 +15,9 @@* */ +#include <linux/init.h> +#include <linux/module.h> +#include "vimc-common.h" static const struct vimc_pix_map vimc_pix_map_list[] = {drivers/media/platform/vimc/vimc-common.c const struct vimc_pix_map · line 157
Quoted 4 lines
drivers/media/platform/vimc/vimc-common.c +1
-0@@ -151,6 +154,7 @@ const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i) return &vimc_pix_map_list[i]; } +EXPORT_SYMBOL (vimc_pix_map_by_index);I would recommend using
EXPORT_SYMBOL_GPL.Quoted 298 lines
drivers/media/platform/vimc/vimc-common.c +1
-0const struct vimc_pix_map *vimc_pix_map_by_code (u32 code) {@@ -162,6 +166,7 @@ const struct vimc_pix_map *vimc_pix_map_by_code(u32 code) }return NULL ; } +EXPORT_SYMBOL (vimc_pix_map_by_code);const struct vimc_pix_map *vimc_pix_map_by_pixelformat (u32 pixelformat){drivers/media/platform/vimc/vimc-common.c +7
-16@@ -173,6 +178,7 @@ const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat) }return NULL ; } +EXPORT_SYMBOL (vimc_pix_map_by_pixelformat);int vimc_propagate_frame (struct media_pad *src,const void *frame) {@@ -207,6 +213,7 @@ int vimc_propagate_frame(struct media_pad *src, const void *frame) return 0; } +EXPORT_SYMBOL (vimc_propagate_frame);/* Helper function to allocate and initialize pads */ struct media_pad *vimc_pads_init (u16 num_pads,const unsigned long *pads_flag)@@ -227,6 +234,7 @@ struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag) return pads; } +EXPORT_SYMBOL (vimc_pads_init);int vimc_pipeline_s_stream (struct media_entity *ent,int enable) {@@ -242,14 +250,8 @@ int vimc_pipeline_s_stream(struct media_entity *ent, int enable)/* Start the stream in the subdevice direct connected */ pad =media_entity_remote_pad (&ent->pads[i]); - /* -* if this is a raw node from vimc-core, then there is -* nothing to activate -* TODO: remove this when there are no more raw nodes in the -* core and return error instead -*/ - if (pad->entity->obj_type == MEDIA_ENTITY_TYPE_BASE) - continue; +if (!is_media_entity_v4l2_subdev(pad->entity)) +return -EINVAL; sd = media_entity_to_v4l2_subdev(pad->entity); ret = v4l2_subdev_call(sd, video, s_stream, enable); @@ -259,6 +261,7 @@ int vimc_pipeline_s_stream(struct media_entity *ent, int enable)return 0 ; } +EXPORT_SYMBOL (vimc_pipeline_s_stream);static void vimc_fmt_pix_to_mbus (struct v4l2_mbus_framefmt *mfmt,struct v4l2_pix_format *pfmt)@@ -315,14 +318,6 @@ int vimc_link_validate(struct media_link *link)struct v4l2_subdev_format source_fmt, sink_fmt;int ret; - /* -* if it is a raw node from vimc-core, ignore the link for now -* TODO: remove this when there are no more raw nodes in the -* core and return error instead -*/ - if (link->source->entity->obj_type == MEDIA_ENTITY_TYPE_BASE) -return 0 ; -ret = vimc_get_mbus_format(link->source, &source_fmt); if (ret) return ret; @@ -393,8 +388,7 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,u32 function, u16 num_pads, const unsigned long *pads_flag, - const struct v4l2_subdev_ops *sd_ops, - void (*sd_destroy)(struct vimc_ent_device *)) + const struct v4l2_subdev_ops *sd_ops) { int ret; @@ -404,7 +398,6 @@ int vimc_ent_sd_register(struct vimc_ent_device*ved,
return PTR_ERR(ved->pads); /* Fill the vimc_ent_device struct */drivers/media/platform/vimc/vimc-common.c +6
-1- ved->destroy = sd_destroy; ved->ent = &sd->entity;/* Initialize the subdev */ @@ -440,6 +433,7 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,vimc_pads_cleanup (ved->pads);return ret; } +EXPORT_SYMBOL (vimc_ent_sd_register);void vimc_ent_sd_unregister (struct vimc_ent_device *ved,struct v4l2_subdev *sd) {@@ -447,3 +441,8 @@ void vimc_ent_sd_unregister(struct vimc_ent_device *ved, struct v4l2_subdev *sd)media_entity_cleanup (ved->ent);vimc_pads_cleanup (ved->pads); } +EXPORT_SYMBOL (vimc_ent_sd_unregister); + +MODULE_DESCRIPTION ("Virtual Media Controller Driver (VIMC) Common" ); +MODULE_AUTHOR ("Helen Koike <[email protected]>" ); +MODULE_LICENSE ("GPL" );drivers/media/platform/vimc/vimc-common.h +1
-2@@ -1,5 +1,5 @@/* -* vimc-ccommon.h Virtual Media Controller Driver +* vimc-common.h Virtual Media Controller Driver * * Copyright (C) 2015-2017 Helen Koike <[email protected]> * @@ -50,7 +50,6 @@ struct vimc_pix_map {* * @ent: the pointer to struct media_entity for the node * @pads: the list of pads of the node -* @destroy: callback to destroy the node * @process_frame: callback send a frame to that node * @vdev_get_format: callback that returns the current format a pad, used
* only whenis_media_entity_v4l2_video_device(ent)returnsdrivers/media/platform/vimc/vimc-common.h +0
-2@@ -67,7 +66,6 @@ struct vimc_pix_map {struct vimc_ent_device {struct media_entity *ent;struct media_pad *pads; -void (*destroy)(struct vimc_ent_device *);void (*process_frame)(struct vimc_ent_device *ved,struct media_pad *sink,const void *frame); void (*vdev_get_format)(struct vimc_ent_device *ved,@@ -152,7 +150,6 @@ const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat); * @num_pads: number of pads to initialize * @pads_flag: flags to use in each pad * @sd_ops: pointer to &struct v4l2_subdev_ops. - * @sd_destroy: callback to destroy the node * * Helper function initialize and register the struct
vimc_ent_deviceand struct
*v4l2_subdevwhich represents a subdev node in the topologydrivers/media/platform/vimc/vimc-common.h +4
-5@@ -164,14 +161,13 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, u32 function, u16 num_pads, const unsigned long *pads_flag, - const struct v4l2_subdev_ops *sd_ops, - void (*sd_destroy)(struct vimc_ent_device *)); + const struct v4l2_subdev_ops *sd_ops);/** -* vimc_ent_sd_register - initialize and register a subdev node +* vimc_ent_sd_unregister - cleanup and unregister a subdev node * -* @ved: the vimc_ent_device struct to be initialize -* @sd: the v4l2_subdev struct to be initialize and registered +* @ved: the vimc_ent_device struct to be cleaned up +* @sd: the v4l2_subdev struct to be unregistered * * Helper function cleanup and unregister the struct vimc_ent_device and struct
*v4l2_subdevwhich represents a subdev node in the topologydrivers/media/platform/vimc/vimc-core.c +4
-10@@ -15,15 +15,14 @@* */ +#include <linux/component.h>#include <linux/init.h> #include <linux/module.h> #include <linux/platform_device.h> #include <media/media-device.h> #include <media/v4l2-device.h> -#include "vimc-capture.h"#include "vimc-common.h" -#include "vimc-sensor.h" #define VIMC_PDEV_NAME "vimc"#define VIMC_MDEV_MODEL_NAME "VIMC MDEV"@@ -37,10 +36,10 @@ }struct vimc_device { -/* -* The pipeline configuration -* (filled before calling vimc_device_register) -*/ +/* The platform device */ +struct platform_device pdev; + +/* The pipeline configuration */ const struct vimc_pipeline_config *pipe_cfg;/* The Associated media_device parent */ @@ -49,43 +48,14 @@ struct vimc_device {/* Internal v4l2 parent device*/ struct v4l2_device v4l2_dev; - /* Internal topology */ - struct vimc_ent_device **ved; -}; - -/** -* enum vimc_ent_node - Select the functionality of a node in the topology
- * @VIMC_ENT_NODE_SENSOR: A node of type SENSOR simulates a camera
sensor
- * generating internal images in bayer format and
- * propagating those images through the pipeline
- * @VIMC_ENT_NODE_CAPTURE: A node of type CAPTURE is a v4l2video_device
- * that exposes the received image from the
- * pipeline to the user space
- * @VIMC_ENT_NODE_INPUT: A node of type INPUT is a v4l2video_devicethat
- * receives images from the user space and
- * propagates them through the pipeline
- * @VIMC_ENT_NODE_DEBAYER: A node type DEBAYER expects to receive
a frame
- * in bayer format converts it to RGB
- * @VIMC_ENT_NODE_SCALER: A node of type SCALER scales the
received image
- * by a given multiplier
- *
- * This enum is used in the entity configuration struct to allow the definition
- * of a custom topology specifying the role of each node on it.
- */drivers/media/platform/vimc/vimc-core.c +2
-6-enum vimc_ent_node { -VIMC_ENT_NODE_SENSOR , -VIMC_ENT_NODE_CAPTURE , -VIMC_ENT_NODE_INPUT , -VIMC_ENT_NODE_DEBAYER , -VIMC_ENT_NODE_SCALER , +/* Subdevices */ +struct platform_device **subdevs; };/* Structure which describes individual configuration for each entity */
struct vimc_ent_config { const char *name;drivers/media/platform/vimc/vimc-core.c +7
-25-size_t pads_qty; -const unsigned long *pads_flag; -enum vimc_ent_node node; +const char *drv; };/* Structure which describes links between entities */ @@ -112,60 +82,40 @@ struct vimc_pipeline_config {static const struct vimc_ent_config ent_config[] = { { .name ="Sensor A" , - .pads_qty =1 , - .pads_flag = (const unsigned long []){MEDIA_PAD_FL_SOURCE }, - .node =VIMC_ENT_NODE_SENSOR , + .drv ="vimc-sensor" , }, { .name ="Sensor B" , - .pads_qty =1 , - .pads_flag = (const unsigned long []){MEDIA_PAD_FL_SOURCE }, - .node =VIMC_ENT_NODE_SENSOR , + .drv ="vimc-sensor" , }, { .name ="Debayer A" , - .pads_qty =2 , - .pads_flag = (const unsigned long []){MEDIA_PAD_FL_SINK , -MEDIA_PAD_FL_SOURCE }, - .node =VIMC_ENT_NODE_DEBAYER , + .drv ="vimc-debayer" , }, { .name ="Debayer B" , - .pads_qty =2 , - .pads_flag = (const unsigned long []){MEDIA_PAD_FL_SINK , -MEDIA_PAD_FL_SOURCE }, - .node =VIMC_ENT_NODE_DEBAYER , + .drv ="vimc-debayer" , }, { .name ="Raw Capture 0" , - .pads_qty =1 , - .pads_flag = (const unsigned long []){MEDIA_PAD_FL_SINK }, - .node =VIMC_ENT_NODE_CAPTURE , + .drv ="vimc-capture" , }, { .name ="Raw Capture 1" , - .pads_qty =1 , - .pads_flag = (const unsigned long []){MEDIA_PAD_FL_SINK }, - .node =VIMC_ENT_NODE_CAPTURE , + .drv ="vimc-capture" , }, { .name ="RGB/YUV Input" , - .pads_qty =1 , - .pads_flag = (const unsigned long []){MEDIA_PAD_FL_SOURCE },
Quoted 8 lines
drivers/media/platform/vimc/vimc-core.c struct vimc_pipeline_config { · line 110
Quoted 3 lines
drivers/media/platform/vimc/vimc-core.c +2
-1- .node = VIMC_ENT_NODE_INPUT, +/* TODO: change to vimc-output when output is implemented */ + .drv = "vimc-sensor",This is confusing: the name indicates an input, but the TODO indicates an output. I assume this is supposed to emulate e.g. an HDMI input? I'm not sure
the TODO text makes sense here.
You are right, I was confused about input/output in the pov of kernel or userspace and I was with HDMI output in mind (I even implement it, I'll send in the next patch series). I'll change this comment to "change to vimc-input when input is implemented"
Quoted 272 lines
Quoted 272 lines
drivers/media/platform/vimc/vimc-core.c +2
-7}, { .name = "Scaler", - .pads_qty = 2, - .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SINK, - MEDIA_PAD_FL_SOURCE}, - .node = VIMC_ENT_NODE_SCALER, + .drv = "vimc-scaler", }, { .name = "RGB/YUV Capture", - .pads_qty = 1, - .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SINK}, - .node = VIMC_ENT_NODE_CAPTURE, + .drv = "vimc-capture", }, }; @@ -197,111 +147,40 @@ static const struct vimc_pipeline_configpipe_cfg = { /*--------------------------------------------------------------------------
*/
-static voidvimc_device_unregister(struct vimc_device *vimc)drivers/media/platform/vimc/vimc-core.c +1
-35+static int vimc_create_links (struct vimc_device *vimc) {unsigned int i; - -media_device_unregister (&vimc->mdev); -/* Cleanup (only initialized) entities */ -for (i =0 ; i < vimc->pipe_cfg->num_ents; i++) { -if (vimc->ved[i] && vimc->ved[i]->destroy) - vimc->ved[i]->destroy (vimc->ved[i]); - - vimc->ved[i] =NULL ; - } -v4l2_device_unregister (&vimc->v4l2_dev); -media_device_cleanup (&vimc->mdev); -} - -/* -* TODO: remove this function when all the -* entities specific code are implemented -*/ -static void vimc_raw_destroy (struct vimc_ent_device *ved) -{ -media_device_unregister_entity (ved->ent); - -media_entity_cleanup (ved->ent); - -vimc_pads_cleanup (ved->pads); - -kfree (ved->ent); - -kfree (ved); -} - -/* -* TODO: remove this function when all the -* entities specific code are implemented -*/ -static struct vimc_ent_device *vimc_raw_create(struct v4l2_device
*v4l2_dev,drivers/media/platform/vimc/vimc-core.c +65
-108-const char *const name, - u16 num_pads, - const unsigned long *pads_flag) -{ - struct vimc_ent_device *ved;int ret; -/* Allocate the main ved struct */ - ved =kzalloc (sizeof (*ved),GFP_KERNEL ); -if (!ved) -return ERR_PTR (-ENOMEM ); - -/* Allocate the media entity */ - ved->ent =kzalloc (sizeof (*ved->ent),GFP_KERNEL ); -if (!ved->ent) { - ret = -ENOMEM ; - goto err_free_ved; - } - -/* Allocate the pads */ - ved->pads =vimc_pads_init (num_pads, pads_flag); -if (IS_ERR (ved->pads)) { - ret =PTR_ERR (ved->pads); - goto err_free_ent; +/* Initialize the links between entities */ + for (i = 0; i < vimc->pipe_cfg->num_links; i++) { +const struct vimc_ent_link *link = &vimc->pipe_cfg->links[i]; +/* +* TODO: Check another way of retrieving ved struct without +* relying on platform_get_drvdata +*/ +struct vimc_ent_device *ved_src = +platform_get_drvdata (vimc->subdevs[link->src_ent]); +struct vimc_ent_device *ved_sink = +platform_get_drvdata (vimc->subdevs[link->sink_ent]); + + ret =media_create_pad_link (ved_src->ent, link->src_pad, + ved_sink->ent, link->sink_pad, + link->flags); +if (ret) +return ret; } -/* Initialize the media entity */ - ved->ent->name = name; - ved->ent->function =MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN ; - ret =media_entity_pads_init (ved->ent, num_pads, ved->pads); -if (ret) - goto err_cleanup_pads; - -/* Register the media entity */ - ret =media_device_register_entity (v4l2_dev->mdev, ved->ent); -if (ret) - goto err_cleanup_entity; - -/* Fill out the destroy function and return */ - ved->destroy = vimc_raw_destroy; -return ved; - -err_cleanup_entity: -media_entity_cleanup (ved->ent); -err_cleanup_pads: -vimc_pads_cleanup (ved->pads); -err_free_ent: -kfree (ved->ent); -err_free_ved: -kfree (ved); - -return ERR_PTR (ret); + return 0; } -static int vimc_device_register(struct vimc_device *vimc) +static int vimc_comp_bind(struct device *master) { -unsigned int i; +struct vimc_device *vimc =container_of (to_platform_device (master), + struct vimc_device, pdev);int ret; -/* Allocate memory for the vimc_ent_devices pointers */ - vimc->ved =devm_kcalloc (vimc->mdev.dev, vimc->pipe_cfg->num_ents, -sizeof (*vimc->ved),GFP_KERNEL ); -if (!vimc->ved) -return -ENOMEM ; - -/* Link the media device within the v4l2_device */ - vimc->v4l2_dev.mdev = &vimc->mdev; +dev_dbg (master,"bind" );/* Register the v4l2 struct */ ret =v4l2_device_register (vimc->mdev.dev, &vimc->v4l2_dev);@@ -311,66 +190,22 @@ static int vimc_device_register(struct vimc_device *vimc)return ret; } -/* Initialize entities */ - for (i = 0; i < vimc->pipe_cfg->num_ents; i++) { -struct vimc_ent_device *(*create_func)(struct v4l2_device *, -const char *const , -u16 , -const unsigned long *); - -/* Register the specific node */ -switch (vimc->pipe_cfg->ents[i].node) { -case VIMC_ENT_NODE_SENSOR : - create_func = vimc_sen_create; -break ; - -case VIMC_ENT_NODE_CAPTURE : - create_func = vimc_cap_create; -break ; - -/* TODO: Instantiate the specific topology node */ -case VIMC_ENT_NODE_INPUT : -case VIMC_ENT_NODE_DEBAYER : -case VIMC_ENT_NODE_SCALER : -default : -/* -* TODO: remove this when all the entities specific -* code are implemented -*/ - create_func = vimc_raw_create; -break ; - } - - vimc->ved[i] =create_func (&vimc->v4l2_dev, - vimc->pipe_cfg->ents[i].name, - vimc->pipe_cfg->ents[i].pads_qty, - vimc->pipe_cfg->ents[i].pads_flag); -if (IS_ERR (vimc->ved[i])) { - ret =PTR_ERR (vimc->ved[i]); - vimc->ved[i] =NULL ; - goto err; - } - } - -/* Initialize the links between entities */ -for (i =0 ; i < vimc->pipe_cfg->num_links; i++) { -const struct vimc_ent_link *link = &vimc->pipe_cfg->links[i]; +/* Bind subdevices */ + ret =component_bind_all (master, &vimc->v4l2_dev); +if (ret) + goto err_v4l2_unregister; - ret =media_create_pad_link (vimc->ved[link->src_ent]->ent, - link->src_pad, - vimc->ved[link->sink_ent]->ent, - link->sink_pad, - link->flags); -if (ret) - goto err; - } +/* Initialize links */ + ret = vimc_create_links(vimc); +if (ret) + goto err_comp_unbind_all;/* Register the media device */ ret =media_device_register (&vimc->mdev);if (ret) {dev_err (vimc->mdev.dev,"media device register failed (err=%d)\n" , ret); -return ret; + goto err_comp_unbind_all; }/* Expose all subdev's nodes*/ @@ -379,32 +214,107 @@ static int vimc_device_register(struct vimc_device *vimc) dev_err(vimc->mdev.dev,"vimc subdev nodes registration failed (err=%d)\n" , ret); - goto err; + goto err_mdev_unregister; }return 0 ; -err: -/* Destroy the so far created topology */ -vimc_device_unregister (vimc); +err_mdev_unregister: +media_device_unregister (&vimc->mdev); +err_comp_unbind_all: +component_unbind_all (master,NULL ); +err_v4l2_unregister: +v4l2_device_unregister (&vimc->v4l2_dev);return ret; } +static void vimc_comp_unbind(struct device *master) +{ +struct vimc_device *vimc =container_of (to_platform_device (master), + struct vimc_device, pdev); + +dev_dbg (master,"unbind" ); + +media_device_unregister (&vimc->mdev); +component_unbind_all (master,NULL ); +v4l2_device_unregister (&vimc->v4l2_dev); +} + +static int vimc_comp_compare (struct device *comp,void *data) +{ +const struct platform_device *pdev =to_platform_device (comp); +const char *name = data; + +return !strcmp (pdev->dev.platform_data, name); +} + +static struct component_match *vimc_add_subdevs (struct vimc_device *vimc) +{ +struct component_match *match =NULL ; +unsigned int i; + +for (i =0 ; i < vimc->pipe_cfg->num_ents; i++) { +dev_dbg (&vimc->pdev.dev,"new pdev for %s\n" , + vimc->pipe_cfg->ents[i].drv);
Quoted 8 lines
drivers/media/platform/vimc/vimc-core.c static int vimc_device_register(struct vimc_device *vimc) · line 265
Quoted 6 lines
drivers/media/platform/vimc/vimc-core.c +6
-0+ +/* +* TODO: check if using platform_data is indeed the best way to +* pass the name to the driver or if we should add the drv name +* in the platform_device_id table +*/ Didn't you set the drv name in the
platform_device_idtable already?
I refer to the name of the entity, there is the name that identifies the driver as "vimc-sensor" that is set in the platform_device_id table but there is also the custom name of the entity e.g. "My Sensor A" that I need to inform to the vimc-sensor driver.
Quoted 2 lines
Using
platform_datafeels like an abuse to be honest.
Another option would be to make the vimc-sensor driver to populate the entity name automatically as "Sensor x", where x could be the entity number, but I don't think this is a good option.
Quoted 6 lines
Creating these components here makes sense. Wouldn't it also make sense to use
v4l2_asyncto wait until they have all been bound? It would more closely emulate
standard drivers. Apologies if I misunderstand what is happening here.
I am using linux/component.h for that, when all devices are present and all modules are loaded, the component.h system brings up the core by calling vimc_comp_bind() function, which calls component_bind_all() to call the binding function of each module, then it finishes registering the topology. If any one of the components or module is unload, the component system takes down the entire topology calling component_unbind_all which calls the unbind functions from each module.
This makes sure that the media device, subdevices and video device are only registered in the v4l2 system if all the modules are loaded.
I wans't familiar with v4l2-async.h, but from a quick look it seems that it only works with struct v4l2_subdev, but I'll also need for struct video_device (for the capture node for example). And also, if a module is missing we would have vimc partially registered, e.g. the debayer could be registered at /dev/subdevX but the sensor not yet and the media wouldn't be ready, I am not sure if this is a problem though.
Maybe we can use component.h for now, then I can implement v4l2_async_{un}register_video_device and migrate to v4l2-sync.h latter. What do you think?
Quoted 343 lines
Quoted 330 lines
drivers/media/platform/vimc/vimc-core.c +68
-18+ vimc->subdevs[i] =platform_device_register_data (&vimc->pdev.dev, + vimc->pipe_cfg->ents[i].drv, +PLATFORM_DEVID_AUTO , + vimc->pipe_cfg->ents[i].name, +strlen (vimc->pipe_cfg->ents[i].name) +1 ); +if (!vimc->subdevs[i]) { +while (--i >=0 ) +platform_device_unregister (vimc->subdevs[i]); + +return ERR_PTR (-ENOMEM ); + } + +component_match_add (&vimc->pdev.dev, &match, vimc_comp_compare, + (void *)vimc->pipe_cfg->ents[i].name); + } + +return match; +} + +static void vimc_rm_subdevs (struct vimc_device *vimc) +{ +unsigned int i; + +for (i =0 ; i < vimc->pipe_cfg->num_ents; i++) +platform_device_unregister (vimc->subdevs[i]); +} + +static const struct component_master_ops vimc_comp_ops = { + .bind = vimc_comp_bind, + .unbind = vimc_comp_unbind, +}; +static int vimc_probe (struct platform_device *pdev) { - struct vimc_device *vimc; + struct vimc_device *vimc = container_of(pdev, struct vimc_device, pdev); +struct component_match *match =NULL ;int ret; -/* Prepare the vimc topology structure */ +dev_dbg (&pdev->dev,"probe" ); -/* Allocate memory for the vimc structure */ - vimc = kzalloc(sizeof(*vimc), GFP_KERNEL); - if (!vimc) +/* Create platform_device for each entity in the topology*/ + vimc->subdevs =devm_kcalloc (&vimc->pdev.dev, vimc->pipe_cfg->num_ents, +sizeof (*vimc->subdevs),GFP_KERNEL ); +if (!vimc->subdevs)return -ENOMEM ; -/* Set the pipeline configuration struct */ - vimc->pipe_cfg = &pipe_cfg; + match =vimc_add_subdevs (vimc); +if (IS_ERR (match)) +return PTR_ERR (match); + +/* Link the media device within the v4l2_device */ + vimc->v4l2_dev.mdev = &vimc->mdev;/* Initialize media device */ strlcpy(vimc->mdev.model, VIMC_MDEV_MODEL_NAME,@@ -412,28 +322,27 @@ static int vimc_probe(struct platform_device *pdev) vimc->mdev.dev = &pdev->dev;media_device_init (&vimc->mdev); -/* Create vimc topology */ - ret =vimc_device_register (vimc); +/* Add self to the component system */ + ret =component_master_add_with_match (&pdev->dev, &vimc_comp_ops, + match);if (ret) { -dev_err (vimc->mdev.dev, -"vimc device registration failed (err=%d)\n" , ret); +media_device_cleanup (&vimc->mdev); +vimc_rm_subdevs (vimc);kfree (vimc);return ret; } -/* Link the topology object with the platform device object */ -platform_set_drvdata (pdev, vimc); - return 0; }static int vimc_remove (struct platform_device *pdev) { -struct vimc_device *vimc =platform_get_drvdata (pdev); + struct vimc_device *vimc = container_of(pdev, struct vimc_device, pdev); -/* Destroy all the topology */ -vimc_device_unregister (vimc); -kfree (vimc); +dev_dbg (&pdev->dev,"remove" ); + +component_master_del (&pdev->dev, &vimc_comp_ops); +vimc_rm_subdevs (vimc);return 0 ; }@@ -442,9 +351,12 @@ static void vimc_dev_release(struct device *dev) { } -static struct platform_device vimc_pdev = { - .name =VIMC_PDEV_NAME , - .dev.release = vimc_dev_release, +static struct vimc_device vimc_dev = { + .pipe_cfg = &pipe_cfg, + .pdev = { + .name =VIMC_PDEV_NAME , + .dev.release = vimc_dev_release, + } }; static struct platform_driver vimc_pdrv = {@@ -459,29 +371,29 @@ static int __init vimc_init(void) {int ret; - ret =platform_device_register (&vimc_pdev); + ret =platform_device_register (&vimc_dev.pdev);if (ret) { -dev_err (&vimc_pdev.dev, +dev_err (&vimc_dev.pdev.dev,"platform device registration failed (err=%d)\n" , ret);return ret; } ret =platform_driver_register (&vimc_pdrv);if (ret) { -dev_err (&vimc_pdev.dev, +dev_err (&vimc_dev.pdev.dev,"platform driver registration failed (err=%d)\n" , ret); - -platform_device_unregister (&vimc_pdev); +platform_driver_unregister (&vimc_pdrv); +return ret; } - return ret; +return 0 ; } static void __exit vimc_exit(void) {platform_driver_unregister (&vimc_pdrv); -platform_device_unregister (&vimc_pdev); +platform_device_unregister (&vimc_dev.pdev); }module_init (vimc_init);drivers/media/platform/vimc/vimc-sensor.c +6
-0@@ -15,15 +15,19 @@* */ -#include <linux/module.h> +#include <linux/component.h> #include <linux/freezer.h> #include <linux/kthread.h> +#include <linux/module.h> +#include <linux/platform_device.h> #include <linux/v4l2-mediabus.h> #include <linux/vmalloc.h> #include <media/v4l2-subdev.h> #include <media/v4l2-tpg.h> -#include "vimc-sensor.h" +#include "vimc-common.h" + +#define VIMC_SEN_DRV_NAME "vimc-sensor"static bool vsen_tpg;module_param (vsen_tpg, bool,0000 );@@ -35,6 +39,7 @@ MODULE_PARM_DESC(vsen_tpg, " generate image fromsensor node\n"
struct vimc_sen_device { struct vimc_ent_device ved; struct v4l2_subdev sd;drivers/media/platform/vimc/vimc-sensor.c +4
-2+struct device *dev;struct tpg_data tpg;struct task_struct *kthread_sen;u8 *frame;@@ -189,7 +194,7 @@ static int vimc_sen_set_fmt(struct v4l2_subdev *sd,/* Set the new format */ vimc_sen_adjust_fmt (&fmt->format); - dev_dbg(vsen->sd.v4l2_dev->mdev->dev, "%s: format update: " + dev_dbg(vsen->dev, "%s: format update: " "old:%dx%d (0x%x, %d, %d, %d, %d) " "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsen->sd.name,/* old */ @@ -282,8 +287,8 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) vsen->kthread_sen =kthread_run (vimc_sen_tpg_thread, vsen,"%s-sen" , vsen->sd.v4l2_dev->name);if (IS_ERR (vsen->kthread_sen)) { -dev_err (vsen->sd.v4l2_dev->dev, -"%s: kernel_thread() failed\n" , vsen->sd.name); +dev_err (vsen->dev,"%s: kernel_thread() failed\n" , + vsen->sd.name);vfree (vsen->frame); vsen->frame =NULL ;return PTR_ERR(vsen->kthread_sen);drivers/media/platform/vimc/vimc-sensor.c +3
-0@@ -315,8 +320,10 @@ static const struct v4l2_subdev_ops vimc_sen_ops = { .video = &vimc_sen_video_ops, }; -static void vimc_sen_destroy(struct vimc_ent_device *ved) +static void vimc_sen_comp_unbind(struct device *comp, struct device *master, + void *master_data) { +struct vimc_ent_device *ved =dev_get_drvdata (comp);struct vimc_sen_device *vsen = container_of(ved, struct vimc_sen_device, ved); @@ -326,36 +333,30 @@ static void vimc_sen_destroy(struct
vimc_ent_device*ved)kfree(vsen);}
-structvimc_ent_device*vimc_sen_create(structv4l2_device*v4l2_dev,drivers/media/platform/vimc/vimc-sensor.c +1
-3-const char *const name, - u16 num_pads, - const unsigned long *pads_flag) +static int vimc_sen_comp_bind(struct device *comp, struct device*master,
drivers/media/platform/vimc/vimc-sensor.c +9
-12+ void *master_data) { +struct v4l2_device *v4l2_dev = master_data; +char *name = comp->platform_data;struct vimc_sen_device *vsen; -unsigned int i;int ret; -/* NOTE: a sensor node may be created with more then one pad */ - if (!name || !num_pads || !pads_flag) -return ERR_PTR (-EINVAL ); - -/* check if all pads are sources */ -for (i =0 ; i < num_pads; i++) -if (!(pads_flag[i] &MEDIA_PAD_FL_SOURCE )) -return ERR_PTR (-EINVAL ); -/* Allocate the vsen struct */ vsen =kzalloc (sizeof (*vsen),GFP_KERNEL );if (!vsen) -return ERR_PTR (-ENOMEM ); +return -ENOMEM ;/* Initialize ved and sd */ ret =vimc_ent_sd_register (&vsen->ved, &vsen->sd, v4l2_dev, name, -MEDIA_ENT_F_CAM_SENSOR , num_pads, pads_flag, - &vimc_sen_ops, vimc_sen_destroy); +MEDIA_ENT_F_ATV_DECODER ,1 , + (const unsigned long [1 ]) {MEDIA_PAD_FL_SOURCE }, + &vimc_sen_ops);if (ret) goto err_free_vsen; +dev_set_drvdata (comp, &vsen->ved); + vsen->dev = comp; +/* Initialize the frame format */ vsen->mbus_format = fmt_default; @@ -368,12 +369,52 @@ struct vimc_ent_device *vimc_sen_create(struct
v4l2_device*v4l2_dev,goto err_unregister_ent_sd; }- return
&vsen->ved;drivers/media/platform/vimc/vimc-sensor.c +42
-0+return 0 ; err_unregister_ent_sd:vimc_ent_sd_unregister (&vsen->ved, &vsen->sd); err_free_vsen:kfree (vsen); - return ERR_PTR(ret); +return ret; +} + +static const struct component_ops vimc_sen_comp_ops = { + .bind = vimc_sen_comp_bind, + .unbind = vimc_sen_comp_unbind, +}; + +static int vimc_sen_probe (struct platform_device *pdev) +{ +return component_add (&pdev->dev, &vimc_sen_comp_ops); } + +static int vimc_sen_remove (struct platform_device *pdev) +{ +component_del (&pdev->dev, &vimc_sen_comp_ops); + +return 0 ; +} + +static struct platform_driver vimc_sen_pdrv = { + .probe = vimc_sen_probe, + .remove = vimc_sen_remove, + .driver = { + .name =VIMC_SEN_DRV_NAME , + }, +}; + +static const struct platform_device_id vimc_sen_driver_ids[] = { + { + .name =VIMC_SEN_DRV_NAME , + }, + { } +}; + +module_platform_driver (vimc_sen_pdrv); + +MODULE_DEVICE_TABLE (platform, vimc_sen_driver_ids); + +MODULE_DESCRIPTION ("Virtual Media Controller Driver (VIMC) Sensor" ); +MODULE_AUTHOR ("Helen Mae Koike Fornazier <[email protected]>" ); +MODULE_LICENSE ("GPL" );drivers/media/platform/vimc/vimc-sensor.h deleted +0
-18@@ -1,28 +0,0 @@ -/* -* vimc-sensor.h Virtual Media Controller Driver -* -* Copyright (C) 2015-2017 Helen Koike <[email protected]> -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -*/ - -#ifndef _VIMC_SENSOR_H_drivers/media/platform/vimc/vimc-sensor.h line 28
Quoted 10 lines
drivers/media/platform/vimc/vimc-sensor.h deleted +0
-10-#define _VIMC_SENSOR_H_ - -#include "vimc-common.h" - -struct vimc_ent_device *vimc_sen_create (struct v4l2_device *v4l2_dev, -const char *const name, -u16 num_pads, -const unsigned long *pads_flag); - -#endif Regards,
Quoted 1 line
Hans
Thanks
Helen
Re: [RFC PATCH v3 09/11] [media] vimc: Subdevices as modules
Quoted 24 lines · Helen Koike
Hi Hans,
Thank you for your review. Please check my comments below
Quoted 10 lines · Hans Verkuil
Quoted 9 lines · Helen Koike
+static struct
component_match*vimc_add_subdevs(structvimc_device*vimc)drivers/media/platform/vimc/vimc-core.c +7
-0+{ +struct component_match *match =NULL ; +unsigned int i; + +for (i =0 ; i < vimc->pipe_cfg->num_ents; i++) { +dev_dbg (&vimc->pdev.dev,"new pdev for %s\n" , + vimc->pipe_cfg->ents[i].drv);Quoted 8 lines
drivers/media/platform/vimc/vimc-core.c static int vimc_device_register(struct vimc_device *vimc) · line 265
Quoted 6 lines
drivers/media/platform/vimc/vimc-core.c +6
-0+ +/* +* TODO: check if using platform_data is indeed the best way to +* pass the name to the driver or if we should add the drv name +* in the platform_device_id table +*/ Didn't you set the drv name in the
platform_device_idtable already?
Quoted 4 lines
I refer to the name of the entity, there is the name that identifies the driver as "vimc-sensor" that is set in the
platform_device_idtable but there is also the custom name of the entity e.g. "My Sensor A" that I need to inform to the vimc-sensor driver.
Ah, so in the TODO you mean:
"the best way to pass the entity name to the driver"
I got confused there.
But in that case I still don't get what you mean with "add the drv name in the platform_device_id table". Do you mean "entity name" there as well?
Quoted 7 lines
Quoted 3 lines
Using
platform_datafeels like an abuse to be honest.Another option would be to make the vimc-sensor driver to populate the entity name automatically as "Sensor x", where x could be the entity number, but I don't think this is a good option.
Why not? Well, probably not the entity number, but a simple instance counter would do fine (i.e. Sensor 1, 2, 3...).
It can be made fancier later with dynamic reconfiguration where you might want to use the first unused instance number.
Quoted 27 lines
Quoted 7 lines
Creating these components here makes sense. Wouldn't it also make sense to use
v4l2_asyncto wait until they have all been bound? It would more closely emulate
standard drivers. Apologies if I misunderstand what is happening here.I am using
linux/component.hfor that, when all devices are present and all modules are loaded, thecomponent.hsystem brings up the core by callingvimc_comp_bind()function, which callscomponent_bind_all()to call the binding function of each module, then it finishes registering the topology.
If any one of the components or module is unload, the component system takes down the entire topology callingcomponent_unbind_allwhich calls the unbind functions from each module.
This makes sure that the media device, subdevices and video device are only registered in the v4l2 system if all the modules are loaded.I wans't familiar with
v4l2-async.h, but from a quick look it seems that it only works with structv4l2_subdev, but I'll also need for structvideo_device(for the capture node for example).
And also, if a module is missing we would have vimc partially registered, e.g. the debayer could be registered at/dev/subdevXbut the sensor not yet and the media wouldn't be ready, I am not sure if this is a problem though.
Quoted 3 lines
Maybe we can use
component.hfor now, then I can implement v4l2_async_{un}register_video_device and migrate tov4l2-sync.hlatter. What do you think?
That's OK. The v4l2-async mechanism precedes the component API. We should probably investigate moving over to the component API. I seem to remember that it didn't have all the features we needed, but it's a long time ago since someone looked at that and whatever the objections were, they may no longer be true.
Regards,
Hans
Re: [RFC PATCH v3 09/11] [media] vimc: Subdevices as modules
Hi Hans,
Quoted 27 lines · Hans Verkuil
Quoted 26 lines · Helen Koike
Hi Hans,
Thank you for your review. Please check my comments below
Quoted 20 lines · Hans Verkuil
Quoted 15 lines · Helen Koike
+static struct
component_match*vimc_add_subdevs(structvimc_device*vimc)drivers/media/platform/vimc/vimc-core.c +10
-0+{ +struct component_match *match =NULL ; +unsigned int i; + +for (i =0 ; i < vimc->pipe_cfg->num_ents; i++) { +dev_dbg (&vimc->pdev.dev,"new pdev for %s\n" , + vimc->pipe_cfg->ents[i].drv); + +/* +* TODO: check if using platform_data is indeed the best way to
+ * pass the name to the driver or if we should add the drv
namedrivers/media/platform/vimc/vimc-core.c static int vimc_device_register(struct vimc_device *vimc) · line 265
Quoted 2 lines
drivers/media/platform/vimc/vimc-core.c +2
-0+* in the platform_device_id table +*/ Didn't you set the drv name in the
platform_device_idtable already?
Quoted 8 lines
Quoted 4 lines
I refer to the name of the entity, there is the name that identifies the driver as "vimc-sensor" that is set in the
platform_device_idtable but there is also the custom name of the entity e.g. "My Sensor A" that I need to inform to the vimc-sensor driver.Ah, so in the TODO you mean:
"the best way to pass the entity name to the driver"
Yes
Quoted 2 lines
I got confused there.
Sorry about that, I'll improve this comment (if we don't decide to remove it)
Quoted 4 lines
But in that case I still don't get what you mean with "add the drv name in the
platform_device_idtable". Do you mean "entity name" there as well?
Yes, it is because there is a member of the platform_device_id table called driver_data and I was wondering if this would be more appropriated then using the platform_data.
Under Documentation/driver-model/platform.txt it is written:
"In many cases, the memory and IRQ resources associated with the platform device are not enough to let the device's driver work. Board setup code will often provide additional information using the device's platform_data
field to hold additional information."
So I thought that using platform_data to pass the entity's name to the driver would be acceptable as it seems to be a "Board setup code" for vimc
Quoted 11 lines
Quoted 8 lines
Quoted 4 lines
Using
platform_datafeels like an abuse to be honest.Another option would be to make the vimc-sensor driver to populate the entity name automatically as "Sensor x", where x could be the entity number, but I don't think this is a good option.
Why not? Well, probably not the entity number, but a simple instance counter would do fine (i.e. Sensor 1, 2, 3...).
Because I usually use tests scripts that configure the right pad image format to a specific entity's name using media-ctl, I would like an assurance that what identifies the entity doesn't change (that doesn't depend on the order they are inserted), and I thought that applications in userspace might want the same.
Quoted 3 lines
It can be made fancier later with dynamic reconfiguration where you might want to use the first unused instance number.
We could use configfs for that, but I was wondering what the names of the folders that represent an entity would mean, if the user do
$ mkdir vimc-sensor-foo $ mkdir vimc-sensor-bar Then foo and bar would unused names as the entities would be first created under the names "Sensor 1" and "Sensor 2", I think it would be nice if they were created as "Sensor foo" and "Sensor bar".
Quoted 32 lines
Quoted 28 lines
Quoted 8 lines
Creating these components here makes sense. Wouldn't it also make sense to use
v4l2_asyncto wait until they have all been bound? It would more closely emulate
standard drivers. Apologies if I misunderstand what is happening here.I am using
linux/component.hfor that, when all devices are present and all modules are loaded, thecomponent.hsystem brings up the core by callingvimc_comp_bind()function, which callscomponent_bind_all()to call the binding function of each module, then it finishes registering the topology.
If any one of the components or module is unload, the component system takes down the entire topology callingcomponent_unbind_allwhich calls the unbind functions from each module.
This makes sure that the media device, subdevices and video device are only registered in the v4l2 system if all the modules are loaded.I wans't familiar with
v4l2-async.h, but from a quick look it seems that it only works with structv4l2_subdev, but I'll also need for structvideo_device(for the capture node for example).
And also, if a module is missing we would have vimc partially registered, e.g. the debayer could be registered at/dev/subdevXbut the sensor not yet and the media wouldn't be ready, I am not sure if this is a problem though.Quoted 3 lines
Maybe we can use
component.hfor now, then I can implement v4l2_async_{un}register_video_device and migrate tov4l2-sync.hlatter. What do you think?
Quoted 5 lines
That's OK. The v4l2-async mechanism precedes the component API. We should probably investigate moving over to the component API. I seem to remember that it didn't have all the features we needed, but it's a long time ago since someone looked at that and whatever the objections were, they may no longer be true.
I see, I can try to take a look on this.
Quoted 4 lines
Regards,
Hans
Thanks
Helen
Re: [RFC PATCH v3 09/11] [media] vimc: Subdevices as modules
Quoted 63 lines · Helen Koike
Hi Hans,
Quoted 27 lines · Hans Verkuil
Quoted 26 lines · Helen Koike
Hi Hans,
Thank you for your review. Please check my comments below
Quoted 20 lines · Hans Verkuil
Quoted 15 lines · Helen Koike
+static struct
component_match*vimc_add_subdevs(structvimc_device*vimc)drivers/media/platform/vimc/vimc-core.c +10
-0+{ +struct component_match *match =NULL ; +unsigned int i; + +for (i =0 ; i < vimc->pipe_cfg->num_ents; i++) { +dev_dbg (&vimc->pdev.dev,"new pdev for %s\n" , + vimc->pipe_cfg->ents[i].drv); + +/* +* TODO: check if using platform_data is indeed the best way to
+ * pass the name to the driver or if we should add the drv
namedrivers/media/platform/vimc/vimc-core.c static int vimc_device_register(struct vimc_device *vimc) · line 265
Quoted 2 lines
drivers/media/platform/vimc/vimc-core.c +2
-0+* in the platform_device_id table +*/ Didn't you set the drv name in the
platform_device_idtable already?Quoted 8 lines
Quoted 4 lines
I refer to the name of the entity, there is the name that identifies the driver as "vimc-sensor" that is set in the
platform_device_idtable but there is also the custom name of the entity e.g. "My Sensor A" that I need to inform to the vimc-sensor driver.Ah, so in the TODO you mean:
"the best way to pass the entity name to the driver"
Yes
Quoted 2 lines
I got confused there.
Sorry about that, I'll improve this comment (if we don't decide to remove it)
Quoted 4 lines
But in that case I still don't get what you mean with "add the drv name in the
platform_device_idtable". Do you mean "entity name" there as well?Yes, it is because there is a member of the
platform_device_idtable calleddriver_dataand I was wondering if this would be more appropriated then using theplatform_data.Under
Documentation/driver-model/platform.txtit is written:
"In many cases, the memory and IRQ resources associated with the platform device are not enough to let the device's driver work. Board setup code
will often provide additional information using the device'splatform_datafield to hold additional information."
Quoted 2 lines
So I thought that using
platform_datato pass the entity's name to the driver would be acceptable as it seems to be a "Board setup code" for vimc
OK, now I understand. I am OK with this, but I would prefer if you made a proper struct for this:
struct vimc_platform_data {
char entity_name[32];
};Then point platform_data to that. Also comment clearly why you do it.
Part of the confusion comes from the fact that this is unusual for MC
devices: they all use the device tree instead of platform_data, so seeing platform_data being used in something like this is unexpected.
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines
Quoted 5 lines
Using
platform_datafeels like an abuse to be honest.Another option would be to make the vimc-sensor driver to populate the entity name automatically as "Sensor x", where x could be the entity number, but I don't think this is a good option.
Quoted 8 lines
Quoted 2 lines
Why not? Well, probably not the entity number, but a simple instance counter would do fine (i.e. Sensor 1, 2, 3...).
Because I usually use tests scripts that configure the right pad image format to a specific entity's name using media-ctl, I would like an assurance that what identifies the entity doesn't change (that doesn't depend on the order they are inserted), and I thought that applications in userspace might want the same.
Good point!
Quoted 45 lines
Quoted 4 lines
It can be made fancier later with dynamic reconfiguration where you might want to use the first unused instance number.
We could use configfs for that, but I was wondering what the names of the folders that represent an entity would mean, if the user do
$ mkdir vimc-sensor-foo $ mkdir vimc-sensor-bar Then foo and bar would unused names as the entities would be first created under the names "Sensor 1" and "Sensor 2", I think it would be nice if they were created as "Sensor foo" and "Sensor bar".Quoted 32 lines
Quoted 31 lines
Quoted 8 lines
Creating these components here makes sense. Wouldn't it also make sense to use
v4l2_asyncto wait until they have all been bound? It would more closely emulate
standard drivers. Apologies if I misunderstand what is happening here.I am using
linux/component.hfor that, when all devices are present and all modules are loaded, thecomponent.hsystem brings up the core by callingvimc_comp_bind()function, which callscomponent_bind_all()to call the binding function of each module, then it finishes registering the topology.
If any one of the components or module is unload, the component system takes down the entire topology callingcomponent_unbind_allwhich calls the unbind functions from each module.
This makes sure that the media device, subdevices and video device are only registered in the v4l2 system if all the modules are loaded.I wans't familiar with
v4l2-async.h, but from a quick look it seems that it only works with structv4l2_subdev, but I'll also need for structvideo_device(for the capture node for example).
And also, if a module is missing we would have vimc partially registered, e.g. the debayer could be registered at/dev/subdevXbut the sensor not yet and the media wouldn't be ready, I am not sure if this is a problem though.Maybe we can use
component.hfor now, then I can implement v4l2_async_{un}register_video_device and migrate tov4l2-sync.hlatter. What do you think?
Quoted 7 lines
Quoted 5 lines
That's OK. The v4l2-async mechanism precedes the component API. We should probably investigate moving over to the component API. I seem to remember that it didn't have all the features we needed, but it's a long time ago since someone looked at that and whatever the objections were, they may no longer be true.
I see, I can try to take a look on this.
Something for later.
So in other words, this looks good but needs better comments and a proper platform_data struct.
Regards,
Hans
RFC PATCH v3 10/11 vimc: deb: Add debayer filter
In reply to Helen KoikeImplement the debayer filter and integrate it with the core
---
Changes in v3:
[media] vimc: deb: Add debayer filter
- Declare frame_size as a local variable
- s_stream(sd, 1): return 0 if stream is already enabled
- s_stream(sd, 0): return 0 if stream is already disabled
- s_stream: add ret variable to propagate return errors
- structure code to be a module, use platform_driver and component system
- fix multiline comment
- s/thought/through
- s/RGB8888/RGB888
- clamp height and width of the image by an even value
- if user try to set colorspace to an invalid format, set all colorimetry parameters to _DEFAULT
- uset _DEFAULT for colorimetry in the default format
Changes in v2:
[media] vimc: deb: Add debayer filter
- Using MEDIA_ENT_F_ATV_DECODER in function
- remove v4l2_dev and dev from vimc_deb_device struct
- src fmt propagates from the sink
- coding style
- remove redundant else if statements
- check end of enum and remove BUG_ON
- enum frame size with min and max values
- set/try fmt
- remove unecessary include freezer.h
- check pad types on create
- return EBUSY when trying to set the format while stream is on
- remove vsd struct
- add IS_SRC and IS_SINK macros
- add deb_mean_win_size as a parameter of the module
- check set_fmt default parameters for quantization, colorspace ...
- add more dev_dbg
--- drivers/media/platform/vimc/Makefile | 4 +- drivers/media/platform/vimc/vimc-common.h | 2 + drivers/media/platform/vimc/vimc-debayer.c | 615 +++++++++++++++++++++++++++++ 3 files changed, 620 insertions(+), 1 deletion(-) create mode 100644 drivers/media/platform/vimc/vimc-debayer.c
drivers/media/platform/vimc/Makefile +3 -1
@@ -1,6 +1,8 @@ vimc-objs := vimc-core.o vimc_capture-objs := vimc-capture.o vimc_common-objs := vimc-common.o +vimc_debayer-objs := vimc-debayer.o vimc_sensor-objs := vimc-sensor.o -obj-$(CONFIG_VIDEO_VIMC) += vimc.o vimc_capture.o vimc_common.o vimc_sensor.o +obj-$(CONFIG_VIDEO_VIMC) += vimc.o vimc_capture.o vimc_common.o vimc-debayer.o \ + vimc_sensor.o
drivers/media/platform/vimc/vimc-common.h +2 -0
@@ -29,6 +29,8 @@#define VIMC_PIPE_OPT 1 +#define VIMC_FRAME_INDEX (lin, col, width, bpp) ((lin * width + col) * bpp) +/** * struct vimc_pix_map - maps media bus code with v4l2 pixel format *
drivers/media/platform/vimc/vimc-debayer.c new file +615 -0
615 lines not on this page · raw message
Signature · 1 line
2.7.4
RFC PATCH v3 11/11 vimc: sca: Add scaler
In reply to Helen KoikeImplement scaler and integrated with the core
---
Changes in v3:
[media] vimc: sca: Add scaler
- Declare frame_size as a local variable
- s_stream(sd, 1): return 0 if stream is already enabled
- s_stream(sd, 0): return 0 if stream is already disabled
- s_stream: add ret variable to propagate return errors
- structure code to be a module, use platform_driver and component system
- s/thought/through
- clamp height and width of the image by an even value
- if user try to set colorspace to an invalid format, set all colorimetry parameters to _DEFAULT
- uset _DEFAULT for colorimetry in the default format
Changes in v2:
[media] vimc: sca: Add scaler
- Add function MEDIA_ENT_F_IO_V4L
- remove v4l2_dev and dev
- s/sink_mbus_fmt/sink_fmt
- remove BUG_ON, remove redundant if else, rewrite TODO, check end of enum
- rm src_width/height, enum fsize with min and max values
- set/try fmt
- remove unecessary include freezer.h
- core: add bayer boolean in pixel table
- coding style
- fix bug in enum frame size
- check pad types on create
- return EBUSY when trying to set the format while stream is on
- remove vsd struct
- add IS_SRC and IS_SINK macros
- add sca_mult as a parameter of the module
- check set_fmt default parameters for quantization, colorspace ...
- add more dev_dbg
--- drivers/media/platform/vimc/Makefile | 3 +- drivers/media/platform/vimc/vimc-common.c | 27 ++ drivers/media/platform/vimc/vimc-common.h | 1 + drivers/media/platform/vimc/vimc-scaler.c | 469 ++++++++++++++++++++++++++++++ 4 files changed, 499 insertions(+), 1 deletion(-) create mode 100644 drivers/media/platform/vimc/vimc-scaler.c
drivers/media/platform/vimc/Makefile +2 -1
@@ -2,7 +2,8 @@ vimc-objs := vimc-core.o vimc_capture-objs := vimc-capture.o vimc_common-objs := vimc-common.o vimc_debayer-objs := vimc-debayer.o +vimc_scaler-objs := vimc-scaler.o vimc_sensor-objs := vimc-sensor.o obj-$(CONFIG_VIDEO_VIMC) += vimc.o vimc_capture.o vimc_common.o vimc-debayer.o \ - vimc_sensor.o + vimc_scaler.o vimc_sensor.o
drivers/media/platform/vimc/vimc-common.c +27 -0
@@ -20,6 +20,10 @@#include "vimc-common.h" +/* +* NOTE: non-bayer formats need to come first (necessary for enum_mbus_code +* in the scaler) +*/ static const struct vimc_pix_map vimc_pix_map_list[] = {/* TODO: add all missing formats */
@@ -28,16 +32,19 @@ static const struct vimc_pix_map vimc_pix_map_list[] = { .code = MEDIA_BUS_FMT_BGR888_1X24, .pixelformat = V4L2_PIX_FMT_BGR24, .bpp = 3, + .bayer = false, }, { .code = MEDIA_BUS_FMT_RGB888_1X24, .pixelformat = V4L2_PIX_FMT_RGB24, .bpp = 3, + .bayer = false, }, { .code = MEDIA_BUS_FMT_ARGB8888_1X32, .pixelformat = V4L2_PIX_FMT_ARGB32, .bpp = 4, + .bayer = false, }, /* Bayer formats */
@@ -45,41 +52,49 @@ static const struct vimc_pix_map vimc_pix_map_list[] = { .code = MEDIA_BUS_FMT_SBGGR8_1X8, .pixelformat = V4L2_PIX_FMT_SBGGR8, .bpp = 1, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SGBRG8_1X8, .pixelformat = V4L2_PIX_FMT_SGBRG8, .bpp = 1, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SGRBG8_1X8, .pixelformat = V4L2_PIX_FMT_SGRBG8, .bpp = 1, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SRGGB8_1X8, .pixelformat = V4L2_PIX_FMT_SRGGB8, .bpp = 1, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SBGGR10_1X10, .pixelformat = V4L2_PIX_FMT_SBGGR10, .bpp = 2, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SGBRG10_1X10, .pixelformat = V4L2_PIX_FMT_SGBRG10, .bpp = 2, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SGRBG10_1X10, .pixelformat = V4L2_PIX_FMT_SGRBG10, .bpp = 2, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SRGGB10_1X10, .pixelformat = V4L2_PIX_FMT_SRGGB10, .bpp = 2, + .bayer = true, }, /* 10bit raw bayer a-law compressed to 8 bits */
@@ -87,21 +102,25 @@ static const struct vimc_pix_map vimc_pix_map_list[] = { .code = MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8, .pixelformat = V4L2_PIX_FMT_SBGGR10ALAW8, .bpp = 1, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8, .pixelformat = V4L2_PIX_FMT_SGBRG10ALAW8, .bpp = 1, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, .pixelformat = V4L2_PIX_FMT_SGRBG10ALAW8, .bpp = 1, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8, .pixelformat = V4L2_PIX_FMT_SRGGB10ALAW8, .bpp = 1, + .bayer = true, }, /* 10bit raw bayer DPCM compressed to 8 bits */
@@ -109,41 +128,49 @@ static const struct vimc_pix_map vimc_pix_map_list[] = { .code = MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, .pixelformat = V4L2_PIX_FMT_SBGGR10DPCM8, .bpp = 1, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, .pixelformat = V4L2_PIX_FMT_SGBRG10DPCM8, .bpp = 1, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8, .bpp = 1, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, .pixelformat = V4L2_PIX_FMT_SRGGB10DPCM8, .bpp = 1, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SBGGR12_1X12, .pixelformat = V4L2_PIX_FMT_SBGGR12, .bpp = 2, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SGBRG12_1X12, .pixelformat = V4L2_PIX_FMT_SGBRG12, .bpp = 2, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SGRBG12_1X12, .pixelformat = V4L2_PIX_FMT_SGRBG12, .bpp = 2, + .bayer = true, }, { .code = MEDIA_BUS_FMT_SRGGB12_1X12, .pixelformat = V4L2_PIX_FMT_SRGGB12, .bpp = 2, + .bayer = true, }, };
drivers/media/platform/vimc/vimc-common.h +1 -0
@@ -45,6 +45,7 @@ struct vimc_pix_map {unsigned int code;unsigned int bpp;u32 pixelformat; +bool bayer; };/**
drivers/media/platform/vimc/vimc-scaler.c new file +469 -0
469 lines not on this page · raw message
Signature · 1 line
2.7.4
Re: [RFC PATCH v3 00/11] [media]: vimc: Virtual Media Control VPU's
In reply to Helen KoikeI forgot to mention that this patch series is also available here https://github.com/helen-fornazier/opw-staging/tree/z/sent/vimc/vpu/v3
Quoted 196 lines · Helen Koike
This patch series improves the current video processing units in vimc (by adding more controls to the sensor and capture node, allowing the user to configure different frame formats) and also adds a debayer and a scaler node.
The debayer transforms the bayer format image received in its sink pad to a bayer format by averaging the pixels within a mean window. The scaler only scales up the image for now.In this version I added an optimization where the image can be generated direct in the capture device instead of being generated in the sensor and processed by each node in the topology.
I also changed the approach to implement each node of the topology as a submodule to make the code component oriented, where new components won't need to touch vimc-core and won't need a header file. Please, let me know your view regarding this new approach.Changes in v3:
[media] vimc: sen: Integrate the tpg on the sensor
- Declareframe_sizeas a local variable
- Set tpg frame format before starting kthread
-s_stream(sd, 1): return 0 if stream is already enabled
-s_stream(sd, 0): return 0 if stream is already disabled
-s_stream: propagate error fromkthread_stop
- coding style when callingtpg_s_bytesperline
- s/vimc_thread_sen/vimc_sen_tpg_thread
- fix multiline comment
[media] vimc: Move common code from the core
- This is a new patch in the series
[media] vimc: Add vimc_ent_sd_* helper functions
- add it invimc-common.cinstead invimc-core.c
- fixvimc_ent_sd_register, use function parameter to assignsd->entity.functioninstead of using a fixed value
- rename commit to add the "common" tag
[media] vimc: Addvimc_pipeline_s_streamin the core
- add it in vimc-common instead of vimc-core
- rename commit with "common" tag
[media] vimc: common: Addvimc_link_validate
- this is a new patch in the series
[media] vimc: sen: Support several image formats
- remove support forV4L2_FIELD_ALTERNATE(left as TODO for now)
- clamp image size to an even dimension for height and width
- set default values for colorimetry using_DEFAULTmacro
- reset all values of colorimetry to_DEFAULTif user tries to set an invalid colorspace
[media] vimc: cap: Support several image formats
- use*_DEFAULTmacros for colorimetry in the default format
- clamp height and width of the image by an even value
- is user try to set colorspace to an invalid format, set all colorimetry parameters to_DEFAULT
- removeV4L2_FMT_FLAG_COMPRESSEDfromvimc_cap_enum_fmt_vid_cap
- removeV4L2_BUF_TYPE_VIDEO_CAPTUREfromvimc_cap_enum_fmt_vid_cap
- increasestep_widthandstep_heightto 2 instead of 1
- remove link validate function, use the one invimc-common.c
[media] vimc: Optimize frame generation through the pipe
- This is a new patch in the series
[media] vimc: Subdevices as modules
- This is a new patch in the series
[media] vimc: deb: Add debayer filter
- Declareframe_sizeas a local variable
-s_stream(sd, 1): return 0 if stream is already enabled
-s_stream(sd, 0): return 0 if stream is already disabled
-s_stream: add ret variable to propagate return errors
- structure code to be a module, useplatform_driverand component system
- fix multiline comment
- s/thought/through
- s/RGB8888/RGB888
- clamp height and width of the image by an even value
- if user try to set colorspace to an invalid format, set all colorimetry parameters to_DEFAULT
- uset_DEFAULTfor colorimetry in the default format
[media] vimc: sca: Add scaler
- Declareframe_sizeas a local variable
-s_stream(sd, 1): return 0 if stream is already enabled
-s_stream(sd, 0): return 0 if stream is already disabled
-s_stream: add ret variable to propagate return errors
- structure code to be a module, useplatform_driverand component system
- s/thought/through
- clamp height and width of the image by an even value
- if user try to set colorspace to an invalid format, set all colorimetry parameters to_DEFAULT
- uset_DEFAULTfor colorimetry in the default formatChanges in v2:
[media] vimc: sen: Integrate the tpg on the sensor
- Fix include location
- SelectV4L2_TPGinKconfig
- configure tpg on streamon only
- rmBUG_ON
- coding style
- removeV4L2_FIELD_ALTERNATEfromtpg_s_field
- removeV4L2_STD_PALfromtpg_fill_plane_buffer
[media] vimc: Add vimc_ent_sd_* helper functions
- Comments invimc_ent_sd_init
- Updatevimc_ent_sd_initwith upstream code asmedia_entity_pads_init
(instead ofmedia_entity_init),entity->functionintead ofentity->type
- Add missingvimc_pads_cleanupinvimc_ent_sd_cleanup
- remove subdevicev4l2_devand dev fields
- change unregister order invimc_ent_sd_cleanup
- rename vimc_ent_sd_{init,cleanup} to vimc_ent_sd_{register,unregister}
- remove structvimc_ent_subdevice, use ved and sd directly
- don't impose structvimc_sen_deviceto declare ved and sd struct first
- add kernel docs
[media] vimc: Addvimc_pipeline_s_streamin the core
- Useis_media_entity_v4l2_subdevinstead of comparing with the old
entity->type
- Fix comments style
- add kernel-docs
- calls_streamacross all sink pads
[media] vimc: sen: Support several image formats
- this is a new commit in the serie (the old one was splitted in two)
- addinit_cfgto initializetry_fmt
- reorder code invimc_sen_set_fmt
- allow user space to change all fields from structv4l2_mbus_framefmt
(e.g. colospace, quantization, field,xfer_func,ycbcr_enc)
- merge with patch for theenum_mbus_codeandenum_frame_size
- change commit message
- addvimc_pix_map_by_index
- rename MIN/MAX macros
- checkset_fmtdefault parameters for quantization, colorspace ...media] vimc: sen: Support several image formats
[media] vimc: cap: Support several image formats
- this is a new commit in the serie (the old one was splitted in two)
- allow user space to change all fields from structv4l2_pix_format
(e.g. colospace, quantization, field,xfer_func,ycbcr_enc)
-link_validateandtry_fmt: also checks colospace, quantization, field,xfer_func,ycbcr_enc
- add structv4l2_pix_formatfmt_default
- addenum_framesizes
-enum_fmt_vid_cap: enumerate all formats fromvimc_pix_map_table
- add modedev_dbg
[media] vimc: deb: Add debayer filter
- UsingMEDIA_ENT_F_ATV_DECODERin function
- removev4l2_devand dev fromvimc_deb_devicestruct
- src fmt propagates from the sink
- coding style
- remove redundant else if statements
- check end of enum and removeBUG_ON
- enum frame size with min and max values
- set/try fmt
- remove unecessary includefreezer.h
- check pad types on create
- return EBUSY when trying to set the format while stream is on
- remove vsd struct
- addIS_SRCandIS_SINKmacros
- adddeb_mean_win_sizeas a parameter of the module
- checkset_fmtdefault parameters for quantization, colorspace ...
- add moredev_dbg
[media] vimc: sca: Add scaler
- Add functionMEDIA_ENT_F_IO_V4L
- removev4l2_devand dev
- s/sink_mbus_fmt/sink_fmt
- removeBUG_ON, remove redundant if else, rewrite TODO, check end of enum
- rm src_width/height, enum fsize with min and max values
- set/try fmt
- remove unecessary includefreezer.h
- core: add bayer boolean in pixel table
- coding style
- fix bug in enum frame size
- check pad types on create
- return EBUSY when trying to set the format while stream is on
- remove vsd struct
- addIS_SRCandIS_SINKmacros
- addsca_multas a parameter of the module
- checkset_fmtdefault parameters for quantization, colorspace ...
- add moredev_dbgHelen Koike (11):
[media] vimc: sen: Integrate the tpg on the sensor [media] vimc: Move common code from the core [media] vimc: common: Add vimc_ent_sd_* helper [media] vimc: common: Addvimc_pipeline_s_streamhelper [media] vimc: common: Addvimc_link_validate[media] vimc: sen: Support several image formats [media] vimc: cap: Support several image formats [media] vimc: Optimize frame generation through the pipe [media] vimc: Subdevices as modules
[media] vimc: deb: Add debayer filter
[media] vimc: sca: Add scalerdrivers/media/platform/vimc/Kconfig | 1 + drivers/media/platform/vimc/Makefile | 10 +- drivers/media/platform/vimc/vimc-capture.c | 488 ++++++++++------ drivers/media/platform/vimc/vimc-capture.h | 28 - drivers/media/platform/vimc/vimc-common.c | 475 ++++++++++++++++ .../platform/vimc/{vimc-core.h => vimc-common.h} | 88 ++- drivers/media/platform/vimc/vimc-core.c | 611 ++++++-------------- drivers/media/platform/vimc/vimc-debayer.c | 615 +++++++++++++++++++++ drivers/media/platform/vimc/vimc-scaler.c | 469 ++++++++++++++++ drivers/media/platform/vimc/vimc-sensor.c | 348 ++++++++---- drivers/media/platform/vimc/vimc-sensor.h | 28 - 11 files changed, 2370 insertions(+), 791 deletions(-) delete mode 100644 drivers/media/platform/vimc/vimc-capture.h create mode 100644 drivers/media/platform/vimc/vimc-common.c rename drivers/media/platform/vimc/{vimc-core.h => vimc-common.h} (54%) create mode 100644 drivers/media/platform/vimc/vimc-debayer.c create mode 100644 drivers/media/platform/vimc/vimc-scaler.c delete mode 100644 drivers/media/platform/vimc/vimc-sensor.h