Driver should tell the number of memory planes and component planes.
the amphion vpu support non contiguous planes,
but for compatibility with other device
that only support contiguous planes.
driver can add support for contiguous planes in the same time.
Then the mem_planes can be different from the comp_planes.
driver need to handle buffer according mem_planes and comp_planes.
So driver can support NV12 and NV12M.
Signed-off-by: Ming Qian <ming.qian@nxp.com>
Reviewed-by: Tommaso Merciai <tommaso.merciai@amarulasolutions.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
static const struct vpu_format vdec_formats[] = {
{
.pixfmt = V4L2_PIX_FMT_NV12M_8L128,
- .num_planes = 2,
+ .mem_planes = 2,
+ .comp_planes = 2,
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
},
{
.pixfmt = V4L2_PIX_FMT_NV12M_10BE_8L128,
- .num_planes = 2,
+ .mem_planes = 2,
+ .comp_planes = 2,
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
},
{
.pixfmt = V4L2_PIX_FMT_H264,
- .num_planes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
- .flags = V4L2_FMT_FLAG_DYN_RESOLUTION
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED
},
{
.pixfmt = V4L2_PIX_FMT_H264_MVC,
- .num_planes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
- .flags = V4L2_FMT_FLAG_DYN_RESOLUTION
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED
},
{
.pixfmt = V4L2_PIX_FMT_HEVC,
- .num_planes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
- .flags = V4L2_FMT_FLAG_DYN_RESOLUTION
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED
},
{
.pixfmt = V4L2_PIX_FMT_VC1_ANNEX_G,
- .num_planes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
- .flags = V4L2_FMT_FLAG_DYN_RESOLUTION
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED
},
{
.pixfmt = V4L2_PIX_FMT_VC1_ANNEX_L,
- .num_planes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .flags = V4L2_FMT_FLAG_COMPRESSED
},
{
.pixfmt = V4L2_PIX_FMT_MPEG2,
- .num_planes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
- .flags = V4L2_FMT_FLAG_DYN_RESOLUTION
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED
},
{
.pixfmt = V4L2_PIX_FMT_MPEG4,
- .num_planes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
- .flags = V4L2_FMT_FLAG_DYN_RESOLUTION
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED
},
{
.pixfmt = V4L2_PIX_FMT_XVID,
- .num_planes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
- .flags = V4L2_FMT_FLAG_DYN_RESOLUTION
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED
},
{
.pixfmt = V4L2_PIX_FMT_VP8,
- .num_planes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
- .flags = V4L2_FMT_FLAG_DYN_RESOLUTION
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED
},
{
.pixfmt = V4L2_PIX_FMT_H263,
- .num_planes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
- .flags = V4L2_FMT_FLAG_DYN_RESOLUTION
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED
},
{0, 0, 0, 0},
};
int ret = -EINVAL;
vpu_inst_lock(inst);
- if (!V4L2_TYPE_IS_OUTPUT(f->type) && vdec->fixed_fmt) {
- if (f->index == 0) {
- f->pixelformat = inst->cap_format.pixfmt;
- f->flags = inst->cap_format.flags;
- ret = 0;
- }
+ if (V4L2_TYPE_IS_CAPTURE(f->type) && vdec->fixed_fmt) {
+ fmt = vpu_get_format(inst, f->type);
+ if (f->index == 1)
+ fmt = vpu_helper_find_sibling(inst, f->type, fmt->pixfmt);
+ if (f->index > 1)
+ fmt = NULL;
} else {
fmt = vpu_helper_enum_format(inst, f->type, f->index);
- memset(f->reserved, 0, sizeof(f->reserved));
- if (!fmt)
- goto exit;
-
- f->pixelformat = fmt->pixfmt;
- f->flags = fmt->flags;
- ret = 0;
}
+ if (!fmt)
+ goto exit;
+ memset(f->reserved, 0, sizeof(f->reserved));
+ f->pixelformat = fmt->pixfmt;
+ f->flags = fmt->flags;
+ ret = 0;
exit:
vpu_inst_unlock(inst);
return ret;
cur_fmt = vpu_get_format(inst, f->type);
pixmp->pixelformat = cur_fmt->pixfmt;
- pixmp->num_planes = cur_fmt->num_planes;
+ pixmp->num_planes = cur_fmt->mem_planes;
pixmp->width = cur_fmt->width;
pixmp->height = cur_fmt->height;
pixmp->field = cur_fmt->field;
pixmp->flags = cur_fmt->flags;
for (i = 0; i < pixmp->num_planes; i++) {
pixmp->plane_fmt[i].bytesperline = cur_fmt->bytesperline[i];
- pixmp->plane_fmt[i].sizeimage = cur_fmt->sizeimage[i];
+ pixmp->plane_fmt[i].sizeimage = vpu_get_fmt_plane_size(cur_fmt, i);
}
f->fmt.pix_mp.colorspace = vdec->codec_info.color_primaries;
{
struct vpu_inst *inst = to_inst(file);
struct vdec_t *vdec = inst->priv;
-
- vpu_try_fmt_common(inst, f);
+ struct vpu_format fmt;
vpu_inst_lock(inst);
+ if (V4L2_TYPE_IS_CAPTURE(f->type) && vdec->fixed_fmt) {
+ struct vpu_format *cap_fmt = vpu_get_format(inst, f->type);
+
+ if (!vpu_helper_match_format(inst, cap_fmt->type, cap_fmt->pixfmt,
+ f->fmt.pix_mp.pixelformat))
+ f->fmt.pix_mp.pixelformat = cap_fmt->pixfmt;
+ }
+
+ vpu_try_fmt_common(inst, f, &fmt);
+
if (vdec->fixed_fmt) {
f->fmt.pix_mp.colorspace = vdec->codec_info.color_primaries;
f->fmt.pix_mp.xfer_func = vdec->codec_info.transfer_chars;
static int vdec_s_fmt_common(struct vpu_inst *inst, struct v4l2_format *f)
{
struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
- const struct vpu_format *fmt;
+ struct vpu_format fmt;
struct vpu_format *cur_fmt;
struct vb2_queue *q;
struct vdec_t *vdec = inst->priv;
if (vb2_is_busy(q))
return -EBUSY;
- fmt = vpu_try_fmt_common(inst, f);
- if (!fmt)
+ if (vpu_try_fmt_common(inst, f, &fmt))
return -EINVAL;
cur_fmt = vpu_get_format(inst, f->type);
if (V4L2_TYPE_IS_OUTPUT(f->type) && inst->state != VPU_CODEC_STATE_DEINIT) {
- if (cur_fmt->pixfmt != fmt->pixfmt) {
+ if (cur_fmt->pixfmt != fmt.pixfmt) {
vdec->reset_codec = true;
vdec->fixed_fmt = false;
}
}
- cur_fmt->pixfmt = fmt->pixfmt;
if (V4L2_TYPE_IS_OUTPUT(f->type) || !vdec->fixed_fmt) {
- cur_fmt->num_planes = fmt->num_planes;
- cur_fmt->flags = fmt->flags;
- cur_fmt->width = pixmp->width;
- cur_fmt->height = pixmp->height;
- for (i = 0; i < fmt->num_planes; i++) {
- cur_fmt->sizeimage[i] = pixmp->plane_fmt[i].sizeimage;
- cur_fmt->bytesperline[i] = pixmp->plane_fmt[i].bytesperline;
- }
- if (pixmp->field != V4L2_FIELD_ANY)
- cur_fmt->field = pixmp->field;
+ memcpy(cur_fmt, &fmt, sizeof(*cur_fmt));
} else {
- pixmp->num_planes = cur_fmt->num_planes;
+ if (vpu_helper_match_format(inst, f->type, cur_fmt->pixfmt, pixmp->pixelformat)) {
+ cur_fmt->pixfmt = fmt.pixfmt;
+ cur_fmt->mem_planes = fmt.mem_planes;
+ }
+ pixmp->pixelformat = cur_fmt->pixfmt;
+ pixmp->num_planes = cur_fmt->mem_planes;
pixmp->width = cur_fmt->width;
pixmp->height = cur_fmt->height;
for (i = 0; i < pixmp->num_planes; i++) {
pixmp->plane_fmt[i].bytesperline = cur_fmt->bytesperline[i];
- pixmp->plane_fmt[i].sizeimage = cur_fmt->sizeimage[i];
+ pixmp->plane_fmt[i].sizeimage = vpu_get_fmt_plane_size(cur_fmt, i);
}
pixmp->field = cur_fmt->field;
}
static void vdec_buf_done(struct vpu_inst *inst, struct vpu_frame_info *frame)
{
struct vdec_t *vdec = inst->priv;
+ struct vpu_format *cur_fmt;
struct vpu_vb2_buffer *vpu_buf;
struct vb2_v4l2_buffer *vbuf;
u32 sequence;
+ int i;
if (!frame)
return;
return;
}
+ cur_fmt = vpu_get_format(inst, inst->cap_format.type);
vbuf = &vpu_buf->m2m_buf.vb;
if (vbuf->vb2_buf.index != frame->id)
dev_err(inst->dev, "[%d] buffer id(%d, %d) dismatch\n",
if (vpu_get_buffer_state(vbuf) != VPU_BUF_STATE_DECODED)
dev_err(inst->dev, "[%d] buffer(%d) ready without decoded\n", inst->id, frame->id);
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_READY);
- vb2_set_plane_payload(&vbuf->vb2_buf, 0, inst->cap_format.sizeimage[0]);
- vb2_set_plane_payload(&vbuf->vb2_buf, 1, inst->cap_format.sizeimage[1]);
- vbuf->field = inst->cap_format.field;
+ for (i = 0; i < vbuf->vb2_buf.num_planes; i++)
+ vb2_set_plane_payload(&vbuf->vb2_buf, i, vpu_get_fmt_plane_size(cur_fmt, i));
+ vbuf->field = cur_fmt->field;
vbuf->sequence = sequence;
dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, vbuf->vb2_buf.timestamp);
static bool vdec_check_source_change(struct vpu_inst *inst)
{
struct vdec_t *vdec = inst->priv;
- const struct vpu_format *fmt;
- int i;
+ const struct vpu_format *sibling;
if (!inst->fh.m2m_ctx)
return false;
if (vdec->reset_codec)
return false;
+ sibling = vpu_helper_find_sibling(inst, inst->cap_format.type, inst->cap_format.pixfmt);
+ if (sibling && vdec->codec_info.pixfmt == sibling->pixfmt)
+ vdec->codec_info.pixfmt = inst->cap_format.pixfmt;
+
if (!vb2_is_streaming(v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx)))
return true;
- fmt = vpu_helper_find_format(inst, inst->cap_format.type, vdec->codec_info.pixfmt);
if (inst->cap_format.pixfmt != vdec->codec_info.pixfmt)
return true;
if (inst->cap_format.width != vdec->codec_info.decoded_width)
return true;
if (inst->crop.height != vdec->codec_info.height)
return true;
- if (fmt && inst->cap_format.num_planes != fmt->num_planes)
- return true;
- for (i = 0; i < inst->cap_format.num_planes; i++) {
- if (inst->cap_format.bytesperline[i] != vdec->codec_info.bytesperline[i])
- return true;
- if (inst->cap_format.sizeimage[i] != vdec->codec_info.sizeimage[i])
- return true;
- }
return false;
}
static void vdec_init_fmt(struct vpu_inst *inst)
{
struct vdec_t *vdec = inst->priv;
- const struct vpu_format *fmt;
- int i;
+ struct v4l2_format f;
- fmt = vpu_helper_find_format(inst, inst->cap_format.type, vdec->codec_info.pixfmt);
- inst->out_format.width = vdec->codec_info.width;
- inst->out_format.height = vdec->codec_info.height;
- inst->cap_format.width = vdec->codec_info.decoded_width;
- inst->cap_format.height = vdec->codec_info.decoded_height;
- inst->cap_format.pixfmt = vdec->codec_info.pixfmt;
- if (fmt) {
- inst->cap_format.num_planes = fmt->num_planes;
- inst->cap_format.flags = fmt->flags;
- }
- for (i = 0; i < inst->cap_format.num_planes; i++) {
- inst->cap_format.bytesperline[i] = vdec->codec_info.bytesperline[i];
- inst->cap_format.sizeimage[i] = vdec->codec_info.sizeimage[i];
- }
+ memset(&f, 0, sizeof(f));
+ f.type = inst->cap_format.type;
+ f.fmt.pix_mp.pixelformat = vdec->codec_info.pixfmt;
+ f.fmt.pix_mp.width = vdec->codec_info.decoded_width;
+ f.fmt.pix_mp.height = vdec->codec_info.decoded_height;
if (vdec->codec_info.progressive)
- inst->cap_format.field = V4L2_FIELD_NONE;
+ f.fmt.pix_mp.field = V4L2_FIELD_NONE;
else
- inst->cap_format.field = V4L2_FIELD_SEQ_TB;
+ f.fmt.pix_mp.field = V4L2_FIELD_SEQ_TB;
+ vpu_try_fmt_common(inst, &f, &inst->cap_format);
+
+ inst->out_format.width = vdec->codec_info.width;
+ inst->out_format.height = vdec->codec_info.height;
}
static void vdec_init_crop(struct vpu_inst *inst)
info.tag = vdec->seq_tag;
info.luma_addr = vpu_get_vb_phy_addr(&vbuf->vb2_buf, 0);
info.luma_size = inst->cap_format.sizeimage[0];
- info.chroma_addr = vpu_get_vb_phy_addr(&vbuf->vb2_buf, 1);
+ if (vbuf->vb2_buf.num_planes > 1)
+ info.chroma_addr = vpu_get_vb_phy_addr(&vbuf->vb2_buf, 1);
+ else
+ info.chroma_addr = info.luma_addr + info.luma_size;
info.chromau_size = inst->cap_format.sizeimage[1];
info.bytesperline = inst->cap_format.bytesperline[0];
ret = vpu_session_alloc_fs(inst, &info);
vpu_buf->tag = info.tag;
vpu_buf->luma = info.luma_addr;
- vpu_buf->chroma_u = info.chromau_size;
+ vpu_buf->chroma_u = info.chroma_addr;
vpu_buf->chroma_v = 0;
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_INUSE);
vdec->slots[info.id] = vpu_buf;
static const struct vpu_format venc_formats[] = {
{
.pixfmt = V4L2_PIX_FMT_NV12M,
- .num_planes = 2,
+ .mem_planes = 2,
+ .comp_planes = 2,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
},
{
.pixfmt = V4L2_PIX_FMT_H264,
- .num_planes = 1,
+ .mem_planes = 1,
+ .comp_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ .flags = V4L2_FMT_FLAG_COMPRESSED
},
{0, 0, 0, 0},
};
cur_fmt = vpu_get_format(inst, f->type);
pixmp->pixelformat = cur_fmt->pixfmt;
- pixmp->num_planes = cur_fmt->num_planes;
+ pixmp->num_planes = cur_fmt->mem_planes;
pixmp->width = cur_fmt->width;
pixmp->height = cur_fmt->height;
pixmp->field = cur_fmt->field;
pixmp->flags = cur_fmt->flags;
for (i = 0; i < pixmp->num_planes; i++) {
pixmp->plane_fmt[i].bytesperline = cur_fmt->bytesperline[i];
- pixmp->plane_fmt[i].sizeimage = cur_fmt->sizeimage[i];
+ pixmp->plane_fmt[i].sizeimage = vpu_get_fmt_plane_size(cur_fmt, i);
}
f->fmt.pix_mp.colorspace = venc->params.color.primaries;
static int venc_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
{
struct vpu_inst *inst = to_inst(file);
+ struct vpu_format fmt;
- vpu_try_fmt_common(inst, f);
+ vpu_try_fmt_common(inst, f, &fmt);
return 0;
}
static int venc_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
{
struct vpu_inst *inst = to_inst(file);
- const struct vpu_format *fmt;
+ struct vpu_format fmt;
struct vpu_format *cur_fmt;
struct vb2_queue *q;
struct venc_t *venc = inst->priv;
struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
- int i;
q = v4l2_m2m_get_vq(inst->fh.m2m_ctx, f->type);
if (!q)
if (vb2_is_busy(q))
return -EBUSY;
- fmt = vpu_try_fmt_common(inst, f);
- if (!fmt)
+ if (vpu_try_fmt_common(inst, f, &fmt))
return -EINVAL;
cur_fmt = vpu_get_format(inst, f->type);
- cur_fmt->pixfmt = fmt->pixfmt;
- cur_fmt->num_planes = fmt->num_planes;
- cur_fmt->flags = fmt->flags;
- cur_fmt->width = pix_mp->width;
- cur_fmt->height = pix_mp->height;
- for (i = 0; i < fmt->num_planes; i++) {
- cur_fmt->sizeimage[i] = pix_mp->plane_fmt[i].sizeimage;
- cur_fmt->bytesperline[i] = pix_mp->plane_fmt[i].bytesperline;
- }
-
- if (pix_mp->field != V4L2_FIELD_ANY)
- cur_fmt->field = pix_mp->field;
+ memcpy(cur_fmt, &fmt, sizeof(*cur_fmt));
if (V4L2_TYPE_IS_OUTPUT(f->type)) {
venc->params.input_format = cur_fmt->pixfmt;
struct vpu_format {
u32 pixfmt;
- unsigned int num_planes;
+ u32 mem_planes;
+ u32 comp_planes;
u32 type;
u32 flags;
u32 width;
u32 sizeimage[VIDEO_MAX_PLANES];
u32 bytesperline[VIDEO_MAX_PLANES];
u32 field;
+ u32 sibling;
};
struct vpu_core_resources {
vq->last_buffer_dequeued);
if (seq_write(s, str, num))
return 0;
- for (i = 0; i < inst->out_format.num_planes; i++) {
+ for (i = 0; i < inst->out_format.mem_planes; i++) {
num = scnprintf(str, sizeof(str), " %d(%d)",
- inst->out_format.sizeimage[i],
+ vpu_get_fmt_plane_size(&inst->out_format, i),
inst->out_format.bytesperline[i]);
if (seq_write(s, str, num))
return 0;
vq->last_buffer_dequeued);
if (seq_write(s, str, num))
return 0;
- for (i = 0; i < inst->cap_format.num_planes; i++) {
+ for (i = 0; i < inst->cap_format.mem_planes; i++) {
num = scnprintf(str, sizeof(str), " %d(%d)",
- inst->cap_format.sizeimage[i],
+ vpu_get_fmt_plane_size(&inst->cap_format, i),
inst->cap_format.bytesperline[i]);
if (seq_write(s, str, num))
return 0;
return NULL;
}
+const struct vpu_format *vpu_helper_find_sibling(struct vpu_inst *inst, u32 type, u32 pixelfmt)
+{
+ const struct vpu_format *fmt;
+ const struct vpu_format *sibling;
+
+ fmt = vpu_helper_find_format(inst, type, pixelfmt);
+ if (!fmt || !fmt->sibling)
+ return NULL;
+
+ sibling = vpu_helper_find_format(inst, type, fmt->sibling);
+ if (!sibling || sibling->sibling != fmt->pixfmt ||
+ sibling->comp_planes != fmt->comp_planes)
+ return NULL;
+
+ return sibling;
+}
+
+bool vpu_helper_match_format(struct vpu_inst *inst, u32 type, u32 fmta, u32 fmtb)
+{
+ const struct vpu_format *sibling;
+
+ if (fmta == fmtb)
+ return true;
+
+ sibling = vpu_helper_find_sibling(inst, type, fmta);
+ if (sibling && sibling->pixfmt == fmtb)
+ return true;
+ return false;
+}
+
const struct vpu_format *vpu_helper_enum_format(struct vpu_inst *inst, u32 type, int index)
{
const struct vpu_format *pfmt;
u32 bytesperline;
u32 size = 0;
- bytesperline = ALIGN(width, stride);
+ bytesperline = width;
if (pbl)
bytesperline = max(bytesperline, *pbl);
+ bytesperline = ALIGN(bytesperline, stride);
height = ALIGN(height, 2);
if (plane_no == 0)
size = bytesperline * height;
if (interlaced)
hs++;
- if (fmt == V4L2_PIX_FMT_NV12M_10BE_8L128)
+ if (fmt == V4L2_PIX_FMT_NV12M_10BE_8L128 || fmt == V4L2_PIX_FMT_NV12_10BE_8L128)
bitdepth = 10;
bytesperline = DIV_ROUND_UP(width * bitdepth, BITS_PER_BYTE);
- bytesperline = ALIGN(bytesperline, 1 << ws);
- bytesperline = ALIGN(bytesperline, stride);
if (pbl)
bytesperline = max(bytesperline, *pbl);
+ bytesperline = ALIGN(bytesperline, 1 << ws);
+ bytesperline = ALIGN(bytesperline, stride);
height = ALIGN(height, 1 << hs);
if (plane_no == 0)
size = bytesperline * height;
u32 bytesperline;
u32 size = 0;
- bytesperline = ALIGN(width, stride);
+ bytesperline = width;
if (pbl)
bytesperline = max(bytesperline, *pbl);
+ bytesperline = ALIGN(bytesperline, stride);
if (plane_no == 0)
size = bytesperline * height;
if (pbl)
u32 stride, u32 interlaced, u32 *pbl)
{
switch (fmt) {
+ case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV12M:
return get_nv12_plane_size(w, h, plane_no, stride, interlaced, pbl);
+ case V4L2_PIX_FMT_NV12_8L128:
case V4L2_PIX_FMT_NV12M_8L128:
+ case V4L2_PIX_FMT_NV12_10BE_8L128:
case V4L2_PIX_FMT_NV12M_10BE_8L128:
return get_tiled_8l128_plane_size(fmt, w, h, plane_no, stride, interlaced, pbl);
default:
int vpu_helper_find_in_array_u8(const u8 *array, u32 size, u32 x);
bool vpu_helper_check_type(struct vpu_inst *inst, u32 type);
const struct vpu_format *vpu_helper_find_format(struct vpu_inst *inst, u32 type, u32 pixelfmt);
+const struct vpu_format *vpu_helper_find_sibling(struct vpu_inst *inst, u32 type, u32 pixelfmt);
+bool vpu_helper_match_format(struct vpu_inst *inst, u32 type, u32 fmta, u32 fmtb);
const struct vpu_format *vpu_helper_enum_format(struct vpu_inst *inst, u32 type, int index);
u32 vpu_helper_valid_frame_width(struct vpu_inst *inst, u32 width);
u32 vpu_helper_valid_frame_height(struct vpu_inst *inst, u32 height);
if (!vpu_imx8q_check_fmt(type, pixelfmt))
return false;
- if (pixelfmt == V4L2_PIX_FMT_NV12M_8L128 || pixelfmt == V4L2_PIX_FMT_NV12M_10BE_8L128)
+ if (pixelfmt == V4L2_PIX_FMT_NV12_8L128 || pixelfmt == V4L2_PIX_FMT_NV12_10BE_8L128 ||
+ pixelfmt == V4L2_PIX_FMT_NV12M_8L128 || pixelfmt == V4L2_PIX_FMT_NV12M_10BE_8L128)
return true;
if (vpu_malone_format_remap(pixelfmt) == MALONE_FMT_NULL)
return false;
return true;
}
-const struct vpu_format *vpu_try_fmt_common(struct vpu_inst *inst, struct v4l2_format *f)
+static int vpu_init_format(struct vpu_inst *inst, struct vpu_format *fmt)
+{
+ const struct vpu_format *info;
+
+ info = vpu_helper_find_format(inst, fmt->type, fmt->pixfmt);
+ if (!info) {
+ info = vpu_helper_enum_format(inst, fmt->type, 0);
+ if (!info)
+ return -EINVAL;
+ }
+ memcpy(fmt, info, sizeof(*fmt));
+
+ return 0;
+}
+
+static int vpu_calc_fmt_bytesperline(struct v4l2_format *f, struct vpu_format *fmt)
{
struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
- u32 type = f->type;
+ int i;
+
+ if (fmt->flags & V4L2_FMT_FLAG_COMPRESSED) {
+ for (i = 0; i < fmt->comp_planes; i++)
+ fmt->bytesperline[i] = 0;
+ return 0;
+ }
+ if (pixmp->num_planes == fmt->comp_planes) {
+ for (i = 0; i < fmt->comp_planes; i++)
+ fmt->bytesperline[i] = pixmp->plane_fmt[i].bytesperline;
+ return 0;
+ }
+ if (pixmp->num_planes > 1)
+ return -EINVAL;
+
+ /*amphion vpu only support nv12 and nv12 tiled,
+ * so the bytesperline of luma and chroma should be same
+ */
+ for (i = 0; i < fmt->comp_planes; i++)
+ fmt->bytesperline[i] = pixmp->plane_fmt[0].bytesperline;
+
+ return 0;
+}
+
+static int vpu_calc_fmt_sizeimage(struct vpu_inst *inst, struct vpu_format *fmt)
+{
u32 stride = 1;
- u32 bytesperline;
- u32 sizeimage;
- const struct vpu_format *fmt;
- const struct vpu_core_resources *res;
int i;
- fmt = vpu_helper_find_format(inst, type, pixmp->pixelformat);
- if (!fmt) {
- fmt = vpu_helper_enum_format(inst, type, 0);
- if (!fmt)
- return NULL;
- pixmp->pixelformat = fmt->pixfmt;
+ if (!(fmt->flags & V4L2_FMT_FLAG_COMPRESSED)) {
+ const struct vpu_core_resources *res = vpu_get_resource(inst);
+
+ if (res)
+ stride = res->stride;
}
- res = vpu_get_resource(inst);
- if (res)
- stride = res->stride;
- if (pixmp->width)
- pixmp->width = vpu_helper_valid_frame_width(inst, pixmp->width);
- if (pixmp->height)
- pixmp->height = vpu_helper_valid_frame_height(inst, pixmp->height);
+ for (i = 0; i < fmt->comp_planes; i++) {
+ fmt->sizeimage[i] = vpu_helper_get_plane_size(fmt->pixfmt,
+ fmt->width,
+ fmt->height,
+ i,
+ stride,
+ fmt->field != V4L2_FIELD_NONE ? 1 : 0,
+ &fmt->bytesperline[i]);
+ fmt->sizeimage[i] = max_t(u32, fmt->sizeimage[i], PAGE_SIZE);
+ if (fmt->flags & V4L2_FMT_FLAG_COMPRESSED) {
+ fmt->sizeimage[i] = clamp_val(fmt->sizeimage[i], SZ_128K, SZ_8M);
+ fmt->bytesperline[i] = 0;
+ }
+ }
+
+ return 0;
+}
+
+u32 vpu_get_fmt_plane_size(struct vpu_format *fmt, u32 plane_no)
+{
+ u32 size;
+ int i;
+
+ if (plane_no >= fmt->mem_planes)
+ return 0;
+
+ if (fmt->comp_planes == fmt->mem_planes)
+ return fmt->sizeimage[plane_no];
+ if (plane_no < fmt->mem_planes - 1)
+ return fmt->sizeimage[plane_no];
+
+ size = fmt->sizeimage[plane_no];
+ for (i = fmt->mem_planes; i < fmt->comp_planes; i++)
+ size += fmt->sizeimage[i];
+
+ return size;
+}
+
+int vpu_try_fmt_common(struct vpu_inst *inst, struct v4l2_format *f, struct vpu_format *fmt)
+{
+ struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
+ int i;
+ int ret;
+
+ fmt->pixfmt = pixmp->pixelformat;
+ fmt->type = f->type;
+ ret = vpu_init_format(inst, fmt);
+ if (ret < 0)
+ return ret;
+
+ fmt->width = pixmp->width;
+ fmt->height = pixmp->height;
+ if (fmt->width)
+ fmt->width = vpu_helper_valid_frame_width(inst, fmt->width);
+ if (fmt->height)
+ fmt->height = vpu_helper_valid_frame_height(inst, fmt->height);
+ fmt->field = pixmp->field == V4L2_FIELD_ANY ? V4L2_FIELD_NONE : pixmp->field;
+ vpu_calc_fmt_bytesperline(f, fmt);
+ vpu_calc_fmt_sizeimage(inst, fmt);
+ if ((fmt->flags & V4L2_FMT_FLAG_COMPRESSED) && pixmp->plane_fmt[0].sizeimage)
+ fmt->sizeimage[0] = clamp_val(pixmp->plane_fmt[0].sizeimage, SZ_128K, SZ_8M);
+
+ pixmp->pixelformat = fmt->pixfmt;
+ pixmp->width = fmt->width;
+ pixmp->height = fmt->height;
pixmp->flags = fmt->flags;
- pixmp->num_planes = fmt->num_planes;
- if (pixmp->field == V4L2_FIELD_ANY)
- pixmp->field = V4L2_FIELD_NONE;
+ pixmp->num_planes = fmt->mem_planes;
+ pixmp->field = fmt->field;
+ memset(pixmp->reserved, 0, sizeof(pixmp->reserved));
for (i = 0; i < pixmp->num_planes; i++) {
- bytesperline = max_t(s32, pixmp->plane_fmt[i].bytesperline, 0);
- sizeimage = vpu_helper_get_plane_size(pixmp->pixelformat,
- pixmp->width,
- pixmp->height,
- i,
- stride,
- pixmp->field > V4L2_FIELD_NONE ? 1 : 0,
- &bytesperline);
- sizeimage = max_t(s32, pixmp->plane_fmt[i].sizeimage, sizeimage);
- pixmp->plane_fmt[i].bytesperline = bytesperline;
- pixmp->plane_fmt[i].sizeimage = sizeimage;
+ pixmp->plane_fmt[i].bytesperline = fmt->bytesperline[i];
+ pixmp->plane_fmt[i].sizeimage = vpu_get_fmt_plane_size(fmt, i);
+ memset(pixmp->plane_fmt[i].reserved, 0, sizeof(pixmp->plane_fmt[i].reserved));
}
- return fmt;
+ return 0;
}
static bool vpu_check_ready(struct vpu_inst *inst, u32 type)
cur_fmt = vpu_get_format(inst, vq->type);
if (*plane_count) {
- if (*plane_count != cur_fmt->num_planes)
+ if (*plane_count != cur_fmt->mem_planes)
return -EINVAL;
- for (i = 0; i < cur_fmt->num_planes; i++) {
- if (psize[i] < cur_fmt->sizeimage[i])
+ for (i = 0; i < cur_fmt->mem_planes; i++) {
+ if (psize[i] < vpu_get_fmt_plane_size(cur_fmt, i))
return -EINVAL;
}
return 0;
*buf_count = max_t(unsigned int, *buf_count, inst->min_buffer_out);
else
*buf_count = max_t(unsigned int, *buf_count, inst->min_buffer_cap);
- *plane_count = cur_fmt->num_planes;
- for (i = 0; i < cur_fmt->num_planes; i++)
- psize[i] = cur_fmt->sizeimage[i];
+ *plane_count = cur_fmt->mem_planes;
+ for (i = 0; i < cur_fmt->mem_planes; i++)
+ psize[i] = vpu_get_fmt_plane_size(cur_fmt, i);
return 0;
}
u32 i;
cur_fmt = vpu_get_format(inst, vb->type);
- for (i = 0; i < cur_fmt->num_planes; i++) {
- if (vpu_get_vb_length(vb, i) < cur_fmt->sizeimage[i]) {
+ for (i = 0; i < cur_fmt->mem_planes; i++) {
+ if (vpu_get_vb_length(vb, i) < vpu_get_fmt_plane_size(cur_fmt, i)) {
dev_dbg(inst->dev, "[%d] %s buf[%d] is invalid\n",
inst->id, vpu_type_name(vb->type), vb->index);
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_ERROR);
int vpu_v4l2_open(struct file *file, struct vpu_inst *inst);
int vpu_v4l2_close(struct file *file);
-const struct vpu_format *vpu_try_fmt_common(struct vpu_inst *inst, struct v4l2_format *f);
+u32 vpu_get_fmt_plane_size(struct vpu_format *fmt, u32 plane_no);
+int vpu_try_fmt_common(struct vpu_inst *inst, struct v4l2_format *f, struct vpu_format *fmt);
int vpu_process_output_buffer(struct vpu_inst *inst);
int vpu_process_capture_buffer(struct vpu_inst *inst);
struct vb2_v4l2_buffer *vpu_next_src_buf(struct vpu_inst *inst);
u32 instance,
struct vb2_buffer *vb)
{
+ struct vpu_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
+ struct vpu_format *out_fmt;
struct vpu_enc_yuv_desc *desc;
struct vb2_v4l2_buffer *vbuf;
return -EINVAL;
desc = get_yuv_desc(shared, instance);
+ out_fmt = vpu_get_format(inst, vb->type);
vbuf = to_vb2_v4l2_buffer(vb);
desc->frame_id = vbuf->sequence;
else
desc->key_frame = 0;
desc->luma_base = vpu_get_vb_phy_addr(vb, 0);
- desc->chroma_base = vpu_get_vb_phy_addr(vb, 1);
+ if (vb->num_planes > 1)
+ desc->chroma_base = vpu_get_vb_phy_addr(vb, 1);
+ else
+ desc->chroma_base = desc->luma_base + out_fmt->sizeimage[0];
return 0;
}