int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct vsp1_rwpf *rwpf = to_rwpf(subdev); struct v4l2_mbus_framefmt *format; /* Cropping is implemented on the sink pad. */ if (sel->pad != RWPF_PAD_SINK) return -EINVAL; switch (sel->target) { case V4L2_SEL_TGT_CROP: sel->r = *vsp1_rwpf_get_crop(rwpf, cfg, sel->which); break; case V4L2_SEL_TGT_CROP_BOUNDS: format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SINK, sel->which); sel->r.left = 0; sel->r.top = 0; sel->r.width = format->width; sel->r.height = format->height; break; default: return -EINVAL; } return 0; }
int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_rwpf *rwpf = to_rwpf(subdev); struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; /* Default to YUV if the requested format is not supported. */ if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, fmt->pad, fmt->which); if (fmt->pad == RWPF_PAD_SOURCE) { /* The RWPF performs format conversion but can't scale, only the * format code can be changed on the source pad. */ format->code = fmt->format.code; fmt->format = *format; return 0; } format->code = fmt->format.code; format->width = clamp_t(unsigned int, fmt->format.width, RWPF_MIN_WIDTH, rwpf->max_width); format->height = clamp_t(unsigned int, fmt->format.height, RWPF_MIN_HEIGHT, rwpf->max_height); format->field = V4L2_FIELD_NONE; format->colorspace = V4L2_COLORSPACE_SRGB; fmt->format = *format; /* Update the sink crop rectangle. */ crop = vsp1_rwpf_get_crop(rwpf, cfg, fmt->which); crop->left = 0; crop->top = 0; crop->width = fmt->format.width; crop->height = fmt->format.height; /* Propagate the format to the source pad. */ format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SOURCE, fmt->which); *format = fmt->format; return 0; }
*/ if (format->code == MEDIA_BUS_FMT_AYUV8_1X32) { sel->r.left = ALIGN(sel->r.left, 2); sel->r.top = ALIGN(sel->r.top, 2); sel->r.width = round_down(sel->r.width, 2); sel->r.height = round_down(sel->r.height, 2); } sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2); sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2); if (rwpf->entity.type == VSP1_ENTITY_WPF) { sel->r.left = min_t(unsigned int, sel->r.left, 255); sel->r.top = min_t(unsigned int, sel->r.top, 255); } sel->r.width = min_t(unsigned int, sel->r.width, format->width - sel->r.left); sel->r.height = min_t(unsigned int, sel->r.height, format->height - sel->r.top); crop = vsp1_rwpf_get_crop(rwpf, cfg, sel->which); *crop = sel->r; /* Propagate the format to the source pad. */ format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SOURCE, sel->which); format->width = crop->width; format->height = crop->height; return 0; }
static void wpf_configure(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; const struct v4l2_mbus_framefmt *source_format; const struct v4l2_mbus_framefmt *sink_format; const struct v4l2_rect *crop; unsigned int i; u32 outfmt = 0; u32 srcrpf = 0; /* Cropping */ crop = vsp1_rwpf_get_crop(wpf, wpf->entity.config); vsp1_wpf_write(wpf, dl, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN | (crop->left << VI6_WPF_SZCLIP_OFST_SHIFT) | (crop->width << VI6_WPF_SZCLIP_SIZE_SHIFT)); vsp1_wpf_write(wpf, dl, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN | (crop->top << VI6_WPF_SZCLIP_OFST_SHIFT) | (crop->height << VI6_WPF_SZCLIP_SIZE_SHIFT)); /* Format */ 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 (!pipe->lif) { const struct v4l2_pix_format_mplane *format = &wpf->format; const struct vsp1_format_info *fmtinfo = wpf->fmtinfo; outfmt = fmtinfo->hwfmt << VI6_WPF_OUTFMT_WRFMT_SHIFT; if (fmtinfo->alpha) outfmt |= VI6_WPF_OUTFMT_PXA; if (fmtinfo->swap_yc) outfmt |= VI6_WPF_OUTFMT_SPYCS; if (fmtinfo->swap_uv) outfmt |= VI6_WPF_OUTFMT_SPUVS; /* Destination stride and byte swapping. */ vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_STRIDE_Y, format->plane_fmt[0].bytesperline); if (format->num_planes > 1) vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_STRIDE_C, format->plane_fmt[1].bytesperline); vsp1_wpf_write(wpf, dl, VI6_WPF_DSWAP, fmtinfo->swap); } if (sink_format->code != source_format->code) outfmt |= VI6_WPF_OUTFMT_CSC; outfmt |= wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT; vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, outfmt); vsp1_dl_list_write(dl, VI6_DPR_WPF_FPORCH(wpf->entity.index), VI6_DPR_WPF_FPORCH_FP_WPFN); vsp1_dl_list_write(dl, VI6_WPF_WRBCK_CTRL, 0); /* Sources. If the pipeline has a single input and BRU is not used, * configure it as the master layer. Otherwise configure all * inputs as sub-layers and select the virtual RPF as the master * layer. */ for (i = 0; i < vsp1->info->rpf_count; ++i) { struct vsp1_rwpf *input = pipe->inputs[i]; if (!input) continue; srcrpf |= (!pipe->bru && pipe->num_inputs == 1) ? VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index) : VI6_WPF_SRCRPF_RPF_ACT_SUB(input->entity.index); } if (pipe->bru || pipe->num_inputs > 1) srcrpf |= VI6_WPF_SRCRPF_VIRACT_MST; vsp1_wpf_write(wpf, dl, VI6_WPF_SRCRPF, srcrpf); /* Enable interrupts */ vsp1_dl_list_write(dl, VI6_WPF_IRQ_STA(wpf->entity.index), 0); vsp1_dl_list_write(dl, VI6_WPF_IRQ_ENB(wpf->entity.index), VI6_WFP_IRQ_ENB_FREE); }
static void rpf_configure_partition(struct vsp1_entity *entity, struct vsp1_pipeline *pipe, struct vsp1_dl_list *dl, struct vsp1_dl_body *dlb) { struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev); struct vsp1_rwpf_memory mem = rpf->mem; struct vsp1_device *vsp1 = rpf->entity.vsp1; const struct vsp1_format_info *fmtinfo = rpf->fmtinfo; const struct v4l2_pix_format_mplane *format = &rpf->format; struct v4l2_rect crop; /* * 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); /* * Partition Algorithm Control * * The partition algorithm can split this frame into multiple * slices. We must scale our partition window based on the pipe * configuration to match the destination partition window. * To achieve this, we adjust our crop to provide a 'sub-crop' * matching the expected partition window. Only 'left' and * 'width' need to be adjusted. */ if (pipe->partitions > 1) { crop.width = pipe->partition->rpf.width; crop.left += pipe->partition->rpf.left; } if (pipe->interlaced) { crop.height = round_down(crop.height / 2, fmtinfo->vsub); crop.top = round_down(crop.top / 2, fmtinfo->vsub); } vsp1_rpf_write(rpf, dlb, VI6_RPF_SRC_BSIZE, (crop.width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) | (crop.height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT)); vsp1_rpf_write(rpf, dlb, VI6_RPF_SRC_ESIZE, (crop.width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) | (crop.height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT)); mem.addr[0] += crop.top * format->plane_fmt[0].bytesperline + crop.left * fmtinfo->bpp[0] / 8; if (format->num_planes > 1) { unsigned int offset; offset = crop.top * format->plane_fmt[1].bytesperline + crop.left / fmtinfo->hsub * fmtinfo->bpp[1] / 8; mem.addr[1] += offset; mem.addr[2] += offset; } /* * 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]); /* * Interlaced pipelines will use the extended pre-cmd to process * SRCM_ADDR_{Y,C0,C1}. */ if (pipe->interlaced) { vsp1_rpf_configure_autofld(rpf, dl); } else { vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_ADDR_Y, mem.addr[0]); vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_ADDR_C0, mem.addr[1]); vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_ADDR_C1, mem.addr[2]); } }
if (sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; /* Make sure the crop rectangle is entirely contained in the image. The * WPF top and left offsets are limited to 255. */ format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SINK, sel->which); sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2); sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2); if (rwpf->entity.type == VSP1_ENTITY_WPF) { sel->r.left = min_t(unsigned int, sel->r.left, 255); sel->r.top = min_t(unsigned int, sel->r.top, 255); } sel->r.width = min_t(unsigned int, sel->r.width, format->width - sel->r.left); sel->r.height = min_t(unsigned int, sel->r.height, format->height - sel->r.top); crop = vsp1_rwpf_get_crop(rwpf, fh, sel->which); *crop = sel->r; /* Propagate the format to the source pad. */ format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SOURCE, sel->which); format->width = crop->width; format->height = crop->height; return 0; }