[media] vcodec: mediatek: Add Mediatek V4L2 Video Decoder Driver
Add v4l2 layer decoder driver for MT8173 [mchehab@s-opensource.com: make checkpatch.pl happy] Signed-off-by: Tiffany Lin <tiffany.lin@mediatek.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
This commit is contained in:
parent
f3ad804c9d
commit
590577a4e5
|
@ -1,7 +1,13 @@
|
|||
|
||||
obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-dec.o \
|
||||
mtk-vcodec-enc.o \
|
||||
mtk-vcodec-common.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-enc.o mtk-vcodec-common.o
|
||||
|
||||
mtk-vcodec-dec-y := mtk_vcodec_dec_drv.o \
|
||||
vdec_drv_if.o \
|
||||
vdec_vpu_if.o \
|
||||
mtk_vcodec_dec.o \
|
||||
mtk_vcodec_dec_pm.o \
|
||||
|
||||
|
||||
mtk-vcodec-enc-y := venc/venc_vp8_if.o \
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (c) 2016 MediaTek Inc.
|
||||
* Author: PC Chen <pc.chen@mediatek.com>
|
||||
* Tiffany Lin <tiffany.lin@mediatek.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _MTK_VCODEC_DEC_H_
|
||||
#define _MTK_VCODEC_DEC_H_
|
||||
|
||||
#include <media/videobuf2-core.h>
|
||||
#include <media/videobuf2-v4l2.h>
|
||||
|
||||
#define VCODEC_CAPABILITY_4K_DISABLED 0x10
|
||||
#define VCODEC_DEC_4K_CODED_WIDTH 4096U
|
||||
#define VCODEC_DEC_4K_CODED_HEIGHT 2304U
|
||||
#define MTK_VDEC_MAX_W 2048U
|
||||
#define MTK_VDEC_MAX_H 1088U
|
||||
|
||||
#define MTK_VDEC_IRQ_STATUS_DEC_SUCCESS 0x10000
|
||||
|
||||
/**
|
||||
* struct vdec_fb - decoder frame buffer
|
||||
* @base_y : Y plane memory info
|
||||
* @base_c : C plane memory info
|
||||
* @status : frame buffer status (vdec_fb_status)
|
||||
*/
|
||||
struct vdec_fb {
|
||||
struct mtk_vcodec_mem base_y;
|
||||
struct mtk_vcodec_mem base_c;
|
||||
unsigned int status;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mtk_video_dec_buf - Private data related to each VB2 buffer.
|
||||
* @b: VB2 buffer
|
||||
* @list: link list
|
||||
* @used: Capture buffer contain decoded frame data and keep in
|
||||
* codec data structure
|
||||
* @ready_to_display: Capture buffer not display yet
|
||||
* @queued_in_vb2: Capture buffer is queue in vb2
|
||||
* @queued_in_v4l2: Capture buffer is in v4l2 driver, but not in vb2
|
||||
* queue yet
|
||||
* @lastframe: Intput buffer is last buffer - EOS
|
||||
* @frame_buffer: Decode status, and buffer information of Capture buffer
|
||||
*
|
||||
* Note : These status information help us track and debug buffer state
|
||||
*/
|
||||
struct mtk_video_dec_buf {
|
||||
struct vb2_v4l2_buffer vb;
|
||||
struct list_head list;
|
||||
|
||||
bool used;
|
||||
bool ready_to_display;
|
||||
bool queued_in_vb2;
|
||||
bool queued_in_v4l2;
|
||||
bool lastframe;
|
||||
struct vdec_fb frame_buffer;
|
||||
};
|
||||
|
||||
extern const struct v4l2_ioctl_ops mtk_vdec_ioctl_ops;
|
||||
extern const struct v4l2_m2m_ops mtk_vdec_m2m_ops;
|
||||
|
||||
|
||||
/*
|
||||
* mtk_vdec_lock/mtk_vdec_unlock are for ctx instance to
|
||||
* get/release lock before/after access decoder hw.
|
||||
* mtk_vdec_lock get decoder hw lock and set curr_ctx
|
||||
* to ctx instance that get lock
|
||||
*/
|
||||
void mtk_vdec_unlock(struct mtk_vcodec_ctx *ctx);
|
||||
void mtk_vdec_lock(struct mtk_vcodec_ctx *ctx);
|
||||
int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq,
|
||||
struct vb2_queue *dst_vq);
|
||||
void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx);
|
||||
void mtk_vcodec_dec_release(struct mtk_vcodec_ctx *ctx);
|
||||
int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_ctx *ctx);
|
||||
|
||||
|
||||
#endif /* _MTK_VCODEC_DEC_H_ */
|
|
@ -0,0 +1,394 @@
|
|||
/*
|
||||
* Copyright (c) 2016 MediaTek Inc.
|
||||
* Author: PC Chen <pc.chen@mediatek.com>
|
||||
* Tiffany Lin <tiffany.lin@mediatek.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <media/v4l2-event.h>
|
||||
#include <media/v4l2-mem2mem.h>
|
||||
#include <media/videobuf2-dma-contig.h>
|
||||
|
||||
#include "mtk_vcodec_drv.h"
|
||||
#include "mtk_vcodec_dec.h"
|
||||
#include "mtk_vcodec_dec_pm.h"
|
||||
#include "mtk_vcodec_intr.h"
|
||||
#include "mtk_vcodec_util.h"
|
||||
#include "mtk_vpu.h"
|
||||
|
||||
#define VDEC_HW_ACTIVE 0x10
|
||||
#define VDEC_IRQ_CFG 0x11
|
||||
#define VDEC_IRQ_CLR 0x10
|
||||
#define VDEC_IRQ_CFG_REG 0xa4
|
||||
|
||||
module_param(mtk_v4l2_dbg_level, int, 0644);
|
||||
module_param(mtk_vcodec_dbg, bool, 0644);
|
||||
|
||||
/* Wake up context wait_queue */
|
||||
static void wake_up_ctx(struct mtk_vcodec_ctx *ctx)
|
||||
{
|
||||
ctx->int_cond = 1;
|
||||
wake_up_interruptible(&ctx->queue);
|
||||
}
|
||||
|
||||
static irqreturn_t mtk_vcodec_dec_irq_handler(int irq, void *priv)
|
||||
{
|
||||
struct mtk_vcodec_dev *dev = priv;
|
||||
struct mtk_vcodec_ctx *ctx;
|
||||
u32 cg_status = 0;
|
||||
unsigned int dec_done_status = 0;
|
||||
void __iomem *vdec_misc_addr = dev->reg_base[VDEC_MISC] +
|
||||
VDEC_IRQ_CFG_REG;
|
||||
|
||||
ctx = mtk_vcodec_get_curr_ctx(dev);
|
||||
|
||||
/* check if HW active or not */
|
||||
cg_status = readl(dev->reg_base[0]);
|
||||
if ((cg_status & VDEC_HW_ACTIVE) != 0) {
|
||||
mtk_v4l2_err("DEC ISR, VDEC active is not 0x0 (0x%08x)",
|
||||
cg_status);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
dec_done_status = readl(vdec_misc_addr);
|
||||
ctx->irq_status = dec_done_status;
|
||||
if ((dec_done_status & MTK_VDEC_IRQ_STATUS_DEC_SUCCESS) !=
|
||||
MTK_VDEC_IRQ_STATUS_DEC_SUCCESS)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
/* clear interrupt */
|
||||
writel((readl(vdec_misc_addr) | VDEC_IRQ_CFG),
|
||||
dev->reg_base[VDEC_MISC] + VDEC_IRQ_CFG_REG);
|
||||
writel((readl(vdec_misc_addr) & ~VDEC_IRQ_CLR),
|
||||
dev->reg_base[VDEC_MISC] + VDEC_IRQ_CFG_REG);
|
||||
|
||||
wake_up_ctx(ctx);
|
||||
|
||||
mtk_v4l2_debug(3,
|
||||
"mtk_vcodec_dec_irq_handler :wake up ctx %d, dec_done_status=%x",
|
||||
ctx->id, dec_done_status);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void mtk_vcodec_dec_reset_handler(void *priv)
|
||||
{
|
||||
struct mtk_vcodec_dev *dev = priv;
|
||||
struct mtk_vcodec_ctx *ctx;
|
||||
|
||||
mtk_v4l2_err("Watchdog timeout!!");
|
||||
|
||||
mutex_lock(&dev->dev_mutex);
|
||||
list_for_each_entry(ctx, &dev->ctx_list, list) {
|
||||
ctx->state = MTK_STATE_ABORT;
|
||||
mtk_v4l2_debug(0, "[%d] Change to state MTK_STATE_ERROR",
|
||||
ctx->id);
|
||||
}
|
||||
mutex_unlock(&dev->dev_mutex);
|
||||
}
|
||||
|
||||
static int fops_vcodec_open(struct file *file)
|
||||
{
|
||||
struct mtk_vcodec_dev *dev = video_drvdata(file);
|
||||
struct mtk_vcodec_ctx *ctx = NULL;
|
||||
int ret = 0;
|
||||
|
||||
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&dev->dev_mutex);
|
||||
ctx->id = dev->id_counter++;
|
||||
v4l2_fh_init(&ctx->fh, video_devdata(file));
|
||||
file->private_data = &ctx->fh;
|
||||
v4l2_fh_add(&ctx->fh);
|
||||
INIT_LIST_HEAD(&ctx->list);
|
||||
ctx->dev = dev;
|
||||
init_waitqueue_head(&ctx->queue);
|
||||
mutex_init(&ctx->lock);
|
||||
|
||||
ctx->type = MTK_INST_DECODER;
|
||||
ret = mtk_vcodec_dec_ctrls_setup(ctx);
|
||||
if (ret) {
|
||||
mtk_v4l2_err("Failed to setup mt vcodec controls");
|
||||
goto err_ctrls_setup;
|
||||
}
|
||||
ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev_dec, ctx,
|
||||
&mtk_vcodec_dec_queue_init);
|
||||
if (IS_ERR((__force void *)ctx->m2m_ctx)) {
|
||||
ret = PTR_ERR((__force void *)ctx->m2m_ctx);
|
||||
mtk_v4l2_err("Failed to v4l2_m2m_ctx_init() (%d)",
|
||||
ret);
|
||||
goto err_m2m_ctx_init;
|
||||
}
|
||||
mtk_vcodec_dec_set_default_params(ctx);
|
||||
|
||||
if (v4l2_fh_is_singular(&ctx->fh)) {
|
||||
mtk_vcodec_dec_pw_on(&dev->pm);
|
||||
/*
|
||||
* vpu_load_firmware checks if it was loaded already and
|
||||
* does nothing in that case
|
||||
*/
|
||||
ret = vpu_load_firmware(dev->vpu_plat_dev);
|
||||
if (ret < 0) {
|
||||
/*
|
||||
* Return 0 if downloading firmware successfully,
|
||||
* otherwise it is failed
|
||||
*/
|
||||
mtk_v4l2_err("vpu_load_firmware failed!");
|
||||
goto err_load_fw;
|
||||
}
|
||||
|
||||
dev->dec_capability =
|
||||
vpu_get_vdec_hw_capa(dev->vpu_plat_dev);
|
||||
mtk_v4l2_debug(0, "decoder capability %x", dev->dec_capability);
|
||||
}
|
||||
|
||||
list_add(&ctx->list, &dev->ctx_list);
|
||||
|
||||
mutex_unlock(&dev->dev_mutex);
|
||||
mtk_v4l2_debug(0, "%s decoder [%d]", dev_name(&dev->plat_dev->dev),
|
||||
ctx->id);
|
||||
return ret;
|
||||
|
||||
/* Deinit when failure occurred */
|
||||
err_load_fw:
|
||||
v4l2_m2m_ctx_release(ctx->m2m_ctx);
|
||||
err_m2m_ctx_init:
|
||||
v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
|
||||
err_ctrls_setup:
|
||||
v4l2_fh_del(&ctx->fh);
|
||||
v4l2_fh_exit(&ctx->fh);
|
||||
kfree(ctx);
|
||||
mutex_unlock(&dev->dev_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fops_vcodec_release(struct file *file)
|
||||
{
|
||||
struct mtk_vcodec_dev *dev = video_drvdata(file);
|
||||
struct mtk_vcodec_ctx *ctx = fh_to_ctx(file->private_data);
|
||||
|
||||
mtk_v4l2_debug(0, "[%d] decoder", ctx->id);
|
||||
mutex_lock(&dev->dev_mutex);
|
||||
|
||||
/*
|
||||
* Call v4l2_m2m_ctx_release before mtk_vcodec_dec_release. First, it
|
||||
* makes sure the worker thread is not running after vdec_if_deinit.
|
||||
* Second, the decoder will be flushed and all the buffers will be
|
||||
* returned in stop_streaming.
|
||||
*/
|
||||
v4l2_m2m_ctx_release(ctx->m2m_ctx);
|
||||
mtk_vcodec_dec_release(ctx);
|
||||
|
||||
if (v4l2_fh_is_singular(&ctx->fh))
|
||||
mtk_vcodec_dec_pw_off(&dev->pm);
|
||||
v4l2_fh_del(&ctx->fh);
|
||||
v4l2_fh_exit(&ctx->fh);
|
||||
v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
|
||||
|
||||
list_del_init(&ctx->list);
|
||||
kfree(ctx);
|
||||
mutex_unlock(&dev->dev_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_file_operations mtk_vcodec_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = fops_vcodec_open,
|
||||
.release = fops_vcodec_release,
|
||||
.poll = v4l2_m2m_fop_poll,
|
||||
.unlocked_ioctl = video_ioctl2,
|
||||
.mmap = v4l2_m2m_fop_mmap,
|
||||
};
|
||||
|
||||
static int mtk_vcodec_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mtk_vcodec_dev *dev;
|
||||
struct video_device *vfd_dec;
|
||||
struct resource *res;
|
||||
int i, ret;
|
||||
|
||||
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&dev->ctx_list);
|
||||
dev->plat_dev = pdev;
|
||||
|
||||
dev->vpu_plat_dev = vpu_get_plat_device(dev->plat_dev);
|
||||
if (dev->vpu_plat_dev == NULL) {
|
||||
mtk_v4l2_err("[VPU] vpu device in not ready");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
vpu_wdt_reg_handler(dev->vpu_plat_dev, mtk_vcodec_dec_reset_handler,
|
||||
dev, VPU_RST_DEC);
|
||||
|
||||
ret = mtk_vcodec_init_dec_pm(dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to get mt vcodec clock source");
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_MAX_VDEC_REG_BASE; i++) {
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "get memory resource failed.");
|
||||
ret = -ENXIO;
|
||||
goto err_res;
|
||||
}
|
||||
dev->reg_base[i] = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR((__force void *)dev->reg_base[i])) {
|
||||
ret = PTR_ERR((__force void *)dev->reg_base);
|
||||
goto err_res;
|
||||
}
|
||||
mtk_v4l2_debug(2, "reg[%d] base=%p", i, dev->reg_base[i]);
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "failed to get irq resource");
|
||||
ret = -ENOENT;
|
||||
goto err_res;
|
||||
}
|
||||
|
||||
dev->dec_irq = platform_get_irq(pdev, 0);
|
||||
ret = devm_request_irq(&pdev->dev, dev->dec_irq,
|
||||
mtk_vcodec_dec_irq_handler, 0, pdev->name, dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to install dev->dec_irq %d (%d)",
|
||||
dev->dec_irq,
|
||||
ret);
|
||||
goto err_res;
|
||||
}
|
||||
|
||||
disable_irq(dev->dec_irq);
|
||||
mutex_init(&dev->dec_mutex);
|
||||
mutex_init(&dev->dev_mutex);
|
||||
spin_lock_init(&dev->irqlock);
|
||||
|
||||
snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s",
|
||||
"[/MTK_V4L2_VDEC]");
|
||||
|
||||
ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
|
||||
if (ret) {
|
||||
mtk_v4l2_err("v4l2_device_register err=%d", ret);
|
||||
goto err_res;
|
||||
}
|
||||
|
||||
init_waitqueue_head(&dev->queue);
|
||||
|
||||
vfd_dec = video_device_alloc();
|
||||
if (!vfd_dec) {
|
||||
mtk_v4l2_err("Failed to allocate video device");
|
||||
ret = -ENOMEM;
|
||||
goto err_dec_alloc;
|
||||
}
|
||||
vfd_dec->fops = &mtk_vcodec_fops;
|
||||
vfd_dec->ioctl_ops = &mtk_vdec_ioctl_ops;
|
||||
vfd_dec->release = video_device_release;
|
||||
vfd_dec->lock = &dev->dev_mutex;
|
||||
vfd_dec->v4l2_dev = &dev->v4l2_dev;
|
||||
vfd_dec->vfl_dir = VFL_DIR_M2M;
|
||||
vfd_dec->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE |
|
||||
V4L2_CAP_STREAMING;
|
||||
|
||||
snprintf(vfd_dec->name, sizeof(vfd_dec->name), "%s",
|
||||
MTK_VCODEC_DEC_NAME);
|
||||
video_set_drvdata(vfd_dec, dev);
|
||||
dev->vfd_dec = vfd_dec;
|
||||
platform_set_drvdata(pdev, dev);
|
||||
|
||||
dev->m2m_dev_dec = v4l2_m2m_init(&mtk_vdec_m2m_ops);
|
||||
if (IS_ERR((__force void *)dev->m2m_dev_dec)) {
|
||||
mtk_v4l2_err("Failed to init mem2mem dec device");
|
||||
ret = PTR_ERR((__force void *)dev->m2m_dev_dec);
|
||||
goto err_dec_mem_init;
|
||||
}
|
||||
|
||||
dev->decode_workqueue =
|
||||
alloc_ordered_workqueue(MTK_VCODEC_DEC_NAME,
|
||||
WQ_MEM_RECLAIM | WQ_FREEZABLE);
|
||||
if (!dev->decode_workqueue) {
|
||||
mtk_v4l2_err("Failed to create decode workqueue");
|
||||
ret = -EINVAL;
|
||||
goto err_event_workq;
|
||||
}
|
||||
|
||||
ret = video_register_device(vfd_dec, VFL_TYPE_GRABBER, 0);
|
||||
if (ret) {
|
||||
mtk_v4l2_err("Failed to register video device");
|
||||
goto err_dec_reg;
|
||||
}
|
||||
|
||||
mtk_v4l2_debug(0, "decoder registered as /dev/video%d",
|
||||
vfd_dec->num);
|
||||
|
||||
return 0;
|
||||
|
||||
err_dec_reg:
|
||||
destroy_workqueue(dev->decode_workqueue);
|
||||
err_event_workq:
|
||||
v4l2_m2m_release(dev->m2m_dev_dec);
|
||||
err_dec_mem_init:
|
||||
video_unregister_device(vfd_dec);
|
||||
err_dec_alloc:
|
||||
v4l2_device_unregister(&dev->v4l2_dev);
|
||||
err_res:
|
||||
mtk_vcodec_release_dec_pm(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id mtk_vcodec_match[] = {
|
||||
{.compatible = "mediatek,mt8173-vcodec-dec",},
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, mtk_vcodec_match);
|
||||
|
||||
static int mtk_vcodec_dec_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mtk_vcodec_dev *dev = platform_get_drvdata(pdev);
|
||||
|
||||
flush_workqueue(dev->decode_workqueue);
|
||||
destroy_workqueue(dev->decode_workqueue);
|
||||
if (dev->m2m_dev_dec)
|
||||
v4l2_m2m_release(dev->m2m_dev_dec);
|
||||
|
||||
if (dev->vfd_dec)
|
||||
video_unregister_device(dev->vfd_dec);
|
||||
|
||||
v4l2_device_unregister(&dev->v4l2_dev);
|
||||
mtk_vcodec_release_dec_pm(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver mtk_vcodec_dec_driver = {
|
||||
.probe = mtk_vcodec_probe,
|
||||
.remove = mtk_vcodec_dec_remove,
|
||||
.driver = {
|
||||
.name = MTK_VCODEC_DEC_NAME,
|
||||
.of_match_table = mtk_vcodec_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(mtk_vcodec_dec_driver);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("Mediatek video codec V4L2 decoder driver");
|
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* Copyright (c) 2016 MediaTek Inc.
|
||||
* Author: Tiffany Lin <tiffany.lin@mediatek.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <soc/mediatek/smi.h>
|
||||
|
||||
#include "mtk_vcodec_dec_pm.h"
|
||||
#include "mtk_vcodec_util.h"
|
||||
#include "mtk_vpu.h"
|
||||
|
||||
int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev)
|
||||
{
|
||||
struct device_node *node;
|
||||
struct platform_device *pdev;
|
||||
struct device *dev;
|
||||
struct mtk_vcodec_pm *pm;
|
||||
int ret = 0;
|
||||
|
||||
pdev = mtkdev->plat_dev;
|
||||
pm = &mtkdev->pm;
|
||||
pm->mtkdev = mtkdev;
|
||||
dev = &pdev->dev;
|
||||
node = of_parse_phandle(pdev->dev.of_node, "mediatek,larb", 0);
|
||||
if (!node) {
|
||||
mtk_v4l2_err("of_parse_phandle mediatek,larb fail!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pdev = of_find_device_by_node(node);
|
||||
if (WARN_ON(!pdev)) {
|
||||
of_node_put(node);
|
||||
return -1;
|
||||
}
|
||||
pm->larbvdec = &pdev->dev;
|
||||
pdev = mtkdev->plat_dev;
|
||||
pm->dev = &pdev->dev;
|
||||
|
||||
pm->vcodecpll = devm_clk_get(&pdev->dev, "vcodecpll");
|
||||
if (IS_ERR(pm->vcodecpll)) {
|
||||
mtk_v4l2_err("devm_clk_get vcodecpll fail");
|
||||
ret = PTR_ERR(pm->vcodecpll);
|
||||
}
|
||||
|
||||
pm->univpll_d2 = devm_clk_get(&pdev->dev, "univpll_d2");
|
||||
if (IS_ERR(pm->univpll_d2)) {
|
||||
mtk_v4l2_err("devm_clk_get univpll_d2 fail");
|
||||
ret = PTR_ERR(pm->univpll_d2);
|
||||
}
|
||||
|
||||
pm->clk_cci400_sel = devm_clk_get(&pdev->dev, "clk_cci400_sel");
|
||||
if (IS_ERR(pm->clk_cci400_sel)) {
|
||||
mtk_v4l2_err("devm_clk_get clk_cci400_sel fail");
|
||||
ret = PTR_ERR(pm->clk_cci400_sel);
|
||||
}
|
||||
|
||||
pm->vdec_sel = devm_clk_get(&pdev->dev, "vdec_sel");
|
||||
if (IS_ERR(pm->vdec_sel)) {
|
||||
mtk_v4l2_err("devm_clk_get vdec_sel fail");
|
||||
ret = PTR_ERR(pm->vdec_sel);
|
||||
}
|
||||
|
||||
pm->vdecpll = devm_clk_get(&pdev->dev, "vdecpll");
|
||||
if (IS_ERR(pm->vdecpll)) {
|
||||
mtk_v4l2_err("devm_clk_get vdecpll fail");
|
||||
ret = PTR_ERR(pm->vdecpll);
|
||||
}
|
||||
|
||||
pm->vencpll = devm_clk_get(&pdev->dev, "vencpll");
|
||||
if (IS_ERR(pm->vencpll)) {
|
||||
mtk_v4l2_err("devm_clk_get vencpll fail");
|
||||
ret = PTR_ERR(pm->vencpll);
|
||||
}
|
||||
|
||||
pm->venc_lt_sel = devm_clk_get(&pdev->dev, "venc_lt_sel");
|
||||
if (IS_ERR(pm->venc_lt_sel)) {
|
||||
mtk_v4l2_err("devm_clk_get venc_lt_sel fail");
|
||||
ret = PTR_ERR(pm->venc_lt_sel);
|
||||
}
|
||||
|
||||
pm->vdec_bus_clk_src = devm_clk_get(&pdev->dev, "vdec_bus_clk_src");
|
||||
if (IS_ERR(pm->vdec_bus_clk_src)) {
|
||||
mtk_v4l2_err("devm_clk_get vdec_bus_clk_src");
|
||||
ret = PTR_ERR(pm->vdec_bus_clk_src);
|
||||
}
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mtk_vcodec_release_dec_pm(struct mtk_vcodec_dev *dev)
|
||||
{
|
||||
pm_runtime_disable(dev->pm.dev);
|
||||
}
|
||||
|
||||
void mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_get_sync(pm->dev);
|
||||
if (ret)
|
||||
mtk_v4l2_err("pm_runtime_get_sync fail %d", ret);
|
||||
}
|
||||
|
||||
void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_put_sync(pm->dev);
|
||||
if (ret)
|
||||
mtk_v4l2_err("pm_runtime_put_sync fail %d", ret);
|
||||
}
|
||||
|
||||
void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = clk_set_rate(pm->vcodecpll, 1482 * 1000000);
|
||||
if (ret)
|
||||
mtk_v4l2_err("clk_set_rate vcodecpll fail %d", ret);
|
||||
|
||||
ret = clk_set_rate(pm->vencpll, 800 * 1000000);
|
||||
if (ret)
|
||||
mtk_v4l2_err("clk_set_rate vencpll fail %d", ret);
|
||||
|
||||
ret = clk_prepare_enable(pm->vcodecpll);
|
||||
if (ret)
|
||||
mtk_v4l2_err("clk_prepare_enable vcodecpll fail %d", ret);
|
||||
|
||||
ret = clk_prepare_enable(pm->vencpll);
|
||||
if (ret)
|
||||
mtk_v4l2_err("clk_prepare_enable vencpll fail %d", ret);
|
||||
|
||||
ret = clk_prepare_enable(pm->vdec_bus_clk_src);
|
||||
if (ret)
|
||||
mtk_v4l2_err("clk_prepare_enable vdec_bus_clk_src fail %d",
|
||||
ret);
|
||||
|
||||
ret = clk_prepare_enable(pm->venc_lt_sel);
|
||||
if (ret)
|
||||
mtk_v4l2_err("clk_prepare_enable venc_lt_sel fail %d", ret);
|
||||
|
||||
ret = clk_set_parent(pm->venc_lt_sel, pm->vdec_bus_clk_src);
|
||||
if (ret)
|
||||
mtk_v4l2_err("clk_set_parent venc_lt_sel vdec_bus_clk_src fail %d",
|
||||
ret);
|
||||
|
||||
ret = clk_prepare_enable(pm->univpll_d2);
|
||||
if (ret)
|
||||
mtk_v4l2_err("clk_prepare_enable univpll_d2 fail %d", ret);
|
||||
|
||||
ret = clk_prepare_enable(pm->clk_cci400_sel);
|
||||
if (ret)
|
||||
mtk_v4l2_err("clk_prepare_enable clk_cci400_sel fail %d", ret);
|
||||
|
||||
ret = clk_set_parent(pm->clk_cci400_sel, pm->univpll_d2);
|
||||
if (ret)
|
||||
mtk_v4l2_err("clk_set_parent clk_cci400_sel univpll_d2 fail %d",
|
||||
ret);
|
||||
|
||||
ret = clk_prepare_enable(pm->vdecpll);
|
||||
if (ret)
|
||||
mtk_v4l2_err("clk_prepare_enable vdecpll fail %d", ret);
|
||||
|
||||
ret = clk_prepare_enable(pm->vdec_sel);
|
||||
if (ret)
|
||||
mtk_v4l2_err("clk_prepare_enable vdec_sel fail %d", ret);
|
||||
|
||||
ret = clk_set_parent(pm->vdec_sel, pm->vdecpll);
|
||||
if (ret)
|
||||
mtk_v4l2_err("clk_set_parent vdec_sel vdecpll fail %d", ret);
|
||||
|
||||
ret = mtk_smi_larb_get(pm->larbvdec);
|
||||
if (ret)
|
||||
mtk_v4l2_err("mtk_smi_larb_get larbvdec fail %d", ret);
|
||||
|
||||
}
|
||||
|
||||
void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm)
|
||||
{
|
||||
mtk_smi_larb_put(pm->larbvdec);
|
||||
clk_disable_unprepare(pm->vdec_sel);
|
||||
clk_disable_unprepare(pm->vdecpll);
|
||||
clk_disable_unprepare(pm->univpll_d2);
|
||||
clk_disable_unprepare(pm->clk_cci400_sel);
|
||||
clk_disable_unprepare(pm->venc_lt_sel);
|
||||
clk_disable_unprepare(pm->vdec_bus_clk_src);
|
||||
clk_disable_unprepare(pm->vencpll);
|
||||
clk_disable_unprepare(pm->vcodecpll);
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2016 MediaTek Inc.
|
||||
* Author: Tiffany Lin <tiffany.lin@mediatek.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _MTK_VCODEC_DEC_PM_H_
|
||||
#define _MTK_VCODEC_DEC_PM_H_
|
||||
|
||||
#include "mtk_vcodec_drv.h"
|
||||
|
||||
int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *dev);
|
||||
void mtk_vcodec_release_dec_pm(struct mtk_vcodec_dev *dev);
|
||||
|
||||
void mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm);
|
||||
void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm);
|
||||
void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm);
|
||||
void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm);
|
||||
|
||||
#endif /* _MTK_VCODEC_DEC_PM_H_ */
|
|
@ -22,13 +22,13 @@
|
|||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <media/videobuf2-core.h>
|
||||
|
||||
#include "mtk_vcodec_util.h"
|
||||
|
||||
#define MTK_VCODEC_DRV_NAME "mtk_vcodec_drv"
|
||||
#define MTK_VCODEC_DEC_NAME "mtk-vcodec-dec"
|
||||
#define MTK_VCODEC_ENC_NAME "mtk-vcodec-enc"
|
||||
#define MTK_PLATFORM_STR "platform:mt8173"
|
||||
|
||||
|
||||
#define MTK_VCODEC_MAX_PLANES 3
|
||||
#define MTK_V4L2_BENCHMARK 0
|
||||
#define WAIT_INTR_TIMEOUT_MS 1000
|
||||
|
@ -179,6 +179,9 @@ struct mtk_enc_params {
|
|||
* struct mtk_vcodec_pm - Power management data structure
|
||||
*/
|
||||
struct mtk_vcodec_pm {
|
||||
struct clk *vdec_bus_clk_src;
|
||||
struct clk *vencpll;
|
||||
|
||||
struct clk *vcodecpll;
|
||||
struct clk *univpll_d2;
|
||||
struct clk *clk_cci400_sel;
|
||||
|
@ -195,6 +198,32 @@ struct mtk_vcodec_pm {
|
|||
struct mtk_vcodec_dev *mtkdev;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vdec_pic_info - picture size information
|
||||
* @pic_w: picture width
|
||||
* @pic_h: picture height
|
||||
* @buf_w: picture buffer width (64 aligned up from pic_w)
|
||||
* @buf_h: picture buffer heiht (64 aligned up from pic_h)
|
||||
* @y_bs_sz: Y bitstream size
|
||||
* @c_bs_sz: CbCr bitstream size
|
||||
* @y_len_sz: additional size required to store decompress information for y
|
||||
* plane
|
||||
* @c_len_sz: additional size required to store decompress information for cbcr
|
||||
* plane
|
||||
* E.g. suppose picture size is 176x144,
|
||||
* buffer size will be aligned to 176x160.
|
||||
*/
|
||||
struct vdec_pic_info {
|
||||
unsigned int pic_w;
|
||||
unsigned int pic_h;
|
||||
unsigned int buf_w;
|
||||
unsigned int buf_h;
|
||||
unsigned int y_bs_sz;
|
||||
unsigned int c_bs_sz;
|
||||
unsigned int y_len_sz;
|
||||
unsigned int c_len_sz;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mtk_vcodec_ctx - Context (instance) private data.
|
||||
*
|
||||
|
@ -209,9 +238,12 @@ struct mtk_vcodec_pm {
|
|||
* @state: state of the context
|
||||
* @param_change: indicate encode parameter type
|
||||
* @enc_params: encoding parameters
|
||||
* @dec_if: hooked decoder driver interface
|
||||
* @enc_if: hoooked encoder driver interface
|
||||
* @drv_handle: driver handle for specific decode/encode instance
|
||||
*
|
||||
* @picinfo: store picture info after header parsing
|
||||
* @dpb_size: store dpb count after header parsing
|
||||
* @int_cond: variable used by the waitqueue
|
||||
* @int_type: type of the last interrupt
|
||||
* @queue: waitqueue that can be used to wait for this context to
|
||||
|
@ -219,12 +251,16 @@ struct mtk_vcodec_pm {
|
|||
* @irq_status: irq status
|
||||
*
|
||||
* @ctrl_hdl: handler for v4l2 framework
|
||||
* @decode_work: worker for the decoding
|
||||
* @encode_work: worker for the encoding
|
||||
* @last_decoded_picinfo: pic information get from latest decode
|
||||
*
|
||||
* @colorspace: enum v4l2_colorspace; supplemental to pixelformat
|
||||
* @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding
|
||||
* @quantization: enum v4l2_quantization, colorspace quantization
|
||||
* @xfer_func: enum v4l2_xfer_func, colorspace transfer function
|
||||
* @lock: protect variables accessed by V4L2 threads and worker thread such as
|
||||
* mtk_video_dec_buf.
|
||||
*/
|
||||
struct mtk_vcodec_ctx {
|
||||
enum mtk_instance_type type;
|
||||
|
@ -239,28 +275,40 @@ struct mtk_vcodec_ctx {
|
|||
enum mtk_encode_param param_change;
|
||||
struct mtk_enc_params enc_params;
|
||||
|
||||
const struct vdec_common_if *dec_if;
|
||||
const struct venc_common_if *enc_if;
|
||||
unsigned long drv_handle;
|
||||
|
||||
struct vdec_pic_info picinfo;
|
||||
int dpb_size;
|
||||
|
||||
int int_cond;
|
||||
int int_type;
|
||||
wait_queue_head_t queue;
|
||||
unsigned int irq_status;
|
||||
|
||||
struct v4l2_ctrl_handler ctrl_hdl;
|
||||
struct work_struct decode_work;
|
||||
struct work_struct encode_work;
|
||||
struct vdec_pic_info last_decoded_picinfo;
|
||||
|
||||
enum v4l2_colorspace colorspace;
|
||||
enum v4l2_ycbcr_encoding ycbcr_enc;
|
||||
enum v4l2_quantization quantization;
|
||||
enum v4l2_xfer_func xfer_func;
|
||||
|
||||
int decoded_frame_cnt;
|
||||
struct mutex lock;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mtk_vcodec_dev - driver data
|
||||
* @v4l2_dev: V4L2 device to register video devices for.
|
||||
* @vfd_dec: Video device for decoder
|
||||
* @vfd_enc: Video device for encoder.
|
||||
*
|
||||
* @m2m_dev_dec: m2m device for decoder
|
||||
* @m2m_dev_enc: m2m device for encoder.
|
||||
* @plat_dev: platform device
|
||||
* @vpu_plat_dev: mtk vpu platform device
|
||||
|
@ -271,7 +319,6 @@ struct mtk_vcodec_ctx {
|
|||
* @reg_base: Mapped address of MTK Vcodec registers.
|
||||
*
|
||||
* @id_counter: used to identify current opened instance
|
||||
* @num_instances: counter of active MTK Vcodec instances
|
||||
*
|
||||
* @encode_workqueue: encode work queue
|
||||
*
|
||||
|
@ -280,9 +327,11 @@ struct mtk_vcodec_ctx {
|
|||
* @dev_mutex: video_device lock
|
||||
* @queue: waitqueue for waiting for completion of device commands
|
||||
*
|
||||
* @dec_irq: decoder irq resource
|
||||
* @enc_irq: h264 encoder irq resource
|
||||
* @enc_lt_irq: vp8 encoder irq resource
|
||||
*
|
||||
* @dec_mutex: decoder hardware lock
|
||||
* @enc_mutex: encoder hardware lock.
|
||||
*
|
||||
* @pm: power management control
|
||||
|
@ -291,8 +340,10 @@ struct mtk_vcodec_ctx {
|
|||
*/
|
||||
struct mtk_vcodec_dev {
|
||||
struct v4l2_device v4l2_dev;
|
||||
struct video_device *vfd_dec;
|
||||
struct video_device *vfd_enc;
|
||||
|
||||
struct v4l2_m2m_dev *m2m_dev_dec;
|
||||
struct v4l2_m2m_dev *m2m_dev_enc;
|
||||
struct platform_device *plat_dev;
|
||||
struct platform_device *vpu_plat_dev;
|
||||
|
@ -302,18 +353,19 @@ struct mtk_vcodec_dev {
|
|||
void __iomem *reg_base[NUM_MAX_VCODEC_REG_BASE];
|
||||
|
||||
unsigned long id_counter;
|
||||
int num_instances;
|
||||
|
||||
struct workqueue_struct *decode_workqueue;
|
||||
struct workqueue_struct *encode_workqueue;
|
||||
|
||||
int int_cond;
|
||||
int int_type;
|
||||
struct mutex dev_mutex;
|
||||
wait_queue_head_t queue;
|
||||
|
||||
int dec_irq;
|
||||
int enc_irq;
|
||||
int enc_lt_irq;
|
||||
|
||||
struct mutex dec_mutex;
|
||||
struct mutex enc_mutex;
|
||||
|
||||
struct mtk_vcodec_pm pm;
|
||||
|
|
|
@ -188,7 +188,6 @@ static int fops_vcodec_open(struct file *file)
|
|||
mtk_v4l2_debug(2, "Create instance [%d]@%p m2m_ctx=%p ",
|
||||
ctx->id, ctx, ctx->m2m_ctx);
|
||||
|
||||
dev->num_instances++;
|
||||
list_add(&ctx->list, &dev->ctx_list);
|
||||
|
||||
mutex_unlock(&dev->dev_mutex);
|
||||
|
@ -218,18 +217,13 @@ static int fops_vcodec_release(struct file *file)
|
|||
mtk_v4l2_debug(1, "[%d] encoder", ctx->id);
|
||||
mutex_lock(&dev->dev_mutex);
|
||||
|
||||
/*
|
||||
* Call v4l2_m2m_ctx_release to make sure the worker thread is not
|
||||
* running after venc_if_deinit.
|
||||
*/
|
||||
v4l2_m2m_ctx_release(ctx->m2m_ctx);
|
||||
mtk_vcodec_enc_release(ctx);
|
||||
v4l2_fh_del(&ctx->fh);
|
||||
v4l2_fh_exit(&ctx->fh);
|
||||
v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
|
||||
v4l2_m2m_ctx_release(ctx->m2m_ctx);
|
||||
|
||||
list_del_init(&ctx->list);
|
||||
dev->num_instances--;
|
||||
kfree(ctx);
|
||||
mutex_unlock(&dev->dev_mutex);
|
||||
return 0;
|
||||
|
|
|
@ -30,8 +30,7 @@ int mtk_vcodec_wait_for_done_ctx(struct mtk_vcodec_ctx *ctx, int command,
|
|||
timeout_jiff = msecs_to_jiffies(timeout_ms);
|
||||
|
||||
ret = wait_event_interruptible_timeout(*waitqueue,
|
||||
(ctx->int_cond &&
|
||||
(ctx->int_type == command)),
|
||||
ctx->int_cond,
|
||||
timeout_jiff);
|
||||
|
||||
if (!ret) {
|
||||
|
|
|
@ -81,14 +81,37 @@ void mtk_vcodec_mem_free(struct mtk_vcodec_ctx *data,
|
|||
return;
|
||||
}
|
||||
|
||||
dma_free_coherent(dev, size, mem->va, mem->dma_addr);
|
||||
mem->va = NULL;
|
||||
mem->dma_addr = 0;
|
||||
mem->size = 0;
|
||||
|
||||
mtk_v4l2_debug(3, "[%d] - va = %p", ctx->id, mem->va);
|
||||
mtk_v4l2_debug(3, "[%d] - dma = 0x%lx", ctx->id,
|
||||
(unsigned long)mem->dma_addr);
|
||||
mtk_v4l2_debug(3, "[%d] size = 0x%lx", ctx->id, size);
|
||||
|
||||
dma_free_coherent(dev, size, mem->va, mem->dma_addr);
|
||||
mem->va = NULL;
|
||||
mem->dma_addr = 0;
|
||||
mem->size = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mtk_vcodec_mem_free);
|
||||
|
||||
void mtk_vcodec_set_curr_ctx(struct mtk_vcodec_dev *dev,
|
||||
struct mtk_vcodec_ctx *ctx)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev->irqlock, flags);
|
||||
dev->curr_ctx = ctx;
|
||||
spin_unlock_irqrestore(&dev->irqlock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(mtk_vcodec_set_curr_ctx);
|
||||
|
||||
struct mtk_vcodec_ctx *mtk_vcodec_get_curr_ctx(struct mtk_vcodec_dev *dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct mtk_vcodec_ctx *ctx;
|
||||
|
||||
spin_lock_irqsave(&dev->irqlock, flags);
|
||||
ctx = dev->curr_ctx;
|
||||
spin_unlock_irqrestore(&dev->irqlock, flags);
|
||||
return ctx;
|
||||
}
|
||||
EXPORT_SYMBOL(mtk_vcodec_get_curr_ctx);
|
||||
|
|
|
@ -26,6 +26,7 @@ struct mtk_vcodec_mem {
|
|||
};
|
||||
|
||||
struct mtk_vcodec_ctx;
|
||||
struct mtk_vcodec_dev;
|
||||
|
||||
extern int mtk_v4l2_dbg_level;
|
||||
extern bool mtk_vcodec_dbg;
|
||||
|
@ -84,4 +85,8 @@ int mtk_vcodec_mem_alloc(struct mtk_vcodec_ctx *data,
|
|||
struct mtk_vcodec_mem *mem);
|
||||
void mtk_vcodec_mem_free(struct mtk_vcodec_ctx *data,
|
||||
struct mtk_vcodec_mem *mem);
|
||||
void mtk_vcodec_set_curr_ctx(struct mtk_vcodec_dev *dev,
|
||||
struct mtk_vcodec_ctx *ctx);
|
||||
struct mtk_vcodec_ctx *mtk_vcodec_get_curr_ctx(struct mtk_vcodec_dev *dev);
|
||||
|
||||
#endif /* _MTK_VCODEC_UTIL_H_ */
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2016 MediaTek Inc.
|
||||
* Author: PC Chen <pc.chen@mediatek.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _VDEC_DRV_BASE_
|
||||
#define _VDEC_DRV_BASE_
|
||||
|
||||
#include "mtk_vcodec_drv.h"
|
||||
|
||||
|
||||
struct vdec_common_if {
|
||||
/**
|
||||
* (*init)() - initialize decode driver
|
||||
* @ctx : [in] mtk v4l2 context
|
||||
* @h_vdec : [out] driver handle
|
||||
*/
|
||||
int (*init)(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec);
|
||||
|
||||
/**
|
||||
* (*decode)() - trigger decode
|
||||
* @h_vdec : [in] driver handle
|
||||
* @bs : [in] input bitstream
|
||||
* @fb : [in] frame buffer to store decoded frame
|
||||
* @res_chg : [out] resolution change happen
|
||||
*/
|
||||
int (*decode)(unsigned long h_vdec, struct mtk_vcodec_mem *bs,
|
||||
struct vdec_fb *fb, bool *res_chg);
|
||||
|
||||
/**
|
||||
* (*get_param)() - get driver's parameter
|
||||
* @h_vdec : [in] driver handle
|
||||
* @type : [in] input parameter type
|
||||
* @out : [out] buffer to store query result
|
||||
*/
|
||||
int (*get_param)(unsigned long h_vdec, enum vdec_get_param_type type,
|
||||
void *out);
|
||||
|
||||
/**
|
||||
* (*deinit)() - deinitialize driver.
|
||||
* @h_vdec : [in] driver handle to be deinit
|
||||
*/
|
||||
void (*deinit)(unsigned long h_vdec);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright (c) 2016 MediaTek Inc.
|
||||
* Author: PC Chen <pc.chen@mediatek.com>
|
||||
* Tiffany Lin <tiffany.lin@mediatek.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "vdec_drv_if.h"
|
||||
#include "mtk_vcodec_dec.h"
|
||||
#include "vdec_drv_base.h"
|
||||
#include "mtk_vcodec_dec_pm.h"
|
||||
#include "mtk_vpu.h"
|
||||
|
||||
|
||||
int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (fourcc) {
|
||||
case V4L2_PIX_FMT_H264:
|
||||
case V4L2_PIX_FMT_VP8:
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mtk_vdec_lock(ctx);
|
||||
mtk_vcodec_dec_clock_on(&ctx->dev->pm);
|
||||
ret = ctx->dec_if->init(ctx, &ctx->drv_handle);
|
||||
mtk_vcodec_dec_clock_off(&ctx->dev->pm);
|
||||
mtk_vdec_unlock(ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vdec_if_decode(struct mtk_vcodec_ctx *ctx, struct mtk_vcodec_mem *bs,
|
||||
struct vdec_fb *fb, bool *res_chg)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (bs) {
|
||||
if ((bs->dma_addr & 63) != 0) {
|
||||
mtk_v4l2_err("bs dma_addr should 64 byte align");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (fb) {
|
||||
if (((fb->base_y.dma_addr & 511) != 0) ||
|
||||
((fb->base_c.dma_addr & 511) != 0)) {
|
||||
mtk_v4l2_err("frame buffer dma_addr should 512 byte align");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->drv_handle == 0)
|
||||
return -EIO;
|
||||
|
||||
mtk_vdec_lock(ctx);
|
||||
|
||||
mtk_vcodec_set_curr_ctx(ctx->dev, ctx);
|
||||
mtk_vcodec_dec_clock_on(&ctx->dev->pm);
|
||||
enable_irq(ctx->dev->dec_irq);
|
||||
ret = ctx->dec_if->decode(ctx->drv_handle, bs, fb, res_chg);
|
||||
disable_irq(ctx->dev->dec_irq);
|
||||
mtk_vcodec_dec_clock_off(&ctx->dev->pm);
|
||||
mtk_vcodec_set_curr_ctx(ctx->dev, NULL);
|
||||
|
||||
mtk_vdec_unlock(ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vdec_if_get_param(struct mtk_vcodec_ctx *ctx, enum vdec_get_param_type type,
|
||||
void *out)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (ctx->drv_handle == 0)
|
||||
return -EIO;
|
||||
|
||||
mtk_vdec_lock(ctx);
|
||||
ret = ctx->dec_if->get_param(ctx->drv_handle, type, out);
|
||||
mtk_vdec_unlock(ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void vdec_if_deinit(struct mtk_vcodec_ctx *ctx)
|
||||
{
|
||||
if (ctx->drv_handle == 0)
|
||||
return;
|
||||
|
||||
mtk_vdec_lock(ctx);
|
||||
mtk_vcodec_dec_clock_on(&ctx->dev->pm);
|
||||
ctx->dec_if->deinit(ctx->drv_handle);
|
||||
mtk_vcodec_dec_clock_off(&ctx->dev->pm);
|
||||
mtk_vdec_unlock(ctx);
|
||||
|
||||
ctx->drv_handle = 0;
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright (c) 2016 MediaTek Inc.
|
||||
* Author: PC Chen <pc.chen@mediatek.com>
|
||||
* Tiffany Lin <tiffany.lin@mediatek.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _VDEC_DRV_IF_H_
|
||||
#define _VDEC_DRV_IF_H_
|
||||
|
||||
#include "mtk_vcodec_drv.h"
|
||||
#include "mtk_vcodec_dec.h"
|
||||
#include "mtk_vcodec_util.h"
|
||||
|
||||
|
||||
/**
|
||||
* struct vdec_fb_status - decoder frame buffer status
|
||||
* @FB_ST_NORMAL : initial state
|
||||
* @FB_ST_DISPLAY : frmae buffer is ready to be displayed
|
||||
* @FB_ST_FREE : frame buffer is not used by decoder any more
|
||||
*/
|
||||
enum vdec_fb_status {
|
||||
FB_ST_NORMAL = 0,
|
||||
FB_ST_DISPLAY = (1 << 0),
|
||||
FB_ST_FREE = (1 << 1)
|
||||
};
|
||||
|
||||
/* For GET_PARAM_DISP_FRAME_BUFFER and GET_PARAM_FREE_FRAME_BUFFER,
|
||||
* the caller does not own the returned buffer. The buffer will not be
|
||||
* released before vdec_if_deinit.
|
||||
* GET_PARAM_DISP_FRAME_BUFFER : get next displayable frame buffer,
|
||||
* struct vdec_fb**
|
||||
* GET_PARAM_FREE_FRAME_BUFFER : get non-referenced framebuffer, vdec_fb**
|
||||
* GET_PARAM_PIC_INFO : get picture info, struct vdec_pic_info*
|
||||
* GET_PARAM_CROP_INFO : get crop info, struct v4l2_crop*
|
||||
* GET_PARAM_DPB_SIZE : get dpb size, unsigned int*
|
||||
*/
|
||||
enum vdec_get_param_type {
|
||||
GET_PARAM_DISP_FRAME_BUFFER,
|
||||
GET_PARAM_FREE_FRAME_BUFFER,
|
||||
GET_PARAM_PIC_INFO,
|
||||
GET_PARAM_CROP_INFO,
|
||||
GET_PARAM_DPB_SIZE
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vdec_fb_node - decoder frame buffer node
|
||||
* @list : list to hold this node
|
||||
* @fb : point to frame buffer (vdec_fb), fb could point to frame buffer and
|
||||
* working buffer this is for maintain buffers in different state
|
||||
*/
|
||||
struct vdec_fb_node {
|
||||
struct list_head list;
|
||||
struct vdec_fb *fb;
|
||||
};
|
||||
|
||||
/**
|
||||
* vdec_if_init() - initialize decode driver
|
||||
* @ctx : [in] v4l2 context
|
||||
* @fourcc : [in] video format fourcc, V4L2_PIX_FMT_H264/VP8/VP9..
|
||||
*/
|
||||
int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc);
|
||||
|
||||
/**
|
||||
* vdec_if_deinit() - deinitialize decode driver
|
||||
* @ctx : [in] v4l2 context
|
||||
*
|
||||
*/
|
||||
void vdec_if_deinit(struct mtk_vcodec_ctx *ctx);
|
||||
|
||||
/**
|
||||
* vdec_if_decode() - trigger decode
|
||||
* @ctx : [in] v4l2 context
|
||||
* @bs : [in] input bitstream
|
||||
* @fb : [in] frame buffer to store decoded frame, when null menas parse
|
||||
* header only
|
||||
* @res_chg : [out] resolution change happens if current bs have different
|
||||
* picture width/height
|
||||
* Note: To flush the decoder when reaching EOF, set input bitstream as NULL.
|
||||
*/
|
||||
int vdec_if_decode(struct mtk_vcodec_ctx *ctx, struct mtk_vcodec_mem *bs,
|
||||
struct vdec_fb *fb, bool *res_chg);
|
||||
|
||||
/**
|
||||
* vdec_if_get_param() - get driver's parameter
|
||||
* @ctx : [in] v4l2 context
|
||||
* @type : [in] input parameter type
|
||||
* @out : [out] buffer to store query result
|
||||
*/
|
||||
int vdec_if_get_param(struct mtk_vcodec_ctx *ctx, enum vdec_get_param_type type,
|
||||
void *out);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright (c) 2016 MediaTek Inc.
|
||||
* Author: PC Chen <pc.chen@mediatek.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _VDEC_IPI_MSG_H_
|
||||
#define _VDEC_IPI_MSG_H_
|
||||
|
||||
/**
|
||||
* enum vdec_ipi_msgid - message id between AP and VPU
|
||||
* @AP_IPIMSG_XXX : AP to VPU cmd message id
|
||||
* @VPU_IPIMSG_XXX_ACK : VPU ack AP cmd message id
|
||||
*/
|
||||
enum vdec_ipi_msgid {
|
||||
AP_IPIMSG_DEC_INIT = 0xA000,
|
||||
AP_IPIMSG_DEC_START = 0xA001,
|
||||
AP_IPIMSG_DEC_END = 0xA002,
|
||||
AP_IPIMSG_DEC_DEINIT = 0xA003,
|
||||
AP_IPIMSG_DEC_RESET = 0xA004,
|
||||
|
||||
VPU_IPIMSG_DEC_INIT_ACK = 0xB000,
|
||||
VPU_IPIMSG_DEC_START_ACK = 0xB001,
|
||||
VPU_IPIMSG_DEC_END_ACK = 0xB002,
|
||||
VPU_IPIMSG_DEC_DEINIT_ACK = 0xB003,
|
||||
VPU_IPIMSG_DEC_RESET_ACK = 0xB004,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vdec_ap_ipi_cmd - generic AP to VPU ipi command format
|
||||
* @msg_id : vdec_ipi_msgid
|
||||
* @vpu_inst_addr : VPU decoder instance address
|
||||
*/
|
||||
struct vdec_ap_ipi_cmd {
|
||||
uint32_t msg_id;
|
||||
uint32_t vpu_inst_addr;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vdec_vpu_ipi_ack - generic VPU to AP ipi command format
|
||||
* @msg_id : vdec_ipi_msgid
|
||||
* @status : VPU exeuction result
|
||||
* @ap_inst_addr : AP video decoder instance address
|
||||
*/
|
||||
struct vdec_vpu_ipi_ack {
|
||||
uint32_t msg_id;
|
||||
int32_t status;
|
||||
uint64_t ap_inst_addr;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vdec_ap_ipi_init - for AP_IPIMSG_DEC_INIT
|
||||
* @msg_id : AP_IPIMSG_DEC_INIT
|
||||
* @reserved : Reserved field
|
||||
* @ap_inst_addr : AP video decoder instance address
|
||||
*/
|
||||
struct vdec_ap_ipi_init {
|
||||
uint32_t msg_id;
|
||||
uint32_t reserved;
|
||||
uint64_t ap_inst_addr;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vdec_ap_ipi_dec_start - for AP_IPIMSG_DEC_START
|
||||
* @msg_id : AP_IPIMSG_DEC_START
|
||||
* @vpu_inst_addr : VPU decoder instance address
|
||||
* @data : Header info
|
||||
* H264 decoder [0]:buf_sz [1]:nal_start
|
||||
* VP8 decoder [0]:width/height
|
||||
* VP9 decoder [0]:profile, [1][2] width/height
|
||||
* @reserved : Reserved field
|
||||
*/
|
||||
struct vdec_ap_ipi_dec_start {
|
||||
uint32_t msg_id;
|
||||
uint32_t vpu_inst_addr;
|
||||
uint32_t data[3];
|
||||
uint32_t reserved;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vdec_vpu_ipi_init_ack - for VPU_IPIMSG_DEC_INIT_ACK
|
||||
* @msg_id : VPU_IPIMSG_DEC_INIT_ACK
|
||||
* @status : VPU exeuction result
|
||||
* @ap_inst_addr : AP vcodec_vpu_inst instance address
|
||||
* @vpu_inst_addr : VPU decoder instance address
|
||||
*/
|
||||
struct vdec_vpu_ipi_init_ack {
|
||||
uint32_t msg_id;
|
||||
int32_t status;
|
||||
uint64_t ap_inst_addr;
|
||||
uint32_t vpu_inst_addr;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* Copyright (c) 2016 MediaTek Inc.
|
||||
* Author: PC Chen <pc.chen@mediatek.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "mtk_vcodec_drv.h"
|
||||
#include "mtk_vcodec_util.h"
|
||||
#include "vdec_ipi_msg.h"
|
||||
#include "vdec_vpu_if.h"
|
||||
|
||||
static void handle_init_ack_msg(struct vdec_vpu_ipi_init_ack *msg)
|
||||
{
|
||||
struct vdec_vpu_inst *vpu = (struct vdec_vpu_inst *)
|
||||
(unsigned long)msg->ap_inst_addr;
|
||||
|
||||
mtk_vcodec_debug(vpu, "+ ap_inst_addr = 0x%llx", msg->ap_inst_addr);
|
||||
|
||||
/* mapping VPU address to kernel virtual address */
|
||||
/* the content in vsi is initialized to 0 in VPU */
|
||||
vpu->vsi = vpu_mapping_dm_addr(vpu->dev, msg->vpu_inst_addr);
|
||||
vpu->inst_addr = msg->vpu_inst_addr;
|
||||
|
||||
mtk_vcodec_debug(vpu, "- vpu_inst_addr = 0x%x", vpu->inst_addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function runs in interrupt context and it means there's an IPI MSG
|
||||
* from VPU.
|
||||
*/
|
||||
void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv)
|
||||
{
|
||||
struct vdec_vpu_ipi_ack *msg = data;
|
||||
struct vdec_vpu_inst *vpu = (struct vdec_vpu_inst *)
|
||||
(unsigned long)msg->ap_inst_addr;
|
||||
|
||||
mtk_vcodec_debug(vpu, "+ id=%X", msg->msg_id);
|
||||
|
||||
if (msg->status == 0) {
|
||||
switch (msg->msg_id) {
|
||||
case VPU_IPIMSG_DEC_INIT_ACK:
|
||||
handle_init_ack_msg(data);
|
||||
break;
|
||||
|
||||
case VPU_IPIMSG_DEC_START_ACK:
|
||||
case VPU_IPIMSG_DEC_END_ACK:
|
||||
case VPU_IPIMSG_DEC_DEINIT_ACK:
|
||||
case VPU_IPIMSG_DEC_RESET_ACK:
|
||||
break;
|
||||
|
||||
default:
|
||||
mtk_vcodec_err(vpu, "invalid msg=%X", msg->msg_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mtk_vcodec_debug(vpu, "- id=%X", msg->msg_id);
|
||||
vpu->failure = msg->status;
|
||||
vpu->signaled = 1;
|
||||
}
|
||||
|
||||
static int vcodec_vpu_send_msg(struct vdec_vpu_inst *vpu, void *msg, int len)
|
||||
{
|
||||
int err;
|
||||
uint32_t msg_id = *(uint32_t *)msg;
|
||||
|
||||
mtk_vcodec_debug(vpu, "id=%X", msg_id);
|
||||
|
||||
vpu->failure = 0;
|
||||
vpu->signaled = 0;
|
||||
|
||||
err = vpu_ipi_send(vpu->dev, vpu->id, msg, len);
|
||||
if (err) {
|
||||
mtk_vcodec_err(vpu, "send fail vpu_id=%d msg_id=%X status=%d",
|
||||
vpu->id, msg_id, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return vpu->failure;
|
||||
}
|
||||
|
||||
static int vcodec_send_ap_ipi(struct vdec_vpu_inst *vpu, unsigned int msg_id)
|
||||
{
|
||||
struct vdec_ap_ipi_cmd msg;
|
||||
int err = 0;
|
||||
|
||||
mtk_vcodec_debug(vpu, "+ id=%X", msg_id);
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_id = msg_id;
|
||||
msg.vpu_inst_addr = vpu->inst_addr;
|
||||
|
||||
err = vcodec_vpu_send_msg(vpu, &msg, sizeof(msg));
|
||||
mtk_vcodec_debug(vpu, "- id=%X ret=%d", msg_id, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
int vpu_dec_init(struct vdec_vpu_inst *vpu)
|
||||
{
|
||||
struct vdec_ap_ipi_init msg;
|
||||
int err;
|
||||
|
||||
mtk_vcodec_debug_enter(vpu);
|
||||
|
||||
init_waitqueue_head(&vpu->wq);
|
||||
|
||||
err = vpu_ipi_register(vpu->dev, vpu->id, vpu->handler, "vdec", NULL);
|
||||
if (err != 0) {
|
||||
mtk_vcodec_err(vpu, "vpu_ipi_register fail status=%d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_id = AP_IPIMSG_DEC_INIT;
|
||||
msg.ap_inst_addr = (unsigned long)vpu;
|
||||
|
||||
mtk_vcodec_debug(vpu, "vdec_inst=%p", vpu);
|
||||
|
||||
err = vcodec_vpu_send_msg(vpu, (void *)&msg, sizeof(msg));
|
||||
mtk_vcodec_debug(vpu, "- ret=%d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
int vpu_dec_start(struct vdec_vpu_inst *vpu, uint32_t *data, unsigned int len)
|
||||
{
|
||||
struct vdec_ap_ipi_dec_start msg;
|
||||
int i;
|
||||
int err = 0;
|
||||
|
||||
mtk_vcodec_debug_enter(vpu);
|
||||
|
||||
if (len > ARRAY_SIZE(msg.data)) {
|
||||
mtk_vcodec_err(vpu, "invalid len = %d\n", len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_id = AP_IPIMSG_DEC_START;
|
||||
msg.vpu_inst_addr = vpu->inst_addr;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
msg.data[i] = data[i];
|
||||
|
||||
err = vcodec_vpu_send_msg(vpu, (void *)&msg, sizeof(msg));
|
||||
mtk_vcodec_debug(vpu, "- ret=%d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
int vpu_dec_end(struct vdec_vpu_inst *vpu)
|
||||
{
|
||||
return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_END);
|
||||
}
|
||||
|
||||
int vpu_dec_deinit(struct vdec_vpu_inst *vpu)
|
||||
{
|
||||
return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_DEINIT);
|
||||
}
|
||||
|
||||
int vpu_dec_reset(struct vdec_vpu_inst *vpu)
|
||||
{
|
||||
return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_RESET);
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2016 MediaTek Inc.
|
||||
* Author: PC Chen <pc.chen@mediatek.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _VDEC_VPU_IF_H_
|
||||
#define _VDEC_VPU_IF_H_
|
||||
|
||||
#include "mtk_vpu.h"
|
||||
|
||||
/**
|
||||
* struct vdec_vpu_inst - VPU instance for video codec
|
||||
* @ipi_id : ipi id for each decoder
|
||||
* @vsi : driver structure allocated by VPU side and shared to AP side
|
||||
* for control and info share
|
||||
* @failure : VPU execution result status, 0: success, others: fail
|
||||
* @inst_addr : VPU decoder instance address
|
||||
* @signaled : 1 - Host has received ack message from VPU, 0 - not received
|
||||
* @ctx : context for v4l2 layer integration
|
||||
* @dev : platform device of VPU
|
||||
* @wq : wait queue to wait VPU message ack
|
||||
* @handler : ipi handler for each decoder
|
||||
*/
|
||||
struct vdec_vpu_inst {
|
||||
enum ipi_id id;
|
||||
void *vsi;
|
||||
int32_t failure;
|
||||
uint32_t inst_addr;
|
||||
unsigned int signaled;
|
||||
struct mtk_vcodec_ctx *ctx;
|
||||
struct platform_device *dev;
|
||||
wait_queue_head_t wq;
|
||||
ipi_handler_t handler;
|
||||
};
|
||||
|
||||
/**
|
||||
* vpu_dec_init - init decoder instance and allocate required resource in VPU.
|
||||
*
|
||||
* @vpu: instance for vdec_vpu_inst
|
||||
*/
|
||||
int vpu_dec_init(struct vdec_vpu_inst *vpu);
|
||||
|
||||
/**
|
||||
* vpu_dec_start - start decoding, basically the function will be invoked once
|
||||
* every frame.
|
||||
*
|
||||
* @vpu : instance for vdec_vpu_inst
|
||||
* @data: meta data to pass bitstream info to VPU decoder
|
||||
* @len : meta data length
|
||||
*/
|
||||
int vpu_dec_start(struct vdec_vpu_inst *vpu, uint32_t *data, unsigned int len);
|
||||
|
||||
/**
|
||||
* vpu_dec_end - end decoding, basically the function will be invoked once
|
||||
* when HW decoding done interrupt received successfully. The
|
||||
* decoder in VPU will continute to do referene frame management
|
||||
* and check if there is a new decoded frame available to display.
|
||||
*
|
||||
* @vpu : instance for vdec_vpu_inst
|
||||
*/
|
||||
int vpu_dec_end(struct vdec_vpu_inst *vpu);
|
||||
|
||||
/**
|
||||
* vpu_dec_deinit - deinit decoder instance and resource freed in VPU.
|
||||
*
|
||||
* @vpu: instance for vdec_vpu_inst
|
||||
*/
|
||||
int vpu_dec_deinit(struct vdec_vpu_inst *vpu);
|
||||
|
||||
/**
|
||||
* vpu_dec_reset - reset decoder, use for flush decoder when end of stream or
|
||||
* seek. Remainig non displayed frame will be pushed to display.
|
||||
*
|
||||
* @vpu: instance for vdec_vpu_inst
|
||||
*/
|
||||
int vpu_dec_reset(struct vdec_vpu_inst *vpu);
|
||||
|
||||
/**
|
||||
* vpu_dec_ipi_handler - Handler for VPU ipi message.
|
||||
*
|
||||
* @data: ipi message
|
||||
* @len : length of ipi message
|
||||
* @priv: callback private data which is passed by decoder when register.
|
||||
*/
|
||||
void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue