Skip to content

Commit

Permalink
WIP: media: meson: vdec: add support for MPEG4 decoding
Browse files Browse the repository at this point in the history
Add support for V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_XVID and
V4L2_PIX_FMT_H.263. This is experimental !!!

Signed-off-by: Maxime Jourdan <[email protected]>
  • Loading branch information
Elyotna authored and chewitt committed Dec 12, 2020
1 parent 7243c89 commit c5377fb
Show file tree
Hide file tree
Showing 4 changed files with 305 additions and 1 deletion.
2 changes: 1 addition & 1 deletion drivers/staging/media/meson/vdec/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@

meson-vdec-objs = esparser.o vdec.o vdec_helpers.o vdec_platform.o
meson-vdec-objs += vdec_1.o vdec_hevc.o
meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_hevc_common.o codec_hevc.o codec_vp9.o
meson-vdec-objs += codec_mpeg12.o codec_mpeg4.o codec_h264.o codec_hevc_common.o codec_hevc.o codec_vp9.o

obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o
140 changes: 140 additions & 0 deletions drivers/staging/media/meson/vdec/codec_mpeg4.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2018 Maxime Jourdan <[email protected]>
*/

#include <media/v4l2-mem2mem.h>
#include <media/videobuf2-dma-contig.h>

#include "vdec_helpers.h"
#include "dos_regs.h"

#define SIZE_WORKSPACE SZ_1M
/* Offset added by firmware, to substract from workspace paddr */
#define DCAC_BUFF_START_IP 0x02b00000

/* map firmware registers to known MPEG4 functions */
#define MREG_BUFFERIN AV_SCRATCH_8
#define MREG_BUFFEROUT AV_SCRATCH_9
#define MP4_NOT_CODED_CNT AV_SCRATCH_A
#define MP4_OFFSET_REG AV_SCRATCH_C
#define MEM_OFFSET_REG AV_SCRATCH_F
#define MREG_FATAL_ERROR AV_SCRATCH_L

#define BUF_IDX_MASK GENMASK(2, 0)
#define INTERLACE_FLAG BIT(7)
#define TOP_FIELD_FIRST_FLAG BIT(6)

struct codec_mpeg4 {
/* Buffer for the MPEG4 Workspace */
void *workspace_vaddr;
dma_addr_t workspace_paddr;
};

static int codec_mpeg4_can_recycle(struct amvdec_core *core)
{
return !amvdec_read_dos(core, MREG_BUFFERIN);
}

static void codec_mpeg4_recycle(struct amvdec_core *core, u32 buf_idx)
{
amvdec_write_dos(core, MREG_BUFFERIN, ~BIT(buf_idx));
}

static int codec_mpeg4_start(struct amvdec_session *sess) {
struct amvdec_core *core = sess->core;
struct codec_mpeg4 *mpeg4 = sess->priv;
int ret;

mpeg4 = kzalloc(sizeof(*mpeg4), GFP_KERNEL);
if (!mpeg4)
return -ENOMEM;

/* Allocate some memory for the MPEG4 decoder's state */
mpeg4->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE,
&mpeg4->workspace_paddr,
GFP_KERNEL);
if (!mpeg4->workspace_vaddr) {
dev_err(core->dev, "Failed to request MPEG4 Workspace\n");
ret = -ENOMEM;
goto free_mpeg4;
}

/* Canvas regs: AV_SCRATCH_0-AV_SCRATCH_4;AV_SCRATCH_G-AV_SCRATCH_J */
amvdec_set_canvases(sess, (u32[]){ AV_SCRATCH_0, AV_SCRATCH_G, 0 },
(u32[]){ 4, 4, 0 });

amvdec_write_dos(core, MEM_OFFSET_REG,
mpeg4->workspace_paddr - DCAC_BUFF_START_IP);
amvdec_write_dos(core, PSCALE_CTRL, 0);
amvdec_write_dos(core, MP4_NOT_CODED_CNT, 0);
amvdec_write_dos(core, MREG_BUFFERIN, 0);
amvdec_write_dos(core, MREG_BUFFEROUT, 0);
amvdec_write_dos(core, MREG_FATAL_ERROR, 0);
amvdec_write_dos(core, MDEC_PIC_DC_THRESH, 0x404038aa);

sess->keyframe_found = 1;
sess->priv = mpeg4;

return 0;

free_mpeg4:
kfree(mpeg4);
return ret;
}

