From: Jeffy Chen Date: Wed, 1 Jun 2016 08:43:23 +0000 (+0800) Subject: CHROMIUM: [media] rk3288-vpu: move rk3288-vpu to rockchip-vpu X-Git-Tag: firefly_0821_release~2293 X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=efcb9583560e04a8448e76485b5f9c8208d7efb6;p=firefly-linux-kernel-4.4.55.git CHROMIUM: [media] rk3288-vpu: move rk3288-vpu to rockchip-vpu Change-Id: I4c884307550b0782c29a482d5df6793132c3a9ff Signed-off-by: Jeffy Chen Signed-off-by: Yakir Yang --- diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 3a006fa02e6e..9f3f03bdc1bd 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -267,16 +267,16 @@ config VIDEO_TI_VPE Support for the TI VPE(Video Processing Engine) block found on DRA7XX SoC. -config VIDEO_RK3288_VPU - tristate "Rockchip RK3288 VPU driver" +config VIDEO_ROCKCHIP_VPU + tristate "Rockchip ROCKCHIP VPU driver" depends on VIDEO_DEV && VIDEO_V4L2 select VIDEOBUF2_DMA_CONTIG default n ---help--- - Support for the VPU video codec found on Rockchip RK3288 SoC. + Support for the VPU video codec found on Rockchip SoC. To compile this driver as a module, choose M here: the module - will be called rk3288-vpu. + will be called rockchip-vpu. config VIDEO_TI_VPE_DEBUG bool "VPE debug messages" diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 63d3e79c9b49..c52535ead136 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -54,6 +54,6 @@ obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/ obj-$(CONFIG_VIDEO_XILINX) += xilinx/ -obj-$(CONFIG_VIDEO_RK3288_VPU) += rk3288-vpu/ +obj-$(CONFIG_VIDEO_ROCKCHIP_VPU) += rockchip-vpu/ ccflags-y += -I$(srctree)/drivers/media/i2c diff --git a/drivers/media/platform/rk3288-vpu/Makefile b/drivers/media/platform/rk3288-vpu/Makefile deleted file mode 100644 index c6024e68c72a..000000000000 --- a/drivers/media/platform/rk3288-vpu/Makefile +++ /dev/null @@ -1,10 +0,0 @@ - -obj-$(CONFIG_VIDEO_RK3288_VPU) += rk3288-vpu.o - -rk3288-vpu-y += rk3288_vpu.o \ - rk3288_vpu_dec.o \ - rk3288_vpu_enc.o \ - rk3288_vpu_hw.o \ - rk3288_vpu_hw_h264d.o \ - rk3288_vpu_hw_vp8d.o \ - rk3288_vpu_hw_vp8e.o diff --git a/drivers/media/platform/rk3288-vpu/rk3288_vpu.c b/drivers/media/platform/rk3288-vpu/rk3288_vpu.c deleted file mode 100644 index ac35b0cf9665..000000000000 --- a/drivers/media/platform/rk3288-vpu/rk3288_vpu.c +++ /dev/null @@ -1,822 +0,0 @@ -/* - * Rockchip RK3288 VPU codec driver - * - * Copyright (C) 2014 Google, Inc. - * Tomasz Figa - * - * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. - * - * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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 "rk3288_vpu_common.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rk3288_vpu_dec.h" -#include "rk3288_vpu_enc.h" -#include "rk3288_vpu_hw.h" - -int debug; -module_param(debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, - "Debug level - higher value produces more verbose messages"); - -/* - * DMA coherent helpers. - */ - -int rk3288_vpu_aux_buf_alloc(struct rk3288_vpu_dev *vpu, - struct rk3288_vpu_aux_buf *buf, size_t size) -{ - buf->cpu = dma_alloc_coherent(vpu->dev, size, &buf->dma, GFP_KERNEL); - if (!buf->cpu) - return -ENOMEM; - - buf->size = size; - return 0; -} - -void rk3288_vpu_aux_buf_free(struct rk3288_vpu_dev *vpu, - struct rk3288_vpu_aux_buf *buf) -{ - dma_free_coherent(vpu->dev, buf->size, buf->cpu, buf->dma); - - buf->cpu = NULL; - buf->dma = 0; - buf->size = 0; -} - -/* - * Context scheduling. - */ - -static void rk3288_vpu_prepare_run(struct rk3288_vpu_ctx *ctx) -{ - if (ctx->run_ops->prepare_run) - ctx->run_ops->prepare_run(ctx); -} - -static void __rk3288_vpu_dequeue_run_locked(struct rk3288_vpu_ctx *ctx) -{ - struct rk3288_vpu_buf *src, *dst; - - /* - * Since ctx was dequeued from ready_ctxs list, we know that it has - * at least one buffer in each queue. - */ - src = list_first_entry(&ctx->src_queue, struct rk3288_vpu_buf, list); - dst = list_first_entry(&ctx->dst_queue, struct rk3288_vpu_buf, list); - - list_del(&src->list); - list_del(&dst->list); - - ctx->run.src = src; - ctx->run.dst = dst; -} - -static struct rk3288_vpu_ctx * -rk3288_vpu_encode_after_decode_war(struct rk3288_vpu_ctx *ctx) -{ - struct rk3288_vpu_dev *dev = ctx->dev; - - if (dev->was_decoding && rk3288_vpu_ctx_is_encoder(ctx)) - return dev->dummy_encode_ctx; - - return ctx; -} - -static void rk3288_vpu_try_run(struct rk3288_vpu_dev *dev) -{ - struct rk3288_vpu_ctx *ctx = NULL; - unsigned long flags; - - vpu_debug_enter(); - - spin_lock_irqsave(&dev->irqlock, flags); - - if (list_empty(&dev->ready_ctxs) || - test_bit(VPU_SUSPENDED, &dev->state)) - /* Nothing to do. */ - goto out; - - if (test_and_set_bit(VPU_RUNNING, &dev->state)) - /* - * The hardware is already running. We will pick another - * run after we get the notification in rk3288_vpu_run_done(). - */ - goto out; - - ctx = list_entry(dev->ready_ctxs.next, struct rk3288_vpu_ctx, list); - - /* - * WAR for corrupted hardware state when encoding directly after - * certain decoding runs. - * - * If previous context was decoding and currently picked one is - * encoding then we need to execute a dummy encode with proper - * settings to reinitialize certain internal hardware state. - */ - ctx = rk3288_vpu_encode_after_decode_war(ctx); - - if (!rk3288_vpu_ctx_is_dummy_encode(ctx)) { - list_del_init(&ctx->list); - __rk3288_vpu_dequeue_run_locked(ctx); - } - - dev->current_ctx = ctx; - dev->was_decoding = !rk3288_vpu_ctx_is_encoder(ctx); - -out: - spin_unlock_irqrestore(&dev->irqlock, flags); - - if (ctx) { - rk3288_vpu_prepare_run(ctx); - rk3288_vpu_run(ctx); - } - - vpu_debug_leave(); -} - -static void __rk3288_vpu_try_context_locked(struct rk3288_vpu_dev *dev, - struct rk3288_vpu_ctx *ctx) -{ - if (!list_empty(&ctx->list)) - /* Context already queued. */ - return; - - if (!list_empty(&ctx->dst_queue) && !list_empty(&ctx->src_queue)) - list_add_tail(&ctx->list, &dev->ready_ctxs); -} - -void rk3288_vpu_run_done(struct rk3288_vpu_ctx *ctx, - enum vb2_buffer_state result) -{ - struct rk3288_vpu_dev *dev = ctx->dev; - unsigned long flags; - - vpu_debug_enter(); - - if (ctx->run_ops->run_done) - ctx->run_ops->run_done(ctx, result); - - if (!rk3288_vpu_ctx_is_dummy_encode(ctx)) { - struct vb2_buffer *src = &ctx->run.src->b; - struct vb2_buffer *dst = &ctx->run.dst->b; - - dst->v4l2_buf.timestamp = src->v4l2_buf.timestamp; - vb2_buffer_done(&ctx->run.src->b, result); - vb2_buffer_done(&ctx->run.dst->b, result); - } - - dev->current_ctx = NULL; - wake_up_all(&dev->run_wq); - - spin_lock_irqsave(&dev->irqlock, flags); - - __rk3288_vpu_try_context_locked(dev, ctx); - clear_bit(VPU_RUNNING, &dev->state); - - spin_unlock_irqrestore(&dev->irqlock, flags); - - /* Try scheduling another run to see if we have anything left to do. */ - rk3288_vpu_try_run(dev); - - vpu_debug_leave(); -} - -void rk3288_vpu_try_context(struct rk3288_vpu_dev *dev, - struct rk3288_vpu_ctx *ctx) -{ - unsigned long flags; - - vpu_debug_enter(); - - spin_lock_irqsave(&dev->irqlock, flags); - - __rk3288_vpu_try_context_locked(dev, ctx); - - spin_unlock_irqrestore(&dev->irqlock, flags); - - rk3288_vpu_try_run(dev); - - vpu_debug_enter(); -} - -/* - * Control registration. - */ - -#define IS_VPU_PRIV(x) ((V4L2_CTRL_ID2CLASS(x) == V4L2_CTRL_CLASS_MPEG) && \ - V4L2_CTRL_DRIVER_PRIV(x)) - -int rk3288_vpu_ctrls_setup(struct rk3288_vpu_ctx *ctx, - const struct v4l2_ctrl_ops *ctrl_ops, - struct rk3288_vpu_control *controls, - unsigned num_ctrls, - const char *const *(*get_menu)(u32)) -{ - struct v4l2_ctrl_config cfg; - int i; - - if (num_ctrls > ARRAY_SIZE(ctx->ctrls)) { - vpu_err("context control array not large enough\n"); - return -ENOSPC; - } - - v4l2_ctrl_handler_init(&ctx->ctrl_handler, num_ctrls); - if (ctx->ctrl_handler.error) { - vpu_err("v4l2_ctrl_handler_init failed\n"); - return ctx->ctrl_handler.error; - } - - for (i = 0; i < num_ctrls; i++) { - if (IS_VPU_PRIV(controls[i].id) - || controls[i].id >= V4L2_CID_CUSTOM_BASE - || controls[i].type == V4L2_CTRL_TYPE_PRIVATE) { - memset(&cfg, 0, sizeof(struct v4l2_ctrl_config)); - - cfg.ops = ctrl_ops; - cfg.id = controls[i].id; - cfg.min = controls[i].minimum; - cfg.max = controls[i].maximum; - cfg.max_stores = controls[i].max_stores; - cfg.def = controls[i].default_value; - cfg.name = controls[i].name; - cfg.type = controls[i].type; - cfg.elem_size = controls[i].elem_size; - memcpy(cfg.dims, controls[i].dims, sizeof(cfg.dims)); - - if (cfg.type == V4L2_CTRL_TYPE_MENU) { - cfg.menu_skip_mask = cfg.menu_skip_mask; - cfg.qmenu = get_menu(cfg.id); - } else { - cfg.step = controls[i].step; - } - - ctx->ctrls[i] = v4l2_ctrl_new_custom( - &ctx->ctrl_handler, &cfg, NULL); - } else { - if (controls[i].type == V4L2_CTRL_TYPE_MENU) { - ctx->ctrls[i] = - v4l2_ctrl_new_std_menu - (&ctx->ctrl_handler, - ctrl_ops, - controls[i].id, - controls[i].maximum, - 0, - controls[i]. - default_value); - } else { - ctx->ctrls[i] = - v4l2_ctrl_new_std(&ctx->ctrl_handler, - ctrl_ops, - controls[i].id, - controls[i].minimum, - controls[i].maximum, - controls[i].step, - controls[i]. - default_value); - } - } - - if (ctx->ctrl_handler.error) { - vpu_err("Adding control (%d) failed\n", i); - return ctx->ctrl_handler.error; - } - - if (controls[i].is_volatile && ctx->ctrls[i]) - ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_VOLATILE; - if (controls[i].is_read_only && ctx->ctrls[i]) - ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_READ_ONLY; - if (controls[i].can_store && ctx->ctrls[i]) - ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_CAN_STORE; - } - - v4l2_ctrl_handler_setup(&ctx->ctrl_handler); - ctx->num_ctrls = num_ctrls; - return 0; -} - -void rk3288_vpu_ctrls_delete(struct rk3288_vpu_ctx *ctx) -{ - int i; - - v4l2_ctrl_handler_free(&ctx->ctrl_handler); - for (i = 0; i < ctx->num_ctrls; i++) - ctx->ctrls[i] = NULL; -} - -/* - * V4L2 file operations. - */ - -static int rk3288_vpu_open(struct file *filp) -{ - struct video_device *vdev = video_devdata(filp); - struct rk3288_vpu_dev *dev = video_drvdata(filp); - struct rk3288_vpu_ctx *ctx = NULL; - struct vb2_queue *q; - int ret = 0; - - /* - * We do not need any extra locking here, because we operate only - * on local data here, except reading few fields from dev, which - * do not change through device's lifetime (which is guaranteed by - * reference on module from open()) and V4L2 internal objects (such - * as vdev and ctx->fh), which have proper locking done in respective - * helper functions used here. - */ - - vpu_debug_enter(); - - /* Allocate memory for context */ - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) { - ret = -ENOMEM; - goto err_leave; - } - - v4l2_fh_init(&ctx->fh, video_devdata(filp)); - filp->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); - ctx->dev = dev; - INIT_LIST_HEAD(&ctx->src_queue); - INIT_LIST_HEAD(&ctx->dst_queue); - INIT_LIST_HEAD(&ctx->list); - - if (vdev == dev->vfd_enc) { - /* only for encoder */ - ret = rk3288_vpu_enc_init(ctx); - if (ret) { - vpu_err("Failed to initialize encoder context\n"); - goto err_fh_free; - } - } else if (vdev == dev->vfd_dec) { - /* only for decoder */ - ret = rk3288_vpu_dec_init(ctx); - if (ret) { - vpu_err("Failed to initialize decoder context\n"); - goto err_fh_free; - } - } else { - ret = -ENOENT; - goto err_fh_free; - } - ctx->fh.ctrl_handler = &ctx->ctrl_handler; - - /* Init videobuf2 queue for CAPTURE */ - q = &ctx->vq_dst; - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - q->drv_priv = &ctx->fh; - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; - q->lock = &dev->vpu_mutex; - q->buf_struct_size = sizeof(struct rk3288_vpu_buf); - - if (vdev == dev->vfd_enc) { - q->ops = get_enc_queue_ops(); - } else if (vdev == dev->vfd_dec) { - q->ops = get_dec_queue_ops(); - q->use_dma_bidirectional = 1; - } - - q->mem_ops = &vb2_dma_contig_memops; - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; - - ret = vb2_queue_init(q); - if (ret) { - vpu_err("Failed to initialize videobuf2 queue(capture)\n"); - goto err_enc_dec_exit; - } - - /* Init videobuf2 queue for OUTPUT */ - q = &ctx->vq_src; - q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - q->drv_priv = &ctx->fh; - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; - q->lock = &dev->vpu_mutex; - q->buf_struct_size = sizeof(struct rk3288_vpu_buf); - - if (vdev == dev->vfd_enc) - q->ops = get_enc_queue_ops(); - else if (vdev == dev->vfd_dec) - q->ops = get_dec_queue_ops(); - - q->mem_ops = &vb2_dma_contig_memops; - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; - - ret = vb2_queue_init(q); - if (ret) { - vpu_err("Failed to initialize videobuf2 queue(output)\n"); - goto err_vq_dst_release; - } - - vpu_debug_leave(); - - return 0; - -err_vq_dst_release: - vb2_queue_release(&ctx->vq_dst); -err_enc_dec_exit: - if (vdev == dev->vfd_enc) - rk3288_vpu_enc_exit(ctx); - else if (vdev == dev->vfd_dec) - rk3288_vpu_dec_exit(ctx); -err_fh_free: - v4l2_fh_del(&ctx->fh); - v4l2_fh_exit(&ctx->fh); - kfree(ctx); -err_leave: - vpu_debug_leave(); - - return ret; -} - -static int rk3288_vpu_release(struct file *filp) -{ - struct rk3288_vpu_ctx *ctx = fh_to_ctx(filp->private_data); - struct video_device *vdev = video_devdata(filp); - struct rk3288_vpu_dev *dev = ctx->dev; - - /* - * No need for extra locking because this was the last reference - * to this file. - */ - - vpu_debug_enter(); - - /* - * vb2_queue_release() ensures that streaming is stopped, which - * in turn means that there are no frames still being processed - * by hardware. - */ - vb2_queue_release(&ctx->vq_src); - vb2_queue_release(&ctx->vq_dst); - - v4l2_fh_del(&ctx->fh); - v4l2_fh_exit(&ctx->fh); - - if (vdev == dev->vfd_enc) - rk3288_vpu_enc_exit(ctx); - else if (vdev == dev->vfd_dec) - rk3288_vpu_dec_exit(ctx); - - kfree(ctx); - - vpu_debug_leave(); - - return 0; -} - -static unsigned int rk3288_vpu_poll(struct file *filp, - struct poll_table_struct *wait) -{ - struct rk3288_vpu_ctx *ctx = fh_to_ctx(filp->private_data); - struct vb2_queue *src_q, *dst_q; - struct vb2_buffer *src_vb = NULL, *dst_vb = NULL; - unsigned int rc = 0; - unsigned long flags; - - vpu_debug_enter(); - - src_q = &ctx->vq_src; - dst_q = &ctx->vq_dst; - - /* - * There has to be at least one buffer queued on each queued_list, which - * means either in driver already or waiting for driver to claim it - * and start processing. - */ - if ((!vb2_is_streaming(src_q) || list_empty(&src_q->queued_list)) && - (!vb2_is_streaming(dst_q) || list_empty(&dst_q->queued_list))) { - vpu_debug(0, "src q streaming %d, dst q streaming %d, src list empty(%d), dst list empty(%d)\n", - src_q->streaming, dst_q->streaming, - list_empty(&src_q->queued_list), - list_empty(&dst_q->queued_list)); - return POLLERR; - } - - poll_wait(filp, &ctx->fh.wait, wait); - poll_wait(filp, &src_q->done_wq, wait); - poll_wait(filp, &dst_q->done_wq, wait); - - if (v4l2_event_pending(&ctx->fh)) - rc |= POLLPRI; - - spin_lock_irqsave(&src_q->done_lock, flags); - - if (!list_empty(&src_q->done_list)) - src_vb = list_first_entry(&src_q->done_list, struct vb2_buffer, - done_entry); - - if (src_vb && (src_vb->state == VB2_BUF_STATE_DONE || - src_vb->state == VB2_BUF_STATE_ERROR)) - rc |= POLLOUT | POLLWRNORM; - - spin_unlock_irqrestore(&src_q->done_lock, flags); - - spin_lock_irqsave(&dst_q->done_lock, flags); - - if (!list_empty(&dst_q->done_list)) - dst_vb = list_first_entry(&dst_q->done_list, struct vb2_buffer, - done_entry); - - if (dst_vb && (dst_vb->state == VB2_BUF_STATE_DONE || - dst_vb->state == VB2_BUF_STATE_ERROR)) - rc |= POLLIN | POLLRDNORM; - - spin_unlock_irqrestore(&dst_q->done_lock, flags); - - return rc; -} - -static int rk3288_vpu_mmap(struct file *filp, struct vm_area_struct *vma) -{ - struct rk3288_vpu_ctx *ctx = fh_to_ctx(filp->private_data); - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - int ret; - - vpu_debug_enter(); - - if (offset < DST_QUEUE_OFF_BASE) { - vpu_debug(4, "mmaping source\n"); - - ret = vb2_mmap(&ctx->vq_src, vma); - } else { /* capture */ - vpu_debug(4, "mmaping destination\n"); - - vma->vm_pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT); - ret = vb2_mmap(&ctx->vq_dst, vma); - } - - vpu_debug_leave(); - - return ret; -} - -static const struct v4l2_file_operations rk3288_vpu_fops = { - .owner = THIS_MODULE, - .open = rk3288_vpu_open, - .release = rk3288_vpu_release, - .poll = rk3288_vpu_poll, - .unlocked_ioctl = video_ioctl2, - .mmap = rk3288_vpu_mmap, -}; - -/* - * Platform driver. - */ - -static int rk3288_vpu_probe(struct platform_device *pdev) -{ - struct rk3288_vpu_dev *vpu = NULL; - DEFINE_DMA_ATTRS(attrs_novm); - DEFINE_DMA_ATTRS(attrs_nohugepage); - struct video_device *vfd; - int ret = 0; - - vpu_debug_enter(); - - vpu = devm_kzalloc(&pdev->dev, sizeof(*vpu), GFP_KERNEL); - if (!vpu) - return -ENOMEM; - - vpu->dev = &pdev->dev; - vpu->pdev = pdev; - mutex_init(&vpu->vpu_mutex); - spin_lock_init(&vpu->irqlock); - INIT_LIST_HEAD(&vpu->ready_ctxs); - init_waitqueue_head(&vpu->run_wq); - - ret = rk3288_vpu_hw_probe(vpu); - if (ret) { - dev_err(&pdev->dev, "vcodec_hw_probe failed\n"); - goto err_hw_probe; - } - - /* - * We'll do mostly sequential access, so sacrifice TLB efficiency for - * faster allocation. - */ - dma_set_attr(DMA_ATTR_ALLOC_SINGLE_PAGES, &attrs_novm); - - dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs_novm); - vpu->alloc_ctx = vb2_dma_contig_init_ctx_attrs(&pdev->dev, - &attrs_novm); - if (IS_ERR(vpu->alloc_ctx)) { - ret = PTR_ERR(vpu->alloc_ctx); - goto err_dma_contig; - } - - dma_set_attr(DMA_ATTR_ALLOC_SINGLE_PAGES, &attrs_nohugepage); - vpu->alloc_ctx_vm = vb2_dma_contig_init_ctx_attrs(&pdev->dev, - &attrs_nohugepage); - if (IS_ERR(vpu->alloc_ctx_vm)) { - ret = PTR_ERR(vpu->alloc_ctx_vm); - goto err_dma_contig_vm; - } - - ret = v4l2_device_register(&pdev->dev, &vpu->v4l2_dev); - if (ret) { - dev_err(&pdev->dev, "Failed to register v4l2 device\n"); - goto err_v4l2_dev_reg; - } - - platform_set_drvdata(pdev, vpu); - - ret = rk3288_vpu_enc_init_dummy_ctx(vpu); - if (ret) { - dev_err(&pdev->dev, "Failed to create dummy encode context\n"); - goto err_dummy_enc; - } - - /* encoder */ - vfd = video_device_alloc(); - if (!vfd) { - v4l2_err(&vpu->v4l2_dev, "Failed to allocate video device\n"); - ret = -ENOMEM; - goto err_enc_alloc; - } - - vfd->fops = &rk3288_vpu_fops; - vfd->ioctl_ops = get_enc_v4l2_ioctl_ops(); - vfd->release = video_device_release; - vfd->lock = &vpu->vpu_mutex; - vfd->v4l2_dev = &vpu->v4l2_dev; - vfd->vfl_dir = VFL_DIR_M2M; - snprintf(vfd->name, sizeof(vfd->name), "%s", RK3288_VPU_ENC_NAME); - vpu->vfd_enc = vfd; - - video_set_drvdata(vfd, vpu); - - ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); - if (ret) { - v4l2_err(&vpu->v4l2_dev, "Failed to register video device\n"); - video_device_release(vfd); - goto err_enc_reg; - } - - v4l2_info(&vpu->v4l2_dev, - "Rockchip RK3288 VPU encoder registered as /vpu/video%d\n", - vfd->num); - - /* decoder */ - vfd = video_device_alloc(); - if (!vfd) { - v4l2_err(&vpu->v4l2_dev, "Failed to allocate video device\n"); - ret = -ENOMEM; - goto err_dec_alloc; - } - - vfd->fops = &rk3288_vpu_fops; - vfd->ioctl_ops = get_dec_v4l2_ioctl_ops(); - vfd->release = video_device_release; - vfd->lock = &vpu->vpu_mutex; - vfd->v4l2_dev = &vpu->v4l2_dev; - vfd->vfl_dir = VFL_DIR_M2M; - snprintf(vfd->name, sizeof(vfd->name), "%s", RK3288_VPU_DEC_NAME); - vpu->vfd_dec = vfd; - - video_set_drvdata(vfd, vpu); - - ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); - if (ret) { - v4l2_err(&vpu->v4l2_dev, "Failed to register video device\n"); - video_device_release(vfd); - goto err_dec_reg; - } - - v4l2_info(&vpu->v4l2_dev, - "Rockchip RK3288 VPU decoder registered as /vpu/video%d\n", - vfd->num); - - vpu_debug_leave(); - - return 0; - -err_dec_reg: - video_device_release(vpu->vfd_dec); -err_dec_alloc: - video_unregister_device(vpu->vfd_enc); -err_enc_reg: - video_device_release(vpu->vfd_enc); -err_enc_alloc: - rk3288_vpu_enc_free_dummy_ctx(vpu); -err_dummy_enc: - v4l2_device_unregister(&vpu->v4l2_dev); -err_v4l2_dev_reg: - vb2_dma_contig_cleanup_ctx(vpu->alloc_ctx_vm); -err_dma_contig_vm: - vb2_dma_contig_cleanup_ctx(vpu->alloc_ctx); -err_dma_contig: - rk3288_vpu_hw_remove(vpu); -err_hw_probe: - pr_debug("%s-- with error\n", __func__); - vpu_debug_leave(); - - return ret; -} - -static int rk3288_vpu_remove(struct platform_device *pdev) -{ - struct rk3288_vpu_dev *vpu = platform_get_drvdata(pdev); - - vpu_debug_enter(); - - v4l2_info(&vpu->v4l2_dev, "Removing %s\n", pdev->name); - - /* - * We are safe here assuming that .remove() got called as - * a result of module removal, which guarantees that all - * contexts have been released. - */ - - video_unregister_device(vpu->vfd_dec); - video_unregister_device(vpu->vfd_enc); - rk3288_vpu_enc_free_dummy_ctx(vpu); - v4l2_device_unregister(&vpu->v4l2_dev); - vb2_dma_contig_cleanup_ctx(vpu->alloc_ctx_vm); - vb2_dma_contig_cleanup_ctx(vpu->alloc_ctx); - rk3288_vpu_hw_remove(vpu); - - vpu_debug_leave(); - - return 0; -} - -static struct platform_device_id vpu_driver_ids[] = { - { .name = "rk3288-vpu", }, - { /* sentinel */ } -}; - -MODULE_DEVICE_TABLE(platform, vpu_driver_ids); - -#ifdef CONFIG_OF -static const struct of_device_id of_rk3288_vpu_match[] = { - { .compatible = "rockchip,rk3288-vpu", }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, of_rk3288_vpu_match); -#endif - -#ifdef CONFIG_PM_SLEEP -static int rk3288_vpu_suspend(struct device *dev) -{ - struct rk3288_vpu_dev *vpu = dev_get_drvdata(dev); - - set_bit(VPU_SUSPENDED, &vpu->state); - wait_event(vpu->run_wq, vpu->current_ctx == NULL); - - return 0; -} - -static int rk3288_vpu_resume(struct device *dev) -{ - struct rk3288_vpu_dev *vpu = dev_get_drvdata(dev); - - clear_bit(VPU_SUSPENDED, &vpu->state); - rk3288_vpu_try_run(vpu); - - return 0; -} -#endif - -static const struct dev_pm_ops rk3288_vpu_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(rk3288_vpu_suspend, rk3288_vpu_resume) -}; - -static struct platform_driver rk3288_vpu_driver = { - .probe = rk3288_vpu_probe, - .remove = rk3288_vpu_remove, - .id_table = vpu_driver_ids, - .driver = { - .name = RK3288_VPU_NAME, - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(of_rk3288_vpu_match), - .pm = &rk3288_vpu_pm_ops, - }, -}; -module_platform_driver(rk3288_vpu_driver); - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Alpha Lin "); -MODULE_AUTHOR("Tomasz Figa "); -MODULE_DESCRIPTION("Rockchip RK3288 VPU codec driver"); diff --git a/drivers/media/platform/rk3288-vpu/rk3288_vpu_common.h b/drivers/media/platform/rk3288-vpu/rk3288_vpu_common.h deleted file mode 100644 index 9ac44e82c42f..000000000000 --- a/drivers/media/platform/rk3288-vpu/rk3288_vpu_common.h +++ /dev/null @@ -1,519 +0,0 @@ -/* - * Rockchip RK3288 VPU codec driver - * - * Copyright (C) 2014 Google, Inc. - * Tomasz Figa - * - * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. - * - * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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 RK3288_VPU_COMMON_H_ -#define RK3288_VPU_COMMON_H_ - -/* Enable debugging by default for now. */ -#define DEBUG - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "rk3288_vpu_hw.h" - -#define RK3288_VPU_NAME "rk3288-vpu" -#define RK3288_VPU_DEC_NAME "rk3288-vpu-dec" -#define RK3288_VPU_ENC_NAME "rk3288-vpu-enc" - -#define V4L2_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0x1000) - -#define DST_QUEUE_OFF_BASE (TASK_SIZE / 2) - -#define RK3288_VPU_MAX_CTRLS 32 - -#define MB_DIM 16 -#define MB_WIDTH(x_size) DIV_ROUND_UP(x_size, MB_DIM) -#define MB_HEIGHT(y_size) DIV_ROUND_UP(y_size, MB_DIM) - -struct rk3288_vpu_variant; -struct rk3288_vpu_ctx; -struct rk3288_vpu_codec_ops; - -/** - * enum rk3288_vpu_codec_mode - codec operating mode. - * @RK_VPU_CODEC_NONE: No operating mode. Used for RAW video formats. - * @RK_VPU_CODEC_H264D: H264 decoder. - * @RK_VPU_CODEC_VP8D: VP8 decoder. - * @RK_VPU_CODEC_H264E: H264 encoder. - * @RK_VPU_CODEC_VP8E: VP8 encoder. - */ -enum rk3288_vpu_codec_mode { - RK_VPU_CODEC_NONE = -1, - RK_VPU_CODEC_H264D, - RK_VPU_CODEC_VP8D, - RK_VPU_CODEC_H264E, - RK_VPU_CODEC_VP8E -}; - -/** - * enum rk3288_vpu_plane - indices of planes inside a VB2 buffer. - * @PLANE_Y: Plane containing luminance data (also denoted as Y). - * @PLANE_CB_CR: Plane containing interleaved chrominance data (also - * denoted as CbCr). - * @PLANE_CB: Plane containing CB part of chrominance data. - * @PLANE_CR: Plane containing CR part of chrominance data. - */ -enum rk3288_vpu_plane { - PLANE_Y = 0, - PLANE_CB_CR = 1, - PLANE_CB = 1, - PLANE_CR = 2, -}; - -/** - * struct rk3288_vpu_vp8e_buf_data - mode-specific per-buffer data - * @dct_offset: Offset inside the buffer to DCT partition. - * @hdr_size: Size of header data in the buffer. - * @ext_hdr_size: Size of ext header data in the buffer. - * @dct_size: Size of DCT partition in the buffer. - * @header: Frame header to copy to destination buffer. - */ -struct rk3288_vpu_vp8e_buf_data { - size_t dct_offset; - size_t hdr_size; - size_t ext_hdr_size; - size_t dct_size; - u8 header[RK3288_HEADER_SIZE]; -}; - -/** - * struct rk3288_vpu_buf - Private data related to each VB2 buffer. - * @list: List head for queuing in buffer queue. - * @b: Pointer to related VB2 buffer. - * @flags: Buffer state. See enum rk3288_vpu_buf_flags. - */ -struct rk3288_vpu_buf { - struct vb2_buffer b; - struct list_head list; - - /* Mode-specific data. */ - union { - struct rk3288_vpu_vp8e_buf_data vp8e; - }; -}; - -/** - * enum rk3288_vpu_state - bitwise flags indicating hardware state. - * @VPU_RUNNING: The hardware has been programmed for operation - * and is running at the moment. - * @VPU_SUSPENDED: System is entering sleep state and no more runs - * should be executed on hardware. - */ -enum rk3288_vpu_state { - VPU_RUNNING = BIT(0), - VPU_SUSPENDED = BIT(1), -}; - -/** - * struct rk3288_vpu_dev - driver data - * @v4l2_dev: V4L2 device to register video devices for. - * @vfd_dec: Video device for decoder. - * @vfd_enc: Video device for encoder. - * @pdev: Pointer to VPU platform device. - * @dev: Pointer to device for convenient logging using - * dev_ macros. - * @alloc_ctx: VB2 allocator context - * (for allocations without kernel mapping). - * @alloc_ctx_vm: VB2 allocator context - * (for allocations with kernel mapping). - * @aclk_vcodec: Handle of ACLK clock. - * @hclk_vcodec: Handle of HCLK clock. - * @base: Mapped address of VPU registers. - * @enc_base: Mapped address of VPU encoder register for convenience. - * @dec_base: Mapped address of VPU decoder register for convenience. - * @mapping: DMA IOMMU mapping. - * @vpu_mutex: Mutex to synchronize V4L2 calls. - * @irqlock: Spinlock to synchronize access to data structures - * shared with interrupt handlers. - * @state: Device state. - * @ready_ctxs: List of contexts ready to run. - * @variant: Hardware variant-specfic parameters. - * @current_ctx: Context being currently processed by hardware. - * @run_wq: Wait queue to wait for run completion. - * @watchdog_work: Delayed work for hardware timeout handling. - * @dummy_encode_ctx: Context used to run dummy frame encoding to initialize - * encoder hardware state. - * @dummy_encode_src: Source buffers used for dummy frame encoding. - * @dummy_encode_dst: Desintation buffer used for dummy frame encoding. - * @was_decoding: Indicates whether last run context was a decoder. - */ -struct rk3288_vpu_dev { - struct v4l2_device v4l2_dev; - struct video_device *vfd_dec; - struct video_device *vfd_enc; - struct platform_device *pdev; - struct device *dev; - void *alloc_ctx; - void *alloc_ctx_vm; - struct clk *aclk_vcodec; - struct clk *hclk_vcodec; - void __iomem *base; - void __iomem *enc_base; - void __iomem *dec_base; - struct dma_iommu_mapping *mapping; - - struct mutex vpu_mutex; /* video_device lock */ - spinlock_t irqlock; - unsigned long state; - struct list_head ready_ctxs; - const struct rk3288_vpu_variant *variant; - struct rk3288_vpu_ctx *current_ctx; - wait_queue_head_t run_wq; - struct delayed_work watchdog_work; - struct rk3288_vpu_ctx *dummy_encode_ctx; - struct rk3288_vpu_aux_buf dummy_encode_src[VIDEO_MAX_PLANES]; - struct rk3288_vpu_aux_buf dummy_encode_dst; - bool was_decoding; -}; - -/** - * struct rk3288_vpu_run_ops - per context operations on run data. - * @prepare_run: Called when the context was selected for running - * to prepare operating mode specific data. - * @run_done: Called when hardware completed the run to collect - * operating mode specific data from hardware and - * finalize the processing. - */ -struct rk3288_vpu_run_ops { - void (*prepare_run)(struct rk3288_vpu_ctx *); - void (*run_done)(struct rk3288_vpu_ctx *, enum vb2_buffer_state); -}; - -/** - * struct rk3288_vpu_vp8e_run - per-run data specific to VP8 encoding. - * @reg_params: Pointer to a buffer containing register values prepared - * by user space. - */ -struct rk3288_vpu_vp8e_run { - const struct rk3288_vp8e_reg_params *reg_params; -}; - -/** - * struct rk3288_vpu_vp8d_run - per-run data specific to VP8 decoding. - * @frame_hdr: Pointer to a buffer containing per-run frame data which - * is needed by setting vpu register. - */ -struct rk3288_vpu_vp8d_run { - const struct v4l2_ctrl_vp8_frame_hdr *frame_hdr; -}; - -/** - * struct rk3288_vpu_h264d_run - per-run data specific to H264 decoding. - * @sps: Pointer to a buffer containing H264 SPS. - * @pps: Pointer to a buffer containing H264 PPS. - * @scaling_matrix: Pointer to a buffer containing scaling matrix. - * @slice_param: Pointer to a buffer containing slice parameters array. - * @decode_param: Pointer to a buffer containing decode parameters. - * @dpb: Array of DPB entries reordered to keep POC order. - * @dpb_map: Map of indices used in ref_pic_list_* into indices to - * reordered DPB array. - */ -struct rk3288_vpu_h264d_run { - const struct v4l2_ctrl_h264_sps *sps; - const struct v4l2_ctrl_h264_pps *pps; - const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix; - const struct v4l2_ctrl_h264_slice_param *slice_param; - const struct v4l2_ctrl_h264_decode_param *decode_param; - struct v4l2_h264_dpb_entry dpb[16]; - u8 dpb_map[16]; -}; - -/** - * struct rk3288_vpu_run - per-run data for hardware code. - * @src: Source buffer to be processed. - * @dst: Destination buffer to be processed. - * @priv_src: Hardware private source buffer. - * @priv_dst: Hardware private destination buffer. - */ -struct rk3288_vpu_run { - /* Generic for more than one operating mode. */ - struct rk3288_vpu_buf *src; - struct rk3288_vpu_buf *dst; - - struct rk3288_vpu_aux_buf priv_src; - struct rk3288_vpu_aux_buf priv_dst; - - /* Specific for particular operating modes. */ - union { - struct rk3288_vpu_vp8e_run vp8e; - struct rk3288_vpu_vp8d_run vp8d; - struct rk3288_vpu_h264d_run h264d; - /* Other modes will need different data. */ - }; -}; - -/** - * struct rk3288_vpu_ctx - Context (instance) private data. - * - * @dev: VPU driver data to which the context belongs. - * @fh: V4L2 file handler. - * - * @vpu_src_fmt: Descriptor of active source format. - * @src_fmt: V4L2 pixel format of active source format. - * @vpu_dst_fmt: Descriptor of active destination format. - * @dst_fmt: V4L2 pixel format of active destination format. - * - * @vq_src: Videobuf2 source queue. - * @src_queue: Internal source buffer queue. - * @src_crop: Configured source crop rectangle (encoder-only). - * @vq_dst: Videobuf2 destination queue - * @dst_queue: Internal destination buffer queue. - * @dst_bufs: Private buffers wrapping VB2 buffers (destination). - * - * @ctrls: Array containing pointer to registered controls. - * @ctrl_handler: Control handler used to register controls. - * @num_ctrls: Number of registered controls. - * - * @list: List head for queue of ready contexts. - * - * @run: Structure containing data about currently scheduled - * processing run. - * @run_ops: Set of operations related to currently scheduled run. - * @hw: Structure containing hardware-related context. - */ -struct rk3288_vpu_ctx { - struct rk3288_vpu_dev *dev; - struct v4l2_fh fh; - - /* Format info */ - struct rk3288_vpu_fmt *vpu_src_fmt; - struct v4l2_pix_format_mplane src_fmt; - struct rk3288_vpu_fmt *vpu_dst_fmt; - struct v4l2_pix_format_mplane dst_fmt; - - /* VB2 queue data */ - struct vb2_queue vq_src; - struct list_head src_queue; - struct v4l2_rect src_crop; - struct vb2_queue vq_dst; - struct list_head dst_queue; - struct vb2_buffer *dst_bufs[VIDEO_MAX_FRAME]; - - /* Controls */ - struct v4l2_ctrl *ctrls[RK3288_VPU_MAX_CTRLS]; - struct v4l2_ctrl_handler ctrl_handler; - unsigned num_ctrls; - - /* Various runtime data */ - struct list_head list; - - struct rk3288_vpu_run run; - const struct rk3288_vpu_run_ops *run_ops; - struct rk3288_vpu_hw_ctx hw; -}; - -/** - * struct rk3288_vpu_fmt - information about supported video formats. - * @name: Human readable name of the format. - * @fourcc: FourCC code of the format. See V4L2_PIX_FMT_*. - * @codec_mode: Codec mode related to this format. See - * enum rk3288_vpu_codec_mode. - * @num_planes: Number of planes used by this format. - * @depth: Depth of each plane in bits per pixel. - * @enc_fmt: Format identifier for encoder registers. - */ -struct rk3288_vpu_fmt { - char *name; - u32 fourcc; - enum rk3288_vpu_codec_mode codec_mode; - int num_planes; - u8 depth[VIDEO_MAX_PLANES]; - enum rk3288_vpu_enc_fmt enc_fmt; -}; - -/** - * struct rk3288_vpu_control - information about controls to be registered. - * @id: Control ID. - * @type: Type of the control. - * @name: Human readable name of the control. - * @minimum: Minimum value of the control. - * @maximum: Maximum value of the control. - * @step: Control value increase step. - * @menu_skip_mask: Mask of invalid menu positions. - * @default_value: Initial value of the control. - * @max_stores: Maximum number of configration stores. - * @dims: Size of each dimension of compound control. - * @elem_size: Size of individual element of compound control. - * @is_volatile: Control is volatile. - * @is_read_only: Control is read-only. - * @can_store: Control uses configuration stores. - * - * See also struct v4l2_ctrl_config. - */ -struct rk3288_vpu_control { - u32 id; - - enum v4l2_ctrl_type type; - const char *name; - s32 minimum; - s32 maximum; - s32 step; - u32 menu_skip_mask; - s32 default_value; - s32 max_stores; - u32 dims[V4L2_CTRL_MAX_DIMS]; - u32 elem_size; - - bool is_volatile:1; - bool is_read_only:1; - bool can_store:1; -}; - -/* Logging helpers */ - -/** - * debug - Module parameter to control level of debugging messages. - * - * Level of debugging messages can be controlled by bits of module parameter - * called "debug". Meaning of particular bits is as follows: - * - * bit 0 - global information: mode, size, init, release - * bit 1 - each run start/result information - * bit 2 - contents of small controls from userspace - * bit 3 - contents of big controls from userspace - * bit 4 - detail fmt, ctrl, buffer q/dq information - * bit 5 - detail function enter/leave trace information - * bit 6 - register write/read information - */ -extern int debug; - -#define vpu_debug(level, fmt, args...) \ - do { \ - if (debug & BIT(level)) \ - pr_debug("%s:%d: " fmt, \ - __func__, __LINE__, ##args); \ - } while (0) - -#define vpu_debug_enter() vpu_debug(5, "enter\n") -#define vpu_debug_leave() vpu_debug(5, "leave\n") - -#define vpu_err(fmt, args...) \ - pr_err("%s:%d: " fmt, __func__, __LINE__, ##args) - -static inline char *fmt2str(u32 fmt, char *str) -{ - char a = fmt & 0xFF; - char b = (fmt >> 8) & 0xFF; - char c = (fmt >> 16) & 0xFF; - char d = (fmt >> 24) & 0xFF; - - sprintf(str, "%c%c%c%c", a, b, c, d); - - return str; -} - -/* Structure access helpers. */ -static inline struct rk3288_vpu_ctx *fh_to_ctx(struct v4l2_fh *fh) -{ - return container_of(fh, struct rk3288_vpu_ctx, fh); -} - -static inline struct rk3288_vpu_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl) -{ - return container_of(ctrl->handler, struct rk3288_vpu_ctx, ctrl_handler); -} - -static inline struct rk3288_vpu_buf *vb_to_buf(struct vb2_buffer *vb) -{ - return container_of(vb, struct rk3288_vpu_buf, b); -} - -static inline bool rk3288_vpu_ctx_is_encoder(struct rk3288_vpu_ctx *ctx) -{ - return ctx->vpu_dst_fmt->codec_mode != RK_VPU_CODEC_NONE; -} - -static inline bool rk3288_vpu_ctx_is_dummy_encode(struct rk3288_vpu_ctx *ctx) -{ - struct rk3288_vpu_dev *dev = ctx->dev; - - return ctx == dev->dummy_encode_ctx; -} - -int rk3288_vpu_ctrls_setup(struct rk3288_vpu_ctx *ctx, - const struct v4l2_ctrl_ops *ctrl_ops, - struct rk3288_vpu_control *controls, - unsigned num_ctrls, - const char *const *(*get_menu)(u32)); -void rk3288_vpu_ctrls_delete(struct rk3288_vpu_ctx *ctx); - -void rk3288_vpu_try_context(struct rk3288_vpu_dev *dev, - struct rk3288_vpu_ctx *ctx); - -void rk3288_vpu_run_done(struct rk3288_vpu_ctx *ctx, - enum vb2_buffer_state result); - -int rk3288_vpu_aux_buf_alloc(struct rk3288_vpu_dev *vpu, - struct rk3288_vpu_aux_buf *buf, size_t size); -void rk3288_vpu_aux_buf_free(struct rk3288_vpu_dev *vpu, - struct rk3288_vpu_aux_buf *buf); - -/* Register accessors. */ -static inline void vepu_write_relaxed(struct rk3288_vpu_dev *vpu, - u32 val, u32 reg) -{ - vpu_debug(6, "MARK: set reg[%03d]: %08x\n", reg / 4, val); - writel_relaxed(val, vpu->enc_base + reg); -} - -static inline void vepu_write(struct rk3288_vpu_dev *vpu, u32 val, u32 reg) -{ - vpu_debug(6, "MARK: set reg[%03d]: %08x\n", reg / 4, val); - writel(val, vpu->enc_base + reg); -} - -static inline u32 vepu_read(struct rk3288_vpu_dev *vpu, u32 reg) -{ - u32 val = readl(vpu->enc_base + reg); - - vpu_debug(6, "MARK: get reg[%03d]: %08x\n", reg / 4, val); - return val; -} - -static inline void vdpu_write_relaxed(struct rk3288_vpu_dev *vpu, - u32 val, u32 reg) -{ - vpu_debug(6, "MARK: set reg[%03d]: %08x\n", reg / 4, val); - writel_relaxed(val, vpu->dec_base + reg); -} - -static inline void vdpu_write(struct rk3288_vpu_dev *vpu, u32 val, u32 reg) -{ - vpu_debug(6, "MARK: set reg[%03d]: %08x\n", reg / 4, val); - writel(val, vpu->dec_base + reg); -} - -static inline u32 vdpu_read(struct rk3288_vpu_dev *vpu, u32 reg) -{ - u32 val = readl(vpu->dec_base + reg); - - vpu_debug(6, "MARK: get reg[%03d]: %08x\n", reg / 4, val); - return val; -} - -#endif /* RK3288_VPU_COMMON_H_ */ diff --git a/drivers/media/platform/rk3288-vpu/rk3288_vpu_dec.c b/drivers/media/platform/rk3288-vpu/rk3288_vpu_dec.c deleted file mode 100644 index 3d4aad957a1e..000000000000 --- a/drivers/media/platform/rk3288-vpu/rk3288_vpu_dec.c +++ /dev/null @@ -1,1152 +0,0 @@ -/* - * Rockchip RK3288 VPU codec driver - * - * Copyright (C) 2014 Rockchip Electronics Co., Ltd. - * Hertz Wong - * - * Copyright (C) 2014 Google, Inc. - * Tomasz Figa - * - * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. - * - * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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 "rk3288_vpu_common.h" - -#include -#include -#include - -#include -#include -#include -#include - -#include "rk3288_vpu_dec.h" -#include "rk3288_vpu_hw.h" - -#define DEF_SRC_FMT_DEC V4L2_PIX_FMT_H264_SLICE -#define DEF_DST_FMT_DEC V4L2_PIX_FMT_NV12 - -#define RK3288_DEC_MIN_WIDTH 48U -#define RK3288_DEC_MAX_WIDTH 3840U -#define RK3288_DEC_MIN_HEIGHT 48U -#define RK3288_DEC_MAX_HEIGHT 2160U - -#define RK3288_H264_MAX_SLICES_PER_FRAME 16 - -static struct rk3288_vpu_fmt formats[] = { - { - .name = "4:2:0 1 plane Y/CbCr", - .fourcc = V4L2_PIX_FMT_NV12, - .codec_mode = RK_VPU_CODEC_NONE, - .num_planes = 1, - .depth = { 12 }, - }, - { - .name = "Slices of H264 Encoded Stream", - .fourcc = V4L2_PIX_FMT_H264_SLICE, - .codec_mode = RK_VPU_CODEC_H264D, - .num_planes = 1, - }, - { - .name = "Frames of VP8 Encoded Stream", - .fourcc = V4L2_PIX_FMT_VP8_FRAME, - .codec_mode = RK_VPU_CODEC_VP8D, - .num_planes = 1, - }, -}; - -static struct rk3288_vpu_fmt *find_format(u32 fourcc, bool bitstream) -{ - unsigned int i; - - vpu_debug_enter(); - - for (i = 0; i < ARRAY_SIZE(formats); i++) { - if (formats[i].fourcc == fourcc && - !!bitstream == (formats[i].codec_mode != RK_VPU_CODEC_NONE)) - return &formats[i]; - } - - return NULL; -} - -/* Indices of controls that need to be accessed directly. */ -enum { - RK3288_VPU_DEC_CTRL_H264_SPS, - RK3288_VPU_DEC_CTRL_H264_PPS, - RK3288_VPU_DEC_CTRL_H264_SCALING_MATRIX, - RK3288_VPU_DEC_CTRL_H264_SLICE_PARAM, - RK3288_VPU_DEC_CTRL_H264_DECODE_PARAM, - RK3288_VPU_DEC_CTRL_VP8_FRAME_HDR, -}; - -static struct rk3288_vpu_control controls[] = { - /* H264 slice-based interface. */ - [RK3288_VPU_DEC_CTRL_H264_SPS] = { - .id = V4L2_CID_MPEG_VIDEO_H264_SPS, - .type = V4L2_CTRL_TYPE_PRIVATE, - .name = "H264 SPS Parameters", - .elem_size = sizeof(struct v4l2_ctrl_h264_sps), - .max_stores = VIDEO_MAX_FRAME, - .can_store = true, - }, - [RK3288_VPU_DEC_CTRL_H264_PPS] = { - .id = V4L2_CID_MPEG_VIDEO_H264_PPS, - .type = V4L2_CTRL_TYPE_PRIVATE, - .name = "H264 PPS Parameters", - .elem_size = sizeof(struct v4l2_ctrl_h264_pps), - .max_stores = VIDEO_MAX_FRAME, - .can_store = true, - }, - [RK3288_VPU_DEC_CTRL_H264_SCALING_MATRIX] = { - .id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, - .type = V4L2_CTRL_TYPE_PRIVATE, - .name = "H264 Scaling Matrix", - .elem_size = sizeof(struct v4l2_ctrl_h264_scaling_matrix), - .max_stores = VIDEO_MAX_FRAME, - .can_store = true, - }, - [RK3288_VPU_DEC_CTRL_H264_SLICE_PARAM] = { - .id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAM, - .type = V4L2_CTRL_TYPE_PRIVATE, - .name = "H264 Slice Parameters", - .max_stores = VIDEO_MAX_FRAME, - .elem_size = sizeof(struct v4l2_ctrl_h264_slice_param), - .dims = { RK3288_H264_MAX_SLICES_PER_FRAME, }, - .can_store = true, - }, - [RK3288_VPU_DEC_CTRL_H264_DECODE_PARAM] = { - .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAM, - .type = V4L2_CTRL_TYPE_PRIVATE, - .name = "H264 Decode Parameters", - .max_stores = VIDEO_MAX_FRAME, - .elem_size = sizeof(struct v4l2_ctrl_h264_decode_param), - .can_store = true, - }, - [RK3288_VPU_DEC_CTRL_VP8_FRAME_HDR] = { - .id = V4L2_CID_MPEG_VIDEO_VP8_FRAME_HDR, - .type = V4L2_CTRL_TYPE_PRIVATE, - .name = "VP8 Frame Header Parameters", - .max_stores = VIDEO_MAX_FRAME, - .elem_size = sizeof(struct v4l2_ctrl_vp8_frame_hdr), - .can_store = true, - }, -}; - -static inline const void *get_ctrl_ptr(struct rk3288_vpu_ctx *ctx, unsigned id) -{ - struct v4l2_ctrl *ctrl = ctx->ctrls[id]; - - return ctrl->p_cur.p; -} - -/* Query capabilities of the device */ -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct rk3288_vpu_dev *dev = video_drvdata(file); - - vpu_debug_enter(); - - strlcpy(cap->driver, RK3288_VPU_DEC_NAME, sizeof(cap->driver)); - strlcpy(cap->card, dev->pdev->name, sizeof(cap->card)); - strlcpy(cap->bus_info, "platform:" RK3288_VPU_NAME, - sizeof(cap->bus_info)); - - /* - * This is only a mem-to-mem video device. The capture and output - * device capability flags are left only for backward compatibility - * and are scheduled for removal. - */ - cap->capabilities = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING | - V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE; - - vpu_debug_leave(); - - return 0; -} - -static int vidioc_enum_framesizes(struct file *file, void *prov, - struct v4l2_frmsizeenum *fsize) -{ - struct v4l2_frmsize_stepwise *s = &fsize->stepwise; - struct rk3288_vpu_fmt *fmt; - - if (fsize->index != 0) { - vpu_debug(0, "invalid frame size index (expected 0, got %d)\n", - fsize->index); - return -EINVAL; - } - - fmt = find_format(fsize->pixel_format, true); - if (!fmt) { - vpu_debug(0, "unsupported bitstream format (%08x)\n", - fsize->pixel_format); - return -EINVAL; - } - - fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; - - s->min_width = RK3288_DEC_MIN_WIDTH; - s->max_width = RK3288_DEC_MAX_WIDTH; - s->step_width = MB_DIM; - s->min_height = RK3288_DEC_MIN_HEIGHT; - s->max_height = RK3288_DEC_MAX_HEIGHT; - s->step_height = MB_DIM; - - return 0; -} - -static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool out) -{ - struct rk3288_vpu_fmt *fmt; - int i, j = 0; - - vpu_debug_enter(); - - for (i = 0; i < ARRAY_SIZE(formats); ++i) { - if (out && formats[i].codec_mode == RK_VPU_CODEC_NONE) - continue; - else if (!out && (formats[i].codec_mode != RK_VPU_CODEC_NONE)) - continue; - - if (j == f->index) { - fmt = &formats[i]; - strlcpy(f->description, fmt->name, - sizeof(f->description)); - f->pixelformat = fmt->fourcc; - - f->flags = 0; - if (formats[i].codec_mode != RK_VPU_CODEC_NONE) - f->flags |= V4L2_FMT_FLAG_COMPRESSED; - - vpu_debug_leave(); - - return 0; - } - - ++j; - } - - vpu_debug_leave(); - - return -EINVAL; -} - -static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - return vidioc_enum_fmt(f, false); -} - -static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - return vidioc_enum_fmt(f, true); -} - -static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) -{ - struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); - - vpu_debug_enter(); - - vpu_debug(4, "f->type = %d\n", f->type); - - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - f->fmt.pix_mp = ctx->dst_fmt; - break; - - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - f->fmt.pix_mp = ctx->src_fmt; - break; - - default: - vpu_err("invalid buf type\n"); - return -EINVAL; - } - - vpu_debug_leave(); - - return 0; -} - -static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) -{ - struct rk3288_vpu_fmt *fmt; - struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; - char str[5]; - - vpu_debug_enter(); - - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - vpu_debug(4, "%s\n", fmt2str(f->fmt.pix_mp.pixelformat, str)); - - fmt = find_format(pix_fmt_mp->pixelformat, true); - if (!fmt) { - vpu_err("failed to try output format\n"); - return -EINVAL; - } - - if (pix_fmt_mp->plane_fmt[0].sizeimage == 0) { - vpu_err("sizeimage of output format must be given\n"); - return -EINVAL; - } - - pix_fmt_mp->plane_fmt[0].bytesperline = 0; - break; - - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - vpu_debug(4, "%s\n", fmt2str(f->fmt.pix_mp.pixelformat, str)); - - fmt = find_format(pix_fmt_mp->pixelformat, false); - if (!fmt) { - vpu_err("failed to try capture format\n"); - return -EINVAL; - } - - if (fmt->num_planes != pix_fmt_mp->num_planes) { - vpu_err("plane number mismatches on capture format\n"); - return -EINVAL; - } - - /* Limit to hardware min/max. */ - pix_fmt_mp->width = clamp(pix_fmt_mp->width, - RK3288_DEC_MIN_WIDTH, RK3288_DEC_MAX_WIDTH); - pix_fmt_mp->height = clamp(pix_fmt_mp->height, - RK3288_DEC_MIN_HEIGHT, RK3288_DEC_MAX_HEIGHT); - - /* Round up to macroblocks. */ - pix_fmt_mp->width = round_up(pix_fmt_mp->width, MB_DIM); - pix_fmt_mp->height = round_up(pix_fmt_mp->height, MB_DIM); - break; - - default: - vpu_err("invalid buf type\n"); - return -EINVAL; - } - - vpu_debug_leave(); - - return 0; -} - -static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; - struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); - unsigned int mb_width, mb_height; - struct rk3288_vpu_fmt *fmt; - int ret = 0; - int i; - - vpu_debug_enter(); - - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - /* Change not allowed if any queue is streaming. */ - if (vb2_is_streaming(&ctx->vq_src) - || vb2_is_streaming(&ctx->vq_dst)) { - ret = -EBUSY; - goto out; - } - /* - * Pixel format change is not allowed when the other queue has - * buffers allocated. - */ - if (vb2_is_busy(&ctx->vq_dst) - && pix_fmt_mp->pixelformat != ctx->src_fmt.pixelformat) { - ret = -EBUSY; - goto out; - } - - ret = vidioc_try_fmt(file, priv, f); - if (ret) - goto out; - - ctx->vpu_src_fmt = find_format(pix_fmt_mp->pixelformat, true); - ctx->src_fmt = *pix_fmt_mp; - break; - - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - /* - * Change not allowed if this queue is streaming. - * - * NOTE: We allow changes with source queue streaming - * to support resolution change in decoded stream. - */ - if (vb2_is_streaming(&ctx->vq_dst)) { - ret = -EBUSY; - goto out; - } - /* - * Pixel format change is not allowed when the other queue has - * buffers allocated. - */ - if (vb2_is_busy(&ctx->vq_src) - && pix_fmt_mp->pixelformat != ctx->dst_fmt.pixelformat) { - ret = -EBUSY; - goto out; - } - - ret = vidioc_try_fmt(file, priv, f); - if (ret) - goto out; - - fmt = find_format(pix_fmt_mp->pixelformat, false); - ctx->vpu_dst_fmt = fmt; - - mb_width = MB_WIDTH(pix_fmt_mp->width); - mb_height = MB_HEIGHT(pix_fmt_mp->height); - - vpu_debug(0, "CAPTURE codec mode: %d\n", fmt->codec_mode); - vpu_debug(0, "fmt - w: %d, h: %d, mb - w: %d, h: %d\n", - pix_fmt_mp->width, pix_fmt_mp->height, - mb_width, mb_height); - - for (i = 0; i < fmt->num_planes; ++i) { - pix_fmt_mp->plane_fmt[i].bytesperline = - mb_width * MB_DIM * fmt->depth[i] / 8; - pix_fmt_mp->plane_fmt[i].sizeimage = - pix_fmt_mp->plane_fmt[i].bytesperline - * mb_height * MB_DIM; - /* - * All of multiplanar formats we support have chroma - * planes subsampled by 2. - */ - if (i != 0) - pix_fmt_mp->plane_fmt[i].sizeimage /= 2; - } - - ctx->dst_fmt = *pix_fmt_mp; - break; - - default: - vpu_err("invalid buf type\n"); - return -EINVAL; - } - -out: - vpu_debug_leave(); - - return ret; -} - -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *reqbufs) -{ - struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); - int ret; - - vpu_debug_enter(); - - switch (reqbufs->type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - ret = vb2_reqbufs(&ctx->vq_src, reqbufs); - if (ret != 0) { - vpu_err("error in vb2_reqbufs() for E(S)\n"); - goto out; - } - break; - - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); - if (ret != 0) { - vpu_err("error in vb2_reqbufs() for E(D)\n"); - goto out; - } - break; - - default: - vpu_err("invalid buf type\n"); - ret = -EINVAL; - goto out; - } - -out: - vpu_debug_leave(); - - return ret; -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); - int ret; - - vpu_debug_enter(); - - switch (buf->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - ret = vb2_querybuf(&ctx->vq_dst, buf); - if (ret != 0) { - vpu_err("error in vb2_querybuf() for E(D)\n"); - goto out; - } - - buf->m.planes[0].m.mem_offset += DST_QUEUE_OFF_BASE; - break; - - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - ret = vb2_querybuf(&ctx->vq_src, buf); - if (ret != 0) { - vpu_err("error in vb2_querybuf() for E(S)\n"); - goto out; - } - break; - - default: - vpu_err("invalid buf type\n"); - ret = -EINVAL; - goto out; - } - -out: - vpu_debug_leave(); - - return ret; -} - -/* Queue a buffer */ -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); - int ret; - int i; - - vpu_debug_enter(); - - for (i = 0; i < buf->length; i++) - vpu_debug(4, "plane[%d]->length %d bytesused %d\n", - i, buf->m.planes[i].length, - buf->m.planes[i].bytesused); - - switch (buf->type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - ret = vb2_qbuf(&ctx->vq_src, buf); - vpu_debug(4, "OUTPUT_MPLANE : vb2_qbuf return %d\n", ret); - break; - - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - ret = vb2_qbuf(&ctx->vq_dst, buf); - vpu_debug(4, "CAPTURE_MPLANE: vb2_qbuf return %d\n", ret); - break; - - default: - ret = -EINVAL; - } - - vpu_debug_leave(); - - return ret; -} - -/* Dequeue a buffer */ -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); - int ret; - - vpu_debug_enter(); - - switch (buf->type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - ret = vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK); - break; - - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - ret = vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK); - break; - - default: - ret = -EINVAL; - } - - vpu_debug_leave(); - - return ret; -} - -/* Export DMA buffer */ -static int vidioc_expbuf(struct file *file, void *priv, - struct v4l2_exportbuffer *eb) -{ - struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); - int ret; - - vpu_debug_enter(); - - switch (eb->type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - ret = vb2_expbuf(&ctx->vq_src, eb); - break; - - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - ret = vb2_expbuf(&ctx->vq_dst, eb); - break; - - default: - ret = -EINVAL; - } - - vpu_debug_leave(); - - return ret; -} - -/* Stream on */ -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); - int ret; - - vpu_debug_enter(); - - switch (type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - ret = vb2_streamon(&ctx->vq_src, type); - break; - - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - ret = vb2_streamon(&ctx->vq_dst, type); - break; - - default: - ret = -EINVAL; - } - - vpu_debug_leave(); - - return ret; -} - -/* Stream off, which equals to a pause */ -static int vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); - int ret; - - vpu_debug_enter(); - - switch (type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - ret = vb2_streamoff(&ctx->vq_src, type); - break; - - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - ret = vb2_streamoff(&ctx->vq_dst, type); - break; - - default: - ret = -EINVAL; - } - - vpu_debug_leave(); - - return ret; -} - -static void rk3288_vpu_dec_set_dpb(struct rk3288_vpu_ctx *ctx, - struct v4l2_ctrl *ctrl) -{ - struct v4l2_ctrl_h264_decode_param *dec_param = ctrl->p_new.p; - const struct v4l2_h264_dpb_entry *new_dpb_entry; - u8 *dpb_map = ctx->run.h264d.dpb_map; - struct v4l2_h264_dpb_entry *cur_dpb_entry; - DECLARE_BITMAP(used, ARRAY_SIZE(ctx->run.h264d.dpb)) = { 0, }; - DECLARE_BITMAP(new, ARRAY_SIZE(dec_param->dpb)) = { 0, }; - int i, j; - - BUILD_BUG_ON(ARRAY_SIZE(ctx->run.h264d.dpb) != - ARRAY_SIZE(dec_param->dpb)); - - /* Disable all entries by default. */ - for (j = 0; j < ARRAY_SIZE(ctx->run.h264d.dpb); ++j) { - cur_dpb_entry = &ctx->run.h264d.dpb[j]; - - cur_dpb_entry->flags &= ~V4L2_H264_DPB_ENTRY_FLAG_ACTIVE; - } - - /* Try to match new DPB entries with existing ones by their POCs. */ - for (i = 0; i < ARRAY_SIZE(dec_param->dpb); ++i) { - new_dpb_entry = &dec_param->dpb[i]; - - if (!(new_dpb_entry->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) - continue; - - /* - * To cut off some comparisons, iterate only on target DPB - * entries which are not used yet. - */ - for_each_clear_bit(j, used, ARRAY_SIZE(ctx->run.h264d.dpb)) { - cur_dpb_entry = &ctx->run.h264d.dpb[j]; - - if (new_dpb_entry->top_field_order_cnt == - cur_dpb_entry->top_field_order_cnt && - new_dpb_entry->bottom_field_order_cnt == - cur_dpb_entry->bottom_field_order_cnt) { - memcpy(cur_dpb_entry, new_dpb_entry, - sizeof(*cur_dpb_entry)); - set_bit(j, used); - dpb_map[i] = j; - break; - } - } - - if (j == ARRAY_SIZE(ctx->run.h264d.dpb)) - set_bit(i, new); - } - - /* For entries that could not be matched, use remaining free slots. */ - for_each_set_bit(i, new, ARRAY_SIZE(dec_param->dpb)) { - new_dpb_entry = &dec_param->dpb[i]; - - j = find_first_zero_bit(used, ARRAY_SIZE(ctx->run.h264d.dpb)); - /* - * Both arrays are of the same sizes, so there is no way - * we can end up with no space in target array, unless - * something is buggy. - */ - if (WARN_ON(j >= ARRAY_SIZE(ctx->run.h264d.dpb))) - return; - - cur_dpb_entry = &ctx->run.h264d.dpb[j]; - memcpy(cur_dpb_entry, new_dpb_entry, sizeof(*cur_dpb_entry)); - set_bit(j, used); - dpb_map[i] = j; - } - - /* - * Verify that reference picture lists are in range, since they - * will be indexing dpb_map[] when programming the hardware. - * - * Fallback to 0 should be safe, as we will get at most corrupt - * decoding result, without any serious side effects. Moreover, - * even if entry 0 is unused, the hardware programming code will - * handle this properly. - */ - for (i = 0; i < ARRAY_SIZE(dec_param->ref_pic_list_b0); ++i) - if (dec_param->ref_pic_list_b0[i] - >= ARRAY_SIZE(ctx->run.h264d.dpb_map)) - dec_param->ref_pic_list_b0[i] = 0; - for (i = 0; i < ARRAY_SIZE(dec_param->ref_pic_list_b1); ++i) - if (dec_param->ref_pic_list_b1[i] - >= ARRAY_SIZE(ctx->run.h264d.dpb_map)) - dec_param->ref_pic_list_b1[i] = 0; - for (i = 0; i < ARRAY_SIZE(dec_param->ref_pic_list_p0); ++i) - if (dec_param->ref_pic_list_p0[i] - >= ARRAY_SIZE(ctx->run.h264d.dpb_map)) - dec_param->ref_pic_list_p0[i] = 0; -} - -static int rk3288_vpu_dec_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct rk3288_vpu_ctx *ctx = ctrl_to_ctx(ctrl); - struct rk3288_vpu_dev *dev = ctx->dev; - int ret = 0; - - vpu_debug_enter(); - - vpu_debug(4, "ctrl id %d\n", ctrl->id); - - switch (ctrl->id) { - case V4L2_CID_MPEG_VIDEO_H264_SPS: - case V4L2_CID_MPEG_VIDEO_H264_PPS: - case V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX: - case V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAM: - case V4L2_CID_MPEG_VIDEO_VP8_FRAME_HDR: - /* These controls are used directly. */ - break; - - case V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAM: - if (ctrl->store) - break; - rk3288_vpu_dec_set_dpb(ctx, ctrl); - break; - - default: - v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n", - ctrl->id, ctrl->val); - ret = -EINVAL; - } - - vpu_debug_leave(); - - return ret; -} - -static const struct v4l2_ctrl_ops rk3288_vpu_dec_ctrl_ops = { - .s_ctrl = rk3288_vpu_dec_s_ctrl, -}; - -static const struct v4l2_ioctl_ops rk3288_vpu_dec_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_framesizes = vidioc_enum_framesizes, - .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane, - .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane, - .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt, - .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt, - .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt, - .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt, - .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt, - .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_expbuf = vidioc_expbuf, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, -}; - -static int rk3288_vpu_queue_setup(struct vb2_queue *vq, - const struct v4l2_format *fmt, - unsigned int *buf_count, - unsigned int *plane_count, - unsigned int psize[], void *allocators[]) -{ - struct rk3288_vpu_ctx *ctx = fh_to_ctx(vq->drv_priv); - int ret = 0; - - vpu_debug_enter(); - - switch (vq->type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - *plane_count = ctx->vpu_src_fmt->num_planes; - - if (*buf_count < 1) - *buf_count = 1; - - if (*buf_count > VIDEO_MAX_FRAME) - *buf_count = VIDEO_MAX_FRAME; - - psize[0] = ctx->src_fmt.plane_fmt[0].sizeimage; - allocators[0] = ctx->dev->alloc_ctx; - vpu_debug(0, "output psize[%d]: %d\n", 0, psize[0]); - break; - - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - *plane_count = ctx->vpu_dst_fmt->num_planes; - - if (*buf_count < 1) - *buf_count = 1; - - if (*buf_count > VIDEO_MAX_FRAME) - *buf_count = VIDEO_MAX_FRAME; - - psize[0] = round_up(ctx->dst_fmt.plane_fmt[0].sizeimage, 8); - allocators[0] = ctx->dev->alloc_ctx; - - if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_H264_SLICE) - /* Add space for appended motion vectors. */ - psize[0] += 64 * MB_WIDTH(ctx->dst_fmt.width) - * MB_HEIGHT(ctx->dst_fmt.height); - - vpu_debug(0, "capture psize[%d]: %d\n", 0, psize[0]); - break; - - default: - vpu_err("invalid queue type: %d\n", vq->type); - ret = -EINVAL; - } - - vpu_debug_leave(); - - return ret; -} - -static int rk3288_vpu_buf_init(struct vb2_buffer *vb) -{ - struct vb2_queue *vq = vb->vb2_queue; - struct rk3288_vpu_ctx *ctx = fh_to_ctx(vq->drv_priv); - - vpu_debug_enter(); - - if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - ctx->dst_bufs[vb->v4l2_buf.index] = vb; - - vpu_debug_leave(); - - return 0; -} - -static void rk3288_vpu_buf_cleanup(struct vb2_buffer *vb) -{ - struct vb2_queue *vq = vb->vb2_queue; - struct rk3288_vpu_ctx *ctx = fh_to_ctx(vq->drv_priv); - - vpu_debug_enter(); - - if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - ctx->dst_bufs[vb->v4l2_buf.index] = NULL; - - vpu_debug_leave(); -} - -static int rk3288_vpu_buf_prepare(struct vb2_buffer *vb) -{ - struct vb2_queue *vq = vb->vb2_queue; - struct rk3288_vpu_ctx *ctx = fh_to_ctx(vq->drv_priv); - int ret = 0; - int i; - - vpu_debug_enter(); - - switch (vq->type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - vpu_debug(4, "plane size: %ld, dst size: %d\n", - vb2_plane_size(vb, 0), - ctx->src_fmt.plane_fmt[0].sizeimage); - - if (vb2_plane_size(vb, 0) - < ctx->src_fmt.plane_fmt[0].sizeimage) { - vpu_err("plane size is too small for output\n"); - ret = -EINVAL; - } - break; - - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - for (i = 0; i < ctx->vpu_dst_fmt->num_planes; ++i) { - vpu_debug(4, "plane %d size: %ld, sizeimage: %u\n", i, - vb2_plane_size(vb, i), - ctx->dst_fmt.plane_fmt[i].sizeimage); - - if (vb2_plane_size(vb, i) - < ctx->dst_fmt.plane_fmt[i].sizeimage) { - vpu_err("size of plane %d is too small for capture\n", - i); - break; - } - } - - if (i != ctx->vpu_dst_fmt->num_planes) - ret = -EINVAL; - break; - - default: - vpu_err("invalid queue type: %d\n", vq->type); - ret = -EINVAL; - } - - vpu_debug_leave(); - - return ret; -} - -static int rk3288_vpu_start_streaming(struct vb2_queue *q, unsigned int count) -{ - int ret = 0; - struct rk3288_vpu_ctx *ctx = fh_to_ctx(q->drv_priv); - struct rk3288_vpu_dev *dev = ctx->dev; - bool ready = false; - - vpu_debug_enter(); - - if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - ret = rk3288_vpu_init(ctx); - if (ret < 0) { - vpu_err("rk3288_vpu_init failed\n"); - return ret; - } - - ready = vb2_is_streaming(&ctx->vq_src); - } else if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - ready = vb2_is_streaming(&ctx->vq_dst); - } - - if (ready) - rk3288_vpu_try_context(dev, ctx); - - vpu_debug_leave(); - - return 0; -} - -static void rk3288_vpu_stop_streaming(struct vb2_queue *q) -{ - unsigned long flags; - struct rk3288_vpu_ctx *ctx = fh_to_ctx(q->drv_priv); - struct rk3288_vpu_dev *dev = ctx->dev; - struct rk3288_vpu_buf *b; - LIST_HEAD(queue); - int i; - - vpu_debug_enter(); - - spin_lock_irqsave(&dev->irqlock, flags); - - list_del_init(&ctx->list); - - switch (q->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - list_splice_init(&ctx->dst_queue, &queue); - break; - - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - list_splice_init(&ctx->src_queue, &queue); - break; - - default: - break; - } - - spin_unlock_irqrestore(&dev->irqlock, flags); - - wait_event(dev->run_wq, dev->current_ctx != ctx); - - while (!list_empty(&queue)) { - b = list_first_entry(&queue, struct rk3288_vpu_buf, list); - for (i = 0; i < b->b.num_planes; i++) - vb2_set_plane_payload(&b->b, i, 0); - vb2_buffer_done(&b->b, VB2_BUF_STATE_ERROR); - list_del(&b->list); - } - - if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - rk3288_vpu_deinit(ctx); - - vpu_debug_leave(); -} - -static void rk3288_vpu_buf_queue(struct vb2_buffer *vb) -{ - struct vb2_queue *vq = vb->vb2_queue; - struct rk3288_vpu_ctx *ctx = fh_to_ctx(vq->drv_priv); - struct rk3288_vpu_dev *dev = ctx->dev; - struct rk3288_vpu_buf *vpu_buf; - unsigned long flags; - - vpu_debug_enter(); - - switch (vq->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - vpu_buf = vb_to_buf(vb); - - /* Mark destination as available for use by VPU */ - spin_lock_irqsave(&dev->irqlock, flags); - - list_add_tail(&vpu_buf->list, &ctx->dst_queue); - - spin_unlock_irqrestore(&dev->irqlock, flags); - break; - - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - vpu_buf = vb_to_buf(vb); - - spin_lock_irqsave(&dev->irqlock, flags); - - list_add_tail(&vpu_buf->list, &ctx->src_queue); - - spin_unlock_irqrestore(&dev->irqlock, flags); - break; - - default: - vpu_err("unsupported buffer type (%d)\n", vq->type); - } - - if (vb2_is_streaming(&ctx->vq_src) && vb2_is_streaming(&ctx->vq_dst)) - rk3288_vpu_try_context(dev, ctx); - - vpu_debug_leave(); -} - -static struct vb2_ops rk3288_vpu_dec_qops = { - .queue_setup = rk3288_vpu_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, - .buf_init = rk3288_vpu_buf_init, - .buf_prepare = rk3288_vpu_buf_prepare, - .buf_cleanup = rk3288_vpu_buf_cleanup, - .start_streaming = rk3288_vpu_start_streaming, - .stop_streaming = rk3288_vpu_stop_streaming, - .buf_queue = rk3288_vpu_buf_queue, -}; - -struct vb2_ops *get_dec_queue_ops(void) -{ - return &rk3288_vpu_dec_qops; -} - -const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void) -{ - return &rk3288_vpu_dec_ioctl_ops; -} - -static void rk3288_vpu_dec_prepare_run(struct rk3288_vpu_ctx *ctx) -{ - struct v4l2_buffer *src = &ctx->run.src->b.v4l2_buf; - - v4l2_ctrl_apply_store(&ctx->ctrl_handler, src->config_store); - - if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_H264_SLICE) { - ctx->run.h264d.sps = get_ctrl_ptr(ctx, - RK3288_VPU_DEC_CTRL_H264_SPS); - ctx->run.h264d.pps = get_ctrl_ptr(ctx, - RK3288_VPU_DEC_CTRL_H264_PPS); - ctx->run.h264d.scaling_matrix = get_ctrl_ptr(ctx, - RK3288_VPU_DEC_CTRL_H264_SCALING_MATRIX); - ctx->run.h264d.slice_param = get_ctrl_ptr(ctx, - RK3288_VPU_DEC_CTRL_H264_SLICE_PARAM); - ctx->run.h264d.decode_param = get_ctrl_ptr(ctx, - RK3288_VPU_DEC_CTRL_H264_DECODE_PARAM); - } else if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_VP8_FRAME) { - ctx->run.vp8d.frame_hdr = get_ctrl_ptr(ctx, - RK3288_VPU_DEC_CTRL_VP8_FRAME_HDR); - } -} - -static void rk3288_vpu_dec_run_done(struct rk3288_vpu_ctx *ctx, - enum vb2_buffer_state result) -{ - struct v4l2_plane_pix_format *plane_fmts = ctx->dst_fmt.plane_fmt; - struct vb2_buffer *dst = &ctx->run.dst->b; - int i; - - if (result != VB2_BUF_STATE_DONE) { - /* Assume no payload after failed run. */ - for (i = 0; i < dst->num_planes; ++i) - vb2_set_plane_payload(dst, i, 0); - return; - } - - for (i = 0; i < dst->num_planes; ++i) - vb2_set_plane_payload(dst, i, plane_fmts[i].sizeimage); -} - -static const struct rk3288_vpu_run_ops rk3288_vpu_dec_run_ops = { - .prepare_run = rk3288_vpu_dec_prepare_run, - .run_done = rk3288_vpu_dec_run_done, -}; - -int rk3288_vpu_dec_init(struct rk3288_vpu_ctx *ctx) -{ - ctx->vpu_src_fmt = find_format(DEF_SRC_FMT_DEC, false); - ctx->vpu_dst_fmt = find_format(DEF_DST_FMT_DEC, true); - - ctx->run_ops = &rk3288_vpu_dec_run_ops; - - return rk3288_vpu_ctrls_setup(ctx, &rk3288_vpu_dec_ctrl_ops, - controls, ARRAY_SIZE(controls), NULL); -} - -void rk3288_vpu_dec_exit(struct rk3288_vpu_ctx *ctx) -{ - rk3288_vpu_ctrls_delete(ctx); -} diff --git a/drivers/media/platform/rk3288-vpu/rk3288_vpu_dec.h b/drivers/media/platform/rk3288-vpu/rk3288_vpu_dec.h deleted file mode 100644 index ac2598751083..000000000000 --- a/drivers/media/platform/rk3288-vpu/rk3288_vpu_dec.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Rockchip RK3288 VPU codec driver - * - * Copyright (C) 2014 Rockchip Electronics Co., Ltd. - * Hertz Wong - * - * Copyright (C) 2014 Google, Inc. - * Tomasz Figa - * - * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. - * - * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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 RK3288_VPU_DEC_H_ -#define RK3288_VPU_DEC_H_ - -struct vb2_ops *get_dec_queue_ops(void); -const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void); -struct rk3288_vpu_fmt *get_dec_def_fmt(bool src); -int rk3288_vpu_dec_init(struct rk3288_vpu_ctx *ctx); -void rk3288_vpu_dec_exit(struct rk3288_vpu_ctx *ctx); - -#endif /* RK3288_VPU_DEC_H_ */ diff --git a/drivers/media/platform/rk3288-vpu/rk3288_vpu_enc.c b/drivers/media/platform/rk3288-vpu/rk3288_vpu_enc.c deleted file mode 100644 index 54b54ae6726d..000000000000 --- a/drivers/media/platform/rk3288-vpu/rk3288_vpu_enc.c +++ /dev/null @@ -1,1503 +0,0 @@ -/* - * Rockchip RK3288 VPU codec driver - * - * Copyright (C) 2014 Rockchip Electronics Co., Ltd. - * Alpha Lin - * Jeffy Chen - * - * Copyright (C) 2014 Google, Inc. - * Tomasz Figa - * - * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. - * - * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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 "rk3288_vpu_common.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rk3288_vpu_enc.h" -#include "rk3288_vpu_hw.h" - -#define DEF_SRC_FMT_ENC V4L2_PIX_FMT_NV12 -#define DEF_DST_FMT_ENC V4L2_PIX_FMT_VP8 - -#define RK3288_ENC_MIN_WIDTH 96U -#define RK3288_ENC_MAX_WIDTH 1920U -#define RK3288_ENC_MIN_HEIGHT 96U -#define RK3288_ENC_MAX_HEIGHT 1088U - -#define V4L2_CID_PRIVATE_RK3288_HEADER (V4L2_CID_CUSTOM_BASE + 0) -#define V4L2_CID_PRIVATE_RK3288_REG_PARAMS (V4L2_CID_CUSTOM_BASE + 1) -#define V4L2_CID_PRIVATE_RK3288_HW_PARAMS (V4L2_CID_CUSTOM_BASE + 2) -#define V4L2_CID_PRIVATE_RK3288_RET_PARAMS (V4L2_CID_CUSTOM_BASE + 3) - -static struct rk3288_vpu_fmt formats[] = { - /* Source formats. */ - { - .name = "4:2:0 3 planes Y/Cb/Cr", - .fourcc = V4L2_PIX_FMT_YUV420M, - .codec_mode = RK_VPU_CODEC_NONE, - .num_planes = 3, - .depth = { 8, 4, 4 }, - .enc_fmt = RK3288_VPU_ENC_FMT_YUV420P, - }, - { - .name = "4:2:0 2 plane Y/CbCr", - .fourcc = V4L2_PIX_FMT_NV12M, - .codec_mode = RK_VPU_CODEC_NONE, - .num_planes = 2, - .depth = { 8, 8 }, - .enc_fmt = RK3288_VPU_ENC_FMT_YUV420SP, - }, - { - .name = "4:2:2 1 plane YUYV", - .fourcc = V4L2_PIX_FMT_YUYV, - .codec_mode = RK_VPU_CODEC_NONE, - .num_planes = 1, - .depth = { 16 }, - .enc_fmt = RK3288_VPU_ENC_FMT_YUYV422, - }, - { - .name = "4:2:2 1 plane UYVY", - .fourcc = V4L2_PIX_FMT_UYVY, - .codec_mode = RK_VPU_CODEC_NONE, - .num_planes = 1, - .depth = { 16 }, - .enc_fmt = RK3288_VPU_ENC_FMT_UYVY422, - }, - /* Destination formats. */ - { - .name = "VP8 Encoded Stream", - .fourcc = V4L2_PIX_FMT_VP8, - .codec_mode = RK_VPU_CODEC_VP8E, - .num_planes = 1, - }, -}; - -static struct rk3288_vpu_fmt *find_format(u32 fourcc, bool bitstream) -{ - unsigned int i; - - vpu_debug_enter(); - - for (i = 0; i < ARRAY_SIZE(formats); i++) { - if (formats[i].fourcc != fourcc) - continue; - if (bitstream && formats[i].codec_mode != RK_VPU_CODEC_NONE) - return &formats[i]; - if (!bitstream && formats[i].codec_mode == RK_VPU_CODEC_NONE) - return &formats[i]; - } - - return NULL; -} - -/* - * Indices of controls that need to be accessed directly, i.e. through - * p_cur.p pointer of their v4l2_ctrl structs. - */ -enum { - RK3288_VPU_ENC_CTRL_HEADER, - RK3288_VPU_ENC_CTRL_REG_PARAMS, - RK3288_VPU_ENC_CTRL_HW_PARAMS, - RK3288_VPU_ENC_CTRL_RET_PARAMS, -}; - -static struct rk3288_vpu_control controls[] = { - /* Private, per-frame controls. */ - [RK3288_VPU_ENC_CTRL_HEADER] = { - .id = V4L2_CID_PRIVATE_RK3288_HEADER, - .type = V4L2_CTRL_TYPE_PRIVATE, - .name = "Rk3288 Private Header", - .elem_size = RK3288_HEADER_SIZE, - .max_stores = VIDEO_MAX_FRAME, - .can_store = true, - }, - [RK3288_VPU_ENC_CTRL_REG_PARAMS] = { - .id = V4L2_CID_PRIVATE_RK3288_REG_PARAMS, - .type = V4L2_CTRL_TYPE_PRIVATE, - .name = "Rk3288 Private Reg Params", - .elem_size = sizeof(struct rk3288_vp8e_reg_params), - .max_stores = VIDEO_MAX_FRAME, - .can_store = true, - }, - [RK3288_VPU_ENC_CTRL_HW_PARAMS] = { - .id = V4L2_CID_PRIVATE_RK3288_HW_PARAMS, - .type = V4L2_CTRL_TYPE_PRIVATE, - .name = "Rk3288 Private Hw Params", - .elem_size = RK3288_HW_PARAMS_SIZE, - .max_stores = VIDEO_MAX_FRAME, - .can_store = true, - }, - [RK3288_VPU_ENC_CTRL_RET_PARAMS] = { - .id = V4L2_CID_PRIVATE_RK3288_RET_PARAMS, - .type = V4L2_CTRL_TYPE_PRIVATE, - .name = "Rk3288 Private Ret Params", - .is_volatile = true, - .is_read_only = true, - .max_stores = VIDEO_MAX_FRAME, - .elem_size = RK3288_RET_PARAMS_SIZE, - }, - /* Generic controls. (currently ignored) */ - { - .id = V4L2_CID_MPEG_VIDEO_GOP_SIZE, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 1, - .maximum = 150, - .step = 1, - .default_value = 30, - }, - { - .id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_BITRATE, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 10000, - .maximum = 288000000, - .step = 1, - .default_value = 2097152, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, - .type = V4L2_CTRL_TYPE_MENU, - .minimum = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, - .maximum = V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH, - .default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, - .menu_skip_mask = ~( - (1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | - (1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | - (1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) - ), - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL, - .type = V4L2_CTRL_TYPE_MENU, - .minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, - .maximum = V4L2_MPEG_VIDEO_H264_LEVEL_4_1, - .default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 51, - .step = 1, - .default_value = 30, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 51, - .step = 1, - .default_value = 18, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 288000, - .step = 1, - .default_value = 30000, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, - .type = V4L2_CTRL_TYPE_BUTTON, - }, - /* - * This hardware does not support features provided by controls - * below, but they are required for compatibility with certain - * userspace software. - */ - { - .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Rate Control Reaction Coeff.", - .minimum = 1, - .maximum = (1 << 16) - 1, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEADER_MODE, - .type = V4L2_CTRL_TYPE_MENU, - .minimum = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, - .maximum = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, - .default_value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, - .menu_skip_mask = 0, - }, - { - .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Fixed Target Bit Enable", - .minimum = 0, - .maximum = 1, - .default_value = 0, - .step = 1, - .menu_skip_mask = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_B_FRAMES, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 2, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 51, - .step = 1, - .default_value = 1, - }, -}; - -static inline const void *get_ctrl_ptr(struct rk3288_vpu_ctx *ctx, unsigned id) -{ - struct v4l2_ctrl *ctrl = ctx->ctrls[id]; - - return ctrl->p_cur.p; -} - -static const char *const *rk3288_vpu_enc_get_menu(u32 id) -{ - static const char *const vpu_video_frame_skip[] = { - "Disabled", - "Level Limit", - "VBV/CPB Limit", - NULL, - }; - - switch (id) { - case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE: - return vpu_video_frame_skip; - } - - return NULL; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct rk3288_vpu_dev *dev = video_drvdata(file); - - vpu_debug_enter(); - - strlcpy(cap->driver, RK3288_VPU_ENC_NAME, sizeof(cap->driver)); - strlcpy(cap->card, dev->pdev->name, sizeof(cap->card)); - strlcpy(cap->bus_info, "platform:" RK3288_VPU_NAME, - sizeof(cap->bus_info)); - - /* - * This is only a mem-to-mem video device. The capture and output - * device capability flags are left only for backward compatibility - * and are scheduled for removal. - */ - cap->capabilities = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING | - V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE; - - vpu_debug_leave(); - - return 0; -} - -static int vidioc_enum_framesizes(struct file *file, void *prov, - struct v4l2_frmsizeenum *fsize) -{ - struct v4l2_frmsize_stepwise *s = &fsize->stepwise; - struct rk3288_vpu_fmt *fmt; - - if (fsize->index != 0) { - vpu_debug(0, "invalid frame size index (expected 0, got %d)\n", - fsize->index); - return -EINVAL; - } - - fmt = find_format(fsize->pixel_format, true); - if (!fmt) { - vpu_debug(0, "unsupported bitstream format (%08x)\n", - fsize->pixel_format); - return -EINVAL; - } - - fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; - - s->min_width = RK3288_ENC_MIN_WIDTH; - s->max_width = RK3288_ENC_MAX_WIDTH; - s->step_width = MB_DIM; - s->min_height = RK3288_ENC_MIN_HEIGHT; - s->max_height = RK3288_ENC_MAX_HEIGHT; - s->step_height = MB_DIM; - - return 0; -} - -static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool out) -{ - struct rk3288_vpu_fmt *fmt; - int i, j = 0; - - vpu_debug_enter(); - - for (i = 0; i < ARRAY_SIZE(formats); ++i) { - if (out && formats[i].codec_mode != RK_VPU_CODEC_NONE) - continue; - else if (!out && formats[i].codec_mode == RK_VPU_CODEC_NONE) - continue; - - if (j == f->index) { - fmt = &formats[i]; - strlcpy(f->description, fmt->name, - sizeof(f->description)); - f->pixelformat = fmt->fourcc; - - f->flags = 0; - if (formats[i].codec_mode != RK_VPU_CODEC_NONE) - f->flags |= V4L2_FMT_FLAG_COMPRESSED; - - vpu_debug_leave(); - - return 0; - } - - ++j; - } - - vpu_debug_leave(); - - return -EINVAL; -} - -static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - return vidioc_enum_fmt(f, false); -} - -static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - return vidioc_enum_fmt(f, true); -} - -static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) -{ - struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); - - vpu_debug_enter(); - - vpu_debug(4, "f->type = %d\n", f->type); - - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - f->fmt.pix_mp = ctx->dst_fmt; - break; - - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - f->fmt.pix_mp = ctx->src_fmt; - break; - - default: - vpu_err("invalid buf type\n"); - return -EINVAL; - } - - vpu_debug_leave(); - - return 0; -} - -static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) -{ - struct rk3288_vpu_fmt *fmt; - struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; - char str[5]; - - vpu_debug_enter(); - - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - vpu_debug(4, "%s\n", fmt2str(f->fmt.pix_mp.pixelformat, str)); - - fmt = find_format(pix_fmt_mp->pixelformat, true); - if (!fmt) { - vpu_err("failed to try capture format\n"); - return -EINVAL; - } - - if (pix_fmt_mp->plane_fmt[0].sizeimage == 0) { - vpu_err("must be set encoding output size\n"); - return -EINVAL; - } - - pix_fmt_mp->plane_fmt[0].bytesperline = 0; - break; - - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - vpu_debug(4, "%s\n", fmt2str(f->fmt.pix_mp.pixelformat, str)); - - fmt = find_format(pix_fmt_mp->pixelformat, false); - if (!fmt) { - vpu_err("failed to try output format\n"); - return -EINVAL; - } - - if (fmt->num_planes != pix_fmt_mp->num_planes) { - vpu_err("plane number mismatches on output format\n"); - return -EINVAL; - } - - /* Limit to hardware min/max. */ - pix_fmt_mp->width = clamp(pix_fmt_mp->width, - RK3288_ENC_MIN_WIDTH, RK3288_ENC_MAX_WIDTH); - pix_fmt_mp->height = clamp(pix_fmt_mp->height, - RK3288_ENC_MIN_HEIGHT, RK3288_ENC_MAX_HEIGHT); - /* Round up to macroblocks. */ - pix_fmt_mp->width = round_up(pix_fmt_mp->width, MB_DIM); - pix_fmt_mp->height = round_up(pix_fmt_mp->height, MB_DIM); - break; - - default: - vpu_err("invalid buf type\n"); - return -EINVAL; - } - - vpu_debug_leave(); - - return 0; -} - -static void calculate_plane_sizes(struct rk3288_vpu_fmt *fmt, - unsigned int w, unsigned int h, - struct v4l2_pix_format_mplane *pix_fmt_mp) -{ - int i; - - for (i = 0; i < fmt->num_planes; ++i) { - pix_fmt_mp->plane_fmt[i].bytesperline = w * fmt->depth[i] / 8; - pix_fmt_mp->plane_fmt[i].sizeimage = h * - pix_fmt_mp->plane_fmt[i].bytesperline; - /* - * All of multiplanar formats we support have chroma - * planes subsampled by 2 vertically. - */ - if (i != 0) - pix_fmt_mp->plane_fmt[i].sizeimage /= 2; - } -} - -static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; - struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); - unsigned int mb_width, mb_height; - struct rk3288_vpu_fmt *fmt; - int ret = 0; - - vpu_debug_enter(); - - /* Change not allowed if any queue is streaming. */ - if (vb2_is_streaming(&ctx->vq_src) || vb2_is_streaming(&ctx->vq_dst)) { - ret = -EBUSY; - goto out; - } - - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - /* - * Pixel format change is not allowed when the other queue has - * buffers allocated. - */ - if (vb2_is_busy(&ctx->vq_src) - && pix_fmt_mp->pixelformat != ctx->dst_fmt.pixelformat) { - ret = -EBUSY; - goto out; - } - - ret = vidioc_try_fmt(file, priv, f); - if (ret) - goto out; - - ctx->vpu_dst_fmt = find_format(pix_fmt_mp->pixelformat, true); - ctx->dst_fmt = *pix_fmt_mp; - break; - - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - /* - * Pixel format change is not allowed when the other queue has - * buffers allocated. - */ - if (vb2_is_busy(&ctx->vq_dst) - && pix_fmt_mp->pixelformat != ctx->src_fmt.pixelformat) { - ret = -EBUSY; - goto out; - } - - ret = vidioc_try_fmt(file, priv, f); - if (ret) - goto out; - - fmt = find_format(pix_fmt_mp->pixelformat, false); - ctx->vpu_src_fmt = fmt; - - mb_width = MB_WIDTH(pix_fmt_mp->width); - mb_height = MB_HEIGHT(pix_fmt_mp->height); - - vpu_debug(0, "OUTPUT codec mode: %d\n", fmt->codec_mode); - vpu_debug(0, "fmt - w: %d, h: %d, mb - w: %d, h: %d\n", - pix_fmt_mp->width, pix_fmt_mp->height, - mb_width, mb_height); - - calculate_plane_sizes(fmt, mb_width * MB_DIM, - mb_height * MB_DIM, pix_fmt_mp); - - /* Reset crop rectangle. */ - ctx->src_crop.width = pix_fmt_mp->width; - ctx->src_crop.height = pix_fmt_mp->height; - - ctx->src_fmt = *pix_fmt_mp; - break; - - default: - vpu_err("invalid buf type\n"); - return -EINVAL; - } - -out: - vpu_debug_leave(); - - return ret; -} - -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *reqbufs) -{ - struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); - int ret; - - vpu_debug_enter(); - - switch (reqbufs->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - vpu_debug(4, "\n"); - - ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); - if (ret != 0) { - vpu_err("error in vb2_reqbufs() for E(D)\n"); - goto out; - } - break; - - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - vpu_debug(4, "memory type %d\n", reqbufs->memory); - - ret = vb2_reqbufs(&ctx->vq_src, reqbufs); - if (ret != 0) { - vpu_err("error in vb2_reqbufs() for E(S)\n"); - goto out; - } - break; - - default: - vpu_err("invalid buf type\n"); - ret = -EINVAL; - goto out; - } - -out: - vpu_debug_leave(); - - return ret; -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); - int ret; - - vpu_debug_enter(); - - switch (buf->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - ret = vb2_querybuf(&ctx->vq_dst, buf); - if (ret != 0) { - vpu_err("error in vb2_querybuf() for E(D)\n"); - goto out; - } - - buf->m.planes[0].m.mem_offset += DST_QUEUE_OFF_BASE; - break; - - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - ret = vb2_querybuf(&ctx->vq_src, buf); - if (ret != 0) { - vpu_err("error in vb2_querybuf() for E(S)\n"); - goto out; - } - break; - - default: - vpu_err("invalid buf type\n"); - ret = -EINVAL; - goto out; - } - -out: - vpu_debug_leave(); - - return ret; -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); - int ret; - int i; - - vpu_debug_enter(); - - for (i = 0; i < buf->length; i++) { - vpu_debug(4, "plane[%d]->length %d bytesused %d\n", - i, buf->m.planes[i].length, - buf->m.planes[i].bytesused); - } - - switch (buf->type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - ret = vb2_qbuf(&ctx->vq_src, buf); - vpu_debug(4, "vb2_qbuf return %d\n", ret); - break; - - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - ret = vb2_qbuf(&ctx->vq_dst, buf); - vpu_debug(4, "vb2_qbuf return %d\n", ret); - break; - - default: - ret = -EINVAL; - } - - vpu_debug_leave(); - - return ret; -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); - int ret; - - vpu_debug_enter(); - - switch (buf->type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - ret = vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK); - break; - - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - ret = vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK); - break; - - default: - ret = -EINVAL; - } - - vpu_debug_leave(); - - return ret; -} - -static int vidioc_expbuf(struct file *file, void *priv, - struct v4l2_exportbuffer *eb) -{ - struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); - int ret; - - vpu_debug_enter(); - - switch (eb->type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - ret = vb2_expbuf(&ctx->vq_src, eb); - break; - - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - ret = vb2_expbuf(&ctx->vq_dst, eb); - break; - - default: - ret = -EINVAL; - } - - vpu_debug_leave(); - - return ret; -} - -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); - int ret; - - vpu_debug_enter(); - - switch (type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - ret = vb2_streamon(&ctx->vq_src, type); - break; - - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - ret = vb2_streamon(&ctx->vq_dst, type); - break; - - default: - ret = -EINVAL; - } - - vpu_debug_leave(); - - return ret; -} - -static int vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); - int ret; - - vpu_debug_enter(); - - switch (type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - ret = vb2_streamoff(&ctx->vq_src, type); - break; - - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - ret = vb2_streamoff(&ctx->vq_dst, type); - break; - - default: - ret = -EINVAL; - } - - vpu_debug_leave(); - - return ret; -} - -static int rk3288_vpu_enc_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct rk3288_vpu_ctx *ctx = ctrl_to_ctx(ctrl); - struct rk3288_vpu_dev *dev = ctx->dev; - int ret = 0; - - vpu_debug_enter(); - - vpu_debug(4, "ctrl id %d\n", ctrl->id); - - switch (ctrl->id) { - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - case V4L2_CID_MPEG_VIDEO_BITRATE: - case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: - case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: - case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: - case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: - case V4L2_CID_MPEG_VIDEO_H264_PROFILE: - case V4L2_CID_MPEG_VIDEO_H264_LEVEL: - case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: - case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE: - case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING: - case V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF: - case V4L2_CID_MPEG_VIDEO_HEADER_MODE: - case V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT: - case V4L2_CID_MPEG_VIDEO_B_FRAMES: - case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: - case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: - /* Ignore these controls for now. (FIXME?) */ - break; - - case V4L2_CID_PRIVATE_RK3288_HEADER: - case V4L2_CID_PRIVATE_RK3288_REG_PARAMS: - case V4L2_CID_PRIVATE_RK3288_HW_PARAMS: - /* Nothing to do here. The control is used directly. */ - break; - - default: - v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n", - ctrl->id, ctrl->val); - ret = -EINVAL; - } - - vpu_debug_leave(); - - return ret; -} - -static int rk3288_vpu_enc_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct rk3288_vpu_ctx *ctx = ctrl_to_ctx(ctrl); - struct rk3288_vpu_dev *dev = ctx->dev; - int ret = 0; - - vpu_debug_enter(); - - vpu_debug(4, "ctrl id %d\n", ctrl->id); - - switch (ctrl->id) { - case V4L2_CID_PRIVATE_RK3288_RET_PARAMS: - memcpy(ctrl->p_new.p, ctx->run.priv_dst.cpu, - RK3288_RET_PARAMS_SIZE); - break; - - default: - v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n", - ctrl->id, ctrl->val); - ret = -EINVAL; - } - - vpu_debug_leave(); - - return ret; -} - -static const struct v4l2_ctrl_ops rk3288_vpu_enc_ctrl_ops = { - .s_ctrl = rk3288_vpu_enc_s_ctrl, - .g_volatile_ctrl = rk3288_vpu_enc_g_volatile_ctrl, -}; - -static int vidioc_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *cap) -{ - struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); - struct v4l2_pix_format_mplane *fmt = &ctx->src_fmt; - int ret = 0; - - vpu_debug_enter(); - - /* Crop only supported on source. */ - if (cap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - ret = -EINVAL; - goto out; - } - - cap->bounds.left = 0; - cap->bounds.top = 0; - cap->bounds.width = fmt->width; - cap->bounds.height = fmt->height; - cap->defrect = cap->bounds; - cap->pixelaspect.numerator = 1; - cap->pixelaspect.denominator = 1; - -out: - vpu_debug_leave(); - - return ret; -} - -static int vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop) -{ - struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); - int ret = 0; - - vpu_debug_enter(); - - /* Crop only supported on source. */ - if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - ret = -EINVAL; - goto out; - } - - crop->c = ctx->src_crop; - -out: - vpu_debug_leave(); - - return ret; -} - -static int vidioc_s_crop(struct file *file, void *priv, - const struct v4l2_crop *crop) -{ - struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); - struct v4l2_pix_format_mplane *fmt = &ctx->src_fmt; - const struct v4l2_rect *rect = &crop->c; - int ret = 0; - - vpu_debug_enter(); - - /* Crop only supported on source. */ - if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - ret = -EINVAL; - goto out; - } - - /* Change not allowed if the queue is streaming. */ - if (vb2_is_streaming(&ctx->vq_src)) { - ret = -EBUSY; - goto out; - } - - /* We do not support offsets. */ - if (rect->left != 0 || rect->top != 0) - goto fallback; - - /* We can crop only inside right- or bottom-most macroblocks. */ - if (round_up(rect->width, MB_DIM) != fmt->width - || round_up(rect->height, MB_DIM) != fmt->height) - goto fallback; - - /* We support widths aligned to 4 pixels and arbitrary heights. */ - ctx->src_crop.width = round_up(rect->width, 4); - ctx->src_crop.height = rect->height; - - vpu_debug_leave(); - - return 0; - -fallback: - /* Default to full frame for incorrect settings. */ - ctx->src_crop.width = fmt->width; - ctx->src_crop.height = fmt->height; - -out: - vpu_debug_leave(); - - return ret; -} - -static const struct v4l2_ioctl_ops rk3288_vpu_enc_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_framesizes = vidioc_enum_framesizes, - .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane, - .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane, - .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt, - .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt, - .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt, - .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt, - .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt, - .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_expbuf = vidioc_expbuf, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_cropcap = vidioc_cropcap, - .vidioc_g_crop = vidioc_g_crop, - .vidioc_s_crop = vidioc_s_crop, -}; - -static int rk3288_vpu_queue_setup(struct vb2_queue *vq, - const struct v4l2_format *fmt, - unsigned int *buf_count, - unsigned int *plane_count, - unsigned int psize[], void *allocators[]) -{ - struct rk3288_vpu_ctx *ctx = fh_to_ctx(vq->drv_priv); - int ret = 0; - int i; - - vpu_debug_enter(); - - switch (vq->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - *plane_count = ctx->vpu_dst_fmt->num_planes; - - if (*buf_count < 1) - *buf_count = 1; - - if (*buf_count > VIDEO_MAX_FRAME) - *buf_count = VIDEO_MAX_FRAME; - - psize[0] = ctx->dst_fmt.plane_fmt[0].sizeimage; - /* Kernel mapping necessary for bitstream post processing. */ - allocators[0] = ctx->dev->alloc_ctx_vm; - vpu_debug(0, "capture psize[%d]: %d\n", 0, psize[0]); - break; - - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - *plane_count = ctx->vpu_src_fmt->num_planes; - - if (*buf_count < 1) - *buf_count = 1; - - if (*buf_count > VIDEO_MAX_FRAME) - *buf_count = VIDEO_MAX_FRAME; - - for (i = 0; i < ctx->vpu_src_fmt->num_planes; ++i) { - psize[i] = ctx->src_fmt.plane_fmt[i].sizeimage; - vpu_debug(0, "output psize[%d]: %d\n", i, psize[i]); - allocators[i] = ctx->dev->alloc_ctx; - } - break; - - default: - vpu_err("invalid queue type: %d\n", vq->type); - ret = -EINVAL; - } - - vpu_debug_leave(); - - return ret; -} - -static int rk3288_vpu_buf_prepare(struct vb2_buffer *vb) -{ - struct vb2_queue *vq = vb->vb2_queue; - struct rk3288_vpu_ctx *ctx = fh_to_ctx(vq->drv_priv); - int ret = 0; - int i; - - vpu_debug_enter(); - - switch (vq->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - vpu_debug(4, "plane size: %ld, dst size: %d\n", - vb2_plane_size(vb, 0), - ctx->dst_fmt.plane_fmt[0].sizeimage); - - if (vb2_plane_size(vb, 0) - < ctx->dst_fmt.plane_fmt[0].sizeimage) { - vpu_err("plane size is too small for capture\n"); - ret = -EINVAL; - } - break; - - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - for (i = 0; i < ctx->vpu_src_fmt->num_planes; ++i) { - vpu_debug(4, "plane %d size: %ld, sizeimage: %u\n", i, - vb2_plane_size(vb, i), - ctx->src_fmt.plane_fmt[i].sizeimage); - - if (vb2_plane_size(vb, i) - < ctx->src_fmt.plane_fmt[i].sizeimage) { - vpu_err("size of plane %d is too small for output\n", - i); - break; - } - } - - if (i != ctx->vpu_src_fmt->num_planes) - ret = -EINVAL; - break; - - default: - vpu_err("invalid queue type: %d\n", vq->type); - ret = -EINVAL; - } - - vpu_debug_leave(); - - return ret; -} - -static void rk3288_vpu_buf_finish(struct vb2_buffer *vb) -{ - struct vb2_queue *vq = vb->vb2_queue; - struct rk3288_vpu_ctx *ctx = fh_to_ctx(vq->drv_priv); - - vpu_debug_enter(); - - if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE - && vb->state == VB2_BUF_STATE_DONE - && ctx->vpu_dst_fmt->fourcc == V4L2_PIX_FMT_VP8) { - struct rk3288_vpu_buf *buf; - - buf = vb_to_buf(vb); - rk3288_vpu_vp8e_assemble_bitstream(ctx, buf); - } - - vpu_debug_leave(); -} - -static int rk3288_vpu_start_streaming(struct vb2_queue *q, unsigned int count) -{ - int ret = 0; - struct rk3288_vpu_ctx *ctx = fh_to_ctx(q->drv_priv); - struct rk3288_vpu_dev *dev = ctx->dev; - bool ready = false; - - vpu_debug_enter(); - - if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - ret = rk3288_vpu_init(ctx); - if (ret < 0) { - vpu_err("rk3288_vpu_init failed\n"); - return ret; - } - - ready = vb2_is_streaming(&ctx->vq_src); - } else if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - ready = vb2_is_streaming(&ctx->vq_dst); - } - - if (ready) - rk3288_vpu_try_context(dev, ctx); - - vpu_debug_leave(); - - return 0; -} - -static void rk3288_vpu_stop_streaming(struct vb2_queue *q) -{ - unsigned long flags; - struct rk3288_vpu_ctx *ctx = fh_to_ctx(q->drv_priv); - struct rk3288_vpu_dev *dev = ctx->dev; - struct rk3288_vpu_buf *b; - LIST_HEAD(queue); - int i; - - vpu_debug_enter(); - - spin_lock_irqsave(&dev->irqlock, flags); - - list_del_init(&ctx->list); - - switch (q->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - list_splice_init(&ctx->dst_queue, &queue); - break; - - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - list_splice_init(&ctx->src_queue, &queue); - break; - - default: - break; - } - - spin_unlock_irqrestore(&dev->irqlock, flags); - - wait_event(dev->run_wq, dev->current_ctx != ctx); - - while (!list_empty(&queue)) { - b = list_first_entry(&queue, struct rk3288_vpu_buf, list); - for (i = 0; i < b->b.num_planes; i++) - vb2_set_plane_payload(&b->b, i, 0); - vb2_buffer_done(&b->b, VB2_BUF_STATE_ERROR); - list_del(&b->list); - } - - if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - rk3288_vpu_deinit(ctx); - - vpu_debug_leave(); -} - -static void rk3288_vpu_buf_queue(struct vb2_buffer *vb) -{ - struct vb2_queue *vq = vb->vb2_queue; - struct rk3288_vpu_ctx *ctx = fh_to_ctx(vq->drv_priv); - struct rk3288_vpu_dev *dev = ctx->dev; - struct rk3288_vpu_buf *vpu_buf; - unsigned long flags; - - vpu_debug_enter(); - - switch (vq->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - vpu_buf = vb_to_buf(vb); - - /* Mark destination as available for use by VPU */ - spin_lock_irqsave(&dev->irqlock, flags); - - list_add_tail(&vpu_buf->list, &ctx->dst_queue); - - spin_unlock_irqrestore(&dev->irqlock, flags); - break; - - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - vpu_buf = vb_to_buf(vb); - - spin_lock_irqsave(&dev->irqlock, flags); - - list_add_tail(&vpu_buf->list, &ctx->src_queue); - - spin_unlock_irqrestore(&dev->irqlock, flags); - break; - - default: - vpu_err("unsupported buffer type (%d)\n", vq->type); - } - - if (vb2_is_streaming(&ctx->vq_src) && vb2_is_streaming(&ctx->vq_dst)) - rk3288_vpu_try_context(dev, ctx); - - vpu_debug_leave(); -} - -static struct vb2_ops rk3288_vpu_enc_qops = { - .queue_setup = rk3288_vpu_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, - .buf_prepare = rk3288_vpu_buf_prepare, - .buf_finish = rk3288_vpu_buf_finish, - .start_streaming = rk3288_vpu_start_streaming, - .stop_streaming = rk3288_vpu_stop_streaming, - .buf_queue = rk3288_vpu_buf_queue, -}; - -struct vb2_ops *get_enc_queue_ops(void) -{ - return &rk3288_vpu_enc_qops; -} - -const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void) -{ - return &rk3288_vpu_enc_ioctl_ops; -} - -static void rk3288_vpu_enc_prepare_run(struct rk3288_vpu_ctx *ctx) -{ - struct vb2_buffer *vb2_src = &ctx->run.src->b; - unsigned config_store = vb2_src->v4l2_buf.config_store; - - v4l2_ctrl_apply_store(&ctx->ctrl_handler, config_store); - - memcpy(ctx->run.dst->vp8e.header, - get_ctrl_ptr(ctx, RK3288_VPU_ENC_CTRL_HEADER), - RK3288_HEADER_SIZE); - ctx->run.vp8e.reg_params = get_ctrl_ptr(ctx, - RK3288_VPU_ENC_CTRL_REG_PARAMS); - memcpy(ctx->run.priv_src.cpu, - get_ctrl_ptr(ctx, RK3288_VPU_ENC_CTRL_HW_PARAMS), - RK3288_HW_PARAMS_SIZE); -} - -static const struct rk3288_vpu_run_ops rk3288_vpu_enc_run_ops = { - .prepare_run = rk3288_vpu_enc_prepare_run, -}; - -int rk3288_vpu_enc_init(struct rk3288_vpu_ctx *ctx) -{ - struct rk3288_vpu_dev *vpu = ctx->dev; - int ret; - - ctx->vpu_src_fmt = find_format(DEF_SRC_FMT_ENC, false); - ctx->vpu_dst_fmt = find_format(DEF_DST_FMT_ENC, true); - - ret = rk3288_vpu_aux_buf_alloc(vpu, &ctx->run.priv_src, - RK3288_HW_PARAMS_SIZE); - if (ret) { - vpu_err("Failed to allocate private source buffer.\n"); - return ret; - } - - - ret = rk3288_vpu_aux_buf_alloc(vpu, &ctx->run.priv_dst, - RK3288_RET_PARAMS_SIZE); - if (ret) { - vpu_err("Failed to allocate private destination buffer.\n"); - goto err_priv_src; - } - - ret = rk3288_vpu_ctrls_setup(ctx, &rk3288_vpu_enc_ctrl_ops, - controls, ARRAY_SIZE(controls), - rk3288_vpu_enc_get_menu); - if (ret) { - vpu_err("Failed to set up controls\n"); - goto err_priv_dst; - } - - ctx->run_ops = &rk3288_vpu_enc_run_ops; - - return 0; - -err_priv_dst: - rk3288_vpu_aux_buf_free(vpu, &ctx->run.priv_dst); -err_priv_src: - rk3288_vpu_aux_buf_free(vpu, &ctx->run.priv_src); - - return ret; -} - -void rk3288_vpu_enc_exit(struct rk3288_vpu_ctx *ctx) -{ - struct rk3288_vpu_dev *vpu = ctx->dev; - - rk3288_vpu_ctrls_delete(ctx); - - rk3288_vpu_aux_buf_free(vpu, &ctx->run.priv_dst); - rk3288_vpu_aux_buf_free(vpu, &ctx->run.priv_src); -}; - -/* - * WAR for encoder state corruption after decoding - */ - -static const struct rk3288_vpu_run_ops dummy_encode_run_ops = { - /* No ops needed for dummy encoding. */ -}; - -#define DUMMY_W 64 -#define DUMMY_H 64 -#define DUMMY_SRC_FMT V4L2_PIX_FMT_YUYV -#define DUMMY_DST_FMT V4L2_PIX_FMT_VP8 -#define DUMMY_DST_SIZE (32 * 1024) - -int rk3288_vpu_enc_init_dummy_ctx(struct rk3288_vpu_dev *dev) -{ - struct rk3288_vpu_ctx *ctx; - int ret; - int i; - - ctx = devm_kzalloc(dev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - ctx->dev = dev; - - ctx->vpu_src_fmt = find_format(DUMMY_SRC_FMT, false); - ctx->src_fmt.width = DUMMY_W; - ctx->src_fmt.height = DUMMY_H; - ctx->src_fmt.pixelformat = ctx->vpu_src_fmt->fourcc; - ctx->src_fmt.num_planes = ctx->vpu_src_fmt->num_planes; - - calculate_plane_sizes(ctx->vpu_src_fmt, ctx->src_fmt.width, - ctx->src_fmt.height, &ctx->src_fmt); - - ctx->vpu_dst_fmt = find_format(DUMMY_DST_FMT, true); - ctx->dst_fmt.width = ctx->src_fmt.width; - ctx->dst_fmt.height = ctx->src_fmt.height; - ctx->dst_fmt.pixelformat = ctx->vpu_dst_fmt->fourcc; - ctx->dst_fmt.plane_fmt[0].sizeimage = DUMMY_DST_SIZE; - ctx->dst_fmt.plane_fmt[0].bytesperline = 0; - ctx->dst_fmt.num_planes = 1; - - INIT_LIST_HEAD(&ctx->src_queue); - - ctx->src_crop.left = 0; - ctx->src_crop.top = 0; - ctx->src_crop.width = ctx->src_fmt.width; - ctx->src_crop.left = ctx->src_fmt.height; - - INIT_LIST_HEAD(&ctx->dst_queue); - INIT_LIST_HEAD(&ctx->list); - - ctx->run.vp8e.reg_params = rk3288_vpu_vp8e_get_dummy_params(); - ctx->run_ops = &dummy_encode_run_ops; - - ctx->run.dst = devm_kzalloc(dev->dev, sizeof(*ctx->run.dst), - GFP_KERNEL); - if (!ctx->run.dst) - return -ENOMEM; - - ret = rk3288_vpu_aux_buf_alloc(dev, &ctx->run.priv_src, - RK3288_HW_PARAMS_SIZE); - if (ret) - return ret; - - ret = rk3288_vpu_aux_buf_alloc(dev, &ctx->run.priv_dst, - RK3288_RET_PARAMS_SIZE); - if (ret) - goto err_free_priv_src; - - for (i = 0; i < ctx->src_fmt.num_planes; ++i) { - ret = rk3288_vpu_aux_buf_alloc(dev, &dev->dummy_encode_src[i], - ctx->src_fmt.plane_fmt[i].sizeimage); - if (ret) - goto err_free_src; - - memset(dev->dummy_encode_src[i].cpu, 0, - dev->dummy_encode_src[i].size); - } - - ret = rk3288_vpu_aux_buf_alloc(dev, &dev->dummy_encode_dst, - ctx->dst_fmt.plane_fmt[0].sizeimage); - if (ret) - goto err_free_src; - - memset(dev->dummy_encode_dst.cpu, 0, dev->dummy_encode_dst.size); - - ret = rk3288_vpu_init(ctx); - if (ret) - goto err_free_dst; - - dev->dummy_encode_ctx = ctx; - - return 0; - -err_free_dst: - rk3288_vpu_aux_buf_free(dev, &dev->dummy_encode_dst); -err_free_src: - for (i = 0; i < ctx->src_fmt.num_planes; ++i) - if (dev->dummy_encode_src[i].cpu) - rk3288_vpu_aux_buf_free(dev, &dev->dummy_encode_src[i]); - rk3288_vpu_aux_buf_free(dev, &ctx->run.priv_dst); -err_free_priv_src: - rk3288_vpu_aux_buf_free(dev, &ctx->run.priv_src); - - return ret; -} - -void rk3288_vpu_enc_free_dummy_ctx(struct rk3288_vpu_dev *dev) -{ - struct rk3288_vpu_ctx *ctx = dev->dummy_encode_ctx; - int i; - - rk3288_vpu_deinit(ctx); - - for (i = 0; i < ctx->src_fmt.num_planes; ++i) - rk3288_vpu_aux_buf_free(dev, &dev->dummy_encode_src[i]); - rk3288_vpu_aux_buf_free(dev, &dev->dummy_encode_dst); - rk3288_vpu_aux_buf_free(dev, &ctx->run.priv_src); - rk3288_vpu_aux_buf_free(dev, &ctx->run.priv_dst); -} diff --git a/drivers/media/platform/rk3288-vpu/rk3288_vpu_enc.h b/drivers/media/platform/rk3288-vpu/rk3288_vpu_enc.h deleted file mode 100644 index 4b1979d5d2ef..000000000000 --- a/drivers/media/platform/rk3288-vpu/rk3288_vpu_enc.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Rockchip RK3288 VPU codec driver - * - * Copyright (c) 2014 Rockchip Electronics Co., Ltd. - * Alpha Lin - * Jeffy Chen - * - * Copyright (C) 2014 Google, Inc. - * Tomasz Figa - * - * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. - * - * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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 RK3288_VPU_ENC_H_ -#define RK3288_VPU_ENC_H_ - -struct vb2_ops *get_enc_queue_ops(void); -const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void); -struct rk3288_vpu_fmt *get_enc_def_fmt(bool src); -int rk3288_vpu_enc_init(struct rk3288_vpu_ctx *ctx); -void rk3288_vpu_enc_exit(struct rk3288_vpu_ctx *ctx); -int rk3288_vpu_enc_init_dummy_ctx(struct rk3288_vpu_dev *dev); -void rk3288_vpu_enc_free_dummy_ctx(struct rk3288_vpu_dev *dev); - -#endif /* RK3288_VPU_ENC_H_ */ diff --git a/drivers/media/platform/rk3288-vpu/rk3288_vpu_hw.c b/drivers/media/platform/rk3288-vpu/rk3288_vpu_hw.c deleted file mode 100644 index 8ca8b9abd548..000000000000 --- a/drivers/media/platform/rk3288-vpu/rk3288_vpu_hw.c +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Rockchip RK3288 VPU codec driver - * - * Copyright (C) 2014 Google, Inc. - * Tomasz Figa - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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 "rk3288_vpu_common.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "rk3288_vpu_regs.h" - -/** - * struct rk3288_vpu_variant - information about VPU hardware variant - * - * @hw_id: Top 16 bits (product ID) of hardware ID register. - * @enc_offset: Offset from VPU base to encoder registers. - * @enc_reg_num: Number of registers of encoder block. - * @dec_offset: Offset from VPU base to decoder registers. - * @dec_reg_num: Number of registers of decoder block. - */ -struct rk3288_vpu_variant { - u16 hw_id; - unsigned enc_offset; - unsigned enc_reg_num; - unsigned dec_offset; - unsigned dec_reg_num; -}; - -/* Supported VPU variants. */ -static const struct rk3288_vpu_variant rk3288_vpu_variants[] = { - { - .hw_id = 0x4831, - .enc_offset = 0x0, - .enc_reg_num = 164, - .dec_offset = 0x400, - .dec_reg_num = 60 + 41, - }, -}; - -/** - * struct rk3288_vpu_codec_ops - codec mode specific operations - * - * @init: Prepare for streaming. Called from VB2 .start_streaming() - * when streaming from both queues is being enabled. - * @exit: Clean-up after streaming. Called from VB2 .stop_streaming() - * when streaming from first of both enabled queues is being - * disabled. - * @run: Start single {en,de)coding run. Called from non-atomic context - * to indicate that a pair of buffers is ready and the hardware - * should be programmed and started. - * @done: Read back processing results and additional data from hardware. - * @reset: Reset the hardware in case of a timeout. - */ -struct rk3288_vpu_codec_ops { - int (*init)(struct rk3288_vpu_ctx *); - void (*exit)(struct rk3288_vpu_ctx *); - - void (*run)(struct rk3288_vpu_ctx *); - void (*done)(struct rk3288_vpu_ctx *, enum vb2_buffer_state); - void (*reset)(struct rk3288_vpu_ctx *); -}; - -/* - * Hardware control routines. - */ - -static int rk3288_vpu_identify(struct rk3288_vpu_dev *vpu) -{ - u32 hw_id; - int i; - - hw_id = readl(vpu->base) >> 16; - - dev_info(vpu->dev, "Read hardware ID: %x\n", hw_id); - - for (i = 0; i < ARRAY_SIZE(rk3288_vpu_variants); ++i) { - if (hw_id == rk3288_vpu_variants[i].hw_id) { - vpu->variant = &rk3288_vpu_variants[i]; - return 0; - } - } - - return -ENOENT; -} - -void rk3288_vpu_power_on(struct rk3288_vpu_dev *vpu) -{ - vpu_debug_enter(); - - /* TODO: Clock gating. */ - - pm_runtime_get_sync(vpu->dev); - - vpu_debug_leave(); -} - -static void rk3288_vpu_power_off(struct rk3288_vpu_dev *vpu) -{ - vpu_debug_enter(); - - pm_runtime_mark_last_busy(vpu->dev); - pm_runtime_put_autosuspend(vpu->dev); - - /* TODO: Clock gating. */ - - vpu_debug_leave(); -} - -/* - * Interrupt handlers. - */ - -static irqreturn_t vepu_irq(int irq, void *dev_id) -{ - struct rk3288_vpu_dev *vpu = dev_id; - u32 status = vepu_read(vpu, VEPU_REG_INTERRUPT); - - vepu_write(vpu, 0, VEPU_REG_INTERRUPT); - - if (status & VEPU_REG_INTERRUPT_BIT) { - struct rk3288_vpu_ctx *ctx = vpu->current_ctx; - - vepu_write(vpu, 0, VEPU_REG_AXI_CTRL); - rk3288_vpu_power_off(vpu); - cancel_delayed_work(&vpu->watchdog_work); - - ctx->hw.codec_ops->done(ctx, VB2_BUF_STATE_DONE); - } - - return IRQ_HANDLED; -} - -static irqreturn_t vdpu_irq(int irq, void *dev_id) -{ - struct rk3288_vpu_dev *vpu = dev_id; - u32 status = vdpu_read(vpu, VDPU_REG_INTERRUPT); - - vdpu_write(vpu, 0, VDPU_REG_INTERRUPT); - - vpu_debug(3, "vdpu_irq status: %08x\n", status); - - if (status & VDPU_REG_INTERRUPT_DEC_IRQ) { - struct rk3288_vpu_ctx *ctx = vpu->current_ctx; - - vdpu_write(vpu, 0, VDPU_REG_CONFIG); - rk3288_vpu_power_off(vpu); - cancel_delayed_work(&vpu->watchdog_work); - - ctx->hw.codec_ops->done(ctx, VB2_BUF_STATE_DONE); - } - - return IRQ_HANDLED; -} - -static void rk3288_vpu_watchdog(struct work_struct *work) -{ - struct rk3288_vpu_dev *vpu = container_of(to_delayed_work(work), - struct rk3288_vpu_dev, watchdog_work); - struct rk3288_vpu_ctx *ctx = vpu->current_ctx; - unsigned long flags; - - spin_lock_irqsave(&vpu->irqlock, flags); - - ctx->hw.codec_ops->reset(ctx); - - spin_unlock_irqrestore(&vpu->irqlock, flags); - - vpu_err("frame processing timed out!\n"); - - rk3288_vpu_power_off(vpu); - ctx->hw.codec_ops->done(ctx, VB2_BUF_STATE_ERROR); -} - -/* - * Initialization/clean-up. - */ - -#if defined(CONFIG_ROCKCHIP_IOMMU) -static int rk3288_vpu_iommu_init(struct rk3288_vpu_dev *vpu) -{ - int ret; - - vpu->mapping = arm_iommu_create_mapping(&platform_bus_type, - 0x10000000, SZ_2G); - if (IS_ERR(vpu->mapping)) { - ret = PTR_ERR(vpu->mapping); - return ret; - } - - vpu->dev->dma_parms = devm_kzalloc(vpu->dev, - sizeof(*vpu->dev->dma_parms), GFP_KERNEL); - if (!vpu->dev->dma_parms) - goto err_release_mapping; - - dma_set_max_seg_size(vpu->dev, 0xffffffffu); - - ret = arm_iommu_attach_device(vpu->dev, vpu->mapping); - if (ret) - goto err_release_mapping; - - return 0; - -err_release_mapping: - arm_iommu_release_mapping(vpu->mapping); - - return ret; -} - -static void rk3288_vpu_iommu_cleanup(struct rk3288_vpu_dev *vpu) -{ - arm_iommu_detach_device(vpu->dev); - arm_iommu_release_mapping(vpu->mapping); -} -#else -static inline int rk3288_vpu_iommu_init(struct rk3288_vpu_dev *vpu) -{ - return 0; -} - -static inline void rk3288_vpu_iommu_cleanup(struct rk3288_vpu_dev *vpu) { } -#endif - -int rk3288_vpu_hw_probe(struct rk3288_vpu_dev *vpu) -{ - struct resource *res; - int irq_enc, irq_dec; - int ret; - - pr_info("probe device %s\n", dev_name(vpu->dev)); - - INIT_DELAYED_WORK(&vpu->watchdog_work, rk3288_vpu_watchdog); - - vpu->aclk_vcodec = devm_clk_get(vpu->dev, "aclk_vcodec"); - if (IS_ERR(vpu->aclk_vcodec)) { - dev_err(vpu->dev, "failed to get aclk_vcodec\n"); - return PTR_ERR(vpu->aclk_vcodec); - } - - vpu->hclk_vcodec = devm_clk_get(vpu->dev, "hclk_vcodec"); - if (IS_ERR(vpu->hclk_vcodec)) { - dev_err(vpu->dev, "failed to get hclk_vcodec\n"); - return PTR_ERR(vpu->hclk_vcodec); - } - - /* - * Bump ACLK to max. possible freq. (400 MHz) to improve performance. - * - * VP8 encoding 1280x720@1.2Mbps 200 MHz: 39 fps, 400: MHz 77 fps - */ - clk_set_rate(vpu->aclk_vcodec, 400*1000*1000); - - res = platform_get_resource(vpu->pdev, IORESOURCE_MEM, 0); - vpu->base = devm_ioremap_resource(vpu->dev, res); - if (IS_ERR(vpu->base)) - return PTR_ERR(vpu->base); - - clk_prepare_enable(vpu->aclk_vcodec); - clk_prepare_enable(vpu->hclk_vcodec); - - ret = rk3288_vpu_identify(vpu); - if (ret < 0) { - dev_err(vpu->dev, "failed to identify hardware variant\n"); - goto err_power; - } - - 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)); - if (ret) { - dev_err(vpu->dev, "could not set DMA coherent mask\n"); - goto err_power; - } - - ret = rk3288_vpu_iommu_init(vpu); - if (ret) - goto err_power; - - irq_enc = platform_get_irq_byname(vpu->pdev, "vepu"); - if (irq_enc <= 0) { - dev_err(vpu->dev, "could not get vepu IRQ\n"); - ret = -ENXIO; - goto err_iommu; - } - - ret = devm_request_threaded_irq(vpu->dev, irq_enc, NULL, vepu_irq, - IRQF_ONESHOT, dev_name(vpu->dev), vpu); - if (ret) { - dev_err(vpu->dev, "could not request vepu IRQ\n"); - goto err_iommu; - } - - irq_dec = platform_get_irq_byname(vpu->pdev, "vdpu"); - if (irq_dec <= 0) { - dev_err(vpu->dev, "could not get vdpu IRQ\n"); - ret = -ENXIO; - goto err_iommu; - } - - ret = devm_request_threaded_irq(vpu->dev, irq_dec, NULL, vdpu_irq, - IRQF_ONESHOT, dev_name(vpu->dev), vpu); - if (ret) { - dev_err(vpu->dev, "could not request vdpu IRQ\n"); - goto err_iommu; - } - - pm_runtime_set_autosuspend_delay(vpu->dev, 100); - pm_runtime_use_autosuspend(vpu->dev); - pm_runtime_enable(vpu->dev); - - return 0; - -err_iommu: - rk3288_vpu_iommu_cleanup(vpu); -err_power: - clk_disable_unprepare(vpu->hclk_vcodec); - clk_disable_unprepare(vpu->aclk_vcodec); - - return ret; -} - -void rk3288_vpu_hw_remove(struct rk3288_vpu_dev *vpu) -{ - rk3288_vpu_iommu_cleanup(vpu); - - pm_runtime_disable(vpu->dev); - - clk_disable_unprepare(vpu->hclk_vcodec); - clk_disable_unprepare(vpu->aclk_vcodec); -} - -static void rk3288_vpu_enc_reset(struct rk3288_vpu_ctx *ctx) -{ - struct rk3288_vpu_dev *vpu = ctx->dev; - - vepu_write(vpu, VEPU_REG_INTERRUPT_DIS_BIT, VEPU_REG_INTERRUPT); - vepu_write(vpu, 0, VEPU_REG_ENC_CTRL); - vepu_write(vpu, 0, VEPU_REG_AXI_CTRL); -} - -static void rk3288_vpu_dec_reset(struct rk3288_vpu_ctx *ctx) -{ - struct rk3288_vpu_dev *vpu = ctx->dev; - - vdpu_write(vpu, VDPU_REG_INTERRUPT_DEC_IRQ_DIS, VDPU_REG_INTERRUPT); - vdpu_write(vpu, 0, VDPU_REG_CONFIG); -} - -static const struct rk3288_vpu_codec_ops mode_ops[] = { - [RK_VPU_CODEC_VP8E] = { - .init = rk3288_vpu_vp8e_init, - .exit = rk3288_vpu_vp8e_exit, - .run = rk3288_vpu_vp8e_run, - .done = rk3288_vpu_vp8e_done, - .reset = rk3288_vpu_enc_reset, - }, - [RK_VPU_CODEC_VP8D] = { - .init = rk3288_vpu_vp8d_init, - .exit = rk3288_vpu_vp8d_exit, - .run = rk3288_vpu_vp8d_run, - .done = rk3288_vpu_run_done, - .reset = rk3288_vpu_dec_reset, - }, - [RK_VPU_CODEC_H264D] = { - .init = rk3288_vpu_h264d_init, - .exit = rk3288_vpu_h264d_exit, - .run = rk3288_vpu_h264d_run, - .done = rk3288_vpu_run_done, - .reset = rk3288_vpu_dec_reset, - }, -}; - -void rk3288_vpu_run(struct rk3288_vpu_ctx *ctx) -{ - ctx->hw.codec_ops->run(ctx); -} - -int rk3288_vpu_init(struct rk3288_vpu_ctx *ctx) -{ - enum rk3288_vpu_codec_mode codec_mode; - - if (rk3288_vpu_ctx_is_encoder(ctx)) - codec_mode = ctx->vpu_dst_fmt->codec_mode; /* Encoder */ - else - codec_mode = ctx->vpu_src_fmt->codec_mode; /* Decoder */ - - ctx->hw.codec_ops = &mode_ops[codec_mode]; - - return ctx->hw.codec_ops->init(ctx); -} - -void rk3288_vpu_deinit(struct rk3288_vpu_ctx *ctx) -{ - ctx->hw.codec_ops->exit(ctx); -} diff --git a/drivers/media/platform/rk3288-vpu/rk3288_vpu_hw.h b/drivers/media/platform/rk3288-vpu/rk3288_vpu_hw.h deleted file mode 100644 index f8325536295b..000000000000 --- a/drivers/media/platform/rk3288-vpu/rk3288_vpu_hw.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Rockchip RK3288 VPU codec driver - * - * Copyright (C) 2014 Google, Inc. - * Tomasz Figa - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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 RK3288_VPU_HW_H_ -#define RK3288_VPU_HW_H_ - -#include - -#define RK3288_HEADER_SIZE 1280 -#define RK3288_HW_PARAMS_SIZE 5487 -#define RK3288_RET_PARAMS_SIZE 488 - -struct rk3288_vpu_dev; -struct rk3288_vpu_ctx; -struct rk3288_vpu_buf; - -struct rk3288_vpu_h264d_priv_tbl; - -/** - * enum rk3288_vpu_enc_fmt - source format ID for hardware registers. - */ -enum rk3288_vpu_enc_fmt { - RK3288_VPU_ENC_FMT_YUV420P = 0, - RK3288_VPU_ENC_FMT_YUV420SP = 1, - RK3288_VPU_ENC_FMT_YUYV422 = 2, - RK3288_VPU_ENC_FMT_UYVY422 = 3, -}; - -/** - * struct rk3288_vp8e_reg_params - low level encoding parameters - * TODO: Create abstract structures for more generic controls or just - * remove unused fields. - */ -struct rk3288_vp8e_reg_params { - u32 unused_00[5]; - u32 hdr_len; - u32 unused_18[8]; - u32 enc_ctrl; - u32 unused_3c; - u32 enc_ctrl0; - u32 enc_ctrl1; - u32 enc_ctrl2; - u32 enc_ctrl3; - u32 enc_ctrl5; - u32 enc_ctrl4; - u32 str_hdr_rem_msb; - u32 str_hdr_rem_lsb; - u32 unused_60; - u32 mad_ctrl; - u32 unused_68; - u32 qp_val[8]; - u32 bool_enc; - u32 vp8_ctrl0; - u32 rlc_ctrl; - u32 mb_ctrl; - u32 unused_9c[14]; - u32 rgb_yuv_coeff[2]; - u32 rgb_mask_msb; - u32 intra_area_ctrl; - u32 cir_intra_ctrl; - u32 unused_e8[2]; - u32 first_roi_area; - u32 second_roi_area; - u32 mvc_ctrl; - u32 unused_fc; - u32 intra_penalty[7]; - u32 unused_11c; - u32 seg_qp[24]; - u32 dmv_4p_1p_penalty[32]; - u32 dmv_qpel_penalty[32]; - u32 vp8_ctrl1; - u32 bit_cost_golden; - u32 loop_flt_delta[2]; -}; - -/** - * struct rk3288_vpu_aux_buf - auxiliary DMA buffer for hardware data - * @cpu: CPU pointer to the buffer. - * @dma: DMA address of the buffer. - * @size: Size of the buffer. - */ -struct rk3288_vpu_aux_buf { - void *cpu; - dma_addr_t dma; - size_t size; -}; - -/** - * struct rk3288_vpu_vp8e_hw_ctx - Context private data specific to codec mode. - * @ctrl_buf: VP8 control buffer. - * @ext_buf: VP8 ext data buffer. - * @mv_buf: VP8 motion vector buffer. - * @ref_rec_ptr: Bit flag for swapping ref and rec buffers every frame. - */ -struct rk3288_vpu_vp8e_hw_ctx { - struct rk3288_vpu_aux_buf ctrl_buf; - struct rk3288_vpu_aux_buf ext_buf; - struct rk3288_vpu_aux_buf mv_buf; - u8 ref_rec_ptr:1; -}; - -/** - * struct rk3288_vpu_vp8d_hw_ctx - Context private data of VP8 decoder. - * @segment_map: Segment map buffer. - * @prob_tbl: Probability table buffer. - */ -struct rk3288_vpu_vp8d_hw_ctx { - struct rk3288_vpu_aux_buf segment_map; - struct rk3288_vpu_aux_buf prob_tbl; -}; - -/** - * struct rk3288_vpu_h264d_hw_ctx - Per context data specific to H264 decoding. - * @priv_tbl: Private auxiliary buffer for hardware. - */ -struct rk3288_vpu_h264d_hw_ctx { - struct rk3288_vpu_aux_buf priv_tbl; -}; - -/** - * struct rk3288_vpu_hw_ctx - Context private data of hardware code. - * @codec_ops: Set of operations associated with current codec mode. - */ -struct rk3288_vpu_hw_ctx { - const struct rk3288_vpu_codec_ops *codec_ops; - - /* Specific for particular codec modes. */ - union { - struct rk3288_vpu_vp8e_hw_ctx vp8e; - struct rk3288_vpu_vp8d_hw_ctx vp8d; - struct rk3288_vpu_h264d_hw_ctx h264d; - /* Other modes will need different data. */ - }; -}; - -int rk3288_vpu_hw_probe(struct rk3288_vpu_dev *vpu); -void rk3288_vpu_hw_remove(struct rk3288_vpu_dev *vpu); - -int rk3288_vpu_init(struct rk3288_vpu_ctx *ctx); -void rk3288_vpu_deinit(struct rk3288_vpu_ctx *ctx); - -void rk3288_vpu_run(struct rk3288_vpu_ctx *ctx); - -/* Run ops for H264 decoder */ -int rk3288_vpu_h264d_init(struct rk3288_vpu_ctx *ctx); -void rk3288_vpu_h264d_exit(struct rk3288_vpu_ctx *ctx); -void rk3288_vpu_h264d_run(struct rk3288_vpu_ctx *ctx); -void rk3288_vpu_power_on(struct rk3288_vpu_dev *vpu); - -/* Run ops for VP8 decoder */ -int rk3288_vpu_vp8d_init(struct rk3288_vpu_ctx *ctx); -void rk3288_vpu_vp8d_exit(struct rk3288_vpu_ctx *ctx); -void rk3288_vpu_vp8d_run(struct rk3288_vpu_ctx *ctx); - -/* Run ops for VP8 encoder */ -int rk3288_vpu_vp8e_init(struct rk3288_vpu_ctx *ctx); -void rk3288_vpu_vp8e_exit(struct rk3288_vpu_ctx *ctx); -void rk3288_vpu_vp8e_run(struct rk3288_vpu_ctx *ctx); -void rk3288_vpu_vp8e_done(struct rk3288_vpu_ctx *ctx, - enum vb2_buffer_state result); -const struct rk3288_vp8e_reg_params *rk3288_vpu_vp8e_get_dummy_params(void); - -void rk3288_vpu_vp8e_assemble_bitstream(struct rk3288_vpu_ctx *ctx, - struct rk3288_vpu_buf *dst_buf); - -#endif /* RK3288_VPU_HW_H_ */ diff --git a/drivers/media/platform/rk3288-vpu/rk3288_vpu_hw_h264d.c b/drivers/media/platform/rk3288-vpu/rk3288_vpu_hw_h264d.c deleted file mode 100644 index b03491efbf32..000000000000 --- a/drivers/media/platform/rk3288-vpu/rk3288_vpu_hw_h264d.c +++ /dev/null @@ -1,558 +0,0 @@ -/* - * Rockchip RK3288 VPU codec driver - * - * Copyright (c) 2014 Rockchip Electronics Co., Ltd. - * Hertz Wong - * Herman Chen - * - * Copyright (C) 2014 Google, Inc. - * Tomasz Figa - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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 "rk3288_vpu_common.h" - -#include -#include - -#include "rk3288_vpu_hw.h" -#include "rk3288_vpu_regs.h" - -/* Max. number of DPB pictures supported by hardware. */ -#define RK3288_VPU_H264_NUM_DPB 16 - -/* Size with u32 units. */ -#define CABAC_INIT_BUFFER_SIZE (460 * 2) -#define POC_BUFFER_SIZE 34 -#define SCALING_LIST_SIZE ((6 * 16 + 6 * 64) / 4) - -/* Data structure describing auxilliary buffer format. */ -struct rk3288_vpu_h264d_priv_tbl { - u32 cabac_table[CABAC_INIT_BUFFER_SIZE]; - u32 poc[POC_BUFFER_SIZE]; - u32 scaling_list[SCALING_LIST_SIZE]; -}; - -/* Constant CABAC table. */ -static const u32 h264_cabac_table[] = { - 0x14f10236, 0x034a14f1, 0x0236034a, 0xe47fe968, 0xfa35ff36, 0x07330000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x0029003f, 0x003f003f, 0xf7530456, 0x0061f948, 0x0d29033e, 0x000b0137, - 0x0045ef7f, 0xf3660052, 0xf94aeb6b, 0xe57fe17f, 0xe87fee5f, 0xe57feb72, - 0xe27fef7b, 0xf473f07a, 0xf573f43f, 0xfe44f154, 0xf368fd46, 0xf85df65a, - 0xe27fff4a, 0xfa61f95b, 0xec7ffc38, 0xfb52f94c, 0xea7df95d, 0xf557fd4d, - 0xfb47fc3f, 0xfc44f454, 0xf93ef941, 0x083d0538, 0xfe420140, 0x003dfe4e, - 0x01320734, 0x0a23002c, 0x0b26012d, 0x002e052c, 0x1f110133, 0x07321c13, - 0x10210e3e, 0xf36cf164, 0xf365f35b, 0xf45ef658, 0xf054f656, 0xf953f357, - 0xed5e0146, 0x0048fb4a, 0x123bf866, 0xf164005f, 0xfc4b0248, 0xf54bfd47, - 0x0f2ef345, 0x003e0041, 0x1525f148, 0x09391036, 0x003e0c48, 0x18000f09, - 0x08190d12, 0x0f090d13, 0x0a250c12, 0x061d1421, 0x0f1e042d, 0x013a003e, - 0x073d0c26, 0x0b2d0f27, 0x0b2a0d2c, 0x102d0c29, 0x0a311e22, 0x122a0a37, - 0x1133112e, 0x00591aed, 0x16ef1aef, 0x1ee71cec, 0x21e925e5, 0x21e928e4, - 0x26ef21f5, 0x28f129fa, 0x26012911, 0x1efa1b03, 0x1a1625f0, 0x23fc26f8, - 0x26fd2503, 0x26052a00, 0x23102716, 0x0e301b25, 0x153c0c44, 0x0261fd47, - 0xfa2afb32, 0xfd36fe3e, 0x003a013f, 0xfe48ff4a, 0xf75bfb43, 0xfb1bfd27, - 0xfe2c002e, 0xf040f844, 0xf64efa4d, 0xf656f45c, 0xf137f63c, 0xfa3efc41, - 0xf449f84c, 0xf950f758, 0xef6ef561, 0xec54f54f, 0xfa49fc4a, 0xf356f360, - 0xf561ed75, 0xf84efb21, 0xfc30fe35, 0xfd3ef347, 0xf64ff456, 0xf35af261, - 0x0000fa5d, 0xfa54f84f, 0x0042ff47, 0x003efe3c, 0xfe3bfb4b, 0xfd3efc3a, - 0xf742ff4f, 0x00470344, 0x0a2cf93e, 0x0f240e28, 0x101b0c1d, 0x012c1424, - 0x1220052a, 0x01300a3e, 0x112e0940, 0xf468f561, 0xf060f958, 0xf855f955, - 0xf755f358, 0x0442fd4d, 0xfd4cfa4c, 0x0a3aff4c, 0xff53f963, 0xf25f025f, - 0x004cfb4a, 0x0046f54b, 0x01440041, 0xf249033e, 0x043eff44, 0xf34b0b37, - 0x05400c46, 0x0f060613, 0x07100c0e, 0x120d0d0b, 0x0d0f0f10, 0x0c170d17, - 0x0f140e1a, 0x0e2c1128, 0x112f1811, 0x15151916, 0x1f1b161d, 0x13230e32, - 0x0a39073f, 0xfe4dfc52, 0xfd5e0945, 0xf46d24dd, 0x24de20e6, 0x25e22ce0, - 0x22ee22f1, 0x28f121f9, 0x23fb2100, 0x2602210d, 0x17230d3a, 0x1dfd1a00, - 0x161e1ff9, 0x23f122fd, 0x220324ff, 0x2205200b, 0x2305220c, 0x270b1e1d, - 0x221a1d27, 0x13421f15, 0x1f1f1932, 0xef78ec70, 0xee72f555, 0xf15cf259, - 0xe647f151, 0xf2500044, 0xf246e838, 0xe944e832, 0xf54a17f3, 0x1af328f1, - 0x31f22c03, 0x2d062c22, 0x21361352, 0xfd4bff17, 0x0122012b, 0x0036fe37, - 0x003d0140, 0x0044f75c, 0xf26af361, 0xf15af45a, 0xee58f649, 0xf74ff256, - 0xf649f646, 0xf645fb42, 0xf740fb3a, 0x023b15f6, 0x18f51cf8, 0x1cff1d03, - 0x1d092314, 0x1d240e43, 0x14f10236, 0x034a14f1, 0x0236034a, 0xe47fe968, - 0xfa35ff36, 0x07331721, 0x17021500, 0x01090031, 0xdb760539, 0xf34ef541, - 0x013e0c31, 0xfc491132, 0x1240092b, 0x1d001a43, 0x105a0968, 0xd27fec68, - 0x0143f34e, 0xf541013e, 0xfa56ef5f, 0xfa3d092d, 0xfd45fa51, 0xf5600637, - 0x0743fb56, 0x0258003a, 0xfd4cf65e, 0x05360445, 0xfd510058, 0xf943fb4a, - 0xfc4afb50, 0xf948013a, 0x0029003f, 0x003f003f, 0xf7530456, 0x0061f948, - 0x0d29033e, 0x002dfc4e, 0xfd60e57e, 0xe462e765, 0xe943e452, 0xec5ef053, - 0xea6eeb5b, 0xee66f35d, 0xe37ff95c, 0xfb59f960, 0xf36cfd2e, 0xff41ff39, - 0xf75dfd4a, 0xf75cf857, 0xe97e0536, 0x063c063b, 0x0645ff30, 0x0044fc45, - 0xf858fe55, 0xfa4eff4b, 0xf94d0236, 0x0532fd44, 0x0132062a, 0xfc51013f, - 0xfc460043, 0x0239fe4c, 0x0b230440, 0x013d0b23, 0x12190c18, 0x0d1d0d24, - 0xf65df949, 0xfe490d2e, 0x0931f964, 0x09350235, 0x0535fe3d, 0x00380038, - 0xf33ffb3c, 0xff3e0439, 0xfa450439, 0x0e270433, 0x0d440340, 0x013d093f, - 0x07321027, 0x052c0434, 0x0b30fb3c, 0xff3b003b, 0x1621052c, 0x0e2bff4e, - 0x003c0945, 0x0b1c0228, 0x032c0031, 0x002e022c, 0x0233002f, 0x0427023e, - 0x062e0036, 0x0336023a, 0x043f0633, 0x06390735, 0x06340637, 0x0b2d0e24, - 0x0835ff52, 0x0737fd4e, 0x0f2e161f, 0xff541907, 0x1ef91c03, 0x1c042000, - 0x22ff1e06, 0x1e062009, 0x1f131a1b, 0x1a1e2514, 0x1c221146, 0x0143053b, - 0x0943101e, 0x12201223, 0x161d181f, 0x1726122b, 0x14290b3f, 0x093b0940, - 0xff5efe59, 0xf76cfa4c, 0xfe2c002d, 0x0034fd40, 0xfe3bfc46, 0xfc4bf852, - 0xef66f74d, 0x0318002a, 0x00300037, 0xfa3bf947, 0xf453f557, 0xe277013a, - 0xfd1dff24, 0x0126022b, 0xfa37003a, 0x0040fd4a, 0xf65a0046, 0xfc1d051f, - 0x072a013b, 0xfe3afd48, 0xfd51f561, 0x003a0805, 0x0a0e0e12, 0x0d1b0228, - 0x003afd46, 0xfa4ff855, 0x0000f36a, 0xf06af657, 0xeb72ee6e, 0xf262ea6e, - 0xeb6aee67, 0xeb6be96c, 0xe670f660, 0xf45ffb5b, 0xf75dea5e, 0xfb560943, - 0xfc50f655, 0xff46073c, 0x093a053d, 0x0c320f32, 0x12311136, 0x0a29072e, - 0xff330731, 0x08340929, 0x062f0237, 0x0d290a2c, 0x06320535, 0x0d31043f, - 0x0640fe45, 0xfe3b0646, 0x0a2c091f, 0x0c2b0335, 0x0e220a26, 0xfd340d28, - 0x1120072c, 0x07260d32, 0x0a391a2b, 0x0e0b0b0e, 0x090b120b, 0x150917fe, - 0x20f120f1, 0x22eb27e9, 0x2adf29e1, 0x2ee426f4, 0x151d2de8, 0x35d330e6, - 0x41d52bed, 0x27f61e09, 0x121a141b, 0x0039f252, 0xfb4bed61, 0xdd7d1b00, - 0x1c001ffc, 0x1b062208, 0x1e0a1816, 0x21131620, 0x1a1f1529, 0x1a2c172f, - 0x10410e47, 0x083c063f, 0x11411518, 0x17141a17, 0x1b201c17, 0x1c181728, - 0x18201c1d, 0x172a1339, 0x1635163d, 0x0b560c28, 0x0b330e3b, 0xfc4ff947, - 0xfb45f746, 0xf842f644, 0xed49f445, 0xf046f143, 0xec3eed46, 0xf042ea41, - 0xec3f09fe, 0x1af721f7, 0x27f929fe, 0x2d033109, 0x2d1b243b, 0xfa42f923, - 0xf92af82d, 0xfb30f438, 0xfa3cfb3e, 0xf842f84c, 0xfb55fa51, 0xf64df951, - 0xef50ee49, 0xfc4af653, 0xf747f743, 0xff3df842, 0xf242003b, 0x023b15f3, - 0x21f227f9, 0x2efe3302, 0x3c063d11, 0x37222a3e, 0x14f10236, 0x034a14f1, - 0x0236034a, 0xe47fe968, 0xfa35ff36, 0x07331619, 0x22001000, 0xfe090429, - 0xe3760241, 0xfa47f34f, 0x05340932, 0xfd460a36, 0x1a221316, 0x28003902, - 0x29241a45, 0xd37ff165, 0xfc4cfa47, 0xf34f0534, 0x0645f35a, 0x0034082b, - 0xfe45fb52, 0xf660023b, 0x024bfd57, 0xfd640138, 0xfd4afa55, 0x003bfd51, - 0xf956fb5f, 0xff42ff4d, 0x0146fe56, 0xfb48003d, 0x0029003f, 0x003f003f, - 0xf7530456, 0x0061f948, 0x0d29033e, 0x0d0f0733, 0x0250d97f, 0xee5bef60, - 0xe651dd62, 0xe866e961, 0xe577e863, 0xeb6eee66, 0xdc7f0050, 0xfb59f95e, - 0xfc5c0027, 0x0041f154, 0xdd7ffe49, 0xf468f75b, 0xe17f0337, 0x07380737, - 0x083dfd35, 0x0044f94a, 0xf758f367, 0xf35bf759, 0xf25cf84c, 0xf457e96e, - 0xe869f64e, 0xec70ef63, 0xb27fba7f, 0xce7fd27f, 0xfc42fb4e, 0xfc47f848, - 0x023bff37, 0xf946fa4b, 0xf859de77, 0xfd4b2014, 0x1e16d47f, 0x0036fb3d, - 0x003aff3c, 0xfd3df843, 0xe754f24a, 0xfb410534, 0x0239003d, 0xf745f546, - 0x1237fc47, 0x003a073d, 0x09291219, 0x0920052b, 0x092f002c, 0x0033022e, - 0x1326fc42, 0x0f260c2a, 0x09220059, 0x042d0a1c, 0x0a1f21f5, 0x34d5120f, - 0x1c0023ea, 0x26e72200, 0x27ee20f4, 0x66a20000, 0x38f121fc, 0x1d0a25fb, - 0x33e327f7, 0x34de45c6, 0x43c12cfb, 0x200737e3, 0x20010000, 0x1b2421e7, - 0x22e224e4, 0x26e426e5, 0x22ee23f0, 0x22f220f8, 0x25fa2300, 0x1e0a1c12, - 0x1a191d29, 0x004b0248, 0x084d0e23, 0x121f1123, 0x151e112d, 0x142a122d, - 0x1b1a1036, 0x07421038, 0x0b490a43, 0xf674e970, 0xf147f93d, 0x0035fb42, - 0xf54df750, 0xf754f657, 0xde7feb65, 0xfd27fb35, 0xf93df54b, 0xf14def5b, - 0xe76be76f, 0xe47af54c, 0xf62cf634, 0xf639f73a, 0xf048f945, 0xfc45fb4a, - 0xf7560242, 0xf7220120, 0x0b1f0534, 0xfe37fe43, 0x0049f859, 0x03340704, - 0x0a081108, 0x10130325, 0xff3dfb49, 0xff46fc4e, 0x0000eb7e, 0xe97cec6e, - 0xe67ee77c, 0xef69e579, 0xe575ef66, 0xe675e574, 0xdf7af65f, 0xf264f85f, - 0xef6fe472, 0xfa59fe50, 0xfc52f755, 0xf851ff48, 0x05400143, 0x09380045, - 0x01450745, 0xf945fa43, 0xf04dfe40, 0x023dfa43, 0xfd400239, 0xfd41fd42, - 0x003e0933, 0xff42fe47, 0xfe4bff46, 0xf7480e3c, 0x1025002f, 0x12230b25, - 0x0c290a29, 0x02300c29, 0x0d29003b, 0x03321328, 0x03421232, 0x13fa12fa, - 0x0e001af4, 0x1ff021e7, 0x21ea25e4, 0x27e22ae2, 0x2fd62ddc, 0x31de29ef, - 0x200945b9, 0x3fc142c0, 0x4db636d9, 0x34dd29f6, 0x240028ff, 0x1e0e1c1a, - 0x17250c37, 0x0b4125df, 0x27dc28db, 0x26e22edf, 0x2ae228e8, 0x31e326f4, - 0x28f626fd, 0x2efb1f14, 0x1d1e192c, 0x0c300b31, 0x1a2d1616, 0x17161b15, - 0x21141a1c, 0x1e181b22, 0x122a1927, 0x12320c46, 0x15360e47, 0x0b531920, - 0x15311536, 0xfb55fa51, 0xf64df951, 0xef50ee49, 0xfc4af653, 0xf747f743, - 0xff3df842, 0xf242003b, 0x023b11f6, 0x20f32af7, 0x31fb3500, 0x4003440a, - 0x421b2f39, 0xfb470018, 0xff24fe2a, 0xfe34f739, 0xfa3ffc41, 0xfc43f952, - 0xfd51fd4c, 0xf948fa4e, 0xf448f244, 0xfd46fa4c, 0xfb42fb3e, 0x0039fc3d, - 0xf73c0136, 0x023a11f6, 0x20f32af7, 0x31fb3500, 0x4003440a, 0x421b2f39, - 0x14f10236, 0x034a14f1, 0x0236034a, 0xe47fe968, 0xfa35ff36, 0x07331d10, - 0x19000e00, 0xf633fd3e, 0xe5631a10, 0xfc55e866, 0x05390639, 0xef490e39, - 0x1428140a, 0x1d003600, 0x252a0c61, 0xe07fea75, 0xfe4afc55, 0xe8660539, - 0xfa5df258, 0xfa2c0437, 0xf559f167, 0xeb741339, 0x143a0454, 0x0660013f, - 0xfb55f36a, 0x053f064b, 0xfd5aff65, 0x0337fc4f, 0xfe4bf461, 0xf932013c, - 0x0029003f, 0x003f003f, 0xf7530456, 0x0061f948, 0x0d29033e, 0x0722f758, - 0xec7fdc7f, 0xef5bf25f, 0xe754e756, 0xf459ef5b, 0xe17ff24c, 0xee67f35a, - 0xdb7f0b50, 0x054c0254, 0x054efa37, 0x043df253, 0xdb7ffb4f, 0xf568f55b, - 0xe27f0041, 0xfe4f0048, 0xfc5cfa38, 0x0344f847, 0xf362fc56, 0xf458fb52, - 0xfd48fc43, 0xf848f059, 0xf745ff3b, 0x05420439, 0xfc47fe47, 0x023aff4a, - 0xfc2cff45, 0x003ef933, 0xfc2ffa2a, 0xfd29fa35, 0x084cf74e, 0xf5530934, - 0x0043fb5a, 0x0143f148, 0xfb4bf850, 0xeb53eb40, 0xf31fe740, 0xe35e094b, - 0x113ff84a, 0xfb23fe1b, 0x0d5b0341, 0xf945084d, 0xf642033e, 0xfd44ec51, - 0x001e0107, 0xfd17eb4a, 0x1042e97c, 0x11252cee, 0x32deea7f, 0x0427002a, - 0x07220b1d, 0x081f0625, 0x072a0328, 0x08210d2b, 0x0d24042f, 0x0337023a, - 0x063c082c, 0x0b2c0e2a, 0x07300438, 0x04340d25, 0x0931133a, 0x0a300c2d, - 0x00451421, 0x083f23ee, 0x21e71cfd, 0x180a1b00, 0x22f234d4, 0x27e81311, - 0x1f19241d, 0x1821220f, 0x1e141649, 0x1422131f, 0x1b2c1310, 0x0f240f24, - 0x151c1915, 0x1e141f0c, 0x1b10182a, 0x005d0e38, 0x0f391a26, 0xe87fe873, - 0xea52f73e, 0x0035003b, 0xf255f359, 0xf35ef55c, 0xe37feb64, 0xf239f443, - 0xf547f64d, 0xeb55f058, 0xe968f162, 0xdb7ff652, 0xf830f83d, 0xf842f946, - 0xf24bf64f, 0xf753f45c, 0xee6cfc4f, 0xea45f04b, 0xfe3a013a, 0xf34ef753, - 0xfc51f363, 0xf351fa26, 0xf33efa3a, 0xfe3bf049, 0xf64cf356, 0xf753f657, - 0x0000ea7f, 0xe77fe778, 0xe57fed72, 0xe975e776, 0xe675e871, 0xe476e178, - 0xdb7cf65e, 0xf166f663, 0xf36ace7f, 0xfb5c1139, 0xfb56f35e, 0xf45bfe4d, - 0x0047ff49, 0x0440f951, 0x05400f39, 0x01430044, 0xf6430144, 0x004d0240, - 0x0044fb4e, 0x0737053b, 0x02410e36, 0x0f2c053c, 0x0246fe4c, 0xee560c46, - 0x0540f446, 0x0b370538, 0x00450241, 0xfa4a0536, 0x0736fa4c, 0xf552fe4d, - 0xfe4d192a, 0x11f310f7, 0x11f41beb, 0x25e229d8, 0x2ad730d1, 0x27e02ed8, - 0x34cd2ed7, 0x34d92bed, 0x200b3dc9, 0x38d23ece, 0x51bd2dec, 0x23fe1c0f, - 0x22012701, 0x1e111426, 0x122d0f36, 0x004f24f0, 0x25f225ef, 0x2001220f, - 0x1d0f1819, 0x22161f10, 0x23121f1c, 0x2129241c, 0x1b2f153e, 0x121f131a, - 0x24181817, 0x1b10181e, 0x1f1d1629, 0x162a103c, 0x0f340e3c, 0x034ef07b, - 0x15351638, 0x193d1521, 0x1332113d, 0xfd4ef84a, 0xf748f648, 0xee4bf447, - 0xf53ffb46, 0xef4bf248, 0xf043f835, 0xf23bf734, 0xf54409fe, 0x1ef61ffc, - 0x21ff2107, 0x1f0c2517, 0x1f261440, 0xf747f925, 0xf82cf531, 0xf638f43b, - 0xf83ff743, 0xfa44f64f, 0xfd4ef84a, 0xf748f648, 0xee4bf447, 0xf53ffb46, - 0xef4bf248, 0xf043f835, 0xf23bf734, 0xf54409fe, 0x1ef61ffc, 0x21ff2107, - 0x1f0c2517, 0x1f261440 -}; - -int rk3288_vpu_h264d_init(struct rk3288_vpu_ctx *ctx) -{ - struct rk3288_vpu_dev *vpu = ctx->dev; - int ret; - - ret = rk3288_vpu_aux_buf_alloc(vpu, &ctx->hw.h264d.priv_tbl, - sizeof(struct rk3288_vpu_h264d_priv_tbl)); - if (ret) { - vpu_err("allocate h264 priv_tbl failed\n"); - return ret; - } - - return 0; -} - -void rk3288_vpu_h264d_exit(struct rk3288_vpu_ctx *ctx) -{ - rk3288_vpu_aux_buf_free(ctx->dev, &ctx->hw.h264d.priv_tbl); -} - -static void rk3288_vpu_h264d_prepare_table(struct rk3288_vpu_ctx *ctx) -{ - struct rk3288_vpu_h264d_priv_tbl *tbl = ctx->hw.h264d.priv_tbl.cpu; - const struct v4l2_ctrl_h264_scaling_matrix *scaling = - ctx->run.h264d.scaling_matrix; - const struct v4l2_ctrl_h264_decode_param *dec_param = - ctx->run.h264d.decode_param; - const struct v4l2_h264_dpb_entry *dpb = ctx->run.h264d.dpb; - int i; - - /* - * Prepare auxiliary buffer. - * - * TODO: The CABAC table never changes, but maybe it would be better - * to have it as a control, which is set by userspace once? - */ - memcpy(tbl->cabac_table, h264_cabac_table, sizeof(tbl->cabac_table)); - - for (i = 0; i < RK3288_VPU_H264_NUM_DPB; ++i) { - tbl->poc[i * 2 + 0] = dpb[i].top_field_order_cnt; - tbl->poc[i * 2 + 1] = dpb[i].bottom_field_order_cnt; - - vpu_debug(2, "poc [%02d]: %08x %08x\n", i, - tbl->poc[i*2+0], tbl->poc[i*2+1]); - } - - tbl->poc[32] = dec_param->top_field_order_cnt; - tbl->poc[33] = dec_param->bottom_field_order_cnt; - - vpu_debug(2, "poc curr: %08x %08x\n", tbl->poc[32], tbl->poc[33]); - - memcpy(tbl->scaling_list, scaling, sizeof(tbl->scaling_list)); -} - -static void rk3288_vpu_h264d_set_params(struct rk3288_vpu_ctx *ctx) -{ - const struct v4l2_ctrl_h264_decode_param *dec_param = - ctx->run.h264d.decode_param; - const struct v4l2_ctrl_h264_slice_param *slice = - ctx->run.h264d.slice_param; - const struct v4l2_ctrl_h264_sps *sps = ctx->run.h264d.sps; - const struct v4l2_ctrl_h264_pps *pps = ctx->run.h264d.pps; - struct rk3288_vpu_dev *vpu = ctx->dev; - u32 reg; - - /* Decoder control register 0. */ - reg = VDPU_REG_DEC_CTRL0_DEC_AXI_WR_ID(0xff); - if (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD) - reg |= VDPU_REG_DEC_CTRL0_SEQ_MBAFF_E; - if (sps->profile_idc > 66) - reg |= VDPU_REG_DEC_CTRL0_PICORD_COUNT_E - | VDPU_REG_DEC_CTRL0_WRITE_MVS_E; - if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY) && - (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD || - slice->flags & V4L2_SLICE_FLAG_FIELD_PIC)) - reg |= VDPU_REG_DEC_CTRL0_PIC_INTERLACE_E; - if (slice->flags & V4L2_SLICE_FLAG_FIELD_PIC) - reg |= VDPU_REG_DEC_CTRL0_PIC_FIELDMODE_E; - if (!(slice->flags & V4L2_SLICE_FLAG_BOTTOM_FIELD)) - reg |= VDPU_REG_DEC_CTRL0_PIC_TOPFIELD_E; - vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_CTRL0); - - /* Decoder control register 1. */ - reg = VDPU_REG_DEC_CTRL1_PIC_MB_WIDTH(sps->pic_width_in_mbs_minus1 + 1) - | VDPU_REG_DEC_CTRL1_PIC_MB_HEIGHT_P( - sps->pic_height_in_map_units_minus1 + 1) - | VDPU_REG_DEC_CTRL1_REF_FRAMES(sps->max_num_ref_frames); - vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_CTRL1); - - /* Decoder control register 2. */ - reg = VDPU_REG_DEC_CTRL2_CH_QP_OFFSET(pps->chroma_qp_index_offset) - | VDPU_REG_DEC_CTRL2_CH_QP_OFFSET2( - pps->second_chroma_qp_index_offset); - if (pps->flags & V4L2_H264_PPS_FLAG_PIC_SCALING_MATRIX_PRESENT) - reg |= VDPU_REG_DEC_CTRL2_TYPE1_QUANT_E; - if (slice->flags & V4L2_SLICE_FLAG_FIELD_PIC) - reg |= VDPU_REG_DEC_CTRL2_FIELDPIC_FLAG_E; - vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_CTRL2); - - /* Decoder control register 3. */ - reg = VDPU_REG_DEC_CTRL3_START_CODE_E - | VDPU_REG_DEC_CTRL3_INIT_QP(pps->pic_init_qp_minus26 + 26) - | VDPU_REG_DEC_CTRL3_STREAM_LEN( - vb2_get_plane_payload(&ctx->run.src->b, 0)); - vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_CTRL3); - - /* Decoder control register 4. */ - reg = VDPU_REG_DEC_CTRL4_FRAMENUM_LEN( - sps->log2_max_frame_num_minus4 + 4) - | VDPU_REG_DEC_CTRL4_FRAMENUM(slice->frame_num) - | VDPU_REG_DEC_CTRL4_WEIGHT_BIPR_IDC(pps->weighted_bipred_idc); - if (pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE) - reg |= VDPU_REG_DEC_CTRL4_CABAC_E; - if (sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE) - reg |= VDPU_REG_DEC_CTRL4_DIR_8X8_INFER_E; - if (sps->profile_idc >= 0 && sps->chroma_format_idc == 0) - reg |= VDPU_REG_DEC_CTRL4_BLACKWHITE_E; - if (pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED) - reg |= VDPU_REG_DEC_CTRL4_WEIGHT_PRED_E; - vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_CTRL4); - - /* Decoder control register 5. */ - reg = VDPU_REG_DEC_CTRL5_REFPIC_MK_LEN( - slice->dec_ref_pic_marking_bit_size) - | VDPU_REG_DEC_CTRL5_IDR_PIC_ID(slice->idr_pic_id); - if (pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED) - reg |= VDPU_REG_DEC_CTRL5_CONST_INTRA_E; - if (pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT) - reg |= VDPU_REG_DEC_CTRL5_FILT_CTRL_PRES; - if (pps->flags & V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT) - reg |= VDPU_REG_DEC_CTRL5_RDPIC_CNT_PRES; - if (pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE) - reg |= VDPU_REG_DEC_CTRL5_8X8TRANS_FLAG_E; - if (dec_param->idr_pic_flag) - reg |= VDPU_REG_DEC_CTRL5_IDR_PIC_E; - vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_CTRL5); - - /* Decoder control register 6. */ - reg = VDPU_REG_DEC_CTRL6_PPS_ID(slice->pic_parameter_set_id) - | VDPU_REG_DEC_CTRL6_REFIDX0_ACTIVE( - pps->num_ref_idx_l0_default_active_minus1 + 1) - | VDPU_REG_DEC_CTRL6_REFIDX1_ACTIVE( - pps->num_ref_idx_l1_default_active_minus1 + 1) - | VDPU_REG_DEC_CTRL6_POC_LENGTH(slice->pic_order_cnt_bit_size); - vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_CTRL6); - - /* Error concealment register. */ - vdpu_write_relaxed(vpu, 0, VDPU_REG_ERR_CONC); - - /* Prediction filter tap register. */ - vdpu_write_relaxed(vpu, VDPU_REG_PRED_FLT_PRED_BC_TAP_0_0(1) - | VDPU_REG_PRED_FLT_PRED_BC_TAP_0_1(-5 & 0x3ff) - | VDPU_REG_PRED_FLT_PRED_BC_TAP_0_2(20), - VDPU_REG_PRED_FLT); - - /* Reference picture buffer control register. */ - vdpu_write_relaxed(vpu, 0, VDPU_REG_REF_BUF_CTRL); - - /* Reference picture buffer control register 2. */ - vdpu_write_relaxed(vpu, VDPU_REG_REF_BUF_CTRL2_APF_THRESHOLD(8), - VDPU_REG_REF_BUF_CTRL2); -} - - -static void rk3288_vpu_h264d_set_ref(struct rk3288_vpu_ctx *ctx) -{ - const struct v4l2_ctrl_h264_decode_param *dec_param = - ctx->run.h264d.decode_param; - const struct v4l2_h264_dpb_entry *dpb = ctx->run.h264d.dpb; - const u8 *dpb_map = ctx->run.h264d.dpb_map; - struct rk3288_vpu_dev *vpu = ctx->dev; - u32 dpb_longterm = 0; - u32 dpb_valid = 0; - int reg_num; - u32 reg; - int i; - - /* - * Set up bit maps of valid and long term DPBs. - * NOTE: The bits are reversed, i.e. MSb is DPB 0. - */ - for (i = 0; i < RK3288_VPU_H264_NUM_DPB; ++i) { - if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) - dpb_valid |= BIT(RK3288_VPU_H264_NUM_DPB - 1 - i); - - if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) - dpb_longterm |= BIT(RK3288_VPU_H264_NUM_DPB - 1 - i); - } - vdpu_write_relaxed(vpu, dpb_valid << 16, VDPU_REG_VALID_REF); - vdpu_write_relaxed(vpu, dpb_longterm << 16, VDPU_REG_LT_REF); - - /* - * Set up reference frame picture numbers. - * - * Each VDPU_REG_REF_PIC(x) register contains numbers of two - * subsequential reference pictures. - */ - for (i = 0; i < RK3288_VPU_H264_NUM_DPB; i += 2) { - reg = 0; - - if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) - reg |= VDPU_REG_REF_PIC_REFER0_NBR(dpb[i].pic_num); - else - reg |= VDPU_REG_REF_PIC_REFER0_NBR(dpb[i].frame_num); - - if (dpb[i + 1].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) - reg |= VDPU_REG_REF_PIC_REFER1_NBR(dpb[i + 1].pic_num); - else - reg |= VDPU_REG_REF_PIC_REFER1_NBR( - dpb[i + 1].frame_num); - - vdpu_write_relaxed(vpu, reg, VDPU_REG_REF_PIC(i / 2)); - } - - /* - * Each VDPU_REG_BD_REF_PIC(x) register contains three entries - * of each forward and backward picture list. - */ - reg_num = 0; - for (i = 0; i < 15; i += 3) { - reg = VDPU_REG_BD_REF_PIC_BINIT_RLIST_F0( - dpb_map[dec_param->ref_pic_list_b0[i + 0]]) - | VDPU_REG_BD_REF_PIC_BINIT_RLIST_F1( - dpb_map[dec_param->ref_pic_list_b0[i + 1]]) - | VDPU_REG_BD_REF_PIC_BINIT_RLIST_F2( - dpb_map[dec_param->ref_pic_list_b0[i + 2]]) - | VDPU_REG_BD_REF_PIC_BINIT_RLIST_B0( - dpb_map[dec_param->ref_pic_list_b1[i + 0]]) - | VDPU_REG_BD_REF_PIC_BINIT_RLIST_B1( - dpb_map[dec_param->ref_pic_list_b1[i + 1]]) - | VDPU_REG_BD_REF_PIC_BINIT_RLIST_B2( - dpb_map[dec_param->ref_pic_list_b1[i + 2]]); - vdpu_write_relaxed(vpu, reg, VDPU_REG_BD_REF_PIC(reg_num++)); - } - - /* - * VDPU_REG_BD_P_REF_PIC register contains last entries (index 15) - * of forward and backward reference picture lists and first 4 entries - * of P forward picture list. - */ - reg = VDPU_REG_BD_P_REF_PIC_BINIT_RLIST_F15( - dpb_map[dec_param->ref_pic_list_b0[15]]) - | VDPU_REG_BD_P_REF_PIC_BINIT_RLIST_B15( - dpb_map[dec_param->ref_pic_list_b1[15]]) - | VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F0( - dpb_map[dec_param->ref_pic_list_p0[0]]) - | VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F1( - dpb_map[dec_param->ref_pic_list_p0[1]]) - | VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F2( - dpb_map[dec_param->ref_pic_list_p0[2]]) - | VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F3( - dpb_map[dec_param->ref_pic_list_p0[3]]); - vdpu_write_relaxed(vpu, reg, VDPU_REG_BD_P_REF_PIC); - - /* - * Each VDPU_REG_FWD_PIC(x) register contains six consecutive - * entries of P forward picture list, starting from index 4. - */ - reg_num = 0; - for (i = 4; i < RK3288_VPU_H264_NUM_DPB; i += 6) { - reg = VDPU_REG_FWD_PIC_PINIT_RLIST_F0( - dpb_map[dec_param->ref_pic_list_p0[i + 0]]) - | VDPU_REG_FWD_PIC_PINIT_RLIST_F1( - dpb_map[dec_param->ref_pic_list_p0[i + 1]]) - | VDPU_REG_FWD_PIC_PINIT_RLIST_F2( - dpb_map[dec_param->ref_pic_list_p0[i + 2]]) - | VDPU_REG_FWD_PIC_PINIT_RLIST_F3( - dpb_map[dec_param->ref_pic_list_p0[i + 3]]) - | VDPU_REG_FWD_PIC_PINIT_RLIST_F4( - dpb_map[dec_param->ref_pic_list_p0[i + 4]]) - | VDPU_REG_FWD_PIC_PINIT_RLIST_F5( - dpb_map[dec_param->ref_pic_list_p0[i + 5]]); - vdpu_write_relaxed(vpu, reg, VDPU_REG_FWD_PIC(reg_num++)); - } - - /* - * Set up addresses of DPB buffers. - * - * If a DPB entry is unused, address of current destination buffer - * is used. - */ - for (i = 0; i < RK3288_VPU_H264_NUM_DPB; ++i) { - struct vb2_buffer *buf; - - if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE - && dpb[i].buf_index < ctx->vq_dst.num_buffers) - buf = ctx->dst_bufs[dpb[i].buf_index]; - else - buf = &ctx->run.dst->b; - - vdpu_write_relaxed(vpu, vb2_dma_contig_plane_dma_addr(buf, 0), - VDPU_REG_ADDR_REF(i)); - } -} - -static void rk3288_vpu_h264d_set_buffers(struct rk3288_vpu_ctx *ctx) -{ - const struct v4l2_ctrl_h264_sps *sps = ctx->run.h264d.sps; - const struct v4l2_ctrl_h264_slice_param *slice = - ctx->run.h264d.slice_param; - struct rk3288_vpu_dev *vpu = ctx->dev; - dma_addr_t src_dma, dst_dma; - - /* Source (stream) buffer. */ - src_dma = vb2_dma_contig_plane_dma_addr(&ctx->run.src->b, 0); - vdpu_write_relaxed(vpu, src_dma, VDPU_REG_ADDR_STR); - - /* Destination (decoded frame) buffer. */ - dst_dma = vb2_dma_contig_plane_dma_addr(&ctx->run.dst->b, 0); - vdpu_write_relaxed(vpu, dst_dma, VDPU_REG_ADDR_DST); - - /* Higher profiles require DMV buffer appended to reference frames. */ - if (sps->profile_idc > 66) { - size_t sizeimage = ctx->dst_fmt.plane_fmt[0].sizeimage; - size_t mv_offset = round_up(sizeimage, 8); - - if (slice->flags & V4L2_SLICE_FLAG_BOTTOM_FIELD) - mv_offset += 32 * MB_WIDTH(ctx->dst_fmt.width); - - vdpu_write_relaxed(vpu, dst_dma + mv_offset, - VDPU_REG_ADDR_DIR_MV); - } - - /* Auxiliary buffer prepared in rk3288_vpu_h264d_prepare_table(). */ - vdpu_write_relaxed(vpu, ctx->hw.h264d.priv_tbl.dma, - VDPU_REG_ADDR_QTABLE); -} - -void rk3288_vpu_h264d_run(struct rk3288_vpu_ctx *ctx) -{ - struct rk3288_vpu_dev *vpu = ctx->dev; - - /* Prepare data in memory. */ - rk3288_vpu_h264d_prepare_table(ctx); - - rk3288_vpu_power_on(vpu); - - /* Configure hardware registers. */ - rk3288_vpu_h264d_set_params(ctx); - rk3288_vpu_h264d_set_ref(ctx); - rk3288_vpu_h264d_set_buffers(ctx); - - schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); - - /* Start decoding! */ - vdpu_write_relaxed(vpu, VDPU_REG_CONFIG_DEC_AXI_RD_ID(0xff) - | VDPU_REG_CONFIG_DEC_TIMEOUT_E - | VDPU_REG_CONFIG_DEC_OUT_ENDIAN - | VDPU_REG_CONFIG_DEC_STRENDIAN_E - | VDPU_REG_CONFIG_DEC_MAX_BURST(16) - | VDPU_REG_CONFIG_DEC_OUTSWAP32_E - | VDPU_REG_CONFIG_DEC_INSWAP32_E - | VDPU_REG_CONFIG_DEC_STRSWAP32_E - | VDPU_REG_CONFIG_DEC_CLK_GATE_E, - VDPU_REG_CONFIG); - vdpu_write(vpu, VDPU_REG_INTERRUPT_DEC_E, VDPU_REG_INTERRUPT); -} diff --git a/drivers/media/platform/rk3288-vpu/rk3288_vpu_hw_vp8d.c b/drivers/media/platform/rk3288-vpu/rk3288_vpu_hw_vp8d.c deleted file mode 100644 index 6e03398d451d..000000000000 --- a/drivers/media/platform/rk3288-vpu/rk3288_vpu_hw_vp8d.c +++ /dev/null @@ -1,767 +0,0 @@ -/* - * Rockchip RK3288 VPU codec vp8 decode driver - * - * Copyright (C) 2014 Rockchip Electronics Co., Ltd. - * ZhiChao Yu - * - * Copyright (C) 2014 Google, Inc. - * Tomasz Figa - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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 "rk3288_vpu_hw.h" -#include "rk3288_vpu_regs.h" -#include "rk3288_vpu_common.h" - -#define DEC_8190_ALIGN_MASK 0x07U - -/* - * probs table with packed - */ -struct vp8_prob_tbl_packed { - u8 prob_mb_skip_false; - u8 prob_intra; - u8 prob_ref_last; - u8 prob_ref_golden; - u8 prob_segment[3]; - u8 packed0; - - u8 prob_luma_16x16_pred_mode[4]; - u8 prob_chroma_pred_mode[3]; - u8 packed1; - - /* mv prob */ - u8 prob_mv_context[2][19]; - u8 packed2[2]; - - /* coeff probs */ - u8 prob_coeffs[4][8][3][11]; - u8 packed3[96]; -}; - -struct vp8d_reg { - u32 base; - u32 shift; - u32 mask; -}; - -/* dct partiton base address regs */ -static const struct vp8d_reg vp8d_dct_base[8] = { - { VDPU_REG_ADDR_STR, 0, 0xffffffff }, - { VDPU_REG_ADDR_REF(8), 0, 0xffffffff }, - { VDPU_REG_ADDR_REF(9), 0, 0xffffffff }, - { VDPU_REG_ADDR_REF(10), 0, 0xffffffff }, - { VDPU_REG_ADDR_REF(11), 0, 0xffffffff }, - { VDPU_REG_ADDR_REF(12), 0, 0xffffffff }, - { VDPU_REG_ADDR_REF(14), 0, 0xffffffff }, - { VDPU_REG_ADDR_REF(15), 0, 0xffffffff }, -}; - -/* loop filter level regs */ -static const struct vp8d_reg vp8d_lf_level[4] = { - { VDPU_REG_REF_PIC(2), 18, 0x3f }, - { VDPU_REG_REF_PIC(2), 12, 0x3f }, - { VDPU_REG_REF_PIC(2), 6, 0x3f }, - { VDPU_REG_REF_PIC(2), 0, 0x3f }, -}; - -/* macroblock loop filter level adjustment regs */ -static const struct vp8d_reg vp8d_mb_adj[4] = { - { VDPU_REG_REF_PIC(0), 21, 0x7f }, - { VDPU_REG_REF_PIC(0), 14, 0x7f }, - { VDPU_REG_REF_PIC(0), 7, 0x7f }, - { VDPU_REG_REF_PIC(0), 0, 0x7f }, -}; - -/* reference frame adjustment regs */ -static const struct vp8d_reg vp8d_ref_adj[4] = { - { VDPU_REG_REF_PIC(1), 21, 0x7f }, - { VDPU_REG_REF_PIC(1), 14, 0x7f }, - { VDPU_REG_REF_PIC(1), 7, 0x7f }, - { VDPU_REG_REF_PIC(1), 0, 0x7f }, -}; - -/* quantizer regs */ -static const struct vp8d_reg vp8d_quant[4] = { - { VDPU_REG_REF_PIC(3), 11, 0x7ff }, - { VDPU_REG_REF_PIC(3), 0, 0x7ff }, - { VDPU_REG_BD_REF_PIC(4), 11, 0x7ff }, - { VDPU_REG_BD_REF_PIC(4), 0, 0x7ff }, -}; - -/* quantizer delta regs */ -static const struct vp8d_reg vp8d_quant_delta[5] = { - { VDPU_REG_REF_PIC(3), 27, 0x1f }, - { VDPU_REG_REF_PIC(3), 22, 0x1f }, - { VDPU_REG_BD_REF_PIC(4), 27, 0x1f }, - { VDPU_REG_BD_REF_PIC(4), 22, 0x1f }, - { VDPU_REG_BD_P_REF_PIC, 27, 0x1f }, -}; - -/* dct partition start bits regs */ -static const struct vp8d_reg vp8d_dct_start_bits[8] = { - { VDPU_REG_DEC_CTRL2, 26, 0x3f }, { VDPU_REG_DEC_CTRL4, 26, 0x3f }, - { VDPU_REG_DEC_CTRL4, 20, 0x3f }, { VDPU_REG_DEC_CTRL7, 24, 0x3f }, - { VDPU_REG_DEC_CTRL7, 18, 0x3f }, { VDPU_REG_DEC_CTRL7, 12, 0x3f }, - { VDPU_REG_DEC_CTRL7, 6, 0x3f }, { VDPU_REG_DEC_CTRL7, 0, 0x3f }, -}; - -/* precision filter tap regs */ -static const struct vp8d_reg vp8d_pred_bc_tap[8][4] = { - { - { VDPU_REG_PRED_FLT, 22, 0x3ff }, - { VDPU_REG_PRED_FLT, 12, 0x3ff }, - { VDPU_REG_PRED_FLT, 2, 0x3ff }, - { VDPU_REG_REF_PIC(4), 22, 0x3ff }, - }, - { - { VDPU_REG_REF_PIC(4), 12, 0x3ff }, - { VDPU_REG_REF_PIC(4), 2, 0x3ff }, - { VDPU_REG_REF_PIC(5), 22, 0x3ff }, - { VDPU_REG_REF_PIC(5), 12, 0x3ff }, - }, - { - { VDPU_REG_REF_PIC(5), 2, 0x3ff }, - { VDPU_REG_REF_PIC(6), 22, 0x3ff }, - { VDPU_REG_REF_PIC(6), 12, 0x3ff }, - { VDPU_REG_REF_PIC(6), 2, 0x3ff }, - }, - { - { VDPU_REG_REF_PIC(7), 22, 0x3ff }, - { VDPU_REG_REF_PIC(7), 12, 0x3ff }, - { VDPU_REG_REF_PIC(7), 2, 0x3ff }, - { VDPU_REG_LT_REF, 22, 0x3ff }, - }, - { - { VDPU_REG_LT_REF, 12, 0x3ff }, - { VDPU_REG_LT_REF, 2, 0x3ff }, - { VDPU_REG_VALID_REF, 22, 0x3ff }, - { VDPU_REG_VALID_REF, 12, 0x3ff }, - }, - { - { VDPU_REG_VALID_REF, 2, 0x3ff }, - { VDPU_REG_BD_REF_PIC(0), 22, 0x3ff }, - { VDPU_REG_BD_REF_PIC(0), 12, 0x3ff }, - { VDPU_REG_BD_REF_PIC(0), 2, 0x3ff }, - }, - { - { VDPU_REG_BD_REF_PIC(1), 22, 0x3ff }, - { VDPU_REG_BD_REF_PIC(1), 12, 0x3ff }, - { VDPU_REG_BD_REF_PIC(1), 2, 0x3ff }, - { VDPU_REG_BD_REF_PIC(2), 22, 0x3ff }, - }, - { - { VDPU_REG_BD_REF_PIC(2), 12, 0x3ff }, - { VDPU_REG_BD_REF_PIC(2), 2, 0x3ff }, - { VDPU_REG_BD_REF_PIC(3), 22, 0x3ff }, - { VDPU_REG_BD_REF_PIC(3), 12, 0x3ff }, - }, -}; - -/* - * filter taps taken to 7-bit precision, - * reference RFC6386#Page-16, filters[8][6] - */ -static const u32 vp8d_mc_filter[8][6] = { - { 0, 0, 128, 0, 0, 0 }, - { 0, -6, 123, 12, -1, 0 }, - { 2, -11, 108, 36, -8, 1 }, - { 0, -9, 93, 50, -6, 0 }, - { 3, -16, 77, 77, -16, 3 }, - { 0, -6, 50, 93, -9, 0 }, - { 1, -8, 36, 108, -11, 2 }, - { 0, -1, 12, 123, -6, 0 } -}; - -static inline void vp8d_reg_write(struct rk3288_vpu_dev *vpu, - const struct vp8d_reg *reg, u32 val) -{ - u32 v; - - v = vdpu_read(vpu, reg->base); - v &= ~(reg->mask << reg->shift); - v |= ((val & reg->mask) << reg->shift); - vdpu_write_relaxed(vpu, v, reg->base); -} - -/* dump hw params for debug */ -#ifdef DEBUG -static void rk3288_vp8d_dump_hdr(struct rk3288_vpu_ctx *ctx) -{ - const struct v4l2_ctrl_vp8_frame_hdr *hdr = ctx->run.vp8d.frame_hdr; - int dct_total_len = 0; - int i; - - vpu_debug(4, "Frame tag: key_frame=0x%02x, version=0x%02x\n", - !hdr->key_frame, hdr->version); - - vpu_debug(4, "Picture size: w=%d, h=%d\n", hdr->width, hdr->height); - - /* stream addresses */ - vpu_debug(4, "Addresses: segmap=0x%x, probs=0x%x\n", - ctx->hw.vp8d.segment_map.dma, - ctx->hw.vp8d.prob_tbl.dma); - - /* reference frame info */ - vpu_debug(4, "Ref frame: last=%d, golden=%d, alt=%d\n", - hdr->last_frame, hdr->golden_frame, hdr->alt_frame); - - /* bool decoder info */ - vpu_debug(4, "Bool decoder: range=0x%x, value=0x%x, count=0x%x\n", - hdr->bool_dec_range, hdr->bool_dec_value, - hdr->bool_dec_count); - - /* control partition info */ - vpu_debug(4, "Control Part: offset=0x%x, size=0x%x\n", - hdr->first_part_offset, hdr->first_part_size); - vpu_debug(2, "Macroblock Data: bits_offset=0x%x\n", - hdr->macroblock_bit_offset); - - /* dct partition info */ - for (i = 0; i < hdr->num_dct_parts; i++) { - dct_total_len += hdr->dct_part_sizes[i]; - vpu_debug(4, "Dct Part%d Size: 0x%x\n", - i, hdr->dct_part_sizes[i]); - } - - dct_total_len += (hdr->num_dct_parts - 1) * 3; - vpu_debug(4, "Dct Part Total Length: 0x%x\n", dct_total_len); -} -#else -static inline void rk3288_vp8d_dump_hdr(struct rk3288_vpu_ctx *ctx) {} -#endif - -static void rk3288_vp8d_prob_update(struct rk3288_vpu_ctx *ctx) -{ - const struct v4l2_ctrl_vp8_frame_hdr *hdr = ctx->run.vp8d.frame_hdr; - const struct v4l2_vp8_entropy_hdr *entropy_hdr = &hdr->entropy_hdr; - u32 i, j, k; - u8 *dst; - - /* first probs */ - dst = ctx->hw.vp8d.prob_tbl.cpu; - - dst[0] = hdr->prob_skip_false; - dst[1] = hdr->prob_intra; - dst[2] = hdr->prob_last; - dst[3] = hdr->prob_gf; - dst[4] = hdr->sgmnt_hdr.segment_probs[0]; - dst[5] = hdr->sgmnt_hdr.segment_probs[1]; - dst[6] = hdr->sgmnt_hdr.segment_probs[2]; - dst[7] = 0; - - dst += 8; - dst[0] = entropy_hdr->y_mode_probs[0]; - dst[1] = entropy_hdr->y_mode_probs[1]; - dst[2] = entropy_hdr->y_mode_probs[2]; - dst[3] = entropy_hdr->y_mode_probs[3]; - dst[4] = entropy_hdr->uv_mode_probs[0]; - dst[5] = entropy_hdr->uv_mode_probs[1]; - dst[6] = entropy_hdr->uv_mode_probs[2]; - dst[7] = 0; /*unused */ - - /* mv probs */ - dst += 8; - dst[0] = entropy_hdr->mv_probs[0][0]; /* is short */ - dst[1] = entropy_hdr->mv_probs[1][0]; - dst[2] = entropy_hdr->mv_probs[0][1]; /* sign */ - dst[3] = entropy_hdr->mv_probs[1][1]; - dst[4] = entropy_hdr->mv_probs[0][8 + 9]; - dst[5] = entropy_hdr->mv_probs[0][9 + 9]; - dst[6] = entropy_hdr->mv_probs[1][8 + 9]; - dst[7] = entropy_hdr->mv_probs[1][9 + 9]; - dst += 8; - for (i = 0; i < 2; ++i) { - for (j = 0; j < 8; j += 4) { - dst[0] = entropy_hdr->mv_probs[i][j + 9 + 0]; - dst[1] = entropy_hdr->mv_probs[i][j + 9 + 1]; - dst[2] = entropy_hdr->mv_probs[i][j + 9 + 2]; - dst[3] = entropy_hdr->mv_probs[i][j + 9 + 3]; - dst += 4; - } - } - for (i = 0; i < 2; ++i) { - dst[0] = entropy_hdr->mv_probs[i][0 + 2]; - dst[1] = entropy_hdr->mv_probs[i][1 + 2]; - dst[2] = entropy_hdr->mv_probs[i][2 + 2]; - dst[3] = entropy_hdr->mv_probs[i][3 + 2]; - dst[4] = entropy_hdr->mv_probs[i][4 + 2]; - dst[5] = entropy_hdr->mv_probs[i][5 + 2]; - dst[6] = entropy_hdr->mv_probs[i][6 + 2]; - dst[7] = 0; /*unused */ - dst += 8; - } - - /* coeff probs (header part) */ - dst = ctx->hw.vp8d.prob_tbl.cpu; - dst += (8 * 7); - for (i = 0; i < 4; ++i) { - for (j = 0; j < 8; ++j) { - for (k = 0; k < 3; ++k) { - dst[0] = entropy_hdr->coeff_probs[i][j][k][0]; - dst[1] = entropy_hdr->coeff_probs[i][j][k][1]; - dst[2] = entropy_hdr->coeff_probs[i][j][k][2]; - dst[3] = entropy_hdr->coeff_probs[i][j][k][3]; - dst += 4; - } - } - } - - /* coeff probs (footer part) */ - dst = ctx->hw.vp8d.prob_tbl.cpu; - dst += (8 * 55); - for (i = 0; i < 4; ++i) { - for (j = 0; j < 8; ++j) { - for (k = 0; k < 3; ++k) { - dst[0] = entropy_hdr->coeff_probs[i][j][k][4]; - dst[1] = entropy_hdr->coeff_probs[i][j][k][5]; - dst[2] = entropy_hdr->coeff_probs[i][j][k][6]; - dst[3] = entropy_hdr->coeff_probs[i][j][k][7]; - dst[4] = entropy_hdr->coeff_probs[i][j][k][8]; - dst[5] = entropy_hdr->coeff_probs[i][j][k][9]; - dst[6] = entropy_hdr->coeff_probs[i][j][k][10]; - dst[7] = 0; /*unused */ - dst += 8; - } - } - } -} - -/* - * set loop filters - */ -static void rk3288_vp8d_cfg_lf(struct rk3288_vpu_ctx *ctx) -{ - const struct v4l2_ctrl_vp8_frame_hdr *hdr = ctx->run.vp8d.frame_hdr; - struct rk3288_vpu_dev *vpu = ctx->dev; - u32 reg; - int i; - - if (!(hdr->sgmnt_hdr.flags & V4L2_VP8_SEGMNT_HDR_FLAG_ENABLED)) { - vp8d_reg_write(vpu, &vp8d_lf_level[0], hdr->lf_hdr.level); - } else if (hdr->sgmnt_hdr.segment_feature_mode) { - /* absolute mode */ - for (i = 0; i < 4; i++) - vp8d_reg_write(vpu, &vp8d_lf_level[i], - hdr->sgmnt_hdr.lf_update[i]); - } else { - /* delta mode */ - for (i = 0; i < 4; i++) - vp8d_reg_write(vpu, &vp8d_lf_level[i], - clamp(hdr->lf_hdr.level - + hdr->sgmnt_hdr.lf_update[i], 0, 63)); - } - - reg = VDPU_REG_REF_PIC_FILT_SHARPNESS(hdr->lf_hdr.sharpness_level); - if (hdr->lf_hdr.type) - reg |= VDPU_REG_REF_PIC_FILT_TYPE_E; - vdpu_write_relaxed(vpu, reg, VDPU_REG_REF_PIC(0)); - - if (hdr->lf_hdr.flags & V4L2_VP8_LF_HDR_ADJ_ENABLE) { - for (i = 0; i < 4; i++) { - vp8d_reg_write(vpu, &vp8d_mb_adj[i], - hdr->lf_hdr.mb_mode_delta_magnitude[i]); - vp8d_reg_write(vpu, &vp8d_ref_adj[i], - hdr->lf_hdr.ref_frm_delta_magnitude[i]); - } - } -} - -/* - * set quantization parameters - */ -static void rk3288_vp8d_cfg_qp(struct rk3288_vpu_ctx *ctx) -{ - const struct v4l2_ctrl_vp8_frame_hdr *hdr = ctx->run.vp8d.frame_hdr; - struct rk3288_vpu_dev *vpu = ctx->dev; - int i; - - if (!(hdr->sgmnt_hdr.flags & V4L2_VP8_SEGMNT_HDR_FLAG_ENABLED)) { - vp8d_reg_write(vpu, &vp8d_quant[0], hdr->quant_hdr.y_ac_qi); - } else if (hdr->sgmnt_hdr.segment_feature_mode) { - /* absolute mode */ - for (i = 0; i < 4; i++) - vp8d_reg_write(vpu, &vp8d_quant[i], - hdr->sgmnt_hdr.quant_update[i]); - } else { - /* delta mode */ - for (i = 0; i < 4; i++) - vp8d_reg_write(vpu, &vp8d_quant[i], - clamp(hdr->quant_hdr.y_ac_qi - + hdr->sgmnt_hdr.quant_update[i], - 0, 127)); - } - - vp8d_reg_write(vpu, &vp8d_quant_delta[0], hdr->quant_hdr.y_dc_delta); - vp8d_reg_write(vpu, &vp8d_quant_delta[1], hdr->quant_hdr.y2_dc_delta); - vp8d_reg_write(vpu, &vp8d_quant_delta[2], hdr->quant_hdr.y2_ac_delta); - vp8d_reg_write(vpu, &vp8d_quant_delta[3], hdr->quant_hdr.uv_dc_delta); - vp8d_reg_write(vpu, &vp8d_quant_delta[4], hdr->quant_hdr.uv_ac_delta); -} - -/* - * set control partition and dct partition regs - * - * VP8 frame stream data layout: - * - * first_part_size parttion_sizes[0] - * ^ ^ - * src_dma | | - * ^ +--------+------+ +-----+-----+ - * | | control part | | | - * +--------+----------------+------------------+-----------+-----+-----------+ - * | tag 3B | extra 7B | hdr | mb_data | dct sz | dct part0 | ... | dct partn | - * +--------+-----------------------------------+-----------+-----+-----------+ - * | | | | | - * | v +----+---+ v - * | mb_start | src_dma_end - * v v - * first_part_offset dct size part - * (num_dct-1)*3B - * Note: - * 1. only key frame has extra 7 bytes - * 2. all offsets are base on src_dma - * 3. number of dct parts is 1, 2, 4 or 8 - * 4. the addresses set to vpu must be 64bits alignment - */ -static void rk3288_vp8d_cfg_parts(struct rk3288_vpu_ctx *ctx) -{ - const struct v4l2_ctrl_vp8_frame_hdr *hdr = ctx->run.vp8d.frame_hdr; - struct rk3288_vpu_dev *vpu = ctx->dev; - u32 dct_part_total_len = 0; - u32 dct_size_part_size = 0; - u32 dct_part_offset = 0; - u32 mb_offset_bytes = 0; - u32 mb_offset_bits = 0; - u32 mb_start_bits = 0; - struct vp8d_reg reg; - dma_addr_t src_dma; - u32 mb_size = 0; - u32 count = 0; - u32 i; - - src_dma = vb2_dma_contig_plane_dma_addr(&ctx->run.src->b, 0); - - /* - * Calculate control partition mb data info - * @macroblock_bit_offset: bits offset of mb data from first - * part start pos - * @mb_offset_bits: bits offset of mb data from src_dma - * base addr - * @mb_offset_byte: bytes offset of mb data from src_dma - * base addr - * @mb_start_bits: bits offset of mb data from mb data - * 64bits alignment addr - */ - mb_offset_bits = hdr->first_part_offset * 8 - + hdr->macroblock_bit_offset + 8; - mb_offset_bytes = mb_offset_bits / 8; - mb_start_bits = mb_offset_bits - - (mb_offset_bytes & (~DEC_8190_ALIGN_MASK)) * 8; - mb_size = hdr->first_part_size - - (mb_offset_bytes - hdr->first_part_offset) - + (mb_offset_bytes & DEC_8190_ALIGN_MASK); - - /* mb data aligned base addr */ - vdpu_write_relaxed(vpu, (mb_offset_bytes & (~DEC_8190_ALIGN_MASK)) - + src_dma, VDPU_REG_ADDR_REF(13)); - - /* mb data start bits */ - reg.base = VDPU_REG_DEC_CTRL2; - reg.mask = 0x3f; - reg.shift = 18; - vp8d_reg_write(vpu, ®, mb_start_bits); - - /* mb aligned data length */ - reg.base = VDPU_REG_DEC_CTRL6; - reg.mask = 0x3fffff; - reg.shift = 0; - vp8d_reg_write(vpu, ®, mb_size); - - /* - * Calculate dct partition info - * @dct_size_part_size: Containing sizes of dct part, every dct part - * has 3 bytes to store its size, except the last - * dct part - * @dct_part_offset: bytes offset of dct parts from src_dma base addr - * @dct_part_total_len: total size of all dct parts - */ - dct_size_part_size = (hdr->num_dct_parts - 1) * 3; - dct_part_offset = hdr->first_part_offset + hdr->first_part_size; - for (i = 0; i < hdr->num_dct_parts; i++) - dct_part_total_len += hdr->dct_part_sizes[i]; - dct_part_total_len += dct_size_part_size; - dct_part_total_len += (dct_part_offset & DEC_8190_ALIGN_MASK); - - /* number of dct partitions */ - reg.base = VDPU_REG_DEC_CTRL6; - reg.mask = 0xf; - reg.shift = 24; - vp8d_reg_write(vpu, ®, hdr->num_dct_parts - 1); - - /* dct partition length */ - vdpu_write_relaxed(vpu, - VDPU_REG_DEC_CTRL3_STREAM_LEN(dct_part_total_len), - VDPU_REG_DEC_CTRL3); - - /* dct partitions base address */ - for (i = 0; i < hdr->num_dct_parts; i++) { - u32 byte_offset = dct_part_offset + dct_size_part_size + count; - u32 base_addr = byte_offset + src_dma; - - vp8d_reg_write(vpu, &vp8d_dct_base[i], - base_addr & (~DEC_8190_ALIGN_MASK)); - - vp8d_reg_write(vpu, &vp8d_dct_start_bits[i], - (byte_offset & DEC_8190_ALIGN_MASK) * 8); - - count += hdr->dct_part_sizes[i]; - } -} - -/* - * prediction filter taps - * normal 6-tap filters - */ -static void rk3288_vp8d_cfg_tap(struct rk3288_vpu_ctx *ctx) -{ - const struct v4l2_ctrl_vp8_frame_hdr *hdr = ctx->run.vp8d.frame_hdr; - struct rk3288_vpu_dev *vpu = ctx->dev; - struct vp8d_reg reg; - u32 val = 0; - int i, j; - - reg.base = VDPU_REG_BD_REF_PIC(3); - reg.mask = 0xf; - - if ((hdr->version & 0x03) != 0) - return; /* Tap filter not used. */ - - - for (i = 0; i < 8; i++) { - val = (vp8d_mc_filter[i][0] << 2) | vp8d_mc_filter[i][5]; - - for (j = 0; j < 4; j++) - vp8d_reg_write(vpu, &vp8d_pred_bc_tap[i][j], - vp8d_mc_filter[i][j + 1]); - - switch (i) { - case 2: - reg.shift = 8; - break; - case 4: - reg.shift = 4; - break; - case 6: - reg.shift = 0; - break; - default: - continue; - } - - vp8d_reg_write(vpu, ®, val); - } -} - -/* set reference frame */ -static void rk3288_vp8d_cfg_ref(struct rk3288_vpu_ctx *ctx) -{ - u32 reg; - struct vb2_buffer *buf; - struct rk3288_vpu_dev *vpu = ctx->dev; - const struct v4l2_ctrl_vp8_frame_hdr *hdr = ctx->run.vp8d.frame_hdr; - - /* set last frame address */ - if (hdr->last_frame >= ctx->vq_dst.num_buffers) - buf = &ctx->run.dst->b; - else - buf = ctx->dst_bufs[hdr->last_frame]; - - if (!hdr->key_frame) - vdpu_write_relaxed(vpu, - vb2_dma_contig_plane_dma_addr(&ctx->run.dst->b, 0), - VDPU_REG_ADDR_REF(0)); - else - vdpu_write_relaxed(vpu, vb2_dma_contig_plane_dma_addr(buf, 0), - VDPU_REG_ADDR_REF(0)); - - /* set golden reference frame buffer address */ - if (hdr->golden_frame >= ctx->vq_dst.num_buffers) - buf = &ctx->run.dst->b; - else - buf = ctx->dst_bufs[hdr->golden_frame]; - - reg = vb2_dma_contig_plane_dma_addr(buf, 0); - if (hdr->sign_bias_golden) - reg |= VDPU_REG_ADDR_REF_TOPC_E; - vdpu_write_relaxed(vpu, reg, VDPU_REG_ADDR_REF(4)); - - /* set alternate reference frame buffer address */ - if (hdr->alt_frame >= ctx->vq_dst.num_buffers) - buf = &ctx->run.dst->b; - else - buf = ctx->dst_bufs[hdr->alt_frame]; - - reg = vb2_dma_contig_plane_dma_addr(buf, 0); - if (hdr->sign_bias_alternate) - reg |= VDPU_REG_ADDR_REF_TOPC_E; - vdpu_write_relaxed(vpu, reg, VDPU_REG_ADDR_REF(5)); -} - -static void rk3288_vp8d_cfg_buffers(struct rk3288_vpu_ctx *ctx) -{ - const struct v4l2_ctrl_vp8_frame_hdr *hdr = ctx->run.vp8d.frame_hdr; - struct rk3288_vpu_dev *vpu = ctx->dev; - u32 reg; - - /* set probability table buffer address */ - vdpu_write_relaxed(vpu, ctx->hw.vp8d.prob_tbl.dma, - VDPU_REG_ADDR_QTABLE); - - /* set segment map address */ - reg = 0; - reg = VDPU_REG_FWD_PIC1_SEGMENT_BASE(ctx->hw.vp8d.segment_map.dma); - if (hdr->sgmnt_hdr.flags & V4L2_VP8_SEGMNT_HDR_FLAG_ENABLED) { - reg |= VDPU_REG_FWD_PIC1_SEGMENT_E; - if (hdr->sgmnt_hdr.flags & V4L2_VP8_SEGMNT_HDR_FLAG_UPDATE_MAP) - reg |= VDPU_REG_FWD_PIC1_SEGMENT_UPD_E; - } - vdpu_write_relaxed(vpu, reg, VDPU_REG_FWD_PIC(0)); - - /* set output frame buffer address */ - vdpu_write_relaxed(vpu, - vb2_dma_contig_plane_dma_addr(&ctx->run.dst->b, 0), - VDPU_REG_ADDR_DST); -} - -int rk3288_vpu_vp8d_init(struct rk3288_vpu_ctx *ctx) -{ - struct rk3288_vpu_dev *vpu = ctx->dev; - unsigned int mb_width, mb_height; - size_t segment_map_size; - int ret; - - /* segment map table size calculation */ - mb_width = MB_WIDTH(ctx->dst_fmt.width); - mb_height = MB_HEIGHT(ctx->dst_fmt.height); - segment_map_size = round_up(DIV_ROUND_UP(mb_width * mb_height, 4), 64); - - /* - * In context init the dma buffer for segment map must be allocated. - * And the data in segment map buffer must be set to all zero. - */ - ret = rk3288_vpu_aux_buf_alloc(vpu, &ctx->hw.vp8d.segment_map, - segment_map_size); - if (ret) { - vpu_err("allocate segment map mem failed\n"); - return ret; - } - memset(ctx->hw.vp8d.segment_map.cpu, 0, ctx->hw.vp8d.segment_map.size); - - /* - * Allocate probability table buffer, - * total 1208 bytes, 4K page is far enough. - */ - ret = rk3288_vpu_aux_buf_alloc(vpu, &ctx->hw.vp8d.prob_tbl, - sizeof(struct vp8_prob_tbl_packed)); - if (ret) { - vpu_err("allocate prob table mem failed\n"); - goto prob_table_failed; - } - - return 0; - -prob_table_failed: - rk3288_vpu_aux_buf_free(vpu, &ctx->hw.vp8d.segment_map); - - return ret; -} - -void rk3288_vpu_vp8d_exit(struct rk3288_vpu_ctx *ctx) -{ - struct rk3288_vpu_dev *vpu = ctx->dev; - - rk3288_vpu_aux_buf_free(vpu, &ctx->hw.vp8d.segment_map); - rk3288_vpu_aux_buf_free(vpu, &ctx->hw.vp8d.prob_tbl); -} - -void rk3288_vpu_vp8d_run(struct rk3288_vpu_ctx *ctx) -{ - const struct v4l2_ctrl_vp8_frame_hdr *hdr = ctx->run.vp8d.frame_hdr; - struct rk3288_vpu_dev *vpu = ctx->dev; - size_t height = ctx->dst_fmt.height; - size_t width = ctx->dst_fmt.width; - u32 mb_width, mb_height; - u32 reg; - - rk3288_vp8d_dump_hdr(ctx); - - /* reset segment_map buffer in keyframe */ - if (!hdr->key_frame && ctx->hw.vp8d.segment_map.cpu) - memset(ctx->hw.vp8d.segment_map.cpu, 0, - ctx->hw.vp8d.segment_map.size); - - rk3288_vp8d_prob_update(ctx); - - rk3288_vpu_power_on(vpu); - - reg = VDPU_REG_CONFIG_DEC_TIMEOUT_E - | VDPU_REG_CONFIG_DEC_STRENDIAN_E - | VDPU_REG_CONFIG_DEC_INSWAP32_E - | VDPU_REG_CONFIG_DEC_STRSWAP32_E - | VDPU_REG_CONFIG_DEC_OUTSWAP32_E - | VDPU_REG_CONFIG_DEC_CLK_GATE_E - | VDPU_REG_CONFIG_DEC_IN_ENDIAN - | VDPU_REG_CONFIG_DEC_OUT_ENDIAN - | VDPU_REG_CONFIG_DEC_MAX_BURST(16); - vdpu_write_relaxed(vpu, reg, VDPU_REG_CONFIG); - - reg = VDPU_REG_DEC_CTRL0_DEC_MODE(10); - if (hdr->key_frame) - reg |= VDPU_REG_DEC_CTRL0_PIC_INTER_E; - if (!(hdr->flags & V4L2_VP8_FRAME_HDR_FLAG_MB_NO_SKIP_COEFF)) - reg |= VDPU_REG_DEC_CTRL0_SKIP_MODE; - if (hdr->lf_hdr.level == 0) - reg |= VDPU_REG_DEC_CTRL0_FILTERING_DIS; - vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_CTRL0); - - /* frame dimensions */ - mb_width = MB_WIDTH(width); - mb_height = MB_HEIGHT(height); - reg = VDPU_REG_DEC_CTRL1_PIC_MB_WIDTH(mb_width) - | VDPU_REG_DEC_CTRL1_PIC_MB_HEIGHT_P(mb_height) - | VDPU_REG_DEC_CTRL1_PIC_MB_W_EXT(mb_width >> 9) - | VDPU_REG_DEC_CTRL1_PIC_MB_H_EXT(mb_height >> 8); - vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_CTRL1); - - /* bool decode info */ - reg = VDPU_REG_DEC_CTRL2_BOOLEAN_RANGE(hdr->bool_dec_range) - | VDPU_REG_DEC_CTRL2_BOOLEAN_VALUE(hdr->bool_dec_value); - vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_CTRL2); - - reg = 0; - if (hdr->version != 3) - reg |= VDPU_REG_DEC_CTRL4_VC1_HEIGHT_EXT; - if (hdr->version & 0x3) - reg |= VDPU_REG_DEC_CTRL4_BILIN_MC_E; - vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_CTRL4); - - rk3288_vp8d_cfg_lf(ctx); - rk3288_vp8d_cfg_qp(ctx); - rk3288_vp8d_cfg_parts(ctx); - rk3288_vp8d_cfg_tap(ctx); - rk3288_vp8d_cfg_ref(ctx); - rk3288_vp8d_cfg_buffers(ctx); - - schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); - - vdpu_write(vpu, VDPU_REG_INTERRUPT_DEC_E, VDPU_REG_INTERRUPT); -} diff --git a/drivers/media/platform/rk3288-vpu/rk3288_vpu_hw_vp8e.c b/drivers/media/platform/rk3288-vpu/rk3288_vpu_hw_vp8e.c deleted file mode 100644 index ce02712dc9fc..000000000000 --- a/drivers/media/platform/rk3288-vpu/rk3288_vpu_hw_vp8e.c +++ /dev/null @@ -1,534 +0,0 @@ -/* - * Rockchip RK3288 VPU codec driver - * - * Copyright (C) 2014 Rockchip Electronics Co., Ltd. - * Alpha Lin - * Jeffy Chen - * - * Copyright (C) 2014 Google, Inc. - * Tomasz Figa - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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 "rk3288_vpu_common.h" - -#include -#include - -#include "rk3288_vpu_regs.h" -#include "rk3288_vpu_hw.h" - -/* Various parameters specific to VP8 encoder. */ -#define VP8_CABAC_CTX_OFFSET 192 -#define VP8_CABAC_CTX_SIZE ((55 + 96) << 3) - -#define VP8_KEY_FRAME_HDR_SIZE 10 -#define VP8_INTER_FRAME_HDR_SIZE 3 - -#define VP8_FRAME_TAG_KEY_FRAME_BIT BIT(0) -#define VP8_FRAME_TAG_LENGTH_SHIFT 5 -#define VP8_FRAME_TAG_LENGTH_MASK (0x7ffff << 5) - -/** - * struct rk3288_vpu_vp8e_ctrl_buf - hardware control buffer layout - * @ext_hdr_size: Ext header size in bytes (written by hardware). - * @dct_size: DCT partition size (written by hardware). - * @rsvd: Reserved for hardware. - */ -struct rk3288_vpu_vp8e_ctrl_buf { - u32 ext_hdr_size; - u32 dct_size; - u8 rsvd[1016]; -}; - -/* - * The hardware takes care only of ext hdr and dct partition. The software - * must take care of frame header. - * - * Buffer layout as received from hardware: - * |<--gap-->|<--ext hdr-->|<-gap->|<---dct part--- - * |<-------dct part offset------->| - * - * Required buffer layout: - * |<--hdr-->|<--ext hdr-->|<---dct part--- - */ -void rk3288_vpu_vp8e_assemble_bitstream(struct rk3288_vpu_ctx *ctx, - struct rk3288_vpu_buf *dst_buf) -{ - size_t ext_hdr_size = dst_buf->vp8e.ext_hdr_size; - size_t dct_size = dst_buf->vp8e.dct_size; - size_t hdr_size = dst_buf->vp8e.hdr_size; - size_t dst_size; - size_t tag_size; - void *dst; - u32 *tag; - - dst_size = vb2_plane_size(&dst_buf->b, 0); - dst = vb2_plane_vaddr(&dst_buf->b, 0); - tag = dst; /* To access frame tag words. */ - - if (WARN_ON(hdr_size + ext_hdr_size + dct_size > dst_size)) - return; - if (WARN_ON(dst_buf->vp8e.dct_offset + dct_size > dst_size)) - return; - - vpu_debug(1, "%s: hdr_size = %u, ext_hdr_size = %u, dct_size = %u\n", - __func__, hdr_size, ext_hdr_size, dct_size); - - memmove(dst + hdr_size + ext_hdr_size, - dst + dst_buf->vp8e.dct_offset, dct_size); - memcpy(dst, dst_buf->vp8e.header, hdr_size); - - /* Patch frame tag at first 32-bit word of the frame. */ - if (dst_buf->b.v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) { - tag_size = VP8_KEY_FRAME_HDR_SIZE; - tag[0] &= ~VP8_FRAME_TAG_KEY_FRAME_BIT; - } else { - tag_size = VP8_INTER_FRAME_HDR_SIZE; - tag[0] |= VP8_FRAME_TAG_KEY_FRAME_BIT; - } - - tag[0] &= ~VP8_FRAME_TAG_LENGTH_MASK; - tag[0] |= (hdr_size + ext_hdr_size - tag_size) - << VP8_FRAME_TAG_LENGTH_SHIFT; - - vb2_set_plane_payload(&dst_buf->b, 0, - hdr_size + ext_hdr_size + dct_size); -} - -static inline unsigned int ref_luma_size(unsigned int w, unsigned int h) -{ - return round_up(w, MB_DIM) * round_up(h, MB_DIM); -} - -int rk3288_vpu_vp8e_init(struct rk3288_vpu_ctx *ctx) -{ - struct rk3288_vpu_dev *vpu = ctx->dev; - size_t height = ctx->src_fmt.height; - size_t width = ctx->src_fmt.width; - size_t ref_buf_size; - size_t mv_size; - int ret; - - ret = rk3288_vpu_aux_buf_alloc(vpu, &ctx->hw.vp8e.ctrl_buf, - sizeof(struct rk3288_vpu_vp8e_ctrl_buf)); - if (ret) { - vpu_err("failed to allocate ctrl buffer\n"); - return ret; - } - - mv_size = DIV_ROUND_UP(width, 16) * DIV_ROUND_UP(height, 16) / 4; - ret = rk3288_vpu_aux_buf_alloc(vpu, &ctx->hw.vp8e.mv_buf, mv_size); - if (ret) { - vpu_err("failed to allocate MV buffer\n"); - goto err_ctrl_buf; - } - - ref_buf_size = ref_luma_size(width, height) * 3 / 2; - ret = rk3288_vpu_aux_buf_alloc(vpu, &ctx->hw.vp8e.ext_buf, - 2 * ref_buf_size); - if (ret) { - vpu_err("failed to allocate ext buffer\n"); - goto err_mv_buf; - } - - return 0; - -err_mv_buf: - rk3288_vpu_aux_buf_free(vpu, &ctx->hw.vp8e.mv_buf); -err_ctrl_buf: - rk3288_vpu_aux_buf_free(vpu, &ctx->hw.vp8e.ctrl_buf); - - return ret; -} - -void rk3288_vpu_vp8e_exit(struct rk3288_vpu_ctx *ctx) -{ - struct rk3288_vpu_dev *vpu = ctx->dev; - - rk3288_vpu_aux_buf_free(vpu, &ctx->hw.vp8e.ext_buf); - rk3288_vpu_aux_buf_free(vpu, &ctx->hw.vp8e.mv_buf); - rk3288_vpu_aux_buf_free(vpu, &ctx->hw.vp8e.ctrl_buf); -} - -static inline u32 enc_in_img_ctrl(struct rk3288_vpu_ctx *ctx) -{ - struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; - struct v4l2_rect *crop = &ctx->src_crop; - unsigned bytes_per_line, overfill_r, overfill_b; - - /* - * The hardware needs only the value for luma plane, because - * values of other planes are calculated internally based on - * format setting. - */ - bytes_per_line = pix_fmt->plane_fmt[0].bytesperline; - overfill_r = (pix_fmt->width - crop->width) / 4; - overfill_b = pix_fmt->height - crop->height; - - return VEPU_REG_IN_IMG_CTRL_ROW_LEN(bytes_per_line) - | VEPU_REG_IN_IMG_CTRL_OVRFLR_D4(overfill_r) - | VEPU_REG_IN_IMG_CTRL_OVRFLB_D4(overfill_b) - | VEPU_REG_IN_IMG_CTRL_FMT(ctx->vpu_src_fmt->enc_fmt); -} - -static void rk3288_vpu_vp8e_set_buffers(struct rk3288_vpu_dev *vpu, - struct rk3288_vpu_ctx *ctx) -{ - const struct rk3288_vp8e_reg_params *params = ctx->run.vp8e.reg_params; - dma_addr_t ref_buf_dma, rec_buf_dma; - dma_addr_t stream_dma; - size_t rounded_size; - dma_addr_t dst_dma; - u32 start_offset; - size_t dst_size; - - rounded_size = ref_luma_size(ctx->src_fmt.width, - ctx->src_fmt.height); - - ref_buf_dma = rec_buf_dma = ctx->hw.vp8e.ext_buf.dma; - if (ctx->hw.vp8e.ref_rec_ptr) - ref_buf_dma += rounded_size * 3 / 2; - else - rec_buf_dma += rounded_size * 3 / 2; - ctx->hw.vp8e.ref_rec_ptr ^= 1; - - if (rk3288_vpu_ctx_is_dummy_encode(ctx)) { - dst_dma = vpu->dummy_encode_dst.dma; - dst_size = vpu->dummy_encode_dst.size; - } else { - dst_dma = vb2_dma_contig_plane_dma_addr(&ctx->run.dst->b, 0); - dst_size = vb2_plane_size(&ctx->run.dst->b, 0); - } - - /* - * stream addr-->| - * align 64bits->|<-start offset->| - * |<---------header size-------->|<---dst buf--- - */ - start_offset = (params->rlc_ctrl & VEPU_REG_RLC_CTRL_STR_OFFS_MASK) - >> VEPU_REG_RLC_CTRL_STR_OFFS_SHIFT; - stream_dma = dst_dma + params->hdr_len; - - /** - * Userspace will pass 8 bytes aligned size(round_down) to us, - * so we need to plus start offset to get real header size. - * - * |<-aligned size->|<-start offset->| - * |<----------header size---------->| - */ - ctx->run.dst->vp8e.hdr_size = params->hdr_len + (start_offset >> 3); - - if (params->enc_ctrl & VEPU_REG_ENC_CTRL_KEYFRAME_BIT) - ctx->run.dst->b.v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME; - else - ctx->run.dst->b.v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME; - - /* - * We assume here that 1/10 of the buffer is enough for headers. - * DCT partition will be placed in remaining 9/10 of the buffer. - */ - ctx->run.dst->vp8e.dct_offset = round_up(dst_size / 10, 8); - - /* Destination buffer. */ - vepu_write_relaxed(vpu, stream_dma, VEPU_REG_ADDR_OUTPUT_STREAM); - vepu_write_relaxed(vpu, dst_dma + ctx->run.dst->vp8e.dct_offset, - VEPU_REG_ADDR_VP8_DCT_PART(0)); - vepu_write_relaxed(vpu, dst_size - ctx->run.dst->vp8e.dct_offset, - VEPU_REG_STR_BUF_LIMIT); - - /* Auxilliary buffers. */ - vepu_write_relaxed(vpu, ctx->hw.vp8e.ctrl_buf.dma, - VEPU_REG_ADDR_OUTPUT_CTRL); - vepu_write_relaxed(vpu, ctx->hw.vp8e.mv_buf.dma, - VEPU_REG_ADDR_MV_OUT); - vepu_write_relaxed(vpu, ctx->run.priv_dst.dma, - VEPU_REG_ADDR_VP8_PROB_CNT); - vepu_write_relaxed(vpu, ctx->run.priv_src.dma + VP8_CABAC_CTX_OFFSET, - VEPU_REG_ADDR_CABAC_TBL); - vepu_write_relaxed(vpu, ctx->run.priv_src.dma - + VP8_CABAC_CTX_OFFSET + VP8_CABAC_CTX_SIZE, - VEPU_REG_ADDR_VP8_SEG_MAP); - - /* Reference buffers. */ - vepu_write_relaxed(vpu, ref_buf_dma, - VEPU_REG_ADDR_REF_LUMA); - vepu_write_relaxed(vpu, ref_buf_dma + rounded_size, - VEPU_REG_ADDR_REF_CHROMA); - - /* Reconstruction buffers. */ - vepu_write_relaxed(vpu, rec_buf_dma, - VEPU_REG_ADDR_REC_LUMA); - vepu_write_relaxed(vpu, rec_buf_dma + rounded_size, - VEPU_REG_ADDR_REC_CHROMA); - - /* Source buffer. */ - if (rk3288_vpu_ctx_is_dummy_encode(ctx)) { - vepu_write_relaxed(vpu, vpu->dummy_encode_src[PLANE_Y].dma, - VEPU_REG_ADDR_IN_LUMA); - vepu_write_relaxed(vpu, vpu->dummy_encode_src[PLANE_CB].dma, - VEPU_REG_ADDR_IN_CB); - vepu_write_relaxed(vpu, vpu->dummy_encode_src[PLANE_CR].dma, - VEPU_REG_ADDR_IN_CR); - } else { - vepu_write_relaxed(vpu, vb2_dma_contig_plane_dma_addr( - &ctx->run.src->b, PLANE_Y), - VEPU_REG_ADDR_IN_LUMA); - vepu_write_relaxed(vpu, vb2_dma_contig_plane_dma_addr( - &ctx->run.src->b, PLANE_CB), - VEPU_REG_ADDR_IN_CB); - vepu_write_relaxed(vpu, vb2_dma_contig_plane_dma_addr( - &ctx->run.src->b, PLANE_CR), - VEPU_REG_ADDR_IN_CR); - } - - /* Source parameters. */ - vepu_write_relaxed(vpu, enc_in_img_ctrl(ctx), VEPU_REG_IN_IMG_CTRL); -} - -static void rk3288_vpu_vp8e_set_params(struct rk3288_vpu_dev *vpu, - struct rk3288_vpu_ctx *ctx) -{ - const struct rk3288_vp8e_reg_params *params = ctx->run.vp8e.reg_params; - int i; - - vepu_write_relaxed(vpu, params->enc_ctrl0, VEPU_REG_ENC_CTRL0); - vepu_write_relaxed(vpu, params->enc_ctrl1, VEPU_REG_ENC_CTRL1); - vepu_write_relaxed(vpu, params->enc_ctrl2, VEPU_REG_ENC_CTRL2); - vepu_write_relaxed(vpu, params->enc_ctrl3, VEPU_REG_ENC_CTRL3); - vepu_write_relaxed(vpu, params->enc_ctrl5, VEPU_REG_ENC_CTRL5); - vepu_write_relaxed(vpu, params->enc_ctrl4, VEPU_REG_ENC_CTRL4); - vepu_write_relaxed(vpu, params->str_hdr_rem_msb, - VEPU_REG_STR_HDR_REM_MSB); - vepu_write_relaxed(vpu, params->str_hdr_rem_lsb, - VEPU_REG_STR_HDR_REM_LSB); - vepu_write_relaxed(vpu, params->mad_ctrl, VEPU_REG_MAD_CTRL); - - for (i = 0; i < ARRAY_SIZE(params->qp_val); ++i) - vepu_write_relaxed(vpu, params->qp_val[i], - VEPU_REG_VP8_QP_VAL(i)); - - vepu_write_relaxed(vpu, params->bool_enc, VEPU_REG_VP8_BOOL_ENC); - vepu_write_relaxed(vpu, params->vp8_ctrl0, VEPU_REG_VP8_CTRL0); - vepu_write_relaxed(vpu, params->rlc_ctrl, VEPU_REG_RLC_CTRL); - vepu_write_relaxed(vpu, params->mb_ctrl, VEPU_REG_MB_CTRL); - - for (i = 0; i < ARRAY_SIZE(params->rgb_yuv_coeff); ++i) - vepu_write_relaxed(vpu, params->rgb_yuv_coeff[i], - VEPU_REG_RGB_YUV_COEFF(i)); - - vepu_write_relaxed(vpu, params->rgb_mask_msb, - VEPU_REG_RGB_MASK_MSB); - vepu_write_relaxed(vpu, params->intra_area_ctrl, - VEPU_REG_INTRA_AREA_CTRL); - vepu_write_relaxed(vpu, params->cir_intra_ctrl, - VEPU_REG_CIR_INTRA_CTRL); - vepu_write_relaxed(vpu, params->first_roi_area, - VEPU_REG_FIRST_ROI_AREA); - vepu_write_relaxed(vpu, params->second_roi_area, - VEPU_REG_SECOND_ROI_AREA); - vepu_write_relaxed(vpu, params->mvc_ctrl, - VEPU_REG_MVC_CTRL); - - for (i = 0; i < ARRAY_SIZE(params->intra_penalty); ++i) - vepu_write_relaxed(vpu, params->intra_penalty[i], - VEPU_REG_VP8_INTRA_PENALTY(i)); - - for (i = 0; i < ARRAY_SIZE(params->seg_qp); ++i) - vepu_write_relaxed(vpu, params->seg_qp[i], - VEPU_REG_VP8_SEG_QP(i)); - - for (i = 0; i < ARRAY_SIZE(params->dmv_4p_1p_penalty); ++i) - vepu_write_relaxed(vpu, params->dmv_4p_1p_penalty[i], - VEPU_REG_DMV_4P_1P_PENALTY(i)); - - for (i = 0; i < ARRAY_SIZE(params->dmv_qpel_penalty); ++i) - vepu_write_relaxed(vpu, params->dmv_qpel_penalty[i], - VEPU_REG_DMV_QPEL_PENALTY(i)); - - vepu_write_relaxed(vpu, params->vp8_ctrl1, VEPU_REG_VP8_CTRL1); - vepu_write_relaxed(vpu, params->bit_cost_golden, - VEPU_REG_VP8_BIT_COST_GOLDEN); - - for (i = 0; i < ARRAY_SIZE(params->loop_flt_delta); ++i) - vepu_write_relaxed(vpu, params->loop_flt_delta[i], - VEPU_REG_VP8_LOOP_FLT_DELTA(i)); -} - -void rk3288_vpu_vp8e_run(struct rk3288_vpu_ctx *ctx) -{ - struct rk3288_vpu_dev *vpu = ctx->dev; - u32 reg; - - /* The hardware expects the control buffer to be zeroed. */ - memset(ctx->hw.vp8e.ctrl_buf.cpu, 0, - sizeof(struct rk3288_vpu_vp8e_ctrl_buf)); - - /* - * Program the hardware. - */ - rk3288_vpu_power_on(vpu); - - vepu_write_relaxed(vpu, VEPU_REG_ENC_CTRL_ENC_MODE_VP8, - VEPU_REG_ENC_CTRL); - - rk3288_vpu_vp8e_set_params(vpu, ctx); - rk3288_vpu_vp8e_set_buffers(vpu, ctx); - - /* Make sure that all registers are written at this point. */ - wmb(); - - /* Set the watchdog. */ - schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); - - /* Start the hardware. */ - reg = VEPU_REG_AXI_CTRL_OUTPUT_SWAP16 - | VEPU_REG_AXI_CTRL_INPUT_SWAP16 - | VEPU_REG_AXI_CTRL_BURST_LEN(16) - | VEPU_REG_AXI_CTRL_GATE_BIT - | VEPU_REG_AXI_CTRL_OUTPUT_SWAP32 - | VEPU_REG_AXI_CTRL_INPUT_SWAP32 - | VEPU_REG_AXI_CTRL_OUTPUT_SWAP8 - | VEPU_REG_AXI_CTRL_INPUT_SWAP8; - vepu_write(vpu, reg, VEPU_REG_AXI_CTRL); - - vepu_write(vpu, 0, VEPU_REG_INTERRUPT); - - reg = VEPU_REG_ENC_CTRL_NAL_MODE_BIT - | VEPU_REG_ENC_CTRL_WIDTH(MB_WIDTH(ctx->src_fmt.width)) - | VEPU_REG_ENC_CTRL_HEIGHT(MB_HEIGHT(ctx->src_fmt.height)) - | VEPU_REG_ENC_CTRL_ENC_MODE_VP8 - | VEPU_REG_ENC_CTRL_EN_BIT; - - if (ctx->run.dst->b.v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) - reg |= VEPU_REG_ENC_CTRL_KEYFRAME_BIT; - - vepu_write(vpu, reg, VEPU_REG_ENC_CTRL); -} - -void rk3288_vpu_vp8e_done(struct rk3288_vpu_ctx *ctx, - enum vb2_buffer_state result) -{ - struct rk3288_vpu_vp8e_ctrl_buf *ctrl_buf = ctx->hw.vp8e.ctrl_buf.cpu; - - /* Read length information of this run from utility buffer. */ - ctx->run.dst->vp8e.ext_hdr_size = ctrl_buf->ext_hdr_size; - ctx->run.dst->vp8e.dct_size = ctrl_buf->dct_size; - - rk3288_vpu_run_done(ctx, result); -} - -/* - * WAR for encoder state corruption after decoding - */ - -static const struct rk3288_vp8e_reg_params dummy_encode_reg_params = { - /* 00000014 */ .hdr_len = 0x00000000, - /* 00000038 */ .enc_ctrl = VEPU_REG_ENC_CTRL_KEYFRAME_BIT, - /* 00000040 */ .enc_ctrl0 = 0x00000000, - /* 00000044 */ .enc_ctrl1 = 0x00000000, - /* 00000048 */ .enc_ctrl2 = 0x00040014, - /* 0000004c */ .enc_ctrl3 = 0x404083c0, - /* 00000050 */ .enc_ctrl5 = 0x01006bff, - /* 00000054 */ .enc_ctrl4 = 0x00000039, - /* 00000058 */ .str_hdr_rem_msb = 0x85848805, - /* 0000005c */ .str_hdr_rem_lsb = 0x02000000, - /* 00000064 */ .mad_ctrl = 0x00000000, - /* 0000006c */ .qp_val = { - /* 0000006c */ 0x020213b1, - /* 00000070 */ 0x02825249, - /* 00000074 */ 0x048409d8, - /* 00000078 */ 0x03834c30, - /* 0000007c */ 0x020213b1, - /* 00000080 */ 0x02825249, - /* 00000084 */ 0x00340e0d, - /* 00000088 */ 0x401c1a15, - }, - /* 0000008c */ .bool_enc = 0x00018140, - /* 00000090 */ .vp8_ctrl0 = 0x000695c0, - /* 00000094 */ .rlc_ctrl = 0x14000000, - /* 00000098 */ .mb_ctrl = 0x00000000, - /* 000000d4 */ .rgb_yuv_coeff = { - /* 000000d4 */ 0x962b4c85, - /* 000000d8 */ 0x90901d50, - }, - /* 000000dc */ .rgb_mask_msb = 0x0000b694, - /* 000000e0 */ .intra_area_ctrl = 0xffffffff, - /* 000000e4 */ .cir_intra_ctrl = 0x00000000, - /* 000000f0 */ .first_roi_area = 0xffffffff, - /* 000000f4 */ .second_roi_area = 0xffffffff, - /* 000000f8 */ .mvc_ctrl = 0x01780000, - /* 00000100 */ .intra_penalty = { - /* 00000100 */ 0x00010005, - /* 00000104 */ 0x00015011, - /* 00000108 */ 0x0000c005, - /* 0000010c */ 0x00016010, - /* 00000110 */ 0x0001a018, - /* 00000114 */ 0x00018015, - /* 00000118 */ 0x0001d01a, - }, - /* 00000120 */ .seg_qp = { - /* 00000120 */ 0x020213b1, - /* 00000124 */ 0x02825249, - /* 00000128 */ 0x048409d8, - /* 0000012c */ 0x03834c30, - /* 00000130 */ 0x020213b1, - /* 00000134 */ 0x02825249, - /* 00000138 */ 0x00340e0d, - /* 0000013c */ 0x341c1a15, - /* 00000140 */ 0x020213b1, - /* 00000144 */ 0x02825249, - /* 00000148 */ 0x048409d8, - /* 0000014c */ 0x03834c30, - /* 00000150 */ 0x020213b1, - /* 00000154 */ 0x02825249, - /* 00000158 */ 0x00340e0d, - /* 0000015c */ 0x341c1a15, - /* 00000160 */ 0x020213b1, - /* 00000164 */ 0x02825249, - /* 00000168 */ 0x048409d8, - /* 0000016c */ 0x03834c30, - /* 00000170 */ 0x020213b1, - /* 00000174 */ 0x02825249, - /* 00000178 */ 0x00340e0d, - /* 0000017c */ 0x341c1a15, - }, - /* 00000180 */ .dmv_4p_1p_penalty = { - /* 00000180 */ 0x00020406, - /* 00000184 */ 0x080a0c0e, - /* 00000188 */ 0x10121416, - /* 0000018c */ 0x181a1c1e, - /* 00000190 */ 0x20222426, - /* 00000194 */ 0x282a2c2e, - /* 00000198 */ 0x30323436, - /* 0000019c */ 0x383a3c3e, - /* 000001a0 */ 0x40424446, - /* 000001a4 */ 0x484a4c4e, - /* 000001a8 */ 0x50525456, - /* 000001ac */ 0x585a5c5e, - /* 000001b0 */ 0x60626466, - /* 000001b4 */ 0x686a6c6e, - /* 000001b8 */ 0x70727476, - /* NOTE: Further 17 registers set to 0. */ - }, - /* - * NOTE: Following registers all set to 0: - * - dmv_qpel_penalty, - * - vp8_ctrl1, - * - bit_cost_golden, - * - loop_flt_delta. - */ -}; - -const struct rk3288_vp8e_reg_params *rk3288_vpu_vp8e_get_dummy_params(void) -{ - return &dummy_encode_reg_params; -} diff --git a/drivers/media/platform/rk3288-vpu/rk3288_vpu_regs.h b/drivers/media/platform/rk3288-vpu/rk3288_vpu_regs.h deleted file mode 100644 index 618757e9bb34..000000000000 --- a/drivers/media/platform/rk3288-vpu/rk3288_vpu_regs.h +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Rockchip RK3288 VPU codec driver - * - * Copyright (C) 2014 Google, Inc. - * Tomasz Figa - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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 RK3288_VPU_REGS_H_ -#define RK3288_VPU_REGS_H_ - -/* Encoder registers. */ -#define VEPU_REG_INTERRUPT 0x004 -#define VEPU_REG_INTERRUPT_DIS_BIT BIT(1) -#define VEPU_REG_INTERRUPT_BIT BIT(0) -#define VEPU_REG_AXI_CTRL 0x008 -#define VEPU_REG_AXI_CTRL_OUTPUT_SWAP16 BIT(15) -#define VEPU_REG_AXI_CTRL_INPUT_SWAP16 BIT(14) -#define VEPU_REG_AXI_CTRL_BURST_LEN(x) ((x) << 8) -#define VEPU_REG_AXI_CTRL_GATE_BIT BIT(4) -#define VEPU_REG_AXI_CTRL_OUTPUT_SWAP32 BIT(3) -#define VEPU_REG_AXI_CTRL_INPUT_SWAP32 BIT(2) -#define VEPU_REG_AXI_CTRL_OUTPUT_SWAP8 BIT(1) -#define VEPU_REG_AXI_CTRL_INPUT_SWAP8 BIT(0) -#define VEPU_REG_ADDR_OUTPUT_STREAM 0x014 -#define VEPU_REG_ADDR_OUTPUT_CTRL 0x018 -#define VEPU_REG_ADDR_REF_LUMA 0x01c -#define VEPU_REG_ADDR_REF_CHROMA 0x020 -#define VEPU_REG_ADDR_REC_LUMA 0x024 -#define VEPU_REG_ADDR_REC_CHROMA 0x028 -#define VEPU_REG_ADDR_IN_LUMA 0x02c -#define VEPU_REG_ADDR_IN_CB 0x030 -#define VEPU_REG_ADDR_IN_CR 0x034 -#define VEPU_REG_ENC_CTRL 0x038 -#define VEPU_REG_ENC_CTRL_NAL_MODE_BIT BIT(29) -#define VEPU_REG_ENC_CTRL_WIDTH(w) ((w) << 19) -#define VEPU_REG_ENC_CTRL_HEIGHT(h) ((h) << 10) -#define VEPU_REG_ENC_CTRL_KEYFRAME_BIT BIT(3) -#define VEPU_REG_ENC_CTRL_ENC_MODE_VP8 (0x1 << 1) -#define VEPU_REG_ENC_CTRL_EN_BIT BIT(0) -#define VEPU_REG_IN_IMG_CTRL 0x03c -#define VEPU_REG_IN_IMG_CTRL_ROW_LEN(x) ((x) << 12) -#define VEPU_REG_IN_IMG_CTRL_OVRFLR_D4(x) ((x) << 10) -#define VEPU_REG_IN_IMG_CTRL_OVRFLB_D4(x) ((x) << 6) -#define VEPU_REG_IN_IMG_CTRL_FMT(x) ((x) << 2) -#define VEPU_REG_ENC_CTRL0 0x040 -#define VEPU_REG_ENC_CTRL1 0x044 -#define VEPU_REG_ENC_CTRL2 0x048 -#define VEPU_REG_ENC_CTRL3 0x04c -#define VEPU_REG_ENC_CTRL5 0x050 -#define VEPU_REG_ENC_CTRL4 0x054 -#define VEPU_REG_STR_HDR_REM_MSB 0x058 -#define VEPU_REG_STR_HDR_REM_LSB 0x05c -#define VEPU_REG_STR_BUF_LIMIT 0x060 -#define VEPU_REG_MAD_CTRL 0x064 -#define VEPU_REG_ADDR_VP8_PROB_CNT 0x068 -#define VEPU_REG_QP_VAL 0x06c -#define VEPU_REG_VP8_QP_VAL(i) (0x06c + ((i) * 0x4)) -#define VEPU_REG_CHECKPOINT(i) (0x070 + ((i) * 0x4)) -#define VEPU_REG_CHKPT_WORD_ERR(i) (0x084 + ((i) * 0x4)) -#define VEPU_REG_VP8_BOOL_ENC 0x08c -#define VEPU_REG_CHKPT_DELTA_QP 0x090 -#define VEPU_REG_VP8_CTRL0 0x090 -#define VEPU_REG_RLC_CTRL 0x094 -#define VEPU_REG_RLC_CTRL_STR_OFFS_SHIFT 23 -#define VEPU_REG_RLC_CTRL_STR_OFFS_MASK (0x3f << 23) -#define VEPU_REG_MB_CTRL 0x098 -#define VEPU_REG_ADDR_CABAC_TBL 0x0cc -#define VEPU_REG_ADDR_MV_OUT 0x0d0 -#define VEPU_REG_RGB_YUV_COEFF(i) (0x0d4 + ((i) * 0x4)) -#define VEPU_REG_RGB_MASK_MSB 0x0dc -#define VEPU_REG_INTRA_AREA_CTRL 0x0e0 -#define VEPU_REG_CIR_INTRA_CTRL 0x0e4 -#define VEPU_REG_INTRA_SLICE_BITMAP(i) (0x0e8 + ((i) * 0x4)) -#define VEPU_REG_ADDR_VP8_DCT_PART(i) (0x0e8 + ((i) * 0x4)) -#define VEPU_REG_FIRST_ROI_AREA 0x0f0 -#define VEPU_REG_SECOND_ROI_AREA 0x0f4 -#define VEPU_REG_MVC_CTRL 0x0f8 -#define VEPU_REG_VP8_INTRA_PENALTY(i) (0x100 + ((i) * 0x4)) -#define VEPU_REG_ADDR_VP8_SEG_MAP 0x11c -#define VEPU_REG_VP8_SEG_QP(i) (0x120 + ((i) * 0x4)) -#define VEPU_REG_DMV_4P_1P_PENALTY(i) (0x180 + ((i) * 0x4)) -#define VEPU_REG_DMV_QPEL_PENALTY(i) (0x200 + ((i) * 0x4)) -#define VEPU_REG_VP8_CTRL1 0x280 -#define VEPU_REG_VP8_BIT_COST_GOLDEN 0x284 -#define VEPU_REG_VP8_LOOP_FLT_DELTA(i) (0x288 + ((i) * 0x4)) - -/* Decoder registers. */ -#define VDPU_REG_INTERRUPT 0x004 -#define VDPU_REG_INTERRUPT_DEC_PIC_INF BIT(24) -#define VDPU_REG_INTERRUPT_DEC_TIMEOUT BIT(18) -#define VDPU_REG_INTERRUPT_DEC_SLICE_INT BIT(17) -#define VDPU_REG_INTERRUPT_DEC_ERROR_INT BIT(16) -#define VDPU_REG_INTERRUPT_DEC_ASO_INT BIT(15) -#define VDPU_REG_INTERRUPT_DEC_BUFFER_INT BIT(14) -#define VDPU_REG_INTERRUPT_DEC_BUS_INT BIT(13) -#define VDPU_REG_INTERRUPT_DEC_RDY_INT BIT(12) -#define VDPU_REG_INTERRUPT_DEC_IRQ BIT(8) -#define VDPU_REG_INTERRUPT_DEC_IRQ_DIS BIT(4) -#define VDPU_REG_INTERRUPT_DEC_E BIT(0) -#define VDPU_REG_CONFIG 0x008 -#define VDPU_REG_CONFIG_DEC_AXI_RD_ID(x) (((x) & 0xff) << 24) -#define VDPU_REG_CONFIG_DEC_TIMEOUT_E BIT(23) -#define VDPU_REG_CONFIG_DEC_STRSWAP32_E BIT(22) -#define VDPU_REG_CONFIG_DEC_STRENDIAN_E BIT(21) -#define VDPU_REG_CONFIG_DEC_INSWAP32_E BIT(20) -#define VDPU_REG_CONFIG_DEC_OUTSWAP32_E BIT(19) -#define VDPU_REG_CONFIG_DEC_DATA_DISC_E BIT(18) -#define VDPU_REG_CONFIG_TILED_MODE_MSB BIT(17) -#define VDPU_REG_CONFIG_DEC_OUT_TILED_E BIT(17) -#define VDPU_REG_CONFIG_DEC_LATENCY(x) (((x) & 0x3f) << 11) -#define VDPU_REG_CONFIG_DEC_CLK_GATE_E BIT(10) -#define VDPU_REG_CONFIG_DEC_IN_ENDIAN BIT(9) -#define VDPU_REG_CONFIG_DEC_OUT_ENDIAN BIT(8) -#define VDPU_REG_CONFIG_PRIORITY_MODE(x) (((x) & 0x7) << 5) -#define VDPU_REG_CONFIG_TILED_MODE_LSB BIT(7) -#define VDPU_REG_CONFIG_DEC_ADV_PRE_DIS BIT(6) -#define VDPU_REG_CONFIG_DEC_SCMD_DIS BIT(5) -#define VDPU_REG_CONFIG_DEC_MAX_BURST(x) (((x) & 0x1f) << 0) -#define VDPU_REG_DEC_CTRL0 0x00c -#define VDPU_REG_DEC_CTRL0_DEC_MODE(x) (((x) & 0xf) << 28) -#define VDPU_REG_DEC_CTRL0_RLC_MODE_E BIT(27) -#define VDPU_REG_DEC_CTRL0_SKIP_MODE BIT(26) -#define VDPU_REG_DEC_CTRL0_DIVX3_E BIT(25) -#define VDPU_REG_DEC_CTRL0_PJPEG_E BIT(24) -#define VDPU_REG_DEC_CTRL0_PIC_INTERLACE_E BIT(23) -#define VDPU_REG_DEC_CTRL0_PIC_FIELDMODE_E BIT(22) -#define VDPU_REG_DEC_CTRL0_PIC_B_E BIT(21) -#define VDPU_REG_DEC_CTRL0_PIC_INTER_E BIT(20) -#define VDPU_REG_DEC_CTRL0_PIC_TOPFIELD_E BIT(19) -#define VDPU_REG_DEC_CTRL0_FWD_INTERLACE_E BIT(18) -#define VDPU_REG_DEC_CTRL0_SORENSON_E BIT(17) -#define VDPU_REG_DEC_CTRL0_REF_TOPFIELD_E BIT(16) -#define VDPU_REG_DEC_CTRL0_DEC_OUT_DIS BIT(15) -#define VDPU_REG_DEC_CTRL0_FILTERING_DIS BIT(14) -#define VDPU_REG_DEC_CTRL0_WEBP_E BIT(13) -#define VDPU_REG_DEC_CTRL0_MVC_E BIT(13) -#define VDPU_REG_DEC_CTRL0_PIC_FIXED_QUANT BIT(13) -#define VDPU_REG_DEC_CTRL0_WRITE_MVS_E BIT(12) -#define VDPU_REG_DEC_CTRL0_REFTOPFIRST_E BIT(11) -#define VDPU_REG_DEC_CTRL0_SEQ_MBAFF_E BIT(10) -#define VDPU_REG_DEC_CTRL0_PICORD_COUNT_E BIT(9) -#define VDPU_REG_DEC_CTRL0_DEC_AHB_HLOCK_E BIT(8) -#define VDPU_REG_DEC_CTRL0_DEC_AXI_WR_ID(x) (((x) & 0xff) << 0) -#define VDPU_REG_DEC_CTRL1 0x010 -#define VDPU_REG_DEC_CTRL1_PIC_MB_WIDTH(x) (((x) & 0x1ff) << 23) -#define VDPU_REG_DEC_CTRL1_MB_WIDTH_OFF(x) (((x) & 0xf) << 19) -#define VDPU_REG_DEC_CTRL1_PIC_MB_HEIGHT_P(x) (((x) & 0xff) << 11) -#define VDPU_REG_DEC_CTRL1_MB_HEIGHT_OFF(x) (((x) & 0xf) << 7) -#define VDPU_REG_DEC_CTRL1_ALT_SCAN_E BIT(6) -#define VDPU_REG_DEC_CTRL1_TOPFIELDFIRST_E BIT(5) -#define VDPU_REG_DEC_CTRL1_REF_FRAMES(x) (((x) & 0x1f) << 0) -#define VDPU_REG_DEC_CTRL1_PIC_MB_W_EXT(x) (((x) & 0x7) << 3) -#define VDPU_REG_DEC_CTRL1_PIC_MB_H_EXT(x) (((x) & 0x7) << 0) -#define VDPU_REG_DEC_CTRL1_PIC_REFER_FLAG BIT(0) -#define VDPU_REG_DEC_CTRL2 0x014 -#define VDPU_REG_DEC_CTRL2_STRM_START_BIT(x) (((x) & 0x3f) << 26) -#define VDPU_REG_DEC_CTRL2_SYNC_MARKER_E BIT(25) -#define VDPU_REG_DEC_CTRL2_TYPE1_QUANT_E BIT(24) -#define VDPU_REG_DEC_CTRL2_CH_QP_OFFSET(x) (((x) & 0x1f) << 19) -#define VDPU_REG_DEC_CTRL2_CH_QP_OFFSET2(x) (((x) & 0x1f) << 14) -#define VDPU_REG_DEC_CTRL2_FIELDPIC_FLAG_E BIT(0) -#define VDPU_REG_DEC_CTRL2_INTRADC_VLC_THR(x) (((x) & 0x7) << 16) -#define VDPU_REG_DEC_CTRL2_VOP_TIME_INCR(x) (((x) & 0xffff) << 0) -#define VDPU_REG_DEC_CTRL2_DQ_PROFILE BIT(24) -#define VDPU_REG_DEC_CTRL2_DQBI_LEVEL BIT(23) -#define VDPU_REG_DEC_CTRL2_RANGE_RED_FRM_E BIT(22) -#define VDPU_REG_DEC_CTRL2_FAST_UVMC_E BIT(20) -#define VDPU_REG_DEC_CTRL2_TRANSDCTAB BIT(17) -#define VDPU_REG_DEC_CTRL2_TRANSACFRM(x) (((x) & 0x3) << 15) -#define VDPU_REG_DEC_CTRL2_TRANSACFRM2(x) (((x) & 0x3) << 13) -#define VDPU_REG_DEC_CTRL2_MB_MODE_TAB(x) (((x) & 0x7) << 10) -#define VDPU_REG_DEC_CTRL2_MVTAB(x) (((x) & 0x7) << 7) -#define VDPU_REG_DEC_CTRL2_CBPTAB(x) (((x) & 0x7) << 4) -#define VDPU_REG_DEC_CTRL2_2MV_BLK_PAT_TAB(x) (((x) & 0x3) << 2) -#define VDPU_REG_DEC_CTRL2_4MV_BLK_PAT_TAB(x) (((x) & 0x3) << 0) -#define VDPU_REG_DEC_CTRL2_QSCALE_TYPE BIT(24) -#define VDPU_REG_DEC_CTRL2_CON_MV_E BIT(4) -#define VDPU_REG_DEC_CTRL2_INTRA_DC_PREC(x) (((x) & 0x3) << 2) -#define VDPU_REG_DEC_CTRL2_INTRA_VLC_TAB BIT(1) -#define VDPU_REG_DEC_CTRL2_FRAME_PRED_DCT BIT(0) -#define VDPU_REG_DEC_CTRL2_JPEG_QTABLES(x) (((x) & 0x3) << 11) -#define VDPU_REG_DEC_CTRL2_JPEG_MODE(x) (((x) & 0x7) << 8) -#define VDPU_REG_DEC_CTRL2_JPEG_FILRIGHT_E BIT(7) -#define VDPU_REG_DEC_CTRL2_JPEG_STREAM_ALL BIT(6) -#define VDPU_REG_DEC_CTRL2_CR_AC_VLCTABLE BIT(5) -#define VDPU_REG_DEC_CTRL2_CB_AC_VLCTABLE BIT(4) -#define VDPU_REG_DEC_CTRL2_CR_DC_VLCTABLE BIT(3) -#define VDPU_REG_DEC_CTRL2_CB_DC_VLCTABLE BIT(2) -#define VDPU_REG_DEC_CTRL2_CR_DC_VLCTABLE3 BIT(1) -#define VDPU_REG_DEC_CTRL2_CB_DC_VLCTABLE3 BIT(0) -#define VDPU_REG_DEC_CTRL2_STRM1_START_BIT(x) (((x) & 0x3f) << 18) -#define VDPU_REG_DEC_CTRL2_HUFFMAN_E BIT(17) -#define VDPU_REG_DEC_CTRL2_MULTISTREAM_E BIT(16) -#define VDPU_REG_DEC_CTRL2_BOOLEAN_VALUE(x) (((x) & 0xff) << 8) -#define VDPU_REG_DEC_CTRL2_BOOLEAN_RANGE(x) (((x) & 0xff) << 0) -#define VDPU_REG_DEC_CTRL2_ALPHA_OFFSET(x) (((x) & 0x1f) << 5) -#define VDPU_REG_DEC_CTRL2_BETA_OFFSET(x) (((x) & 0x1f) << 0) -#define VDPU_REG_DEC_CTRL3 0x018 -#define VDPU_REG_DEC_CTRL3_START_CODE_E BIT(31) -#define VDPU_REG_DEC_CTRL3_INIT_QP(x) (((x) & 0x3f) << 25) -#define VDPU_REG_DEC_CTRL3_CH_8PIX_ILEAV_E BIT(24) -#define VDPU_REG_DEC_CTRL3_STREAM_LEN_EXT(x) (((x) & 0xff) << 24) -#define VDPU_REG_DEC_CTRL3_STREAM_LEN(x) (((x) & 0xffffff) << 0) -#define VDPU_REG_DEC_CTRL4 0x01c -#define VDPU_REG_DEC_CTRL4_CABAC_E BIT(31) -#define VDPU_REG_DEC_CTRL4_BLACKWHITE_E BIT(30) -#define VDPU_REG_DEC_CTRL4_DIR_8X8_INFER_E BIT(29) -#define VDPU_REG_DEC_CTRL4_WEIGHT_PRED_E BIT(28) -#define VDPU_REG_DEC_CTRL4_WEIGHT_BIPR_IDC(x) (((x) & 0x3) << 26) -#define VDPU_REG_DEC_CTRL4_AVS_H264_H_EXT BIT(25) -#define VDPU_REG_DEC_CTRL4_FRAMENUM_LEN(x) (((x) & 0x1f) << 16) -#define VDPU_REG_DEC_CTRL4_FRAMENUM(x) (((x) & 0xffff) << 0) -#define VDPU_REG_DEC_CTRL4_BITPLANE0_E BIT(31) -#define VDPU_REG_DEC_CTRL4_BITPLANE1_E BIT(30) -#define VDPU_REG_DEC_CTRL4_BITPLANE2_E BIT(29) -#define VDPU_REG_DEC_CTRL4_ALT_PQUANT(x) (((x) & 0x1f) << 24) -#define VDPU_REG_DEC_CTRL4_DQ_EDGES(x) (((x) & 0xf) << 20) -#define VDPU_REG_DEC_CTRL4_TTMBF BIT(19) -#define VDPU_REG_DEC_CTRL4_PQINDEX(x) (((x) & 0x1f) << 14) -#define VDPU_REG_DEC_CTRL4_VC1_HEIGHT_EXT BIT(13) -#define VDPU_REG_DEC_CTRL4_BILIN_MC_E BIT(12) -#define VDPU_REG_DEC_CTRL4_UNIQP_E BIT(11) -#define VDPU_REG_DEC_CTRL4_HALFQP_E BIT(10) -#define VDPU_REG_DEC_CTRL4_TTFRM(x) (((x) & 0x3) << 8) -#define VDPU_REG_DEC_CTRL4_2ND_BYTE_EMUL_E BIT(7) -#define VDPU_REG_DEC_CTRL4_DQUANT_E BIT(6) -#define VDPU_REG_DEC_CTRL4_VC1_ADV_E BIT(5) -#define VDPU_REG_DEC_CTRL4_PJPEG_FILDOWN_E BIT(26) -#define VDPU_REG_DEC_CTRL4_PJPEG_WDIV8 BIT(25) -#define VDPU_REG_DEC_CTRL4_PJPEG_HDIV8 BIT(24) -#define VDPU_REG_DEC_CTRL4_PJPEG_AH(x) (((x) & 0xf) << 20) -#define VDPU_REG_DEC_CTRL4_PJPEG_AL(x) (((x) & 0xf) << 16) -#define VDPU_REG_DEC_CTRL4_PJPEG_SS(x) (((x) & 0xff) << 8) -#define VDPU_REG_DEC_CTRL4_PJPEG_SE(x) (((x) & 0xff) << 0) -#define VDPU_REG_DEC_CTRL4_DCT1_START_BIT(x) (((x) & 0x3f) << 26) -#define VDPU_REG_DEC_CTRL4_DCT2_START_BIT(x) (((x) & 0x3f) << 20) -#define VDPU_REG_DEC_CTRL4_CH_MV_RES BIT(13) -#define VDPU_REG_DEC_CTRL4_INIT_DC_MATCH0(x) (((x) & 0x7) << 9) -#define VDPU_REG_DEC_CTRL4_INIT_DC_MATCH1(x) (((x) & 0x7) << 6) -#define VDPU_REG_DEC_CTRL4_VP7_VERSION BIT(5) -#define VDPU_REG_DEC_CTRL5 0x020 -#define VDPU_REG_DEC_CTRL5_CONST_INTRA_E BIT(31) -#define VDPU_REG_DEC_CTRL5_FILT_CTRL_PRES BIT(30) -#define VDPU_REG_DEC_CTRL5_RDPIC_CNT_PRES BIT(29) -#define VDPU_REG_DEC_CTRL5_8X8TRANS_FLAG_E BIT(28) -#define VDPU_REG_DEC_CTRL5_REFPIC_MK_LEN(x) (((x) & 0x7ff) << 17) -#define VDPU_REG_DEC_CTRL5_IDR_PIC_E BIT(16) -#define VDPU_REG_DEC_CTRL5_IDR_PIC_ID(x) (((x) & 0xffff) << 0) -#define VDPU_REG_DEC_CTRL5_MV_SCALEFACTOR(x) (((x) & 0xff) << 24) -#define VDPU_REG_DEC_CTRL5_REF_DIST_FWD(x) (((x) & 0x1f) << 19) -#define VDPU_REG_DEC_CTRL5_REF_DIST_BWD(x) (((x) & 0x1f) << 14) -#define VDPU_REG_DEC_CTRL5_LOOP_FILT_LIMIT(x) (((x) & 0xf) << 14) -#define VDPU_REG_DEC_CTRL5_VARIANCE_TEST_E BIT(13) -#define VDPU_REG_DEC_CTRL5_MV_THRESHOLD(x) (((x) & 0x7) << 10) -#define VDPU_REG_DEC_CTRL5_VAR_THRESHOLD(x) (((x) & 0x3ff) << 0) -#define VDPU_REG_DEC_CTRL5_DIVX_IDCT_E BIT(8) -#define VDPU_REG_DEC_CTRL5_DIVX3_SLICE_SIZE(x) (((x) & 0xff) << 0) -#define VDPU_REG_DEC_CTRL5_PJPEG_REST_FREQ(x) (((x) & 0xffff) << 0) -#define VDPU_REG_DEC_CTRL5_RV_PROFILE(x) (((x) & 0x3) << 30) -#define VDPU_REG_DEC_CTRL5_RV_OSV_QUANT(x) (((x) & 0x3) << 28) -#define VDPU_REG_DEC_CTRL5_RV_FWD_SCALE(x) (((x) & 0x3fff) << 14) -#define VDPU_REG_DEC_CTRL5_RV_BWD_SCALE(x) (((x) & 0x3fff) << 0) -#define VDPU_REG_DEC_CTRL5_INIT_DC_COMP0(x) (((x) & 0xffff) << 16) -#define VDPU_REG_DEC_CTRL5_INIT_DC_COMP1(x) (((x) & 0xffff) << 0) -#define VDPU_REG_DEC_CTRL6 0x024 -#define VDPU_REG_DEC_CTRL6_PPS_ID(x) (((x) & 0xff) << 24) -#define VDPU_REG_DEC_CTRL6_REFIDX1_ACTIVE(x) (((x) & 0x1f) << 19) -#define VDPU_REG_DEC_CTRL6_REFIDX0_ACTIVE(x) (((x) & 0x1f) << 14) -#define VDPU_REG_DEC_CTRL6_POC_LENGTH(x) (((x) & 0xff) << 0) -#define VDPU_REG_DEC_CTRL6_ICOMP0_E BIT(24) -#define VDPU_REG_DEC_CTRL6_ISCALE0(x) (((x) & 0xff) << 16) -#define VDPU_REG_DEC_CTRL6_ISHIFT0(x) (((x) & 0xffff) << 0) -#define VDPU_REG_DEC_CTRL6_STREAM1_LEN(x) (((x) & 0xffffff) << 0) -#define VDPU_REG_DEC_CTRL6_PIC_SLICE_AM(x) (((x) & 0x1fff) << 0) -#define VDPU_REG_DEC_CTRL6_COEFFS_PART_AM(x) (((x) & 0xf) << 24) -#define VDPU_REG_FWD_PIC(i) (0x028 + ((i) * 0x4)) -#define VDPU_REG_FWD_PIC_PINIT_RLIST_F5(x) (((x) & 0x1f) << 25) -#define VDPU_REG_FWD_PIC_PINIT_RLIST_F4(x) (((x) & 0x1f) << 20) -#define VDPU_REG_FWD_PIC_PINIT_RLIST_F3(x) (((x) & 0x1f) << 15) -#define VDPU_REG_FWD_PIC_PINIT_RLIST_F2(x) (((x) & 0x1f) << 10) -#define VDPU_REG_FWD_PIC_PINIT_RLIST_F1(x) (((x) & 0x1f) << 5) -#define VDPU_REG_FWD_PIC_PINIT_RLIST_F0(x) (((x) & 0x1f) << 0) -#define VDPU_REG_FWD_PIC1_ICOMP1_E BIT(24) -#define VDPU_REG_FWD_PIC1_ISCALE1(x) (((x) & 0xff) << 16) -#define VDPU_REG_FWD_PIC1_ISHIFT1(x) (((x) & 0xffff) << 0) -#define VDPU_REG_FWD_PIC1_SEGMENT_BASE(x) ((x) << 0) -#define VDPU_REG_FWD_PIC1_SEGMENT_UPD_E BIT(1) -#define VDPU_REG_FWD_PIC1_SEGMENT_E BIT(0) -#define VDPU_REG_DEC_CTRL7 0x02c -#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F15(x) (((x) & 0x1f) << 25) -#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F14(x) (((x) & 0x1f) << 20) -#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F13(x) (((x) & 0x1f) << 15) -#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F12(x) (((x) & 0x1f) << 10) -#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F11(x) (((x) & 0x1f) << 5) -#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F10(x) (((x) & 0x1f) << 0) -#define VDPU_REG_DEC_CTRL7_ICOMP2_E BIT(24) -#define VDPU_REG_DEC_CTRL7_ISCALE2(x) (((x) & 0xff) << 16) -#define VDPU_REG_DEC_CTRL7_ISHIFT2(x) (((x) & 0xffff) << 0) -#define VDPU_REG_DEC_CTRL7_DCT3_START_BIT(x) (((x) & 0x3f) << 24) -#define VDPU_REG_DEC_CTRL7_DCT4_START_BIT(x) (((x) & 0x3f) << 18) -#define VDPU_REG_DEC_CTRL7_DCT5_START_BIT(x) (((x) & 0x3f) << 12) -#define VDPU_REG_DEC_CTRL7_DCT6_START_BIT(x) (((x) & 0x3f) << 6) -#define VDPU_REG_DEC_CTRL7_DCT7_START_BIT(x) (((x) & 0x3f) << 0) -#define VDPU_REG_ADDR_STR 0x030 -#define VDPU_REG_ADDR_DST 0x034 -#define VDPU_REG_ADDR_REF(i) (0x038 + ((i) * 0x4)) -#define VDPU_REG_ADDR_REF_FIELD_E BIT(1) -#define VDPU_REG_ADDR_REF_TOPC_E BIT(0) -#define VDPU_REG_REF_PIC(i) (0x078 + ((i) * 0x4)) -#define VDPU_REG_REF_PIC_FILT_TYPE_E BIT(31) -#define VDPU_REG_REF_PIC_FILT_SHARPNESS(x) (((x) & 0x7) << 28) -#define VDPU_REG_REF_PIC_MB_ADJ_0(x) (((x) & 0x7f) << 21) -#define VDPU_REG_REF_PIC_MB_ADJ_1(x) (((x) & 0x7f) << 14) -#define VDPU_REG_REF_PIC_MB_ADJ_2(x) (((x) & 0x7f) << 7) -#define VDPU_REG_REF_PIC_MB_ADJ_3(x) (((x) & 0x7f) << 0) -#define VDPU_REG_REF_PIC_REFER1_NBR(x) (((x) & 0xffff) << 16) -#define VDPU_REG_REF_PIC_REFER0_NBR(x) (((x) & 0xffff) << 0) -#define VDPU_REG_REF_PIC_LF_LEVEL_0(x) (((x) & 0x3f) << 18) -#define VDPU_REG_REF_PIC_LF_LEVEL_1(x) (((x) & 0x3f) << 12) -#define VDPU_REG_REF_PIC_LF_LEVEL_2(x) (((x) & 0x3f) << 6) -#define VDPU_REG_REF_PIC_LF_LEVEL_3(x) (((x) & 0x3f) << 0) -#define VDPU_REG_REF_PIC_QUANT_DELTA_0(x) (((x) & 0x1f) << 27) -#define VDPU_REG_REF_PIC_QUANT_DELTA_1(x) (((x) & 0x1f) << 22) -#define VDPU_REG_REF_PIC_QUANT_0(x) (((x) & 0x7ff) << 11) -#define VDPU_REG_REF_PIC_QUANT_1(x) (((x) & 0x7ff) << 0) -#define VDPU_REG_LT_REF 0x098 -#define VDPU_REG_VALID_REF 0x09c -#define VDPU_REG_ADDR_QTABLE 0x0a0 -#define VDPU_REG_ADDR_DIR_MV 0x0a4 -#define VDPU_REG_BD_REF_PIC(i) (0x0a8 + ((i) * 0x4)) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B2(x) (((x) & 0x1f) << 25) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F2(x) (((x) & 0x1f) << 20) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B1(x) (((x) & 0x1f) << 15) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F1(x) (((x) & 0x1f) << 10) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B0(x) (((x) & 0x1f) << 5) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F0(x) (((x) & 0x1f) << 0) -#define VDPU_REG_BD_REF_PIC_PRED_TAP_2_M1(x) (((x) & 0x3) << 10) -#define VDPU_REG_BD_REF_PIC_PRED_TAP_2_4(x) (((x) & 0x3) << 8) -#define VDPU_REG_BD_REF_PIC_PRED_TAP_4_M1(x) (((x) & 0x3) << 6) -#define VDPU_REG_BD_REF_PIC_PRED_TAP_4_4(x) (((x) & 0x3) << 4) -#define VDPU_REG_BD_REF_PIC_PRED_TAP_6_M1(x) (((x) & 0x3) << 2) -#define VDPU_REG_BD_REF_PIC_PRED_TAP_6_4(x) (((x) & 0x3) << 0) -#define VDPU_REG_BD_REF_PIC_QUANT_DELTA_2(x) (((x) & 0x1f) << 27) -#define VDPU_REG_BD_REF_PIC_QUANT_DELTA_3(x) (((x) & 0x1f) << 22) -#define VDPU_REG_BD_REF_PIC_QUANT_2(x) (((x) & 0x7ff) << 11) -#define VDPU_REG_BD_REF_PIC_QUANT_3(x) (((x) & 0x7ff) << 0) -#define VDPU_REG_BD_P_REF_PIC 0x0bc -#define VDPU_REG_BD_P_REF_PIC_QUANT_DELTA_4(x) (((x) & 0x1f) << 27) -#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F3(x) (((x) & 0x1f) << 25) -#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F2(x) (((x) & 0x1f) << 20) -#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F1(x) (((x) & 0x1f) << 15) -#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F0(x) (((x) & 0x1f) << 10) -#define VDPU_REG_BD_P_REF_PIC_BINIT_RLIST_B15(x) (((x) & 0x1f) << 5) -#define VDPU_REG_BD_P_REF_PIC_BINIT_RLIST_F15(x) (((x) & 0x1f) << 0) -#define VDPU_REG_ERR_CONC 0x0c0 -#define VDPU_REG_ERR_CONC_STARTMB_X(x) (((x) & 0x1ff) << 23) -#define VDPU_REG_ERR_CONC_STARTMB_Y(x) (((x) & 0xff) << 15) -#define VDPU_REG_PRED_FLT 0x0c4 -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_0_0(x) (((x) & 0x3ff) << 22) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_0_1(x) (((x) & 0x3ff) << 12) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_0_2(x) (((x) & 0x3ff) << 2) -#define VDPU_REG_REF_BUF_CTRL 0x0cc -#define VDPU_REG_REF_BUF_CTRL_REFBU_E BIT(31) -#define VDPU_REG_REF_BUF_CTRL_REFBU_THR(x) (((x) & 0xfff) << 19) -#define VDPU_REG_REF_BUF_CTRL_REFBU_PICID(x) (((x) & 0x1f) << 14) -#define VDPU_REG_REF_BUF_CTRL_REFBU_EVAL_E BIT(13) -#define VDPU_REG_REF_BUF_CTRL_REFBU_FPARMOD_E BIT(12) -#define VDPU_REG_REF_BUF_CTRL_REFBU_Y_OFFSET(x) (((x) & 0x1ff) << 0) -#define VDPU_REG_REF_BUF_CTRL2 0x0dc -#define VDPU_REG_REF_BUF_CTRL2_REFBU2_BUF_E BIT(31) -#define VDPU_REG_REF_BUF_CTRL2_REFBU2_THR(x) (((x) & 0xfff) << 19) -#define VDPU_REG_REF_BUF_CTRL2_REFBU2_PICID(x) (((x) & 0x1f) << 14) -#define VDPU_REG_REF_BUF_CTRL2_APF_THRESHOLD(x) (((x) & 0x3fff) << 0) - -#endif /* RK3288_VPU_REGS_H_ */ diff --git a/drivers/media/platform/rockchip-vpu/Makefile b/drivers/media/platform/rockchip-vpu/Makefile new file mode 100644 index 000000000000..7fb2433f9f58 --- /dev/null +++ b/drivers/media/platform/rockchip-vpu/Makefile @@ -0,0 +1,10 @@ + +obj-$(CONFIG_VIDEO_ROCKCHIP_VPU) += rockchip-vpu.o + +rockchip-vpu-y += rk3288_vpu.o \ + rk3288_vpu_dec.o \ + rk3288_vpu_enc.o \ + rk3288_vpu_hw.o \ + rk3288_vpu_hw_h264d.o \ + rk3288_vpu_hw_vp8d.o \ + rk3288_vpu_hw_vp8e.o diff --git a/drivers/media/platform/rockchip-vpu/rk3288_vpu.c b/drivers/media/platform/rockchip-vpu/rk3288_vpu.c new file mode 100644 index 000000000000..ac35b0cf9665 --- /dev/null +++ b/drivers/media/platform/rockchip-vpu/rk3288_vpu.c @@ -0,0 +1,822 @@ +/* + * Rockchip RK3288 VPU codec driver + * + * Copyright (C) 2014 Google, Inc. + * Tomasz Figa + * + * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "rk3288_vpu_common.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rk3288_vpu_dec.h" +#include "rk3288_vpu_enc.h" +#include "rk3288_vpu_hw.h" + +int debug; +module_param(debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, + "Debug level - higher value produces more verbose messages"); + +/* + * DMA coherent helpers. + */ + +int rk3288_vpu_aux_buf_alloc(struct rk3288_vpu_dev *vpu, + struct rk3288_vpu_aux_buf *buf, size_t size) +{ + buf->cpu = dma_alloc_coherent(vpu->dev, size, &buf->dma, GFP_KERNEL); + if (!buf->cpu) + return -ENOMEM; + + buf->size = size; + return 0; +} + +void rk3288_vpu_aux_buf_free(struct rk3288_vpu_dev *vpu, + struct rk3288_vpu_aux_buf *buf) +{ + dma_free_coherent(vpu->dev, buf->size, buf->cpu, buf->dma); + + buf->cpu = NULL; + buf->dma = 0; + buf->size = 0; +} + +/* + * Context scheduling. + */ + +static void rk3288_vpu_prepare_run(struct rk3288_vpu_ctx *ctx) +{ + if (ctx->run_ops->prepare_run) + ctx->run_ops->prepare_run(ctx); +} + +static void __rk3288_vpu_dequeue_run_locked(struct rk3288_vpu_ctx *ctx) +{ + struct rk3288_vpu_buf *src, *dst; + + /* + * Since ctx was dequeued from ready_ctxs list, we know that it has + * at least one buffer in each queue. + */ + src = list_first_entry(&ctx->src_queue, struct rk3288_vpu_buf, list); + dst = list_first_entry(&ctx->dst_queue, struct rk3288_vpu_buf, list); + + list_del(&src->list); + list_del(&dst->list); + + ctx->run.src = src; + ctx->run.dst = dst; +} + +static struct rk3288_vpu_ctx * +rk3288_vpu_encode_after_decode_war(struct rk3288_vpu_ctx *ctx) +{ + struct rk3288_vpu_dev *dev = ctx->dev; + + if (dev->was_decoding && rk3288_vpu_ctx_is_encoder(ctx)) + return dev->dummy_encode_ctx; + + return ctx; +} + +static void rk3288_vpu_try_run(struct rk3288_vpu_dev *dev) +{ + struct rk3288_vpu_ctx *ctx = NULL; + unsigned long flags; + + vpu_debug_enter(); + + spin_lock_irqsave(&dev->irqlock, flags); + + if (list_empty(&dev->ready_ctxs) || + test_bit(VPU_SUSPENDED, &dev->state)) + /* Nothing to do. */ + goto out; + + if (test_and_set_bit(VPU_RUNNING, &dev->state)) + /* + * The hardware is already running. We will pick another + * run after we get the notification in rk3288_vpu_run_done(). + */ + goto out; + + ctx = list_entry(dev->ready_ctxs.next, struct rk3288_vpu_ctx, list); + + /* + * WAR for corrupted hardware state when encoding directly after + * certain decoding runs. + * + * If previous context was decoding and currently picked one is + * encoding then we need to execute a dummy encode with proper + * settings to reinitialize certain internal hardware state. + */ + ctx = rk3288_vpu_encode_after_decode_war(ctx); + + if (!rk3288_vpu_ctx_is_dummy_encode(ctx)) { + list_del_init(&ctx->list); + __rk3288_vpu_dequeue_run_locked(ctx); + } + + dev->current_ctx = ctx; + dev->was_decoding = !rk3288_vpu_ctx_is_encoder(ctx); + +out: + spin_unlock_irqrestore(&dev->irqlock, flags); + + if (ctx) { + rk3288_vpu_prepare_run(ctx); + rk3288_vpu_run(ctx); + } + + vpu_debug_leave(); +} + +static void __rk3288_vpu_try_context_locked(struct rk3288_vpu_dev *dev, + struct rk3288_vpu_ctx *ctx) +{ + if (!list_empty(&ctx->list)) + /* Context already queued. */ + return; + + if (!list_empty(&ctx->dst_queue) && !list_empty(&ctx->src_queue)) + list_add_tail(&ctx->list, &dev->ready_ctxs); +} + +void rk3288_vpu_run_done(struct rk3288_vpu_ctx *ctx, + enum vb2_buffer_state result) +{ + struct rk3288_vpu_dev *dev = ctx->dev; + unsigned long flags; + + vpu_debug_enter(); + + if (ctx->run_ops->run_done) + ctx->run_ops->run_done(ctx, result); + + if (!rk3288_vpu_ctx_is_dummy_encode(ctx)) { + struct vb2_buffer *src = &ctx->run.src->b; + struct vb2_buffer *dst = &ctx->run.dst->b; + + dst->v4l2_buf.timestamp = src->v4l2_buf.timestamp; + vb2_buffer_done(&ctx->run.src->b, result); + vb2_buffer_done(&ctx->run.dst->b, result); + } + + dev->current_ctx = NULL; + wake_up_all(&dev->run_wq); + + spin_lock_irqsave(&dev->irqlock, flags); + + __rk3288_vpu_try_context_locked(dev, ctx); + clear_bit(VPU_RUNNING, &dev->state); + + spin_unlock_irqrestore(&dev->irqlock, flags); + + /* Try scheduling another run to see if we have anything left to do. */ + rk3288_vpu_try_run(dev); + + vpu_debug_leave(); +} + +void rk3288_vpu_try_context(struct rk3288_vpu_dev *dev, + struct rk3288_vpu_ctx *ctx) +{ + unsigned long flags; + + vpu_debug_enter(); + + spin_lock_irqsave(&dev->irqlock, flags); + + __rk3288_vpu_try_context_locked(dev, ctx); + + spin_unlock_irqrestore(&dev->irqlock, flags); + + rk3288_vpu_try_run(dev); + + vpu_debug_enter(); +} + +/* + * Control registration. + */ + +#define IS_VPU_PRIV(x) ((V4L2_CTRL_ID2CLASS(x) == V4L2_CTRL_CLASS_MPEG) && \ + V4L2_CTRL_DRIVER_PRIV(x)) + +int rk3288_vpu_ctrls_setup(struct rk3288_vpu_ctx *ctx, + const struct v4l2_ctrl_ops *ctrl_ops, + struct rk3288_vpu_control *controls, + unsigned num_ctrls, + const char *const *(*get_menu)(u32)) +{ + struct v4l2_ctrl_config cfg; + int i; + + if (num_ctrls > ARRAY_SIZE(ctx->ctrls)) { + vpu_err("context control array not large enough\n"); + return -ENOSPC; + } + + v4l2_ctrl_handler_init(&ctx->ctrl_handler, num_ctrls); + if (ctx->ctrl_handler.error) { + vpu_err("v4l2_ctrl_handler_init failed\n"); + return ctx->ctrl_handler.error; + } + + for (i = 0; i < num_ctrls; i++) { + if (IS_VPU_PRIV(controls[i].id) + || controls[i].id >= V4L2_CID_CUSTOM_BASE + || controls[i].type == V4L2_CTRL_TYPE_PRIVATE) { + memset(&cfg, 0, sizeof(struct v4l2_ctrl_config)); + + cfg.ops = ctrl_ops; + cfg.id = controls[i].id; + cfg.min = controls[i].minimum; + cfg.max = controls[i].maximum; + cfg.max_stores = controls[i].max_stores; + cfg.def = controls[i].default_value; + cfg.name = controls[i].name; + cfg.type = controls[i].type; + cfg.elem_size = controls[i].elem_size; + memcpy(cfg.dims, controls[i].dims, sizeof(cfg.dims)); + + if (cfg.type == V4L2_CTRL_TYPE_MENU) { + cfg.menu_skip_mask = cfg.menu_skip_mask; + cfg.qmenu = get_menu(cfg.id); + } else { + cfg.step = controls[i].step; + } + + ctx->ctrls[i] = v4l2_ctrl_new_custom( + &ctx->ctrl_handler, &cfg, NULL); + } else { + if (controls[i].type == V4L2_CTRL_TYPE_MENU) { + ctx->ctrls[i] = + v4l2_ctrl_new_std_menu + (&ctx->ctrl_handler, + ctrl_ops, + controls[i].id, + controls[i].maximum, + 0, + controls[i]. + default_value); + } else { + ctx->ctrls[i] = + v4l2_ctrl_new_std(&ctx->ctrl_handler, + ctrl_ops, + controls[i].id, + controls[i].minimum, + controls[i].maximum, + controls[i].step, + controls[i]. + default_value); + } + } + + if (ctx->ctrl_handler.error) { + vpu_err("Adding control (%d) failed\n", i); + return ctx->ctrl_handler.error; + } + + if (controls[i].is_volatile && ctx->ctrls[i]) + ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_VOLATILE; + if (controls[i].is_read_only && ctx->ctrls[i]) + ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_READ_ONLY; + if (controls[i].can_store && ctx->ctrls[i]) + ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_CAN_STORE; + } + + v4l2_ctrl_handler_setup(&ctx->ctrl_handler); + ctx->num_ctrls = num_ctrls; + return 0; +} + +void rk3288_vpu_ctrls_delete(struct rk3288_vpu_ctx *ctx) +{ + int i; + + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + for (i = 0; i < ctx->num_ctrls; i++) + ctx->ctrls[i] = NULL; +} + +/* + * V4L2 file operations. + */ + +static int rk3288_vpu_open(struct file *filp) +{ + struct video_device *vdev = video_devdata(filp); + struct rk3288_vpu_dev *dev = video_drvdata(filp); + struct rk3288_vpu_ctx *ctx = NULL; + struct vb2_queue *q; + int ret = 0; + + /* + * We do not need any extra locking here, because we operate only + * on local data here, except reading few fields from dev, which + * do not change through device's lifetime (which is guaranteed by + * reference on module from open()) and V4L2 internal objects (such + * as vdev and ctx->fh), which have proper locking done in respective + * helper functions used here. + */ + + vpu_debug_enter(); + + /* Allocate memory for context */ + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + ret = -ENOMEM; + goto err_leave; + } + + v4l2_fh_init(&ctx->fh, video_devdata(filp)); + filp->private_data = &ctx->fh; + v4l2_fh_add(&ctx->fh); + ctx->dev = dev; + INIT_LIST_HEAD(&ctx->src_queue); + INIT_LIST_HEAD(&ctx->dst_queue); + INIT_LIST_HEAD(&ctx->list); + + if (vdev == dev->vfd_enc) { + /* only for encoder */ + ret = rk3288_vpu_enc_init(ctx); + if (ret) { + vpu_err("Failed to initialize encoder context\n"); + goto err_fh_free; + } + } else if (vdev == dev->vfd_dec) { + /* only for decoder */ + ret = rk3288_vpu_dec_init(ctx); + if (ret) { + vpu_err("Failed to initialize decoder context\n"); + goto err_fh_free; + } + } else { + ret = -ENOENT; + goto err_fh_free; + } + ctx->fh.ctrl_handler = &ctx->ctrl_handler; + + /* Init videobuf2 queue for CAPTURE */ + q = &ctx->vq_dst; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + q->drv_priv = &ctx->fh; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + q->lock = &dev->vpu_mutex; + q->buf_struct_size = sizeof(struct rk3288_vpu_buf); + + if (vdev == dev->vfd_enc) { + q->ops = get_enc_queue_ops(); + } else if (vdev == dev->vfd_dec) { + q->ops = get_dec_queue_ops(); + q->use_dma_bidirectional = 1; + } + + q->mem_ops = &vb2_dma_contig_memops; + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; + + ret = vb2_queue_init(q); + if (ret) { + vpu_err("Failed to initialize videobuf2 queue(capture)\n"); + goto err_enc_dec_exit; + } + + /* Init videobuf2 queue for OUTPUT */ + q = &ctx->vq_src; + q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + q->drv_priv = &ctx->fh; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + q->lock = &dev->vpu_mutex; + q->buf_struct_size = sizeof(struct rk3288_vpu_buf); + + if (vdev == dev->vfd_enc) + q->ops = get_enc_queue_ops(); + else if (vdev == dev->vfd_dec) + q->ops = get_dec_queue_ops(); + + q->mem_ops = &vb2_dma_contig_memops; + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; + + ret = vb2_queue_init(q); + if (ret) { + vpu_err("Failed to initialize videobuf2 queue(output)\n"); + goto err_vq_dst_release; + } + + vpu_debug_leave(); + + return 0; + +err_vq_dst_release: + vb2_queue_release(&ctx->vq_dst); +err_enc_dec_exit: + if (vdev == dev->vfd_enc) + rk3288_vpu_enc_exit(ctx); + else if (vdev == dev->vfd_dec) + rk3288_vpu_dec_exit(ctx); +err_fh_free: + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + kfree(ctx); +err_leave: + vpu_debug_leave(); + + return ret; +} + +static int rk3288_vpu_release(struct file *filp) +{ + struct rk3288_vpu_ctx *ctx = fh_to_ctx(filp->private_data); + struct video_device *vdev = video_devdata(filp); + struct rk3288_vpu_dev *dev = ctx->dev; + + /* + * No need for extra locking because this was the last reference + * to this file. + */ + + vpu_debug_enter(); + + /* + * vb2_queue_release() ensures that streaming is stopped, which + * in turn means that there are no frames still being processed + * by hardware. + */ + vb2_queue_release(&ctx->vq_src); + vb2_queue_release(&ctx->vq_dst); + + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + + if (vdev == dev->vfd_enc) + rk3288_vpu_enc_exit(ctx); + else if (vdev == dev->vfd_dec) + rk3288_vpu_dec_exit(ctx); + + kfree(ctx); + + vpu_debug_leave(); + + return 0; +} + +static unsigned int rk3288_vpu_poll(struct file *filp, + struct poll_table_struct *wait) +{ + struct rk3288_vpu_ctx *ctx = fh_to_ctx(filp->private_data); + struct vb2_queue *src_q, *dst_q; + struct vb2_buffer *src_vb = NULL, *dst_vb = NULL; + unsigned int rc = 0; + unsigned long flags; + + vpu_debug_enter(); + + src_q = &ctx->vq_src; + dst_q = &ctx->vq_dst; + + /* + * There has to be at least one buffer queued on each queued_list, which + * means either in driver already or waiting for driver to claim it + * and start processing. + */ + if ((!vb2_is_streaming(src_q) || list_empty(&src_q->queued_list)) && + (!vb2_is_streaming(dst_q) || list_empty(&dst_q->queued_list))) { + vpu_debug(0, "src q streaming %d, dst q streaming %d, src list empty(%d), dst list empty(%d)\n", + src_q->streaming, dst_q->streaming, + list_empty(&src_q->queued_list), + list_empty(&dst_q->queued_list)); + return POLLERR; + } + + poll_wait(filp, &ctx->fh.wait, wait); + poll_wait(filp, &src_q->done_wq, wait); + poll_wait(filp, &dst_q->done_wq, wait); + + if (v4l2_event_pending(&ctx->fh)) + rc |= POLLPRI; + + spin_lock_irqsave(&src_q->done_lock, flags); + + if (!list_empty(&src_q->done_list)) + src_vb = list_first_entry(&src_q->done_list, struct vb2_buffer, + done_entry); + + if (src_vb && (src_vb->state == VB2_BUF_STATE_DONE || + src_vb->state == VB2_BUF_STATE_ERROR)) + rc |= POLLOUT | POLLWRNORM; + + spin_unlock_irqrestore(&src_q->done_lock, flags); + + spin_lock_irqsave(&dst_q->done_lock, flags); + + if (!list_empty(&dst_q->done_list)) + dst_vb = list_first_entry(&dst_q->done_list, struct vb2_buffer, + done_entry); + + if (dst_vb && (dst_vb->state == VB2_BUF_STATE_DONE || + dst_vb->state == VB2_BUF_STATE_ERROR)) + rc |= POLLIN | POLLRDNORM; + + spin_unlock_irqrestore(&dst_q->done_lock, flags); + + return rc; +} + +static int rk3288_vpu_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct rk3288_vpu_ctx *ctx = fh_to_ctx(filp->private_data); + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + int ret; + + vpu_debug_enter(); + + if (offset < DST_QUEUE_OFF_BASE) { + vpu_debug(4, "mmaping source\n"); + + ret = vb2_mmap(&ctx->vq_src, vma); + } else { /* capture */ + vpu_debug(4, "mmaping destination\n"); + + vma->vm_pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT); + ret = vb2_mmap(&ctx->vq_dst, vma); + } + + vpu_debug_leave(); + + return ret; +} + +static const struct v4l2_file_operations rk3288_vpu_fops = { + .owner = THIS_MODULE, + .open = rk3288_vpu_open, + .release = rk3288_vpu_release, + .poll = rk3288_vpu_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = rk3288_vpu_mmap, +}; + +/* + * Platform driver. + */ + +static int rk3288_vpu_probe(struct platform_device *pdev) +{ + struct rk3288_vpu_dev *vpu = NULL; + DEFINE_DMA_ATTRS(attrs_novm); + DEFINE_DMA_ATTRS(attrs_nohugepage); + struct video_device *vfd; + int ret = 0; + + vpu_debug_enter(); + + vpu = devm_kzalloc(&pdev->dev, sizeof(*vpu), GFP_KERNEL); + if (!vpu) + return -ENOMEM; + + vpu->dev = &pdev->dev; + vpu->pdev = pdev; + mutex_init(&vpu->vpu_mutex); + spin_lock_init(&vpu->irqlock); + INIT_LIST_HEAD(&vpu->ready_ctxs); + init_waitqueue_head(&vpu->run_wq); + + ret = rk3288_vpu_hw_probe(vpu); + if (ret) { + dev_err(&pdev->dev, "vcodec_hw_probe failed\n"); + goto err_hw_probe; + } + + /* + * We'll do mostly sequential access, so sacrifice TLB efficiency for + * faster allocation. + */ + dma_set_attr(DMA_ATTR_ALLOC_SINGLE_PAGES, &attrs_novm); + + dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs_novm); + vpu->alloc_ctx = vb2_dma_contig_init_ctx_attrs(&pdev->dev, + &attrs_novm); + if (IS_ERR(vpu->alloc_ctx)) { + ret = PTR_ERR(vpu->alloc_ctx); + goto err_dma_contig; + } + + dma_set_attr(DMA_ATTR_ALLOC_SINGLE_PAGES, &attrs_nohugepage); + vpu->alloc_ctx_vm = vb2_dma_contig_init_ctx_attrs(&pdev->dev, + &attrs_nohugepage); + if (IS_ERR(vpu->alloc_ctx_vm)) { + ret = PTR_ERR(vpu->alloc_ctx_vm); + goto err_dma_contig_vm; + } + + ret = v4l2_device_register(&pdev->dev, &vpu->v4l2_dev); + if (ret) { + dev_err(&pdev->dev, "Failed to register v4l2 device\n"); + goto err_v4l2_dev_reg; + } + + platform_set_drvdata(pdev, vpu); + + ret = rk3288_vpu_enc_init_dummy_ctx(vpu); + if (ret) { + dev_err(&pdev->dev, "Failed to create dummy encode context\n"); + goto err_dummy_enc; + } + + /* encoder */ + vfd = video_device_alloc(); + if (!vfd) { + v4l2_err(&vpu->v4l2_dev, "Failed to allocate video device\n"); + ret = -ENOMEM; + goto err_enc_alloc; + } + + vfd->fops = &rk3288_vpu_fops; + vfd->ioctl_ops = get_enc_v4l2_ioctl_ops(); + vfd->release = video_device_release; + vfd->lock = &vpu->vpu_mutex; + vfd->v4l2_dev = &vpu->v4l2_dev; + vfd->vfl_dir = VFL_DIR_M2M; + snprintf(vfd->name, sizeof(vfd->name), "%s", RK3288_VPU_ENC_NAME); + vpu->vfd_enc = vfd; + + video_set_drvdata(vfd, vpu); + + ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); + if (ret) { + v4l2_err(&vpu->v4l2_dev, "Failed to register video device\n"); + video_device_release(vfd); + goto err_enc_reg; + } + + v4l2_info(&vpu->v4l2_dev, + "Rockchip RK3288 VPU encoder registered as /vpu/video%d\n", + vfd->num); + + /* decoder */ + vfd = video_device_alloc(); + if (!vfd) { + v4l2_err(&vpu->v4l2_dev, "Failed to allocate video device\n"); + ret = -ENOMEM; + goto err_dec_alloc; + } + + vfd->fops = &rk3288_vpu_fops; + vfd->ioctl_ops = get_dec_v4l2_ioctl_ops(); + vfd->release = video_device_release; + vfd->lock = &vpu->vpu_mutex; + vfd->v4l2_dev = &vpu->v4l2_dev; + vfd->vfl_dir = VFL_DIR_M2M; + snprintf(vfd->name, sizeof(vfd->name), "%s", RK3288_VPU_DEC_NAME); + vpu->vfd_dec = vfd; + + video_set_drvdata(vfd, vpu); + + ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); + if (ret) { + v4l2_err(&vpu->v4l2_dev, "Failed to register video device\n"); + video_device_release(vfd); + goto err_dec_reg; + } + + v4l2_info(&vpu->v4l2_dev, + "Rockchip RK3288 VPU decoder registered as /vpu/video%d\n", + vfd->num); + + vpu_debug_leave(); + + return 0; + +err_dec_reg: + video_device_release(vpu->vfd_dec); +err_dec_alloc: + video_unregister_device(vpu->vfd_enc); +err_enc_reg: + video_device_release(vpu->vfd_enc); +err_enc_alloc: + rk3288_vpu_enc_free_dummy_ctx(vpu); +err_dummy_enc: + v4l2_device_unregister(&vpu->v4l2_dev); +err_v4l2_dev_reg: + vb2_dma_contig_cleanup_ctx(vpu->alloc_ctx_vm); +err_dma_contig_vm: + vb2_dma_contig_cleanup_ctx(vpu->alloc_ctx); +err_dma_contig: + rk3288_vpu_hw_remove(vpu); +err_hw_probe: + pr_debug("%s-- with error\n", __func__); + vpu_debug_leave(); + + return ret; +} + +static int rk3288_vpu_remove(struct platform_device *pdev) +{ + struct rk3288_vpu_dev *vpu = platform_get_drvdata(pdev); + + vpu_debug_enter(); + + v4l2_info(&vpu->v4l2_dev, "Removing %s\n", pdev->name); + + /* + * We are safe here assuming that .remove() got called as + * a result of module removal, which guarantees that all + * contexts have been released. + */ + + video_unregister_device(vpu->vfd_dec); + video_unregister_device(vpu->vfd_enc); + rk3288_vpu_enc_free_dummy_ctx(vpu); + v4l2_device_unregister(&vpu->v4l2_dev); + vb2_dma_contig_cleanup_ctx(vpu->alloc_ctx_vm); + vb2_dma_contig_cleanup_ctx(vpu->alloc_ctx); + rk3288_vpu_hw_remove(vpu); + + vpu_debug_leave(); + + return 0; +} + +static struct platform_device_id vpu_driver_ids[] = { + { .name = "rk3288-vpu", }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(platform, vpu_driver_ids); + +#ifdef CONFIG_OF +static const struct of_device_id of_rk3288_vpu_match[] = { + { .compatible = "rockchip,rk3288-vpu", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_rk3288_vpu_match); +#endif + +#ifdef CONFIG_PM_SLEEP +static int rk3288_vpu_suspend(struct device *dev) +{ + struct rk3288_vpu_dev *vpu = dev_get_drvdata(dev); + + set_bit(VPU_SUSPENDED, &vpu->state); + wait_event(vpu->run_wq, vpu->current_ctx == NULL); + + return 0; +} + +static int rk3288_vpu_resume(struct device *dev) +{ + struct rk3288_vpu_dev *vpu = dev_get_drvdata(dev); + + clear_bit(VPU_SUSPENDED, &vpu->state); + rk3288_vpu_try_run(vpu); + + return 0; +} +#endif + +static const struct dev_pm_ops rk3288_vpu_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(rk3288_vpu_suspend, rk3288_vpu_resume) +}; + +static struct platform_driver rk3288_vpu_driver = { + .probe = rk3288_vpu_probe, + .remove = rk3288_vpu_remove, + .id_table = vpu_driver_ids, + .driver = { + .name = RK3288_VPU_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(of_rk3288_vpu_match), + .pm = &rk3288_vpu_pm_ops, + }, +}; +module_platform_driver(rk3288_vpu_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Alpha Lin "); +MODULE_AUTHOR("Tomasz Figa "); +MODULE_DESCRIPTION("Rockchip RK3288 VPU codec driver"); diff --git a/drivers/media/platform/rockchip-vpu/rk3288_vpu_common.h b/drivers/media/platform/rockchip-vpu/rk3288_vpu_common.h new file mode 100644 index 000000000000..9ac44e82c42f --- /dev/null +++ b/drivers/media/platform/rockchip-vpu/rk3288_vpu_common.h @@ -0,0 +1,519 @@ +/* + * Rockchip RK3288 VPU codec driver + * + * Copyright (C) 2014 Google, Inc. + * Tomasz Figa + * + * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 RK3288_VPU_COMMON_H_ +#define RK3288_VPU_COMMON_H_ + +/* Enable debugging by default for now. */ +#define DEBUG + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "rk3288_vpu_hw.h" + +#define RK3288_VPU_NAME "rk3288-vpu" +#define RK3288_VPU_DEC_NAME "rk3288-vpu-dec" +#define RK3288_VPU_ENC_NAME "rk3288-vpu-enc" + +#define V4L2_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0x1000) + +#define DST_QUEUE_OFF_BASE (TASK_SIZE / 2) + +#define RK3288_VPU_MAX_CTRLS 32 + +#define MB_DIM 16 +#define MB_WIDTH(x_size) DIV_ROUND_UP(x_size, MB_DIM) +#define MB_HEIGHT(y_size) DIV_ROUND_UP(y_size, MB_DIM) + +struct rk3288_vpu_variant; +struct rk3288_vpu_ctx; +struct rk3288_vpu_codec_ops; + +/** + * enum rk3288_vpu_codec_mode - codec operating mode. + * @RK_VPU_CODEC_NONE: No operating mode. Used for RAW video formats. + * @RK_VPU_CODEC_H264D: H264 decoder. + * @RK_VPU_CODEC_VP8D: VP8 decoder. + * @RK_VPU_CODEC_H264E: H264 encoder. + * @RK_VPU_CODEC_VP8E: VP8 encoder. + */ +enum rk3288_vpu_codec_mode { + RK_VPU_CODEC_NONE = -1, + RK_VPU_CODEC_H264D, + RK_VPU_CODEC_VP8D, + RK_VPU_CODEC_H264E, + RK_VPU_CODEC_VP8E +}; + +/** + * enum rk3288_vpu_plane - indices of planes inside a VB2 buffer. + * @PLANE_Y: Plane containing luminance data (also denoted as Y). + * @PLANE_CB_CR: Plane containing interleaved chrominance data (also + * denoted as CbCr). + * @PLANE_CB: Plane containing CB part of chrominance data. + * @PLANE_CR: Plane containing CR part of chrominance data. + */ +enum rk3288_vpu_plane { + PLANE_Y = 0, + PLANE_CB_CR = 1, + PLANE_CB = 1, + PLANE_CR = 2, +}; + +/** + * struct rk3288_vpu_vp8e_buf_data - mode-specific per-buffer data + * @dct_offset: Offset inside the buffer to DCT partition. + * @hdr_size: Size of header data in the buffer. + * @ext_hdr_size: Size of ext header data in the buffer. + * @dct_size: Size of DCT partition in the buffer. + * @header: Frame header to copy to destination buffer. + */ +struct rk3288_vpu_vp8e_buf_data { + size_t dct_offset; + size_t hdr_size; + size_t ext_hdr_size; + size_t dct_size; + u8 header[RK3288_HEADER_SIZE]; +}; + +/** + * struct rk3288_vpu_buf - Private data related to each VB2 buffer. + * @list: List head for queuing in buffer queue. + * @b: Pointer to related VB2 buffer. + * @flags: Buffer state. See enum rk3288_vpu_buf_flags. + */ +struct rk3288_vpu_buf { + struct vb2_buffer b; + struct list_head list; + + /* Mode-specific data. */ + union { + struct rk3288_vpu_vp8e_buf_data vp8e; + }; +}; + +/** + * enum rk3288_vpu_state - bitwise flags indicating hardware state. + * @VPU_RUNNING: The hardware has been programmed for operation + * and is running at the moment. + * @VPU_SUSPENDED: System is entering sleep state and no more runs + * should be executed on hardware. + */ +enum rk3288_vpu_state { + VPU_RUNNING = BIT(0), + VPU_SUSPENDED = BIT(1), +}; + +/** + * struct rk3288_vpu_dev - driver data + * @v4l2_dev: V4L2 device to register video devices for. + * @vfd_dec: Video device for decoder. + * @vfd_enc: Video device for encoder. + * @pdev: Pointer to VPU platform device. + * @dev: Pointer to device for convenient logging using + * dev_ macros. + * @alloc_ctx: VB2 allocator context + * (for allocations without kernel mapping). + * @alloc_ctx_vm: VB2 allocator context + * (for allocations with kernel mapping). + * @aclk_vcodec: Handle of ACLK clock. + * @hclk_vcodec: Handle of HCLK clock. + * @base: Mapped address of VPU registers. + * @enc_base: Mapped address of VPU encoder register for convenience. + * @dec_base: Mapped address of VPU decoder register for convenience. + * @mapping: DMA IOMMU mapping. + * @vpu_mutex: Mutex to synchronize V4L2 calls. + * @irqlock: Spinlock to synchronize access to data structures + * shared with interrupt handlers. + * @state: Device state. + * @ready_ctxs: List of contexts ready to run. + * @variant: Hardware variant-specfic parameters. + * @current_ctx: Context being currently processed by hardware. + * @run_wq: Wait queue to wait for run completion. + * @watchdog_work: Delayed work for hardware timeout handling. + * @dummy_encode_ctx: Context used to run dummy frame encoding to initialize + * encoder hardware state. + * @dummy_encode_src: Source buffers used for dummy frame encoding. + * @dummy_encode_dst: Desintation buffer used for dummy frame encoding. + * @was_decoding: Indicates whether last run context was a decoder. + */ +struct rk3288_vpu_dev { + struct v4l2_device v4l2_dev; + struct video_device *vfd_dec; + struct video_device *vfd_enc; + struct platform_device *pdev; + struct device *dev; + void *alloc_ctx; + void *alloc_ctx_vm; + struct clk *aclk_vcodec; + struct clk *hclk_vcodec; + void __iomem *base; + void __iomem *enc_base; + void __iomem *dec_base; + struct dma_iommu_mapping *mapping; + + struct mutex vpu_mutex; /* video_device lock */ + spinlock_t irqlock; + unsigned long state; + struct list_head ready_ctxs; + const struct rk3288_vpu_variant *variant; + struct rk3288_vpu_ctx *current_ctx; + wait_queue_head_t run_wq; + struct delayed_work watchdog_work; + struct rk3288_vpu_ctx *dummy_encode_ctx; + struct rk3288_vpu_aux_buf dummy_encode_src[VIDEO_MAX_PLANES]; + struct rk3288_vpu_aux_buf dummy_encode_dst; + bool was_decoding; +}; + +/** + * struct rk3288_vpu_run_ops - per context operations on run data. + * @prepare_run: Called when the context was selected for running + * to prepare operating mode specific data. + * @run_done: Called when hardware completed the run to collect + * operating mode specific data from hardware and + * finalize the processing. + */ +struct rk3288_vpu_run_ops { + void (*prepare_run)(struct rk3288_vpu_ctx *); + void (*run_done)(struct rk3288_vpu_ctx *, enum vb2_buffer_state); +}; + +/** + * struct rk3288_vpu_vp8e_run - per-run data specific to VP8 encoding. + * @reg_params: Pointer to a buffer containing register values prepared + * by user space. + */ +struct rk3288_vpu_vp8e_run { + const struct rk3288_vp8e_reg_params *reg_params; +}; + +/** + * struct rk3288_vpu_vp8d_run - per-run data specific to VP8 decoding. + * @frame_hdr: Pointer to a buffer containing per-run frame data which + * is needed by setting vpu register. + */ +struct rk3288_vpu_vp8d_run { + const struct v4l2_ctrl_vp8_frame_hdr *frame_hdr; +}; + +/** + * struct rk3288_vpu_h264d_run - per-run data specific to H264 decoding. + * @sps: Pointer to a buffer containing H264 SPS. + * @pps: Pointer to a buffer containing H264 PPS. + * @scaling_matrix: Pointer to a buffer containing scaling matrix. + * @slice_param: Pointer to a buffer containing slice parameters array. + * @decode_param: Pointer to a buffer containing decode parameters. + * @dpb: Array of DPB entries reordered to keep POC order. + * @dpb_map: Map of indices used in ref_pic_list_* into indices to + * reordered DPB array. + */ +struct rk3288_vpu_h264d_run { + const struct v4l2_ctrl_h264_sps *sps; + const struct v4l2_ctrl_h264_pps *pps; + const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix; + const struct v4l2_ctrl_h264_slice_param *slice_param; + const struct v4l2_ctrl_h264_decode_param *decode_param; + struct v4l2_h264_dpb_entry dpb[16]; + u8 dpb_map[16]; +}; + +/** + * struct rk3288_vpu_run - per-run data for hardware code. + * @src: Source buffer to be processed. + * @dst: Destination buffer to be processed. + * @priv_src: Hardware private source buffer. + * @priv_dst: Hardware private destination buffer. + */ +struct rk3288_vpu_run { + /* Generic for more than one operating mode. */ + struct rk3288_vpu_buf *src; + struct rk3288_vpu_buf *dst; + + struct rk3288_vpu_aux_buf priv_src; + struct rk3288_vpu_aux_buf priv_dst; + + /* Specific for particular operating modes. */ + union { + struct rk3288_vpu_vp8e_run vp8e; + struct rk3288_vpu_vp8d_run vp8d; + struct rk3288_vpu_h264d_run h264d; + /* Other modes will need different data. */ + }; +}; + +/** + * struct rk3288_vpu_ctx - Context (instance) private data. + * + * @dev: VPU driver data to which the context belongs. + * @fh: V4L2 file handler. + * + * @vpu_src_fmt: Descriptor of active source format. + * @src_fmt: V4L2 pixel format of active source format. + * @vpu_dst_fmt: Descriptor of active destination format. + * @dst_fmt: V4L2 pixel format of active destination format. + * + * @vq_src: Videobuf2 source queue. + * @src_queue: Internal source buffer queue. + * @src_crop: Configured source crop rectangle (encoder-only). + * @vq_dst: Videobuf2 destination queue + * @dst_queue: Internal destination buffer queue. + * @dst_bufs: Private buffers wrapping VB2 buffers (destination). + * + * @ctrls: Array containing pointer to registered controls. + * @ctrl_handler: Control handler used to register controls. + * @num_ctrls: Number of registered controls. + * + * @list: List head for queue of ready contexts. + * + * @run: Structure containing data about currently scheduled + * processing run. + * @run_ops: Set of operations related to currently scheduled run. + * @hw: Structure containing hardware-related context. + */ +struct rk3288_vpu_ctx { + struct rk3288_vpu_dev *dev; + struct v4l2_fh fh; + + /* Format info */ + struct rk3288_vpu_fmt *vpu_src_fmt; + struct v4l2_pix_format_mplane src_fmt; + struct rk3288_vpu_fmt *vpu_dst_fmt; + struct v4l2_pix_format_mplane dst_fmt; + + /* VB2 queue data */ + struct vb2_queue vq_src; + struct list_head src_queue; + struct v4l2_rect src_crop; + struct vb2_queue vq_dst; + struct list_head dst_queue; + struct vb2_buffer *dst_bufs[VIDEO_MAX_FRAME]; + + /* Controls */ + struct v4l2_ctrl *ctrls[RK3288_VPU_MAX_CTRLS]; + struct v4l2_ctrl_handler ctrl_handler; + unsigned num_ctrls; + + /* Various runtime data */ + struct list_head list; + + struct rk3288_vpu_run run; + const struct rk3288_vpu_run_ops *run_ops; + struct rk3288_vpu_hw_ctx hw; +}; + +/** + * struct rk3288_vpu_fmt - information about supported video formats. + * @name: Human readable name of the format. + * @fourcc: FourCC code of the format. See V4L2_PIX_FMT_*. + * @codec_mode: Codec mode related to this format. See + * enum rk3288_vpu_codec_mode. + * @num_planes: Number of planes used by this format. + * @depth: Depth of each plane in bits per pixel. + * @enc_fmt: Format identifier for encoder registers. + */ +struct rk3288_vpu_fmt { + char *name; + u32 fourcc; + enum rk3288_vpu_codec_mode codec_mode; + int num_planes; + u8 depth[VIDEO_MAX_PLANES]; + enum rk3288_vpu_enc_fmt enc_fmt; +}; + +/** + * struct rk3288_vpu_control - information about controls to be registered. + * @id: Control ID. + * @type: Type of the control. + * @name: Human readable name of the control. + * @minimum: Minimum value of the control. + * @maximum: Maximum value of the control. + * @step: Control value increase step. + * @menu_skip_mask: Mask of invalid menu positions. + * @default_value: Initial value of the control. + * @max_stores: Maximum number of configration stores. + * @dims: Size of each dimension of compound control. + * @elem_size: Size of individual element of compound control. + * @is_volatile: Control is volatile. + * @is_read_only: Control is read-only. + * @can_store: Control uses configuration stores. + * + * See also struct v4l2_ctrl_config. + */ +struct rk3288_vpu_control { + u32 id; + + enum v4l2_ctrl_type type; + const char *name; + s32 minimum; + s32 maximum; + s32 step; + u32 menu_skip_mask; + s32 default_value; + s32 max_stores; + u32 dims[V4L2_CTRL_MAX_DIMS]; + u32 elem_size; + + bool is_volatile:1; + bool is_read_only:1; + bool can_store:1; +}; + +/* Logging helpers */ + +/** + * debug - Module parameter to control level of debugging messages. + * + * Level of debugging messages can be controlled by bits of module parameter + * called "debug". Meaning of particular bits is as follows: + * + * bit 0 - global information: mode, size, init, release + * bit 1 - each run start/result information + * bit 2 - contents of small controls from userspace + * bit 3 - contents of big controls from userspace + * bit 4 - detail fmt, ctrl, buffer q/dq information + * bit 5 - detail function enter/leave trace information + * bit 6 - register write/read information + */ +extern int debug; + +#define vpu_debug(level, fmt, args...) \ + do { \ + if (debug & BIT(level)) \ + pr_debug("%s:%d: " fmt, \ + __func__, __LINE__, ##args); \ + } while (0) + +#define vpu_debug_enter() vpu_debug(5, "enter\n") +#define vpu_debug_leave() vpu_debug(5, "leave\n") + +#define vpu_err(fmt, args...) \ + pr_err("%s:%d: " fmt, __func__, __LINE__, ##args) + +static inline char *fmt2str(u32 fmt, char *str) +{ + char a = fmt & 0xFF; + char b = (fmt >> 8) & 0xFF; + char c = (fmt >> 16) & 0xFF; + char d = (fmt >> 24) & 0xFF; + + sprintf(str, "%c%c%c%c", a, b, c, d); + + return str; +} + +/* Structure access helpers. */ +static inline struct rk3288_vpu_ctx *fh_to_ctx(struct v4l2_fh *fh) +{ + return container_of(fh, struct rk3288_vpu_ctx, fh); +} + +static inline struct rk3288_vpu_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl) +{ + return container_of(ctrl->handler, struct rk3288_vpu_ctx, ctrl_handler); +} + +static inline struct rk3288_vpu_buf *vb_to_buf(struct vb2_buffer *vb) +{ + return container_of(vb, struct rk3288_vpu_buf, b); +} + +static inline bool rk3288_vpu_ctx_is_encoder(struct rk3288_vpu_ctx *ctx) +{ + return ctx->vpu_dst_fmt->codec_mode != RK_VPU_CODEC_NONE; +} + +static inline bool rk3288_vpu_ctx_is_dummy_encode(struct rk3288_vpu_ctx *ctx) +{ + struct rk3288_vpu_dev *dev = ctx->dev; + + return ctx == dev->dummy_encode_ctx; +} + +int rk3288_vpu_ctrls_setup(struct rk3288_vpu_ctx *ctx, + const struct v4l2_ctrl_ops *ctrl_ops, + struct rk3288_vpu_control *controls, + unsigned num_ctrls, + const char *const *(*get_menu)(u32)); +void rk3288_vpu_ctrls_delete(struct rk3288_vpu_ctx *ctx); + +void rk3288_vpu_try_context(struct rk3288_vpu_dev *dev, + struct rk3288_vpu_ctx *ctx); + +void rk3288_vpu_run_done(struct rk3288_vpu_ctx *ctx, + enum vb2_buffer_state result); + +int rk3288_vpu_aux_buf_alloc(struct rk3288_vpu_dev *vpu, + struct rk3288_vpu_aux_buf *buf, size_t size); +void rk3288_vpu_aux_buf_free(struct rk3288_vpu_dev *vpu, + struct rk3288_vpu_aux_buf *buf); + +/* Register accessors. */ +static inline void vepu_write_relaxed(struct rk3288_vpu_dev *vpu, + u32 val, u32 reg) +{ + vpu_debug(6, "MARK: set reg[%03d]: %08x\n", reg / 4, val); + writel_relaxed(val, vpu->enc_base + reg); +} + +static inline void vepu_write(struct rk3288_vpu_dev *vpu, u32 val, u32 reg) +{ + vpu_debug(6, "MARK: set reg[%03d]: %08x\n", reg / 4, val); + writel(val, vpu->enc_base + reg); +} + +static inline u32 vepu_read(struct rk3288_vpu_dev *vpu, u32 reg) +{ + u32 val = readl(vpu->enc_base + reg); + + vpu_debug(6, "MARK: get reg[%03d]: %08x\n", reg / 4, val); + return val; +} + +static inline void vdpu_write_relaxed(struct rk3288_vpu_dev *vpu, + u32 val, u32 reg) +{ + vpu_debug(6, "MARK: set reg[%03d]: %08x\n", reg / 4, val); + writel_relaxed(val, vpu->dec_base + reg); +} + +static inline void vdpu_write(struct rk3288_vpu_dev *vpu, u32 val, u32 reg) +{ + vpu_debug(6, "MARK: set reg[%03d]: %08x\n", reg / 4, val); + writel(val, vpu->dec_base + reg); +} + +static inline u32 vdpu_read(struct rk3288_vpu_dev *vpu, u32 reg) +{ + u32 val = readl(vpu->dec_base + reg); + + vpu_debug(6, "MARK: get reg[%03d]: %08x\n", reg / 4, val); + return val; +} + +#endif /* RK3288_VPU_COMMON_H_ */ diff --git a/drivers/media/platform/rockchip-vpu/rk3288_vpu_dec.c b/drivers/media/platform/rockchip-vpu/rk3288_vpu_dec.c new file mode 100644 index 000000000000..3d4aad957a1e --- /dev/null +++ b/drivers/media/platform/rockchip-vpu/rk3288_vpu_dec.c @@ -0,0 +1,1152 @@ +/* + * Rockchip RK3288 VPU codec driver + * + * Copyright (C) 2014 Rockchip Electronics Co., Ltd. + * Hertz Wong + * + * Copyright (C) 2014 Google, Inc. + * Tomasz Figa + * + * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. + * + * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "rk3288_vpu_common.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "rk3288_vpu_dec.h" +#include "rk3288_vpu_hw.h" + +#define DEF_SRC_FMT_DEC V4L2_PIX_FMT_H264_SLICE +#define DEF_DST_FMT_DEC V4L2_PIX_FMT_NV12 + +#define RK3288_DEC_MIN_WIDTH 48U +#define RK3288_DEC_MAX_WIDTH 3840U +#define RK3288_DEC_MIN_HEIGHT 48U +#define RK3288_DEC_MAX_HEIGHT 2160U + +#define RK3288_H264_MAX_SLICES_PER_FRAME 16 + +static struct rk3288_vpu_fmt formats[] = { + { + .name = "4:2:0 1 plane Y/CbCr", + .fourcc = V4L2_PIX_FMT_NV12, + .codec_mode = RK_VPU_CODEC_NONE, + .num_planes = 1, + .depth = { 12 }, + }, + { + .name = "Slices of H264 Encoded Stream", + .fourcc = V4L2_PIX_FMT_H264_SLICE, + .codec_mode = RK_VPU_CODEC_H264D, + .num_planes = 1, + }, + { + .name = "Frames of VP8 Encoded Stream", + .fourcc = V4L2_PIX_FMT_VP8_FRAME, + .codec_mode = RK_VPU_CODEC_VP8D, + .num_planes = 1, + }, +}; + +static struct rk3288_vpu_fmt *find_format(u32 fourcc, bool bitstream) +{ + unsigned int i; + + vpu_debug_enter(); + + for (i = 0; i < ARRAY_SIZE(formats); i++) { + if (formats[i].fourcc == fourcc && + !!bitstream == (formats[i].codec_mode != RK_VPU_CODEC_NONE)) + return &formats[i]; + } + + return NULL; +} + +/* Indices of controls that need to be accessed directly. */ +enum { + RK3288_VPU_DEC_CTRL_H264_SPS, + RK3288_VPU_DEC_CTRL_H264_PPS, + RK3288_VPU_DEC_CTRL_H264_SCALING_MATRIX, + RK3288_VPU_DEC_CTRL_H264_SLICE_PARAM, + RK3288_VPU_DEC_CTRL_H264_DECODE_PARAM, + RK3288_VPU_DEC_CTRL_VP8_FRAME_HDR, +}; + +static struct rk3288_vpu_control controls[] = { + /* H264 slice-based interface. */ + [RK3288_VPU_DEC_CTRL_H264_SPS] = { + .id = V4L2_CID_MPEG_VIDEO_H264_SPS, + .type = V4L2_CTRL_TYPE_PRIVATE, + .name = "H264 SPS Parameters", + .elem_size = sizeof(struct v4l2_ctrl_h264_sps), + .max_stores = VIDEO_MAX_FRAME, + .can_store = true, + }, + [RK3288_VPU_DEC_CTRL_H264_PPS] = { + .id = V4L2_CID_MPEG_VIDEO_H264_PPS, + .type = V4L2_CTRL_TYPE_PRIVATE, + .name = "H264 PPS Parameters", + .elem_size = sizeof(struct v4l2_ctrl_h264_pps), + .max_stores = VIDEO_MAX_FRAME, + .can_store = true, + }, + [RK3288_VPU_DEC_CTRL_H264_SCALING_MATRIX] = { + .id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, + .type = V4L2_CTRL_TYPE_PRIVATE, + .name = "H264 Scaling Matrix", + .elem_size = sizeof(struct v4l2_ctrl_h264_scaling_matrix), + .max_stores = VIDEO_MAX_FRAME, + .can_store = true, + }, + [RK3288_VPU_DEC_CTRL_H264_SLICE_PARAM] = { + .id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAM, + .type = V4L2_CTRL_TYPE_PRIVATE, + .name = "H264 Slice Parameters", + .max_stores = VIDEO_MAX_FRAME, + .elem_size = sizeof(struct v4l2_ctrl_h264_slice_param), + .dims = { RK3288_H264_MAX_SLICES_PER_FRAME, }, + .can_store = true, + }, + [RK3288_VPU_DEC_CTRL_H264_DECODE_PARAM] = { + .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAM, + .type = V4L2_CTRL_TYPE_PRIVATE, + .name = "H264 Decode Parameters", + .max_stores = VIDEO_MAX_FRAME, + .elem_size = sizeof(struct v4l2_ctrl_h264_decode_param), + .can_store = true, + }, + [RK3288_VPU_DEC_CTRL_VP8_FRAME_HDR] = { + .id = V4L2_CID_MPEG_VIDEO_VP8_FRAME_HDR, + .type = V4L2_CTRL_TYPE_PRIVATE, + .name = "VP8 Frame Header Parameters", + .max_stores = VIDEO_MAX_FRAME, + .elem_size = sizeof(struct v4l2_ctrl_vp8_frame_hdr), + .can_store = true, + }, +}; + +static inline const void *get_ctrl_ptr(struct rk3288_vpu_ctx *ctx, unsigned id) +{ + struct v4l2_ctrl *ctrl = ctx->ctrls[id]; + + return ctrl->p_cur.p; +} + +/* Query capabilities of the device */ +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct rk3288_vpu_dev *dev = video_drvdata(file); + + vpu_debug_enter(); + + strlcpy(cap->driver, RK3288_VPU_DEC_NAME, sizeof(cap->driver)); + strlcpy(cap->card, dev->pdev->name, sizeof(cap->card)); + strlcpy(cap->bus_info, "platform:" RK3288_VPU_NAME, + sizeof(cap->bus_info)); + + /* + * This is only a mem-to-mem video device. The capture and output + * device capability flags are left only for backward compatibility + * and are scheduled for removal. + */ + cap->capabilities = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE; + + vpu_debug_leave(); + + return 0; +} + +static int vidioc_enum_framesizes(struct file *file, void *prov, + struct v4l2_frmsizeenum *fsize) +{ + struct v4l2_frmsize_stepwise *s = &fsize->stepwise; + struct rk3288_vpu_fmt *fmt; + + if (fsize->index != 0) { + vpu_debug(0, "invalid frame size index (expected 0, got %d)\n", + fsize->index); + return -EINVAL; + } + + fmt = find_format(fsize->pixel_format, true); + if (!fmt) { + vpu_debug(0, "unsupported bitstream format (%08x)\n", + fsize->pixel_format); + return -EINVAL; + } + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + + s->min_width = RK3288_DEC_MIN_WIDTH; + s->max_width = RK3288_DEC_MAX_WIDTH; + s->step_width = MB_DIM; + s->min_height = RK3288_DEC_MIN_HEIGHT; + s->max_height = RK3288_DEC_MAX_HEIGHT; + s->step_height = MB_DIM; + + return 0; +} + +static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool out) +{ + struct rk3288_vpu_fmt *fmt; + int i, j = 0; + + vpu_debug_enter(); + + for (i = 0; i < ARRAY_SIZE(formats); ++i) { + if (out && formats[i].codec_mode == RK_VPU_CODEC_NONE) + continue; + else if (!out && (formats[i].codec_mode != RK_VPU_CODEC_NONE)) + continue; + + if (j == f->index) { + fmt = &formats[i]; + strlcpy(f->description, fmt->name, + sizeof(f->description)); + f->pixelformat = fmt->fourcc; + + f->flags = 0; + if (formats[i].codec_mode != RK_VPU_CODEC_NONE) + f->flags |= V4L2_FMT_FLAG_COMPRESSED; + + vpu_debug_leave(); + + return 0; + } + + ++j; + } + + vpu_debug_leave(); + + return -EINVAL; +} + +static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + return vidioc_enum_fmt(f, false); +} + +static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + return vidioc_enum_fmt(f, true); +} + +static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); + + vpu_debug_enter(); + + vpu_debug(4, "f->type = %d\n", f->type); + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + f->fmt.pix_mp = ctx->dst_fmt; + break; + + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + f->fmt.pix_mp = ctx->src_fmt; + break; + + default: + vpu_err("invalid buf type\n"); + return -EINVAL; + } + + vpu_debug_leave(); + + return 0; +} + +static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct rk3288_vpu_fmt *fmt; + struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; + char str[5]; + + vpu_debug_enter(); + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + vpu_debug(4, "%s\n", fmt2str(f->fmt.pix_mp.pixelformat, str)); + + fmt = find_format(pix_fmt_mp->pixelformat, true); + if (!fmt) { + vpu_err("failed to try output format\n"); + return -EINVAL; + } + + if (pix_fmt_mp->plane_fmt[0].sizeimage == 0) { + vpu_err("sizeimage of output format must be given\n"); + return -EINVAL; + } + + pix_fmt_mp->plane_fmt[0].bytesperline = 0; + break; + + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + vpu_debug(4, "%s\n", fmt2str(f->fmt.pix_mp.pixelformat, str)); + + fmt = find_format(pix_fmt_mp->pixelformat, false); + if (!fmt) { + vpu_err("failed to try capture format\n"); + return -EINVAL; + } + + if (fmt->num_planes != pix_fmt_mp->num_planes) { + vpu_err("plane number mismatches on capture format\n"); + return -EINVAL; + } + + /* Limit to hardware min/max. */ + pix_fmt_mp->width = clamp(pix_fmt_mp->width, + RK3288_DEC_MIN_WIDTH, RK3288_DEC_MAX_WIDTH); + pix_fmt_mp->height = clamp(pix_fmt_mp->height, + RK3288_DEC_MIN_HEIGHT, RK3288_DEC_MAX_HEIGHT); + + /* Round up to macroblocks. */ + pix_fmt_mp->width = round_up(pix_fmt_mp->width, MB_DIM); + pix_fmt_mp->height = round_up(pix_fmt_mp->height, MB_DIM); + break; + + default: + vpu_err("invalid buf type\n"); + return -EINVAL; + } + + vpu_debug_leave(); + + return 0; +} + +static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; + struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); + unsigned int mb_width, mb_height; + struct rk3288_vpu_fmt *fmt; + int ret = 0; + int i; + + vpu_debug_enter(); + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + /* Change not allowed if any queue is streaming. */ + if (vb2_is_streaming(&ctx->vq_src) + || vb2_is_streaming(&ctx->vq_dst)) { + ret = -EBUSY; + goto out; + } + /* + * Pixel format change is not allowed when the other queue has + * buffers allocated. + */ + if (vb2_is_busy(&ctx->vq_dst) + && pix_fmt_mp->pixelformat != ctx->src_fmt.pixelformat) { + ret = -EBUSY; + goto out; + } + + ret = vidioc_try_fmt(file, priv, f); + if (ret) + goto out; + + ctx->vpu_src_fmt = find_format(pix_fmt_mp->pixelformat, true); + ctx->src_fmt = *pix_fmt_mp; + break; + + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + /* + * Change not allowed if this queue is streaming. + * + * NOTE: We allow changes with source queue streaming + * to support resolution change in decoded stream. + */ + if (vb2_is_streaming(&ctx->vq_dst)) { + ret = -EBUSY; + goto out; + } + /* + * Pixel format change is not allowed when the other queue has + * buffers allocated. + */ + if (vb2_is_busy(&ctx->vq_src) + && pix_fmt_mp->pixelformat != ctx->dst_fmt.pixelformat) { + ret = -EBUSY; + goto out; + } + + ret = vidioc_try_fmt(file, priv, f); + if (ret) + goto out; + + fmt = find_format(pix_fmt_mp->pixelformat, false); + ctx->vpu_dst_fmt = fmt; + + mb_width = MB_WIDTH(pix_fmt_mp->width); + mb_height = MB_HEIGHT(pix_fmt_mp->height); + + vpu_debug(0, "CAPTURE codec mode: %d\n", fmt->codec_mode); + vpu_debug(0, "fmt - w: %d, h: %d, mb - w: %d, h: %d\n", + pix_fmt_mp->width, pix_fmt_mp->height, + mb_width, mb_height); + + for (i = 0; i < fmt->num_planes; ++i) { + pix_fmt_mp->plane_fmt[i].bytesperline = + mb_width * MB_DIM * fmt->depth[i] / 8; + pix_fmt_mp->plane_fmt[i].sizeimage = + pix_fmt_mp->plane_fmt[i].bytesperline + * mb_height * MB_DIM; + /* + * All of multiplanar formats we support have chroma + * planes subsampled by 2. + */ + if (i != 0) + pix_fmt_mp->plane_fmt[i].sizeimage /= 2; + } + + ctx->dst_fmt = *pix_fmt_mp; + break; + + default: + vpu_err("invalid buf type\n"); + return -EINVAL; + } + +out: + vpu_debug_leave(); + + return ret; +} + +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *reqbufs) +{ + struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); + int ret; + + vpu_debug_enter(); + + switch (reqbufs->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + ret = vb2_reqbufs(&ctx->vq_src, reqbufs); + if (ret != 0) { + vpu_err("error in vb2_reqbufs() for E(S)\n"); + goto out; + } + break; + + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); + if (ret != 0) { + vpu_err("error in vb2_reqbufs() for E(D)\n"); + goto out; + } + break; + + default: + vpu_err("invalid buf type\n"); + ret = -EINVAL; + goto out; + } + +out: + vpu_debug_leave(); + + return ret; +} + +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); + int ret; + + vpu_debug_enter(); + + switch (buf->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + ret = vb2_querybuf(&ctx->vq_dst, buf); + if (ret != 0) { + vpu_err("error in vb2_querybuf() for E(D)\n"); + goto out; + } + + buf->m.planes[0].m.mem_offset += DST_QUEUE_OFF_BASE; + break; + + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + ret = vb2_querybuf(&ctx->vq_src, buf); + if (ret != 0) { + vpu_err("error in vb2_querybuf() for E(S)\n"); + goto out; + } + break; + + default: + vpu_err("invalid buf type\n"); + ret = -EINVAL; + goto out; + } + +out: + vpu_debug_leave(); + + return ret; +} + +/* Queue a buffer */ +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); + int ret; + int i; + + vpu_debug_enter(); + + for (i = 0; i < buf->length; i++) + vpu_debug(4, "plane[%d]->length %d bytesused %d\n", + i, buf->m.planes[i].length, + buf->m.planes[i].bytesused); + + switch (buf->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + ret = vb2_qbuf(&ctx->vq_src, buf); + vpu_debug(4, "OUTPUT_MPLANE : vb2_qbuf return %d\n", ret); + break; + + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + ret = vb2_qbuf(&ctx->vq_dst, buf); + vpu_debug(4, "CAPTURE_MPLANE: vb2_qbuf return %d\n", ret); + break; + + default: + ret = -EINVAL; + } + + vpu_debug_leave(); + + return ret; +} + +/* Dequeue a buffer */ +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); + int ret; + + vpu_debug_enter(); + + switch (buf->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + ret = vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK); + break; + + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + ret = vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK); + break; + + default: + ret = -EINVAL; + } + + vpu_debug_leave(); + + return ret; +} + +/* Export DMA buffer */ +static int vidioc_expbuf(struct file *file, void *priv, + struct v4l2_exportbuffer *eb) +{ + struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); + int ret; + + vpu_debug_enter(); + + switch (eb->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + ret = vb2_expbuf(&ctx->vq_src, eb); + break; + + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + ret = vb2_expbuf(&ctx->vq_dst, eb); + break; + + default: + ret = -EINVAL; + } + + vpu_debug_leave(); + + return ret; +} + +/* Stream on */ +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); + int ret; + + vpu_debug_enter(); + + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + ret = vb2_streamon(&ctx->vq_src, type); + break; + + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + ret = vb2_streamon(&ctx->vq_dst, type); + break; + + default: + ret = -EINVAL; + } + + vpu_debug_leave(); + + return ret; +} + +/* Stream off, which equals to a pause */ +static int vidioc_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); + int ret; + + vpu_debug_enter(); + + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + ret = vb2_streamoff(&ctx->vq_src, type); + break; + + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + ret = vb2_streamoff(&ctx->vq_dst, type); + break; + + default: + ret = -EINVAL; + } + + vpu_debug_leave(); + + return ret; +} + +static void rk3288_vpu_dec_set_dpb(struct rk3288_vpu_ctx *ctx, + struct v4l2_ctrl *ctrl) +{ + struct v4l2_ctrl_h264_decode_param *dec_param = ctrl->p_new.p; + const struct v4l2_h264_dpb_entry *new_dpb_entry; + u8 *dpb_map = ctx->run.h264d.dpb_map; + struct v4l2_h264_dpb_entry *cur_dpb_entry; + DECLARE_BITMAP(used, ARRAY_SIZE(ctx->run.h264d.dpb)) = { 0, }; + DECLARE_BITMAP(new, ARRAY_SIZE(dec_param->dpb)) = { 0, }; + int i, j; + + BUILD_BUG_ON(ARRAY_SIZE(ctx->run.h264d.dpb) != + ARRAY_SIZE(dec_param->dpb)); + + /* Disable all entries by default. */ + for (j = 0; j < ARRAY_SIZE(ctx->run.h264d.dpb); ++j) { + cur_dpb_entry = &ctx->run.h264d.dpb[j]; + + cur_dpb_entry->flags &= ~V4L2_H264_DPB_ENTRY_FLAG_ACTIVE; + } + + /* Try to match new DPB entries with existing ones by their POCs. */ + for (i = 0; i < ARRAY_SIZE(dec_param->dpb); ++i) { + new_dpb_entry = &dec_param->dpb[i]; + + if (!(new_dpb_entry->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) + continue; + + /* + * To cut off some comparisons, iterate only on target DPB + * entries which are not used yet. + */ + for_each_clear_bit(j, used, ARRAY_SIZE(ctx->run.h264d.dpb)) { + cur_dpb_entry = &ctx->run.h264d.dpb[j]; + + if (new_dpb_entry->top_field_order_cnt == + cur_dpb_entry->top_field_order_cnt && + new_dpb_entry->bottom_field_order_cnt == + cur_dpb_entry->bottom_field_order_cnt) { + memcpy(cur_dpb_entry, new_dpb_entry, + sizeof(*cur_dpb_entry)); + set_bit(j, used); + dpb_map[i] = j; + break; + } + } + + if (j == ARRAY_SIZE(ctx->run.h264d.dpb)) + set_bit(i, new); + } + + /* For entries that could not be matched, use remaining free slots. */ + for_each_set_bit(i, new, ARRAY_SIZE(dec_param->dpb)) { + new_dpb_entry = &dec_param->dpb[i]; + + j = find_first_zero_bit(used, ARRAY_SIZE(ctx->run.h264d.dpb)); + /* + * Both arrays are of the same sizes, so there is no way + * we can end up with no space in target array, unless + * something is buggy. + */ + if (WARN_ON(j >= ARRAY_SIZE(ctx->run.h264d.dpb))) + return; + + cur_dpb_entry = &ctx->run.h264d.dpb[j]; + memcpy(cur_dpb_entry, new_dpb_entry, sizeof(*cur_dpb_entry)); + set_bit(j, used); + dpb_map[i] = j; + } + + /* + * Verify that reference picture lists are in range, since they + * will be indexing dpb_map[] when programming the hardware. + * + * Fallback to 0 should be safe, as we will get at most corrupt + * decoding result, without any serious side effects. Moreover, + * even if entry 0 is unused, the hardware programming code will + * handle this properly. + */ + for (i = 0; i < ARRAY_SIZE(dec_param->ref_pic_list_b0); ++i) + if (dec_param->ref_pic_list_b0[i] + >= ARRAY_SIZE(ctx->run.h264d.dpb_map)) + dec_param->ref_pic_list_b0[i] = 0; + for (i = 0; i < ARRAY_SIZE(dec_param->ref_pic_list_b1); ++i) + if (dec_param->ref_pic_list_b1[i] + >= ARRAY_SIZE(ctx->run.h264d.dpb_map)) + dec_param->ref_pic_list_b1[i] = 0; + for (i = 0; i < ARRAY_SIZE(dec_param->ref_pic_list_p0); ++i) + if (dec_param->ref_pic_list_p0[i] + >= ARRAY_SIZE(ctx->run.h264d.dpb_map)) + dec_param->ref_pic_list_p0[i] = 0; +} + +static int rk3288_vpu_dec_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct rk3288_vpu_ctx *ctx = ctrl_to_ctx(ctrl); + struct rk3288_vpu_dev *dev = ctx->dev; + int ret = 0; + + vpu_debug_enter(); + + vpu_debug(4, "ctrl id %d\n", ctrl->id); + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDEO_H264_SPS: + case V4L2_CID_MPEG_VIDEO_H264_PPS: + case V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX: + case V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAM: + case V4L2_CID_MPEG_VIDEO_VP8_FRAME_HDR: + /* These controls are used directly. */ + break; + + case V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAM: + if (ctrl->store) + break; + rk3288_vpu_dec_set_dpb(ctx, ctrl); + break; + + default: + v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n", + ctrl->id, ctrl->val); + ret = -EINVAL; + } + + vpu_debug_leave(); + + return ret; +} + +static const struct v4l2_ctrl_ops rk3288_vpu_dec_ctrl_ops = { + .s_ctrl = rk3288_vpu_dec_s_ctrl, +}; + +static const struct v4l2_ioctl_ops rk3288_vpu_dec_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_framesizes = vidioc_enum_framesizes, + .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane, + .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane, + .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt, + .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt, + .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt, + .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt, + .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt, + .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_expbuf = vidioc_expbuf, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, +}; + +static int rk3288_vpu_queue_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, + unsigned int *buf_count, + unsigned int *plane_count, + unsigned int psize[], void *allocators[]) +{ + struct rk3288_vpu_ctx *ctx = fh_to_ctx(vq->drv_priv); + int ret = 0; + + vpu_debug_enter(); + + switch (vq->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + *plane_count = ctx->vpu_src_fmt->num_planes; + + if (*buf_count < 1) + *buf_count = 1; + + if (*buf_count > VIDEO_MAX_FRAME) + *buf_count = VIDEO_MAX_FRAME; + + psize[0] = ctx->src_fmt.plane_fmt[0].sizeimage; + allocators[0] = ctx->dev->alloc_ctx; + vpu_debug(0, "output psize[%d]: %d\n", 0, psize[0]); + break; + + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + *plane_count = ctx->vpu_dst_fmt->num_planes; + + if (*buf_count < 1) + *buf_count = 1; + + if (*buf_count > VIDEO_MAX_FRAME) + *buf_count = VIDEO_MAX_FRAME; + + psize[0] = round_up(ctx->dst_fmt.plane_fmt[0].sizeimage, 8); + allocators[0] = ctx->dev->alloc_ctx; + + if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_H264_SLICE) + /* Add space for appended motion vectors. */ + psize[0] += 64 * MB_WIDTH(ctx->dst_fmt.width) + * MB_HEIGHT(ctx->dst_fmt.height); + + vpu_debug(0, "capture psize[%d]: %d\n", 0, psize[0]); + break; + + default: + vpu_err("invalid queue type: %d\n", vq->type); + ret = -EINVAL; + } + + vpu_debug_leave(); + + return ret; +} + +static int rk3288_vpu_buf_init(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct rk3288_vpu_ctx *ctx = fh_to_ctx(vq->drv_priv); + + vpu_debug_enter(); + + if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + ctx->dst_bufs[vb->v4l2_buf.index] = vb; + + vpu_debug_leave(); + + return 0; +} + +static void rk3288_vpu_buf_cleanup(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct rk3288_vpu_ctx *ctx = fh_to_ctx(vq->drv_priv); + + vpu_debug_enter(); + + if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + ctx->dst_bufs[vb->v4l2_buf.index] = NULL; + + vpu_debug_leave(); +} + +static int rk3288_vpu_buf_prepare(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct rk3288_vpu_ctx *ctx = fh_to_ctx(vq->drv_priv); + int ret = 0; + int i; + + vpu_debug_enter(); + + switch (vq->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + vpu_debug(4, "plane size: %ld, dst size: %d\n", + vb2_plane_size(vb, 0), + ctx->src_fmt.plane_fmt[0].sizeimage); + + if (vb2_plane_size(vb, 0) + < ctx->src_fmt.plane_fmt[0].sizeimage) { + vpu_err("plane size is too small for output\n"); + ret = -EINVAL; + } + break; + + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + for (i = 0; i < ctx->vpu_dst_fmt->num_planes; ++i) { + vpu_debug(4, "plane %d size: %ld, sizeimage: %u\n", i, + vb2_plane_size(vb, i), + ctx->dst_fmt.plane_fmt[i].sizeimage); + + if (vb2_plane_size(vb, i) + < ctx->dst_fmt.plane_fmt[i].sizeimage) { + vpu_err("size of plane %d is too small for capture\n", + i); + break; + } + } + + if (i != ctx->vpu_dst_fmt->num_planes) + ret = -EINVAL; + break; + + default: + vpu_err("invalid queue type: %d\n", vq->type); + ret = -EINVAL; + } + + vpu_debug_leave(); + + return ret; +} + +static int rk3288_vpu_start_streaming(struct vb2_queue *q, unsigned int count) +{ + int ret = 0; + struct rk3288_vpu_ctx *ctx = fh_to_ctx(q->drv_priv); + struct rk3288_vpu_dev *dev = ctx->dev; + bool ready = false; + + vpu_debug_enter(); + + if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + ret = rk3288_vpu_init(ctx); + if (ret < 0) { + vpu_err("rk3288_vpu_init failed\n"); + return ret; + } + + ready = vb2_is_streaming(&ctx->vq_src); + } else if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + ready = vb2_is_streaming(&ctx->vq_dst); + } + + if (ready) + rk3288_vpu_try_context(dev, ctx); + + vpu_debug_leave(); + + return 0; +} + +static void rk3288_vpu_stop_streaming(struct vb2_queue *q) +{ + unsigned long flags; + struct rk3288_vpu_ctx *ctx = fh_to_ctx(q->drv_priv); + struct rk3288_vpu_dev *dev = ctx->dev; + struct rk3288_vpu_buf *b; + LIST_HEAD(queue); + int i; + + vpu_debug_enter(); + + spin_lock_irqsave(&dev->irqlock, flags); + + list_del_init(&ctx->list); + + switch (q->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + list_splice_init(&ctx->dst_queue, &queue); + break; + + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + list_splice_init(&ctx->src_queue, &queue); + break; + + default: + break; + } + + spin_unlock_irqrestore(&dev->irqlock, flags); + + wait_event(dev->run_wq, dev->current_ctx != ctx); + + while (!list_empty(&queue)) { + b = list_first_entry(&queue, struct rk3288_vpu_buf, list); + for (i = 0; i < b->b.num_planes; i++) + vb2_set_plane_payload(&b->b, i, 0); + vb2_buffer_done(&b->b, VB2_BUF_STATE_ERROR); + list_del(&b->list); + } + + if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + rk3288_vpu_deinit(ctx); + + vpu_debug_leave(); +} + +static void rk3288_vpu_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct rk3288_vpu_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct rk3288_vpu_dev *dev = ctx->dev; + struct rk3288_vpu_buf *vpu_buf; + unsigned long flags; + + vpu_debug_enter(); + + switch (vq->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + vpu_buf = vb_to_buf(vb); + + /* Mark destination as available for use by VPU */ + spin_lock_irqsave(&dev->irqlock, flags); + + list_add_tail(&vpu_buf->list, &ctx->dst_queue); + + spin_unlock_irqrestore(&dev->irqlock, flags); + break; + + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + vpu_buf = vb_to_buf(vb); + + spin_lock_irqsave(&dev->irqlock, flags); + + list_add_tail(&vpu_buf->list, &ctx->src_queue); + + spin_unlock_irqrestore(&dev->irqlock, flags); + break; + + default: + vpu_err("unsupported buffer type (%d)\n", vq->type); + } + + if (vb2_is_streaming(&ctx->vq_src) && vb2_is_streaming(&ctx->vq_dst)) + rk3288_vpu_try_context(dev, ctx); + + vpu_debug_leave(); +} + +static struct vb2_ops rk3288_vpu_dec_qops = { + .queue_setup = rk3288_vpu_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_init = rk3288_vpu_buf_init, + .buf_prepare = rk3288_vpu_buf_prepare, + .buf_cleanup = rk3288_vpu_buf_cleanup, + .start_streaming = rk3288_vpu_start_streaming, + .stop_streaming = rk3288_vpu_stop_streaming, + .buf_queue = rk3288_vpu_buf_queue, +}; + +struct vb2_ops *get_dec_queue_ops(void) +{ + return &rk3288_vpu_dec_qops; +} + +const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void) +{ + return &rk3288_vpu_dec_ioctl_ops; +} + +static void rk3288_vpu_dec_prepare_run(struct rk3288_vpu_ctx *ctx) +{ + struct v4l2_buffer *src = &ctx->run.src->b.v4l2_buf; + + v4l2_ctrl_apply_store(&ctx->ctrl_handler, src->config_store); + + if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_H264_SLICE) { + ctx->run.h264d.sps = get_ctrl_ptr(ctx, + RK3288_VPU_DEC_CTRL_H264_SPS); + ctx->run.h264d.pps = get_ctrl_ptr(ctx, + RK3288_VPU_DEC_CTRL_H264_PPS); + ctx->run.h264d.scaling_matrix = get_ctrl_ptr(ctx, + RK3288_VPU_DEC_CTRL_H264_SCALING_MATRIX); + ctx->run.h264d.slice_param = get_ctrl_ptr(ctx, + RK3288_VPU_DEC_CTRL_H264_SLICE_PARAM); + ctx->run.h264d.decode_param = get_ctrl_ptr(ctx, + RK3288_VPU_DEC_CTRL_H264_DECODE_PARAM); + } else if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_VP8_FRAME) { + ctx->run.vp8d.frame_hdr = get_ctrl_ptr(ctx, + RK3288_VPU_DEC_CTRL_VP8_FRAME_HDR); + } +} + +static void rk3288_vpu_dec_run_done(struct rk3288_vpu_ctx *ctx, + enum vb2_buffer_state result) +{ + struct v4l2_plane_pix_format *plane_fmts = ctx->dst_fmt.plane_fmt; + struct vb2_buffer *dst = &ctx->run.dst->b; + int i; + + if (result != VB2_BUF_STATE_DONE) { + /* Assume no payload after failed run. */ + for (i = 0; i < dst->num_planes; ++i) + vb2_set_plane_payload(dst, i, 0); + return; + } + + for (i = 0; i < dst->num_planes; ++i) + vb2_set_plane_payload(dst, i, plane_fmts[i].sizeimage); +} + +static const struct rk3288_vpu_run_ops rk3288_vpu_dec_run_ops = { + .prepare_run = rk3288_vpu_dec_prepare_run, + .run_done = rk3288_vpu_dec_run_done, +}; + +int rk3288_vpu_dec_init(struct rk3288_vpu_ctx *ctx) +{ + ctx->vpu_src_fmt = find_format(DEF_SRC_FMT_DEC, false); + ctx->vpu_dst_fmt = find_format(DEF_DST_FMT_DEC, true); + + ctx->run_ops = &rk3288_vpu_dec_run_ops; + + return rk3288_vpu_ctrls_setup(ctx, &rk3288_vpu_dec_ctrl_ops, + controls, ARRAY_SIZE(controls), NULL); +} + +void rk3288_vpu_dec_exit(struct rk3288_vpu_ctx *ctx) +{ + rk3288_vpu_ctrls_delete(ctx); +} diff --git a/drivers/media/platform/rockchip-vpu/rk3288_vpu_dec.h b/drivers/media/platform/rockchip-vpu/rk3288_vpu_dec.h new file mode 100644 index 000000000000..ac2598751083 --- /dev/null +++ b/drivers/media/platform/rockchip-vpu/rk3288_vpu_dec.h @@ -0,0 +1,33 @@ +/* + * Rockchip RK3288 VPU codec driver + * + * Copyright (C) 2014 Rockchip Electronics Co., Ltd. + * Hertz Wong + * + * Copyright (C) 2014 Google, Inc. + * Tomasz Figa + * + * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 RK3288_VPU_DEC_H_ +#define RK3288_VPU_DEC_H_ + +struct vb2_ops *get_dec_queue_ops(void); +const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void); +struct rk3288_vpu_fmt *get_dec_def_fmt(bool src); +int rk3288_vpu_dec_init(struct rk3288_vpu_ctx *ctx); +void rk3288_vpu_dec_exit(struct rk3288_vpu_ctx *ctx); + +#endif /* RK3288_VPU_DEC_H_ */ diff --git a/drivers/media/platform/rockchip-vpu/rk3288_vpu_enc.c b/drivers/media/platform/rockchip-vpu/rk3288_vpu_enc.c new file mode 100644 index 000000000000..54b54ae6726d --- /dev/null +++ b/drivers/media/platform/rockchip-vpu/rk3288_vpu_enc.c @@ -0,0 +1,1503 @@ +/* + * Rockchip RK3288 VPU codec driver + * + * Copyright (C) 2014 Rockchip Electronics Co., Ltd. + * Alpha Lin + * Jeffy Chen + * + * Copyright (C) 2014 Google, Inc. + * Tomasz Figa + * + * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. + * + * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "rk3288_vpu_common.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rk3288_vpu_enc.h" +#include "rk3288_vpu_hw.h" + +#define DEF_SRC_FMT_ENC V4L2_PIX_FMT_NV12 +#define DEF_DST_FMT_ENC V4L2_PIX_FMT_VP8 + +#define RK3288_ENC_MIN_WIDTH 96U +#define RK3288_ENC_MAX_WIDTH 1920U +#define RK3288_ENC_MIN_HEIGHT 96U +#define RK3288_ENC_MAX_HEIGHT 1088U + +#define V4L2_CID_PRIVATE_RK3288_HEADER (V4L2_CID_CUSTOM_BASE + 0) +#define V4L2_CID_PRIVATE_RK3288_REG_PARAMS (V4L2_CID_CUSTOM_BASE + 1) +#define V4L2_CID_PRIVATE_RK3288_HW_PARAMS (V4L2_CID_CUSTOM_BASE + 2) +#define V4L2_CID_PRIVATE_RK3288_RET_PARAMS (V4L2_CID_CUSTOM_BASE + 3) + +static struct rk3288_vpu_fmt formats[] = { + /* Source formats. */ + { + .name = "4:2:0 3 planes Y/Cb/Cr", + .fourcc = V4L2_PIX_FMT_YUV420M, + .codec_mode = RK_VPU_CODEC_NONE, + .num_planes = 3, + .depth = { 8, 4, 4 }, + .enc_fmt = RK3288_VPU_ENC_FMT_YUV420P, + }, + { + .name = "4:2:0 2 plane Y/CbCr", + .fourcc = V4L2_PIX_FMT_NV12M, + .codec_mode = RK_VPU_CODEC_NONE, + .num_planes = 2, + .depth = { 8, 8 }, + .enc_fmt = RK3288_VPU_ENC_FMT_YUV420SP, + }, + { + .name = "4:2:2 1 plane YUYV", + .fourcc = V4L2_PIX_FMT_YUYV, + .codec_mode = RK_VPU_CODEC_NONE, + .num_planes = 1, + .depth = { 16 }, + .enc_fmt = RK3288_VPU_ENC_FMT_YUYV422, + }, + { + .name = "4:2:2 1 plane UYVY", + .fourcc = V4L2_PIX_FMT_UYVY, + .codec_mode = RK_VPU_CODEC_NONE, + .num_planes = 1, + .depth = { 16 }, + .enc_fmt = RK3288_VPU_ENC_FMT_UYVY422, + }, + /* Destination formats. */ + { + .name = "VP8 Encoded Stream", + .fourcc = V4L2_PIX_FMT_VP8, + .codec_mode = RK_VPU_CODEC_VP8E, + .num_planes = 1, + }, +}; + +static struct rk3288_vpu_fmt *find_format(u32 fourcc, bool bitstream) +{ + unsigned int i; + + vpu_debug_enter(); + + for (i = 0; i < ARRAY_SIZE(formats); i++) { + if (formats[i].fourcc != fourcc) + continue; + if (bitstream && formats[i].codec_mode != RK_VPU_CODEC_NONE) + return &formats[i]; + if (!bitstream && formats[i].codec_mode == RK_VPU_CODEC_NONE) + return &formats[i]; + } + + return NULL; +} + +/* + * Indices of controls that need to be accessed directly, i.e. through + * p_cur.p pointer of their v4l2_ctrl structs. + */ +enum { + RK3288_VPU_ENC_CTRL_HEADER, + RK3288_VPU_ENC_CTRL_REG_PARAMS, + RK3288_VPU_ENC_CTRL_HW_PARAMS, + RK3288_VPU_ENC_CTRL_RET_PARAMS, +}; + +static struct rk3288_vpu_control controls[] = { + /* Private, per-frame controls. */ + [RK3288_VPU_ENC_CTRL_HEADER] = { + .id = V4L2_CID_PRIVATE_RK3288_HEADER, + .type = V4L2_CTRL_TYPE_PRIVATE, + .name = "Rk3288 Private Header", + .elem_size = RK3288_HEADER_SIZE, + .max_stores = VIDEO_MAX_FRAME, + .can_store = true, + }, + [RK3288_VPU_ENC_CTRL_REG_PARAMS] = { + .id = V4L2_CID_PRIVATE_RK3288_REG_PARAMS, + .type = V4L2_CTRL_TYPE_PRIVATE, + .name = "Rk3288 Private Reg Params", + .elem_size = sizeof(struct rk3288_vp8e_reg_params), + .max_stores = VIDEO_MAX_FRAME, + .can_store = true, + }, + [RK3288_VPU_ENC_CTRL_HW_PARAMS] = { + .id = V4L2_CID_PRIVATE_RK3288_HW_PARAMS, + .type = V4L2_CTRL_TYPE_PRIVATE, + .name = "Rk3288 Private Hw Params", + .elem_size = RK3288_HW_PARAMS_SIZE, + .max_stores = VIDEO_MAX_FRAME, + .can_store = true, + }, + [RK3288_VPU_ENC_CTRL_RET_PARAMS] = { + .id = V4L2_CID_PRIVATE_RK3288_RET_PARAMS, + .type = V4L2_CTRL_TYPE_PRIVATE, + .name = "Rk3288 Private Ret Params", + .is_volatile = true, + .is_read_only = true, + .max_stores = VIDEO_MAX_FRAME, + .elem_size = RK3288_RET_PARAMS_SIZE, + }, + /* Generic controls. (currently ignored) */ + { + .id = V4L2_CID_MPEG_VIDEO_GOP_SIZE, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 150, + .step = 1, + .default_value = 30, + }, + { + .id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_BITRATE, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 10000, + .maximum = 288000000, + .step = 1, + .default_value = 2097152, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .maximum = V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH, + .default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) + ), + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .maximum = V4L2_MPEG_VIDEO_H264_LEVEL_4_1, + .default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 30, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 18, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 288000, + .step = 1, + .default_value = 30000, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, + .type = V4L2_CTRL_TYPE_BUTTON, + }, + /* + * This hardware does not support features provided by controls + * below, but they are required for compatibility with certain + * userspace software. + */ + { + .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Rate Control Reaction Coeff.", + .minimum = 1, + .maximum = (1 << 16) - 1, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEADER_MODE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + .maximum = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + .default_value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + .menu_skip_mask = 0, + }, + { + .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Fixed Target Bit Enable", + .minimum = 0, + .maximum = 1, + .default_value = 0, + .step = 1, + .menu_skip_mask = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_B_FRAMES, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 1, + }, +}; + +static inline const void *get_ctrl_ptr(struct rk3288_vpu_ctx *ctx, unsigned id) +{ + struct v4l2_ctrl *ctrl = ctx->ctrls[id]; + + return ctrl->p_cur.p; +} + +static const char *const *rk3288_vpu_enc_get_menu(u32 id) +{ + static const char *const vpu_video_frame_skip[] = { + "Disabled", + "Level Limit", + "VBV/CPB Limit", + NULL, + }; + + switch (id) { + case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE: + return vpu_video_frame_skip; + } + + return NULL; +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct rk3288_vpu_dev *dev = video_drvdata(file); + + vpu_debug_enter(); + + strlcpy(cap->driver, RK3288_VPU_ENC_NAME, sizeof(cap->driver)); + strlcpy(cap->card, dev->pdev->name, sizeof(cap->card)); + strlcpy(cap->bus_info, "platform:" RK3288_VPU_NAME, + sizeof(cap->bus_info)); + + /* + * This is only a mem-to-mem video device. The capture and output + * device capability flags are left only for backward compatibility + * and are scheduled for removal. + */ + cap->capabilities = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE; + + vpu_debug_leave(); + + return 0; +} + +static int vidioc_enum_framesizes(struct file *file, void *prov, + struct v4l2_frmsizeenum *fsize) +{ + struct v4l2_frmsize_stepwise *s = &fsize->stepwise; + struct rk3288_vpu_fmt *fmt; + + if (fsize->index != 0) { + vpu_debug(0, "invalid frame size index (expected 0, got %d)\n", + fsize->index); + return -EINVAL; + } + + fmt = find_format(fsize->pixel_format, true); + if (!fmt) { + vpu_debug(0, "unsupported bitstream format (%08x)\n", + fsize->pixel_format); + return -EINVAL; + } + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + + s->min_width = RK3288_ENC_MIN_WIDTH; + s->max_width = RK3288_ENC_MAX_WIDTH; + s->step_width = MB_DIM; + s->min_height = RK3288_ENC_MIN_HEIGHT; + s->max_height = RK3288_ENC_MAX_HEIGHT; + s->step_height = MB_DIM; + + return 0; +} + +static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool out) +{ + struct rk3288_vpu_fmt *fmt; + int i, j = 0; + + vpu_debug_enter(); + + for (i = 0; i < ARRAY_SIZE(formats); ++i) { + if (out && formats[i].codec_mode != RK_VPU_CODEC_NONE) + continue; + else if (!out && formats[i].codec_mode == RK_VPU_CODEC_NONE) + continue; + + if (j == f->index) { + fmt = &formats[i]; + strlcpy(f->description, fmt->name, + sizeof(f->description)); + f->pixelformat = fmt->fourcc; + + f->flags = 0; + if (formats[i].codec_mode != RK_VPU_CODEC_NONE) + f->flags |= V4L2_FMT_FLAG_COMPRESSED; + + vpu_debug_leave(); + + return 0; + } + + ++j; + } + + vpu_debug_leave(); + + return -EINVAL; +} + +static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + return vidioc_enum_fmt(f, false); +} + +static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + return vidioc_enum_fmt(f, true); +} + +static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); + + vpu_debug_enter(); + + vpu_debug(4, "f->type = %d\n", f->type); + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + f->fmt.pix_mp = ctx->dst_fmt; + break; + + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + f->fmt.pix_mp = ctx->src_fmt; + break; + + default: + vpu_err("invalid buf type\n"); + return -EINVAL; + } + + vpu_debug_leave(); + + return 0; +} + +static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct rk3288_vpu_fmt *fmt; + struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; + char str[5]; + + vpu_debug_enter(); + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + vpu_debug(4, "%s\n", fmt2str(f->fmt.pix_mp.pixelformat, str)); + + fmt = find_format(pix_fmt_mp->pixelformat, true); + if (!fmt) { + vpu_err("failed to try capture format\n"); + return -EINVAL; + } + + if (pix_fmt_mp->plane_fmt[0].sizeimage == 0) { + vpu_err("must be set encoding output size\n"); + return -EINVAL; + } + + pix_fmt_mp->plane_fmt[0].bytesperline = 0; + break; + + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + vpu_debug(4, "%s\n", fmt2str(f->fmt.pix_mp.pixelformat, str)); + + fmt = find_format(pix_fmt_mp->pixelformat, false); + if (!fmt) { + vpu_err("failed to try output format\n"); + return -EINVAL; + } + + if (fmt->num_planes != pix_fmt_mp->num_planes) { + vpu_err("plane number mismatches on output format\n"); + return -EINVAL; + } + + /* Limit to hardware min/max. */ + pix_fmt_mp->width = clamp(pix_fmt_mp->width, + RK3288_ENC_MIN_WIDTH, RK3288_ENC_MAX_WIDTH); + pix_fmt_mp->height = clamp(pix_fmt_mp->height, + RK3288_ENC_MIN_HEIGHT, RK3288_ENC_MAX_HEIGHT); + /* Round up to macroblocks. */ + pix_fmt_mp->width = round_up(pix_fmt_mp->width, MB_DIM); + pix_fmt_mp->height = round_up(pix_fmt_mp->height, MB_DIM); + break; + + default: + vpu_err("invalid buf type\n"); + return -EINVAL; + } + + vpu_debug_leave(); + + return 0; +} + +static void calculate_plane_sizes(struct rk3288_vpu_fmt *fmt, + unsigned int w, unsigned int h, + struct v4l2_pix_format_mplane *pix_fmt_mp) +{ + int i; + + for (i = 0; i < fmt->num_planes; ++i) { + pix_fmt_mp->plane_fmt[i].bytesperline = w * fmt->depth[i] / 8; + pix_fmt_mp->plane_fmt[i].sizeimage = h * + pix_fmt_mp->plane_fmt[i].bytesperline; + /* + * All of multiplanar formats we support have chroma + * planes subsampled by 2 vertically. + */ + if (i != 0) + pix_fmt_mp->plane_fmt[i].sizeimage /= 2; + } +} + +static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; + struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); + unsigned int mb_width, mb_height; + struct rk3288_vpu_fmt *fmt; + int ret = 0; + + vpu_debug_enter(); + + /* Change not allowed if any queue is streaming. */ + if (vb2_is_streaming(&ctx->vq_src) || vb2_is_streaming(&ctx->vq_dst)) { + ret = -EBUSY; + goto out; + } + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + /* + * Pixel format change is not allowed when the other queue has + * buffers allocated. + */ + if (vb2_is_busy(&ctx->vq_src) + && pix_fmt_mp->pixelformat != ctx->dst_fmt.pixelformat) { + ret = -EBUSY; + goto out; + } + + ret = vidioc_try_fmt(file, priv, f); + if (ret) + goto out; + + ctx->vpu_dst_fmt = find_format(pix_fmt_mp->pixelformat, true); + ctx->dst_fmt = *pix_fmt_mp; + break; + + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + /* + * Pixel format change is not allowed when the other queue has + * buffers allocated. + */ + if (vb2_is_busy(&ctx->vq_dst) + && pix_fmt_mp->pixelformat != ctx->src_fmt.pixelformat) { + ret = -EBUSY; + goto out; + } + + ret = vidioc_try_fmt(file, priv, f); + if (ret) + goto out; + + fmt = find_format(pix_fmt_mp->pixelformat, false); + ctx->vpu_src_fmt = fmt; + + mb_width = MB_WIDTH(pix_fmt_mp->width); + mb_height = MB_HEIGHT(pix_fmt_mp->height); + + vpu_debug(0, "OUTPUT codec mode: %d\n", fmt->codec_mode); + vpu_debug(0, "fmt - w: %d, h: %d, mb - w: %d, h: %d\n", + pix_fmt_mp->width, pix_fmt_mp->height, + mb_width, mb_height); + + calculate_plane_sizes(fmt, mb_width * MB_DIM, + mb_height * MB_DIM, pix_fmt_mp); + + /* Reset crop rectangle. */ + ctx->src_crop.width = pix_fmt_mp->width; + ctx->src_crop.height = pix_fmt_mp->height; + + ctx->src_fmt = *pix_fmt_mp; + break; + + default: + vpu_err("invalid buf type\n"); + return -EINVAL; + } + +out: + vpu_debug_leave(); + + return ret; +} + +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *reqbufs) +{ + struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); + int ret; + + vpu_debug_enter(); + + switch (reqbufs->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + vpu_debug(4, "\n"); + + ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); + if (ret != 0) { + vpu_err("error in vb2_reqbufs() for E(D)\n"); + goto out; + } + break; + + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + vpu_debug(4, "memory type %d\n", reqbufs->memory); + + ret = vb2_reqbufs(&ctx->vq_src, reqbufs); + if (ret != 0) { + vpu_err("error in vb2_reqbufs() for E(S)\n"); + goto out; + } + break; + + default: + vpu_err("invalid buf type\n"); + ret = -EINVAL; + goto out; + } + +out: + vpu_debug_leave(); + + return ret; +} + +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); + int ret; + + vpu_debug_enter(); + + switch (buf->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + ret = vb2_querybuf(&ctx->vq_dst, buf); + if (ret != 0) { + vpu_err("error in vb2_querybuf() for E(D)\n"); + goto out; + } + + buf->m.planes[0].m.mem_offset += DST_QUEUE_OFF_BASE; + break; + + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + ret = vb2_querybuf(&ctx->vq_src, buf); + if (ret != 0) { + vpu_err("error in vb2_querybuf() for E(S)\n"); + goto out; + } + break; + + default: + vpu_err("invalid buf type\n"); + ret = -EINVAL; + goto out; + } + +out: + vpu_debug_leave(); + + return ret; +} + +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); + int ret; + int i; + + vpu_debug_enter(); + + for (i = 0; i < buf->length; i++) { + vpu_debug(4, "plane[%d]->length %d bytesused %d\n", + i, buf->m.planes[i].length, + buf->m.planes[i].bytesused); + } + + switch (buf->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + ret = vb2_qbuf(&ctx->vq_src, buf); + vpu_debug(4, "vb2_qbuf return %d\n", ret); + break; + + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + ret = vb2_qbuf(&ctx->vq_dst, buf); + vpu_debug(4, "vb2_qbuf return %d\n", ret); + break; + + default: + ret = -EINVAL; + } + + vpu_debug_leave(); + + return ret; +} + +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); + int ret; + + vpu_debug_enter(); + + switch (buf->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + ret = vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK); + break; + + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + ret = vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK); + break; + + default: + ret = -EINVAL; + } + + vpu_debug_leave(); + + return ret; +} + +static int vidioc_expbuf(struct file *file, void *priv, + struct v4l2_exportbuffer *eb) +{ + struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); + int ret; + + vpu_debug_enter(); + + switch (eb->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + ret = vb2_expbuf(&ctx->vq_src, eb); + break; + + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + ret = vb2_expbuf(&ctx->vq_dst, eb); + break; + + default: + ret = -EINVAL; + } + + vpu_debug_leave(); + + return ret; +} + +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); + int ret; + + vpu_debug_enter(); + + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + ret = vb2_streamon(&ctx->vq_src, type); + break; + + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + ret = vb2_streamon(&ctx->vq_dst, type); + break; + + default: + ret = -EINVAL; + } + + vpu_debug_leave(); + + return ret; +} + +static int vidioc_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); + int ret; + + vpu_debug_enter(); + + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + ret = vb2_streamoff(&ctx->vq_src, type); + break; + + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + ret = vb2_streamoff(&ctx->vq_dst, type); + break; + + default: + ret = -EINVAL; + } + + vpu_debug_leave(); + + return ret; +} + +static int rk3288_vpu_enc_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct rk3288_vpu_ctx *ctx = ctrl_to_ctx(ctrl); + struct rk3288_vpu_dev *dev = ctx->dev; + int ret = 0; + + vpu_debug_enter(); + + vpu_debug(4, "ctrl id %d\n", ctrl->id); + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: + case V4L2_CID_MPEG_VIDEO_BITRATE: + case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: + case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: + case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: + case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: + case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE: + case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING: + case V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF: + case V4L2_CID_MPEG_VIDEO_HEADER_MODE: + case V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT: + case V4L2_CID_MPEG_VIDEO_B_FRAMES: + case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: + case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: + /* Ignore these controls for now. (FIXME?) */ + break; + + case V4L2_CID_PRIVATE_RK3288_HEADER: + case V4L2_CID_PRIVATE_RK3288_REG_PARAMS: + case V4L2_CID_PRIVATE_RK3288_HW_PARAMS: + /* Nothing to do here. The control is used directly. */ + break; + + default: + v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n", + ctrl->id, ctrl->val); + ret = -EINVAL; + } + + vpu_debug_leave(); + + return ret; +} + +static int rk3288_vpu_enc_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct rk3288_vpu_ctx *ctx = ctrl_to_ctx(ctrl); + struct rk3288_vpu_dev *dev = ctx->dev; + int ret = 0; + + vpu_debug_enter(); + + vpu_debug(4, "ctrl id %d\n", ctrl->id); + + switch (ctrl->id) { + case V4L2_CID_PRIVATE_RK3288_RET_PARAMS: + memcpy(ctrl->p_new.p, ctx->run.priv_dst.cpu, + RK3288_RET_PARAMS_SIZE); + break; + + default: + v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n", + ctrl->id, ctrl->val); + ret = -EINVAL; + } + + vpu_debug_leave(); + + return ret; +} + +static const struct v4l2_ctrl_ops rk3288_vpu_enc_ctrl_ops = { + .s_ctrl = rk3288_vpu_enc_s_ctrl, + .g_volatile_ctrl = rk3288_vpu_enc_g_volatile_ctrl, +}; + +static int vidioc_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cap) +{ + struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); + struct v4l2_pix_format_mplane *fmt = &ctx->src_fmt; + int ret = 0; + + vpu_debug_enter(); + + /* Crop only supported on source. */ + if (cap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + ret = -EINVAL; + goto out; + } + + cap->bounds.left = 0; + cap->bounds.top = 0; + cap->bounds.width = fmt->width; + cap->bounds.height = fmt->height; + cap->defrect = cap->bounds; + cap->pixelaspect.numerator = 1; + cap->pixelaspect.denominator = 1; + +out: + vpu_debug_leave(); + + return ret; +} + +static int vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop) +{ + struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); + int ret = 0; + + vpu_debug_enter(); + + /* Crop only supported on source. */ + if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + ret = -EINVAL; + goto out; + } + + crop->c = ctx->src_crop; + +out: + vpu_debug_leave(); + + return ret; +} + +static int vidioc_s_crop(struct file *file, void *priv, + const struct v4l2_crop *crop) +{ + struct rk3288_vpu_ctx *ctx = fh_to_ctx(priv); + struct v4l2_pix_format_mplane *fmt = &ctx->src_fmt; + const struct v4l2_rect *rect = &crop->c; + int ret = 0; + + vpu_debug_enter(); + + /* Crop only supported on source. */ + if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + ret = -EINVAL; + goto out; + } + + /* Change not allowed if the queue is streaming. */ + if (vb2_is_streaming(&ctx->vq_src)) { + ret = -EBUSY; + goto out; + } + + /* We do not support offsets. */ + if (rect->left != 0 || rect->top != 0) + goto fallback; + + /* We can crop only inside right- or bottom-most macroblocks. */ + if (round_up(rect->width, MB_DIM) != fmt->width + || round_up(rect->height, MB_DIM) != fmt->height) + goto fallback; + + /* We support widths aligned to 4 pixels and arbitrary heights. */ + ctx->src_crop.width = round_up(rect->width, 4); + ctx->src_crop.height = rect->height; + + vpu_debug_leave(); + + return 0; + +fallback: + /* Default to full frame for incorrect settings. */ + ctx->src_crop.width = fmt->width; + ctx->src_crop.height = fmt->height; + +out: + vpu_debug_leave(); + + return ret; +} + +static const struct v4l2_ioctl_ops rk3288_vpu_enc_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_framesizes = vidioc_enum_framesizes, + .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane, + .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane, + .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt, + .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt, + .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt, + .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt, + .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt, + .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_expbuf = vidioc_expbuf, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_cropcap = vidioc_cropcap, + .vidioc_g_crop = vidioc_g_crop, + .vidioc_s_crop = vidioc_s_crop, +}; + +static int rk3288_vpu_queue_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, + unsigned int *buf_count, + unsigned int *plane_count, + unsigned int psize[], void *allocators[]) +{ + struct rk3288_vpu_ctx *ctx = fh_to_ctx(vq->drv_priv); + int ret = 0; + int i; + + vpu_debug_enter(); + + switch (vq->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + *plane_count = ctx->vpu_dst_fmt->num_planes; + + if (*buf_count < 1) + *buf_count = 1; + + if (*buf_count > VIDEO_MAX_FRAME) + *buf_count = VIDEO_MAX_FRAME; + + psize[0] = ctx->dst_fmt.plane_fmt[0].sizeimage; + /* Kernel mapping necessary for bitstream post processing. */ + allocators[0] = ctx->dev->alloc_ctx_vm; + vpu_debug(0, "capture psize[%d]: %d\n", 0, psize[0]); + break; + + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + *plane_count = ctx->vpu_src_fmt->num_planes; + + if (*buf_count < 1) + *buf_count = 1; + + if (*buf_count > VIDEO_MAX_FRAME) + *buf_count = VIDEO_MAX_FRAME; + + for (i = 0; i < ctx->vpu_src_fmt->num_planes; ++i) { + psize[i] = ctx->src_fmt.plane_fmt[i].sizeimage; + vpu_debug(0, "output psize[%d]: %d\n", i, psize[i]); + allocators[i] = ctx->dev->alloc_ctx; + } + break; + + default: + vpu_err("invalid queue type: %d\n", vq->type); + ret = -EINVAL; + } + + vpu_debug_leave(); + + return ret; +} + +static int rk3288_vpu_buf_prepare(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct rk3288_vpu_ctx *ctx = fh_to_ctx(vq->drv_priv); + int ret = 0; + int i; + + vpu_debug_enter(); + + switch (vq->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + vpu_debug(4, "plane size: %ld, dst size: %d\n", + vb2_plane_size(vb, 0), + ctx->dst_fmt.plane_fmt[0].sizeimage); + + if (vb2_plane_size(vb, 0) + < ctx->dst_fmt.plane_fmt[0].sizeimage) { + vpu_err("plane size is too small for capture\n"); + ret = -EINVAL; + } + break; + + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + for (i = 0; i < ctx->vpu_src_fmt->num_planes; ++i) { + vpu_debug(4, "plane %d size: %ld, sizeimage: %u\n", i, + vb2_plane_size(vb, i), + ctx->src_fmt.plane_fmt[i].sizeimage); + + if (vb2_plane_size(vb, i) + < ctx->src_fmt.plane_fmt[i].sizeimage) { + vpu_err("size of plane %d is too small for output\n", + i); + break; + } + } + + if (i != ctx->vpu_src_fmt->num_planes) + ret = -EINVAL; + break; + + default: + vpu_err("invalid queue type: %d\n", vq->type); + ret = -EINVAL; + } + + vpu_debug_leave(); + + return ret; +} + +static void rk3288_vpu_buf_finish(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct rk3288_vpu_ctx *ctx = fh_to_ctx(vq->drv_priv); + + vpu_debug_enter(); + + if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE + && vb->state == VB2_BUF_STATE_DONE + && ctx->vpu_dst_fmt->fourcc == V4L2_PIX_FMT_VP8) { + struct rk3288_vpu_buf *buf; + + buf = vb_to_buf(vb); + rk3288_vpu_vp8e_assemble_bitstream(ctx, buf); + } + + vpu_debug_leave(); +} + +static int rk3288_vpu_start_streaming(struct vb2_queue *q, unsigned int count) +{ + int ret = 0; + struct rk3288_vpu_ctx *ctx = fh_to_ctx(q->drv_priv); + struct rk3288_vpu_dev *dev = ctx->dev; + bool ready = false; + + vpu_debug_enter(); + + if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + ret = rk3288_vpu_init(ctx); + if (ret < 0) { + vpu_err("rk3288_vpu_init failed\n"); + return ret; + } + + ready = vb2_is_streaming(&ctx->vq_src); + } else if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + ready = vb2_is_streaming(&ctx->vq_dst); + } + + if (ready) + rk3288_vpu_try_context(dev, ctx); + + vpu_debug_leave(); + + return 0; +} + +static void rk3288_vpu_stop_streaming(struct vb2_queue *q) +{ + unsigned long flags; + struct rk3288_vpu_ctx *ctx = fh_to_ctx(q->drv_priv); + struct rk3288_vpu_dev *dev = ctx->dev; + struct rk3288_vpu_buf *b; + LIST_HEAD(queue); + int i; + + vpu_debug_enter(); + + spin_lock_irqsave(&dev->irqlock, flags); + + list_del_init(&ctx->list); + + switch (q->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + list_splice_init(&ctx->dst_queue, &queue); + break; + + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + list_splice_init(&ctx->src_queue, &queue); + break; + + default: + break; + } + + spin_unlock_irqrestore(&dev->irqlock, flags); + + wait_event(dev->run_wq, dev->current_ctx != ctx); + + while (!list_empty(&queue)) { + b = list_first_entry(&queue, struct rk3288_vpu_buf, list); + for (i = 0; i < b->b.num_planes; i++) + vb2_set_plane_payload(&b->b, i, 0); + vb2_buffer_done(&b->b, VB2_BUF_STATE_ERROR); + list_del(&b->list); + } + + if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + rk3288_vpu_deinit(ctx); + + vpu_debug_leave(); +} + +static void rk3288_vpu_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct rk3288_vpu_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct rk3288_vpu_dev *dev = ctx->dev; + struct rk3288_vpu_buf *vpu_buf; + unsigned long flags; + + vpu_debug_enter(); + + switch (vq->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + vpu_buf = vb_to_buf(vb); + + /* Mark destination as available for use by VPU */ + spin_lock_irqsave(&dev->irqlock, flags); + + list_add_tail(&vpu_buf->list, &ctx->dst_queue); + + spin_unlock_irqrestore(&dev->irqlock, flags); + break; + + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + vpu_buf = vb_to_buf(vb); + + spin_lock_irqsave(&dev->irqlock, flags); + + list_add_tail(&vpu_buf->list, &ctx->src_queue); + + spin_unlock_irqrestore(&dev->irqlock, flags); + break; + + default: + vpu_err("unsupported buffer type (%d)\n", vq->type); + } + + if (vb2_is_streaming(&ctx->vq_src) && vb2_is_streaming(&ctx->vq_dst)) + rk3288_vpu_try_context(dev, ctx); + + vpu_debug_leave(); +} + +static struct vb2_ops rk3288_vpu_enc_qops = { + .queue_setup = rk3288_vpu_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_prepare = rk3288_vpu_buf_prepare, + .buf_finish = rk3288_vpu_buf_finish, + .start_streaming = rk3288_vpu_start_streaming, + .stop_streaming = rk3288_vpu_stop_streaming, + .buf_queue = rk3288_vpu_buf_queue, +}; + +struct vb2_ops *get_enc_queue_ops(void) +{ + return &rk3288_vpu_enc_qops; +} + +const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void) +{ + return &rk3288_vpu_enc_ioctl_ops; +} + +static void rk3288_vpu_enc_prepare_run(struct rk3288_vpu_ctx *ctx) +{ + struct vb2_buffer *vb2_src = &ctx->run.src->b; + unsigned config_store = vb2_src->v4l2_buf.config_store; + + v4l2_ctrl_apply_store(&ctx->ctrl_handler, config_store); + + memcpy(ctx->run.dst->vp8e.header, + get_ctrl_ptr(ctx, RK3288_VPU_ENC_CTRL_HEADER), + RK3288_HEADER_SIZE); + ctx->run.vp8e.reg_params = get_ctrl_ptr(ctx, + RK3288_VPU_ENC_CTRL_REG_PARAMS); + memcpy(ctx->run.priv_src.cpu, + get_ctrl_ptr(ctx, RK3288_VPU_ENC_CTRL_HW_PARAMS), + RK3288_HW_PARAMS_SIZE); +} + +static const struct rk3288_vpu_run_ops rk3288_vpu_enc_run_ops = { + .prepare_run = rk3288_vpu_enc_prepare_run, +}; + +int rk3288_vpu_enc_init(struct rk3288_vpu_ctx *ctx) +{ + struct rk3288_vpu_dev *vpu = ctx->dev; + int ret; + + ctx->vpu_src_fmt = find_format(DEF_SRC_FMT_ENC, false); + ctx->vpu_dst_fmt = find_format(DEF_DST_FMT_ENC, true); + + ret = rk3288_vpu_aux_buf_alloc(vpu, &ctx->run.priv_src, + RK3288_HW_PARAMS_SIZE); + if (ret) { + vpu_err("Failed to allocate private source buffer.\n"); + return ret; + } + + + ret = rk3288_vpu_aux_buf_alloc(vpu, &ctx->run.priv_dst, + RK3288_RET_PARAMS_SIZE); + if (ret) { + vpu_err("Failed to allocate private destination buffer.\n"); + goto err_priv_src; + } + + ret = rk3288_vpu_ctrls_setup(ctx, &rk3288_vpu_enc_ctrl_ops, + controls, ARRAY_SIZE(controls), + rk3288_vpu_enc_get_menu); + if (ret) { + vpu_err("Failed to set up controls\n"); + goto err_priv_dst; + } + + ctx->run_ops = &rk3288_vpu_enc_run_ops; + + return 0; + +err_priv_dst: + rk3288_vpu_aux_buf_free(vpu, &ctx->run.priv_dst); +err_priv_src: + rk3288_vpu_aux_buf_free(vpu, &ctx->run.priv_src); + + return ret; +} + +void rk3288_vpu_enc_exit(struct rk3288_vpu_ctx *ctx) +{ + struct rk3288_vpu_dev *vpu = ctx->dev; + + rk3288_vpu_ctrls_delete(ctx); + + rk3288_vpu_aux_buf_free(vpu, &ctx->run.priv_dst); + rk3288_vpu_aux_buf_free(vpu, &ctx->run.priv_src); +}; + +/* + * WAR for encoder state corruption after decoding + */ + +static const struct rk3288_vpu_run_ops dummy_encode_run_ops = { + /* No ops needed for dummy encoding. */ +}; + +#define DUMMY_W 64 +#define DUMMY_H 64 +#define DUMMY_SRC_FMT V4L2_PIX_FMT_YUYV +#define DUMMY_DST_FMT V4L2_PIX_FMT_VP8 +#define DUMMY_DST_SIZE (32 * 1024) + +int rk3288_vpu_enc_init_dummy_ctx(struct rk3288_vpu_dev *dev) +{ + struct rk3288_vpu_ctx *ctx; + int ret; + int i; + + ctx = devm_kzalloc(dev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->dev = dev; + + ctx->vpu_src_fmt = find_format(DUMMY_SRC_FMT, false); + ctx->src_fmt.width = DUMMY_W; + ctx->src_fmt.height = DUMMY_H; + ctx->src_fmt.pixelformat = ctx->vpu_src_fmt->fourcc; + ctx->src_fmt.num_planes = ctx->vpu_src_fmt->num_planes; + + calculate_plane_sizes(ctx->vpu_src_fmt, ctx->src_fmt.width, + ctx->src_fmt.height, &ctx->src_fmt); + + ctx->vpu_dst_fmt = find_format(DUMMY_DST_FMT, true); + ctx->dst_fmt.width = ctx->src_fmt.width; + ctx->dst_fmt.height = ctx->src_fmt.height; + ctx->dst_fmt.pixelformat = ctx->vpu_dst_fmt->fourcc; + ctx->dst_fmt.plane_fmt[0].sizeimage = DUMMY_DST_SIZE; + ctx->dst_fmt.plane_fmt[0].bytesperline = 0; + ctx->dst_fmt.num_planes = 1; + + INIT_LIST_HEAD(&ctx->src_queue); + + ctx->src_crop.left = 0; + ctx->src_crop.top = 0; + ctx->src_crop.width = ctx->src_fmt.width; + ctx->src_crop.left = ctx->src_fmt.height; + + INIT_LIST_HEAD(&ctx->dst_queue); + INIT_LIST_HEAD(&ctx->list); + + ctx->run.vp8e.reg_params = rk3288_vpu_vp8e_get_dummy_params(); + ctx->run_ops = &dummy_encode_run_ops; + + ctx->run.dst = devm_kzalloc(dev->dev, sizeof(*ctx->run.dst), + GFP_KERNEL); + if (!ctx->run.dst) + return -ENOMEM; + + ret = rk3288_vpu_aux_buf_alloc(dev, &ctx->run.priv_src, + RK3288_HW_PARAMS_SIZE); + if (ret) + return ret; + + ret = rk3288_vpu_aux_buf_alloc(dev, &ctx->run.priv_dst, + RK3288_RET_PARAMS_SIZE); + if (ret) + goto err_free_priv_src; + + for (i = 0; i < ctx->src_fmt.num_planes; ++i) { + ret = rk3288_vpu_aux_buf_alloc(dev, &dev->dummy_encode_src[i], + ctx->src_fmt.plane_fmt[i].sizeimage); + if (ret) + goto err_free_src; + + memset(dev->dummy_encode_src[i].cpu, 0, + dev->dummy_encode_src[i].size); + } + + ret = rk3288_vpu_aux_buf_alloc(dev, &dev->dummy_encode_dst, + ctx->dst_fmt.plane_fmt[0].sizeimage); + if (ret) + goto err_free_src; + + memset(dev->dummy_encode_dst.cpu, 0, dev->dummy_encode_dst.size); + + ret = rk3288_vpu_init(ctx); + if (ret) + goto err_free_dst; + + dev->dummy_encode_ctx = ctx; + + return 0; + +err_free_dst: + rk3288_vpu_aux_buf_free(dev, &dev->dummy_encode_dst); +err_free_src: + for (i = 0; i < ctx->src_fmt.num_planes; ++i) + if (dev->dummy_encode_src[i].cpu) + rk3288_vpu_aux_buf_free(dev, &dev->dummy_encode_src[i]); + rk3288_vpu_aux_buf_free(dev, &ctx->run.priv_dst); +err_free_priv_src: + rk3288_vpu_aux_buf_free(dev, &ctx->run.priv_src); + + return ret; +} + +void rk3288_vpu_enc_free_dummy_ctx(struct rk3288_vpu_dev *dev) +{ + struct rk3288_vpu_ctx *ctx = dev->dummy_encode_ctx; + int i; + + rk3288_vpu_deinit(ctx); + + for (i = 0; i < ctx->src_fmt.num_planes; ++i) + rk3288_vpu_aux_buf_free(dev, &dev->dummy_encode_src[i]); + rk3288_vpu_aux_buf_free(dev, &dev->dummy_encode_dst); + rk3288_vpu_aux_buf_free(dev, &ctx->run.priv_src); + rk3288_vpu_aux_buf_free(dev, &ctx->run.priv_dst); +} diff --git a/drivers/media/platform/rockchip-vpu/rk3288_vpu_enc.h b/drivers/media/platform/rockchip-vpu/rk3288_vpu_enc.h new file mode 100644 index 000000000000..4b1979d5d2ef --- /dev/null +++ b/drivers/media/platform/rockchip-vpu/rk3288_vpu_enc.h @@ -0,0 +1,36 @@ +/* + * Rockchip RK3288 VPU codec driver + * + * Copyright (c) 2014 Rockchip Electronics Co., Ltd. + * Alpha Lin + * Jeffy Chen + * + * Copyright (C) 2014 Google, Inc. + * Tomasz Figa + * + * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 RK3288_VPU_ENC_H_ +#define RK3288_VPU_ENC_H_ + +struct vb2_ops *get_enc_queue_ops(void); +const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void); +struct rk3288_vpu_fmt *get_enc_def_fmt(bool src); +int rk3288_vpu_enc_init(struct rk3288_vpu_ctx *ctx); +void rk3288_vpu_enc_exit(struct rk3288_vpu_ctx *ctx); +int rk3288_vpu_enc_init_dummy_ctx(struct rk3288_vpu_dev *dev); +void rk3288_vpu_enc_free_dummy_ctx(struct rk3288_vpu_dev *dev); + +#endif /* RK3288_VPU_ENC_H_ */ diff --git a/drivers/media/platform/rockchip-vpu/rk3288_vpu_hw.c b/drivers/media/platform/rockchip-vpu/rk3288_vpu_hw.c new file mode 100644 index 000000000000..8ca8b9abd548 --- /dev/null +++ b/drivers/media/platform/rockchip-vpu/rk3288_vpu_hw.c @@ -0,0 +1,418 @@ +/* + * Rockchip RK3288 VPU codec driver + * + * Copyright (C) 2014 Google, Inc. + * Tomasz Figa + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "rk3288_vpu_common.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "rk3288_vpu_regs.h" + +/** + * struct rk3288_vpu_variant - information about VPU hardware variant + * + * @hw_id: Top 16 bits (product ID) of hardware ID register. + * @enc_offset: Offset from VPU base to encoder registers. + * @enc_reg_num: Number of registers of encoder block. + * @dec_offset: Offset from VPU base to decoder registers. + * @dec_reg_num: Number of registers of decoder block. + */ +struct rk3288_vpu_variant { + u16 hw_id; + unsigned enc_offset; + unsigned enc_reg_num; + unsigned dec_offset; + unsigned dec_reg_num; +}; + +/* Supported VPU variants. */ +static const struct rk3288_vpu_variant rk3288_vpu_variants[] = { + { + .hw_id = 0x4831, + .enc_offset = 0x0, + .enc_reg_num = 164, + .dec_offset = 0x400, + .dec_reg_num = 60 + 41, + }, +}; + +/** + * struct rk3288_vpu_codec_ops - codec mode specific operations + * + * @init: Prepare for streaming. Called from VB2 .start_streaming() + * when streaming from both queues is being enabled. + * @exit: Clean-up after streaming. Called from VB2 .stop_streaming() + * when streaming from first of both enabled queues is being + * disabled. + * @run: Start single {en,de)coding run. Called from non-atomic context + * to indicate that a pair of buffers is ready and the hardware + * should be programmed and started. + * @done: Read back processing results and additional data from hardware. + * @reset: Reset the hardware in case of a timeout. + */ +struct rk3288_vpu_codec_ops { + int (*init)(struct rk3288_vpu_ctx *); + void (*exit)(struct rk3288_vpu_ctx *); + + void (*run)(struct rk3288_vpu_ctx *); + void (*done)(struct rk3288_vpu_ctx *, enum vb2_buffer_state); + void (*reset)(struct rk3288_vpu_ctx *); +}; + +/* + * Hardware control routines. + */ + +static int rk3288_vpu_identify(struct rk3288_vpu_dev *vpu) +{ + u32 hw_id; + int i; + + hw_id = readl(vpu->base) >> 16; + + dev_info(vpu->dev, "Read hardware ID: %x\n", hw_id); + + for (i = 0; i < ARRAY_SIZE(rk3288_vpu_variants); ++i) { + if (hw_id == rk3288_vpu_variants[i].hw_id) { + vpu->variant = &rk3288_vpu_variants[i]; + return 0; + } + } + + return -ENOENT; +} + +void rk3288_vpu_power_on(struct rk3288_vpu_dev *vpu) +{ + vpu_debug_enter(); + + /* TODO: Clock gating. */ + + pm_runtime_get_sync(vpu->dev); + + vpu_debug_leave(); +} + +static void rk3288_vpu_power_off(struct rk3288_vpu_dev *vpu) +{ + vpu_debug_enter(); + + pm_runtime_mark_last_busy(vpu->dev); + pm_runtime_put_autosuspend(vpu->dev); + + /* TODO: Clock gating. */ + + vpu_debug_leave(); +} + +/* + * Interrupt handlers. + */ + +static irqreturn_t vepu_irq(int irq, void *dev_id) +{ + struct rk3288_vpu_dev *vpu = dev_id; + u32 status = vepu_read(vpu, VEPU_REG_INTERRUPT); + + vepu_write(vpu, 0, VEPU_REG_INTERRUPT); + + if (status & VEPU_REG_INTERRUPT_BIT) { + struct rk3288_vpu_ctx *ctx = vpu->current_ctx; + + vepu_write(vpu, 0, VEPU_REG_AXI_CTRL); + rk3288_vpu_power_off(vpu); + cancel_delayed_work(&vpu->watchdog_work); + + ctx->hw.codec_ops->done(ctx, VB2_BUF_STATE_DONE); + } + + return IRQ_HANDLED; +} + +static irqreturn_t vdpu_irq(int irq, void *dev_id) +{ + struct rk3288_vpu_dev *vpu = dev_id; + u32 status = vdpu_read(vpu, VDPU_REG_INTERRUPT); + + vdpu_write(vpu, 0, VDPU_REG_INTERRUPT); + + vpu_debug(3, "vdpu_irq status: %08x\n", status); + + if (status & VDPU_REG_INTERRUPT_DEC_IRQ) { + struct rk3288_vpu_ctx *ctx = vpu->current_ctx; + + vdpu_write(vpu, 0, VDPU_REG_CONFIG); + rk3288_vpu_power_off(vpu); + cancel_delayed_work(&vpu->watchdog_work); + + ctx->hw.codec_ops->done(ctx, VB2_BUF_STATE_DONE); + } + + return IRQ_HANDLED; +} + +static void rk3288_vpu_watchdog(struct work_struct *work) +{ + struct rk3288_vpu_dev *vpu = container_of(to_delayed_work(work), + struct rk3288_vpu_dev, watchdog_work); + struct rk3288_vpu_ctx *ctx = vpu->current_ctx; + unsigned long flags; + + spin_lock_irqsave(&vpu->irqlock, flags); + + ctx->hw.codec_ops->reset(ctx); + + spin_unlock_irqrestore(&vpu->irqlock, flags); + + vpu_err("frame processing timed out!\n"); + + rk3288_vpu_power_off(vpu); + ctx->hw.codec_ops->done(ctx, VB2_BUF_STATE_ERROR); +} + +/* + * Initialization/clean-up. + */ + +#if defined(CONFIG_ROCKCHIP_IOMMU) +static int rk3288_vpu_iommu_init(struct rk3288_vpu_dev *vpu) +{ + int ret; + + vpu->mapping = arm_iommu_create_mapping(&platform_bus_type, + 0x10000000, SZ_2G); + if (IS_ERR(vpu->mapping)) { + ret = PTR_ERR(vpu->mapping); + return ret; + } + + vpu->dev->dma_parms = devm_kzalloc(vpu->dev, + sizeof(*vpu->dev->dma_parms), GFP_KERNEL); + if (!vpu->dev->dma_parms) + goto err_release_mapping; + + dma_set_max_seg_size(vpu->dev, 0xffffffffu); + + ret = arm_iommu_attach_device(vpu->dev, vpu->mapping); + if (ret) + goto err_release_mapping; + + return 0; + +err_release_mapping: + arm_iommu_release_mapping(vpu->mapping); + + return ret; +} + +static void rk3288_vpu_iommu_cleanup(struct rk3288_vpu_dev *vpu) +{ + arm_iommu_detach_device(vpu->dev); + arm_iommu_release_mapping(vpu->mapping); +} +#else +static inline int rk3288_vpu_iommu_init(struct rk3288_vpu_dev *vpu) +{ + return 0; +} + +static inline void rk3288_vpu_iommu_cleanup(struct rk3288_vpu_dev *vpu) { } +#endif + +int rk3288_vpu_hw_probe(struct rk3288_vpu_dev *vpu) +{ + struct resource *res; + int irq_enc, irq_dec; + int ret; + + pr_info("probe device %s\n", dev_name(vpu->dev)); + + INIT_DELAYED_WORK(&vpu->watchdog_work, rk3288_vpu_watchdog); + + vpu->aclk_vcodec = devm_clk_get(vpu->dev, "aclk_vcodec"); + if (IS_ERR(vpu->aclk_vcodec)) { + dev_err(vpu->dev, "failed to get aclk_vcodec\n"); + return PTR_ERR(vpu->aclk_vcodec); + } + + vpu->hclk_vcodec = devm_clk_get(vpu->dev, "hclk_vcodec"); + if (IS_ERR(vpu->hclk_vcodec)) { + dev_err(vpu->dev, "failed to get hclk_vcodec\n"); + return PTR_ERR(vpu->hclk_vcodec); + } + + /* + * Bump ACLK to max. possible freq. (400 MHz) to improve performance. + * + * VP8 encoding 1280x720@1.2Mbps 200 MHz: 39 fps, 400: MHz 77 fps + */ + clk_set_rate(vpu->aclk_vcodec, 400*1000*1000); + + res = platform_get_resource(vpu->pdev, IORESOURCE_MEM, 0); + vpu->base = devm_ioremap_resource(vpu->dev, res); + if (IS_ERR(vpu->base)) + return PTR_ERR(vpu->base); + + clk_prepare_enable(vpu->aclk_vcodec); + clk_prepare_enable(vpu->hclk_vcodec); + + ret = rk3288_vpu_identify(vpu); + if (ret < 0) { + dev_err(vpu->dev, "failed to identify hardware variant\n"); + goto err_power; + } + + 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)); + if (ret) { + dev_err(vpu->dev, "could not set DMA coherent mask\n"); + goto err_power; + } + + ret = rk3288_vpu_iommu_init(vpu); + if (ret) + goto err_power; + + irq_enc = platform_get_irq_byname(vpu->pdev, "vepu"); + if (irq_enc <= 0) { + dev_err(vpu->dev, "could not get vepu IRQ\n"); + ret = -ENXIO; + goto err_iommu; + } + + ret = devm_request_threaded_irq(vpu->dev, irq_enc, NULL, vepu_irq, + IRQF_ONESHOT, dev_name(vpu->dev), vpu); + if (ret) { + dev_err(vpu->dev, "could not request vepu IRQ\n"); + goto err_iommu; + } + + irq_dec = platform_get_irq_byname(vpu->pdev, "vdpu"); + if (irq_dec <= 0) { + dev_err(vpu->dev, "could not get vdpu IRQ\n"); + ret = -ENXIO; + goto err_iommu; + } + + ret = devm_request_threaded_irq(vpu->dev, irq_dec, NULL, vdpu_irq, + IRQF_ONESHOT, dev_name(vpu->dev), vpu); + if (ret) { + dev_err(vpu->dev, "could not request vdpu IRQ\n"); + goto err_iommu; + } + + pm_runtime_set_autosuspend_delay(vpu->dev, 100); + pm_runtime_use_autosuspend(vpu->dev); + pm_runtime_enable(vpu->dev); + + return 0; + +err_iommu: + rk3288_vpu_iommu_cleanup(vpu); +err_power: + clk_disable_unprepare(vpu->hclk_vcodec); + clk_disable_unprepare(vpu->aclk_vcodec); + + return ret; +} + +void rk3288_vpu_hw_remove(struct rk3288_vpu_dev *vpu) +{ + rk3288_vpu_iommu_cleanup(vpu); + + pm_runtime_disable(vpu->dev); + + clk_disable_unprepare(vpu->hclk_vcodec); + clk_disable_unprepare(vpu->aclk_vcodec); +} + +static void rk3288_vpu_enc_reset(struct rk3288_vpu_ctx *ctx) +{ + struct rk3288_vpu_dev *vpu = ctx->dev; + + vepu_write(vpu, VEPU_REG_INTERRUPT_DIS_BIT, VEPU_REG_INTERRUPT); + vepu_write(vpu, 0, VEPU_REG_ENC_CTRL); + vepu_write(vpu, 0, VEPU_REG_AXI_CTRL); +} + +static void rk3288_vpu_dec_reset(struct rk3288_vpu_ctx *ctx) +{ + struct rk3288_vpu_dev *vpu = ctx->dev; + + vdpu_write(vpu, VDPU_REG_INTERRUPT_DEC_IRQ_DIS, VDPU_REG_INTERRUPT); + vdpu_write(vpu, 0, VDPU_REG_CONFIG); +} + +static const struct rk3288_vpu_codec_ops mode_ops[] = { + [RK_VPU_CODEC_VP8E] = { + .init = rk3288_vpu_vp8e_init, + .exit = rk3288_vpu_vp8e_exit, + .run = rk3288_vpu_vp8e_run, + .done = rk3288_vpu_vp8e_done, + .reset = rk3288_vpu_enc_reset, + }, + [RK_VPU_CODEC_VP8D] = { + .init = rk3288_vpu_vp8d_init, + .exit = rk3288_vpu_vp8d_exit, + .run = rk3288_vpu_vp8d_run, + .done = rk3288_vpu_run_done, + .reset = rk3288_vpu_dec_reset, + }, + [RK_VPU_CODEC_H264D] = { + .init = rk3288_vpu_h264d_init, + .exit = rk3288_vpu_h264d_exit, + .run = rk3288_vpu_h264d_run, + .done = rk3288_vpu_run_done, + .reset = rk3288_vpu_dec_reset, + }, +}; + +void rk3288_vpu_run(struct rk3288_vpu_ctx *ctx) +{ + ctx->hw.codec_ops->run(ctx); +} + +int rk3288_vpu_init(struct rk3288_vpu_ctx *ctx) +{ + enum rk3288_vpu_codec_mode codec_mode; + + if (rk3288_vpu_ctx_is_encoder(ctx)) + codec_mode = ctx->vpu_dst_fmt->codec_mode; /* Encoder */ + else + codec_mode = ctx->vpu_src_fmt->codec_mode; /* Decoder */ + + ctx->hw.codec_ops = &mode_ops[codec_mode]; + + return ctx->hw.codec_ops->init(ctx); +} + +void rk3288_vpu_deinit(struct rk3288_vpu_ctx *ctx) +{ + ctx->hw.codec_ops->exit(ctx); +} diff --git a/drivers/media/platform/rockchip-vpu/rk3288_vpu_hw.h b/drivers/media/platform/rockchip-vpu/rk3288_vpu_hw.h new file mode 100644 index 000000000000..f8325536295b --- /dev/null +++ b/drivers/media/platform/rockchip-vpu/rk3288_vpu_hw.h @@ -0,0 +1,179 @@ +/* + * Rockchip RK3288 VPU codec driver + * + * Copyright (C) 2014 Google, Inc. + * Tomasz Figa + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 RK3288_VPU_HW_H_ +#define RK3288_VPU_HW_H_ + +#include + +#define RK3288_HEADER_SIZE 1280 +#define RK3288_HW_PARAMS_SIZE 5487 +#define RK3288_RET_PARAMS_SIZE 488 + +struct rk3288_vpu_dev; +struct rk3288_vpu_ctx; +struct rk3288_vpu_buf; + +struct rk3288_vpu_h264d_priv_tbl; + +/** + * enum rk3288_vpu_enc_fmt - source format ID for hardware registers. + */ +enum rk3288_vpu_enc_fmt { + RK3288_VPU_ENC_FMT_YUV420P = 0, + RK3288_VPU_ENC_FMT_YUV420SP = 1, + RK3288_VPU_ENC_FMT_YUYV422 = 2, + RK3288_VPU_ENC_FMT_UYVY422 = 3, +}; + +/** + * struct rk3288_vp8e_reg_params - low level encoding parameters + * TODO: Create abstract structures for more generic controls or just + * remove unused fields. + */ +struct rk3288_vp8e_reg_params { + u32 unused_00[5]; + u32 hdr_len; + u32 unused_18[8]; + u32 enc_ctrl; + u32 unused_3c; + u32 enc_ctrl0; + u32 enc_ctrl1; + u32 enc_ctrl2; + u32 enc_ctrl3; + u32 enc_ctrl5; + u32 enc_ctrl4; + u32 str_hdr_rem_msb; + u32 str_hdr_rem_lsb; + u32 unused_60; + u32 mad_ctrl; + u32 unused_68; + u32 qp_val[8]; + u32 bool_enc; + u32 vp8_ctrl0; + u32 rlc_ctrl; + u32 mb_ctrl; + u32 unused_9c[14]; + u32 rgb_yuv_coeff[2]; + u32 rgb_mask_msb; + u32 intra_area_ctrl; + u32 cir_intra_ctrl; + u32 unused_e8[2]; + u32 first_roi_area; + u32 second_roi_area; + u32 mvc_ctrl; + u32 unused_fc; + u32 intra_penalty[7]; + u32 unused_11c; + u32 seg_qp[24]; + u32 dmv_4p_1p_penalty[32]; + u32 dmv_qpel_penalty[32]; + u32 vp8_ctrl1; + u32 bit_cost_golden; + u32 loop_flt_delta[2]; +}; + +/** + * struct rk3288_vpu_aux_buf - auxiliary DMA buffer for hardware data + * @cpu: CPU pointer to the buffer. + * @dma: DMA address of the buffer. + * @size: Size of the buffer. + */ +struct rk3288_vpu_aux_buf { + void *cpu; + dma_addr_t dma; + size_t size; +}; + +/** + * struct rk3288_vpu_vp8e_hw_ctx - Context private data specific to codec mode. + * @ctrl_buf: VP8 control buffer. + * @ext_buf: VP8 ext data buffer. + * @mv_buf: VP8 motion vector buffer. + * @ref_rec_ptr: Bit flag for swapping ref and rec buffers every frame. + */ +struct rk3288_vpu_vp8e_hw_ctx { + struct rk3288_vpu_aux_buf ctrl_buf; + struct rk3288_vpu_aux_buf ext_buf; + struct rk3288_vpu_aux_buf mv_buf; + u8 ref_rec_ptr:1; +}; + +/** + * struct rk3288_vpu_vp8d_hw_ctx - Context private data of VP8 decoder. + * @segment_map: Segment map buffer. + * @prob_tbl: Probability table buffer. + */ +struct rk3288_vpu_vp8d_hw_ctx { + struct rk3288_vpu_aux_buf segment_map; + struct rk3288_vpu_aux_buf prob_tbl; +}; + +/** + * struct rk3288_vpu_h264d_hw_ctx - Per context data specific to H264 decoding. + * @priv_tbl: Private auxiliary buffer for hardware. + */ +struct rk3288_vpu_h264d_hw_ctx { + struct rk3288_vpu_aux_buf priv_tbl; +}; + +/** + * struct rk3288_vpu_hw_ctx - Context private data of hardware code. + * @codec_ops: Set of operations associated with current codec mode. + */ +struct rk3288_vpu_hw_ctx { + const struct rk3288_vpu_codec_ops *codec_ops; + + /* Specific for particular codec modes. */ + union { + struct rk3288_vpu_vp8e_hw_ctx vp8e; + struct rk3288_vpu_vp8d_hw_ctx vp8d; + struct rk3288_vpu_h264d_hw_ctx h264d; + /* Other modes will need different data. */ + }; +}; + +int rk3288_vpu_hw_probe(struct rk3288_vpu_dev *vpu); +void rk3288_vpu_hw_remove(struct rk3288_vpu_dev *vpu); + +int rk3288_vpu_init(struct rk3288_vpu_ctx *ctx); +void rk3288_vpu_deinit(struct rk3288_vpu_ctx *ctx); + +void rk3288_vpu_run(struct rk3288_vpu_ctx *ctx); + +/* Run ops for H264 decoder */ +int rk3288_vpu_h264d_init(struct rk3288_vpu_ctx *ctx); +void rk3288_vpu_h264d_exit(struct rk3288_vpu_ctx *ctx); +void rk3288_vpu_h264d_run(struct rk3288_vpu_ctx *ctx); +void rk3288_vpu_power_on(struct rk3288_vpu_dev *vpu); + +/* Run ops for VP8 decoder */ +int rk3288_vpu_vp8d_init(struct rk3288_vpu_ctx *ctx); +void rk3288_vpu_vp8d_exit(struct rk3288_vpu_ctx *ctx); +void rk3288_vpu_vp8d_run(struct rk3288_vpu_ctx *ctx); + +/* Run ops for VP8 encoder */ +int rk3288_vpu_vp8e_init(struct rk3288_vpu_ctx *ctx); +void rk3288_vpu_vp8e_exit(struct rk3288_vpu_ctx *ctx); +void rk3288_vpu_vp8e_run(struct rk3288_vpu_ctx *ctx); +void rk3288_vpu_vp8e_done(struct rk3288_vpu_ctx *ctx, + enum vb2_buffer_state result); +const struct rk3288_vp8e_reg_params *rk3288_vpu_vp8e_get_dummy_params(void); + +void rk3288_vpu_vp8e_assemble_bitstream(struct rk3288_vpu_ctx *ctx, + struct rk3288_vpu_buf *dst_buf); + +#endif /* RK3288_VPU_HW_H_ */ diff --git a/drivers/media/platform/rockchip-vpu/rk3288_vpu_hw_h264d.c b/drivers/media/platform/rockchip-vpu/rk3288_vpu_hw_h264d.c new file mode 100644 index 000000000000..b03491efbf32 --- /dev/null +++ b/drivers/media/platform/rockchip-vpu/rk3288_vpu_hw_h264d.c @@ -0,0 +1,558 @@ +/* + * Rockchip RK3288 VPU codec driver + * + * Copyright (c) 2014 Rockchip Electronics Co., Ltd. + * Hertz Wong + * Herman Chen + * + * Copyright (C) 2014 Google, Inc. + * Tomasz Figa + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "rk3288_vpu_common.h" + +#include +#include + +#include "rk3288_vpu_hw.h" +#include "rk3288_vpu_regs.h" + +/* Max. number of DPB pictures supported by hardware. */ +#define RK3288_VPU_H264_NUM_DPB 16 + +/* Size with u32 units. */ +#define CABAC_INIT_BUFFER_SIZE (460 * 2) +#define POC_BUFFER_SIZE 34 +#define SCALING_LIST_SIZE ((6 * 16 + 6 * 64) / 4) + +/* Data structure describing auxilliary buffer format. */ +struct rk3288_vpu_h264d_priv_tbl { + u32 cabac_table[CABAC_INIT_BUFFER_SIZE]; + u32 poc[POC_BUFFER_SIZE]; + u32 scaling_list[SCALING_LIST_SIZE]; +}; + +/* Constant CABAC table. */ +static const u32 h264_cabac_table[] = { + 0x14f10236, 0x034a14f1, 0x0236034a, 0xe47fe968, 0xfa35ff36, 0x07330000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0029003f, 0x003f003f, 0xf7530456, 0x0061f948, 0x0d29033e, 0x000b0137, + 0x0045ef7f, 0xf3660052, 0xf94aeb6b, 0xe57fe17f, 0xe87fee5f, 0xe57feb72, + 0xe27fef7b, 0xf473f07a, 0xf573f43f, 0xfe44f154, 0xf368fd46, 0xf85df65a, + 0xe27fff4a, 0xfa61f95b, 0xec7ffc38, 0xfb52f94c, 0xea7df95d, 0xf557fd4d, + 0xfb47fc3f, 0xfc44f454, 0xf93ef941, 0x083d0538, 0xfe420140, 0x003dfe4e, + 0x01320734, 0x0a23002c, 0x0b26012d, 0x002e052c, 0x1f110133, 0x07321c13, + 0x10210e3e, 0xf36cf164, 0xf365f35b, 0xf45ef658, 0xf054f656, 0xf953f357, + 0xed5e0146, 0x0048fb4a, 0x123bf866, 0xf164005f, 0xfc4b0248, 0xf54bfd47, + 0x0f2ef345, 0x003e0041, 0x1525f148, 0x09391036, 0x003e0c48, 0x18000f09, + 0x08190d12, 0x0f090d13, 0x0a250c12, 0x061d1421, 0x0f1e042d, 0x013a003e, + 0x073d0c26, 0x0b2d0f27, 0x0b2a0d2c, 0x102d0c29, 0x0a311e22, 0x122a0a37, + 0x1133112e, 0x00591aed, 0x16ef1aef, 0x1ee71cec, 0x21e925e5, 0x21e928e4, + 0x26ef21f5, 0x28f129fa, 0x26012911, 0x1efa1b03, 0x1a1625f0, 0x23fc26f8, + 0x26fd2503, 0x26052a00, 0x23102716, 0x0e301b25, 0x153c0c44, 0x0261fd47, + 0xfa2afb32, 0xfd36fe3e, 0x003a013f, 0xfe48ff4a, 0xf75bfb43, 0xfb1bfd27, + 0xfe2c002e, 0xf040f844, 0xf64efa4d, 0xf656f45c, 0xf137f63c, 0xfa3efc41, + 0xf449f84c, 0xf950f758, 0xef6ef561, 0xec54f54f, 0xfa49fc4a, 0xf356f360, + 0xf561ed75, 0xf84efb21, 0xfc30fe35, 0xfd3ef347, 0xf64ff456, 0xf35af261, + 0x0000fa5d, 0xfa54f84f, 0x0042ff47, 0x003efe3c, 0xfe3bfb4b, 0xfd3efc3a, + 0xf742ff4f, 0x00470344, 0x0a2cf93e, 0x0f240e28, 0x101b0c1d, 0x012c1424, + 0x1220052a, 0x01300a3e, 0x112e0940, 0xf468f561, 0xf060f958, 0xf855f955, + 0xf755f358, 0x0442fd4d, 0xfd4cfa4c, 0x0a3aff4c, 0xff53f963, 0xf25f025f, + 0x004cfb4a, 0x0046f54b, 0x01440041, 0xf249033e, 0x043eff44, 0xf34b0b37, + 0x05400c46, 0x0f060613, 0x07100c0e, 0x120d0d0b, 0x0d0f0f10, 0x0c170d17, + 0x0f140e1a, 0x0e2c1128, 0x112f1811, 0x15151916, 0x1f1b161d, 0x13230e32, + 0x0a39073f, 0xfe4dfc52, 0xfd5e0945, 0xf46d24dd, 0x24de20e6, 0x25e22ce0, + 0x22ee22f1, 0x28f121f9, 0x23fb2100, 0x2602210d, 0x17230d3a, 0x1dfd1a00, + 0x161e1ff9, 0x23f122fd, 0x220324ff, 0x2205200b, 0x2305220c, 0x270b1e1d, + 0x221a1d27, 0x13421f15, 0x1f1f1932, 0xef78ec70, 0xee72f555, 0xf15cf259, + 0xe647f151, 0xf2500044, 0xf246e838, 0xe944e832, 0xf54a17f3, 0x1af328f1, + 0x31f22c03, 0x2d062c22, 0x21361352, 0xfd4bff17, 0x0122012b, 0x0036fe37, + 0x003d0140, 0x0044f75c, 0xf26af361, 0xf15af45a, 0xee58f649, 0xf74ff256, + 0xf649f646, 0xf645fb42, 0xf740fb3a, 0x023b15f6, 0x18f51cf8, 0x1cff1d03, + 0x1d092314, 0x1d240e43, 0x14f10236, 0x034a14f1, 0x0236034a, 0xe47fe968, + 0xfa35ff36, 0x07331721, 0x17021500, 0x01090031, 0xdb760539, 0xf34ef541, + 0x013e0c31, 0xfc491132, 0x1240092b, 0x1d001a43, 0x105a0968, 0xd27fec68, + 0x0143f34e, 0xf541013e, 0xfa56ef5f, 0xfa3d092d, 0xfd45fa51, 0xf5600637, + 0x0743fb56, 0x0258003a, 0xfd4cf65e, 0x05360445, 0xfd510058, 0xf943fb4a, + 0xfc4afb50, 0xf948013a, 0x0029003f, 0x003f003f, 0xf7530456, 0x0061f948, + 0x0d29033e, 0x002dfc4e, 0xfd60e57e, 0xe462e765, 0xe943e452, 0xec5ef053, + 0xea6eeb5b, 0xee66f35d, 0xe37ff95c, 0xfb59f960, 0xf36cfd2e, 0xff41ff39, + 0xf75dfd4a, 0xf75cf857, 0xe97e0536, 0x063c063b, 0x0645ff30, 0x0044fc45, + 0xf858fe55, 0xfa4eff4b, 0xf94d0236, 0x0532fd44, 0x0132062a, 0xfc51013f, + 0xfc460043, 0x0239fe4c, 0x0b230440, 0x013d0b23, 0x12190c18, 0x0d1d0d24, + 0xf65df949, 0xfe490d2e, 0x0931f964, 0x09350235, 0x0535fe3d, 0x00380038, + 0xf33ffb3c, 0xff3e0439, 0xfa450439, 0x0e270433, 0x0d440340, 0x013d093f, + 0x07321027, 0x052c0434, 0x0b30fb3c, 0xff3b003b, 0x1621052c, 0x0e2bff4e, + 0x003c0945, 0x0b1c0228, 0x032c0031, 0x002e022c, 0x0233002f, 0x0427023e, + 0x062e0036, 0x0336023a, 0x043f0633, 0x06390735, 0x06340637, 0x0b2d0e24, + 0x0835ff52, 0x0737fd4e, 0x0f2e161f, 0xff541907, 0x1ef91c03, 0x1c042000, + 0x22ff1e06, 0x1e062009, 0x1f131a1b, 0x1a1e2514, 0x1c221146, 0x0143053b, + 0x0943101e, 0x12201223, 0x161d181f, 0x1726122b, 0x14290b3f, 0x093b0940, + 0xff5efe59, 0xf76cfa4c, 0xfe2c002d, 0x0034fd40, 0xfe3bfc46, 0xfc4bf852, + 0xef66f74d, 0x0318002a, 0x00300037, 0xfa3bf947, 0xf453f557, 0xe277013a, + 0xfd1dff24, 0x0126022b, 0xfa37003a, 0x0040fd4a, 0xf65a0046, 0xfc1d051f, + 0x072a013b, 0xfe3afd48, 0xfd51f561, 0x003a0805, 0x0a0e0e12, 0x0d1b0228, + 0x003afd46, 0xfa4ff855, 0x0000f36a, 0xf06af657, 0xeb72ee6e, 0xf262ea6e, + 0xeb6aee67, 0xeb6be96c, 0xe670f660, 0xf45ffb5b, 0xf75dea5e, 0xfb560943, + 0xfc50f655, 0xff46073c, 0x093a053d, 0x0c320f32, 0x12311136, 0x0a29072e, + 0xff330731, 0x08340929, 0x062f0237, 0x0d290a2c, 0x06320535, 0x0d31043f, + 0x0640fe45, 0xfe3b0646, 0x0a2c091f, 0x0c2b0335, 0x0e220a26, 0xfd340d28, + 0x1120072c, 0x07260d32, 0x0a391a2b, 0x0e0b0b0e, 0x090b120b, 0x150917fe, + 0x20f120f1, 0x22eb27e9, 0x2adf29e1, 0x2ee426f4, 0x151d2de8, 0x35d330e6, + 0x41d52bed, 0x27f61e09, 0x121a141b, 0x0039f252, 0xfb4bed61, 0xdd7d1b00, + 0x1c001ffc, 0x1b062208, 0x1e0a1816, 0x21131620, 0x1a1f1529, 0x1a2c172f, + 0x10410e47, 0x083c063f, 0x11411518, 0x17141a17, 0x1b201c17, 0x1c181728, + 0x18201c1d, 0x172a1339, 0x1635163d, 0x0b560c28, 0x0b330e3b, 0xfc4ff947, + 0xfb45f746, 0xf842f644, 0xed49f445, 0xf046f143, 0xec3eed46, 0xf042ea41, + 0xec3f09fe, 0x1af721f7, 0x27f929fe, 0x2d033109, 0x2d1b243b, 0xfa42f923, + 0xf92af82d, 0xfb30f438, 0xfa3cfb3e, 0xf842f84c, 0xfb55fa51, 0xf64df951, + 0xef50ee49, 0xfc4af653, 0xf747f743, 0xff3df842, 0xf242003b, 0x023b15f3, + 0x21f227f9, 0x2efe3302, 0x3c063d11, 0x37222a3e, 0x14f10236, 0x034a14f1, + 0x0236034a, 0xe47fe968, 0xfa35ff36, 0x07331619, 0x22001000, 0xfe090429, + 0xe3760241, 0xfa47f34f, 0x05340932, 0xfd460a36, 0x1a221316, 0x28003902, + 0x29241a45, 0xd37ff165, 0xfc4cfa47, 0xf34f0534, 0x0645f35a, 0x0034082b, + 0xfe45fb52, 0xf660023b, 0x024bfd57, 0xfd640138, 0xfd4afa55, 0x003bfd51, + 0xf956fb5f, 0xff42ff4d, 0x0146fe56, 0xfb48003d, 0x0029003f, 0x003f003f, + 0xf7530456, 0x0061f948, 0x0d29033e, 0x0d0f0733, 0x0250d97f, 0xee5bef60, + 0xe651dd62, 0xe866e961, 0xe577e863, 0xeb6eee66, 0xdc7f0050, 0xfb59f95e, + 0xfc5c0027, 0x0041f154, 0xdd7ffe49, 0xf468f75b, 0xe17f0337, 0x07380737, + 0x083dfd35, 0x0044f94a, 0xf758f367, 0xf35bf759, 0xf25cf84c, 0xf457e96e, + 0xe869f64e, 0xec70ef63, 0xb27fba7f, 0xce7fd27f, 0xfc42fb4e, 0xfc47f848, + 0x023bff37, 0xf946fa4b, 0xf859de77, 0xfd4b2014, 0x1e16d47f, 0x0036fb3d, + 0x003aff3c, 0xfd3df843, 0xe754f24a, 0xfb410534, 0x0239003d, 0xf745f546, + 0x1237fc47, 0x003a073d, 0x09291219, 0x0920052b, 0x092f002c, 0x0033022e, + 0x1326fc42, 0x0f260c2a, 0x09220059, 0x042d0a1c, 0x0a1f21f5, 0x34d5120f, + 0x1c0023ea, 0x26e72200, 0x27ee20f4, 0x66a20000, 0x38f121fc, 0x1d0a25fb, + 0x33e327f7, 0x34de45c6, 0x43c12cfb, 0x200737e3, 0x20010000, 0x1b2421e7, + 0x22e224e4, 0x26e426e5, 0x22ee23f0, 0x22f220f8, 0x25fa2300, 0x1e0a1c12, + 0x1a191d29, 0x004b0248, 0x084d0e23, 0x121f1123, 0x151e112d, 0x142a122d, + 0x1b1a1036, 0x07421038, 0x0b490a43, 0xf674e970, 0xf147f93d, 0x0035fb42, + 0xf54df750, 0xf754f657, 0xde7feb65, 0xfd27fb35, 0xf93df54b, 0xf14def5b, + 0xe76be76f, 0xe47af54c, 0xf62cf634, 0xf639f73a, 0xf048f945, 0xfc45fb4a, + 0xf7560242, 0xf7220120, 0x0b1f0534, 0xfe37fe43, 0x0049f859, 0x03340704, + 0x0a081108, 0x10130325, 0xff3dfb49, 0xff46fc4e, 0x0000eb7e, 0xe97cec6e, + 0xe67ee77c, 0xef69e579, 0xe575ef66, 0xe675e574, 0xdf7af65f, 0xf264f85f, + 0xef6fe472, 0xfa59fe50, 0xfc52f755, 0xf851ff48, 0x05400143, 0x09380045, + 0x01450745, 0xf945fa43, 0xf04dfe40, 0x023dfa43, 0xfd400239, 0xfd41fd42, + 0x003e0933, 0xff42fe47, 0xfe4bff46, 0xf7480e3c, 0x1025002f, 0x12230b25, + 0x0c290a29, 0x02300c29, 0x0d29003b, 0x03321328, 0x03421232, 0x13fa12fa, + 0x0e001af4, 0x1ff021e7, 0x21ea25e4, 0x27e22ae2, 0x2fd62ddc, 0x31de29ef, + 0x200945b9, 0x3fc142c0, 0x4db636d9, 0x34dd29f6, 0x240028ff, 0x1e0e1c1a, + 0x17250c37, 0x0b4125df, 0x27dc28db, 0x26e22edf, 0x2ae228e8, 0x31e326f4, + 0x28f626fd, 0x2efb1f14, 0x1d1e192c, 0x0c300b31, 0x1a2d1616, 0x17161b15, + 0x21141a1c, 0x1e181b22, 0x122a1927, 0x12320c46, 0x15360e47, 0x0b531920, + 0x15311536, 0xfb55fa51, 0xf64df951, 0xef50ee49, 0xfc4af653, 0xf747f743, + 0xff3df842, 0xf242003b, 0x023b11f6, 0x20f32af7, 0x31fb3500, 0x4003440a, + 0x421b2f39, 0xfb470018, 0xff24fe2a, 0xfe34f739, 0xfa3ffc41, 0xfc43f952, + 0xfd51fd4c, 0xf948fa4e, 0xf448f244, 0xfd46fa4c, 0xfb42fb3e, 0x0039fc3d, + 0xf73c0136, 0x023a11f6, 0x20f32af7, 0x31fb3500, 0x4003440a, 0x421b2f39, + 0x14f10236, 0x034a14f1, 0x0236034a, 0xe47fe968, 0xfa35ff36, 0x07331d10, + 0x19000e00, 0xf633fd3e, 0xe5631a10, 0xfc55e866, 0x05390639, 0xef490e39, + 0x1428140a, 0x1d003600, 0x252a0c61, 0xe07fea75, 0xfe4afc55, 0xe8660539, + 0xfa5df258, 0xfa2c0437, 0xf559f167, 0xeb741339, 0x143a0454, 0x0660013f, + 0xfb55f36a, 0x053f064b, 0xfd5aff65, 0x0337fc4f, 0xfe4bf461, 0xf932013c, + 0x0029003f, 0x003f003f, 0xf7530456, 0x0061f948, 0x0d29033e, 0x0722f758, + 0xec7fdc7f, 0xef5bf25f, 0xe754e756, 0xf459ef5b, 0xe17ff24c, 0xee67f35a, + 0xdb7f0b50, 0x054c0254, 0x054efa37, 0x043df253, 0xdb7ffb4f, 0xf568f55b, + 0xe27f0041, 0xfe4f0048, 0xfc5cfa38, 0x0344f847, 0xf362fc56, 0xf458fb52, + 0xfd48fc43, 0xf848f059, 0xf745ff3b, 0x05420439, 0xfc47fe47, 0x023aff4a, + 0xfc2cff45, 0x003ef933, 0xfc2ffa2a, 0xfd29fa35, 0x084cf74e, 0xf5530934, + 0x0043fb5a, 0x0143f148, 0xfb4bf850, 0xeb53eb40, 0xf31fe740, 0xe35e094b, + 0x113ff84a, 0xfb23fe1b, 0x0d5b0341, 0xf945084d, 0xf642033e, 0xfd44ec51, + 0x001e0107, 0xfd17eb4a, 0x1042e97c, 0x11252cee, 0x32deea7f, 0x0427002a, + 0x07220b1d, 0x081f0625, 0x072a0328, 0x08210d2b, 0x0d24042f, 0x0337023a, + 0x063c082c, 0x0b2c0e2a, 0x07300438, 0x04340d25, 0x0931133a, 0x0a300c2d, + 0x00451421, 0x083f23ee, 0x21e71cfd, 0x180a1b00, 0x22f234d4, 0x27e81311, + 0x1f19241d, 0x1821220f, 0x1e141649, 0x1422131f, 0x1b2c1310, 0x0f240f24, + 0x151c1915, 0x1e141f0c, 0x1b10182a, 0x005d0e38, 0x0f391a26, 0xe87fe873, + 0xea52f73e, 0x0035003b, 0xf255f359, 0xf35ef55c, 0xe37feb64, 0xf239f443, + 0xf547f64d, 0xeb55f058, 0xe968f162, 0xdb7ff652, 0xf830f83d, 0xf842f946, + 0xf24bf64f, 0xf753f45c, 0xee6cfc4f, 0xea45f04b, 0xfe3a013a, 0xf34ef753, + 0xfc51f363, 0xf351fa26, 0xf33efa3a, 0xfe3bf049, 0xf64cf356, 0xf753f657, + 0x0000ea7f, 0xe77fe778, 0xe57fed72, 0xe975e776, 0xe675e871, 0xe476e178, + 0xdb7cf65e, 0xf166f663, 0xf36ace7f, 0xfb5c1139, 0xfb56f35e, 0xf45bfe4d, + 0x0047ff49, 0x0440f951, 0x05400f39, 0x01430044, 0xf6430144, 0x004d0240, + 0x0044fb4e, 0x0737053b, 0x02410e36, 0x0f2c053c, 0x0246fe4c, 0xee560c46, + 0x0540f446, 0x0b370538, 0x00450241, 0xfa4a0536, 0x0736fa4c, 0xf552fe4d, + 0xfe4d192a, 0x11f310f7, 0x11f41beb, 0x25e229d8, 0x2ad730d1, 0x27e02ed8, + 0x34cd2ed7, 0x34d92bed, 0x200b3dc9, 0x38d23ece, 0x51bd2dec, 0x23fe1c0f, + 0x22012701, 0x1e111426, 0x122d0f36, 0x004f24f0, 0x25f225ef, 0x2001220f, + 0x1d0f1819, 0x22161f10, 0x23121f1c, 0x2129241c, 0x1b2f153e, 0x121f131a, + 0x24181817, 0x1b10181e, 0x1f1d1629, 0x162a103c, 0x0f340e3c, 0x034ef07b, + 0x15351638, 0x193d1521, 0x1332113d, 0xfd4ef84a, 0xf748f648, 0xee4bf447, + 0xf53ffb46, 0xef4bf248, 0xf043f835, 0xf23bf734, 0xf54409fe, 0x1ef61ffc, + 0x21ff2107, 0x1f0c2517, 0x1f261440, 0xf747f925, 0xf82cf531, 0xf638f43b, + 0xf83ff743, 0xfa44f64f, 0xfd4ef84a, 0xf748f648, 0xee4bf447, 0xf53ffb46, + 0xef4bf248, 0xf043f835, 0xf23bf734, 0xf54409fe, 0x1ef61ffc, 0x21ff2107, + 0x1f0c2517, 0x1f261440 +}; + +int rk3288_vpu_h264d_init(struct rk3288_vpu_ctx *ctx) +{ + struct rk3288_vpu_dev *vpu = ctx->dev; + int ret; + + ret = rk3288_vpu_aux_buf_alloc(vpu, &ctx->hw.h264d.priv_tbl, + sizeof(struct rk3288_vpu_h264d_priv_tbl)); + if (ret) { + vpu_err("allocate h264 priv_tbl failed\n"); + return ret; + } + + return 0; +} + +void rk3288_vpu_h264d_exit(struct rk3288_vpu_ctx *ctx) +{ + rk3288_vpu_aux_buf_free(ctx->dev, &ctx->hw.h264d.priv_tbl); +} + +static void rk3288_vpu_h264d_prepare_table(struct rk3288_vpu_ctx *ctx) +{ + struct rk3288_vpu_h264d_priv_tbl *tbl = ctx->hw.h264d.priv_tbl.cpu; + const struct v4l2_ctrl_h264_scaling_matrix *scaling = + ctx->run.h264d.scaling_matrix; + const struct v4l2_ctrl_h264_decode_param *dec_param = + ctx->run.h264d.decode_param; + const struct v4l2_h264_dpb_entry *dpb = ctx->run.h264d.dpb; + int i; + + /* + * Prepare auxiliary buffer. + * + * TODO: The CABAC table never changes, but maybe it would be better + * to have it as a control, which is set by userspace once? + */ + memcpy(tbl->cabac_table, h264_cabac_table, sizeof(tbl->cabac_table)); + + for (i = 0; i < RK3288_VPU_H264_NUM_DPB; ++i) { + tbl->poc[i * 2 + 0] = dpb[i].top_field_order_cnt; + tbl->poc[i * 2 + 1] = dpb[i].bottom_field_order_cnt; + + vpu_debug(2, "poc [%02d]: %08x %08x\n", i, + tbl->poc[i*2+0], tbl->poc[i*2+1]); + } + + tbl->poc[32] = dec_param->top_field_order_cnt; + tbl->poc[33] = dec_param->bottom_field_order_cnt; + + vpu_debug(2, "poc curr: %08x %08x\n", tbl->poc[32], tbl->poc[33]); + + memcpy(tbl->scaling_list, scaling, sizeof(tbl->scaling_list)); +} + +static void rk3288_vpu_h264d_set_params(struct rk3288_vpu_ctx *ctx) +{ + const struct v4l2_ctrl_h264_decode_param *dec_param = + ctx->run.h264d.decode_param; + const struct v4l2_ctrl_h264_slice_param *slice = + ctx->run.h264d.slice_param; + const struct v4l2_ctrl_h264_sps *sps = ctx->run.h264d.sps; + const struct v4l2_ctrl_h264_pps *pps = ctx->run.h264d.pps; + struct rk3288_vpu_dev *vpu = ctx->dev; + u32 reg; + + /* Decoder control register 0. */ + reg = VDPU_REG_DEC_CTRL0_DEC_AXI_WR_ID(0xff); + if (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD) + reg |= VDPU_REG_DEC_CTRL0_SEQ_MBAFF_E; + if (sps->profile_idc > 66) + reg |= VDPU_REG_DEC_CTRL0_PICORD_COUNT_E + | VDPU_REG_DEC_CTRL0_WRITE_MVS_E; + if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY) && + (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD || + slice->flags & V4L2_SLICE_FLAG_FIELD_PIC)) + reg |= VDPU_REG_DEC_CTRL0_PIC_INTERLACE_E; + if (slice->flags & V4L2_SLICE_FLAG_FIELD_PIC) + reg |= VDPU_REG_DEC_CTRL0_PIC_FIELDMODE_E; + if (!(slice->flags & V4L2_SLICE_FLAG_BOTTOM_FIELD)) + reg |= VDPU_REG_DEC_CTRL0_PIC_TOPFIELD_E; + vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_CTRL0); + + /* Decoder control register 1. */ + reg = VDPU_REG_DEC_CTRL1_PIC_MB_WIDTH(sps->pic_width_in_mbs_minus1 + 1) + | VDPU_REG_DEC_CTRL1_PIC_MB_HEIGHT_P( + sps->pic_height_in_map_units_minus1 + 1) + | VDPU_REG_DEC_CTRL1_REF_FRAMES(sps->max_num_ref_frames); + vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_CTRL1); + + /* Decoder control register 2. */ + reg = VDPU_REG_DEC_CTRL2_CH_QP_OFFSET(pps->chroma_qp_index_offset) + | VDPU_REG_DEC_CTRL2_CH_QP_OFFSET2( + pps->second_chroma_qp_index_offset); + if (pps->flags & V4L2_H264_PPS_FLAG_PIC_SCALING_MATRIX_PRESENT) + reg |= VDPU_REG_DEC_CTRL2_TYPE1_QUANT_E; + if (slice->flags & V4L2_SLICE_FLAG_FIELD_PIC) + reg |= VDPU_REG_DEC_CTRL2_FIELDPIC_FLAG_E; + vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_CTRL2); + + /* Decoder control register 3. */ + reg = VDPU_REG_DEC_CTRL3_START_CODE_E + | VDPU_REG_DEC_CTRL3_INIT_QP(pps->pic_init_qp_minus26 + 26) + | VDPU_REG_DEC_CTRL3_STREAM_LEN( + vb2_get_plane_payload(&ctx->run.src->b, 0)); + vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_CTRL3); + + /* Decoder control register 4. */ + reg = VDPU_REG_DEC_CTRL4_FRAMENUM_LEN( + sps->log2_max_frame_num_minus4 + 4) + | VDPU_REG_DEC_CTRL4_FRAMENUM(slice->frame_num) + | VDPU_REG_DEC_CTRL4_WEIGHT_BIPR_IDC(pps->weighted_bipred_idc); + if (pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE) + reg |= VDPU_REG_DEC_CTRL4_CABAC_E; + if (sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE) + reg |= VDPU_REG_DEC_CTRL4_DIR_8X8_INFER_E; + if (sps->profile_idc >= 0 && sps->chroma_format_idc == 0) + reg |= VDPU_REG_DEC_CTRL4_BLACKWHITE_E; + if (pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED) + reg |= VDPU_REG_DEC_CTRL4_WEIGHT_PRED_E; + vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_CTRL4); + + /* Decoder control register 5. */ + reg = VDPU_REG_DEC_CTRL5_REFPIC_MK_LEN( + slice->dec_ref_pic_marking_bit_size) + | VDPU_REG_DEC_CTRL5_IDR_PIC_ID(slice->idr_pic_id); + if (pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED) + reg |= VDPU_REG_DEC_CTRL5_CONST_INTRA_E; + if (pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT) + reg |= VDPU_REG_DEC_CTRL5_FILT_CTRL_PRES; + if (pps->flags & V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT) + reg |= VDPU_REG_DEC_CTRL5_RDPIC_CNT_PRES; + if (pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE) + reg |= VDPU_REG_DEC_CTRL5_8X8TRANS_FLAG_E; + if (dec_param->idr_pic_flag) + reg |= VDPU_REG_DEC_CTRL5_IDR_PIC_E; + vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_CTRL5); + + /* Decoder control register 6. */ + reg = VDPU_REG_DEC_CTRL6_PPS_ID(slice->pic_parameter_set_id) + | VDPU_REG_DEC_CTRL6_REFIDX0_ACTIVE( + pps->num_ref_idx_l0_default_active_minus1 + 1) + | VDPU_REG_DEC_CTRL6_REFIDX1_ACTIVE( + pps->num_ref_idx_l1_default_active_minus1 + 1) + | VDPU_REG_DEC_CTRL6_POC_LENGTH(slice->pic_order_cnt_bit_size); + vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_CTRL6); + + /* Error concealment register. */ + vdpu_write_relaxed(vpu, 0, VDPU_REG_ERR_CONC); + + /* Prediction filter tap register. */ + vdpu_write_relaxed(vpu, VDPU_REG_PRED_FLT_PRED_BC_TAP_0_0(1) + | VDPU_REG_PRED_FLT_PRED_BC_TAP_0_1(-5 & 0x3ff) + | VDPU_REG_PRED_FLT_PRED_BC_TAP_0_2(20), + VDPU_REG_PRED_FLT); + + /* Reference picture buffer control register. */ + vdpu_write_relaxed(vpu, 0, VDPU_REG_REF_BUF_CTRL); + + /* Reference picture buffer control register 2. */ + vdpu_write_relaxed(vpu, VDPU_REG_REF_BUF_CTRL2_APF_THRESHOLD(8), + VDPU_REG_REF_BUF_CTRL2); +} + + +static void rk3288_vpu_h264d_set_ref(struct rk3288_vpu_ctx *ctx) +{ + const struct v4l2_ctrl_h264_decode_param *dec_param = + ctx->run.h264d.decode_param; + const struct v4l2_h264_dpb_entry *dpb = ctx->run.h264d.dpb; + const u8 *dpb_map = ctx->run.h264d.dpb_map; + struct rk3288_vpu_dev *vpu = ctx->dev; + u32 dpb_longterm = 0; + u32 dpb_valid = 0; + int reg_num; + u32 reg; + int i; + + /* + * Set up bit maps of valid and long term DPBs. + * NOTE: The bits are reversed, i.e. MSb is DPB 0. + */ + for (i = 0; i < RK3288_VPU_H264_NUM_DPB; ++i) { + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) + dpb_valid |= BIT(RK3288_VPU_H264_NUM_DPB - 1 - i); + + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) + dpb_longterm |= BIT(RK3288_VPU_H264_NUM_DPB - 1 - i); + } + vdpu_write_relaxed(vpu, dpb_valid << 16, VDPU_REG_VALID_REF); + vdpu_write_relaxed(vpu, dpb_longterm << 16, VDPU_REG_LT_REF); + + /* + * Set up reference frame picture numbers. + * + * Each VDPU_REG_REF_PIC(x) register contains numbers of two + * subsequential reference pictures. + */ + for (i = 0; i < RK3288_VPU_H264_NUM_DPB; i += 2) { + reg = 0; + + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) + reg |= VDPU_REG_REF_PIC_REFER0_NBR(dpb[i].pic_num); + else + reg |= VDPU_REG_REF_PIC_REFER0_NBR(dpb[i].frame_num); + + if (dpb[i + 1].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) + reg |= VDPU_REG_REF_PIC_REFER1_NBR(dpb[i + 1].pic_num); + else + reg |= VDPU_REG_REF_PIC_REFER1_NBR( + dpb[i + 1].frame_num); + + vdpu_write_relaxed(vpu, reg, VDPU_REG_REF_PIC(i / 2)); + } + + /* + * Each VDPU_REG_BD_REF_PIC(x) register contains three entries + * of each forward and backward picture list. + */ + reg_num = 0; + for (i = 0; i < 15; i += 3) { + reg = VDPU_REG_BD_REF_PIC_BINIT_RLIST_F0( + dpb_map[dec_param->ref_pic_list_b0[i + 0]]) + | VDPU_REG_BD_REF_PIC_BINIT_RLIST_F1( + dpb_map[dec_param->ref_pic_list_b0[i + 1]]) + | VDPU_REG_BD_REF_PIC_BINIT_RLIST_F2( + dpb_map[dec_param->ref_pic_list_b0[i + 2]]) + | VDPU_REG_BD_REF_PIC_BINIT_RLIST_B0( + dpb_map[dec_param->ref_pic_list_b1[i + 0]]) + | VDPU_REG_BD_REF_PIC_BINIT_RLIST_B1( + dpb_map[dec_param->ref_pic_list_b1[i + 1]]) + | VDPU_REG_BD_REF_PIC_BINIT_RLIST_B2( + dpb_map[dec_param->ref_pic_list_b1[i + 2]]); + vdpu_write_relaxed(vpu, reg, VDPU_REG_BD_REF_PIC(reg_num++)); + } + + /* + * VDPU_REG_BD_P_REF_PIC register contains last entries (index 15) + * of forward and backward reference picture lists and first 4 entries + * of P forward picture list. + */ + reg = VDPU_REG_BD_P_REF_PIC_BINIT_RLIST_F15( + dpb_map[dec_param->ref_pic_list_b0[15]]) + | VDPU_REG_BD_P_REF_PIC_BINIT_RLIST_B15( + dpb_map[dec_param->ref_pic_list_b1[15]]) + | VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F0( + dpb_map[dec_param->ref_pic_list_p0[0]]) + | VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F1( + dpb_map[dec_param->ref_pic_list_p0[1]]) + | VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F2( + dpb_map[dec_param->ref_pic_list_p0[2]]) + | VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F3( + dpb_map[dec_param->ref_pic_list_p0[3]]); + vdpu_write_relaxed(vpu, reg, VDPU_REG_BD_P_REF_PIC); + + /* + * Each VDPU_REG_FWD_PIC(x) register contains six consecutive + * entries of P forward picture list, starting from index 4. + */ + reg_num = 0; + for (i = 4; i < RK3288_VPU_H264_NUM_DPB; i += 6) { + reg = VDPU_REG_FWD_PIC_PINIT_RLIST_F0( + dpb_map[dec_param->ref_pic_list_p0[i + 0]]) + | VDPU_REG_FWD_PIC_PINIT_RLIST_F1( + dpb_map[dec_param->ref_pic_list_p0[i + 1]]) + | VDPU_REG_FWD_PIC_PINIT_RLIST_F2( + dpb_map[dec_param->ref_pic_list_p0[i + 2]]) + | VDPU_REG_FWD_PIC_PINIT_RLIST_F3( + dpb_map[dec_param->ref_pic_list_p0[i + 3]]) + | VDPU_REG_FWD_PIC_PINIT_RLIST_F4( + dpb_map[dec_param->ref_pic_list_p0[i + 4]]) + | VDPU_REG_FWD_PIC_PINIT_RLIST_F5( + dpb_map[dec_param->ref_pic_list_p0[i + 5]]); + vdpu_write_relaxed(vpu, reg, VDPU_REG_FWD_PIC(reg_num++)); + } + + /* + * Set up addresses of DPB buffers. + * + * If a DPB entry is unused, address of current destination buffer + * is used. + */ + for (i = 0; i < RK3288_VPU_H264_NUM_DPB; ++i) { + struct vb2_buffer *buf; + + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE + && dpb[i].buf_index < ctx->vq_dst.num_buffers) + buf = ctx->dst_bufs[dpb[i].buf_index]; + else + buf = &ctx->run.dst->b; + + vdpu_write_relaxed(vpu, vb2_dma_contig_plane_dma_addr(buf, 0), + VDPU_REG_ADDR_REF(i)); + } +} + +static void rk3288_vpu_h264d_set_buffers(struct rk3288_vpu_ctx *ctx) +{ + const struct v4l2_ctrl_h264_sps *sps = ctx->run.h264d.sps; + const struct v4l2_ctrl_h264_slice_param *slice = + ctx->run.h264d.slice_param; + struct rk3288_vpu_dev *vpu = ctx->dev; + dma_addr_t src_dma, dst_dma; + + /* Source (stream) buffer. */ + src_dma = vb2_dma_contig_plane_dma_addr(&ctx->run.src->b, 0); + vdpu_write_relaxed(vpu, src_dma, VDPU_REG_ADDR_STR); + + /* Destination (decoded frame) buffer. */ + dst_dma = vb2_dma_contig_plane_dma_addr(&ctx->run.dst->b, 0); + vdpu_write_relaxed(vpu, dst_dma, VDPU_REG_ADDR_DST); + + /* Higher profiles require DMV buffer appended to reference frames. */ + if (sps->profile_idc > 66) { + size_t sizeimage = ctx->dst_fmt.plane_fmt[0].sizeimage; + size_t mv_offset = round_up(sizeimage, 8); + + if (slice->flags & V4L2_SLICE_FLAG_BOTTOM_FIELD) + mv_offset += 32 * MB_WIDTH(ctx->dst_fmt.width); + + vdpu_write_relaxed(vpu, dst_dma + mv_offset, + VDPU_REG_ADDR_DIR_MV); + } + + /* Auxiliary buffer prepared in rk3288_vpu_h264d_prepare_table(). */ + vdpu_write_relaxed(vpu, ctx->hw.h264d.priv_tbl.dma, + VDPU_REG_ADDR_QTABLE); +} + +void rk3288_vpu_h264d_run(struct rk3288_vpu_ctx *ctx) +{ + struct rk3288_vpu_dev *vpu = ctx->dev; + + /* Prepare data in memory. */ + rk3288_vpu_h264d_prepare_table(ctx); + + rk3288_vpu_power_on(vpu); + + /* Configure hardware registers. */ + rk3288_vpu_h264d_set_params(ctx); + rk3288_vpu_h264d_set_ref(ctx); + rk3288_vpu_h264d_set_buffers(ctx); + + schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); + + /* Start decoding! */ + vdpu_write_relaxed(vpu, VDPU_REG_CONFIG_DEC_AXI_RD_ID(0xff) + | VDPU_REG_CONFIG_DEC_TIMEOUT_E + | VDPU_REG_CONFIG_DEC_OUT_ENDIAN + | VDPU_REG_CONFIG_DEC_STRENDIAN_E + | VDPU_REG_CONFIG_DEC_MAX_BURST(16) + | VDPU_REG_CONFIG_DEC_OUTSWAP32_E + | VDPU_REG_CONFIG_DEC_INSWAP32_E + | VDPU_REG_CONFIG_DEC_STRSWAP32_E + | VDPU_REG_CONFIG_DEC_CLK_GATE_E, + VDPU_REG_CONFIG); + vdpu_write(vpu, VDPU_REG_INTERRUPT_DEC_E, VDPU_REG_INTERRUPT); +} diff --git a/drivers/media/platform/rockchip-vpu/rk3288_vpu_hw_vp8d.c b/drivers/media/platform/rockchip-vpu/rk3288_vpu_hw_vp8d.c new file mode 100644 index 000000000000..6e03398d451d --- /dev/null +++ b/drivers/media/platform/rockchip-vpu/rk3288_vpu_hw_vp8d.c @@ -0,0 +1,767 @@ +/* + * Rockchip RK3288 VPU codec vp8 decode driver + * + * Copyright (C) 2014 Rockchip Electronics Co., Ltd. + * ZhiChao Yu + * + * Copyright (C) 2014 Google, Inc. + * Tomasz Figa + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "rk3288_vpu_hw.h" +#include "rk3288_vpu_regs.h" +#include "rk3288_vpu_common.h" + +#define DEC_8190_ALIGN_MASK 0x07U + +/* + * probs table with packed + */ +struct vp8_prob_tbl_packed { + u8 prob_mb_skip_false; + u8 prob_intra; + u8 prob_ref_last; + u8 prob_ref_golden; + u8 prob_segment[3]; + u8 packed0; + + u8 prob_luma_16x16_pred_mode[4]; + u8 prob_chroma_pred_mode[3]; + u8 packed1; + + /* mv prob */ + u8 prob_mv_context[2][19]; + u8 packed2[2]; + + /* coeff probs */ + u8 prob_coeffs[4][8][3][11]; + u8 packed3[96]; +}; + +struct vp8d_reg { + u32 base; + u32 shift; + u32 mask; +}; + +/* dct partiton base address regs */ +static const struct vp8d_reg vp8d_dct_base[8] = { + { VDPU_REG_ADDR_STR, 0, 0xffffffff }, + { VDPU_REG_ADDR_REF(8), 0, 0xffffffff }, + { VDPU_REG_ADDR_REF(9), 0, 0xffffffff }, + { VDPU_REG_ADDR_REF(10), 0, 0xffffffff }, + { VDPU_REG_ADDR_REF(11), 0, 0xffffffff }, + { VDPU_REG_ADDR_REF(12), 0, 0xffffffff }, + { VDPU_REG_ADDR_REF(14), 0, 0xffffffff }, + { VDPU_REG_ADDR_REF(15), 0, 0xffffffff }, +}; + +/* loop filter level regs */ +static const struct vp8d_reg vp8d_lf_level[4] = { + { VDPU_REG_REF_PIC(2), 18, 0x3f }, + { VDPU_REG_REF_PIC(2), 12, 0x3f }, + { VDPU_REG_REF_PIC(2), 6, 0x3f }, + { VDPU_REG_REF_PIC(2), 0, 0x3f }, +}; + +/* macroblock loop filter level adjustment regs */ +static const struct vp8d_reg vp8d_mb_adj[4] = { + { VDPU_REG_REF_PIC(0), 21, 0x7f }, + { VDPU_REG_REF_PIC(0), 14, 0x7f }, + { VDPU_REG_REF_PIC(0), 7, 0x7f }, + { VDPU_REG_REF_PIC(0), 0, 0x7f }, +}; + +/* reference frame adjustment regs */ +static const struct vp8d_reg vp8d_ref_adj[4] = { + { VDPU_REG_REF_PIC(1), 21, 0x7f }, + { VDPU_REG_REF_PIC(1), 14, 0x7f }, + { VDPU_REG_REF_PIC(1), 7, 0x7f }, + { VDPU_REG_REF_PIC(1), 0, 0x7f }, +}; + +/* quantizer regs */ +static const struct vp8d_reg vp8d_quant[4] = { + { VDPU_REG_REF_PIC(3), 11, 0x7ff }, + { VDPU_REG_REF_PIC(3), 0, 0x7ff }, + { VDPU_REG_BD_REF_PIC(4), 11, 0x7ff }, + { VDPU_REG_BD_REF_PIC(4), 0, 0x7ff }, +}; + +/* quantizer delta regs */ +static const struct vp8d_reg vp8d_quant_delta[5] = { + { VDPU_REG_REF_PIC(3), 27, 0x1f }, + { VDPU_REG_REF_PIC(3), 22, 0x1f }, + { VDPU_REG_BD_REF_PIC(4), 27, 0x1f }, + { VDPU_REG_BD_REF_PIC(4), 22, 0x1f }, + { VDPU_REG_BD_P_REF_PIC, 27, 0x1f }, +}; + +/* dct partition start bits regs */ +static const struct vp8d_reg vp8d_dct_start_bits[8] = { + { VDPU_REG_DEC_CTRL2, 26, 0x3f }, { VDPU_REG_DEC_CTRL4, 26, 0x3f }, + { VDPU_REG_DEC_CTRL4, 20, 0x3f }, { VDPU_REG_DEC_CTRL7, 24, 0x3f }, + { VDPU_REG_DEC_CTRL7, 18, 0x3f }, { VDPU_REG_DEC_CTRL7, 12, 0x3f }, + { VDPU_REG_DEC_CTRL7, 6, 0x3f }, { VDPU_REG_DEC_CTRL7, 0, 0x3f }, +}; + +/* precision filter tap regs */ +static const struct vp8d_reg vp8d_pred_bc_tap[8][4] = { + { + { VDPU_REG_PRED_FLT, 22, 0x3ff }, + { VDPU_REG_PRED_FLT, 12, 0x3ff }, + { VDPU_REG_PRED_FLT, 2, 0x3ff }, + { VDPU_REG_REF_PIC(4), 22, 0x3ff }, + }, + { + { VDPU_REG_REF_PIC(4), 12, 0x3ff }, + { VDPU_REG_REF_PIC(4), 2, 0x3ff }, + { VDPU_REG_REF_PIC(5), 22, 0x3ff }, + { VDPU_REG_REF_PIC(5), 12, 0x3ff }, + }, + { + { VDPU_REG_REF_PIC(5), 2, 0x3ff }, + { VDPU_REG_REF_PIC(6), 22, 0x3ff }, + { VDPU_REG_REF_PIC(6), 12, 0x3ff }, + { VDPU_REG_REF_PIC(6), 2, 0x3ff }, + }, + { + { VDPU_REG_REF_PIC(7), 22, 0x3ff }, + { VDPU_REG_REF_PIC(7), 12, 0x3ff }, + { VDPU_REG_REF_PIC(7), 2, 0x3ff }, + { VDPU_REG_LT_REF, 22, 0x3ff }, + }, + { + { VDPU_REG_LT_REF, 12, 0x3ff }, + { VDPU_REG_LT_REF, 2, 0x3ff }, + { VDPU_REG_VALID_REF, 22, 0x3ff }, + { VDPU_REG_VALID_REF, 12, 0x3ff }, + }, + { + { VDPU_REG_VALID_REF, 2, 0x3ff }, + { VDPU_REG_BD_REF_PIC(0), 22, 0x3ff }, + { VDPU_REG_BD_REF_PIC(0), 12, 0x3ff }, + { VDPU_REG_BD_REF_PIC(0), 2, 0x3ff }, + }, + { + { VDPU_REG_BD_REF_PIC(1), 22, 0x3ff }, + { VDPU_REG_BD_REF_PIC(1), 12, 0x3ff }, + { VDPU_REG_BD_REF_PIC(1), 2, 0x3ff }, + { VDPU_REG_BD_REF_PIC(2), 22, 0x3ff }, + }, + { + { VDPU_REG_BD_REF_PIC(2), 12, 0x3ff }, + { VDPU_REG_BD_REF_PIC(2), 2, 0x3ff }, + { VDPU_REG_BD_REF_PIC(3), 22, 0x3ff }, + { VDPU_REG_BD_REF_PIC(3), 12, 0x3ff }, + }, +}; + +/* + * filter taps taken to 7-bit precision, + * reference RFC6386#Page-16, filters[8][6] + */ +static const u32 vp8d_mc_filter[8][6] = { + { 0, 0, 128, 0, 0, 0 }, + { 0, -6, 123, 12, -1, 0 }, + { 2, -11, 108, 36, -8, 1 }, + { 0, -9, 93, 50, -6, 0 }, + { 3, -16, 77, 77, -16, 3 }, + { 0, -6, 50, 93, -9, 0 }, + { 1, -8, 36, 108, -11, 2 }, + { 0, -1, 12, 123, -6, 0 } +}; + +static inline void vp8d_reg_write(struct rk3288_vpu_dev *vpu, + const struct vp8d_reg *reg, u32 val) +{ + u32 v; + + v = vdpu_read(vpu, reg->base); + v &= ~(reg->mask << reg->shift); + v |= ((val & reg->mask) << reg->shift); + vdpu_write_relaxed(vpu, v, reg->base); +} + +/* dump hw params for debug */ +#ifdef DEBUG +static void rk3288_vp8d_dump_hdr(struct rk3288_vpu_ctx *ctx) +{ + const struct v4l2_ctrl_vp8_frame_hdr *hdr = ctx->run.vp8d.frame_hdr; + int dct_total_len = 0; + int i; + + vpu_debug(4, "Frame tag: key_frame=0x%02x, version=0x%02x\n", + !hdr->key_frame, hdr->version); + + vpu_debug(4, "Picture size: w=%d, h=%d\n", hdr->width, hdr->height); + + /* stream addresses */ + vpu_debug(4, "Addresses: segmap=0x%x, probs=0x%x\n", + ctx->hw.vp8d.segment_map.dma, + ctx->hw.vp8d.prob_tbl.dma); + + /* reference frame info */ + vpu_debug(4, "Ref frame: last=%d, golden=%d, alt=%d\n", + hdr->last_frame, hdr->golden_frame, hdr->alt_frame); + + /* bool decoder info */ + vpu_debug(4, "Bool decoder: range=0x%x, value=0x%x, count=0x%x\n", + hdr->bool_dec_range, hdr->bool_dec_value, + hdr->bool_dec_count); + + /* control partition info */ + vpu_debug(4, "Control Part: offset=0x%x, size=0x%x\n", + hdr->first_part_offset, hdr->first_part_size); + vpu_debug(2, "Macroblock Data: bits_offset=0x%x\n", + hdr->macroblock_bit_offset); + + /* dct partition info */ + for (i = 0; i < hdr->num_dct_parts; i++) { + dct_total_len += hdr->dct_part_sizes[i]; + vpu_debug(4, "Dct Part%d Size: 0x%x\n", + i, hdr->dct_part_sizes[i]); + } + + dct_total_len += (hdr->num_dct_parts - 1) * 3; + vpu_debug(4, "Dct Part Total Length: 0x%x\n", dct_total_len); +} +#else +static inline void rk3288_vp8d_dump_hdr(struct rk3288_vpu_ctx *ctx) {} +#endif + +static void rk3288_vp8d_prob_update(struct rk3288_vpu_ctx *ctx) +{ + const struct v4l2_ctrl_vp8_frame_hdr *hdr = ctx->run.vp8d.frame_hdr; + const struct v4l2_vp8_entropy_hdr *entropy_hdr = &hdr->entropy_hdr; + u32 i, j, k; + u8 *dst; + + /* first probs */ + dst = ctx->hw.vp8d.prob_tbl.cpu; + + dst[0] = hdr->prob_skip_false; + dst[1] = hdr->prob_intra; + dst[2] = hdr->prob_last; + dst[3] = hdr->prob_gf; + dst[4] = hdr->sgmnt_hdr.segment_probs[0]; + dst[5] = hdr->sgmnt_hdr.segment_probs[1]; + dst[6] = hdr->sgmnt_hdr.segment_probs[2]; + dst[7] = 0; + + dst += 8; + dst[0] = entropy_hdr->y_mode_probs[0]; + dst[1] = entropy_hdr->y_mode_probs[1]; + dst[2] = entropy_hdr->y_mode_probs[2]; + dst[3] = entropy_hdr->y_mode_probs[3]; + dst[4] = entropy_hdr->uv_mode_probs[0]; + dst[5] = entropy_hdr->uv_mode_probs[1]; + dst[6] = entropy_hdr->uv_mode_probs[2]; + dst[7] = 0; /*unused */ + + /* mv probs */ + dst += 8; + dst[0] = entropy_hdr->mv_probs[0][0]; /* is short */ + dst[1] = entropy_hdr->mv_probs[1][0]; + dst[2] = entropy_hdr->mv_probs[0][1]; /* sign */ + dst[3] = entropy_hdr->mv_probs[1][1]; + dst[4] = entropy_hdr->mv_probs[0][8 + 9]; + dst[5] = entropy_hdr->mv_probs[0][9 + 9]; + dst[6] = entropy_hdr->mv_probs[1][8 + 9]; + dst[7] = entropy_hdr->mv_probs[1][9 + 9]; + dst += 8; + for (i = 0; i < 2; ++i) { + for (j = 0; j < 8; j += 4) { + dst[0] = entropy_hdr->mv_probs[i][j + 9 + 0]; + dst[1] = entropy_hdr->mv_probs[i][j + 9 + 1]; + dst[2] = entropy_hdr->mv_probs[i][j + 9 + 2]; + dst[3] = entropy_hdr->mv_probs[i][j + 9 + 3]; + dst += 4; + } + } + for (i = 0; i < 2; ++i) { + dst[0] = entropy_hdr->mv_probs[i][0 + 2]; + dst[1] = entropy_hdr->mv_probs[i][1 + 2]; + dst[2] = entropy_hdr->mv_probs[i][2 + 2]; + dst[3] = entropy_hdr->mv_probs[i][3 + 2]; + dst[4] = entropy_hdr->mv_probs[i][4 + 2]; + dst[5] = entropy_hdr->mv_probs[i][5 + 2]; + dst[6] = entropy_hdr->mv_probs[i][6 + 2]; + dst[7] = 0; /*unused */ + dst += 8; + } + + /* coeff probs (header part) */ + dst = ctx->hw.vp8d.prob_tbl.cpu; + dst += (8 * 7); + for (i = 0; i < 4; ++i) { + for (j = 0; j < 8; ++j) { + for (k = 0; k < 3; ++k) { + dst[0] = entropy_hdr->coeff_probs[i][j][k][0]; + dst[1] = entropy_hdr->coeff_probs[i][j][k][1]; + dst[2] = entropy_hdr->coeff_probs[i][j][k][2]; + dst[3] = entropy_hdr->coeff_probs[i][j][k][3]; + dst += 4; + } + } + } + + /* coeff probs (footer part) */ + dst = ctx->hw.vp8d.prob_tbl.cpu; + dst += (8 * 55); + for (i = 0; i < 4; ++i) { + for (j = 0; j < 8; ++j) { + for (k = 0; k < 3; ++k) { + dst[0] = entropy_hdr->coeff_probs[i][j][k][4]; + dst[1] = entropy_hdr->coeff_probs[i][j][k][5]; + dst[2] = entropy_hdr->coeff_probs[i][j][k][6]; + dst[3] = entropy_hdr->coeff_probs[i][j][k][7]; + dst[4] = entropy_hdr->coeff_probs[i][j][k][8]; + dst[5] = entropy_hdr->coeff_probs[i][j][k][9]; + dst[6] = entropy_hdr->coeff_probs[i][j][k][10]; + dst[7] = 0; /*unused */ + dst += 8; + } + } + } +} + +/* + * set loop filters + */ +static void rk3288_vp8d_cfg_lf(struct rk3288_vpu_ctx *ctx) +{ + const struct v4l2_ctrl_vp8_frame_hdr *hdr = ctx->run.vp8d.frame_hdr; + struct rk3288_vpu_dev *vpu = ctx->dev; + u32 reg; + int i; + + if (!(hdr->sgmnt_hdr.flags & V4L2_VP8_SEGMNT_HDR_FLAG_ENABLED)) { + vp8d_reg_write(vpu, &vp8d_lf_level[0], hdr->lf_hdr.level); + } else if (hdr->sgmnt_hdr.segment_feature_mode) { + /* absolute mode */ + for (i = 0; i < 4; i++) + vp8d_reg_write(vpu, &vp8d_lf_level[i], + hdr->sgmnt_hdr.lf_update[i]); + } else { + /* delta mode */ + for (i = 0; i < 4; i++) + vp8d_reg_write(vpu, &vp8d_lf_level[i], + clamp(hdr->lf_hdr.level + + hdr->sgmnt_hdr.lf_update[i], 0, 63)); + } + + reg = VDPU_REG_REF_PIC_FILT_SHARPNESS(hdr->lf_hdr.sharpness_level); + if (hdr->lf_hdr.type) + reg |= VDPU_REG_REF_PIC_FILT_TYPE_E; + vdpu_write_relaxed(vpu, reg, VDPU_REG_REF_PIC(0)); + + if (hdr->lf_hdr.flags & V4L2_VP8_LF_HDR_ADJ_ENABLE) { + for (i = 0; i < 4; i++) { + vp8d_reg_write(vpu, &vp8d_mb_adj[i], + hdr->lf_hdr.mb_mode_delta_magnitude[i]); + vp8d_reg_write(vpu, &vp8d_ref_adj[i], + hdr->lf_hdr.ref_frm_delta_magnitude[i]); + } + } +} + +/* + * set quantization parameters + */ +static void rk3288_vp8d_cfg_qp(struct rk3288_vpu_ctx *ctx) +{ + const struct v4l2_ctrl_vp8_frame_hdr *hdr = ctx->run.vp8d.frame_hdr; + struct rk3288_vpu_dev *vpu = ctx->dev; + int i; + + if (!(hdr->sgmnt_hdr.flags & V4L2_VP8_SEGMNT_HDR_FLAG_ENABLED)) { + vp8d_reg_write(vpu, &vp8d_quant[0], hdr->quant_hdr.y_ac_qi); + } else if (hdr->sgmnt_hdr.segment_feature_mode) { + /* absolute mode */ + for (i = 0; i < 4; i++) + vp8d_reg_write(vpu, &vp8d_quant[i], + hdr->sgmnt_hdr.quant_update[i]); + } else { + /* delta mode */ + for (i = 0; i < 4; i++) + vp8d_reg_write(vpu, &vp8d_quant[i], + clamp(hdr->quant_hdr.y_ac_qi + + hdr->sgmnt_hdr.quant_update[i], + 0, 127)); + } + + vp8d_reg_write(vpu, &vp8d_quant_delta[0], hdr->quant_hdr.y_dc_delta); + vp8d_reg_write(vpu, &vp8d_quant_delta[1], hdr->quant_hdr.y2_dc_delta); + vp8d_reg_write(vpu, &vp8d_quant_delta[2], hdr->quant_hdr.y2_ac_delta); + vp8d_reg_write(vpu, &vp8d_quant_delta[3], hdr->quant_hdr.uv_dc_delta); + vp8d_reg_write(vpu, &vp8d_quant_delta[4], hdr->quant_hdr.uv_ac_delta); +} + +/* + * set control partition and dct partition regs + * + * VP8 frame stream data layout: + * + * first_part_size parttion_sizes[0] + * ^ ^ + * src_dma | | + * ^ +--------+------+ +-----+-----+ + * | | control part | | | + * +--------+----------------+------------------+-----------+-----+-----------+ + * | tag 3B | extra 7B | hdr | mb_data | dct sz | dct part0 | ... | dct partn | + * +--------+-----------------------------------+-----------+-----+-----------+ + * | | | | | + * | v +----+---+ v + * | mb_start | src_dma_end + * v v + * first_part_offset dct size part + * (num_dct-1)*3B + * Note: + * 1. only key frame has extra 7 bytes + * 2. all offsets are base on src_dma + * 3. number of dct parts is 1, 2, 4 or 8 + * 4. the addresses set to vpu must be 64bits alignment + */ +static void rk3288_vp8d_cfg_parts(struct rk3288_vpu_ctx *ctx) +{ + const struct v4l2_ctrl_vp8_frame_hdr *hdr = ctx->run.vp8d.frame_hdr; + struct rk3288_vpu_dev *vpu = ctx->dev; + u32 dct_part_total_len = 0; + u32 dct_size_part_size = 0; + u32 dct_part_offset = 0; + u32 mb_offset_bytes = 0; + u32 mb_offset_bits = 0; + u32 mb_start_bits = 0; + struct vp8d_reg reg; + dma_addr_t src_dma; + u32 mb_size = 0; + u32 count = 0; + u32 i; + + src_dma = vb2_dma_contig_plane_dma_addr(&ctx->run.src->b, 0); + + /* + * Calculate control partition mb data info + * @macroblock_bit_offset: bits offset of mb data from first + * part start pos + * @mb_offset_bits: bits offset of mb data from src_dma + * base addr + * @mb_offset_byte: bytes offset of mb data from src_dma + * base addr + * @mb_start_bits: bits offset of mb data from mb data + * 64bits alignment addr + */ + mb_offset_bits = hdr->first_part_offset * 8 + + hdr->macroblock_bit_offset + 8; + mb_offset_bytes = mb_offset_bits / 8; + mb_start_bits = mb_offset_bits + - (mb_offset_bytes & (~DEC_8190_ALIGN_MASK)) * 8; + mb_size = hdr->first_part_size + - (mb_offset_bytes - hdr->first_part_offset) + + (mb_offset_bytes & DEC_8190_ALIGN_MASK); + + /* mb data aligned base addr */ + vdpu_write_relaxed(vpu, (mb_offset_bytes & (~DEC_8190_ALIGN_MASK)) + + src_dma, VDPU_REG_ADDR_REF(13)); + + /* mb data start bits */ + reg.base = VDPU_REG_DEC_CTRL2; + reg.mask = 0x3f; + reg.shift = 18; + vp8d_reg_write(vpu, ®, mb_start_bits); + + /* mb aligned data length */ + reg.base = VDPU_REG_DEC_CTRL6; + reg.mask = 0x3fffff; + reg.shift = 0; + vp8d_reg_write(vpu, ®, mb_size); + + /* + * Calculate dct partition info + * @dct_size_part_size: Containing sizes of dct part, every dct part + * has 3 bytes to store its size, except the last + * dct part + * @dct_part_offset: bytes offset of dct parts from src_dma base addr + * @dct_part_total_len: total size of all dct parts + */ + dct_size_part_size = (hdr->num_dct_parts - 1) * 3; + dct_part_offset = hdr->first_part_offset + hdr->first_part_size; + for (i = 0; i < hdr->num_dct_parts; i++) + dct_part_total_len += hdr->dct_part_sizes[i]; + dct_part_total_len += dct_size_part_size; + dct_part_total_len += (dct_part_offset & DEC_8190_ALIGN_MASK); + + /* number of dct partitions */ + reg.base = VDPU_REG_DEC_CTRL6; + reg.mask = 0xf; + reg.shift = 24; + vp8d_reg_write(vpu, ®, hdr->num_dct_parts - 1); + + /* dct partition length */ + vdpu_write_relaxed(vpu, + VDPU_REG_DEC_CTRL3_STREAM_LEN(dct_part_total_len), + VDPU_REG_DEC_CTRL3); + + /* dct partitions base address */ + for (i = 0; i < hdr->num_dct_parts; i++) { + u32 byte_offset = dct_part_offset + dct_size_part_size + count; + u32 base_addr = byte_offset + src_dma; + + vp8d_reg_write(vpu, &vp8d_dct_base[i], + base_addr & (~DEC_8190_ALIGN_MASK)); + + vp8d_reg_write(vpu, &vp8d_dct_start_bits[i], + (byte_offset & DEC_8190_ALIGN_MASK) * 8); + + count += hdr->dct_part_sizes[i]; + } +} + +/* + * prediction filter taps + * normal 6-tap filters + */ +static void rk3288_vp8d_cfg_tap(struct rk3288_vpu_ctx *ctx) +{ + const struct v4l2_ctrl_vp8_frame_hdr *hdr = ctx->run.vp8d.frame_hdr; + struct rk3288_vpu_dev *vpu = ctx->dev; + struct vp8d_reg reg; + u32 val = 0; + int i, j; + + reg.base = VDPU_REG_BD_REF_PIC(3); + reg.mask = 0xf; + + if ((hdr->version & 0x03) != 0) + return; /* Tap filter not used. */ + + + for (i = 0; i < 8; i++) { + val = (vp8d_mc_filter[i][0] << 2) | vp8d_mc_filter[i][5]; + + for (j = 0; j < 4; j++) + vp8d_reg_write(vpu, &vp8d_pred_bc_tap[i][j], + vp8d_mc_filter[i][j + 1]); + + switch (i) { + case 2: + reg.shift = 8; + break; + case 4: + reg.shift = 4; + break; + case 6: + reg.shift = 0; + break; + default: + continue; + } + + vp8d_reg_write(vpu, ®, val); + } +} + +/* set reference frame */ +static void rk3288_vp8d_cfg_ref(struct rk3288_vpu_ctx *ctx) +{ + u32 reg; + struct vb2_buffer *buf; + struct rk3288_vpu_dev *vpu = ctx->dev; + const struct v4l2_ctrl_vp8_frame_hdr *hdr = ctx->run.vp8d.frame_hdr; + + /* set last frame address */ + if (hdr->last_frame >= ctx->vq_dst.num_buffers) + buf = &ctx->run.dst->b; + else + buf = ctx->dst_bufs[hdr->last_frame]; + + if (!hdr->key_frame) + vdpu_write_relaxed(vpu, + vb2_dma_contig_plane_dma_addr(&ctx->run.dst->b, 0), + VDPU_REG_ADDR_REF(0)); + else + vdpu_write_relaxed(vpu, vb2_dma_contig_plane_dma_addr(buf, 0), + VDPU_REG_ADDR_REF(0)); + + /* set golden reference frame buffer address */ + if (hdr->golden_frame >= ctx->vq_dst.num_buffers) + buf = &ctx->run.dst->b; + else + buf = ctx->dst_bufs[hdr->golden_frame]; + + reg = vb2_dma_contig_plane_dma_addr(buf, 0); + if (hdr->sign_bias_golden) + reg |= VDPU_REG_ADDR_REF_TOPC_E; + vdpu_write_relaxed(vpu, reg, VDPU_REG_ADDR_REF(4)); + + /* set alternate reference frame buffer address */ + if (hdr->alt_frame >= ctx->vq_dst.num_buffers) + buf = &ctx->run.dst->b; + else + buf = ctx->dst_bufs[hdr->alt_frame]; + + reg = vb2_dma_contig_plane_dma_addr(buf, 0); + if (hdr->sign_bias_alternate) + reg |= VDPU_REG_ADDR_REF_TOPC_E; + vdpu_write_relaxed(vpu, reg, VDPU_REG_ADDR_REF(5)); +} + +static void rk3288_vp8d_cfg_buffers(struct rk3288_vpu_ctx *ctx) +{ + const struct v4l2_ctrl_vp8_frame_hdr *hdr = ctx->run.vp8d.frame_hdr; + struct rk3288_vpu_dev *vpu = ctx->dev; + u32 reg; + + /* set probability table buffer address */ + vdpu_write_relaxed(vpu, ctx->hw.vp8d.prob_tbl.dma, + VDPU_REG_ADDR_QTABLE); + + /* set segment map address */ + reg = 0; + reg = VDPU_REG_FWD_PIC1_SEGMENT_BASE(ctx->hw.vp8d.segment_map.dma); + if (hdr->sgmnt_hdr.flags & V4L2_VP8_SEGMNT_HDR_FLAG_ENABLED) { + reg |= VDPU_REG_FWD_PIC1_SEGMENT_E; + if (hdr->sgmnt_hdr.flags & V4L2_VP8_SEGMNT_HDR_FLAG_UPDATE_MAP) + reg |= VDPU_REG_FWD_PIC1_SEGMENT_UPD_E; + } + vdpu_write_relaxed(vpu, reg, VDPU_REG_FWD_PIC(0)); + + /* set output frame buffer address */ + vdpu_write_relaxed(vpu, + vb2_dma_contig_plane_dma_addr(&ctx->run.dst->b, 0), + VDPU_REG_ADDR_DST); +} + +int rk3288_vpu_vp8d_init(struct rk3288_vpu_ctx *ctx) +{ + struct rk3288_vpu_dev *vpu = ctx->dev; + unsigned int mb_width, mb_height; + size_t segment_map_size; + int ret; + + /* segment map table size calculation */ + mb_width = MB_WIDTH(ctx->dst_fmt.width); + mb_height = MB_HEIGHT(ctx->dst_fmt.height); + segment_map_size = round_up(DIV_ROUND_UP(mb_width * mb_height, 4), 64); + + /* + * In context init the dma buffer for segment map must be allocated. + * And the data in segment map buffer must be set to all zero. + */ + ret = rk3288_vpu_aux_buf_alloc(vpu, &ctx->hw.vp8d.segment_map, + segment_map_size); + if (ret) { + vpu_err("allocate segment map mem failed\n"); + return ret; + } + memset(ctx->hw.vp8d.segment_map.cpu, 0, ctx->hw.vp8d.segment_map.size); + + /* + * Allocate probability table buffer, + * total 1208 bytes, 4K page is far enough. + */ + ret = rk3288_vpu_aux_buf_alloc(vpu, &ctx->hw.vp8d.prob_tbl, + sizeof(struct vp8_prob_tbl_packed)); + if (ret) { + vpu_err("allocate prob table mem failed\n"); + goto prob_table_failed; + } + + return 0; + +prob_table_failed: + rk3288_vpu_aux_buf_free(vpu, &ctx->hw.vp8d.segment_map); + + return ret; +} + +void rk3288_vpu_vp8d_exit(struct rk3288_vpu_ctx *ctx) +{ + struct rk3288_vpu_dev *vpu = ctx->dev; + + rk3288_vpu_aux_buf_free(vpu, &ctx->hw.vp8d.segment_map); + rk3288_vpu_aux_buf_free(vpu, &ctx->hw.vp8d.prob_tbl); +} + +void rk3288_vpu_vp8d_run(struct rk3288_vpu_ctx *ctx) +{ + const struct v4l2_ctrl_vp8_frame_hdr *hdr = ctx->run.vp8d.frame_hdr; + struct rk3288_vpu_dev *vpu = ctx->dev; + size_t height = ctx->dst_fmt.height; + size_t width = ctx->dst_fmt.width; + u32 mb_width, mb_height; + u32 reg; + + rk3288_vp8d_dump_hdr(ctx); + + /* reset segment_map buffer in keyframe */ + if (!hdr->key_frame && ctx->hw.vp8d.segment_map.cpu) + memset(ctx->hw.vp8d.segment_map.cpu, 0, + ctx->hw.vp8d.segment_map.size); + + rk3288_vp8d_prob_update(ctx); + + rk3288_vpu_power_on(vpu); + + reg = VDPU_REG_CONFIG_DEC_TIMEOUT_E + | VDPU_REG_CONFIG_DEC_STRENDIAN_E + | VDPU_REG_CONFIG_DEC_INSWAP32_E + | VDPU_REG_CONFIG_DEC_STRSWAP32_E + | VDPU_REG_CONFIG_DEC_OUTSWAP32_E + | VDPU_REG_CONFIG_DEC_CLK_GATE_E + | VDPU_REG_CONFIG_DEC_IN_ENDIAN + | VDPU_REG_CONFIG_DEC_OUT_ENDIAN + | VDPU_REG_CONFIG_DEC_MAX_BURST(16); + vdpu_write_relaxed(vpu, reg, VDPU_REG_CONFIG); + + reg = VDPU_REG_DEC_CTRL0_DEC_MODE(10); + if (hdr->key_frame) + reg |= VDPU_REG_DEC_CTRL0_PIC_INTER_E; + if (!(hdr->flags & V4L2_VP8_FRAME_HDR_FLAG_MB_NO_SKIP_COEFF)) + reg |= VDPU_REG_DEC_CTRL0_SKIP_MODE; + if (hdr->lf_hdr.level == 0) + reg |= VDPU_REG_DEC_CTRL0_FILTERING_DIS; + vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_CTRL0); + + /* frame dimensions */ + mb_width = MB_WIDTH(width); + mb_height = MB_HEIGHT(height); + reg = VDPU_REG_DEC_CTRL1_PIC_MB_WIDTH(mb_width) + | VDPU_REG_DEC_CTRL1_PIC_MB_HEIGHT_P(mb_height) + | VDPU_REG_DEC_CTRL1_PIC_MB_W_EXT(mb_width >> 9) + | VDPU_REG_DEC_CTRL1_PIC_MB_H_EXT(mb_height >> 8); + vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_CTRL1); + + /* bool decode info */ + reg = VDPU_REG_DEC_CTRL2_BOOLEAN_RANGE(hdr->bool_dec_range) + | VDPU_REG_DEC_CTRL2_BOOLEAN_VALUE(hdr->bool_dec_value); + vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_CTRL2); + + reg = 0; + if (hdr->version != 3) + reg |= VDPU_REG_DEC_CTRL4_VC1_HEIGHT_EXT; + if (hdr->version & 0x3) + reg |= VDPU_REG_DEC_CTRL4_BILIN_MC_E; + vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_CTRL4); + + rk3288_vp8d_cfg_lf(ctx); + rk3288_vp8d_cfg_qp(ctx); + rk3288_vp8d_cfg_parts(ctx); + rk3288_vp8d_cfg_tap(ctx); + rk3288_vp8d_cfg_ref(ctx); + rk3288_vp8d_cfg_buffers(ctx); + + schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); + + vdpu_write(vpu, VDPU_REG_INTERRUPT_DEC_E, VDPU_REG_INTERRUPT); +} diff --git a/drivers/media/platform/rockchip-vpu/rk3288_vpu_hw_vp8e.c b/drivers/media/platform/rockchip-vpu/rk3288_vpu_hw_vp8e.c new file mode 100644 index 000000000000..ce02712dc9fc --- /dev/null +++ b/drivers/media/platform/rockchip-vpu/rk3288_vpu_hw_vp8e.c @@ -0,0 +1,534 @@ +/* + * Rockchip RK3288 VPU codec driver + * + * Copyright (C) 2014 Rockchip Electronics Co., Ltd. + * Alpha Lin + * Jeffy Chen + * + * Copyright (C) 2014 Google, Inc. + * Tomasz Figa + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "rk3288_vpu_common.h" + +#include +#include + +#include "rk3288_vpu_regs.h" +#include "rk3288_vpu_hw.h" + +/* Various parameters specific to VP8 encoder. */ +#define VP8_CABAC_CTX_OFFSET 192 +#define VP8_CABAC_CTX_SIZE ((55 + 96) << 3) + +#define VP8_KEY_FRAME_HDR_SIZE 10 +#define VP8_INTER_FRAME_HDR_SIZE 3 + +#define VP8_FRAME_TAG_KEY_FRAME_BIT BIT(0) +#define VP8_FRAME_TAG_LENGTH_SHIFT 5 +#define VP8_FRAME_TAG_LENGTH_MASK (0x7ffff << 5) + +/** + * struct rk3288_vpu_vp8e_ctrl_buf - hardware control buffer layout + * @ext_hdr_size: Ext header size in bytes (written by hardware). + * @dct_size: DCT partition size (written by hardware). + * @rsvd: Reserved for hardware. + */ +struct rk3288_vpu_vp8e_ctrl_buf { + u32 ext_hdr_size; + u32 dct_size; + u8 rsvd[1016]; +}; + +/* + * The hardware takes care only of ext hdr and dct partition. The software + * must take care of frame header. + * + * Buffer layout as received from hardware: + * |<--gap-->|<--ext hdr-->|<-gap->|<---dct part--- + * |<-------dct part offset------->| + * + * Required buffer layout: + * |<--hdr-->|<--ext hdr-->|<---dct part--- + */ +void rk3288_vpu_vp8e_assemble_bitstream(struct rk3288_vpu_ctx *ctx, + struct rk3288_vpu_buf *dst_buf) +{ + size_t ext_hdr_size = dst_buf->vp8e.ext_hdr_size; + size_t dct_size = dst_buf->vp8e.dct_size; + size_t hdr_size = dst_buf->vp8e.hdr_size; + size_t dst_size; + size_t tag_size; + void *dst; + u32 *tag; + + dst_size = vb2_plane_size(&dst_buf->b, 0); + dst = vb2_plane_vaddr(&dst_buf->b, 0); + tag = dst; /* To access frame tag words. */ + + if (WARN_ON(hdr_size + ext_hdr_size + dct_size > dst_size)) + return; + if (WARN_ON(dst_buf->vp8e.dct_offset + dct_size > dst_size)) + return; + + vpu_debug(1, "%s: hdr_size = %u, ext_hdr_size = %u, dct_size = %u\n", + __func__, hdr_size, ext_hdr_size, dct_size); + + memmove(dst + hdr_size + ext_hdr_size, + dst + dst_buf->vp8e.dct_offset, dct_size); + memcpy(dst, dst_buf->vp8e.header, hdr_size); + + /* Patch frame tag at first 32-bit word of the frame. */ + if (dst_buf->b.v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) { + tag_size = VP8_KEY_FRAME_HDR_SIZE; + tag[0] &= ~VP8_FRAME_TAG_KEY_FRAME_BIT; + } else { + tag_size = VP8_INTER_FRAME_HDR_SIZE; + tag[0] |= VP8_FRAME_TAG_KEY_FRAME_BIT; + } + + tag[0] &= ~VP8_FRAME_TAG_LENGTH_MASK; + tag[0] |= (hdr_size + ext_hdr_size - tag_size) + << VP8_FRAME_TAG_LENGTH_SHIFT; + + vb2_set_plane_payload(&dst_buf->b, 0, + hdr_size + ext_hdr_size + dct_size); +} + +static inline unsigned int ref_luma_size(unsigned int w, unsigned int h) +{ + return round_up(w, MB_DIM) * round_up(h, MB_DIM); +} + +int rk3288_vpu_vp8e_init(struct rk3288_vpu_ctx *ctx) +{ + struct rk3288_vpu_dev *vpu = ctx->dev; + size_t height = ctx->src_fmt.height; + size_t width = ctx->src_fmt.width; + size_t ref_buf_size; + size_t mv_size; + int ret; + + ret = rk3288_vpu_aux_buf_alloc(vpu, &ctx->hw.vp8e.ctrl_buf, + sizeof(struct rk3288_vpu_vp8e_ctrl_buf)); + if (ret) { + vpu_err("failed to allocate ctrl buffer\n"); + return ret; + } + + mv_size = DIV_ROUND_UP(width, 16) * DIV_ROUND_UP(height, 16) / 4; + ret = rk3288_vpu_aux_buf_alloc(vpu, &ctx->hw.vp8e.mv_buf, mv_size); + if (ret) { + vpu_err("failed to allocate MV buffer\n"); + goto err_ctrl_buf; + } + + ref_buf_size = ref_luma_size(width, height) * 3 / 2; + ret = rk3288_vpu_aux_buf_alloc(vpu, &ctx->hw.vp8e.ext_buf, + 2 * ref_buf_size); + if (ret) { + vpu_err("failed to allocate ext buffer\n"); + goto err_mv_buf; + } + + return 0; + +err_mv_buf: + rk3288_vpu_aux_buf_free(vpu, &ctx->hw.vp8e.mv_buf); +err_ctrl_buf: + rk3288_vpu_aux_buf_free(vpu, &ctx->hw.vp8e.ctrl_buf); + + return ret; +} + +void rk3288_vpu_vp8e_exit(struct rk3288_vpu_ctx *ctx) +{ + struct rk3288_vpu_dev *vpu = ctx->dev; + + rk3288_vpu_aux_buf_free(vpu, &ctx->hw.vp8e.ext_buf); + rk3288_vpu_aux_buf_free(vpu, &ctx->hw.vp8e.mv_buf); + rk3288_vpu_aux_buf_free(vpu, &ctx->hw.vp8e.ctrl_buf); +} + +static inline u32 enc_in_img_ctrl(struct rk3288_vpu_ctx *ctx) +{ + struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; + struct v4l2_rect *crop = &ctx->src_crop; + unsigned bytes_per_line, overfill_r, overfill_b; + + /* + * The hardware needs only the value for luma plane, because + * values of other planes are calculated internally based on + * format setting. + */ + bytes_per_line = pix_fmt->plane_fmt[0].bytesperline; + overfill_r = (pix_fmt->width - crop->width) / 4; + overfill_b = pix_fmt->height - crop->height; + + return VEPU_REG_IN_IMG_CTRL_ROW_LEN(bytes_per_line) + | VEPU_REG_IN_IMG_CTRL_OVRFLR_D4(overfill_r) + | VEPU_REG_IN_IMG_CTRL_OVRFLB_D4(overfill_b) + | VEPU_REG_IN_IMG_CTRL_FMT(ctx->vpu_src_fmt->enc_fmt); +} + +static void rk3288_vpu_vp8e_set_buffers(struct rk3288_vpu_dev *vpu, + struct rk3288_vpu_ctx *ctx) +{ + const struct rk3288_vp8e_reg_params *params = ctx->run.vp8e.reg_params; + dma_addr_t ref_buf_dma, rec_buf_dma; + dma_addr_t stream_dma; + size_t rounded_size; + dma_addr_t dst_dma; + u32 start_offset; + size_t dst_size; + + rounded_size = ref_luma_size(ctx->src_fmt.width, + ctx->src_fmt.height); + + ref_buf_dma = rec_buf_dma = ctx->hw.vp8e.ext_buf.dma; + if (ctx->hw.vp8e.ref_rec_ptr) + ref_buf_dma += rounded_size * 3 / 2; + else + rec_buf_dma += rounded_size * 3 / 2; + ctx->hw.vp8e.ref_rec_ptr ^= 1; + + if (rk3288_vpu_ctx_is_dummy_encode(ctx)) { + dst_dma = vpu->dummy_encode_dst.dma; + dst_size = vpu->dummy_encode_dst.size; + } else { + dst_dma = vb2_dma_contig_plane_dma_addr(&ctx->run.dst->b, 0); + dst_size = vb2_plane_size(&ctx->run.dst->b, 0); + } + + /* + * stream addr-->| + * align 64bits->|<-start offset->| + * |<---------header size-------->|<---dst buf--- + */ + start_offset = (params->rlc_ctrl & VEPU_REG_RLC_CTRL_STR_OFFS_MASK) + >> VEPU_REG_RLC_CTRL_STR_OFFS_SHIFT; + stream_dma = dst_dma + params->hdr_len; + + /** + * Userspace will pass 8 bytes aligned size(round_down) to us, + * so we need to plus start offset to get real header size. + * + * |<-aligned size->|<-start offset->| + * |<----------header size---------->| + */ + ctx->run.dst->vp8e.hdr_size = params->hdr_len + (start_offset >> 3); + + if (params->enc_ctrl & VEPU_REG_ENC_CTRL_KEYFRAME_BIT) + ctx->run.dst->b.v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME; + else + ctx->run.dst->b.v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME; + + /* + * We assume here that 1/10 of the buffer is enough for headers. + * DCT partition will be placed in remaining 9/10 of the buffer. + */ + ctx->run.dst->vp8e.dct_offset = round_up(dst_size / 10, 8); + + /* Destination buffer. */ + vepu_write_relaxed(vpu, stream_dma, VEPU_REG_ADDR_OUTPUT_STREAM); + vepu_write_relaxed(vpu, dst_dma + ctx->run.dst->vp8e.dct_offset, + VEPU_REG_ADDR_VP8_DCT_PART(0)); + vepu_write_relaxed(vpu, dst_size - ctx->run.dst->vp8e.dct_offset, + VEPU_REG_STR_BUF_LIMIT); + + /* Auxilliary buffers. */ + vepu_write_relaxed(vpu, ctx->hw.vp8e.ctrl_buf.dma, + VEPU_REG_ADDR_OUTPUT_CTRL); + vepu_write_relaxed(vpu, ctx->hw.vp8e.mv_buf.dma, + VEPU_REG_ADDR_MV_OUT); + vepu_write_relaxed(vpu, ctx->run.priv_dst.dma, + VEPU_REG_ADDR_VP8_PROB_CNT); + vepu_write_relaxed(vpu, ctx->run.priv_src.dma + VP8_CABAC_CTX_OFFSET, + VEPU_REG_ADDR_CABAC_TBL); + vepu_write_relaxed(vpu, ctx->run.priv_src.dma + + VP8_CABAC_CTX_OFFSET + VP8_CABAC_CTX_SIZE, + VEPU_REG_ADDR_VP8_SEG_MAP); + + /* Reference buffers. */ + vepu_write_relaxed(vpu, ref_buf_dma, + VEPU_REG_ADDR_REF_LUMA); + vepu_write_relaxed(vpu, ref_buf_dma + rounded_size, + VEPU_REG_ADDR_REF_CHROMA); + + /* Reconstruction buffers. */ + vepu_write_relaxed(vpu, rec_buf_dma, + VEPU_REG_ADDR_REC_LUMA); + vepu_write_relaxed(vpu, rec_buf_dma + rounded_size, + VEPU_REG_ADDR_REC_CHROMA); + + /* Source buffer. */ + if (rk3288_vpu_ctx_is_dummy_encode(ctx)) { + vepu_write_relaxed(vpu, vpu->dummy_encode_src[PLANE_Y].dma, + VEPU_REG_ADDR_IN_LUMA); + vepu_write_relaxed(vpu, vpu->dummy_encode_src[PLANE_CB].dma, + VEPU_REG_ADDR_IN_CB); + vepu_write_relaxed(vpu, vpu->dummy_encode_src[PLANE_CR].dma, + VEPU_REG_ADDR_IN_CR); + } else { + vepu_write_relaxed(vpu, vb2_dma_contig_plane_dma_addr( + &ctx->run.src->b, PLANE_Y), + VEPU_REG_ADDR_IN_LUMA); + vepu_write_relaxed(vpu, vb2_dma_contig_plane_dma_addr( + &ctx->run.src->b, PLANE_CB), + VEPU_REG_ADDR_IN_CB); + vepu_write_relaxed(vpu, vb2_dma_contig_plane_dma_addr( + &ctx->run.src->b, PLANE_CR), + VEPU_REG_ADDR_IN_CR); + } + + /* Source parameters. */ + vepu_write_relaxed(vpu, enc_in_img_ctrl(ctx), VEPU_REG_IN_IMG_CTRL); +} + +static void rk3288_vpu_vp8e_set_params(struct rk3288_vpu_dev *vpu, + struct rk3288_vpu_ctx *ctx) +{ + const struct rk3288_vp8e_reg_params *params = ctx->run.vp8e.reg_params; + int i; + + vepu_write_relaxed(vpu, params->enc_ctrl0, VEPU_REG_ENC_CTRL0); + vepu_write_relaxed(vpu, params->enc_ctrl1, VEPU_REG_ENC_CTRL1); + vepu_write_relaxed(vpu, params->enc_ctrl2, VEPU_REG_ENC_CTRL2); + vepu_write_relaxed(vpu, params->enc_ctrl3, VEPU_REG_ENC_CTRL3); + vepu_write_relaxed(vpu, params->enc_ctrl5, VEPU_REG_ENC_CTRL5); + vepu_write_relaxed(vpu, params->enc_ctrl4, VEPU_REG_ENC_CTRL4); + vepu_write_relaxed(vpu, params->str_hdr_rem_msb, + VEPU_REG_STR_HDR_REM_MSB); + vepu_write_relaxed(vpu, params->str_hdr_rem_lsb, + VEPU_REG_STR_HDR_REM_LSB); + vepu_write_relaxed(vpu, params->mad_ctrl, VEPU_REG_MAD_CTRL); + + for (i = 0; i < ARRAY_SIZE(params->qp_val); ++i) + vepu_write_relaxed(vpu, params->qp_val[i], + VEPU_REG_VP8_QP_VAL(i)); + + vepu_write_relaxed(vpu, params->bool_enc, VEPU_REG_VP8_BOOL_ENC); + vepu_write_relaxed(vpu, params->vp8_ctrl0, VEPU_REG_VP8_CTRL0); + vepu_write_relaxed(vpu, params->rlc_ctrl, VEPU_REG_RLC_CTRL); + vepu_write_relaxed(vpu, params->mb_ctrl, VEPU_REG_MB_CTRL); + + for (i = 0; i < ARRAY_SIZE(params->rgb_yuv_coeff); ++i) + vepu_write_relaxed(vpu, params->rgb_yuv_coeff[i], + VEPU_REG_RGB_YUV_COEFF(i)); + + vepu_write_relaxed(vpu, params->rgb_mask_msb, + VEPU_REG_RGB_MASK_MSB); + vepu_write_relaxed(vpu, params->intra_area_ctrl, + VEPU_REG_INTRA_AREA_CTRL); + vepu_write_relaxed(vpu, params->cir_intra_ctrl, + VEPU_REG_CIR_INTRA_CTRL); + vepu_write_relaxed(vpu, params->first_roi_area, + VEPU_REG_FIRST_ROI_AREA); + vepu_write_relaxed(vpu, params->second_roi_area, + VEPU_REG_SECOND_ROI_AREA); + vepu_write_relaxed(vpu, params->mvc_ctrl, + VEPU_REG_MVC_CTRL); + + for (i = 0; i < ARRAY_SIZE(params->intra_penalty); ++i) + vepu_write_relaxed(vpu, params->intra_penalty[i], + VEPU_REG_VP8_INTRA_PENALTY(i)); + + for (i = 0; i < ARRAY_SIZE(params->seg_qp); ++i) + vepu_write_relaxed(vpu, params->seg_qp[i], + VEPU_REG_VP8_SEG_QP(i)); + + for (i = 0; i < ARRAY_SIZE(params->dmv_4p_1p_penalty); ++i) + vepu_write_relaxed(vpu, params->dmv_4p_1p_penalty[i], + VEPU_REG_DMV_4P_1P_PENALTY(i)); + + for (i = 0; i < ARRAY_SIZE(params->dmv_qpel_penalty); ++i) + vepu_write_relaxed(vpu, params->dmv_qpel_penalty[i], + VEPU_REG_DMV_QPEL_PENALTY(i)); + + vepu_write_relaxed(vpu, params->vp8_ctrl1, VEPU_REG_VP8_CTRL1); + vepu_write_relaxed(vpu, params->bit_cost_golden, + VEPU_REG_VP8_BIT_COST_GOLDEN); + + for (i = 0; i < ARRAY_SIZE(params->loop_flt_delta); ++i) + vepu_write_relaxed(vpu, params->loop_flt_delta[i], + VEPU_REG_VP8_LOOP_FLT_DELTA(i)); +} + +void rk3288_vpu_vp8e_run(struct rk3288_vpu_ctx *ctx) +{ + struct rk3288_vpu_dev *vpu = ctx->dev; + u32 reg; + + /* The hardware expects the control buffer to be zeroed. */ + memset(ctx->hw.vp8e.ctrl_buf.cpu, 0, + sizeof(struct rk3288_vpu_vp8e_ctrl_buf)); + + /* + * Program the hardware. + */ + rk3288_vpu_power_on(vpu); + + vepu_write_relaxed(vpu, VEPU_REG_ENC_CTRL_ENC_MODE_VP8, + VEPU_REG_ENC_CTRL); + + rk3288_vpu_vp8e_set_params(vpu, ctx); + rk3288_vpu_vp8e_set_buffers(vpu, ctx); + + /* Make sure that all registers are written at this point. */ + wmb(); + + /* Set the watchdog. */ + schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); + + /* Start the hardware. */ + reg = VEPU_REG_AXI_CTRL_OUTPUT_SWAP16 + | VEPU_REG_AXI_CTRL_INPUT_SWAP16 + | VEPU_REG_AXI_CTRL_BURST_LEN(16) + | VEPU_REG_AXI_CTRL_GATE_BIT + | VEPU_REG_AXI_CTRL_OUTPUT_SWAP32 + | VEPU_REG_AXI_CTRL_INPUT_SWAP32 + | VEPU_REG_AXI_CTRL_OUTPUT_SWAP8 + | VEPU_REG_AXI_CTRL_INPUT_SWAP8; + vepu_write(vpu, reg, VEPU_REG_AXI_CTRL); + + vepu_write(vpu, 0, VEPU_REG_INTERRUPT); + + reg = VEPU_REG_ENC_CTRL_NAL_MODE_BIT + | VEPU_REG_ENC_CTRL_WIDTH(MB_WIDTH(ctx->src_fmt.width)) + | VEPU_REG_ENC_CTRL_HEIGHT(MB_HEIGHT(ctx->src_fmt.height)) + | VEPU_REG_ENC_CTRL_ENC_MODE_VP8 + | VEPU_REG_ENC_CTRL_EN_BIT; + + if (ctx->run.dst->b.v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) + reg |= VEPU_REG_ENC_CTRL_KEYFRAME_BIT; + + vepu_write(vpu, reg, VEPU_REG_ENC_CTRL); +} + +void rk3288_vpu_vp8e_done(struct rk3288_vpu_ctx *ctx, + enum vb2_buffer_state result) +{ + struct rk3288_vpu_vp8e_ctrl_buf *ctrl_buf = ctx->hw.vp8e.ctrl_buf.cpu; + + /* Read length information of this run from utility buffer. */ + ctx->run.dst->vp8e.ext_hdr_size = ctrl_buf->ext_hdr_size; + ctx->run.dst->vp8e.dct_size = ctrl_buf->dct_size; + + rk3288_vpu_run_done(ctx, result); +} + +/* + * WAR for encoder state corruption after decoding + */ + +static const struct rk3288_vp8e_reg_params dummy_encode_reg_params = { + /* 00000014 */ .hdr_len = 0x00000000, + /* 00000038 */ .enc_ctrl = VEPU_REG_ENC_CTRL_KEYFRAME_BIT, + /* 00000040 */ .enc_ctrl0 = 0x00000000, + /* 00000044 */ .enc_ctrl1 = 0x00000000, + /* 00000048 */ .enc_ctrl2 = 0x00040014, + /* 0000004c */ .enc_ctrl3 = 0x404083c0, + /* 00000050 */ .enc_ctrl5 = 0x01006bff, + /* 00000054 */ .enc_ctrl4 = 0x00000039, + /* 00000058 */ .str_hdr_rem_msb = 0x85848805, + /* 0000005c */ .str_hdr_rem_lsb = 0x02000000, + /* 00000064 */ .mad_ctrl = 0x00000000, + /* 0000006c */ .qp_val = { + /* 0000006c */ 0x020213b1, + /* 00000070 */ 0x02825249, + /* 00000074 */ 0x048409d8, + /* 00000078 */ 0x03834c30, + /* 0000007c */ 0x020213b1, + /* 00000080 */ 0x02825249, + /* 00000084 */ 0x00340e0d, + /* 00000088 */ 0x401c1a15, + }, + /* 0000008c */ .bool_enc = 0x00018140, + /* 00000090 */ .vp8_ctrl0 = 0x000695c0, + /* 00000094 */ .rlc_ctrl = 0x14000000, + /* 00000098 */ .mb_ctrl = 0x00000000, + /* 000000d4 */ .rgb_yuv_coeff = { + /* 000000d4 */ 0x962b4c85, + /* 000000d8 */ 0x90901d50, + }, + /* 000000dc */ .rgb_mask_msb = 0x0000b694, + /* 000000e0 */ .intra_area_ctrl = 0xffffffff, + /* 000000e4 */ .cir_intra_ctrl = 0x00000000, + /* 000000f0 */ .first_roi_area = 0xffffffff, + /* 000000f4 */ .second_roi_area = 0xffffffff, + /* 000000f8 */ .mvc_ctrl = 0x01780000, + /* 00000100 */ .intra_penalty = { + /* 00000100 */ 0x00010005, + /* 00000104 */ 0x00015011, + /* 00000108 */ 0x0000c005, + /* 0000010c */ 0x00016010, + /* 00000110 */ 0x0001a018, + /* 00000114 */ 0x00018015, + /* 00000118 */ 0x0001d01a, + }, + /* 00000120 */ .seg_qp = { + /* 00000120 */ 0x020213b1, + /* 00000124 */ 0x02825249, + /* 00000128 */ 0x048409d8, + /* 0000012c */ 0x03834c30, + /* 00000130 */ 0x020213b1, + /* 00000134 */ 0x02825249, + /* 00000138 */ 0x00340e0d, + /* 0000013c */ 0x341c1a15, + /* 00000140 */ 0x020213b1, + /* 00000144 */ 0x02825249, + /* 00000148 */ 0x048409d8, + /* 0000014c */ 0x03834c30, + /* 00000150 */ 0x020213b1, + /* 00000154 */ 0x02825249, + /* 00000158 */ 0x00340e0d, + /* 0000015c */ 0x341c1a15, + /* 00000160 */ 0x020213b1, + /* 00000164 */ 0x02825249, + /* 00000168 */ 0x048409d8, + /* 0000016c */ 0x03834c30, + /* 00000170 */ 0x020213b1, + /* 00000174 */ 0x02825249, + /* 00000178 */ 0x00340e0d, + /* 0000017c */ 0x341c1a15, + }, + /* 00000180 */ .dmv_4p_1p_penalty = { + /* 00000180 */ 0x00020406, + /* 00000184 */ 0x080a0c0e, + /* 00000188 */ 0x10121416, + /* 0000018c */ 0x181a1c1e, + /* 00000190 */ 0x20222426, + /* 00000194 */ 0x282a2c2e, + /* 00000198 */ 0x30323436, + /* 0000019c */ 0x383a3c3e, + /* 000001a0 */ 0x40424446, + /* 000001a4 */ 0x484a4c4e, + /* 000001a8 */ 0x50525456, + /* 000001ac */ 0x585a5c5e, + /* 000001b0 */ 0x60626466, + /* 000001b4 */ 0x686a6c6e, + /* 000001b8 */ 0x70727476, + /* NOTE: Further 17 registers set to 0. */ + }, + /* + * NOTE: Following registers all set to 0: + * - dmv_qpel_penalty, + * - vp8_ctrl1, + * - bit_cost_golden, + * - loop_flt_delta. + */ +}; + +const struct rk3288_vp8e_reg_params *rk3288_vpu_vp8e_get_dummy_params(void) +{ + return &dummy_encode_reg_params; +} diff --git a/drivers/media/platform/rockchip-vpu/rk3288_vpu_regs.h b/drivers/media/platform/rockchip-vpu/rk3288_vpu_regs.h new file mode 100644 index 000000000000..618757e9bb34 --- /dev/null +++ b/drivers/media/platform/rockchip-vpu/rk3288_vpu_regs.h @@ -0,0 +1,384 @@ +/* + * Rockchip RK3288 VPU codec driver + * + * Copyright (C) 2014 Google, Inc. + * Tomasz Figa + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 RK3288_VPU_REGS_H_ +#define RK3288_VPU_REGS_H_ + +/* Encoder registers. */ +#define VEPU_REG_INTERRUPT 0x004 +#define VEPU_REG_INTERRUPT_DIS_BIT BIT(1) +#define VEPU_REG_INTERRUPT_BIT BIT(0) +#define VEPU_REG_AXI_CTRL 0x008 +#define VEPU_REG_AXI_CTRL_OUTPUT_SWAP16 BIT(15) +#define VEPU_REG_AXI_CTRL_INPUT_SWAP16 BIT(14) +#define VEPU_REG_AXI_CTRL_BURST_LEN(x) ((x) << 8) +#define VEPU_REG_AXI_CTRL_GATE_BIT BIT(4) +#define VEPU_REG_AXI_CTRL_OUTPUT_SWAP32 BIT(3) +#define VEPU_REG_AXI_CTRL_INPUT_SWAP32 BIT(2) +#define VEPU_REG_AXI_CTRL_OUTPUT_SWAP8 BIT(1) +#define VEPU_REG_AXI_CTRL_INPUT_SWAP8 BIT(0) +#define VEPU_REG_ADDR_OUTPUT_STREAM 0x014 +#define VEPU_REG_ADDR_OUTPUT_CTRL 0x018 +#define VEPU_REG_ADDR_REF_LUMA 0x01c +#define VEPU_REG_ADDR_REF_CHROMA 0x020 +#define VEPU_REG_ADDR_REC_LUMA 0x024 +#define VEPU_REG_ADDR_REC_CHROMA 0x028 +#define VEPU_REG_ADDR_IN_LUMA 0x02c +#define VEPU_REG_ADDR_IN_CB 0x030 +#define VEPU_REG_ADDR_IN_CR 0x034 +#define VEPU_REG_ENC_CTRL 0x038 +#define VEPU_REG_ENC_CTRL_NAL_MODE_BIT BIT(29) +#define VEPU_REG_ENC_CTRL_WIDTH(w) ((w) << 19) +#define VEPU_REG_ENC_CTRL_HEIGHT(h) ((h) << 10) +#define VEPU_REG_ENC_CTRL_KEYFRAME_BIT BIT(3) +#define VEPU_REG_ENC_CTRL_ENC_MODE_VP8 (0x1 << 1) +#define VEPU_REG_ENC_CTRL_EN_BIT BIT(0) +#define VEPU_REG_IN_IMG_CTRL 0x03c +#define VEPU_REG_IN_IMG_CTRL_ROW_LEN(x) ((x) << 12) +#define VEPU_REG_IN_IMG_CTRL_OVRFLR_D4(x) ((x) << 10) +#define VEPU_REG_IN_IMG_CTRL_OVRFLB_D4(x) ((x) << 6) +#define VEPU_REG_IN_IMG_CTRL_FMT(x) ((x) << 2) +#define VEPU_REG_ENC_CTRL0 0x040 +#define VEPU_REG_ENC_CTRL1 0x044 +#define VEPU_REG_ENC_CTRL2 0x048 +#define VEPU_REG_ENC_CTRL3 0x04c +#define VEPU_REG_ENC_CTRL5 0x050 +#define VEPU_REG_ENC_CTRL4 0x054 +#define VEPU_REG_STR_HDR_REM_MSB 0x058 +#define VEPU_REG_STR_HDR_REM_LSB 0x05c +#define VEPU_REG_STR_BUF_LIMIT 0x060 +#define VEPU_REG_MAD_CTRL 0x064 +#define VEPU_REG_ADDR_VP8_PROB_CNT 0x068 +#define VEPU_REG_QP_VAL 0x06c +#define VEPU_REG_VP8_QP_VAL(i) (0x06c + ((i) * 0x4)) +#define VEPU_REG_CHECKPOINT(i) (0x070 + ((i) * 0x4)) +#define VEPU_REG_CHKPT_WORD_ERR(i) (0x084 + ((i) * 0x4)) +#define VEPU_REG_VP8_BOOL_ENC 0x08c +#define VEPU_REG_CHKPT_DELTA_QP 0x090 +#define VEPU_REG_VP8_CTRL0 0x090 +#define VEPU_REG_RLC_CTRL 0x094 +#define VEPU_REG_RLC_CTRL_STR_OFFS_SHIFT 23 +#define VEPU_REG_RLC_CTRL_STR_OFFS_MASK (0x3f << 23) +#define VEPU_REG_MB_CTRL 0x098 +#define VEPU_REG_ADDR_CABAC_TBL 0x0cc +#define VEPU_REG_ADDR_MV_OUT 0x0d0 +#define VEPU_REG_RGB_YUV_COEFF(i) (0x0d4 + ((i) * 0x4)) +#define VEPU_REG_RGB_MASK_MSB 0x0dc +#define VEPU_REG_INTRA_AREA_CTRL 0x0e0 +#define VEPU_REG_CIR_INTRA_CTRL 0x0e4 +#define VEPU_REG_INTRA_SLICE_BITMAP(i) (0x0e8 + ((i) * 0x4)) +#define VEPU_REG_ADDR_VP8_DCT_PART(i) (0x0e8 + ((i) * 0x4)) +#define VEPU_REG_FIRST_ROI_AREA 0x0f0 +#define VEPU_REG_SECOND_ROI_AREA 0x0f4 +#define VEPU_REG_MVC_CTRL 0x0f8 +#define VEPU_REG_VP8_INTRA_PENALTY(i) (0x100 + ((i) * 0x4)) +#define VEPU_REG_ADDR_VP8_SEG_MAP 0x11c +#define VEPU_REG_VP8_SEG_QP(i) (0x120 + ((i) * 0x4)) +#define VEPU_REG_DMV_4P_1P_PENALTY(i) (0x180 + ((i) * 0x4)) +#define VEPU_REG_DMV_QPEL_PENALTY(i) (0x200 + ((i) * 0x4)) +#define VEPU_REG_VP8_CTRL1 0x280 +#define VEPU_REG_VP8_BIT_COST_GOLDEN 0x284 +#define VEPU_REG_VP8_LOOP_FLT_DELTA(i) (0x288 + ((i) * 0x4)) + +/* Decoder registers. */ +#define VDPU_REG_INTERRUPT 0x004 +#define VDPU_REG_INTERRUPT_DEC_PIC_INF BIT(24) +#define VDPU_REG_INTERRUPT_DEC_TIMEOUT BIT(18) +#define VDPU_REG_INTERRUPT_DEC_SLICE_INT BIT(17) +#define VDPU_REG_INTERRUPT_DEC_ERROR_INT BIT(16) +#define VDPU_REG_INTERRUPT_DEC_ASO_INT BIT(15) +#define VDPU_REG_INTERRUPT_DEC_BUFFER_INT BIT(14) +#define VDPU_REG_INTERRUPT_DEC_BUS_INT BIT(13) +#define VDPU_REG_INTERRUPT_DEC_RDY_INT BIT(12) +#define VDPU_REG_INTERRUPT_DEC_IRQ BIT(8) +#define VDPU_REG_INTERRUPT_DEC_IRQ_DIS BIT(4) +#define VDPU_REG_INTERRUPT_DEC_E BIT(0) +#define VDPU_REG_CONFIG 0x008 +#define VDPU_REG_CONFIG_DEC_AXI_RD_ID(x) (((x) & 0xff) << 24) +#define VDPU_REG_CONFIG_DEC_TIMEOUT_E BIT(23) +#define VDPU_REG_CONFIG_DEC_STRSWAP32_E BIT(22) +#define VDPU_REG_CONFIG_DEC_STRENDIAN_E BIT(21) +#define VDPU_REG_CONFIG_DEC_INSWAP32_E BIT(20) +#define VDPU_REG_CONFIG_DEC_OUTSWAP32_E BIT(19) +#define VDPU_REG_CONFIG_DEC_DATA_DISC_E BIT(18) +#define VDPU_REG_CONFIG_TILED_MODE_MSB BIT(17) +#define VDPU_REG_CONFIG_DEC_OUT_TILED_E BIT(17) +#define VDPU_REG_CONFIG_DEC_LATENCY(x) (((x) & 0x3f) << 11) +#define VDPU_REG_CONFIG_DEC_CLK_GATE_E BIT(10) +#define VDPU_REG_CONFIG_DEC_IN_ENDIAN BIT(9) +#define VDPU_REG_CONFIG_DEC_OUT_ENDIAN BIT(8) +#define VDPU_REG_CONFIG_PRIORITY_MODE(x) (((x) & 0x7) << 5) +#define VDPU_REG_CONFIG_TILED_MODE_LSB BIT(7) +#define VDPU_REG_CONFIG_DEC_ADV_PRE_DIS BIT(6) +#define VDPU_REG_CONFIG_DEC_SCMD_DIS BIT(5) +#define VDPU_REG_CONFIG_DEC_MAX_BURST(x) (((x) & 0x1f) << 0) +#define VDPU_REG_DEC_CTRL0 0x00c +#define VDPU_REG_DEC_CTRL0_DEC_MODE(x) (((x) & 0xf) << 28) +#define VDPU_REG_DEC_CTRL0_RLC_MODE_E BIT(27) +#define VDPU_REG_DEC_CTRL0_SKIP_MODE BIT(26) +#define VDPU_REG_DEC_CTRL0_DIVX3_E BIT(25) +#define VDPU_REG_DEC_CTRL0_PJPEG_E BIT(24) +#define VDPU_REG_DEC_CTRL0_PIC_INTERLACE_E BIT(23) +#define VDPU_REG_DEC_CTRL0_PIC_FIELDMODE_E BIT(22) +#define VDPU_REG_DEC_CTRL0_PIC_B_E BIT(21) +#define VDPU_REG_DEC_CTRL0_PIC_INTER_E BIT(20) +#define VDPU_REG_DEC_CTRL0_PIC_TOPFIELD_E BIT(19) +#define VDPU_REG_DEC_CTRL0_FWD_INTERLACE_E BIT(18) +#define VDPU_REG_DEC_CTRL0_SORENSON_E BIT(17) +#define VDPU_REG_DEC_CTRL0_REF_TOPFIELD_E BIT(16) +#define VDPU_REG_DEC_CTRL0_DEC_OUT_DIS BIT(15) +#define VDPU_REG_DEC_CTRL0_FILTERING_DIS BIT(14) +#define VDPU_REG_DEC_CTRL0_WEBP_E BIT(13) +#define VDPU_REG_DEC_CTRL0_MVC_E BIT(13) +#define VDPU_REG_DEC_CTRL0_PIC_FIXED_QUANT BIT(13) +#define VDPU_REG_DEC_CTRL0_WRITE_MVS_E BIT(12) +#define VDPU_REG_DEC_CTRL0_REFTOPFIRST_E BIT(11) +#define VDPU_REG_DEC_CTRL0_SEQ_MBAFF_E BIT(10) +#define VDPU_REG_DEC_CTRL0_PICORD_COUNT_E BIT(9) +#define VDPU_REG_DEC_CTRL0_DEC_AHB_HLOCK_E BIT(8) +#define VDPU_REG_DEC_CTRL0_DEC_AXI_WR_ID(x) (((x) & 0xff) << 0) +#define VDPU_REG_DEC_CTRL1 0x010 +#define VDPU_REG_DEC_CTRL1_PIC_MB_WIDTH(x) (((x) & 0x1ff) << 23) +#define VDPU_REG_DEC_CTRL1_MB_WIDTH_OFF(x) (((x) & 0xf) << 19) +#define VDPU_REG_DEC_CTRL1_PIC_MB_HEIGHT_P(x) (((x) & 0xff) << 11) +#define VDPU_REG_DEC_CTRL1_MB_HEIGHT_OFF(x) (((x) & 0xf) << 7) +#define VDPU_REG_DEC_CTRL1_ALT_SCAN_E BIT(6) +#define VDPU_REG_DEC_CTRL1_TOPFIELDFIRST_E BIT(5) +#define VDPU_REG_DEC_CTRL1_REF_FRAMES(x) (((x) & 0x1f) << 0) +#define VDPU_REG_DEC_CTRL1_PIC_MB_W_EXT(x) (((x) & 0x7) << 3) +#define VDPU_REG_DEC_CTRL1_PIC_MB_H_EXT(x) (((x) & 0x7) << 0) +#define VDPU_REG_DEC_CTRL1_PIC_REFER_FLAG BIT(0) +#define VDPU_REG_DEC_CTRL2 0x014 +#define VDPU_REG_DEC_CTRL2_STRM_START_BIT(x) (((x) & 0x3f) << 26) +#define VDPU_REG_DEC_CTRL2_SYNC_MARKER_E BIT(25) +#define VDPU_REG_DEC_CTRL2_TYPE1_QUANT_E BIT(24) +#define VDPU_REG_DEC_CTRL2_CH_QP_OFFSET(x) (((x) & 0x1f) << 19) +#define VDPU_REG_DEC_CTRL2_CH_QP_OFFSET2(x) (((x) & 0x1f) << 14) +#define VDPU_REG_DEC_CTRL2_FIELDPIC_FLAG_E BIT(0) +#define VDPU_REG_DEC_CTRL2_INTRADC_VLC_THR(x) (((x) & 0x7) << 16) +#define VDPU_REG_DEC_CTRL2_VOP_TIME_INCR(x) (((x) & 0xffff) << 0) +#define VDPU_REG_DEC_CTRL2_DQ_PROFILE BIT(24) +#define VDPU_REG_DEC_CTRL2_DQBI_LEVEL BIT(23) +#define VDPU_REG_DEC_CTRL2_RANGE_RED_FRM_E BIT(22) +#define VDPU_REG_DEC_CTRL2_FAST_UVMC_E BIT(20) +#define VDPU_REG_DEC_CTRL2_TRANSDCTAB BIT(17) +#define VDPU_REG_DEC_CTRL2_TRANSACFRM(x) (((x) & 0x3) << 15) +#define VDPU_REG_DEC_CTRL2_TRANSACFRM2(x) (((x) & 0x3) << 13) +#define VDPU_REG_DEC_CTRL2_MB_MODE_TAB(x) (((x) & 0x7) << 10) +#define VDPU_REG_DEC_CTRL2_MVTAB(x) (((x) & 0x7) << 7) +#define VDPU_REG_DEC_CTRL2_CBPTAB(x) (((x) & 0x7) << 4) +#define VDPU_REG_DEC_CTRL2_2MV_BLK_PAT_TAB(x) (((x) & 0x3) << 2) +#define VDPU_REG_DEC_CTRL2_4MV_BLK_PAT_TAB(x) (((x) & 0x3) << 0) +#define VDPU_REG_DEC_CTRL2_QSCALE_TYPE BIT(24) +#define VDPU_REG_DEC_CTRL2_CON_MV_E BIT(4) +#define VDPU_REG_DEC_CTRL2_INTRA_DC_PREC(x) (((x) & 0x3) << 2) +#define VDPU_REG_DEC_CTRL2_INTRA_VLC_TAB BIT(1) +#define VDPU_REG_DEC_CTRL2_FRAME_PRED_DCT BIT(0) +#define VDPU_REG_DEC_CTRL2_JPEG_QTABLES(x) (((x) & 0x3) << 11) +#define VDPU_REG_DEC_CTRL2_JPEG_MODE(x) (((x) & 0x7) << 8) +#define VDPU_REG_DEC_CTRL2_JPEG_FILRIGHT_E BIT(7) +#define VDPU_REG_DEC_CTRL2_JPEG_STREAM_ALL BIT(6) +#define VDPU_REG_DEC_CTRL2_CR_AC_VLCTABLE BIT(5) +#define VDPU_REG_DEC_CTRL2_CB_AC_VLCTABLE BIT(4) +#define VDPU_REG_DEC_CTRL2_CR_DC_VLCTABLE BIT(3) +#define VDPU_REG_DEC_CTRL2_CB_DC_VLCTABLE BIT(2) +#define VDPU_REG_DEC_CTRL2_CR_DC_VLCTABLE3 BIT(1) +#define VDPU_REG_DEC_CTRL2_CB_DC_VLCTABLE3 BIT(0) +#define VDPU_REG_DEC_CTRL2_STRM1_START_BIT(x) (((x) & 0x3f) << 18) +#define VDPU_REG_DEC_CTRL2_HUFFMAN_E BIT(17) +#define VDPU_REG_DEC_CTRL2_MULTISTREAM_E BIT(16) +#define VDPU_REG_DEC_CTRL2_BOOLEAN_VALUE(x) (((x) & 0xff) << 8) +#define VDPU_REG_DEC_CTRL2_BOOLEAN_RANGE(x) (((x) & 0xff) << 0) +#define VDPU_REG_DEC_CTRL2_ALPHA_OFFSET(x) (((x) & 0x1f) << 5) +#define VDPU_REG_DEC_CTRL2_BETA_OFFSET(x) (((x) & 0x1f) << 0) +#define VDPU_REG_DEC_CTRL3 0x018 +#define VDPU_REG_DEC_CTRL3_START_CODE_E BIT(31) +#define VDPU_REG_DEC_CTRL3_INIT_QP(x) (((x) & 0x3f) << 25) +#define VDPU_REG_DEC_CTRL3_CH_8PIX_ILEAV_E BIT(24) +#define VDPU_REG_DEC_CTRL3_STREAM_LEN_EXT(x) (((x) & 0xff) << 24) +#define VDPU_REG_DEC_CTRL3_STREAM_LEN(x) (((x) & 0xffffff) << 0) +#define VDPU_REG_DEC_CTRL4 0x01c +#define VDPU_REG_DEC_CTRL4_CABAC_E BIT(31) +#define VDPU_REG_DEC_CTRL4_BLACKWHITE_E BIT(30) +#define VDPU_REG_DEC_CTRL4_DIR_8X8_INFER_E BIT(29) +#define VDPU_REG_DEC_CTRL4_WEIGHT_PRED_E BIT(28) +#define VDPU_REG_DEC_CTRL4_WEIGHT_BIPR_IDC(x) (((x) & 0x3) << 26) +#define VDPU_REG_DEC_CTRL4_AVS_H264_H_EXT BIT(25) +#define VDPU_REG_DEC_CTRL4_FRAMENUM_LEN(x) (((x) & 0x1f) << 16) +#define VDPU_REG_DEC_CTRL4_FRAMENUM(x) (((x) & 0xffff) << 0) +#define VDPU_REG_DEC_CTRL4_BITPLANE0_E BIT(31) +#define VDPU_REG_DEC_CTRL4_BITPLANE1_E BIT(30) +#define VDPU_REG_DEC_CTRL4_BITPLANE2_E BIT(29) +#define VDPU_REG_DEC_CTRL4_ALT_PQUANT(x) (((x) & 0x1f) << 24) +#define VDPU_REG_DEC_CTRL4_DQ_EDGES(x) (((x) & 0xf) << 20) +#define VDPU_REG_DEC_CTRL4_TTMBF BIT(19) +#define VDPU_REG_DEC_CTRL4_PQINDEX(x) (((x) & 0x1f) << 14) +#define VDPU_REG_DEC_CTRL4_VC1_HEIGHT_EXT BIT(13) +#define VDPU_REG_DEC_CTRL4_BILIN_MC_E BIT(12) +#define VDPU_REG_DEC_CTRL4_UNIQP_E BIT(11) +#define VDPU_REG_DEC_CTRL4_HALFQP_E BIT(10) +#define VDPU_REG_DEC_CTRL4_TTFRM(x) (((x) & 0x3) << 8) +#define VDPU_REG_DEC_CTRL4_2ND_BYTE_EMUL_E BIT(7) +#define VDPU_REG_DEC_CTRL4_DQUANT_E BIT(6) +#define VDPU_REG_DEC_CTRL4_VC1_ADV_E BIT(5) +#define VDPU_REG_DEC_CTRL4_PJPEG_FILDOWN_E BIT(26) +#define VDPU_REG_DEC_CTRL4_PJPEG_WDIV8 BIT(25) +#define VDPU_REG_DEC_CTRL4_PJPEG_HDIV8 BIT(24) +#define VDPU_REG_DEC_CTRL4_PJPEG_AH(x) (((x) & 0xf) << 20) +#define VDPU_REG_DEC_CTRL4_PJPEG_AL(x) (((x) & 0xf) << 16) +#define VDPU_REG_DEC_CTRL4_PJPEG_SS(x) (((x) & 0xff) << 8) +#define VDPU_REG_DEC_CTRL4_PJPEG_SE(x) (((x) & 0xff) << 0) +#define VDPU_REG_DEC_CTRL4_DCT1_START_BIT(x) (((x) & 0x3f) << 26) +#define VDPU_REG_DEC_CTRL4_DCT2_START_BIT(x) (((x) & 0x3f) << 20) +#define VDPU_REG_DEC_CTRL4_CH_MV_RES BIT(13) +#define VDPU_REG_DEC_CTRL4_INIT_DC_MATCH0(x) (((x) & 0x7) << 9) +#define VDPU_REG_DEC_CTRL4_INIT_DC_MATCH1(x) (((x) & 0x7) << 6) +#define VDPU_REG_DEC_CTRL4_VP7_VERSION BIT(5) +#define VDPU_REG_DEC_CTRL5 0x020 +#define VDPU_REG_DEC_CTRL5_CONST_INTRA_E BIT(31) +#define VDPU_REG_DEC_CTRL5_FILT_CTRL_PRES BIT(30) +#define VDPU_REG_DEC_CTRL5_RDPIC_CNT_PRES BIT(29) +#define VDPU_REG_DEC_CTRL5_8X8TRANS_FLAG_E BIT(28) +#define VDPU_REG_DEC_CTRL5_REFPIC_MK_LEN(x) (((x) & 0x7ff) << 17) +#define VDPU_REG_DEC_CTRL5_IDR_PIC_E BIT(16) +#define VDPU_REG_DEC_CTRL5_IDR_PIC_ID(x) (((x) & 0xffff) << 0) +#define VDPU_REG_DEC_CTRL5_MV_SCALEFACTOR(x) (((x) & 0xff) << 24) +#define VDPU_REG_DEC_CTRL5_REF_DIST_FWD(x) (((x) & 0x1f) << 19) +#define VDPU_REG_DEC_CTRL5_REF_DIST_BWD(x) (((x) & 0x1f) << 14) +#define VDPU_REG_DEC_CTRL5_LOOP_FILT_LIMIT(x) (((x) & 0xf) << 14) +#define VDPU_REG_DEC_CTRL5_VARIANCE_TEST_E BIT(13) +#define VDPU_REG_DEC_CTRL5_MV_THRESHOLD(x) (((x) & 0x7) << 10) +#define VDPU_REG_DEC_CTRL5_VAR_THRESHOLD(x) (((x) & 0x3ff) << 0) +#define VDPU_REG_DEC_CTRL5_DIVX_IDCT_E BIT(8) +#define VDPU_REG_DEC_CTRL5_DIVX3_SLICE_SIZE(x) (((x) & 0xff) << 0) +#define VDPU_REG_DEC_CTRL5_PJPEG_REST_FREQ(x) (((x) & 0xffff) << 0) +#define VDPU_REG_DEC_CTRL5_RV_PROFILE(x) (((x) & 0x3) << 30) +#define VDPU_REG_DEC_CTRL5_RV_OSV_QUANT(x) (((x) & 0x3) << 28) +#define VDPU_REG_DEC_CTRL5_RV_FWD_SCALE(x) (((x) & 0x3fff) << 14) +#define VDPU_REG_DEC_CTRL5_RV_BWD_SCALE(x) (((x) & 0x3fff) << 0) +#define VDPU_REG_DEC_CTRL5_INIT_DC_COMP0(x) (((x) & 0xffff) << 16) +#define VDPU_REG_DEC_CTRL5_INIT_DC_COMP1(x) (((x) & 0xffff) << 0) +#define VDPU_REG_DEC_CTRL6 0x024 +#define VDPU_REG_DEC_CTRL6_PPS_ID(x) (((x) & 0xff) << 24) +#define VDPU_REG_DEC_CTRL6_REFIDX1_ACTIVE(x) (((x) & 0x1f) << 19) +#define VDPU_REG_DEC_CTRL6_REFIDX0_ACTIVE(x) (((x) & 0x1f) << 14) +#define VDPU_REG_DEC_CTRL6_POC_LENGTH(x) (((x) & 0xff) << 0) +#define VDPU_REG_DEC_CTRL6_ICOMP0_E BIT(24) +#define VDPU_REG_DEC_CTRL6_ISCALE0(x) (((x) & 0xff) << 16) +#define VDPU_REG_DEC_CTRL6_ISHIFT0(x) (((x) & 0xffff) << 0) +#define VDPU_REG_DEC_CTRL6_STREAM1_LEN(x) (((x) & 0xffffff) << 0) +#define VDPU_REG_DEC_CTRL6_PIC_SLICE_AM(x) (((x) & 0x1fff) << 0) +#define VDPU_REG_DEC_CTRL6_COEFFS_PART_AM(x) (((x) & 0xf) << 24) +#define VDPU_REG_FWD_PIC(i) (0x028 + ((i) * 0x4)) +#define VDPU_REG_FWD_PIC_PINIT_RLIST_F5(x) (((x) & 0x1f) << 25) +#define VDPU_REG_FWD_PIC_PINIT_RLIST_F4(x) (((x) & 0x1f) << 20) +#define VDPU_REG_FWD_PIC_PINIT_RLIST_F3(x) (((x) & 0x1f) << 15) +#define VDPU_REG_FWD_PIC_PINIT_RLIST_F2(x) (((x) & 0x1f) << 10) +#define VDPU_REG_FWD_PIC_PINIT_RLIST_F1(x) (((x) & 0x1f) << 5) +#define VDPU_REG_FWD_PIC_PINIT_RLIST_F0(x) (((x) & 0x1f) << 0) +#define VDPU_REG_FWD_PIC1_ICOMP1_E BIT(24) +#define VDPU_REG_FWD_PIC1_ISCALE1(x) (((x) & 0xff) << 16) +#define VDPU_REG_FWD_PIC1_ISHIFT1(x) (((x) & 0xffff) << 0) +#define VDPU_REG_FWD_PIC1_SEGMENT_BASE(x) ((x) << 0) +#define VDPU_REG_FWD_PIC1_SEGMENT_UPD_E BIT(1) +#define VDPU_REG_FWD_PIC1_SEGMENT_E BIT(0) +#define VDPU_REG_DEC_CTRL7 0x02c +#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F15(x) (((x) & 0x1f) << 25) +#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F14(x) (((x) & 0x1f) << 20) +#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F13(x) (((x) & 0x1f) << 15) +#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F12(x) (((x) & 0x1f) << 10) +#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F11(x) (((x) & 0x1f) << 5) +#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F10(x) (((x) & 0x1f) << 0) +#define VDPU_REG_DEC_CTRL7_ICOMP2_E BIT(24) +#define VDPU_REG_DEC_CTRL7_ISCALE2(x) (((x) & 0xff) << 16) +#define VDPU_REG_DEC_CTRL7_ISHIFT2(x) (((x) & 0xffff) << 0) +#define VDPU_REG_DEC_CTRL7_DCT3_START_BIT(x) (((x) & 0x3f) << 24) +#define VDPU_REG_DEC_CTRL7_DCT4_START_BIT(x) (((x) & 0x3f) << 18) +#define VDPU_REG_DEC_CTRL7_DCT5_START_BIT(x) (((x) & 0x3f) << 12) +#define VDPU_REG_DEC_CTRL7_DCT6_START_BIT(x) (((x) & 0x3f) << 6) +#define VDPU_REG_DEC_CTRL7_DCT7_START_BIT(x) (((x) & 0x3f) << 0) +#define VDPU_REG_ADDR_STR 0x030 +#define VDPU_REG_ADDR_DST 0x034 +#define VDPU_REG_ADDR_REF(i) (0x038 + ((i) * 0x4)) +#define VDPU_REG_ADDR_REF_FIELD_E BIT(1) +#define VDPU_REG_ADDR_REF_TOPC_E BIT(0) +#define VDPU_REG_REF_PIC(i) (0x078 + ((i) * 0x4)) +#define VDPU_REG_REF_PIC_FILT_TYPE_E BIT(31) +#define VDPU_REG_REF_PIC_FILT_SHARPNESS(x) (((x) & 0x7) << 28) +#define VDPU_REG_REF_PIC_MB_ADJ_0(x) (((x) & 0x7f) << 21) +#define VDPU_REG_REF_PIC_MB_ADJ_1(x) (((x) & 0x7f) << 14) +#define VDPU_REG_REF_PIC_MB_ADJ_2(x) (((x) & 0x7f) << 7) +#define VDPU_REG_REF_PIC_MB_ADJ_3(x) (((x) & 0x7f) << 0) +#define VDPU_REG_REF_PIC_REFER1_NBR(x) (((x) & 0xffff) << 16) +#define VDPU_REG_REF_PIC_REFER0_NBR(x) (((x) & 0xffff) << 0) +#define VDPU_REG_REF_PIC_LF_LEVEL_0(x) (((x) & 0x3f) << 18) +#define VDPU_REG_REF_PIC_LF_LEVEL_1(x) (((x) & 0x3f) << 12) +#define VDPU_REG_REF_PIC_LF_LEVEL_2(x) (((x) & 0x3f) << 6) +#define VDPU_REG_REF_PIC_LF_LEVEL_3(x) (((x) & 0x3f) << 0) +#define VDPU_REG_REF_PIC_QUANT_DELTA_0(x) (((x) & 0x1f) << 27) +#define VDPU_REG_REF_PIC_QUANT_DELTA_1(x) (((x) & 0x1f) << 22) +#define VDPU_REG_REF_PIC_QUANT_0(x) (((x) & 0x7ff) << 11) +#define VDPU_REG_REF_PIC_QUANT_1(x) (((x) & 0x7ff) << 0) +#define VDPU_REG_LT_REF 0x098 +#define VDPU_REG_VALID_REF 0x09c +#define VDPU_REG_ADDR_QTABLE 0x0a0 +#define VDPU_REG_ADDR_DIR_MV 0x0a4 +#define VDPU_REG_BD_REF_PIC(i) (0x0a8 + ((i) * 0x4)) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B2(x) (((x) & 0x1f) << 25) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F2(x) (((x) & 0x1f) << 20) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B1(x) (((x) & 0x1f) << 15) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F1(x) (((x) & 0x1f) << 10) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B0(x) (((x) & 0x1f) << 5) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F0(x) (((x) & 0x1f) << 0) +#define VDPU_REG_BD_REF_PIC_PRED_TAP_2_M1(x) (((x) & 0x3) << 10) +#define VDPU_REG_BD_REF_PIC_PRED_TAP_2_4(x) (((x) & 0x3) << 8) +#define VDPU_REG_BD_REF_PIC_PRED_TAP_4_M1(x) (((x) & 0x3) << 6) +#define VDPU_REG_BD_REF_PIC_PRED_TAP_4_4(x) (((x) & 0x3) << 4) +#define VDPU_REG_BD_REF_PIC_PRED_TAP_6_M1(x) (((x) & 0x3) << 2) +#define VDPU_REG_BD_REF_PIC_PRED_TAP_6_4(x) (((x) & 0x3) << 0) +#define VDPU_REG_BD_REF_PIC_QUANT_DELTA_2(x) (((x) & 0x1f) << 27) +#define VDPU_REG_BD_REF_PIC_QUANT_DELTA_3(x) (((x) & 0x1f) << 22) +#define VDPU_REG_BD_REF_PIC_QUANT_2(x) (((x) & 0x7ff) << 11) +#define VDPU_REG_BD_REF_PIC_QUANT_3(x) (((x) & 0x7ff) << 0) +#define VDPU_REG_BD_P_REF_PIC 0x0bc +#define VDPU_REG_BD_P_REF_PIC_QUANT_DELTA_4(x) (((x) & 0x1f) << 27) +#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F3(x) (((x) & 0x1f) << 25) +#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F2(x) (((x) & 0x1f) << 20) +#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F1(x) (((x) & 0x1f) << 15) +#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F0(x) (((x) & 0x1f) << 10) +#define VDPU_REG_BD_P_REF_PIC_BINIT_RLIST_B15(x) (((x) & 0x1f) << 5) +#define VDPU_REG_BD_P_REF_PIC_BINIT_RLIST_F15(x) (((x) & 0x1f) << 0) +#define VDPU_REG_ERR_CONC 0x0c0 +#define VDPU_REG_ERR_CONC_STARTMB_X(x) (((x) & 0x1ff) << 23) +#define VDPU_REG_ERR_CONC_STARTMB_Y(x) (((x) & 0xff) << 15) +#define VDPU_REG_PRED_FLT 0x0c4 +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_0_0(x) (((x) & 0x3ff) << 22) +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_0_1(x) (((x) & 0x3ff) << 12) +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_0_2(x) (((x) & 0x3ff) << 2) +#define VDPU_REG_REF_BUF_CTRL 0x0cc +#define VDPU_REG_REF_BUF_CTRL_REFBU_E BIT(31) +#define VDPU_REG_REF_BUF_CTRL_REFBU_THR(x) (((x) & 0xfff) << 19) +#define VDPU_REG_REF_BUF_CTRL_REFBU_PICID(x) (((x) & 0x1f) << 14) +#define VDPU_REG_REF_BUF_CTRL_REFBU_EVAL_E BIT(13) +#define VDPU_REG_REF_BUF_CTRL_REFBU_FPARMOD_E BIT(12) +#define VDPU_REG_REF_BUF_CTRL_REFBU_Y_OFFSET(x) (((x) & 0x1ff) << 0) +#define VDPU_REG_REF_BUF_CTRL2 0x0dc +#define VDPU_REG_REF_BUF_CTRL2_REFBU2_BUF_E BIT(31) +#define VDPU_REG_REF_BUF_CTRL2_REFBU2_THR(x) (((x) & 0xfff) << 19) +#define VDPU_REG_REF_BUF_CTRL2_REFBU2_PICID(x) (((x) & 0x1f) << 14) +#define VDPU_REG_REF_BUF_CTRL2_APF_THRESHOLD(x) (((x) & 0x3fff) << 0) + +#endif /* RK3288_VPU_REGS_H_ */