-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
media: chips-media: wave5: Add the v4l2 layer
Add the decoder and encoder implementing the v4l2 API. This patch also adds the Makefile and the VIDEO_WAVE_VPU config Signed-off-by: Sebastian Fricke <sebastian.fricke@collabora.com> Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com> Signed-off-by: Robert Beckett <bob.beckett@collabora.com> Signed-off-by: Dafna Hirschfeld <dafna.hirschfeld@collabora.com> Signed-off-by: Nas Chung <nas.chung@chipsnmedia.com> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
- Loading branch information
Nas Chung
authored and
Hans Verkuil
committed
Nov 16, 2023
1 parent
45d1a2b
commit 9707a62
Showing
10 changed files
with
4,368 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
# SPDX-License-Identifier: GPL-2.0-only | ||
|
||
obj-y += coda/ | ||
obj-y += wave5/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# SPDX-License-Identifier: GPL-2.0 | ||
config VIDEO_WAVE_VPU | ||
tristate "Chips&Media Wave Codec Driver" | ||
depends on VIDEO_DEV | ||
select VIDEOBUF2_DMA_CONTIG | ||
select VIDEOBUF2_VMALLOC | ||
select V4L2_MEM2MEM_DEV | ||
help | ||
Chips&Media stateful encoder and decoder driver. | ||
The driver supports HEVC and H264 formats. | ||
To compile this driver as modules, choose M here: the | ||
modules will be called wave5. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# SPDX-License-Identifier: GPL-2.0 | ||
|
||
obj-$(CONFIG_VIDEO_WAVE_VPU) += wave5.o | ||
wave5-objs += wave5-hw.o \ | ||
wave5-vpuapi.o \ | ||
wave5-vdi.o \ | ||
wave5-vpu-dec.o \ | ||
wave5-vpu.o \ | ||
wave5-vpu-enc.o \ | ||
wave5-helper.o |
213 changes: 213 additions & 0 deletions
213
drivers/media/platform/chips-media/wave5/wave5-helper.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,213 @@ | ||
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) | ||
/* | ||
* Wave5 series multi-standard codec IP - decoder interface | ||
* | ||
* Copyright (C) 2021-2023 CHIPS&MEDIA INC | ||
*/ | ||
|
||
#include "wave5-helper.h" | ||
|
||
const char *state_to_str(enum vpu_instance_state state) | ||
{ | ||
switch (state) { | ||
case VPU_INST_STATE_NONE: | ||
return "NONE"; | ||
case VPU_INST_STATE_OPEN: | ||
return "OPEN"; | ||
case VPU_INST_STATE_INIT_SEQ: | ||
return "INIT_SEQ"; | ||
case VPU_INST_STATE_PIC_RUN: | ||
return "PIC_RUN"; | ||
case VPU_INST_STATE_STOP: | ||
return "STOP"; | ||
default: | ||
return "UNKNOWN"; | ||
} | ||
} | ||
|
||
void wave5_cleanup_instance(struct vpu_instance *inst) | ||
{ | ||
int i; | ||
|
||
if (list_is_singular(&inst->list)) | ||
wave5_vdi_free_sram(inst->dev); | ||
|
||
for (i = 0; i < inst->fbc_buf_count; i++) | ||
wave5_vpu_dec_reset_framebuffer(inst, i); | ||
|
||
wave5_vdi_free_dma_memory(inst->dev, &inst->bitstream_vbuf); | ||
v4l2_ctrl_handler_free(&inst->v4l2_ctrl_hdl); | ||
if (inst->v4l2_fh.vdev) { | ||
v4l2_fh_del(&inst->v4l2_fh); | ||
v4l2_fh_exit(&inst->v4l2_fh); | ||
} | ||
list_del_init(&inst->list); | ||
ida_free(&inst->dev->inst_ida, inst->id); | ||
kfree(inst->codec_info); | ||
kfree(inst); | ||
} | ||
|
||
int wave5_vpu_release_device(struct file *filp, | ||
int (*close_func)(struct vpu_instance *inst, u32 *fail_res), | ||
char *name) | ||
{ | ||
struct vpu_instance *inst = wave5_to_vpu_inst(filp->private_data); | ||
|
||
v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx); | ||
if (inst->state != VPU_INST_STATE_NONE) { | ||
u32 fail_res; | ||
int ret; | ||
|
||
ret = close_func(inst, &fail_res); | ||
if (fail_res == WAVE5_SYSERR_VPU_STILL_RUNNING) { | ||
dev_err(inst->dev->dev, "%s close failed, device is still running\n", | ||
name); | ||
return -EBUSY; | ||
} | ||
if (ret && ret != -EIO) { | ||
dev_err(inst->dev->dev, "%s close, fail: %d\n", name, ret); | ||
return ret; | ||
} | ||
} | ||
|
||
wave5_cleanup_instance(inst); | ||
|
||
return 0; | ||
} | ||
|
||
int wave5_vpu_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq, | ||
const struct vb2_ops *ops) | ||
{ | ||
struct vpu_instance *inst = priv; | ||
int ret; | ||
|
||
src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | ||
src_vq->io_modes = VB2_MMAP | VB2_DMABUF; | ||
src_vq->mem_ops = &vb2_dma_contig_memops; | ||
src_vq->ops = ops; | ||
src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; | ||
src_vq->buf_struct_size = sizeof(struct vpu_src_buffer); | ||
src_vq->drv_priv = inst; | ||
src_vq->lock = &inst->dev->dev_lock; | ||
src_vq->dev = inst->dev->v4l2_dev.dev; | ||
ret = vb2_queue_init(src_vq); | ||
if (ret) | ||
return ret; | ||
|
||
dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | ||
dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; | ||
dst_vq->mem_ops = &vb2_dma_contig_memops; | ||
dst_vq->ops = ops; | ||
dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; | ||
dst_vq->buf_struct_size = sizeof(struct vpu_src_buffer); | ||
dst_vq->drv_priv = inst; | ||
dst_vq->lock = &inst->dev->dev_lock; | ||
dst_vq->dev = inst->dev->v4l2_dev.dev; | ||
ret = vb2_queue_init(dst_vq); | ||
if (ret) | ||
return ret; | ||
|
||
return 0; | ||
} | ||
|
||
int wave5_vpu_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) | ||
{ | ||
struct vpu_instance *inst = wave5_to_vpu_inst(fh); | ||
bool is_decoder = inst->type == VPU_INST_TYPE_DEC; | ||
|
||
dev_dbg(inst->dev->dev, "%s: [%s] type: %u id: %u | flags: %u\n", __func__, | ||
is_decoder ? "decoder" : "encoder", sub->type, sub->id, sub->flags); | ||
|
||
switch (sub->type) { | ||
case V4L2_EVENT_EOS: | ||
return v4l2_event_subscribe(fh, sub, 0, NULL); | ||
case V4L2_EVENT_SOURCE_CHANGE: | ||
if (is_decoder) | ||
return v4l2_src_change_event_subscribe(fh, sub); | ||
return -EINVAL; | ||
case V4L2_EVENT_CTRL: | ||
return v4l2_ctrl_subscribe_event(fh, sub); | ||
default: | ||
return -EINVAL; | ||
} | ||
} | ||
|
||
int wave5_vpu_g_fmt_out(struct file *file, void *fh, struct v4l2_format *f) | ||
{ | ||
struct vpu_instance *inst = wave5_to_vpu_inst(fh); | ||
int i; | ||
|
||
f->fmt.pix_mp.width = inst->src_fmt.width; | ||
f->fmt.pix_mp.height = inst->src_fmt.height; | ||
f->fmt.pix_mp.pixelformat = inst->src_fmt.pixelformat; | ||
f->fmt.pix_mp.field = inst->src_fmt.field; | ||
f->fmt.pix_mp.flags = inst->src_fmt.flags; | ||
f->fmt.pix_mp.num_planes = inst->src_fmt.num_planes; | ||
for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { | ||
f->fmt.pix_mp.plane_fmt[i].bytesperline = inst->src_fmt.plane_fmt[i].bytesperline; | ||
f->fmt.pix_mp.plane_fmt[i].sizeimage = inst->src_fmt.plane_fmt[i].sizeimage; | ||
} | ||
|
||
f->fmt.pix_mp.colorspace = inst->colorspace; | ||
f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc; | ||
f->fmt.pix_mp.quantization = inst->quantization; | ||
f->fmt.pix_mp.xfer_func = inst->xfer_func; | ||
|
||
return 0; | ||
} | ||
|
||
const struct vpu_format *wave5_find_vpu_fmt(unsigned int v4l2_pix_fmt, | ||
const struct vpu_format fmt_list[MAX_FMTS]) | ||
{ | ||
unsigned int index; | ||
|
||
for (index = 0; index < MAX_FMTS; index++) { | ||
if (fmt_list[index].v4l2_pix_fmt == v4l2_pix_fmt) | ||
return &fmt_list[index]; | ||
} | ||
|
||
return NULL; | ||
} | ||
|
||
const struct vpu_format *wave5_find_vpu_fmt_by_idx(unsigned int idx, | ||
const struct vpu_format fmt_list[MAX_FMTS]) | ||
{ | ||
if (idx >= MAX_FMTS) | ||
return NULL; | ||
|
||
if (!fmt_list[idx].v4l2_pix_fmt) | ||
return NULL; | ||
|
||
return &fmt_list[idx]; | ||
} | ||
|
||
enum wave_std wave5_to_vpu_std(unsigned int v4l2_pix_fmt, enum vpu_instance_type type) | ||
{ | ||
switch (v4l2_pix_fmt) { | ||
case V4L2_PIX_FMT_H264: | ||
return type == VPU_INST_TYPE_DEC ? W_AVC_DEC : W_AVC_ENC; | ||
case V4L2_PIX_FMT_HEVC: | ||
return type == VPU_INST_TYPE_DEC ? W_HEVC_DEC : W_HEVC_ENC; | ||
default: | ||
return STD_UNKNOWN; | ||
} | ||
} | ||
|
||
void wave5_return_bufs(struct vb2_queue *q, u32 state) | ||
{ | ||
struct vpu_instance *inst = vb2_get_drv_priv(q); | ||
struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; | ||
struct v4l2_ctrl_handler v4l2_ctrl_hdl = inst->v4l2_ctrl_hdl; | ||
struct vb2_v4l2_buffer *vbuf; | ||
|
||
for (;;) { | ||
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | ||
vbuf = v4l2_m2m_src_buf_remove(m2m_ctx); | ||
else | ||
vbuf = v4l2_m2m_dst_buf_remove(m2m_ctx); | ||
if (!vbuf) | ||
return; | ||
v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, &v4l2_ctrl_hdl); | ||
v4l2_m2m_buf_done(vbuf, state); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ | ||
/* | ||
* Wave5 series multi-standard codec IP - basic types | ||
* | ||
* Copyright (C) 2021-2023 CHIPS&MEDIA INC | ||
*/ | ||
|
||
#ifndef __WAVE_HELPER_H__ | ||
#define __WAVE_HELPER_H__ | ||
|
||
#include "wave5-vpu.h" | ||
|
||
#define FMT_TYPES 2 | ||
#define MAX_FMTS 12 | ||
|
||
const char *state_to_str(enum vpu_instance_state state); | ||
void wave5_cleanup_instance(struct vpu_instance *inst); | ||
int wave5_vpu_release_device(struct file *filp, | ||
int (*close_func)(struct vpu_instance *inst, u32 *fail_res), | ||
char *name); | ||
int wave5_vpu_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq, | ||
const struct vb2_ops *ops); | ||
int wave5_vpu_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub); | ||
int wave5_vpu_g_fmt_out(struct file *file, void *fh, struct v4l2_format *f); | ||
const struct vpu_format *wave5_find_vpu_fmt(unsigned int v4l2_pix_fmt, | ||
const struct vpu_format fmt_list[MAX_FMTS]); | ||
const struct vpu_format *wave5_find_vpu_fmt_by_idx(unsigned int idx, | ||
const struct vpu_format fmt_list[MAX_FMTS]); | ||
enum wave_std wave5_to_vpu_std(unsigned int v4l2_pix_fmt, enum vpu_instance_type type); | ||
void wave5_return_bufs(struct vb2_queue *q, u32 state); | ||
#endif |
Oops, something went wrong.