diff options
Diffstat (limited to 'isp')
-rw-r--r-- | isp/omap3isp-priv.h | 20 | ||||
-rw-r--r-- | isp/omap3isp.c | 127 |
2 files changed, 127 insertions, 20 deletions
diff --git a/isp/omap3isp-priv.h b/isp/omap3isp-priv.h index bb683b5..375c5c9 100644 --- a/isp/omap3isp-priv.h +++ b/isp/omap3isp-priv.h @@ -23,6 +23,8 @@ #ifndef __OMAP3ISP_PRIV_H #define __OMAP3ISP_PRIV_H +#include <linux/v4l2-mediabus.h> + #include "omap3isp.h" /* @@ -50,17 +52,27 @@ struct omap3_isp_video { }; /* + * struct omap3_isp_pad - OMAP3 entity pad + * @link: Link connected to the pad + * @format: Format on the pad + */ +struct omap3_isp_pad { + struct media_entity_link *link; + struct v4l2_mbus_framefmt format; +}; + +/* * struct omap3_isp_entity - OMAP3 entity in a pipeline * @list: Entities list * @entity: Media entity information - * @link_sink: Link connected to the sink pad - * @link_source: Link connected to the source pad + * @sink: Sink pad + * @source: Sink pad */ struct omap3_isp_entity { struct list_entry list; struct media_entity *entity; - struct media_entity_link *link_sink; - struct media_entity_link *link_source; + struct omap3_isp_pad sink; + struct omap3_isp_pad source; }; /* diff --git a/isp/omap3isp.c b/isp/omap3isp.c index 04d69ad..75467e1 100644 --- a/isp/omap3isp.c +++ b/isp/omap3isp.c @@ -187,8 +187,8 @@ static int omap3_isp_pipeline_build(struct omap3_isp_device *isp, } /* Store link information in source and sink */ - source->link_source = &source->entity->links[i]; - sink->link_sink = &source->entity->links[i]; + source->source.link = &source->entity->links[i]; + sink->sink.link = &source->entity->links[i]; } list_append(&sink->list, &pipe->entities); @@ -210,6 +210,97 @@ done: return ret; } +static int omap3_isp_pipeline_try_format(struct omap3_isp_device *isp, + struct omap3_isp_pipeline *pipe, + struct v4l2_mbus_framefmt *ofmt, + enum omap3_isp_scaler scaler) +{ + struct v4l2_mbus_framefmt format; + struct omap3_isp_entity *source = NULL; + struct omap3_isp_entity *sink; + struct media_entity_pad *pad; + int ret; + + /* Configure formats. Start from the sensor output and propagate the + * format through the pipeline. + */ + + /* When scaling on the ISP, select the sensor default output format. + * Otherwise scale as much as possible on the sensor. + */ + if (scaler == OMAP3_ISP_SCALER_ISP) + format = isp->sensor_format; + else + format = *ofmt; + + ret = v4l2_subdev_set_format(isp->sensor, &format, 0, + V4L2_SUBDEV_FORMAT_TRY); + if (ret < 0) { + printf("error: get format on sensor output failed.\n"); + return ret; + } + + list_for_each_entry(sink, &pipe->entities, list) { + if (source == NULL) { + source = sink; + continue; + } + + if (media_entity_type(sink->entity) == MEDIA_ENT_T_DEVNODE) + break; + + /* Try to force the output format code onto the source pad. */ + pad = source->source.link->source; + + ret = v4l2_subdev_get_format(pad->entity, &format, pad->index, + V4L2_SUBDEV_FORMAT_TRY); + if (ret < 0) { + printf("error: get format failed on %s:%u.\n", + pad->entity->info.name, pad->index); + return ret; + } + + format.code = ofmt->code; + ret = v4l2_subdev_set_format(pad->entity, &format, pad->index, + V4L2_SUBDEV_FORMAT_TRY); + if (ret < 0) { + printf("error: set format failed on %s:%u.\n", + pad->entity->info.name, pad->index); + return ret; + } + + source->source.format = format; + + /* Propagate the format to the link target. */ + pad = sink->sink.link->sink; + + ret = v4l2_subdev_set_format(pad->entity, &format, pad->index, + V4L2_SUBDEV_FORMAT_TRY); + if (ret < 0) { + printf("error: set format failed on %s:%u.\n", + pad->entity->info.name, pad->index); + return ret; + } + + sink->sink.format = format; + + source = sink; + } + + pad = source->source.link->source; + + ret = v4l2_subdev_set_format(pad->entity, ofmt, pad->index, + V4L2_SUBDEV_FORMAT_TRY); + if (ret < 0) { + printf("error: set format failed on %s:%u.\n", + pad->entity->info.name, pad->index); + return ret; + } + + source->source.format = format; + return 0; +} + static int omap3_isp_pipeline_activate(struct omap3_isp_device *isp, struct omap3_isp_pipeline *pipe) { @@ -221,11 +312,11 @@ static int omap3_isp_pipeline_activate(struct omap3_isp_device *isp, return ret; list_for_each_entry(entity, &pipe->entities, list) { - if (entity->link_source == NULL) + if (entity->source.link == NULL) break; - ret = setup_link(isp, entity->link_source->source->entity, - entity->link_source->sink->entity, + ret = setup_link(isp, entity->source.link->source->entity, + entity->source.link->sink->entity, MEDIA_LNK_FL_ENABLED); if (ret < 0) return ret; @@ -467,6 +558,12 @@ int omap3_isp_viewfinder_setup(struct omap3_isp_device *isp, return ret; } + /* Try the format. */ + ret = omap3_isp_pipeline_try_format(isp, &isp->viewfinder, ofmt, + isp->viewfinder.output.scaler); + if (ret < 0) + return ret; + /* Setup the pipeline. */ ret = omap3_isp_viewfinder_setup_pipeline(isp, ofmt); if (ret < 0) @@ -523,13 +620,14 @@ int omap3_isp_viewfinder_set_scaler(struct omap3_isp_device *isp, isp->viewfinder.output.scaler = scaler; - /* If omap3_isp_viewfinder_setup() hasn't been called yet retur now. */ + /* If omap3_isp_viewfinder_setup() hasn't been called yet return now. */ if (isp->viewfinder.output.format.width == 0 || isp->viewfinder.output.format.height == 0) return 0; format = isp->viewfinder.output.format; - ret = omap3_isp_viewfinder_setup_pipeline(isp, &format); + ret = omap3_isp_pipeline_try_format(isp, &isp->viewfinder, &format, + isp->viewfinder.output.scaler); if (ret < 0) return ret; @@ -647,8 +745,7 @@ static int omap3_isp_snapshot_restore_pipeline(struct omap3_isp_device *isp) } static int omap3_isp_snapshot_setup_pipeline(struct omap3_isp_device *isp, - struct v4l2_mbus_framefmt *ofmt, - enum v4l2_subdev_format_whence which) + struct v4l2_mbus_framefmt *ofmt) { int ret; @@ -658,7 +755,8 @@ static int omap3_isp_snapshot_setup_pipeline(struct omap3_isp_device *isp, return ret; /* Configure the formats on the pipeline. */ - ret = omap3_isp_pipeline_set_format(isp, ofmt, isp->snapshot.output.scaler, which); + ret = omap3_isp_pipeline_set_format(isp, ofmt, isp->snapshot.output.scaler, + V4L2_SUBDEV_FORMAT_ACTIVE); if (ret < 0) { printf("error: unable to configure formats on pipeline.\n"); return ret; @@ -706,16 +804,13 @@ int omap3_isp_snapshot_setup(struct omap3_isp_device *isp, return -ENOENT; /* Try the format. */ - ret = omap3_isp_snapshot_setup_pipeline(isp, ofmt, V4L2_SUBDEV_FORMAT_TRY); + ret = omap3_isp_pipeline_try_format(isp, &isp->snapshot, ofmt, + OMAP3_ISP_SCALER_ISP); if (ret < 0) return ret; isp->snapshot.output.format = *ofmt; - ret = omap3_isp_snapshot_restore_pipeline(isp); - if (ret < 0) - return ret; - /* Open the V4L2 device. */ isp->snapshot.output.video = v4l2_open(isp->snapshot.output.node->devname); if (isp->snapshot.output.video == NULL) { @@ -831,7 +926,7 @@ int omap3_isp_snapshot_capture(struct omap3_isp_device *isp) /* Configure the pipeline. */ format = isp->snapshot.output.format; - ret = omap3_isp_snapshot_setup_pipeline(isp, &format, V4L2_SUBDEV_FORMAT_ACTIVE); + ret = omap3_isp_snapshot_setup_pipeline(isp, &format); if (ret < 0) { printf("error: unable to setup snapshot pipeline.\n"); return ret; |