Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1377865 > unrolled thread
| Started by | Tiffany Lin <tiffany.lin@mediatek.com> |
|---|---|
| First post | 2016-04-13 14:10 +0200 |
| Last post | 2016-04-14 08:20 +0200 |
| Articles | 8 — 4 participants |
Back to article view | Back to linux.kernel
[PATCH 0/7] Add MT8173 Video Decoder Driver Tiffany Lin <tiffany.lin@mediatek.com> - 2016-04-13 14:10 +0200
[PATCH 5/7] [media] vcodec: mediatek: Add Mediatek VP8 Video Decoder Driver Tiffany Lin <tiffany.lin@mediatek.com> - 2016-04-13 14:10 +0200
[PATCH 2/7] dt-bindings: Add a binding for Mediatek Video Decoder Tiffany Lin <tiffany.lin@mediatek.com> - 2016-04-13 14:10 +0200
[PATCH 4/7] [media] vcodec: mediatek: Add Mediatek H264 Video Decoder Driver Tiffany Lin <tiffany.lin@mediatek.com> - 2016-04-13 14:10 +0200
Re: [PATCH 2/7] dt-bindings: Add a binding for Mediatek Video Decoder Rob Herring <robh@kernel.org> - 2016-04-14 18:20 +0200
[PATCH 1/7] [media]: v4l: add Mediatek MT21 video block format Tiffany Lin <tiffany.lin@mediatek.com> - 2016-04-13 14:10 +0200
Re: [PATCH 1/7] [media]: v4l: add Mediatek MT21 video block format Nicolas Dufresne <nicolas.dufresne@gmail.com> - 2016-04-13 16:30 +0200
Re: [PATCH 1/7] [media]: v4l: add Mediatek MT21 video block format tiffany lin <tiffany.lin@mediatek.com> - 2016-04-14 08:20 +0200
| From | Tiffany Lin <tiffany.lin@mediatek.com> |
|---|---|
| Date | 2016-04-13 14:10 +0200 |
| Subject | [PATCH 0/7] Add MT8173 Video Decoder Driver |
| Message-ID | <rnrMm-116-3@gated-at.bofh.it> |
==============
Introduction
==============
The purpose of this series is to add the driver for video codec hw embedded in the Mediatek's MT8173 SoCs.
Mediatek Video Codec is able to handle video decoding of in a range of formats.
This patch series add Mediatek block format V4L2_PIX_FMT_MT21, the decoder driver will decoded bitstream to
V4L2_PIX_FMT_MT21 format.
This patch series rely on MTK VPU driver in patch series "Add MT8173 Video Encoder Driver and VPU Driver"[1]
and patch "CHROMIUM: v4l: Add V4L2_PIX_FMT_VP9 definition"[2] for VP9 support.
Mediatek Video Decoder driver rely on VPU driver to load, communicate with VPU.
Internally the driver uses videobuf2 framework and MTK IOMMU and MTK SMI both have been merged in v4.6-rc1.
[1]https://patchwork.linuxtv.org/patch/33734/
[2]https://chromium-review.googlesource.com/#/c/245241/
==================
Device interface
==================
In principle the driver bases on v4l2 memory-to-memory framework:
it provides a single video node and each opened file handle gets its own private context with separate
buffer queues. Each context consist of 2 buffer queues: OUTPUT (for source buffers, i.e. bitstream)
and CAPTURE (for destination buffers, i.e. decoded video frames).
OUTPUT and CAPTURE buffer could be MMAP or DMABUF memory type.
VIDIOC_G_CTRL and VIDIOC_G_EXT_CTRLS return V4L2_CID_MIN_BUFFERS_FOR_CAPTURE only when dirver in MTK_STATE_HEADER
state, or it will return EAGAIN.
Driver do not support subscribe event for control 'User Controls' for now.
And it default support export DMABUF for other display drivers.
v4l2-compliance test output:
localhost Encode # ./v4l2-compliance -d /dev/video0
Driver Info:
Driver name : mtk-vcodec-dec
Card type : platform:mt8173
Bus info : platform:mt8173
Driver version: 4.4.0
Capabilities : 0x84204000
Video Memory-to-Memory Multiplanar
Streaming
Extended Pix Format
Device Capabilities
Device Caps : 0x04204000
Video Memory-to-Memory Multiplanar
Streaming
Extended Pix Format
Compliance test for device /dev/video0 (not using libv4l2):
Required ioctls:
test VIDIOC_QUERYCAP: OK
Allow for multiple opens:
test second video open: OK
test VIDIOC_QUERYCAP: OK
test VIDIOC_G/S_PRIORITY: OK
Debug ioctls:
test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
test VIDIOC_LOG_STATUS: OK (Not Supported)
Input ioctls:
test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
test VIDIOC_ENUMAUDIO: OK (Not Supported)
test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
test VIDIOC_G/S_AUDIO: OK (Not Supported)
Inputs: 0 Audio Inputs: 0 Tuners: 0
Output ioctls:
test VIDIOC_G/S_MODULATOR: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_ENUMAUDOUT: OK (Not Supported)
test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
test VIDIOC_G/S_AUDOUT: OK (Not Supported)
Outputs: 0 Audio Outputs: 0 Modulators: 0
Input/Output configuration ioctls:
test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
test VIDIOC_G/S_EDID: OK (Not Supported)
Control ioctls:
test VIDIOC_QUERYCTRL/MENU: OK
fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-controls.cpp(357): g_ctrl returned an error (11)
test VIDIOC_G/S_CTRL: FAIL
fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-controls.cpp(579): g_ext_ctrls returned an error (11)
test VIDIOC_G/S/TRY_EXT_CTRLS: FAIL
fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-controls.cpp(721): subscribe event for control 'User Controls' failed
test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: FAIL
test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
Standard Controls: 2 Private Controls: 0
Format ioctls:
test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
test VIDIOC_G/S_PARM: OK (Not Supported)
test VIDIOC_G_FBUF: OK (Not Supported)
fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-formats.cpp(405): expected EINVAL, but got 11 when getting format for buftype 9
test VIDIOC_G_FMT: FAIL
test VIDIOC_TRY_FMT: OK (Not Supported)
test VIDIOC_S_FMT: OK (Not Supported)
test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
Codec ioctls:
test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
test VIDIOC_G_ENC_INDEX: OK (Not Supported)
test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)
Buffer ioctls:
test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
fail: ../../../v4l-utils-1.6.0/utils/v4l2-compliance/v4l2-test-buffers.cpp(500): q.has_expbuf(node)
test VIDIOC_EXPBUF: FAIL
Total: 38, Succeeded: 33, Failed: 5, Warnings: 0
Daniel Kurtz (1):
[media]: v4l: add Mediatek MT21 video block format
Tiffany Lin (6):
dt-bindings: Add a binding for Mediatek Video Decoder
[Media] vcodec: mediatek: Add Mediatek V4L2 Video Decoder Driver
[media] vcodec: mediatek: Add Mediatek H264 Video Decoder Driver
[media] vcodec: mediatek: Add Mediatek VP8 Video Decoder Driver
[media] vcodec: mediatek: Add Mediatek VP9 Video Decoder Driver
arm64: dts: mediatek: Add Video Encoder for MT8173
.../devicetree/bindings/media/mediatek-vcodec.txt | 50 +-
arch/arm64/boot/dts/mediatek/mt8173.dtsi | 38 +
drivers/media/platform/mtk-vcodec/Makefile | 15 +-
drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c | 1429 ++++++++++++++++++++
drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h | 81 ++
.../media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 469 +++++++
.../media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c | 153 +++
.../media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h | 28 +
drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h | 98 +-
.../media/platform/mtk-vcodec/vdec/vdec_h264_if.c | 487 +++++++
.../media/platform/mtk-vcodec/vdec/vdec_vp8_if.c | 630 +++++++++
.../media/platform/mtk-vcodec/vdec/vdec_vp9_if.c | 1108 +++++++++++++++
drivers/media/platform/mtk-vcodec/vdec_drv_base.h | 56 +
drivers/media/platform/mtk-vcodec/vdec_drv_if.c | 123 ++
drivers/media/platform/mtk-vcodec/vdec_drv_if.h | 93 ++
drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h | 100 ++
drivers/media/platform/mtk-vcodec/vdec_vpu_if.c | 164 +++
drivers/media/platform/mtk-vcodec/vdec_vpu_if.h | 60 +
include/uapi/drm/drm_fourcc.h | 1 +
include/uapi/linux/videodev2.h | 2 +
20 files changed, 5160 insertions(+), 25 deletions(-)
create mode 100644 drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
create mode 100644 drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h
create mode 100644 drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
create mode 100644 drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
create mode 100644 drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h
create mode 100644 drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c
create mode 100644 drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c
create mode 100644 drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c
create mode 100644 drivers/media/platform/mtk-vcodec/vdec_drv_base.h
create mode 100644 drivers/media/platform/mtk-vcodec/vdec_drv_if.c
create mode 100644 drivers/media/platform/mtk-vcodec/vdec_drv_if.h
create mode 100644 drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h
create mode 100644 drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
create mode 100644 drivers/media/platform/mtk-vcodec/vdec_vpu_if.h
--
1.7.9.5
[toc] | [next] | [standalone]
| From | Tiffany Lin <tiffany.lin@mediatek.com> |
|---|---|
| Date | 2016-04-13 14:10 +0200 |
| Subject | [PATCH 5/7] [media] vcodec: mediatek: Add Mediatek VP8 Video Decoder Driver |
| Message-ID | <rnrMm-116-13@gated-at.bofh.it> |
| In reply to | #1377865 |
Add vp8 decoder driver for MT8173
Signed-off-by: PC Chen <pc.chen@mediatek.com>
Signed-off-by: Tiffany Lin <tiffany.lin@mediatek.com>
---
drivers/media/platform/mtk-vcodec/Makefile | 1 +
.../media/platform/mtk-vcodec/vdec/vdec_vp8_if.c | 630 ++++++++++++++++++++
drivers/media/platform/mtk-vcodec/vdec_drv_if.c | 3 +
3 files changed, 634 insertions(+)
create mode 100644 drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c
diff --git a/drivers/media/platform/mtk-vcodec/Makefile b/drivers/media/platform/mtk-vcodec/Makefile
index 58243ed..7743c81 100644
--- a/drivers/media/platform/mtk-vcodec/Makefile
+++ b/drivers/media/platform/mtk-vcodec/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-dec.o \
mtk-vcodec-common.o
mtk-vcodec-dec-y := vdec/vdec_h264_if.o \
+ vdec/vdec_vp8_if.o \
mtk_vcodec_dec_drv.o \
vdec_drv_if.o \
vdec_vpu_if.o \
diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c
new file mode 100644
index 0000000..9b6ef9d
--- /dev/null
+++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c
@@ -0,0 +1,630 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Jungchang Tsao <jungchang.tsao@mediatek.com>
+ * PC Chen <pc.chen@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "mtk_vcodec_intr.h"
+#include "vdec_vpu_if.h"
+#include "vdec_drv_base.h"
+
+#define VP8_VP_WRAP_SZ (45 * 4096)
+#define VP8_SEGID_DRAM_ADDR 0x3c
+#define VP8_HW_DATA_ADDR 0x93C
+#define VP8_HW_DATA_VALUE 0x940
+#define VP8_BSASET 0x100
+#define VP8_BSDSET 0x104
+#define VP8_DEC_DATA_PROCESSING_LOOP 96
+
+#define VP8_RW_CKEN_SET 0x0
+#define VP8_RW_DCM_CON 0x18
+#define VP8_WO_VLD_SRST 0x108
+#define VP8_RW_MISC_SYS_SEL 0x84
+#define VP8_RW_MISC_SPEC_CON 0xC8
+#define VP8_WO_VLD_SRST 0x108
+#define VP8_RW_VP8_CTRL 0xA4
+#define VP8_RW_MISC_DCM_CON 0xEC
+#define VP8_RW_MISC_SRST 0xF4
+#define VP8_RW_MISC_FUNC_CON 0xCC
+
+#define VP8_MAX_FRM_BUFF_NUM 5
+#define VP8_HW_DATA_SZ 272
+#define VP8_DEC_DATA_SZ 300
+
+/**
+ * struct vdec_vp8_dec_info - decode misc information
+ * @vp_wrapper_dma : wrapper buffer dma
+ * @prev_y_dma : previous decoded frame buffer Y plane address
+ * @cur_y_fb_dma : current plane Y frame buffer dma
+ * @cur_c_fb_dma : current plane C frame buffer dma
+ * @bs_dma : bitstream dma
+ * @bs_sz : current plane C frame buffer dma
+ * @resolution_changed: resolution change flag
+ * @show_frame : display this frame or not
+ * @wait_key_frame : wait key frame coming
+ */
+struct vdec_vp8_dec_info {
+ uint64_t vp_wrapper_dma;
+ uint64_t prev_y_dma;
+ uint64_t cur_y_fb_dma;
+ uint64_t cur_c_fb_dma;
+ uint64_t bs_dma;
+ uint32_t bs_sz;
+ uint32_t resolution_changed;
+ uint32_t show_frame;
+ uint32_t wait_key_frame;
+};
+
+/**
+ * struct vdec_vp8_vsi - VPU shared information
+ * @dec : decoding information
+ * @pic : picture information
+ * @dec_data : decode data
+ * @segid_wrapper_work : seg id wrapper buffer
+ * @load_data : flag to indicate reload decode data
+ */
+struct vdec_vp8_vsi {
+ struct vdec_vp8_dec_info dec;
+ struct vdec_pic_info pic;
+ unsigned int dec_data[VP8_DEC_DATA_SZ];
+ unsigned int segid_wrapper_work[VP8_HW_DATA_SZ][4];
+ unsigned int load_data;
+};
+
+/**
+ * struct vdec_vp8_hw_reg_base - HW register base
+ * @sys : base address for sys
+ * @misc : base address for misc
+ * @ld : base address for ld
+ * @top : base address for top
+ * @cm : base address for cm
+ * @hwd : base address for hwd
+ * @hwb : base address for hwb
+*/
+struct vdec_vp8_hw_reg_base {
+ void __iomem *sys;
+ void __iomem *misc;
+ void __iomem *ld;
+ void __iomem *top;
+ void __iomem *cm;
+ void __iomem *hwd;
+ void __iomem *hwb;
+};
+
+/**
+ * struct vdec_vp8_vpu_inst - VPU instance for VP8 decode
+ * @wq_hd : Wait queue to wait VPU message ack
+ * @signaled : 1 - Host has received ack message from VPU, 0 - not recevie
+ * @failure : VPU execution result status
+ * @inst_addr : VPU decoder instance addr
+ */
+struct vdec_vp8_vpu_inst {
+ wait_queue_head_t wq_hd;
+ int signaled;
+ int failure;
+ unsigned int inst_addr;
+};
+
+/* frame buffer (fb) list
+ * [dec_fb_list] - decode fb are initialized to 0 and populated in
+ * [dec_use_list] - fb is set after decode and is moved to this list
+ * [dec_free_list] - fb is not needed for reference will be moved from
+ * [dec_use_list] to [dec_free_list] and
+ * once user remove fb from [dec_free_list],
+ * it is circulated back to [dec_fb_list]
+ * [disp_fb_list] - display fb are initialized to 0 and populated in
+ * [disp_rdy_list] - fb is set after decode and is moved to this list
+ * once user remove fb from [disp_rdy_list] it is
+ * circulated back to [disp_fb_list]
+ */
+
+/**
+ * struct vdec_vp8_inst - VP8 decoder instance
+ * @cur_fb : current frame buffer
+ * @dec_fb : decode frame buffer node
+ * @disp_fb : display frame buffer node
+ * @dec_fb_list : list to store decode frame buffer
+ * @dec_use_list : list to store frame buffer in use
+ * @dec_free_list : list to store free frame buffer
+ * @disp_fb_list : list to store display frame buffer
+ * @disp_rdy_list : list to store display ready frame buffer
+ * @vp_wrapper_buf : decoder working buffer
+ * @reg_base : hw register base address
+ * @frm_cnt : decode frame count
+ * @ctx : V4L2 context
+ * @dev : platform device
+ * @vpu : VPU instance for decoder
+ * @vsi : VPU share information
+ */
+struct vdec_vp8_inst {
+ struct vdec_fb *cur_fb;
+ struct vdec_fb_node dec_fb[VP8_MAX_FRM_BUFF_NUM];
+ struct vdec_fb_node disp_fb[VP8_MAX_FRM_BUFF_NUM];
+ struct list_head dec_fb_list;
+ struct list_head dec_use_list;
+ struct list_head dec_free_list;
+ struct list_head disp_fb_list;
+ struct list_head disp_rdy_list;
+ struct mtk_vcodec_mem vp_wrapper_buf;
+ struct vdec_vp8_hw_reg_base reg_base;
+ unsigned int frm_cnt;
+ struct mtk_vcodec_ctx *ctx;
+ struct vdec_vpu_inst vpu;
+ struct vdec_vp8_vsi *vsi;
+};
+
+static void get_hw_reg_base(struct vdec_vp8_inst *inst)
+{
+ inst->reg_base.top = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_TOP);
+ inst->reg_base.cm = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_CM);
+ inst->reg_base.hwd = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_HWD);
+ inst->reg_base.sys = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_SYS);
+ inst->reg_base.misc = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_MISC);
+ inst->reg_base.ld = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_LD);
+ inst->reg_base.hwb = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_HWB);
+}
+
+static void write_hw_data(struct vdec_vp8_inst *inst)
+{
+ int i, j;
+ unsigned int seg_id_addr;
+ unsigned int val;
+ void __iomem *cm = inst->reg_base.cm;
+
+ seg_id_addr = readl(inst->reg_base.top + VP8_SEGID_DRAM_ADDR) >> 4;
+
+ for (i = 0; i < VP8_HW_DATA_SZ; i++) {
+ for (j = 3; j >= 0; j--) {
+ val = (1 << 16) + ((seg_id_addr + i) << 2) + j;
+ writel(val, cm + VP8_HW_DATA_ADDR);
+
+ val = inst->vsi->segid_wrapper_work[i][j];
+ writel(val, cm + VP8_HW_DATA_VALUE);
+ }
+ }
+}
+
+static void read_hw_data(struct vdec_vp8_inst *inst)
+{
+ int i, j;
+ unsigned int seg_id_addr;
+ unsigned int val;
+ void __iomem *cm = inst->reg_base.cm;
+
+ seg_id_addr = readl(inst->reg_base.top + VP8_SEGID_DRAM_ADDR) >> 4;
+
+ for (i = 0; i < VP8_HW_DATA_SZ; i++) {
+ for (j = 3; j >= 0; j--) {
+ val = ((seg_id_addr + i) << 2) + j;
+ writel(val, cm + VP8_HW_DATA_ADDR);
+
+ val = readl(cm + VP8_HW_DATA_VALUE);
+ inst->vsi->segid_wrapper_work[i][j] = val;
+ }
+ }
+}
+
+static void enable_hw_rw_dec_data(struct vdec_vp8_inst *inst)
+{
+ unsigned int reg_val = 0;
+ void __iomem *sys = inst->reg_base.sys;
+ void __iomem *misc = inst->reg_base.misc;
+ void __iomem *ld = inst->reg_base.ld;
+ void __iomem *hwb = inst->reg_base.hwb;
+ void __iomem *hwd = inst->reg_base.hwd;
+
+ writel(0x1, sys + VP8_RW_CKEN_SET);
+ writel(0x101, ld + VP8_WO_VLD_SRST);
+ writel(0x101, hwb + VP8_WO_VLD_SRST);
+
+ writel(1, sys);
+ reg_val = readl(misc + VP8_RW_MISC_SRST);
+ writel((reg_val & 0xFFFFFFFE), misc + VP8_RW_MISC_SRST);
+
+ writel(0x1, misc + VP8_RW_MISC_SYS_SEL);
+ writel(0x17F, misc + VP8_RW_MISC_SPEC_CON);
+ writel(0x71201100, misc + VP8_RW_MISC_FUNC_CON);
+ writel(0x0, ld + VP8_WO_VLD_SRST);
+ writel(0x0, hwb + VP8_WO_VLD_SRST);
+ writel(0x1, sys + VP8_RW_DCM_CON);
+ writel(0x1, misc + VP8_RW_MISC_DCM_CON);
+ writel(0x1, hwd + VP8_RW_VP8_CTRL);
+}
+
+static void store_dec_data(struct vdec_vp8_inst *inst)
+{
+ int i, j;
+ unsigned int addr = 0, val = 0;
+ void __iomem *hwd = inst->reg_base.hwd;
+ unsigned int *p = &inst->vsi->dec_data[2];
+
+ for (i = 0; i < VP8_DEC_DATA_PROCESSING_LOOP; i++) {
+ writel(addr, hwd + VP8_BSASET);
+ for (j = 0; j < 3 ; j++) {
+ val = *p++;
+ writel(val, hwd + VP8_BSDSET);
+ }
+ addr += 4;
+ }
+}
+
+static void load_dec_data(struct vdec_vp8_inst *inst)
+{
+ int i;
+ unsigned int addr = 0;
+ unsigned int *p = &inst->vsi->dec_data[2];
+ void __iomem *hwd = inst->reg_base.hwd;
+
+ for (i = 0; i < VP8_DEC_DATA_PROCESSING_LOOP; i++) {
+ writel(addr, hwd + VP8_BSASET);
+ *p++ = readl(hwd + VP8_BSDSET);
+ *p++ = readl(hwd + VP8_BSDSET);
+ *p++ = readl(hwd + VP8_BSDSET) & 0xFFFFFF;
+ addr += 4;
+ }
+}
+
+static void get_pic_info(struct vdec_vp8_inst *inst, struct vdec_pic_info *pic)
+{
+ pic->pic_w = inst->vsi->pic.pic_w;
+ pic->pic_h = inst->vsi->pic.pic_h;
+ pic->buf_w = inst->vsi->pic.buf_w;
+ pic->buf_h = inst->vsi->pic.buf_h;
+ pic->y_bs_sz = inst->vsi->pic.y_bs_sz;
+ pic->c_bs_sz = inst->vsi->pic.c_bs_sz;
+ pic->y_len_sz = inst->vsi->pic.y_len_sz;
+ pic->c_len_sz = inst->vsi->pic.c_len_sz;
+
+ mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)",
+ pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h);
+ mtk_vcodec_debug(inst, "Y(%d, %d), C(%d, %d)", pic->y_bs_sz,
+ pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz);
+}
+
+static int vp8_dec_finish(struct vdec_vp8_inst *inst)
+{
+ struct vdec_fb_node *node;
+ uint64_t prev_y_dma = inst->vsi->dec.prev_y_dma;
+
+ mtk_vcodec_debug(inst, "prev fb base dma=%llx", prev_y_dma);
+
+ /* put last decode ok frame to dec_free_list */
+ if (0 != prev_y_dma) {
+ list_for_each_entry(node, &inst->dec_use_list, list) {
+ struct vdec_fb *fb = (struct vdec_fb *)node->fb;
+
+ if (prev_y_dma == (unsigned long)fb->base_y.dma_addr) {
+ list_move_tail(&node->list,
+ &inst->dec_free_list);
+ break;
+ }
+ }
+ }
+
+ /* dec_fb_list -> dec_use_list */
+ node = list_first_entry(&inst->dec_fb_list, struct vdec_fb_node, list);
+ node->fb = inst->cur_fb;
+ list_move_tail(&node->list, &inst->dec_use_list);
+
+ /* disp_fb_list -> disp_rdy_list */
+ if (inst->vsi->dec.show_frame) {
+ node = list_first_entry(&inst->disp_fb_list,
+ struct vdec_fb_node, list);
+ node->fb = inst->cur_fb;
+ list_move_tail(&node->list, &inst->disp_rdy_list);
+ }
+
+ return 0;
+}
+
+static void move_fb_list_use_to_free(struct vdec_vp8_inst *inst)
+{
+ struct vdec_fb_node *node, *tmp;
+
+ list_for_each_entry_safe(node, tmp, &inst->dec_use_list, list)
+ list_move_tail(&node->list, &inst->dec_free_list);
+}
+
+static void init_list(struct vdec_vp8_inst *inst)
+{
+ int i;
+
+ INIT_LIST_HEAD(&inst->dec_fb_list);
+ INIT_LIST_HEAD(&inst->dec_use_list);
+ INIT_LIST_HEAD(&inst->dec_free_list);
+ INIT_LIST_HEAD(&inst->disp_fb_list);
+ INIT_LIST_HEAD(&inst->disp_rdy_list);
+
+ for (i = 0; i < VP8_MAX_FRM_BUFF_NUM; i++) {
+ INIT_LIST_HEAD(&inst->dec_fb[i].list);
+ inst->dec_fb[i].fb = NULL;
+ list_add_tail(&inst->dec_fb[i].list, &inst->dec_fb_list);
+
+ INIT_LIST_HEAD(&inst->disp_fb[i].list);
+ inst->disp_fb[i].fb = NULL;
+ list_add_tail(&inst->disp_fb[i].list, &inst->disp_fb_list);
+ }
+}
+
+static void add_fb_to_free_list(struct vdec_vp8_inst *inst, void *fb)
+{
+ struct vdec_fb_node *node;
+
+ if (fb) {
+ node = list_first_entry(&inst->dec_fb_list,
+ struct vdec_fb_node, list);
+ node->fb = fb;
+ list_move_tail(&node->list, &inst->dec_free_list);
+ }
+}
+
+static int alloc_all_working_buf(struct vdec_vp8_inst *inst)
+{
+ int err;
+ struct mtk_vcodec_mem *mem = &inst->vp_wrapper_buf;
+
+ mem->size = VP8_VP_WRAP_SZ;
+ err = mtk_vcodec_mem_alloc(inst->ctx, mem);
+ if (err) {
+ mtk_vcodec_err(inst, "Cannot allocate vp wrapper buffer");
+ return -ENOMEM;
+ }
+
+ inst->vsi->dec.vp_wrapper_dma = (u64)mem->dma_addr;
+ return 0;
+}
+
+static void free_all_working_buf(struct vdec_vp8_inst *inst)
+{
+ struct mtk_vcodec_mem *mem = &inst->vp_wrapper_buf;
+
+ if (mem->va)
+ mtk_vcodec_mem_free(inst->ctx, mem);
+
+ inst->vsi->dec.vp_wrapper_dma = 0;
+}
+
+static int vdec_vp8_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec)
+{
+ struct vdec_vp8_inst *inst;
+ int err;
+
+ inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+ if (!inst)
+ return -ENOMEM;
+
+ inst->ctx = ctx;
+
+ inst->vpu.id = IPI_VDEC_VP8;
+ inst->vpu.dev = ctx->dev->vpu_plat_dev;
+ inst->vpu.ctx = ctx;
+ inst->vpu.handler = vpu_dec_ipi_handler;
+
+ err = vpu_dec_init(&inst->vpu);
+ if (err) {
+ mtk_vcodec_err(inst, "vdec_vp8 init err=%d", err);
+ goto error_free_inst;
+ }
+
+ inst->vsi = (struct vdec_vp8_vsi *)inst->vpu.vsi;
+ init_list(inst);
+ err = alloc_all_working_buf(inst);
+ if (err)
+ goto error_free_buf;
+
+ get_hw_reg_base(inst);
+ mtk_vcodec_debug(inst, "VP8 Instance >> %p", inst);
+
+ *h_vdec = (unsigned long)inst;
+ return 0;
+
+error_free_buf:
+ free_all_working_buf(inst);
+error_free_inst:
+ kfree(inst);
+ return err;
+}
+
+static int vdec_vp8_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs,
+ struct vdec_fb *fb, bool *res_chg)
+{
+ struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec;
+ struct vdec_vp8_dec_info *dec = &inst->vsi->dec;
+ struct vdec_vpu_inst *vpu = &inst->vpu;
+ unsigned char *bs_va;
+ unsigned int data;
+ int err = 0;
+ uint64_t y_fb_dma;
+ uint64_t c_fb_dma;
+
+ y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0;
+ c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0;
+
+ mtk_vcodec_debug(inst, "+ [%d] FB y_dma=%llx c_dma=%llx fb=%p",
+ inst->frm_cnt, y_fb_dma, c_fb_dma, fb);
+
+ inst->cur_fb = fb;
+
+ /* bs NULL means flush decoder */
+ if (bs == NULL) {
+ move_fb_list_use_to_free(inst);
+ return vpu_dec_reset(vpu);
+ }
+
+ bs_va = (unsigned char *)bs->va;
+ data = (*(bs_va + 9) << 24) | (*(bs_va + 8) << 16) |
+ (*(bs_va + 7) << 8) | *(bs_va + 6);
+
+ dec->bs_dma = (unsigned long)bs->dma_addr;
+ dec->bs_sz = bs->size;
+ dec->cur_y_fb_dma = y_fb_dma;
+ dec->cur_c_fb_dma = c_fb_dma;
+
+ mtk_vcodec_debug(inst, "\n + FRAME[%d] +\n", inst->frm_cnt);
+
+ write_hw_data(inst);
+ enable_hw_rw_dec_data(inst);
+ store_dec_data(inst);
+
+ err = vpu_dec_start(vpu, &data, 1);
+ if (err) {
+ add_fb_to_free_list(inst, fb);
+ if (dec->wait_key_frame) {
+ mtk_vcodec_debug(inst, "wait key frame !");
+ return 0;
+ }
+
+ goto error;
+ }
+
+ if (dec->resolution_changed) {
+ mtk_vcodec_debug(inst, "- resolution_changed -");
+ *res_chg = true;
+ add_fb_to_free_list(inst, fb);
+ return 0;
+ }
+
+ /* wait decoder done interrupt */
+ mtk_vcodec_wait_for_done_ctx(inst->ctx, MTK_INST_IRQ_RECEIVED,
+ WAIT_INTR_TIMEOUT_MS);
+
+ if (inst->vsi->load_data)
+ load_dec_data(inst);
+
+ vp8_dec_finish(inst);
+ read_hw_data(inst);
+
+ err = vpu_dec_end(vpu);
+ if (err)
+ goto error;
+
+ mtk_vcodec_debug(inst, "\n - FRAME[%d] - show=%d\n", inst->frm_cnt,
+ dec->show_frame);
+ inst->frm_cnt++;
+ *res_chg = false;
+ return 0;
+
+error:
+ mtk_vcodec_err(inst, "\n - FRAME[%d] - err=%d\n", inst->frm_cnt, err);
+ return err;
+}
+
+static void get_disp_fb(struct vdec_vp8_inst *inst, struct vdec_fb **out_fb)
+{
+ struct vdec_fb_node *node;
+ struct vdec_fb *fb;
+
+ node = list_first_entry_or_null(&inst->disp_rdy_list,
+ struct vdec_fb_node, list);
+ if (node) {
+ list_move_tail(&node->list, &inst->disp_fb_list);
+ fb = (struct vdec_fb *)node->fb;
+ fb->status |= FB_ST_DISPLAY;
+ mtk_vcodec_debug(inst, "[FB] get disp fb %p st=%d",
+ node->fb, fb->status);
+ } else {
+ fb = NULL;
+ mtk_vcodec_debug(inst, "[FB] there is no disp fb");
+ }
+
+ *out_fb = fb;
+}
+
+static void get_free_fb(struct vdec_vp8_inst *inst, struct vdec_fb **out_fb)
+{
+ struct vdec_fb_node *node;
+ struct vdec_fb *fb;
+
+ node = list_first_entry_or_null(&inst->dec_free_list,
+ struct vdec_fb_node, list);
+ if (node) {
+ list_move_tail(&node->list, &inst->dec_fb_list);
+ fb = (struct vdec_fb *)node->fb;
+ fb->status |= FB_ST_FREE;
+ mtk_vcodec_debug(inst, "[FB] get free fb %p st=%d",
+ node->fb, fb->status);
+ } else {
+ fb = NULL;
+ mtk_vcodec_debug(inst, "[FB] there is no free fb");
+ }
+
+ *out_fb = fb;
+}
+
+static void get_crop_info(struct vdec_vp8_inst *inst, struct v4l2_crop *cr)
+{
+ cr->c.left = 0;
+ cr->c.top = 0;
+ cr->c.width = inst->vsi->pic.pic_w;
+ cr->c.height = inst->vsi->pic.pic_h;
+ mtk_vcodec_debug(inst, "get crop info l=%d, t=%d, w=%d, h=%d",
+ cr->c.left, cr->c.top, cr->c.width, cr->c.height);
+}
+
+static int vdec_vp8_get_param(unsigned long h_vdec,
+ enum vdec_get_param_type type, void *out)
+{
+ struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec;
+
+ switch (type) {
+ case GET_PARAM_DISP_FRAME_BUFFER:
+ get_disp_fb(inst, out);
+ break;
+
+ case GET_PARAM_FREE_FRAME_BUFFER:
+ get_free_fb(inst, out);
+ break;
+
+ case GET_PARAM_PIC_INFO:
+ get_pic_info(inst, out);
+ break;
+
+ case GET_PARAM_CROP_INFO:
+ get_crop_info(inst, out);
+ break;
+
+ case GET_PARAM_DPB_SIZE:
+ *((unsigned int *)out) = 4;
+ break;
+
+ default:
+ mtk_vcodec_err(inst, "invalid get parameter type=%d", type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vdec_vp8_deinit(unsigned long h_vdec)
+{
+ struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec;
+
+ mtk_vcodec_debug_enter(inst);
+
+ vpu_dec_deinit(&inst->vpu);
+ free_all_working_buf(inst);
+ kfree(inst);
+
+ return 0;
+}
+
+static struct vdec_common_if vdec_vp8_if = {
+ vdec_vp8_init,
+ vdec_vp8_decode,
+ vdec_vp8_get_param,
+ vdec_vp8_deinit,
+};
+
+struct vdec_common_if *get_vp8_dec_comm_if(void)
+{
+ return &vdec_vp8_if;
+}
diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c
index 576920c..6e2f065 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c
+++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c
@@ -25,6 +25,7 @@
#include "mtk_vpu.h"
struct vdec_common_if *get_h264_dec_comm_if(void);
+struct vdec_common_if *get_vp8_dec_comm_if(void);
int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc)
{
@@ -35,6 +36,8 @@ int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc)
ctx->dec_if = get_h264_dec_comm_if();
break;
case V4L2_PIX_FMT_VP8:
+ ctx->dec_if = get_vp8_dec_comm_if();
+ break;
case V4L2_PIX_FMT_VP9:
default:
return -EINVAL;
--
1.7.9.5
[toc] | [prev] | [next] | [standalone]
| From | Tiffany Lin <tiffany.lin@mediatek.com> |
|---|---|
| Date | 2016-04-13 14:10 +0200 |
| Subject | [PATCH 2/7] dt-bindings: Add a binding for Mediatek Video Decoder |
| Message-ID | <rnrMm-116-7@gated-at.bofh.it> |
| In reply to | #1377865 |
Add a DT binding documentation of Video Decoder for the
MT8173 SoC from Mediatek.
Signed-off-by: Tiffany Lin <tiffany.lin@mediatek.com>
---
.../devicetree/bindings/media/mediatek-vcodec.txt | 50 ++++++++++++++++++--
1 file changed, 46 insertions(+), 4 deletions(-)
diff --git a/Documentation/devicetree/bindings/media/mediatek-vcodec.txt b/Documentation/devicetree/bindings/media/mediatek-vcodec.txt
index 59a47a5..9aa8848 100644
--- a/Documentation/devicetree/bindings/media/mediatek-vcodec.txt
+++ b/Documentation/devicetree/bindings/media/mediatek-vcodec.txt
@@ -1,25 +1,67 @@
Mediatek Video Codec
Mediatek Video Codec is the video codec hw present in Mediatek SoCs which
-supports high resolution encoding functionalities.
+supports high resolution encoding and decoding functionalities.
Required properties:
- compatible : "mediatek,mt8173-vcodec-enc" for encoder
+ "mediatek,mt8173-vcodec-dec" for decoder.
- reg : Physical base address of the video codec registers and length of
memory mapped region.
- interrupts : interrupt number to the cpu.
- mediatek,larb : must contain the local arbiters in the current Socs.
- clocks : list of clock specifiers, corresponding to entries in
the clock-names property.
-- clock-names: encoder must contain "venc_sel_src", "venc_sel",
-- "venc_lt_sel_src", "venc_lt_sel".
+- clock-names: encoder must contain "venc_sel_src", "venc_sel",,
+ "venc_lt_sel_src", "venc_lt_sel", decoder must contain "vcodecpll",
+ "univpll_d2", "clk_cci400_sel", "vdec_sel", "vdecpll".
- iommus : should point to the respective IOMMU block with master port as
argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
for details.
- mediatek,vpu : the node of video processor unit
+
Example:
-vcodec_enc: vcodec@0x18002000 {
+
+vcodec_dec: vcodec@16000000 {
+ compatible = "mediatek,mt8173-vcodec-dec";
+ reg = <0 0x16000000 0 0x100>, /*VDEC_SYS*/
+ <0 0x16020000 0 0x1000>, /*VDEC_MISC*/
+ <0 0x16021000 0 0x800>, /*VDEC_LD*/
+ <0 0x16021800 0 0x800>, /*VDEC_TOP*/
+ <0 0x16022000 0 0x1000>, /*VDEC_CM*/
+ <0 0x16023000 0 0x1000>, /*VDEC_AD*/
+ <0 0x16024000 0 0x1000>, /*VDEC_AV*/
+ <0 0x16025000 0 0x1000>, /*VDEC_PP*/
+ <0 0x16026800 0 0x800>, /*VP8_VD*/
+ <0 0x16027000 0 0x800>, /*VP6_VD*/
+ <0 0x16027800 0 0x800>, /*VP8_VL*/
+ <0 0x16028400 0 0x400>; /*VP9_VD*/
+ interrupts = <GIC_SPI 204 IRQ_TYPE_LEVEL_LOW>;
+ mediatek,larb = <&larb1>;
+ iommus = <&iommu M4U_PORT_HW_VDEC_MC_EXT>,
+ <&iommu M4U_PORT_HW_VDEC_PP_EXT>,
+ <&iommu M4U_PORT_HW_VDEC_AVC_MV_EXT>,
+ <&iommu M4U_PORT_HW_VDEC_PRED_RD_EXT>,
+ <&iommu M4U_PORT_HW_VDEC_PRED_WR_EXT>,
+ <&iommu M4U_PORT_HW_VDEC_UFO_EXT>,
+ <&iommu M4U_PORT_HW_VDEC_VLD_EXT>,
+ <&iommu M4U_PORT_HW_VDEC_VLD2_EXT>;
+ mediatek,vpu = <&vpu>;
+ power-domains = <&scpsys MT8173_POWER_DOMAIN_VDEC>;
+ clocks = <&apmixedsys CLK_APMIXED_VCODECPLL>,
+ <&topckgen CLK_TOP_UNIVPLL_D2>,
+ <&topckgen CLK_TOP_CCI400_SEL>,
+ <&topckgen CLK_TOP_VDEC_SEL>,
+ <&topckgen CLK_TOP_VCODECPLL>;
+ clock-names = "vcodecpll",
+ "univpll_d2",
+ "clk_cci400_sel",
+ "vdec_sel",
+ "vdecpll";
+ };
+
+ vcodec_enc: vcodec@0x18002000 {
compatible = "mediatek,mt8173-vcodec-enc";
reg = <0 0x18002000 0 0x1000>, /*VENC_SYS*/
<0 0x19002000 0 0x1000>; /*VENC_LT_SYS*/
--
1.7.9.5
[toc] | [prev] | [next] | [standalone]
| From | Tiffany Lin <tiffany.lin@mediatek.com> |
|---|---|
| Date | 2016-04-13 14:10 +0200 |
| Subject | [PATCH 4/7] [media] vcodec: mediatek: Add Mediatek H264 Video Decoder Driver |
| Message-ID | <rnrMm-116-11@gated-at.bofh.it> |
| In reply to | #1377868 |
Add h264 driver for MT8173
Signed-off-by: PC Chen <pc.chen@mediatek.com>
Signed-off-by: Tiffany Lin <tiffany.lin@mediatek.com>
---
drivers/media/platform/mtk-vcodec/Makefile | 5 +-
.../media/platform/mtk-vcodec/vdec/vdec_h264_if.c | 487 ++++++++++++++++++++
drivers/media/platform/mtk-vcodec/vdec_drv_if.c | 4 +
drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h | 28 +-
drivers/media/platform/mtk-vcodec/vdec_vpu_if.c | 164 +++++++
drivers/media/platform/mtk-vcodec/vdec_vpu_if.h | 60 +++
6 files changed, 739 insertions(+), 9 deletions(-)
create mode 100644 drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c
create mode 100644 drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
create mode 100644 drivers/media/platform/mtk-vcodec/vdec_vpu_if.h
diff --git a/drivers/media/platform/mtk-vcodec/Makefile b/drivers/media/platform/mtk-vcodec/Makefile
index 4c8ed2f..58243ed 100644
--- a/drivers/media/platform/mtk-vcodec/Makefile
+++ b/drivers/media/platform/mtk-vcodec/Makefile
@@ -1,11 +1,12 @@
-
obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-dec.o \
mtk-vcodec-enc.o \
mtk-vcodec-common.o
-mtk-vcodec-dec-y := mtk_vcodec_dec_drv.o \
+mtk-vcodec-dec-y := vdec/vdec_h264_if.o \
+ mtk_vcodec_dec_drv.o \
vdec_drv_if.o \
+ vdec_vpu_if.o \
mtk_vcodec_dec.o \
mtk_vcodec_dec_pm.o \
diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c
new file mode 100644
index 0000000..9762bbf
--- /dev/null
+++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c
@@ -0,0 +1,487 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: PC Chen <pc.chen@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "mtk_vcodec_intr.h"
+#include "vdec_vpu_if.h"
+#include "vdec_drv_base.h"
+
+#define NON_IDR_SLICE 0x01
+#define IDR_SLICE 0x05
+#define H264_PPS 0x08
+
+#define BUF_PREDICTION_SZ (32 * 1024)
+#define BUF_PP_SZ (30 * 4096)
+#define BUF_LD_SZ (15 * 4096)
+
+#define MB_UNIT_SZ 16
+#define HW_MB_STORE_SZ 64
+
+#define H264_MAX_FB_NUM 17
+#define HDR_PARSING_BUF_SZ 1024
+#define NAL_TYPE(value) ((value) & 0x1F)
+
+/**
+ * struct h264_fb - h264 decode frame buffer information
+ * @vdec_fb_va : virtual address of struct vdec_fb
+ * @y_fb_dma : dma address of Y frame buffer
+ * @c_fb_dma : dma address of C frame buffer
+ * @poc : picture order count of frame buffer
+ * @reserved : for 8 bytes alignment
+ */
+struct h264_fb {
+ uint64_t vdec_fb_va;
+ uint64_t y_fb_dma;
+ uint64_t c_fb_dma;
+ int32_t poc;
+ uint32_t reserved;
+};
+
+/**
+ * struct h264_ring_fb_list - ring frame buffer list
+ * @fb_list : frame buffer arrary
+ * @read_idx : read index
+ * @write_idx : write index
+ * @count : buffer count in list
+ */
+struct h264_ring_fb_list {
+ struct h264_fb fb_list[H264_MAX_FB_NUM];
+ unsigned int read_idx;
+ unsigned int write_idx;
+ unsigned int count;
+ unsigned int reserved;
+};
+
+/**
+ * struct vdec_h264_dec_info - decode information
+ * @dpb_sz : decoding picture buffer size
+ * @resolution_changed : resoltion change happen
+ * @realloc_mv_buf : flag to notify driver to re-allocate mv buffer
+ * @reserved : for 8 bytes alignment
+ * @bs_dma : Input bit-stream buffer dma address
+ * @y_fb_dma : Y frame buffer dma address
+ * @c_fb_dma : C frame buffer dma address
+ * @vdec_fb_va : VDEC frame buffer struct virtual address
+ */
+struct vdec_h264_dec_info {
+ uint32_t dpb_sz;
+ uint32_t resolution_changed;
+ uint32_t realloc_mv_buf;
+ uint32_t reserved;
+ uint64_t bs_dma;
+ uint64_t y_fb_dma;
+ uint64_t c_fb_dma;
+ uint64_t vdec_fb_va;
+};
+
+/**
+ * struct vdec_h264_vsi - shared memory for decode information exchange
+ * between VPU and Host.
+ * The memory is allocated by VPU and mapping to Host
+ * in vpu_dec_init()
+ * @hdr_buf : Header parsing buffer
+ * @ppl_buf_dma : HW working buffer ppl dma address
+ * @mv_buf_dma : HW working buffer mv dma address
+ * @list_free : free frame buffer ring list
+ * @list_disp : display frame buffer ring list
+ * @dec : decode information
+ * @pic : picture information
+ * @crop : crop information
+ */
+struct vdec_h264_vsi {
+ unsigned char hdr_buf[HDR_PARSING_BUF_SZ];
+ uint64_t ppl_buf_dma;
+ uint64_t mv_buf_dma[H264_MAX_FB_NUM];
+ struct h264_ring_fb_list list_free;
+ struct h264_ring_fb_list list_disp;
+ struct vdec_h264_dec_info dec;
+ struct vdec_pic_info pic;
+ struct v4l2_rect crop;
+};
+
+/**
+ * struct vdec_h264_inst - h264 decoder instance
+ * @num_nalu : how many nalus be decoded
+ * @ctx : point to mtk_vcodec_ctx
+ * @ppl_buf : HW working buffer for ppl
+ * @mv_buf : HW working buffer for mv
+ * @vpu : VPU instance
+ * @vsi : VPU shared information
+ */
+struct vdec_h264_inst {
+ unsigned int num_nalu;
+ struct mtk_vcodec_ctx *ctx;
+ struct mtk_vcodec_mem ppl_buf;
+ struct mtk_vcodec_mem mv_buf[H264_MAX_FB_NUM];
+ struct vdec_vpu_inst vpu;
+ struct vdec_h264_vsi *vsi;
+};
+
+static unsigned int get_mv_buf_size(unsigned int width, unsigned int height)
+{
+ return HW_MB_STORE_SZ * (width/MB_UNIT_SZ) * (height/MB_UNIT_SZ);
+}
+
+static int alloc_mv_buf(struct vdec_h264_inst *inst, struct vdec_pic_info *pic)
+{
+ int i;
+ int err;
+ struct mtk_vcodec_mem *mem = NULL;
+ unsigned int buf_sz;
+
+ buf_sz = get_mv_buf_size(pic->buf_w, pic->buf_h);
+
+ for (i = 0; i < H264_MAX_FB_NUM; i++) {
+ mem = &inst->mv_buf[i];
+ if (mem->va)
+ mtk_vcodec_mem_free(inst->ctx, mem);
+ mem->size = buf_sz;
+ err = mtk_vcodec_mem_alloc(inst->ctx, mem);
+ if (err) {
+ mtk_vcodec_err(inst, "failed to allocate mv buf");
+ return -ENOMEM;
+ }
+ inst->vsi->mv_buf_dma[i] = mem->dma_addr;
+ }
+
+ return 0;
+}
+
+static void free_all_working_buf(struct vdec_h264_inst *inst)
+{
+ int i;
+ struct mtk_vcodec_mem *mem = NULL;
+
+ mtk_vcodec_debug_enter(inst);
+
+ inst->vsi->ppl_buf_dma = 0;
+ mem = &inst->ppl_buf;
+ if (mem->va)
+ mtk_vcodec_mem_free(inst->ctx, mem);
+
+ for (i = 0; i < H264_MAX_FB_NUM; i++) {
+ inst->vsi->mv_buf_dma[i] = 0;
+ mem = &inst->mv_buf[i];
+ if (mem->va)
+ mtk_vcodec_mem_free(inst->ctx, mem);
+ }
+}
+
+static int allocate_working_buf(struct vdec_h264_inst *inst)
+{
+ int err = 0;
+
+ inst->ppl_buf.size = BUF_PREDICTION_SZ + BUF_PP_SZ + BUF_LD_SZ;
+ err = mtk_vcodec_mem_alloc(inst->ctx, &inst->ppl_buf);
+ if (err) {
+ mtk_vcodec_err(inst, "failed to allocate ppl buf");
+ return -ENOMEM;
+ }
+
+ inst->vsi->ppl_buf_dma = inst->ppl_buf.dma_addr;
+ return 0;
+}
+
+static void put_fb_to_free(struct vdec_h264_inst *inst, struct vdec_fb *fb)
+{
+ struct h264_ring_fb_list *list;
+
+ if (fb) {
+ list = &inst->vsi->list_free;
+ if (list->count == H264_MAX_FB_NUM) {
+ mtk_vcodec_err(inst, "[FB] put fb free_list full");
+ return;
+ }
+
+ mtk_vcodec_debug(inst, "[FB] put fb into free_list @(%p, %llx)",
+ fb->base_y.va, (u64)fb->base_y.dma_addr);
+
+ list->fb_list[list->write_idx].vdec_fb_va = (u64)fb;
+ list->write_idx = (list->write_idx == H264_MAX_FB_NUM - 1) ?
+ 0 : list->write_idx + 1;
+ list->count++;
+ }
+}
+
+static void get_pic_info(struct vdec_h264_inst *inst,
+ struct vdec_pic_info *pic)
+{
+ pic->pic_w = inst->vsi->pic.pic_w;
+ pic->pic_h = inst->vsi->pic.pic_h;
+ pic->buf_w = inst->vsi->pic.buf_w;
+ pic->buf_h = inst->vsi->pic.buf_h;
+ pic->y_bs_sz = inst->vsi->pic.y_bs_sz;
+ pic->c_bs_sz = inst->vsi->pic.c_bs_sz;
+ pic->y_len_sz = inst->vsi->pic.y_len_sz;
+ pic->c_len_sz = inst->vsi->pic.c_len_sz;
+
+ mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)",
+ pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h);
+ mtk_vcodec_debug(inst, "Y(%d, %d), C(%d, %d)", pic->y_bs_sz,
+ pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz);
+}
+
+static void get_crop_info(struct vdec_h264_inst *inst, struct v4l2_crop *cr)
+{
+ cr->c.left = inst->vsi->crop.left;
+ cr->c.top = inst->vsi->crop.top;
+ cr->c.width = inst->vsi->crop.width;
+ cr->c.height = inst->vsi->crop.height;
+ mtk_vcodec_debug(inst, "l=%d, t=%d, w=%d, h=%d",
+ cr->c.left, cr->c.top, cr->c.width, cr->c.height);
+}
+
+static void get_dpb_size(struct vdec_h264_inst *inst, unsigned int *dpb_sz)
+{
+ *dpb_sz = inst->vsi->dec.dpb_sz;
+ mtk_vcodec_debug(inst, "sz=%d", *dpb_sz);
+}
+
+static int vdec_h264_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec)
+{
+ struct vdec_h264_inst *inst = NULL;
+ int err;
+
+ inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+ if (!inst)
+ return -ENOMEM;
+
+ inst->ctx = ctx;
+
+ inst->vpu.id = IPI_VDEC_H264;
+ inst->vpu.dev = ctx->dev->vpu_plat_dev;
+ inst->vpu.ctx = ctx;
+ inst->vpu.handler = vpu_dec_ipi_handler;
+
+ err = vpu_dec_init(&inst->vpu);
+ if (err) {
+ mtk_vcodec_err(inst, "vdec_h264 init err=%d", err);
+ goto error_free_inst;
+ }
+
+ inst->vsi = (struct vdec_h264_vsi *)inst->vpu.vsi;
+ err = allocate_working_buf(inst);
+ if (err)
+ goto error_free_inst;
+
+ mtk_vcodec_debug(inst, "H264 Instance >> %p", inst);
+
+ *h_vdec = (unsigned long)inst;
+ return 0;
+
+error_free_inst:
+ kfree(inst);
+
+ return err;
+}
+
+static int vdec_h264_deinit(unsigned long h_vdec)
+{
+ struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec;
+
+ mtk_vcodec_debug_enter(inst);
+
+ vpu_dec_deinit(&inst->vpu);
+ free_all_working_buf(inst);
+
+ kfree(inst);
+ return 0;
+}
+
+static int find_start_code(unsigned char *data, unsigned int data_sz)
+{
+ if (data_sz >= 3 && data[0] == 0 && data[1] == 0 && data[2] == 1)
+ return 3;
+
+ if (data_sz >= 4 && data[0] == 0 && data[1] == 0 && data[2] == 0 &&
+ data[3] == 1)
+ return 4;
+
+ return -1;
+}
+
+static int vdec_h264_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs,
+ struct vdec_fb *fb, bool *res_chg)
+{
+ struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec;
+ struct vdec_vpu_inst *vpu = &inst->vpu;
+ int idx = 0;
+ int err = 0;
+ unsigned int nal_start;
+ unsigned int nal_type;
+ unsigned char *buf;
+ unsigned int buf_sz;
+ unsigned int data[2];
+ uint64_t vdec_fb_va;
+ uint64_t y_fb_dma;
+ uint64_t c_fb_dma;
+
+ y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0;
+ c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0;
+
+ vdec_fb_va = (u64)fb;
+
+ mtk_vcodec_debug(inst, "+ [%d] FB y_dma=%llx c_dma=%llx va=%p",
+ inst->num_nalu, y_fb_dma, c_fb_dma, fb);
+
+ /* bs NULL means flush decoder */
+ if (bs == NULL)
+ return vpu_dec_reset(vpu);
+
+ buf = (unsigned char *)bs->va;
+ buf_sz = bs->size;
+ idx = find_start_code(buf, buf_sz);
+ if (idx < 0)
+ goto err_free_fb_out;
+
+ nal_start = buf[idx];
+ nal_type = NAL_TYPE(buf[idx]);
+ mtk_vcodec_debug(inst, "\n + NALU[%d] type %d +\n", inst->num_nalu,
+ nal_type);
+
+ if (nal_type == H264_PPS) {
+ if (buf_sz > HDR_PARSING_BUF_SZ) {
+ err = -EILSEQ;
+ goto err_free_fb_out;
+ }
+ buf_sz -= idx;
+ memcpy(inst->vsi->hdr_buf, buf + idx, buf_sz);
+ }
+
+ inst->vsi->dec.bs_dma = (uint64_t)bs->dma_addr;
+ inst->vsi->dec.y_fb_dma = y_fb_dma;
+ inst->vsi->dec.c_fb_dma = c_fb_dma;
+ inst->vsi->dec.vdec_fb_va = vdec_fb_va;
+
+ data[0] = buf_sz;
+ data[1] = nal_start;
+ err = vpu_dec_start(vpu, data, 2);
+ if (err)
+ goto err_free_fb_out;
+
+ *res_chg = inst->vsi->dec.resolution_changed;
+ if (*res_chg) {
+ struct vdec_pic_info pic;
+
+ mtk_vcodec_debug(inst, "- resolution changed -");
+ get_pic_info(inst, &pic);
+
+ if (inst->vsi->dec.realloc_mv_buf) {
+ err = alloc_mv_buf(inst, &pic);
+ if (err)
+ goto err_free_fb_out;
+ }
+ }
+
+ if (nal_type == NON_IDR_SLICE || nal_type == IDR_SLICE) {
+ /* wait decoder done interrupt */
+ err = mtk_vcodec_wait_for_done_ctx(inst->ctx,
+ MTK_INST_IRQ_RECEIVED,
+ WAIT_INTR_TIMEOUT_MS);
+ if (err)
+ goto err_free_fb_out;
+
+ vpu_dec_end(vpu);
+ }
+
+ mtk_vcodec_debug(inst, "\n - NALU[%d] type=%d -\n", inst->num_nalu,
+ nal_type);
+ inst->num_nalu++;
+ return 0;
+
+err_free_fb_out:
+ put_fb_to_free(inst, fb);
+ mtk_vcodec_err(inst, "\n - NALU[%d] err=%d -\n", inst->num_nalu, err);
+ return err;
+}
+
+static void vdec_h264_get_fb(struct vdec_h264_inst *inst,
+ struct h264_ring_fb_list *list,
+ bool disp_list, struct vdec_fb **out_fb)
+{
+ unsigned long vdec_fb_va;
+ struct vdec_fb *fb;
+
+ if (list->count == 0) {
+ mtk_vcodec_debug(inst, "[FB] there is no %s fb",
+ disp_list ? "disp" : "free");
+ *out_fb = NULL;
+ return;
+ }
+
+ vdec_fb_va = (unsigned long)list->fb_list[list->read_idx].vdec_fb_va;
+ fb = (struct vdec_fb *)vdec_fb_va;
+ if (disp_list)
+ fb->status |= FB_ST_DISPLAY;
+ else
+ fb->status |= FB_ST_FREE;
+
+ *out_fb = fb;
+ mtk_vcodec_debug(inst, "[FB] get %s fb st=%d poc=%d %llx",
+ disp_list ? "disp" : "free",
+ fb->status, list->fb_list[list->read_idx].poc,
+ list->fb_list[list->read_idx].vdec_fb_va);
+
+ list->read_idx = (list->read_idx == H264_MAX_FB_NUM - 1) ?
+ 0 : list->read_idx + 1;
+ list->count--;
+}
+
+static int vdec_h264_get_param(unsigned long h_vdec,
+ enum vdec_get_param_type type, void *out)
+{
+ struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec;
+
+ switch (type) {
+ case GET_PARAM_DISP_FRAME_BUFFER:
+ vdec_h264_get_fb(inst, &inst->vsi->list_disp, true, out);
+ break;
+
+ case GET_PARAM_FREE_FRAME_BUFFER:
+ vdec_h264_get_fb(inst, &inst->vsi->list_free, false, out);
+ break;
+
+ case GET_PARAM_PIC_INFO:
+ get_pic_info(inst, out);
+ break;
+
+ case GET_PARAM_DPB_SIZE:
+ get_dpb_size(inst, out);
+ break;
+
+ case GET_PARAM_CROP_INFO:
+ get_crop_info(inst, out);
+ break;
+
+ default:
+ mtk_vcodec_err(inst, "invalid get parameter type=%d", type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct vdec_common_if vdec_h264_if = {
+ vdec_h264_init,
+ vdec_h264_decode,
+ vdec_h264_get_param,
+ vdec_h264_deinit,
+};
+
+struct vdec_common_if *get_h264_dec_comm_if(void)
+{
+ return &vdec_h264_if;
+}
diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c
index 1d12719..576920c 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c
+++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c
@@ -24,12 +24,16 @@
#include "mtk_vcodec_util.h"
#include "mtk_vpu.h"
+struct vdec_common_if *get_h264_dec_comm_if(void);
+
int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc)
{
int ret = 0;
switch (fourcc) {
case V4L2_PIX_FMT_H264:
+ ctx->dec_if = get_h264_dec_comm_if();
+ break;
case V4L2_PIX_FMT_VP8:
case V4L2_PIX_FMT_VP9:
default:
diff --git a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h
index 937192c..131928b 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h
+++ b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h
@@ -54,7 +54,7 @@ struct vdec_ap_ipi_cmd {
struct vdec_vpu_ipi_ack {
uint32_t msg_id;
int32_t status;
- uint64_t vdec_inst;
+ uint64_t ap_inst_addr;
};
/**
@@ -66,20 +66,34 @@ struct vdec_vpu_ipi_ack {
struct vdec_ap_ipi_init {
uint32_t msg_id;
uint32_t reserved;
- uint64_t vdec_inst;
+ uint64_t ap_inst_addr;
};
/**
- * struct vdec_vpu_ipi_init_ack - for VPU_IPIMSG_DEC_INIT_ACK
- * @msg_id : VPU_IPIMSG_DEC_INIT_ACK
- * @status : VPU exeuction result
- * @vdec_inst : AP video decoder instance address
+ * struct vdec_ap_ipi_dec_start - for AP_IPIMSG_DEC_START
+ * @msg_id : AP_IPIMSG_DEC_START
* @vpu_inst_addr : VPU decoder instance address
+ * @data : Header info
+ * @reserved : Reserved field
+ */
+struct vdec_ap_ipi_dec_start {
+ uint32_t msg_id;
+ uint32_t vpu_inst_addr;
+ uint32_t data[3];
+ uint32_t reserved;
+};
+
+/**
+ * struct vdec_vpu_ipi_init_ack - for VPU_IPIMSG_DEC_INIT_ACK
+ * @msg_id : VPU_IPIMSG_DEC_INIT_ACK
+ * @status : VPU exeuction result
+ * @ap_inst_addr : AP vcodec_vpu_inst instance address
+ * @vpu_inst_addr : VPU decoder instance address
*/
struct vdec_vpu_ipi_init_ack {
uint32_t msg_id;
int32_t status;
- uint64_t vdec_inst;
+ uint64_t ap_inst_addr;
uint32_t vpu_inst_addr;
};
diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
new file mode 100644
index 0000000..33b96db
--- /dev/null
+++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: PC Chen <pc.chen@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "mtk_vcodec_drv.h"
+#include "mtk_vcodec_util.h"
+#include "vdec_ipi_msg.h"
+#include "vdec_vpu_if.h"
+
+static void handle_init_ack_msg(struct vdec_vpu_ipi_init_ack *msg)
+{
+ struct vdec_vpu_inst *vpu = (struct vdec_vpu_inst *)msg->ap_inst_addr;
+
+ mtk_vcodec_debug(vpu, "+ ap_inst_addr = 0x%llx", msg->ap_inst_addr);
+
+ /* mapping VPU address to kernel virtual address */
+ vpu->vsi = vpu_mapping_dm_addr(vpu->dev, msg->vpu_inst_addr);
+ vpu->inst_addr = msg->vpu_inst_addr;
+
+ mtk_vcodec_debug(vpu, "- vpu_inst_addr = 0x%x", vpu->inst_addr);
+}
+
+/*
+ * This function runs in interrupt context and it means there's a IPI MSG
+ * from VPU.
+ */
+void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv)
+{
+ struct vdec_vpu_ipi_ack *msg = data;
+ struct vdec_vpu_inst *vpu = (struct vdec_vpu_inst *)msg->ap_inst_addr;
+
+ mtk_vcodec_debug(vpu, "+ id=%X", msg->msg_id);
+
+ vpu->failure = msg->status;
+
+ if (msg->status == 0) {
+ switch (msg->msg_id) {
+ case VPU_IPIMSG_DEC_INIT_ACK:
+ handle_init_ack_msg(data);
+ break;
+
+ case VPU_IPIMSG_DEC_START_ACK:
+ case VPU_IPIMSG_DEC_END_ACK:
+ case VPU_IPIMSG_DEC_DEINIT_ACK:
+ case VPU_IPIMSG_DEC_RESET_ACK:
+ break;
+
+ default:
+ mtk_vcodec_err(vpu, "invalid msg=%X", msg->msg_id);
+ break;
+ }
+ }
+
+ mtk_vcodec_debug(vpu, "- id=%X", msg->msg_id);
+ vpu->signaled = 1;
+}
+
+static int vcodec_vpu_send_msg(struct vdec_vpu_inst *vpu, void *msg, int len)
+{
+ int err;
+
+ mtk_vcodec_debug(vpu, "id=%X", *(unsigned int *)msg);
+
+ vpu->failure = 0;
+ vpu->signaled = 0;
+
+ err = vpu_ipi_send(vpu->dev, vpu->id, msg, len);
+ if (err) {
+ mtk_vcodec_err(vpu, "vpu_ipi_send fail status=%d", err);
+ return err;
+ }
+
+ return vpu->failure;
+}
+
+static int vcodec_send_ap_ipi(struct vdec_vpu_inst *vpu, unsigned int msg_id)
+{
+ struct vdec_ap_ipi_cmd msg;
+ int err = 0;
+
+ mtk_vcodec_debug(vpu, "+ id=%X", msg_id);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_id = msg_id;
+ msg.vpu_inst_addr = vpu->inst_addr;
+
+ err = vcodec_vpu_send_msg(vpu, &msg, sizeof(msg));
+ mtk_vcodec_debug(vpu, "- id=%X ret=%d", msg_id, err);
+ return err;
+}
+
+int vpu_dec_init(struct vdec_vpu_inst *vpu)
+{
+ struct vdec_ap_ipi_init msg;
+ int err;
+
+ mtk_vcodec_debug_enter(vpu);
+
+ init_waitqueue_head(&vpu->wq);
+ vpu->signaled = 0;
+ vpu->failure = 0;
+
+ err = vpu_ipi_register(vpu->dev, vpu->id, vpu->handler, NULL, NULL);
+ if (err != 0) {
+ mtk_vcodec_err(vpu, "vpu_ipi_register fail status=%d", err);
+ return err;
+ }
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_id = AP_IPIMSG_DEC_INIT;
+ msg.ap_inst_addr = (unsigned long)vpu;
+
+ mtk_vcodec_debug(vpu, "vdec_inst=%p", vpu);
+
+ err = vcodec_vpu_send_msg(vpu, (void *)&msg, sizeof(msg));
+ mtk_vcodec_debug(vpu, "- ret=%d", err);
+ return err;
+}
+
+int vpu_dec_start(struct vdec_vpu_inst *vpu, unsigned int *data,
+ unsigned int length)
+{
+ struct vdec_ap_ipi_dec_start msg;
+ int i;
+ int err = 0;
+
+ mtk_vcodec_debug_enter(vpu);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_id = AP_IPIMSG_DEC_START;
+ msg.vpu_inst_addr = vpu->inst_addr;
+
+ for (i = 0; i < length; i++)
+ msg.data[i] = data[i];
+
+ err = vcodec_vpu_send_msg(vpu, (void *)&msg, sizeof(msg));
+ mtk_vcodec_debug(vpu, "- ret=%d", err);
+ return err;
+}
+
+int vpu_dec_end(struct vdec_vpu_inst *vpu)
+{
+ return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_END);
+}
+
+int vpu_dec_deinit(struct vdec_vpu_inst *vpu)
+{
+ return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_DEINIT);
+}
+
+int vpu_dec_reset(struct vdec_vpu_inst *vpu)
+{
+ return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_RESET);
+}
diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h
new file mode 100644
index 0000000..c16cd75
--- /dev/null
+++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: PC Chen <pc.chen@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _VDEC_VPU_IF_H_
+#define _VDEC_VPU_IF_H_
+
+#include "mtk_vpu.h"
+
+/**
+ * struct vdec_vpu_inst - VPU instance for video codec
+ * @dev : platform device of VPU
+ * @inst_addr : VPU decoder instance addr
+ * @signaled : 1 - Host has received ack message from VPU, 0 - not recevie
+ * @failure : VPU execution result status
+ * @wq : Wait queue to wait VPU message ack
+ */
+struct vdec_vpu_inst {
+ enum ipi_id id;
+ void *vsi;
+ int failure;
+ unsigned int inst_addr;
+ unsigned int signaled;
+ struct mtk_vcodec_ctx *ctx;
+ struct platform_device *dev;
+ wait_queue_head_t wq;
+ ipi_handler_t handler;
+};
+
+/*
+ * Note these functions are not thread-safe for the same decoder instance.
+ * the reason is |signaled|. In vdec_vpu_wait_ack,
+ * wait_event_interruptible_timeout waits |signaled| to be 1.
+ * Suppose wait_event_interruptible_timeout returns and the execution has not
+ * reached line 127. If another thread calls vpu_dec_end,
+ * |signaled| will be 1 and wait_event_interruptible_timeout will return
+ * immediately. We enusure thread-safe to add mtk_vdec_lock()/unlock() in
+ * vdec_drv_if.c
+ *
+ */
+
+int vpu_dec_init(struct vdec_vpu_inst *vpu);
+int vpu_dec_start(struct vdec_vpu_inst *vpu, unsigned int *data,
+ unsigned int length);
+int vpu_dec_end(struct vdec_vpu_inst *vpu);
+int vpu_dec_deinit(struct vdec_vpu_inst *vpu);
+int vpu_dec_reset(struct vdec_vpu_inst *vpu);
+void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv);
+
+#endif
--
1.7.9.5
[toc] | [prev] | [next] | [standalone]
| From | Rob Herring <robh@kernel.org> |
|---|---|
| Date | 2016-04-14 18:20 +0200 |
| Subject | Re: [PATCH 2/7] dt-bindings: Add a binding for Mediatek Video Decoder |
| Message-ID | <rnS9Q-4Iu-1@gated-at.bofh.it> |
| In reply to | #1377868 |
On Wed, Apr 13, 2016 at 08:01:50PM +0800, Tiffany Lin wrote: > Add a DT binding documentation of Video Decoder for the > MT8173 SoC from Mediatek. > > Signed-off-by: Tiffany Lin <tiffany.lin@mediatek.com> > --- > .../devicetree/bindings/media/mediatek-vcodec.txt | 50 ++++++++++++++++++-- > 1 file changed, 46 insertions(+), 4 deletions(-) Acked-by: Rob Herring <rob@kernel.org>
[toc] | [prev] | [next] | [standalone]
| From | Tiffany Lin <tiffany.lin@mediatek.com> |
|---|---|
| Date | 2016-04-13 14:10 +0200 |
| Subject | [PATCH 1/7] [media]: v4l: add Mediatek MT21 video block format |
| Message-ID | <rnrMm-116-5@gated-at.bofh.it> |
| In reply to | #1377865 |
From: Daniel Kurtz <djkurtz@chromium.org>
Mediatek video format is YVU8_420_2PLANE_PACK8_PROGRESSIVE.
Create V4L2_PIX_FMT_MT21 and DRM_FORMAT_MT21 to be consistent with
V4L2_PIX_FMT_NV12 notation.
Signed-off-by: Tiffany Lin <tiffany.lin@mediatek.com>
---
include/uapi/drm/drm_fourcc.h | 1 +
include/uapi/linux/videodev2.h | 2 ++
2 files changed, 3 insertions(+)
diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
index 0b69a77..a193905 100644
--- a/include/uapi/drm/drm_fourcc.h
+++ b/include/uapi/drm/drm_fourcc.h
@@ -116,6 +116,7 @@
#define DRM_FORMAT_NV24 fourcc_code('N', 'V', '2', '4') /* non-subsampled Cr:Cb plane */
#define DRM_FORMAT_NV42 fourcc_code('N', 'V', '4', '2') /* non-subsampled Cb:Cr plane */
+#define DRM_FORMAT_MT21 fourcc_code('M', 'T', '2', '1') /* Mediatek Block Mode */
/*
* 3 plane YCbCr
* index 0: Y plane, [7:0] Y
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index d0acd26..e9e3276 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -527,6 +527,8 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_HM12 v4l2_fourcc('H', 'M', '1', '2') /* 8 YUV 4:2:0 16x16 macroblocks */
#define V4L2_PIX_FMT_M420 v4l2_fourcc('M', '4', '2', '0') /* 12 YUV 4:2:0 2 lines y, 1 line uv interleaved */
+#define V4L2_PIX_FMT_MT21 v4l2_fourcc('M', 'T', '2', '1') /* Mediatek Block Mode */
+
/* two planes -- one Y, one Cr + Cb interleaved */
#define V4L2_PIX_FMT_NV12 v4l2_fourcc('N', 'V', '1', '2') /* 12 Y/CbCr 4:2:0 */
#define V4L2_PIX_FMT_NV21 v4l2_fourcc('N', 'V', '2', '1') /* 12 Y/CrCb 4:2:0 */
--
1.7.9.5
[toc] | [prev] | [next] | [standalone]
| From | Nicolas Dufresne <nicolas.dufresne@gmail.com> |
|---|---|
| Date | 2016-04-13 16:30 +0200 |
| Subject | Re: [PATCH 1/7] [media]: v4l: add Mediatek MT21 video block format |
| Message-ID | <rntXQ-2yU-7@gated-at.bofh.it> |
| In reply to | #1377878 |
Le mercredi 13 avril 2016 à 20:01 +0800, Tiffany Lin a écrit :
> From: Daniel Kurtz <djkurtz@chromium.org>
>
> Mediatek video format is YVU8_420_2PLANE_PACK8_PROGRESSIVE.
>
> Create V4L2_PIX_FMT_MT21 and DRM_FORMAT_MT21 to be consistent with
> V4L2_PIX_FMT_NV12 notation.
>
> Signed-off-by: Tiffany Lin <tiffany.lin@mediatek.com>
> ---
> include/uapi/drm/drm_fourcc.h | 1 +
> include/uapi/linux/videodev2.h | 2 ++
Might be better to split this patch.
> 2 files changed, 3 insertions(+)
>
> diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
> index 0b69a77..a193905 100644
> --- a/include/uapi/drm/drm_fourcc.h
> +++ b/include/uapi/drm/drm_fourcc.h
> @@ -116,6 +116,7 @@
> #define DRM_FORMAT_NV24 fourcc_code('N', 'V', '2', '4') /* non-subsampled Cr:Cb plane */
> #define DRM_FORMAT_NV42 fourcc_code('N', 'V', '4', '2') /* non-subsampled Cb:Cr plane */
>
> +#define DRM_FORMAT_MT21 fourcc_code('M', 'T', '2', '1') /* Mediatek Block Mode */
Please document the tiling format, don't just add a define here.
> /*
> * 3 plane YCbCr
> * index 0: Y plane, [7:0] Y
> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> index d0acd26..e9e3276 100644
> --- a/include/uapi/linux/videodev2.h
> +++ b/include/uapi/linux/videodev2.h
> @@ -527,6 +527,8 @@ struct v4l2_pix_format {
> #define V4L2_PIX_FMT_HM12 v4l2_fourcc('H', 'M', '1', '2') /* 8 YUV 4:2:0 16x16 macroblocks */
> #define V4L2_PIX_FMT_M420 v4l2_fourcc('M', '4', '2', '0') /* 12 YUV 4:2:0 2 lines y, 1 line uv interleaved */
>
> +#define V4L2_PIX_FMT_MT21 v4l2_fourcc('M', 'T', '2', '1') /* Mediatek Block Mode */
> +
Same. On Linux Media side, there is docbook documentation where you can
explain in detail.
> /* two planes -- one Y, one Cr + Cb interleaved */
> #define V4L2_PIX_FMT_NV12 v4l2_fourcc('N', 'V', '1', '2') /* 12 Y/CbCr 4:2:0 */
> #define V4L2_PIX_FMT_NV21 v4l2_fourcc('N', 'V', '2', '1') /* 12 Y/CrCb 4:2:0 */
[toc] | [prev] | [next] | [standalone]
| From | tiffany lin <tiffany.lin@mediatek.com> |
|---|---|
| Date | 2016-04-14 08:20 +0200 |
| Subject | Re: [PATCH 1/7] [media]: v4l: add Mediatek MT21 video block format |
| Message-ID | <rnINc-5LS-7@gated-at.bofh.it> |
| In reply to | #1377986 |
Hi
On Wed, 2016-04-13 at 10:23 -0400, Nicolas Dufresne wrote:
> Le mercredi 13 avril 2016 à 20:01 +0800, Tiffany Lin a écrit :
> > From: Daniel Kurtz <djkurtz@chromium.org>
> >
> > Mediatek video format is YVU8_420_2PLANE_PACK8_PROGRESSIVE.
> >
> > Create V4L2_PIX_FMT_MT21 and DRM_FORMAT_MT21 to be consistent with
> > V4L2_PIX_FMT_NV12 notation.
> >
> > Signed-off-by: Tiffany Lin <tiffany.lin@mediatek.com>
> > ---
> > include/uapi/drm/drm_fourcc.h | 1 +
> > include/uapi/linux/videodev2.h | 2 ++
>
> Might be better to split this patch.
Got it, will split to two patch in next version.
>
> > 2 files changed, 3 insertions(+)
> >
> > diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
> > index 0b69a77..a193905 100644
> > --- a/include/uapi/drm/drm_fourcc.h
> > +++ b/include/uapi/drm/drm_fourcc.h
> > @@ -116,6 +116,7 @@
> > #define DRM_FORMAT_NV24 fourcc_code('N', 'V', '2', '4') /* non-subsampled Cr:Cb plane */
> > #define DRM_FORMAT_NV42 fourcc_code('N', 'V', '4', '2') /* non-subsampled Cb:Cr plane */
> >
> > +#define DRM_FORMAT_MT21 fourcc_code('M', 'T', '2', '1') /* Mediatek Block Mode */
>
> Please document the tiling format, don't just add a define here.
Got it, will add documentation in next version.
>
> > /*
> > * 3 plane YCbCr
> > * index 0: Y plane, [7:0] Y
> > diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> > index d0acd26..e9e3276 100644
> > --- a/include/uapi/linux/videodev2.h
> > +++ b/include/uapi/linux/videodev2.h
> > @@ -527,6 +527,8 @@ struct v4l2_pix_format {
> > #define V4L2_PIX_FMT_HM12 v4l2_fourcc('H', 'M', '1', '2') /* 8 YUV 4:2:0 16x16 macroblocks */
> > #define V4L2_PIX_FMT_M420 v4l2_fourcc('M', '4', '2', '0') /* 12 YUV 4:2:0 2 lines y, 1 line uv interleaved */
> >
> > +#define V4L2_PIX_FMT_MT21 v4l2_fourcc('M', 'T', '2', '1') /* Mediatek Block Mode */
> > +
>
> Same. On Linux Media side, there is docbook documentation where you can
> explain in detail.
Got it, will add documentation in next version.
>
> > /* two planes -- one Y, one Cr + Cb interleaved */
> > #define V4L2_PIX_FMT_NV12 v4l2_fourcc('N', 'V', '1', '2') /* 12 Y/CbCr 4:2:0 */
> > #define V4L2_PIX_FMT_NV21 v4l2_fourcc('N', 'V', '2', '1') /* 12 Y/CrCb 4:2:0 */
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web