Skip to content
Permalink
Browse files
media: amphion: add amphion vpu device driver
The amphion vpu codec ip contains encoder and decoder.
Windsor is the encoder, it supports to encode H.264.
Malone is the decoder, it features a powerful
video processing unit able to decode many foramts,
such as H.264, HEVC, and other foramts.

This Driver is for this IP that is based on the v4l2 mem2mem framework.

Supported SoCs are: IMX8QXP, IMX8QM

Signed-off-by: Ming Qian <ming.qian@nxp.com>
Signed-off-by: Shijie Qin <shijie.qin@nxp.com>
Signed-off-by: Zhou Peng <eagle.zhou@nxp.com>
Reported-by: kernel test robot <lkp@intel.com>
  • Loading branch information
mingqian-0 authored and intel-lab-lkp committed Oct 13, 2021
1 parent 361c929 commit d009494a2472451fb05646fe6439d7918790be2d
Show file tree
Hide file tree
Showing 8 changed files with 1,194 additions and 0 deletions.
@@ -200,6 +200,25 @@ config VIDEO_TI_CAL_MC

endif # VIDEO_TI_CAL

config VIDEO_AMPHION_VPU
tristate "Amphion VPU(Video Processing Unit) Codec IP"
depends on ARCH_MXC
depends on MEDIA_SUPPORT
depends on VIDEO_DEV
depends on VIDEO_V4L2
select V4L2_MEM2MEM_DEV
select VIDEOBUF2_DMA_CONTIG
select VIDEOBUF2_VMALLOC
default y
help
Amphion VPU Codec IP contains two parts: Windsor and Malone.
Windsor is encoder that supports H.264, and Malone is decoder
that supports H.264, HEVC, and other video formats.
This is a V4L2 driver for NXP MXC 8Q video accelerator hardware.
It accelerates encoding and decoding operations on
various NXP SoCs.
To compile this driver as a module choose m here.

endif # V4L_PLATFORM_DRIVERS

menuconfig V4L_MEM2MEM_DRIVERS
@@ -86,3 +86,5 @@ obj-$(CONFIG_VIDEO_QCOM_VENUS) += qcom/venus/
obj-y += sunxi/

obj-$(CONFIG_VIDEO_MESON_GE2D) += meson/ge2d/

obj-$(CONFIG_VIDEO_AMPHION_VPU) += amphion/
@@ -0,0 +1,20 @@
# SPDX-License-Identifier: GPL-2.0
# Makefile for NXP VPU driver

amphion-vpu-objs += vpu_drv.o \
vpu_core.o \
vpu_mbox.o \
vpu_v4l2.o \
vpu_helpers.o \
vpu_cmds.o \
vpu_msgs.o \
vpu_rpc.o \
vpu_imx8q.o \
vpu_windsor.o \
vpu_malone.o \
vpu_color.o \
vdec.o \
venc.o \
vpu_dbg.o

obj-$(CONFIG_VIDEO_AMPHION_VPU) += amphion-vpu.o
@@ -0,0 +1,344 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright 2020-2021 NXP
*/

#ifndef _AMPHION_VPU_H
#define _AMPHION_VPU_H

#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-mem2mem.h>
#include <linux/mailbox_client.h>
#include <linux/mailbox_controller.h>
#include <linux/kfifo.h>

#define VPU_TIMEOUT msecs_to_jiffies(1000)
#define VPU_INST_NULL_ID (-1L)
#define VPU_MSG_BUFFER_SIZE (8192)

enum imx_plat_type {
IMX8QXP = 0,
IMX8QM = 1,
IMX8DM,
IMX8DX,
PLAT_TYPE_RESERVED
};

enum vpu_core_type {
VPU_CORE_TYPE_ENC = 0,
VPU_CORE_TYPE_DEC = 0x10,
};

struct vpu_dev;
struct vpu_resources {
enum imx_plat_type plat_type;
u32 mreg_base;
int (*setup)(struct vpu_dev *vpu);
int (*setup_encoder)(struct vpu_dev *vpu);
int (*setup_decoder)(struct vpu_dev *vpu);
int (*reset)(struct vpu_dev *vpu);
};

struct vpu_buffer {
void *virt;
dma_addr_t phys;
u32 length;
u32 bytesused;
struct device *dev;
};