static int codec_mpeg4_stop(struct amvdec_session *sess)
{
struct codec_mpeg4 *mpeg4 = sess->priv;
struct amvdec_core *core = sess->core;

if (mpeg4->workspace_vaddr) {
dma_free_coherent(core->dev, SIZE_WORKSPACE,
mpeg4->workspace_vaddr,
mpeg4->workspace_paddr);
mpeg4->workspace_vaddr = 0;
}

return 0;
}

static irqreturn_t codec_mpeg4_isr(struct amvdec_session *sess)
{
struct amvdec_core *core = sess->core;
u32 reg;
u32 buffer_index;
u32 field = V4L2_FIELD_NONE;

reg = amvdec_read_dos(core, MREG_FATAL_ERROR);
if (reg == 1) {
dev_err(core->dev, "mpeg4 fatal error\n");
amvdec_abort(sess);
return IRQ_HANDLED;
}

reg = amvdec_read_dos(core, MREG_BUFFEROUT);
if (!reg)
goto end;

buffer_index = reg & BUF_IDX_MASK;
if (reg & INTERLACE_FLAG)
field = (reg & TOP_FIELD_FIRST_FLAG) ?
V4L2_FIELD_INTERLACED_TB :
V4L2_FIELD_INTERLACED_BT;

amvdec_dst_buf_done_idx(sess, buffer_index, -1, field);
amvdec_write_dos(core, MREG_BUFFEROUT, 0);

end:
amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1);
return IRQ_HANDLED;
}

struct amvdec_codec_ops codec_mpeg4_ops = {
.start = codec_mpeg4_start,
.stop = codec_mpeg4_stop,
.isr = codec_mpeg4_isr,
.can_recycle = codec_mpeg4_can_recycle,
.recycle = codec_mpeg4_recycle,
};

13 changes: 13 additions & 0 deletions drivers/staging/media/meson/vdec/codec_mpeg4.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2018 Maxime Jourdan <[email protected]>
*/

#ifndef __MESON_VDEC_CODEC_MPEG4_H_
#define __MESON_VDEC_CODEC_MPEG4_H_

#include "vdec.h"

extern struct amvdec_codec_ops codec_mpeg4_ops;

#endif
151 changes: 151 additions & 0 deletions drivers/staging/media/meson/vdec/vdec_platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,43 @@
#include "vdec_1.h"
#include "vdec_hevc.h"
#include "codec_mpeg12.h"
#include "codec_mpeg4.h"
#include "codec_h264.h"
#include "codec_hevc.h"
#include "codec_vp9.h"

static const struct amvdec_format vdec_formats_gxbb[] = {
{
.pixfmt = V4L2_PIX_FMT_MPEG4,
.min_buffers = 8,
.max_buffers = 8,
.max_width = 1920,
.max_height = 1080,
.vdec_ops = &vdec_1_ops,
.codec_ops = &codec_mpeg4_ops,
.firmware_path = "meson/vdec/gxl_mpeg4_5.bin",
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
}, {
.pixfmt = V4L2_PIX_FMT_H263,
.min_buffers = 8,
.max_buffers = 8,
.max_width = 1920,
.max_height = 1080,
.vdec_ops = &vdec_1_ops,
.codec_ops = &codec_mpeg4_ops,
.firmware_path = "meson/vdec/gxl_h263.bin",
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
}, {
.pixfmt = V4L2_PIX_FMT_XVID,
.min_buffers = 8,
.max_buffers = 8,
.max_width = 1920,
.max_height = 1080,
.vdec_ops = &vdec_1_ops,
.codec_ops = &codec_mpeg4_ops,
.firmware_path = "meson/vdec/gxl_mpeg4_5.bin",
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
}, {
.pixfmt = V4L2_PIX_FMT_H264,
.min_buffers = 2,
.max_buffers = 24,
Expand Down Expand Up @@ -54,6 +85,36 @@ static const struct amvdec_format vdec_formats_gxbb[] = {

static const struct amvdec_format vdec_formats_gxl[] = {
{
.pixfmt = V4L2_PIX_FMT_MPEG4,
.min_buffers = 8,
.max_buffers = 8,
.max_width = 1920,
.max_height = 1080,
.vdec_ops = &vdec_1_ops,
.codec_ops = &codec_mpeg4_ops,
.firmware_path = "meson/vdec/gxl_mpeg4_5.bin",
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
}, {
.pixfmt = V4L2_PIX_FMT_H263,
.min_buffers = 8,
.max_buffers = 8,
.max_width = 1920,
.max_height = 1080,
.vdec_ops = &vdec_1_ops,
.codec_ops = &codec_mpeg4_ops,
.firmware_path = "meson/vdec/gxl_h263.bin",
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
}, {
.pixfmt = V4L2_PIX_FMT_XVID,
.min_buffers = 8,
.max_buffers = 8,
.max_width = 1920,
.max_height = 1080,
.vdec_ops = &vdec_1_ops,
.codec_ops = &codec_mpeg4_ops,
.firmware_path = "meson/vdec/gxl_mpeg4_5.bin",
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
}, {
.pixfmt = V4L2_PIX_FMT_VP9,
.min_buffers = 16,
.max_buffers = 24,
Expand Down Expand Up @@ -116,6 +177,36 @@ static const struct amvdec_format vdec_formats_gxl[] = {

static const struct amvdec_format vdec_formats_gxm[] = {
{
.pixfmt = V4L2_PIX_FMT_MPEG4,
.min_buffers = 8,
.max_buffers = 8,
.max_width = 1920,
.max_height = 1080,
.vdec_ops = &vdec_1_ops,
.codec_ops = &codec_mpeg4_ops,
.firmware_path = "meson/vdec/gxl_mpeg4_5.bin",
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
}, {
.pixfmt = V4L2_PIX_FMT_H263,
.min_buffers = 8,
.max_buffers = 8,
.max_width = 1920,
.max_height = 1080,
.vdec_ops = &vdec_1_ops,
.codec_ops = &codec_mpeg4_ops,
.firmware_path = "meson/vdec/gxl_h263.bin",
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
}, {
.pixfmt = V4L2_PIX_FMT_XVID,
.min_buffers = 8,
.max_buffers = 8,
.max_width = 1920,
.max_height = 1080,
.vdec_ops = &vdec_1_ops,
.codec_ops = &codec_mpeg4_ops,
.firmware_path = "meson/vdec/gxl_mpeg4_5.bin",
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
}, {
.pixfmt = V4L2_PIX_FMT_H264,
.min_buffers = 2,
.max_buffers = 24,
Expand Down Expand Up @@ -166,6 +257,36 @@ static const struct amvdec_format vdec_formats_gxm[] = {

static const struct amvdec_format vdec_formats_g12a[] = {
{
.pixfmt = V4L2_PIX_FMT_MPEG4,
.min_buffers = 8,
.max_buffers = 8,
.max_width = 1920,
.max_height = 1080,
.vdec_ops = &vdec_1_ops,
.codec_ops = &codec_mpeg4_ops,
.firmware_path = "meson/vdec/gxl_mpeg4_5.bin",
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
}, {
.pixfmt = V4L2_PIX_FMT_H263,
.min_buffers = 8,
.max_buffers = 8,
.max_width = 1920,
.max_height = 1080,
.vdec_ops = &vdec_1_ops,
.codec_ops = &codec_mpeg4_ops,
.firmware_path = "meson/vdec/gxl_h263.bin",
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
}, {
.pixfmt = V4L2_PIX_FMT_XVID,
.min_buffers = 8,
.max_buffers = 8,
.max_width = 1920,
.max_height = 1080,
.vdec_ops = &vdec_1_ops,
.codec_ops = &codec_mpeg4_ops,
.firmware_path = "meson/vdec/gxl_mpeg4_5.bin",
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
}, {
.pixfmt = V4L2_PIX_FMT_VP9,
.min_buffers = 16,
.max_buffers = 24,
Expand Down Expand Up @@ -228,6 +349,36 @@ static const struct amvdec_format vdec_formats_g12a[] = {

static const struct amvdec_format vdec_formats_sm1[] = {
{
.pixfmt = V4L2_PIX_FMT_MPEG4,
.min_buffers = 8,
.max_buffers = 8,
.max_width = 1920,
.max_height = 1080,
.vdec_ops = &vdec_1_ops,
.codec_ops = &codec_mpeg4_ops,
.firmware_path = "meson/vdec/gxl_mpeg4_5.bin",
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
}, {
.pixfmt = V4L2_PIX_FMT_H263,
.min_buffers = 8,
.max_buffers = 8,
.max_width = 1920,
.max_height = 1080,
.vdec_ops = &vdec_1_ops,
.codec_ops = &codec_mpeg4_ops,
.firmware_path = "meson/vdec/gxl_h263.bin",
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
}, {
.pixfmt = V4L2_PIX_FMT_XVID,
.min_buffers = 8,
.max_buffers = 8,
.max_width = 1920,
.max_height = 1080,
.vdec_ops = &vdec_1_ops,
.codec_ops = &codec_mpeg4_ops,
.firmware_path = "meson/vdec/gxl_mpeg4_5.bin",
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
}, {
.pixfmt = V4L2_PIX_FMT_VP9,
.min_buffers = 16,
.max_buffers = 24,
Expand Down

0 comments on commit c5377fb

Please sign in to comment.