Commit 8c3dc73d authored by Ezequiel Garcia's avatar Ezequiel Garcia Committed by Mauro Carvalho Chehab

media: rockchip/vpu: Add decoder boilerplate

This commit adds the needed boilerplate code to support the VPU
in decoding operation. Two v4l2 interfaces are exposed, one for
encoding and one for decoding, but a single m2m device is shared
by them, so jobs are properly serialized.
Signed-off-by: default avatarEzequiel Garcia <ezequiel@collabora.com>
Signed-off-by: default avatarBoris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent 953aaa14
...@@ -3,6 +3,7 @@ config VIDEO_ROCKCHIP_VPU ...@@ -3,6 +3,7 @@ config VIDEO_ROCKCHIP_VPU
tristate "Rockchip VPU driver" tristate "Rockchip VPU driver"
depends on ARCH_ROCKCHIP || COMPILE_TEST depends on ARCH_ROCKCHIP || COMPILE_TEST
depends on VIDEO_DEV && VIDEO_V4L2 && MEDIA_CONTROLLER depends on VIDEO_DEV && VIDEO_V4L2 && MEDIA_CONTROLLER
depends on MEDIA_CONTROLLER_REQUEST_API
select VIDEOBUF2_DMA_CONTIG select VIDEOBUF2_DMA_CONTIG
select VIDEOBUF2_VMALLOC select VIDEOBUF2_VMALLOC
select V4L2_MEM2MEM_DEV select V4L2_MEM2MEM_DEV
......
...@@ -40,23 +40,31 @@ struct rockchip_vpu_codec_ops; ...@@ -40,23 +40,31 @@ struct rockchip_vpu_codec_ops;
* struct rockchip_vpu_variant - information about VPU hardware variant * struct rockchip_vpu_variant - information about VPU hardware variant
* *
* @enc_offset: Offset from VPU base to encoder registers. * @enc_offset: Offset from VPU base to encoder registers.
* @dec_offset: Offset from VPU base to decoder registers.
* @enc_fmts: Encoder formats. * @enc_fmts: Encoder formats.
* @num_enc_fmts: Number of encoder formats. * @num_enc_fmts: Number of encoder formats.
* @dec_fmts: Decoder formats.
* @num_dec_fmts: Number of decoder formats.
* @codec: Supported codecs * @codec: Supported codecs
* @codec_ops: Codec ops. * @codec_ops: Codec ops.
* @init: Initialize hardware. * @init: Initialize hardware.
* @vepu_irq: encoder interrupt handler * @vepu_irq: encoder interrupt handler
* @vdpu_irq: decoder interrupt handler
* @clk_names: array of clock names * @clk_names: array of clock names
* @num_clocks: number of clocks in the array * @num_clocks: number of clocks in the array
*/ */
struct rockchip_vpu_variant { struct rockchip_vpu_variant {
unsigned int enc_offset; unsigned int enc_offset;
unsigned int dec_offset;
const struct rockchip_vpu_fmt *enc_fmts; const struct rockchip_vpu_fmt *enc_fmts;
unsigned int num_enc_fmts; unsigned int num_enc_fmts;
const struct rockchip_vpu_fmt *dec_fmts;
unsigned int num_dec_fmts;
unsigned int codec; unsigned int codec;
const struct rockchip_vpu_codec_ops *codec_ops; const struct rockchip_vpu_codec_ops *codec_ops;
int (*init)(struct rockchip_vpu_dev *vpu); int (*init)(struct rockchip_vpu_dev *vpu);
irqreturn_t (*vepu_irq)(int irq, void *priv); irqreturn_t (*vepu_irq)(int irq, void *priv);
irqreturn_t (*vdpu_irq)(int irq, void *priv);
const char *clk_names[ROCKCHIP_VPU_MAX_CLOCKS]; const char *clk_names[ROCKCHIP_VPU_MAX_CLOCKS];
int num_clocks; int num_clocks;
}; };
...@@ -112,12 +120,14 @@ rockchip_vpu_vdev_to_func(struct video_device *vdev) ...@@ -112,12 +120,14 @@ rockchip_vpu_vdev_to_func(struct video_device *vdev)
* @m2m_dev: mem2mem device associated to this device. * @m2m_dev: mem2mem device associated to this device.
* @mdev: media device associated to this device. * @mdev: media device associated to this device.
* @encoder: encoder functionality. * @encoder: encoder functionality.
* @decoder: decoder functionality.
* @pdev: Pointer to VPU platform device. * @pdev: Pointer to VPU platform device.
* @dev: Pointer to device for convenient logging using * @dev: Pointer to device for convenient logging using
* dev_ macros. * dev_ macros.
* @clocks: Array of clock handles. * @clocks: Array of clock handles.
* @base: Mapped address of VPU registers. * @base: Mapped address of VPU registers.
* @enc_base: Mapped address of VPU encoder register for convenience. * @enc_base: Mapped address of VPU encoder register for convenience.
* @dec_base: Mapped address of VPU decoder register for convenience.
* @vpu_mutex: Mutex to synchronize V4L2 calls. * @vpu_mutex: Mutex to synchronize V4L2 calls.
* @irqlock: Spinlock to synchronize access to data structures * @irqlock: Spinlock to synchronize access to data structures
* shared with interrupt handlers. * shared with interrupt handlers.
...@@ -129,11 +139,13 @@ struct rockchip_vpu_dev { ...@@ -129,11 +139,13 @@ struct rockchip_vpu_dev {
struct v4l2_m2m_dev *m2m_dev; struct v4l2_m2m_dev *m2m_dev;
struct media_device mdev; struct media_device mdev;
struct rockchip_vpu_func *encoder; struct rockchip_vpu_func *encoder;
struct rockchip_vpu_func *decoder;
struct platform_device *pdev; struct platform_device *pdev;
struct device *dev; struct device *dev;
struct clk_bulk_data clocks[ROCKCHIP_VPU_MAX_CLOCKS]; struct clk_bulk_data clocks[ROCKCHIP_VPU_MAX_CLOCKS];
void __iomem *base; void __iomem *base;
void __iomem *enc_base; void __iomem *enc_base;
void __iomem *dec_base;
struct mutex vpu_mutex; /* video_device lock */ struct mutex vpu_mutex; /* video_device lock */
spinlock_t irqlock; spinlock_t irqlock;
...@@ -158,6 +170,9 @@ struct rockchip_vpu_dev { ...@@ -158,6 +170,9 @@ struct rockchip_vpu_dev {
* @ctrl_handler: Control handler used to register controls. * @ctrl_handler: Control handler used to register controls.
* @jpeg_quality: User-specified JPEG compression quality. * @jpeg_quality: User-specified JPEG compression quality.
* *
* @buf_finish: Buffer finish. This depends on encoder or decoder
* context, and it's called right before
* calling v4l2_m2m_job_finish.
* @codec_ops: Set of operations related to codec mode. * @codec_ops: Set of operations related to codec mode.
* @jpeg_enc: JPEG-encoding context. * @jpeg_enc: JPEG-encoding context.
*/ */
...@@ -176,6 +191,10 @@ struct rockchip_vpu_ctx { ...@@ -176,6 +191,10 @@ struct rockchip_vpu_ctx {
struct v4l2_ctrl_handler ctrl_handler; struct v4l2_ctrl_handler ctrl_handler;
int jpeg_quality; int jpeg_quality;
int (*buf_finish)(struct rockchip_vpu_ctx *ctx,
struct vb2_buffer *buf,
unsigned int bytesused);
const struct rockchip_vpu_codec_ops *codec_ops; const struct rockchip_vpu_codec_ops *codec_ops;
/* Specific for particular codec modes. */ /* Specific for particular codec modes. */
...@@ -262,10 +281,27 @@ static inline u32 vepu_read(struct rockchip_vpu_dev *vpu, u32 reg) ...@@ -262,10 +281,27 @@ static inline u32 vepu_read(struct rockchip_vpu_dev *vpu, u32 reg)
return val; return val;
} }
static inline bool static inline void vdpu_write_relaxed(struct rockchip_vpu_dev *vpu,
rockchip_vpu_is_encoder_ctx(const struct rockchip_vpu_ctx *ctx) u32 val, u32 reg)
{
vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val);
writel_relaxed(val, vpu->dec_base + reg);
}
static inline void vdpu_write(struct rockchip_vpu_dev *vpu, u32 val, u32 reg)
{
vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val);
writel(val, vpu->dec_base + reg);
}
static inline u32 vdpu_read(struct rockchip_vpu_dev *vpu, u32 reg)
{ {
return true; u32 val = readl(vpu->dec_base + reg);
vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val);
return val;
} }
bool rockchip_vpu_is_encoder_ctx(const struct rockchip_vpu_ctx *ctx);
#endif /* ROCKCHIP_VPU_H_ */ #endif /* ROCKCHIP_VPU_H_ */
...@@ -35,13 +35,48 @@ module_param_named(debug, rockchip_vpu_debug, int, 0644); ...@@ -35,13 +35,48 @@ module_param_named(debug, rockchip_vpu_debug, int, 0644);
MODULE_PARM_DESC(debug, MODULE_PARM_DESC(debug,
"Debug level - higher value produces more verbose messages"); "Debug level - higher value produces more verbose messages");
static int
rockchip_vpu_enc_buf_finish(struct rockchip_vpu_ctx *ctx,
struct vb2_buffer *buf,
unsigned int bytesused)
{
size_t avail_size;
avail_size = vb2_plane_size(buf, 0) - ctx->vpu_dst_fmt->header_size;
if (bytesused > avail_size)
return -EINVAL;
/*
* The bounce buffer is only for the JPEG encoder.
* TODO: Rework the JPEG encoder to eliminate the need
* for a bounce buffer.
*/
if (ctx->jpeg_enc.bounce_buffer.cpu) {
memcpy(vb2_plane_vaddr(buf, 0) +
ctx->vpu_dst_fmt->header_size,
ctx->jpeg_enc.bounce_buffer.cpu, bytesused);
}
buf->planes[0].bytesused =
ctx->vpu_dst_fmt->header_size + bytesused;
return 0;
}
static int
rockchip_vpu_dec_buf_finish(struct rockchip_vpu_ctx *ctx,
struct vb2_buffer *buf,
unsigned int bytesused)
{
/* For decoders set bytesused as per the output picture. */
buf->planes[0].bytesused = ctx->dst_fmt.plane_fmt[0].sizeimage;
return 0;
}
static void rockchip_vpu_job_finish(struct rockchip_vpu_dev *vpu, static void rockchip_vpu_job_finish(struct rockchip_vpu_dev *vpu,
struct rockchip_vpu_ctx *ctx, struct rockchip_vpu_ctx *ctx,
unsigned int bytesused, unsigned int bytesused,
enum vb2_buffer_state result) enum vb2_buffer_state result)
{ {
struct vb2_v4l2_buffer *src, *dst; struct vb2_v4l2_buffer *src, *dst;
size_t avail_size; int ret;
pm_runtime_mark_last_busy(vpu->dev); pm_runtime_mark_last_busy(vpu->dev);
pm_runtime_put_autosuspend(vpu->dev); pm_runtime_put_autosuspend(vpu->dev);
...@@ -60,24 +95,9 @@ static void rockchip_vpu_job_finish(struct rockchip_vpu_dev *vpu, ...@@ -60,24 +95,9 @@ static void rockchip_vpu_job_finish(struct rockchip_vpu_dev *vpu,
v4l2_m2m_buf_copy_metadata(src, dst, true); v4l2_m2m_buf_copy_metadata(src, dst, true);
avail_size = vb2_plane_size(&dst->vb2_buf, 0) - ret = ctx->buf_finish(ctx, &dst->vb2_buf, bytesused);
ctx->vpu_dst_fmt->header_size; if (ret)
if (bytesused <= avail_size) {
/*
* The bounce buffer is only for the JPEG encoder.
* TODO: Rework the JPEG encoder to eliminate the need
* for a bounce buffer.
*/
if (ctx->jpeg_enc.bounce_buffer.cpu) {
memcpy(vb2_plane_vaddr(&dst->vb2_buf, 0) +
ctx->vpu_dst_fmt->header_size,
ctx->jpeg_enc.bounce_buffer.cpu, bytesused);
}
dst->vb2_buf.planes[0].bytesused =
ctx->vpu_dst_fmt->header_size + bytesused;
} else {
result = VB2_BUF_STATE_ERROR; result = VB2_BUF_STATE_ERROR;
}
v4l2_m2m_buf_done(src, result); v4l2_m2m_buf_done(src, result);
v4l2_m2m_buf_done(dst, result); v4l2_m2m_buf_done(dst, result);
...@@ -135,6 +155,11 @@ static void device_run(void *priv) ...@@ -135,6 +155,11 @@ static void device_run(void *priv)
rockchip_vpu_job_finish(ctx->dev, ctx, 0, VB2_BUF_STATE_ERROR); rockchip_vpu_job_finish(ctx->dev, ctx, 0, VB2_BUF_STATE_ERROR);
} }
bool rockchip_vpu_is_encoder_ctx(const struct rockchip_vpu_ctx *ctx)
{
return ctx->buf_finish == rockchip_vpu_enc_buf_finish;
}
static struct v4l2_m2m_ops vpu_m2m_ops = { static struct v4l2_m2m_ops vpu_m2m_ops = {
.device_run = device_run, .device_run = device_run,
}; };
...@@ -169,18 +194,25 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) ...@@ -169,18 +194,25 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
return ret; return ret;
/* /*
* The CAPTURE queue doesn't need dma memory, * When encoding, the CAPTURE queue doesn't need dma memory,
* as the CPU needs to create the JPEG frames, * as the CPU needs to create the JPEG frames, from the
* from the hardware-produced JPEG payload. * hardware-produced JPEG payload.
* *
* For the DMA destination buffer, we use * For the DMA destination buffer, we use a bounce buffer.
* a bounce buffer.
*/ */
if (rockchip_vpu_is_encoder_ctx(ctx)) {
dst_vq->mem_ops = &vb2_vmalloc_memops;
} else {
dst_vq->bidirectional = true;
dst_vq->mem_ops = &vb2_dma_contig_memops;
dst_vq->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES |
DMA_ATTR_NO_KERNEL_MAPPING;
}
dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
dst_vq->drv_priv = ctx; dst_vq->drv_priv = ctx;
dst_vq->ops = &rockchip_vpu_queue_ops; dst_vq->ops = &rockchip_vpu_queue_ops;
dst_vq->mem_ops = &vb2_vmalloc_memops;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
dst_vq->lock = &ctx->dev->vpu_mutex; dst_vq->lock = &ctx->dev->vpu_mutex;
...@@ -258,11 +290,17 @@ static int rockchip_vpu_open(struct file *filp) ...@@ -258,11 +290,17 @@ static int rockchip_vpu_open(struct file *filp)
return -ENOMEM; return -ENOMEM;
ctx->dev = vpu; ctx->dev = vpu;
if (func->id == MEDIA_ENT_F_PROC_VIDEO_ENCODER) if (func->id == MEDIA_ENT_F_PROC_VIDEO_ENCODER) {
ctx->buf_finish = rockchip_vpu_enc_buf_finish;
ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(vpu->m2m_dev, ctx, ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(vpu->m2m_dev, ctx,
queue_init); queue_init);
else } else if (func->id == MEDIA_ENT_F_PROC_VIDEO_DECODER) {
ctx->buf_finish = rockchip_vpu_dec_buf_finish;
ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(vpu->m2m_dev, ctx,
queue_init);
} else {
ctx->fh.m2m_ctx = ERR_PTR(-ENODEV); ctx->fh.m2m_ctx = ERR_PTR(-ENODEV);
}
if (IS_ERR(ctx->fh.m2m_ctx)) { if (IS_ERR(ctx->fh.m2m_ctx)) {
ret = PTR_ERR(ctx->fh.m2m_ctx); ret = PTR_ERR(ctx->fh.m2m_ctx);
kfree(ctx); kfree(ctx);
...@@ -463,7 +501,8 @@ static void rockchip_detach_func(struct rockchip_vpu_func *func) ...@@ -463,7 +501,8 @@ static void rockchip_detach_func(struct rockchip_vpu_func *func)
media_device_unregister_entity(&func->vdev.entity); media_device_unregister_entity(&func->vdev.entity);
} }
static int rockchip_vpu_add_enc_func(struct rockchip_vpu_dev *vpu) static int rockchip_vpu_add_func(struct rockchip_vpu_dev *vpu,
unsigned int funcid)
{ {
const struct of_device_id *match; const struct of_device_id *match;
struct rockchip_vpu_func *func; struct rockchip_vpu_func *func;
...@@ -477,7 +516,7 @@ static int rockchip_vpu_add_enc_func(struct rockchip_vpu_dev *vpu) ...@@ -477,7 +516,7 @@ static int rockchip_vpu_add_enc_func(struct rockchip_vpu_dev *vpu)
return -ENOMEM; return -ENOMEM;
} }
func->id = MEDIA_ENT_F_PROC_VIDEO_ENCODER; func->id = funcid;
vfd = &func->vdev; vfd = &func->vdev;
vfd->fops = &rockchip_vpu_fops; vfd->fops = &rockchip_vpu_fops;
...@@ -487,9 +526,14 @@ static int rockchip_vpu_add_enc_func(struct rockchip_vpu_dev *vpu) ...@@ -487,9 +526,14 @@ static int rockchip_vpu_add_enc_func(struct rockchip_vpu_dev *vpu)
vfd->vfl_dir = VFL_DIR_M2M; vfd->vfl_dir = VFL_DIR_M2M;
vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
vfd->ioctl_ops = &rockchip_vpu_ioctl_ops; vfd->ioctl_ops = &rockchip_vpu_ioctl_ops;
snprintf(vfd->name, sizeof(vfd->name), "%s-enc", match->compatible); snprintf(vfd->name, sizeof(vfd->name), "%s-%s", match->compatible,
funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER ? "enc" : "dec");
if (funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER)
vpu->encoder = func;
else
vpu->decoder = func;
vpu->encoder = func;
video_set_drvdata(vfd, vpu); video_set_drvdata(vfd, vpu);
ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
...@@ -514,9 +558,31 @@ static int rockchip_vpu_add_enc_func(struct rockchip_vpu_dev *vpu) ...@@ -514,9 +558,31 @@ static int rockchip_vpu_add_enc_func(struct rockchip_vpu_dev *vpu)
return ret; return ret;
} }
static void rockchip_vpu_remove_enc_func(struct rockchip_vpu_dev *vpu) static int rockchip_vpu_add_enc_func(struct rockchip_vpu_dev *vpu)
{
if (!vpu->variant->enc_fmts)
return 0;
return rockchip_vpu_add_func(vpu, MEDIA_ENT_F_PROC_VIDEO_ENCODER);
}
static int rockchip_vpu_add_dec_func(struct rockchip_vpu_dev *vpu)
{
if (!vpu->variant->dec_fmts)
return 0;
return rockchip_vpu_add_func(vpu, MEDIA_ENT_F_PROC_VIDEO_DECODER);
}
static void rockchip_vpu_remove_func(struct rockchip_vpu_dev *vpu,
unsigned int funcid)
{ {
struct rockchip_vpu_func *func = vpu->encoder; struct rockchip_vpu_func *func;
if (funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER)
func = vpu->encoder;
else
func = vpu->decoder;
if (!func) if (!func)
return; return;
...@@ -525,6 +591,16 @@ static void rockchip_vpu_remove_enc_func(struct rockchip_vpu_dev *vpu) ...@@ -525,6 +591,16 @@ static void rockchip_vpu_remove_enc_func(struct rockchip_vpu_dev *vpu)
video_unregister_device(&func->vdev); video_unregister_device(&func->vdev);
} }
static void rockchip_vpu_remove_enc_func(struct rockchip_vpu_dev *vpu)
{
rockchip_vpu_remove_func(vpu, MEDIA_ENT_F_PROC_VIDEO_ENCODER);
}
static void rockchip_vpu_remove_dec_func(struct rockchip_vpu_dev *vpu)
{
rockchip_vpu_remove_func(vpu, MEDIA_ENT_F_PROC_VIDEO_DECODER);
}
static const struct media_device_ops rockchip_m2m_media_ops = { static const struct media_device_ops rockchip_m2m_media_ops = {
.req_validate = vb2_request_validate, .req_validate = vb2_request_validate,
.req_queue = v4l2_m2m_request_queue, .req_queue = v4l2_m2m_request_queue,
...@@ -563,6 +639,7 @@ static int rockchip_vpu_probe(struct platform_device *pdev) ...@@ -563,6 +639,7 @@ static int rockchip_vpu_probe(struct platform_device *pdev)
if (IS_ERR(vpu->base)) if (IS_ERR(vpu->base))
return PTR_ERR(vpu->base); return PTR_ERR(vpu->base);
vpu->enc_base = vpu->base + vpu->variant->enc_offset; vpu->enc_base = vpu->base + vpu->variant->enc_offset;
vpu->dec_base = vpu->base + vpu->variant->dec_offset;
ret = dma_set_coherent_mask(vpu->dev, DMA_BIT_MASK(32)); ret = dma_set_coherent_mask(vpu->dev, DMA_BIT_MASK(32));
if (ret) { if (ret) {
...@@ -570,6 +647,23 @@ static int rockchip_vpu_probe(struct platform_device *pdev) ...@@ -570,6 +647,23 @@ static int rockchip_vpu_probe(struct platform_device *pdev)
return ret; return ret;
} }
if (vpu->variant->vdpu_irq) {
int irq;
irq = platform_get_irq_byname(vpu->pdev, "vdpu");
if (irq <= 0) {
dev_err(vpu->dev, "Could not get vdpu IRQ.\n");
return -ENXIO;
}
ret = devm_request_irq(vpu->dev, irq, vpu->variant->vdpu_irq,
0, dev_name(vpu->dev), vpu);
if (ret) {
dev_err(vpu->dev, "Could not request vdpu IRQ.\n");
return ret;
}
}
if (vpu->variant->vepu_irq) { if (vpu->variant->vepu_irq) {
int irq; int irq;
...@@ -631,14 +725,22 @@ static int rockchip_vpu_probe(struct platform_device *pdev) ...@@ -631,14 +725,22 @@ static int rockchip_vpu_probe(struct platform_device *pdev)
goto err_m2m_rel; goto err_m2m_rel;
} }
ret = rockchip_vpu_add_dec_func(vpu);
if (ret) {
dev_err(&pdev->dev, "Failed to register decoder\n");
goto err_rm_enc_func;
}
ret = media_device_register(&vpu->mdev); ret = media_device_register(&vpu->mdev);
if (ret) { if (ret) {
v4l2_err(&vpu->v4l2_dev, "Failed to register mem2mem media device\n"); v4l2_err(&vpu->v4l2_dev, "Failed to register mem2mem media device\n");
goto err_rm_enc_func; goto err_rm_dec_func;
} }
return 0; return 0;
err_rm_dec_func:
rockchip_vpu_remove_dec_func(vpu);
err_rm_enc_func: err_rm_enc_func:
rockchip_vpu_remove_enc_func(vpu); rockchip_vpu_remove_enc_func(vpu);
err_m2m_rel: err_m2m_rel:
...@@ -660,6 +762,7 @@ static int rockchip_vpu_remove(struct platform_device *pdev) ...@@ -660,6 +762,7 @@ static int rockchip_vpu_remove(struct platform_device *pdev)
v4l2_info(&vpu->v4l2_dev, "Removing %s\n", pdev->name); v4l2_info(&vpu->v4l2_dev, "Removing %s\n", pdev->name);
media_device_unregister(&vpu->mdev); media_device_unregister(&vpu->mdev);
rockchip_vpu_remove_dec_func(vpu);
rockchip_vpu_remove_enc_func(vpu); rockchip_vpu_remove_enc_func(vpu);
media_device_cleanup(&vpu->mdev); media_device_cleanup(&vpu->mdev);
v4l2_m2m_release(vpu->m2m_dev); v4l2_m2m_release(vpu->m2m_dev);
......
...@@ -36,8 +36,13 @@ rockchip_vpu_get_formats(const struct rockchip_vpu_ctx *ctx, ...@@ -36,8 +36,13 @@ rockchip_vpu_get_formats(const struct rockchip_vpu_ctx *ctx,
{ {
const struct rockchip_vpu_fmt *formats; const struct rockchip_vpu_fmt *formats;
formats = ctx->dev->variant->enc_fmts; if (rockchip_vpu_is_encoder_ctx(ctx)) {
*num_fmts = ctx->dev->variant->num_enc_fmts; formats = ctx->dev->variant->enc_fmts;
*num_fmts = ctx->dev->variant->num_enc_fmts;
} else {
formats = ctx->dev->variant->dec_fmts;
*num_fmts = ctx->dev->variant->num_dec_fmts;
}
return formats; return formats;
} }
...@@ -331,6 +336,22 @@ void rockchip_vpu_reset_fmts(struct rockchip_vpu_ctx *ctx) ...@@ -331,6 +336,22 @@ void rockchip_vpu_reset_fmts(struct rockchip_vpu_ctx *ctx)
rockchip_vpu_reset_raw_fmt(ctx); rockchip_vpu_reset_raw_fmt(ctx);
} }
static void
rockchip_vpu_update_requires_request(struct rockchip_vpu_ctx *ctx,
u32 fourcc)
{
switch (fourcc) {
case V4L2_PIX_FMT_JPEG:
ctx->fh.m2m_ctx->out_q_ctx.q.requires_requests = false;
break;
case V4L2_PIX_FMT_MPEG2_SLICE:
ctx->fh.m2m_ctx->out_q_ctx.q.requires_requests = true;
break;
default:
break;
}
}
static int static int
vidioc_s_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f) vidioc_s_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f)
{ {
...@@ -387,6 +408,8 @@ vidioc_s_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f) ...@@ -387,6 +408,8 @@ vidioc_s_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f)
ctx->dst_fmt.xfer_func = pix_mp->xfer_func; ctx->dst_fmt.xfer_func = pix_mp->xfer_func;
ctx->dst_fmt.quantization = pix_mp->quantization; ctx->dst_fmt.quantization = pix_mp->quantization;
rockchip_vpu_update_requires_request(ctx, pix_mp->pixelformat);
vpu_debug(0, "OUTPUT codec mode: %d\n", ctx->vpu_src_fmt->codec_mode); vpu_debug(0, "OUTPUT codec mode: %d\n", ctx->vpu_src_fmt->codec_mode);
vpu_debug(0, "fmt - w: %d, h: %d\n", vpu_debug(0, "fmt - w: %d, h: %d\n",
pix_mp->width, pix_mp->height); pix_mp->width, pix_mp->height);
...@@ -456,6 +479,8 @@ static int vidioc_s_fmt_cap_mplane(struct file *file, void *priv, ...@@ -456,6 +479,8 @@ static int vidioc_s_fmt_cap_mplane(struct file *file, void *priv,
vpu_debug(0, "fmt - w: %d, h: %d\n", vpu_debug(0, "fmt - w: %d, h: %d\n",
pix_mp->width, pix_mp->height); pix_mp->width, pix_mp->height);
rockchip_vpu_update_requires_request(ctx, pix_mp->pixelformat);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment