build/patch/kernel/meson64-dev/0047-media-meson-vdec-add-MJPEG-decoding-support.patch
2019-01-21 01:18:20 -05:00

252 lines
7.8 KiB
Diff

From e795ad9070631877adb8cfabcf4f7c999acc5dad Mon Sep 17 00:00:00 2001
From: Maxime Jourdan <mjourdan@baylibre.com>
Date: Sun, 21 Oct 2018 15:14:27 +0200
Subject: [PATCH] media: meson: vdec: add MJPEG decoding support
Add support for V4L2_PIX_FMT_MJPEG
---
drivers/media/platform/meson/vdec/Makefile | 2 +-
.../media/platform/meson/vdec/codec_mjpeg.c | 140 ++++++++++++++++++
.../media/platform/meson/vdec/codec_mjpeg.h | 13 ++
.../media/platform/meson/vdec/vdec_platform.c | 31 ++++
4 files changed, 185 insertions(+), 1 deletion(-)
create mode 100644 drivers/media/platform/meson/vdec/codec_mjpeg.c
create mode 100644 drivers/media/platform/meson/vdec/codec_mjpeg.h
diff --git a/drivers/media/platform/meson/vdec/Makefile b/drivers/media/platform/meson/vdec/Makefile
index bb7a134e2728..acf07f3c3dac 100644
--- a/drivers/media/platform/meson/vdec/Makefile
+++ b/drivers/media/platform/meson/vdec/Makefile
@@ -3,6 +3,6 @@
meson-vdec-objs = esparser.o vdec.o vdec_ctrls.o vdec_helpers.o vdec_platform.o
meson-vdec-objs += vdec_1.o
-meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o
+meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o codec_mjpeg.o
obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o
diff --git a/drivers/media/platform/meson/vdec/codec_mjpeg.c b/drivers/media/platform/meson/vdec/codec_mjpeg.c
new file mode 100644
index 000000000000..abea9e3f944c
--- /dev/null
+++ b/drivers/media/platform/meson/vdec/codec_mjpeg.c
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
+ */
+
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "vdec_helpers.h"
+#include "dos_regs.h"
+
+/* map FW registers to known MJPEG functions */
+#define MREG_DECODE_PARAM AV_SCRATCH_2
+#define MREG_TO_AMRISC AV_SCRATCH_8
+#define MREG_FROM_AMRISC AV_SCRATCH_9
+#define MREG_FRAME_OFFSET AV_SCRATCH_A
+
+static int codec_mjpeg_can_recycle(struct amvdec_core *core)
+{
+ return !amvdec_read_dos(core, MREG_TO_AMRISC);
+}
+
+static void codec_mjpeg_recycle(struct amvdec_core *core, u32 buf_idx)
+{
+ amvdec_write_dos(core, MREG_TO_AMRISC, buf_idx + 1);
+}
+
+/* 4 point triangle */
+static const uint32_t filt_coef[] = {
+ 0x20402000, 0x20402000, 0x1f3f2101, 0x1f3f2101,
+ 0x1e3e2202, 0x1e3e2202, 0x1d3d2303, 0x1d3d2303,
+ 0x1c3c2404, 0x1c3c2404, 0x1b3b2505, 0x1b3b2505,
+ 0x1a3a2606, 0x1a3a2606, 0x19392707, 0x19392707,
+ 0x18382808, 0x18382808, 0x17372909, 0x17372909,
+ 0x16362a0a, 0x16362a0a, 0x15352b0b, 0x15352b0b,
+ 0x14342c0c, 0x14342c0c, 0x13332d0d, 0x13332d0d,
+ 0x12322e0e, 0x12322e0e, 0x11312f0f, 0x11312f0f,
+ 0x10303010
+};
+
+static void codec_mjpeg_init_scaler(struct amvdec_core *core)
+{
+ int i;
+
+ /* PSCALE cbus bmem enable */
+ amvdec_write_dos(core, PSCALE_CTRL, 0xc000);
+
+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 0);
+ for (i = 0; i < ARRAY_SIZE(filt_coef); ++i) {
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0);
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, filt_coef[i]);
+ }
+
+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 74);
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x0008);
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x60000000);
+
+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 82);
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x0008);
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x60000000);
+
+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 78);
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x0008);
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x60000000);
+
+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 86);
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x0008);
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x60000000);
+
+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 73);
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x10000);
+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 81);
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x10000);
+
+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 77);
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x10000);
+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 85);
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x10000);
+
+ amvdec_write_dos(core, PSCALE_RST, 0x7);
+ amvdec_write_dos(core, PSCALE_RST, 0);
+}
+
+static int codec_mjpeg_start(struct amvdec_session *sess)
+{
+ struct amvdec_core *core = sess->core;
+
+ amvdec_write_dos(core, AV_SCRATCH_0, 12);
+ amvdec_write_dos(core, AV_SCRATCH_1, 0x031a);
+
+ amvdec_set_canvases(sess, (u32[]){ AV_SCRATCH_4, 0 },
+ (u32[]){ 4, 0 });
+ codec_mjpeg_init_scaler(core);
+
+ amvdec_write_dos(core, MREG_TO_AMRISC, 0);
+ amvdec_write_dos(core, MREG_FROM_AMRISC, 0);
+ amvdec_write_dos(core, MCPU_INTR_MSK, 0xffff);
+ amvdec_write_dos(core, MREG_DECODE_PARAM,
+ (sess->height << 4) | 0x8000);
+ amvdec_write_dos(core, VDEC_ASSIST_AMR1_INT8, 8);
+
+ /* Intra-only codec */
+ sess->keyframe_found = 1;
+
+ return 0;
+}
+
+static int codec_mjpeg_stop(struct amvdec_session *sess)
+{
+ return 0;
+}
+
+static irqreturn_t codec_mjpeg_isr(struct amvdec_session *sess)
+{
+ struct amvdec_core *core = sess->core;
+ u32 reg;
+ u32 buffer_index;
+ u32 offset;
+
+ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1);
+
+ reg = amvdec_read_dos(core, MREG_FROM_AMRISC);
+ if (!(reg & 0x7))
+ return IRQ_HANDLED;
+
+ buffer_index = ((reg & 0x7) - 1) & 3;
+ offset = amvdec_read_dos(core, MREG_FRAME_OFFSET);
+ amvdec_dst_buf_done_idx(sess, buffer_index, offset, V4L2_FIELD_NONE);
+
+ amvdec_write_dos(core, MREG_FROM_AMRISC, 0);
+ return IRQ_HANDLED;
+}
+
+struct amvdec_codec_ops codec_mjpeg_ops = {
+ .start = codec_mjpeg_start,
+ .stop = codec_mjpeg_stop,
+ .isr = codec_mjpeg_isr,
+ .can_recycle = codec_mjpeg_can_recycle,
+ .recycle = codec_mjpeg_recycle,
+};
diff --git a/drivers/media/platform/meson/vdec/codec_mjpeg.h b/drivers/media/platform/meson/vdec/codec_mjpeg.h
new file mode 100644
index 000000000000..cc1cf731050d
--- /dev/null
+++ b/drivers/media/platform/meson/vdec/codec_mjpeg.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
+ */
+
+#ifndef __MESON_VDEC_CODEC_MJPEG_H_
+#define __MESON_VDEC_CODEC_MJPEG_H_
+
+#include "vdec.h"
+
+extern struct amvdec_codec_ops codec_mjpeg_ops;
+
+#endif
\ No newline at end of file
diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c
index 80b43fd5d01f..61def155a5fd 100644
--- a/drivers/media/platform/meson/vdec/vdec_platform.c
+++ b/drivers/media/platform/meson/vdec/vdec_platform.c
@@ -11,9 +11,20 @@
#include "codec_mpeg12.h"
#include "codec_h264.h"
#include "codec_mpeg4.h"
+#include "codec_mjpeg.h"
static const struct amvdec_format vdec_formats_gxbb[] = {
{
+ .pixfmt = V4L2_PIX_FMT_MJPEG,
+ .min_buffers = 4,
+ .max_buffers = 4,
+ .max_width = 1920,
+ .max_height = 1080,
+ .vdec_ops = &vdec_1_ops,
+ .codec_ops = &codec_mjpeg_ops,
+ .firmware_path = "meson/gx/vmjpeg_mc",
+ .pixfmts_cap = { V4L2_PIX_FMT_YUV420M, 0 },
+ }, {
.pixfmt = V4L2_PIX_FMT_MPEG4,
.min_buffers = 8,
.max_buffers = 8,
@@ -80,6 +91,16 @@ static const struct amvdec_format vdec_formats_gxbb[] = {
static const struct amvdec_format vdec_formats_gxl[] = {
{
+ .pixfmt = V4L2_PIX_FMT_MJPEG,
+ .min_buffers = 4,
+ .max_buffers = 4,
+ .max_width = 1920,
+ .max_height = 1080,
+ .vdec_ops = &vdec_1_ops,
+ .codec_ops = &codec_mjpeg_ops,
+ .firmware_path = "meson/gx/vmjpeg_mc",
+ .pixfmts_cap = { V4L2_PIX_FMT_YUV420M, 0 },
+ }, {
.pixfmt = V4L2_PIX_FMT_MPEG4,
.min_buffers = 8,
.max_buffers = 8,
@@ -146,6 +167,16 @@ static const struct amvdec_format vdec_formats_gxl[] = {
static const struct amvdec_format vdec_formats_gxm[] = {
{
+ .pixfmt = V4L2_PIX_FMT_MJPEG,
+ .min_buffers = 4,
+ .max_buffers = 4,
+ .max_width = 1920,
+ .max_height = 1080,
+ .vdec_ops = &vdec_1_ops,
+ .codec_ops = &codec_mjpeg_ops,
+ .firmware_path = "meson/gx/vmjpeg_mc",
+ .pixfmts_cap = { V4L2_PIX_FMT_YUV420M, 0 },
+ }, {
.pixfmt = V4L2_PIX_FMT_MPEG4,
.min_buffers = 8,
.max_buffers = 8,