From 9a662159440cf5e0f55275ef63588e35c91c581e Mon Sep 17 00:00:00 2001 From: Maxime Jourdan 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 +- drivers/media/platform/meson/vdec/codec_mjpeg.c | 140 ++++++++++++++++++++++ drivers/media/platform/meson/vdec/codec_mjpeg.h | 13 ++ drivers/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 bb7a134..acf07f3 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 0000000..abea9e3 --- /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 + */ + +#include +#include + +#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 0000000..cc1cf73 --- /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 + */ + +#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 80b43fd..61def15 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,