break;
}
+ case VSP1_ENTITY_PARAMS_PARTITION:
+ break;
+
case VSP1_ENTITY_PARAMS_RUNTIME:
/* 2D mode can only be used with the YCbCr pixel encoding. */
if (clu->mode == V4L2_CID_VSP1_CLU_MODE_2D && clu->yuv_mode)
VSP1_ENTITY_PARAMS_INIT);
entity->ops->configure(entity, pipe, pipe->dl,
VSP1_ENTITY_PARAMS_RUNTIME);
+ entity->ops->configure(entity, pipe, pipe->dl,
+ VSP1_ENTITY_PARAMS_PARTITION);
}
-
- /* The memory buffer address must be applied after configuring
- * the RPF to make sure the crop offset are computed.
- */
- if (entity->type == VSP1_ENTITY_RPF)
- vsp1_rwpf_set_memory(to_rwpf(&entity->subdev),
- pipe->dl);
}
vsp1_dl_list_commit(pipe->dl);
/*
* enum vsp1_entity_params - Entity configuration parameters class
* @VSP1_ENTITY_PARAMS_INIT - Initial parameters
+ * @VSP1_ENTITY_PARAMS_PARTITION - Per-image partition parameters
* @VSP1_ENTITY_PARAMS_RUNTIME - Runtime-configurable parameters
*/
enum vsp1_entity_params {
VSP1_ENTITY_PARAMS_INIT,
+ VSP1_ENTITY_PARAMS_PARTITION,
VSP1_ENTITY_PARAMS_RUNTIME,
};
/**
* struct vsp1_entity_operations - Entity operations
* @destroy: Destroy the entity.
- * @set_memory: Setup memory buffer access. This operation applies the settings
- * stored in the rwpf mem field to the display list. Valid for RPF
- * and WPF only.
* @configure: Setup the hardware based on the entity state (pipeline, formats,
* selection rectangles, ...)
*/
struct vsp1_entity_operations {
void (*destroy)(struct vsp1_entity *);
- void (*set_memory)(struct vsp1_entity *, struct vsp1_dl_list *dl);
void (*configure)(struct vsp1_entity *, struct vsp1_pipeline *,
struct vsp1_dl_list *, enum vsp1_entity_params);
};
vsp1_lut_write(lut, dl, VI6_LUT_CTRL, VI6_LUT_CTRL_EN);
break;
+ case VSP1_ENTITY_PARAMS_PARTITION:
+ break;
+
case VSP1_ENTITY_PARAMS_RUNTIME:
spin_lock_irqsave(&lut->lock, flags);
dlb = lut->lut;
* VSP1 Entity Operations
*/
-static void rpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl)
-{
- struct vsp1_rwpf *rpf = entity_to_rwpf(entity);
-
- vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_Y,
- rpf->mem.addr[0] + rpf->offsets[0]);
- vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C0,
- rpf->mem.addr[1] + rpf->offsets[1]);
- vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C1,
- rpf->mem.addr[2] + rpf->offsets[1]);
-}
-
static void rpf_configure(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
const struct v4l2_pix_format_mplane *format = &rpf->format;
const struct v4l2_mbus_framefmt *source_format;
const struct v4l2_mbus_framefmt *sink_format;
- const struct v4l2_rect *crop;
unsigned int left = 0;
unsigned int top = 0;
u32 pstride;
return;
}
- /* Source size, stride and crop offsets.
- *
- * The crop offsets correspond to the location of the crop rectangle top
- * left corner in the plane buffer. Only two offsets are needed, as
- * planes 2 and 3 always have identical strides.
- */
- crop = vsp1_rwpf_get_crop(rpf, rpf->entity.config);
-
- vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_BSIZE,
- (crop->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
- (crop->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT));
- vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_ESIZE,
- (crop->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) |
- (crop->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT));
+ if (params == VSP1_ENTITY_PARAMS_PARTITION) {
+ const struct v4l2_rect *crop;
+ unsigned int offsets[2];
+
+ /* Source size and crop offsets.
+ *
+ * The crop offsets correspond to the location of the crop
+ * rectangle top left corner in the plane buffer. Only two
+ * offsets are needed, as planes 2 and 3 always have identical
+ * strides.
+ */
+ crop = vsp1_rwpf_get_crop(rpf, rpf->entity.config);
+
+ vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_BSIZE,
+ (crop->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
+ (crop->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT));
+ vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_ESIZE,
+ (crop->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) |
+ (crop->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT));
+
+ offsets[0] = crop->top * format->plane_fmt[0].bytesperline
+ + crop->left * fmtinfo->bpp[0] / 8;
+
+ if (format->num_planes > 1)
+ offsets[1] = crop->top * format->plane_fmt[1].bytesperline
+ + crop->left / fmtinfo->hsub
+ * fmtinfo->bpp[1] / 8;
+ else
+ offsets[1] = 0;
+
+ vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_Y,
+ rpf->mem.addr[0] + offsets[0]);
+ vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C0,
+ rpf->mem.addr[1] + offsets[1]);
+ vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C1,
+ rpf->mem.addr[2] + offsets[1]);
+ return;
+ }
- rpf->offsets[0] = crop->top * format->plane_fmt[0].bytesperline
- + crop->left * fmtinfo->bpp[0] / 8;
+ /* Stride */
pstride = format->plane_fmt[0].bytesperline
<< VI6_RPF_SRCM_PSTRIDE_Y_SHIFT;
-
- if (format->num_planes > 1) {
- rpf->offsets[1] = crop->top * format->plane_fmt[1].bytesperline
- + crop->left / fmtinfo->hsub * fmtinfo->bpp[1]
- / 8;
+ if (format->num_planes > 1)
pstride |= format->plane_fmt[1].bytesperline
<< VI6_RPF_SRCM_PSTRIDE_C_SHIFT;
- } else {
- rpf->offsets[1] = 0;
- }
vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_PSTRIDE, pstride);
}
static const struct vsp1_entity_operations rpf_entity_ops = {
- .set_memory = rpf_set_memory,
.configure = rpf_configure,
};
unsigned int active;
} flip;
- unsigned int offsets[2];
struct vsp1_rwpf_memory mem;
struct vsp1_dl_manager *dlm;
struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
struct v4l2_subdev_pad_config *config);
-/**
- * vsp1_rwpf_set_memory - Configure DMA addresses for a [RW]PF
- * @rwpf: the [RW]PF instance
- * @dl: the display list
- *
- * This function applies the cached memory buffer address to the display list.
- */
-static inline void vsp1_rwpf_set_memory(struct vsp1_rwpf *rwpf,
- struct vsp1_dl_list *dl)
-{
- rwpf->entity.ops->set_memory(&rwpf->entity, dl);
-}
#endif /* __VSP1_RWPF_H__ */
static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe)
{
- struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
struct vsp1_entity *entity;
- unsigned int i;
if (!pipe->dl)
pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
list_for_each_entry(entity, &pipe->entities, list_pipe) {
- if (entity->ops->configure)
+ if (entity->ops->configure) {
entity->ops->configure(entity, pipe, pipe->dl,
VSP1_ENTITY_PARAMS_RUNTIME);
+ entity->ops->configure(entity, pipe, pipe->dl,
+ VSP1_ENTITY_PARAMS_PARTITION);
+ }
}
- for (i = 0; i < vsp1->info->rpf_count; ++i) {
- struct vsp1_rwpf *rwpf = pipe->inputs[i];
-
- if (rwpf)
- vsp1_rwpf_set_memory(rwpf, pipe->dl);
- }
-
- if (!pipe->lif)
- vsp1_rwpf_set_memory(pipe->output, pipe->dl);
-
vsp1_dl_list_commit(pipe->dl);
pipe->dl = NULL;
vsp1_dlm_destroy(wpf->dlm);
}
-static void wpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl)
-{
- struct vsp1_rwpf *wpf = entity_to_rwpf(entity);
- const struct v4l2_pix_format_mplane *format = &wpf->format;
- struct vsp1_rwpf_memory mem = wpf->mem;
- unsigned int flip = wpf->flip.active;
- unsigned int offset;
-
- /* Update the memory offsets based on flipping configuration. The
- * destination addresses point to the locations where the VSP starts
- * writing to memory, which can be different corners of the image
- * depending on vertical flipping. Horizontal flipping is handled
- * through a line buffer and doesn't modify the start address.
- */
- if (flip & BIT(WPF_CTRL_VFLIP)) {
- mem.addr[0] += (format->height - 1)
- * format->plane_fmt[0].bytesperline;
-
- if (format->num_planes > 1) {
- offset = (format->height / wpf->fmtinfo->vsub - 1)
- * format->plane_fmt[1].bytesperline;
- mem.addr[1] += offset;
- mem.addr[2] += offset;
- }
- }
-
- vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y, mem.addr[0]);
- vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0, mem.addr[1]);
- vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1, mem.addr[2]);
-}
-
static void wpf_configure(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
return;
}
- /* Format */
sink_format = vsp1_entity_get_pad_format(&wpf->entity,
wpf->entity.config,
RWPF_PAD_SINK);
wpf->entity.config,
RWPF_PAD_SOURCE);
- vsp1_wpf_write(wpf, dl, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
- (0 << VI6_WPF_SZCLIP_OFST_SHIFT) |
- (source_format->width << VI6_WPF_SZCLIP_SIZE_SHIFT));
- vsp1_wpf_write(wpf, dl, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN |
- (0 << VI6_WPF_SZCLIP_OFST_SHIFT) |
- (source_format->height << VI6_WPF_SZCLIP_SIZE_SHIFT));
+ if (params == VSP1_ENTITY_PARAMS_PARTITION) {
+ const struct v4l2_pix_format_mplane *format = &wpf->format;
+ struct vsp1_rwpf_memory mem = wpf->mem;
+ unsigned int flip = wpf->flip.active;
+ unsigned int width = source_format->width;
+ unsigned int height = source_format->height;
+ unsigned int offset;
+
+ /* Cropping. The partition algorithm can split the image into
+ * multiple slices.
+ */
+ vsp1_wpf_write(wpf, dl, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
+ (0 << VI6_WPF_SZCLIP_OFST_SHIFT) |
+ (width << VI6_WPF_SZCLIP_SIZE_SHIFT));
+ vsp1_wpf_write(wpf, dl, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN |
+ (0 << VI6_WPF_SZCLIP_OFST_SHIFT) |
+ (height << VI6_WPF_SZCLIP_SIZE_SHIFT));
+
+ if (pipe->lif)
+ return;
+
+ /* Update the memory offsets based on flipping configuration.
+ * The destination addresses point to the locations where the
+ * VSP starts writing to memory, which can be different corners
+ * of the image depending on vertical flipping. Horizontal
+ * flipping is handled through a line buffer and doesn't modify
+ * the start address.
+ */
+ if (flip & BIT(WPF_CTRL_VFLIP)) {
+ mem.addr[0] += (format->height - 1)
+ * format->plane_fmt[0].bytesperline;
+
+ if (format->num_planes > 1) {
+ offset = (format->height / wpf->fmtinfo->vsub - 1)
+ * format->plane_fmt[1].bytesperline;
+ mem.addr[1] += offset;
+ mem.addr[2] += offset;
+ }
+ }
+ vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y, mem.addr[0]);
+ vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0, mem.addr[1]);
+ vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1, mem.addr[2]);
+ return;
+ }
+
+ /* Format */
if (!pipe->lif) {
const struct v4l2_pix_format_mplane *format = &wpf->format;
const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;
static const struct vsp1_entity_operations wpf_entity_ops = {
.destroy = vsp1_wpf_destroy,
- .set_memory = wpf_set_memory,
.configure = wpf_configure,
};