struct vsp1_device;
struct vsp1_dl_list;
struct vsp1_pipeline;
+struct vsp1_partition;
+struct vsp1_partition_window;
enum vsp1_entity_type {
VSP1_ENTITY_BRU,
* selection rectangles, ...)
* @max_width: Return the max supported width of data that the entity can
* process in a single operation.
+ * @partition: Process the partition construction based on this entity's
+ * configuration.
*/
struct vsp1_entity_operations {
void (*destroy)(struct vsp1_entity *);
void (*configure)(struct vsp1_entity *, struct vsp1_pipeline *,
struct vsp1_dl_list *, enum vsp1_entity_params);
unsigned int (*max_width)(struct vsp1_entity *, struct vsp1_pipeline *);
+ void (*partition)(struct vsp1_entity *, struct vsp1_pipeline *,
+ struct vsp1_partition *, unsigned int,
+ struct vsp1_partition_window *);
};
struct vsp1_entity {
vsp1_uds_set_alpha(pipe->uds, dl, alpha);
}
+/*
+ * Propagate the partition calculations through the pipeline
+ *
+ * Work backwards through the pipe, allowing each entity to update the partition
+ * parameters based on its configuration, and the entity connected to its
+ * source. Each entity must produce the partition required for the previous
+ * entity in the pipeline.
+ */
+void vsp1_pipeline_propagate_partition(struct vsp1_pipeline *pipe,
+ struct vsp1_partition *partition,
+ unsigned int index,
+ struct vsp1_partition_window *window)
+{
+ struct vsp1_entity *entity;
+
+ list_for_each_entry_reverse(entity, &pipe->entities, list_pipe) {
+ if (entity->ops->partition)
+ entity->ops->partition(entity, pipe, partition, index,
+ window);
+ }
+}
+
void vsp1_pipelines_suspend(struct vsp1_device *vsp1)
{
unsigned long flags;
};
/*
- * struct vsp1_partition - A description of a slice for the partition algorithm
+ * struct vsp1_partition_window - Partition window coordinates
* @left: horizontal coordinate of the partition start in pixels relative to the
* left edge of the image
* @width: partition width in pixels
*/
-struct vsp1_partition {
+struct vsp1_partition_window {
unsigned int left;
unsigned int width;
};
+/*
+ * struct vsp1_partition - A description of a slice for the partition algorithm
+ * @rpf: The RPF partition window configuration
+ * @uds_sink: The UDS input partition window configuration
+ * @uds_source: The UDS output partition window configuration
+ * @sru: The SRU partition window configuration
+ * @wpf: The WPF partition window configuration
+ */
+struct vsp1_partition {
+ struct vsp1_partition_window rpf;
+ struct vsp1_partition_window uds_sink;
+ struct vsp1_partition_window uds_source;
+ struct vsp1_partition_window sru;
+ struct vsp1_partition_window wpf;
+};
+
/*
* struct vsp1_pipeline - A VSP1 hardware pipeline
* @pipe: the media pipeline
struct vsp1_entity *uds;
struct vsp1_entity *uds_input;
+ /*
+ * The order of this list must be identical to the order of the entities
+ * in the pipeline, as it is assumed by the partition algorithm that we
+ * can walk this list in sequence.
+ */
struct list_head entities;
struct vsp1_dl_list *dl;
void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl, unsigned int alpha);
+void vsp1_pipeline_propagate_partition(struct vsp1_pipeline *pipe,
+ struct vsp1_partition *partition,
+ unsigned int index,
+ struct vsp1_partition_window *window);
+
void vsp1_pipelines_suspend(struct vsp1_device *vsp1);
void vsp1_pipelines_resume(struct vsp1_device *vsp1);
* 'width' need to be adjusted.
*/
if (pipe->partitions > 1) {
- const struct v4l2_mbus_framefmt *output;
- struct vsp1_entity *wpf = &pipe->output->entity;
- unsigned int input_width = crop.width;
-
- /*
- * Scale the partition window based on the configuration
- * of the pipeline.
- */
- output = vsp1_entity_get_pad_format(wpf, wpf->config,
- RWPF_PAD_SINK);
-
- crop.width = pipe->partition->width * input_width
- / output->width;
- crop.left += pipe->partition->left * input_width
- / output->width;
+ crop.width = pipe->partition->rpf.width;
+ crop.left += pipe->partition->rpf.left;
}
vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_BSIZE,
}
+static void rpf_partition(struct vsp1_entity *entity,
+ struct vsp1_pipeline *pipe,
+ struct vsp1_partition *partition,
+ unsigned int partition_idx,
+ struct vsp1_partition_window *window)
+{
+ partition->rpf = *window;
+}
+
static const struct vsp1_entity_operations rpf_entity_ops = {
.configure = rpf_configure,
+ .partition = rpf_partition,
};
/* -----------------------------------------------------------------------------
#include "vsp1.h"
#include "vsp1_dl.h"
+#include "vsp1_pipe.h"
#include "vsp1_sru.h"
#define SRU_MIN_SIZE 4U
return 256;
}
+static void sru_partition(struct vsp1_entity *entity,
+ struct vsp1_pipeline *pipe,
+ struct vsp1_partition *partition,
+ unsigned int partition_idx,
+ struct vsp1_partition_window *window)
+{
+ struct vsp1_sru *sru = to_sru(&entity->subdev);
+ struct v4l2_mbus_framefmt *input;
+ struct v4l2_mbus_framefmt *output;
+
+ input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
+ SRU_PAD_SINK);
+ output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
+ SRU_PAD_SOURCE);
+
+ /* Adapt if SRUx2 is enabled */
+ if (input->width != output->width) {
+ window->width /= 2;
+ window->left /= 2;
+ }
+
+ partition->sru = *window;
+}
+
static const struct vsp1_entity_operations sru_entity_ops = {
.configure = sru_configure,
.max_width = sru_max_width,
+ .partition = sru_partition,
};
/* -----------------------------------------------------------------------------
if (params == VSP1_ENTITY_PARAMS_PARTITION) {
struct vsp1_partition *partition = pipe->partition;
+ /* Input size clipping */
+ vsp1_uds_write(uds, dl, VI6_UDS_HSZCLIP, VI6_UDS_HSZCLIP_HCEN |
+ (0 << VI6_UDS_HSZCLIP_HCL_OFST_SHIFT) |
+ (partition->uds_sink.width
+ << VI6_UDS_HSZCLIP_HCL_SIZE_SHIFT));
+
+ /* Output size clipping */
vsp1_uds_write(uds, dl, VI6_UDS_CLIP_SIZE,
- (partition->width
+ (partition->uds_source.width
<< VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) |
(output->height
<< VI6_UDS_CLIP_SIZE_VSIZE_SHIFT));
return 2048;
}
+/* -----------------------------------------------------------------------------
+ * Partition Algorithm Support
+ */
+
+static void uds_partition(struct vsp1_entity *entity,
+ struct vsp1_pipeline *pipe,
+ struct vsp1_partition *partition,
+ unsigned int partition_idx,
+ struct vsp1_partition_window *window)
+{
+ struct vsp1_uds *uds = to_uds(&entity->subdev);
+ const struct v4l2_mbus_framefmt *output;
+ const struct v4l2_mbus_framefmt *input;
+
+ /* Initialise the partition state */
+ partition->uds_sink = *window;
+ partition->uds_source = *window;
+
+ input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
+ UDS_PAD_SINK);
+ output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
+ UDS_PAD_SOURCE);
+
+ partition->uds_sink.width = window->width * input->width
+ / output->width;
+ partition->uds_sink.left = window->left * input->width
+ / output->width;
+
+ *window = partition->uds_sink;
+}
+
static const struct vsp1_entity_operations uds_entity_ops = {
.configure = uds_configure,
.max_width = uds_max_width,
+ .partition = uds_partition,
};
/* -----------------------------------------------------------------------------
unsigned int index)
{
const struct v4l2_mbus_framefmt *format;
+ struct vsp1_partition_window window;
unsigned int modulus;
/*
/* A single partition simply processes the output size in full. */
if (pipe->partitions <= 1) {
- partition->left = 0;
- partition->width = format->width;
+ window.left = 0;
+ window.width = format->width;
+
+ vsp1_pipeline_propagate_partition(pipe, partition, index,
+ &window);
return;
}
/* Initialise the partition with sane starting conditions. */
- partition->left = index * div_size;
- partition->width = div_size;
+ window.left = index * div_size;
+ window.width = div_size;
modulus = format->width % div_size;
if (modulus < div_size / 2) {
if (index == partitions - 1) {
/* Halve the penultimate partition. */
- partition->width = div_size / 2;
+ window.width = div_size / 2;
} else if (index == partitions) {
/* Increase the final partition. */
- partition->width = (div_size / 2) + modulus;
- partition->left -= div_size / 2;
+ window.width = (div_size / 2) + modulus;
+ window.left -= div_size / 2;
}
} else if (index == partitions) {
- partition->width = modulus;
+ window.width = modulus;
}
}
+
+ vsp1_pipeline_propagate_partition(pipe, partition, index, &window);
}
static int vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe)
* multiple slices.
*/
if (pipe->partitions > 1)
- width = pipe->partition->width;
+ width = pipe->partition->wpf.width;
vsp1_wpf_write(wpf, dl, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
(0 << VI6_WPF_SZCLIP_OFST_SHIFT) |
* is applied horizontally or vertically accordingly.
*/
if (flip & BIT(WPF_CTRL_HFLIP) && !wpf->flip.rotate)
- offset = format->width - pipe->partition->left
- - pipe->partition->width;
+ offset = format->width - pipe->partition->wpf.left
+ - pipe->partition->wpf.width;
else if (flip & BIT(WPF_CTRL_VFLIP) && wpf->flip.rotate)
- offset = format->height - pipe->partition->left
- - pipe->partition->width;
+ offset = format->height - pipe->partition->wpf.left
+ - pipe->partition->wpf.width;
else
- offset = pipe->partition->left;
+ offset = pipe->partition->wpf.left;
for (i = 0; i < format->num_planes; ++i) {
unsigned int hsub = i > 0 ? fmtinfo->hsub : 1;
* image height.
*/
if (wpf->flip.rotate)
- height = pipe->partition->width;
+ height = pipe->partition->wpf.width;
else
height = format->height;
return wpf->flip.rotate ? 256 : wpf->max_width;
}
+static void wpf_partition(struct vsp1_entity *entity,
+ struct vsp1_pipeline *pipe,
+ struct vsp1_partition *partition,
+ unsigned int partition_idx,
+ struct vsp1_partition_window *window)
+{
+ partition->wpf = *window;
+}
+
static const struct vsp1_entity_operations wpf_entity_ops = {
.destroy = vsp1_wpf_destroy,
.configure = wpf_configure,
.max_width = wpf_max_width,
+ .partition = wpf_partition,
};
/* -----------------------------------------------------------------------------