struct vpu_dev {
void __iomem *base;
struct platform_device *pdev;
struct device *dev;
struct mutex lock;
const struct vpu_resources *res;
struct list_head cores;

struct v4l2_device v4l2_dev;
struct video_device *vdev_dec;
struct video_device *vdev_enc;

struct delayed_work watchdog_work;
void (*get_vpu)(struct vpu_dev *vpu);
void (*put_vpu)(struct vpu_dev *vpu);
void (*get_enc)(struct vpu_dev *vpu);
void (*put_enc)(struct vpu_dev *vpu);
void (*get_dec)(struct vpu_dev *vpu);
void (*put_dec)(struct vpu_dev *vpu);
atomic_t ref_vpu;
atomic_t ref_enc;
atomic_t ref_dec;

struct dentry *debugfs;
};

struct vpu_format {
u32 pixfmt;
unsigned int num_planes;
u32 type;
u32 flags;
u32 width;
u32 height;
u32 sizeimage[VIDEO_MAX_PLANES];
u32 bytesperline[VIDEO_MAX_PLANES];
u32 field;
};

struct vpu_core_resources {
enum vpu_core_type type;
const char *fwname;
u32 stride;
u32 max_width;
u32 min_width;
u32 step_width;
u32 max_height;
u32 min_height;
u32 step_height;
u32 rpc_size;
u32 fwlog_size;
u32 act_size;
bool standalone;
};

struct vpu_mbox {
char name[20];
struct mbox_client cl;
struct mbox_chan *ch;
bool block;
};

enum vpu_core_state {
VPU_CORE_DEINIT = 0,
VPU_CORE_ACTIVE,
VPU_CORE_SNAPSHOT,
VPU_CORE_HANG
};

struct vpu_core {
void __iomem *base;
struct platform_device *pdev;
struct device *dev;
struct device *parent;
struct device *pd;
struct device_link *pd_link;
struct mutex lock;
struct mutex cmd_lock;
struct list_head list;
enum vpu_core_type type;
int id;
const struct vpu_core_resources *res;
unsigned long instance_mask;
u32 supported_instance_count;
unsigned long hang_mask;
u32 request_count;
struct list_head instances;
enum vpu_core_state state;
u32 fw_version;

struct vpu_buffer fw;
struct vpu_buffer rpc;
struct vpu_buffer log;
struct vpu_buffer act;

struct vpu_mbox tx_type;
struct vpu_mbox tx_data;
struct vpu_mbox rx;
unsigned long cmd_seq;

wait_queue_head_t ack_wq;
struct completion cmp;
struct workqueue_struct *workqueue;
struct work_struct msg_work;
struct delayed_work msg_delayed_work;
struct kfifo msg_fifo;
void *msg_buffer;
unsigned int msg_buffer_size;

struct vpu_dev *vpu;
void *iface;

struct dentry *debugfs;
struct dentry *debugfs_fwlog;
};

enum vpu_codec_state {
VPU_CODEC_STATE_DEINIT = 1,
VPU_CODEC_STATE_CONFIGURED,
VPU_CODEC_STATE_START,
VPU_CODEC_STATE_STARTED,
VPU_CODEC_STATE_ACTIVE,
VPU_CODEC_STATE_SEEK,
VPU_CODEC_STATE_STOP,
VPU_CODEC_STATE_DRAIN,
VPU_CODEC_STATE_DYAMIC_RESOLUTION_CHANGE,
};

struct vpu_frame_info {
u32 type;
u32 id;
u32 sequence;
u32 luma;
u32 chroma_u;
u32 chroma_v;
u32 data_offset;
u32 flags;
u32 skipped;
s64 timestamp;
};

struct vpu_inst;
struct vpu_inst_ops {
int (*ctrl_init)(struct vpu_inst *inst);
int (*start)(struct vpu_inst *inst, u32 type);
int (*stop)(struct vpu_inst *inst, u32 type);
int (*abort)(struct vpu_inst *inst);
bool (*check_ready)(struct vpu_inst *inst, unsigned int type);
void (*buf_done)(struct vpu_inst *inst, struct vpu_frame_info *frame);
void (*event_notify)(struct vpu_inst *inst, u32 event, void *data);
void (*release)(struct vpu_inst *inst);
void (*cleanup)(struct vpu_inst *inst);
void (*mem_request)(struct vpu_inst *inst,
u32 enc_frame_size,
u32 enc_frame_num,
u32 ref_frame_size,
u32 ref_frame_num,
u32 act_frame_size,
u32 act_frame_num);
void (*input_done)(struct vpu_inst *inst);
void (*stop_done)(struct vpu_inst *inst);
int (*process_output)(struct vpu_inst *inst, struct vb2_buffer *vb);
int (*process_capture)(struct vpu_inst *inst, struct vb2_buffer *vb);
int (*get_one_frame)(struct vpu_inst *inst, void *info);
void (*on_queue_empty)(struct vpu_inst *inst, u32 type);
int (*get_debug_info)(struct vpu_inst *inst, char *str, u32 size, u32 i);
void (*wait_prepare)(struct vpu_inst *inst);
void (*wait_finish)(struct vpu_inst *inst);
};

struct vpu_inst {
struct list_head list;
struct mutex lock;
struct vpu_core *core;
struct device *dev;
int id;

struct v4l2_fh fh;
struct v4l2_m2m_dev *m2m_dev;
struct v4l2_m2m_ctx *m2m_ctx;
struct v4l2_ctrl_handler ctrl_handler;
atomic_t ref_count;
int (*release)(struct vpu_inst *inst);

enum vpu_codec_state state;
enum vpu_core_type type;

struct workqueue_struct *workqueue;
struct work_struct msg_work;
struct kfifo msg_fifo;
u8 msg_buffer[VPU_MSG_BUFFER_SIZE];

struct vpu_buffer stream_buffer;
bool use_stream_buffer;
struct vpu_buffer act;

struct list_head cmd_q;
void *pending;

struct vpu_inst_ops *ops;
const struct vpu_format *formats;
struct vpu_format out_format;
struct vpu_format cap_format;
u32 min_buffer_cap;
u32 min_buffer_out;

struct v4l2_rect crop;
u32 colorspace;
u8 ycbcr_enc;
u8 quantization;
u8 xfer_func;
u32 sequence;
u32 extra_size;

u32 flows[16];
u32 flow_idx;

pid_t pid;
pid_t tgid;
struct dentry *debugfs;

void *priv;
};

#define call_vop(inst, op, args...) \
((inst)->ops->op ? (inst)->ops->op(inst, ##args) : 0) \

enum {
VPU_BUF_STATE_IDLE = 0,
VPU_BUF_STATE_INUSE,
VPU_BUF_STATE_DECODED,
VPU_BUF_STATE_READY,
VPU_BUF_STATE_SKIP,
VPU_BUF_STATE_ERROR
};

struct vpu_vb2_buffer {
struct v4l2_m2m_buffer m2m_buf;
dma_addr_t luma;
dma_addr_t chroma_u;
dma_addr_t chroma_v;
unsigned int state;
u32 tag;
};

void vpu_writel(struct vpu_dev *vpu, u32 reg, u32 val);
u32 vpu_readl(struct vpu_dev *vpu, u32 reg);

static inline struct vpu_vb2_buffer *to_vpu_vb2_buffer(struct vb2_v4l2_buffer *vbuf)
{
struct v4l2_m2m_buffer *m2m_buf = container_of(vbuf, struct v4l2_m2m_buffer, vb);

return container_of(m2m_buf, struct vpu_vb2_buffer, m2m_buf);
}

static inline const char *vpu_core_type_desc(enum vpu_core_type type)
{
return type == VPU_CORE_TYPE_ENC ? "encoder" : "decoder";
}

static inline struct vpu_inst *to_inst(struct file *filp)
{
return container_of(filp->private_data, struct vpu_inst, fh);
}

#define ctrl_to_inst(ctrl) \
container_of((ctrl)->handler, struct vpu_inst, ctrl_handler)

int venc_create_video_device(struct vpu_dev *vpu);
int vdec_create_video_device(struct vpu_dev *vpu);

struct vpu_inst *vpu_inst_get(struct vpu_inst *inst);
void vpu_inst_put(struct vpu_inst *inst);
struct vpu_core *vpu_request_core(struct vpu_dev *vpu, enum vpu_core_type type);
void vpu_release_core(struct vpu_core *core);
int vpu_inst_register(struct vpu_inst *inst);
int vpu_inst_unregister(struct vpu_inst *inst);

int vpu_inst_create_dbgfs_file(struct vpu_inst *inst);
int vpu_inst_remove_dbgfs_file(struct vpu_inst *inst);
int vpu_core_create_dbgfs_file(struct vpu_core *core);
int vpu_core_remove_dbgfs_file(struct vpu_core *core);
void vpu_inst_record_flow(struct vpu_inst *inst, u32 flow);

int vpu_core_driver_init(void);
void vpu_core_driver_exit(void);

extern bool debug;
#define vpu_trace(dev, fmt, arg...) \
do { \
if (debug) \
dev_info(dev, "%s: " fmt, __func__, ## arg); \
} while (0)

#endif

0 comments on commit d009494

Please sign in to comment.