|
|
@@ -232,10 +232,9 @@ static void vsp1_wpf_destroy(struct vsp1_entity *entity)
|
|
|
vsp1_dlm_destroy(wpf->dlm);
|
|
|
}
|
|
|
|
|
|
-static void wpf_configure(struct vsp1_entity *entity,
|
|
|
- struct vsp1_pipeline *pipe,
|
|
|
- struct vsp1_dl_list *dl,
|
|
|
- enum vsp1_entity_params params)
|
|
|
+static void wpf_configure_stream(struct vsp1_entity *entity,
|
|
|
+ struct vsp1_pipeline *pipe,
|
|
|
+ struct vsp1_dl_list *dl)
|
|
|
{
|
|
|
struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
|
|
|
struct vsp1_device *vsp1 = wpf->entity.vsp1;
|
|
|
@@ -245,149 +244,12 @@ static void wpf_configure(struct vsp1_entity *entity,
|
|
|
u32 outfmt = 0;
|
|
|
u32 srcrpf = 0;
|
|
|
|
|
|
- if (params == VSP1_ENTITY_PARAMS_RUNTIME) {
|
|
|
- const unsigned int mask = BIT(WPF_CTRL_VFLIP)
|
|
|
- | BIT(WPF_CTRL_HFLIP);
|
|
|
- unsigned long flags;
|
|
|
-
|
|
|
- spin_lock_irqsave(&wpf->flip.lock, flags);
|
|
|
- wpf->flip.active = (wpf->flip.active & ~mask)
|
|
|
- | (wpf->flip.pending & mask);
|
|
|
- spin_unlock_irqrestore(&wpf->flip.lock, flags);
|
|
|
-
|
|
|
- outfmt = (wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT) | wpf->outfmt;
|
|
|
-
|
|
|
- if (wpf->flip.active & BIT(WPF_CTRL_VFLIP))
|
|
|
- outfmt |= VI6_WPF_OUTFMT_FLP;
|
|
|
- if (wpf->flip.active & BIT(WPF_CTRL_HFLIP))
|
|
|
- outfmt |= VI6_WPF_OUTFMT_HFLP;
|
|
|
-
|
|
|
- vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, outfmt);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
sink_format = vsp1_entity_get_pad_format(&wpf->entity,
|
|
|
wpf->entity.config,
|
|
|
RWPF_PAD_SINK);
|
|
|
source_format = vsp1_entity_get_pad_format(&wpf->entity,
|
|
|
wpf->entity.config,
|
|
|
RWPF_PAD_SOURCE);
|
|
|
-
|
|
|
- if (params == VSP1_ENTITY_PARAMS_PARTITION) {
|
|
|
- const struct v4l2_pix_format_mplane *format = &wpf->format;
|
|
|
- const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;
|
|
|
- struct vsp1_rwpf_memory mem = wpf->mem;
|
|
|
- unsigned int flip = wpf->flip.active;
|
|
|
- unsigned int width = sink_format->width;
|
|
|
- unsigned int height = sink_format->height;
|
|
|
- unsigned int offset;
|
|
|
-
|
|
|
- /*
|
|
|
- * Cropping. The partition algorithm can split the image into
|
|
|
- * multiple slices.
|
|
|
- */
|
|
|
- if (pipe->partitions > 1)
|
|
|
- width = pipe->partition->wpf.width;
|
|
|
-
|
|
|
- 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 any corner of the
|
|
|
- * image depending on the combination of flipping and rotation.
|
|
|
- */
|
|
|
-
|
|
|
- /*
|
|
|
- * First take the partition left coordinate into account.
|
|
|
- * Compute the offset to order the partitions correctly on the
|
|
|
- * output based on whether flipping is enabled. Consider
|
|
|
- * horizontal flipping when rotation is disabled but vertical
|
|
|
- * flipping when rotation is enabled, as rotating the image
|
|
|
- * switches the horizontal and vertical directions. The offset
|
|
|
- * is applied horizontally or vertically accordingly.
|
|
|
- */
|
|
|
- if (flip & BIT(WPF_CTRL_HFLIP) && !wpf->flip.rotate)
|
|
|
- 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->wpf.left
|
|
|
- - pipe->partition->wpf.width;
|
|
|
- else
|
|
|
- offset = pipe->partition->wpf.left;
|
|
|
-
|
|
|
- for (i = 0; i < format->num_planes; ++i) {
|
|
|
- unsigned int hsub = i > 0 ? fmtinfo->hsub : 1;
|
|
|
- unsigned int vsub = i > 0 ? fmtinfo->vsub : 1;
|
|
|
-
|
|
|
- if (wpf->flip.rotate)
|
|
|
- mem.addr[i] += offset / vsub
|
|
|
- * format->plane_fmt[i].bytesperline;
|
|
|
- else
|
|
|
- mem.addr[i] += offset / hsub
|
|
|
- * fmtinfo->bpp[i] / 8;
|
|
|
- }
|
|
|
-
|
|
|
- if (flip & BIT(WPF_CTRL_VFLIP)) {
|
|
|
- /*
|
|
|
- * When rotating the output (after rotation) image
|
|
|
- * height is equal to the partition width (before
|
|
|
- * rotation). Otherwise it is equal to the output
|
|
|
- * image height.
|
|
|
- */
|
|
|
- if (wpf->flip.rotate)
|
|
|
- height = pipe->partition->wpf.width;
|
|
|
- else
|
|
|
- height = format->height;
|
|
|
-
|
|
|
- mem.addr[0] += (height - 1)
|
|
|
- * format->plane_fmt[0].bytesperline;
|
|
|
-
|
|
|
- if (format->num_planes > 1) {
|
|
|
- offset = (height / fmtinfo->vsub - 1)
|
|
|
- * format->plane_fmt[1].bytesperline;
|
|
|
- mem.addr[1] += offset;
|
|
|
- mem.addr[2] += offset;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (wpf->flip.rotate && !(flip & BIT(WPF_CTRL_HFLIP))) {
|
|
|
- unsigned int hoffset = max(0, (int)format->width - 16);
|
|
|
-
|
|
|
- /*
|
|
|
- * Compute the output coordinate. The partition
|
|
|
- * horizontal (left) offset becomes a vertical offset.
|
|
|
- */
|
|
|
- for (i = 0; i < format->num_planes; ++i) {
|
|
|
- unsigned int hsub = i > 0 ? fmtinfo->hsub : 1;
|
|
|
-
|
|
|
- mem.addr[i] += hoffset / hsub
|
|
|
- * fmtinfo->bpp[i] / 8;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- * On Gen3 hardware the SPUVS bit has no effect on 3-planar
|
|
|
- * formats. Swap the U and V planes manually in that case.
|
|
|
- */
|
|
|
- if (vsp1->info->gen == 3 && format->num_planes == 3 &&
|
|
|
- fmtinfo->swap_uv)
|
|
|
- swap(mem.addr[1], mem.addr[2]);
|
|
|
-
|
|
|
- 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;
|
|
|
@@ -461,6 +323,160 @@ static void wpf_configure(struct vsp1_entity *entity,
|
|
|
VI6_WFP_IRQ_ENB_DFEE);
|
|
|
}
|
|
|
|
|
|
+static void wpf_configure_frame(struct vsp1_entity *entity,
|
|
|
+ struct vsp1_pipeline *pipe,
|
|
|
+ struct vsp1_dl_list *dl)
|
|
|
+{
|
|
|
+ const unsigned int mask = BIT(WPF_CTRL_VFLIP)
|
|
|
+ | BIT(WPF_CTRL_HFLIP);
|
|
|
+ struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
|
|
|
+ unsigned long flags;
|
|
|
+ u32 outfmt;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&wpf->flip.lock, flags);
|
|
|
+ wpf->flip.active = (wpf->flip.active & ~mask)
|
|
|
+ | (wpf->flip.pending & mask);
|
|
|
+ spin_unlock_irqrestore(&wpf->flip.lock, flags);
|
|
|
+
|
|
|
+ outfmt = (wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT) | wpf->outfmt;
|
|
|
+
|
|
|
+ if (wpf->flip.active & BIT(WPF_CTRL_VFLIP))
|
|
|
+ outfmt |= VI6_WPF_OUTFMT_FLP;
|
|
|
+ if (wpf->flip.active & BIT(WPF_CTRL_HFLIP))
|
|
|
+ outfmt |= VI6_WPF_OUTFMT_HFLP;
|
|
|
+
|
|
|
+ vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, outfmt);
|
|
|
+}
|
|
|
+
|
|
|
+static void wpf_configure_partition(struct vsp1_entity *entity,
|
|
|
+ struct vsp1_pipeline *pipe,
|
|
|
+ struct vsp1_dl_list *dl)
|
|
|
+{
|
|
|
+ struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
|
|
|
+ struct vsp1_device *vsp1 = wpf->entity.vsp1;
|
|
|
+ struct vsp1_rwpf_memory mem = wpf->mem;
|
|
|
+ const struct v4l2_mbus_framefmt *sink_format;
|
|
|
+ const struct v4l2_pix_format_mplane *format = &wpf->format;
|
|
|
+ const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;
|
|
|
+ unsigned int width;
|
|
|
+ unsigned int height;
|
|
|
+ unsigned int offset;
|
|
|
+ unsigned int flip;
|
|
|
+ unsigned int i;
|
|
|
+
|
|
|
+ sink_format = vsp1_entity_get_pad_format(&wpf->entity,
|
|
|
+ wpf->entity.config,
|
|
|
+ RWPF_PAD_SINK);
|
|
|
+ width = sink_format->width;
|
|
|
+ height = sink_format->height;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Cropping. The partition algorithm can split the image into
|
|
|
+ * multiple slices.
|
|
|
+ */
|
|
|
+ if (pipe->partitions > 1)
|
|
|
+ width = pipe->partition->wpf.width;
|
|
|
+
|
|
|
+ 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 any corner of the
|
|
|
+ * image depending on the combination of flipping and rotation.
|
|
|
+ */
|
|
|
+
|
|
|
+ /*
|
|
|
+ * First take the partition left coordinate into account.
|
|
|
+ * Compute the offset to order the partitions correctly on the
|
|
|
+ * output based on whether flipping is enabled. Consider
|
|
|
+ * horizontal flipping when rotation is disabled but vertical
|
|
|
+ * flipping when rotation is enabled, as rotating the image
|
|
|
+ * switches the horizontal and vertical directions. The offset
|
|
|
+ * is applied horizontally or vertically accordingly.
|
|
|
+ */
|
|
|
+ flip = wpf->flip.active;
|
|
|
+
|
|
|
+ if (flip & BIT(WPF_CTRL_HFLIP) && !wpf->flip.rotate)
|
|
|
+ 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->wpf.left
|
|
|
+ - pipe->partition->wpf.width;
|
|
|
+ else
|
|
|
+ offset = pipe->partition->wpf.left;
|
|
|
+
|
|
|
+ for (i = 0; i < format->num_planes; ++i) {
|
|
|
+ unsigned int hsub = i > 0 ? fmtinfo->hsub : 1;
|
|
|
+ unsigned int vsub = i > 0 ? fmtinfo->vsub : 1;
|
|
|
+
|
|
|
+ if (wpf->flip.rotate)
|
|
|
+ mem.addr[i] += offset / vsub
|
|
|
+ * format->plane_fmt[i].bytesperline;
|
|
|
+ else
|
|
|
+ mem.addr[i] += offset / hsub
|
|
|
+ * fmtinfo->bpp[i] / 8;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (flip & BIT(WPF_CTRL_VFLIP)) {
|
|
|
+ /*
|
|
|
+ * When rotating the output (after rotation) image
|
|
|
+ * height is equal to the partition width (before
|
|
|
+ * rotation). Otherwise it is equal to the output
|
|
|
+ * image height.
|
|
|
+ */
|
|
|
+ if (wpf->flip.rotate)
|
|
|
+ height = pipe->partition->wpf.width;
|
|
|
+ else
|
|
|
+ height = format->height;
|
|
|
+
|
|
|
+ mem.addr[0] += (height - 1)
|
|
|
+ * format->plane_fmt[0].bytesperline;
|
|
|
+
|
|
|
+ if (format->num_planes > 1) {
|
|
|
+ offset = (height / fmtinfo->vsub - 1)
|
|
|
+ * format->plane_fmt[1].bytesperline;
|
|
|
+ mem.addr[1] += offset;
|
|
|
+ mem.addr[2] += offset;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (wpf->flip.rotate && !(flip & BIT(WPF_CTRL_HFLIP))) {
|
|
|
+ unsigned int hoffset = max(0, (int)format->width - 16);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Compute the output coordinate. The partition
|
|
|
+ * horizontal (left) offset becomes a vertical offset.
|
|
|
+ */
|
|
|
+ for (i = 0; i < format->num_planes; ++i) {
|
|
|
+ unsigned int hsub = i > 0 ? fmtinfo->hsub : 1;
|
|
|
+
|
|
|
+ mem.addr[i] += hoffset / hsub
|
|
|
+ * fmtinfo->bpp[i] / 8;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * On Gen3 hardware the SPUVS bit has no effect on 3-planar
|
|
|
+ * formats. Swap the U and V planes manually in that case.
|
|
|
+ */
|
|
|
+ if (vsp1->info->gen == 3 && format->num_planes == 3 &&
|
|
|
+ fmtinfo->swap_uv)
|
|
|
+ swap(mem.addr[1], mem.addr[2]);
|
|
|
+
|
|
|
+ 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 unsigned int wpf_max_width(struct vsp1_entity *entity,
|
|
|
struct vsp1_pipeline *pipe)
|
|
|
{
|
|
|
@@ -480,7 +496,9 @@ static void wpf_partition(struct vsp1_entity *entity,
|
|
|
|
|
|
static const struct vsp1_entity_operations wpf_entity_ops = {
|
|
|
.destroy = vsp1_wpf_destroy,
|
|
|
- .configure = wpf_configure,
|
|
|
+ .configure_stream = wpf_configure_stream,
|
|
|
+ .configure_frame = wpf_configure_frame,
|
|
|
+ .configure_partition = wpf_configure_partition,
|
|
|
.max_width = wpf_max_width,
|
|
|
.partition = wpf_partition,
|
|
|
};
|