summaryrefslogtreecommitdiff
path: root/drivers/media/platform/chips-media
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/chips-media')
-rw-r--r--drivers/media/platform/chips-media/coda/coda-bit.c2
-rw-r--r--drivers/media/platform/chips-media/coda/coda-common.c5
-rw-r--r--drivers/media/platform/chips-media/coda/coda-jpeg.c2
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-helper.c36
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-helper.h5
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-hw.c425
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-regdefine.h5
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vdi.c27
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c390
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c324
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpu.c210
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpu.h5
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpuapi.c43
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpuapi.h8
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h43
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5.h9
16 files changed, 1007 insertions, 532 deletions
diff --git a/drivers/media/platform/chips-media/coda/coda-bit.c b/drivers/media/platform/chips-media/coda/coda-bit.c
index ed47d5bd8d61..84ded154adfe 100644
--- a/drivers/media/platform/chips-media/coda/coda-bit.c
+++ b/drivers/media/platform/chips-media/coda/coda-bit.c
@@ -585,7 +585,7 @@ static int coda_alloc_context_buffers(struct coda_ctx *ctx,
if (!ctx->slicebuf.vaddr && q_data->fourcc == V4L2_PIX_FMT_H264) {
/* worst case slice size */
- size = (DIV_ROUND_UP(q_data->rect.width, 16) *
+ size = (unsigned long)(DIV_ROUND_UP(q_data->rect.width, 16) *
DIV_ROUND_UP(q_data->rect.height, 16)) * 3200 / 8 + 512;
ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size,
"slicebuf");
diff --git a/drivers/media/platform/chips-media/coda/coda-common.c b/drivers/media/platform/chips-media/coda/coda-common.c
index 7da0194ec850..e6e3f5ec24f6 100644
--- a/drivers/media/platform/chips-media/coda/coda-common.c
+++ b/drivers/media/platform/chips-media/coda/coda-common.c
@@ -2171,8 +2171,6 @@ static const struct vb2_ops coda_qops = {
.buf_queue = coda_buf_queue,
.start_streaming = coda_start_streaming,
.stop_streaming = coda_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
@@ -3342,11 +3340,12 @@ static int coda_runtime_resume(struct device *dev)
static const struct dev_pm_ops coda_pm_ops = {
SET_RUNTIME_PM_OPS(NULL, coda_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static struct platform_driver coda_driver = {
.probe = coda_probe,
- .remove_new = coda_remove,
+ .remove = coda_remove,
.driver = {
.name = CODA_NAME,
.of_match_table = coda_dt_ids,
diff --git a/drivers/media/platform/chips-media/coda/coda-jpeg.c b/drivers/media/platform/chips-media/coda/coda-jpeg.c
index ba8f41002917..5746892658b1 100644
--- a/drivers/media/platform/chips-media/coda/coda-jpeg.c
+++ b/drivers/media/platform/chips-media/coda/coda-jpeg.c
@@ -5,7 +5,7 @@
* Copyright (C) 2014 Philipp Zabel, Pengutronix
*/
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/irqreturn.h>
#include <linux/kernel.h>
#include <linux/ktime.h>
diff --git a/drivers/media/platform/chips-media/wave5/wave5-helper.c b/drivers/media/platform/chips-media/wave5/wave5-helper.c
index 8433ecab230c..2c9d8cbca6e4 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-helper.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-helper.c
@@ -7,6 +7,8 @@
#include "wave5-helper.h"
+#define DEFAULT_BS_SIZE(width, height) ((width) * (height) / 8 * 3)
+
const char *state_to_str(enum vpu_instance_state state)
{
switch (state) {
@@ -29,7 +31,13 @@ void wave5_cleanup_instance(struct vpu_instance *inst)
{
int i;
- if (list_is_singular(&inst->list))
+ /*
+ * For Wave515 SRAM memory is allocated at
+ * wave5_vpu_dec_register_device() and freed at
+ * wave5_vpu_dec_unregister_device().
+ */
+ if (list_is_singular(&inst->list) &&
+ inst->dev->product_code != WAVE515_CODE)
wave5_vdi_free_sram(inst->dev);
for (i = 0; i < inst->fbc_buf_count; i++)
@@ -52,11 +60,11 @@ int wave5_vpu_release_device(struct file *filp,
char *name)
{
struct vpu_instance *inst = wave5_to_vpu_inst(filp->private_data);
+ int ret = 0;
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) {
@@ -72,7 +80,7 @@ int wave5_vpu_release_device(struct file *filp,
wave5_cleanup_instance(inst);
- return 0;
+ return ret;
}
int wave5_vpu_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq,
@@ -211,3 +219,25 @@ void wave5_return_bufs(struct vb2_queue *q, u32 state)
v4l2_m2m_buf_done(vbuf, state);
}
}
+
+void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp,
+ int pix_fmt_type,
+ unsigned int width,
+ unsigned int height,
+ const struct v4l2_frmsize_stepwise *frmsize)
+{
+ v4l2_apply_frmsize_constraints(&width, &height, frmsize);
+
+ if (pix_fmt_type == VPU_FMT_TYPE_CODEC) {
+ pix_mp->width = width;
+ pix_mp->height = height;
+ pix_mp->num_planes = 1;
+ pix_mp->plane_fmt[0].bytesperline = 0;
+ pix_mp->plane_fmt[0].sizeimage = max(DEFAULT_BS_SIZE(width, height),
+ pix_mp->plane_fmt[0].sizeimage);
+ } else {
+ v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, width, height);
+ }
+ pix_mp->flags = 0;
+ pix_mp->field = V4L2_FIELD_NONE;
+}
diff --git a/drivers/media/platform/chips-media/wave5/wave5-helper.h b/drivers/media/platform/chips-media/wave5/wave5-helper.h
index 6cee1c14d3ce..9937fce553fc 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-helper.h
+++ b/drivers/media/platform/chips-media/wave5/wave5-helper.h
@@ -28,4 +28,9 @@ 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);
+void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp,
+ int pix_fmt_type,
+ unsigned int width,
+ unsigned int height,
+ const struct v4l2_frmsize_stepwise *frmsize);
#endif
diff --git a/drivers/media/platform/chips-media/wave5/wave5-hw.c b/drivers/media/platform/chips-media/wave5/wave5-hw.c
index 2d82791f575e..d94cf84c3ee5 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-hw.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-hw.c
@@ -18,22 +18,33 @@
#define QUEUE_REPORT_MASK 0xffff
/* Encoder support fields */
-#define FEATURE_HEVC10BIT_ENC BIT(3)
-#define FEATURE_AVC10BIT_ENC BIT(11)
-#define FEATURE_AVC_ENCODER BIT(1)
-#define FEATURE_HEVC_ENCODER BIT(0)
+#define W521_FEATURE_HEVC10BIT_ENC BIT(3)
+#define W521_FEATURE_AVC10BIT_ENC BIT(11)
+#define W521_FEATURE_AVC_ENCODER BIT(1)
+#define W521_FEATURE_HEVC_ENCODER BIT(0)
+
+#define ENC_AVC_INTRA_IDR_PARAM_MASK 0x7ff
+#define ENC_AVC_INTRA_PERIOD_SHIFT 6
+#define ENC_AVC_IDR_PERIOD_SHIFT 17
+#define ENC_AVC_FORCED_IDR_HEADER_SHIFT 28
+
+#define ENC_HEVC_INTRA_QP_SHIFT 3
+#define ENC_HEVC_FORCED_IDR_HEADER_SHIFT 9
+#define ENC_HEVC_INTRA_PERIOD_SHIFT 16
/* Decoder support fields */
-#define FEATURE_AVC_DECODER BIT(3)
-#define FEATURE_HEVC_DECODER BIT(2)
+#define W521_FEATURE_AVC_DECODER BIT(3)
+#define W521_FEATURE_HEVC_DECODER BIT(2)
+#define W515_FEATURE_HEVC10BIT_DEC BIT(1)
+#define W515_FEATURE_HEVC_DECODER BIT(0)
-#define FEATURE_BACKBONE BIT(16)
-#define FEATURE_VCORE_BACKBONE BIT(22)
-#define FEATURE_VCPU_BACKBONE BIT(28)
+#define W521_FEATURE_BACKBONE BIT(16)
+#define W521_FEATURE_VCORE_BACKBONE BIT(22)
+#define W521_FEATURE_VCPU_BACKBONE BIT(28)
#define REMAP_CTRL_MAX_SIZE_BITS ((W5_REMAP_MAX_SIZE >> 12) & 0x1ff)
#define REMAP_CTRL_REGISTER_VALUE(index) ( \
- (BIT(31) | (index << 12) | BIT(11) | REMAP_CTRL_MAX_SIZE_BITS) \
+ (BIT(31) | ((index) << 12) | BIT(11) | REMAP_CTRL_MAX_SIZE_BITS)\
)
#define FASTIO_ADDRESS_MASK GENMASK(15, 0)
@@ -155,6 +166,8 @@ static int wave5_wait_bus_busy(struct vpu_device *vpu_dev, unsigned int addr)
{
u32 gdi_status_check_value = 0x3f;
+ if (vpu_dev->product_code == WAVE515_CODE)
+ gdi_status_check_value = 0x0738;
if (vpu_dev->product_code == WAVE521C_CODE ||
vpu_dev->product_code == WAVE521_CODE ||
vpu_dev->product_code == WAVE521E1_CODE)
@@ -186,6 +199,8 @@ unsigned int wave5_vpu_get_product_id(struct vpu_device *vpu_dev)
u32 val = vpu_read_reg(vpu_dev, W5_PRODUCT_NUMBER);
switch (val) {
+ case WAVE515_CODE:
+ return PRODUCT_ID_515;
case WAVE521C_CODE:
return PRODUCT_ID_521;
case WAVE521_CODE:
@@ -299,6 +314,27 @@ static int wave5_send_query(struct vpu_device *vpu_dev, struct vpu_instance *ins
return wave5_vpu_firmware_command_queue_error_check(vpu_dev, NULL);
}
+static void setup_wave5_interrupts(struct vpu_device *vpu_dev)
+{
+ u32 reg_val = 0;
+
+ if (vpu_dev->attr.support_encoders) {
+ /* Encoder interrupt */
+ reg_val |= BIT(INT_WAVE5_ENC_SET_PARAM);
+ reg_val |= BIT(INT_WAVE5_ENC_PIC);
+ reg_val |= BIT(INT_WAVE5_BSBUF_FULL);
+ }
+
+ if (vpu_dev->attr.support_decoders) {
+ /* Decoder interrupt */
+ reg_val |= BIT(INT_WAVE5_INIT_SEQ);
+ reg_val |= BIT(INT_WAVE5_DEC_PIC);
+ reg_val |= BIT(INT_WAVE5_BSBUF_EMPTY);
+ }
+
+ return vpu_write_reg(vpu_dev, W5_VPU_VINT_ENABLE, reg_val);
+}
+
static int setup_wave5_properties(struct device *dev)
{
struct vpu_device *vpu_dev = dev_get_drvdata(dev);
@@ -328,17 +364,35 @@ static int setup_wave5_properties(struct device *dev)
hw_config_def1 = vpu_read_reg(vpu_dev, W5_RET_STD_DEF1);
hw_config_feature = vpu_read_reg(vpu_dev, W5_RET_CONF_FEATURE);
- p_attr->support_hevc10bit_enc = FIELD_GET(FEATURE_HEVC10BIT_ENC, hw_config_feature);
- p_attr->support_avc10bit_enc = FIELD_GET(FEATURE_AVC10BIT_ENC, hw_config_feature);
-
- p_attr->support_decoders = FIELD_GET(FEATURE_AVC_DECODER, hw_config_def1) << STD_AVC;
- p_attr->support_decoders |= FIELD_GET(FEATURE_HEVC_DECODER, hw_config_def1) << STD_HEVC;
- p_attr->support_encoders = FIELD_GET(FEATURE_AVC_ENCODER, hw_config_def1) << STD_AVC;
- p_attr->support_encoders |= FIELD_GET(FEATURE_HEVC_ENCODER, hw_config_def1) << STD_HEVC;
-
- p_attr->support_backbone = FIELD_GET(FEATURE_BACKBONE, hw_config_def0);
- p_attr->support_vcpu_backbone = FIELD_GET(FEATURE_VCPU_BACKBONE, hw_config_def0);
- p_attr->support_vcore_backbone = FIELD_GET(FEATURE_VCORE_BACKBONE, hw_config_def0);
+ if (vpu_dev->product_code == WAVE515_CODE) {
+ p_attr->support_hevc10bit_dec = FIELD_GET(W515_FEATURE_HEVC10BIT_DEC,
+ hw_config_feature);
+ p_attr->support_decoders = FIELD_GET(W515_FEATURE_HEVC_DECODER,
+ hw_config_def1) << STD_HEVC;
+ } else {
+ p_attr->support_hevc10bit_enc = FIELD_GET(W521_FEATURE_HEVC10BIT_ENC,
+ hw_config_feature);
+ p_attr->support_avc10bit_enc = FIELD_GET(W521_FEATURE_AVC10BIT_ENC,
+ hw_config_feature);
+
+ p_attr->support_decoders = FIELD_GET(W521_FEATURE_AVC_DECODER,
+ hw_config_def1) << STD_AVC;
+ p_attr->support_decoders |= FIELD_GET(W521_FEATURE_HEVC_DECODER,
+ hw_config_def1) << STD_HEVC;
+ p_attr->support_encoders = FIELD_GET(W521_FEATURE_AVC_ENCODER,
+ hw_config_def1) << STD_AVC;
+ p_attr->support_encoders |= FIELD_GET(W521_FEATURE_HEVC_ENCODER,
+ hw_config_def1) << STD_HEVC;
+
+ p_attr->support_backbone = FIELD_GET(W521_FEATURE_BACKBONE,
+ hw_config_def0);
+ p_attr->support_vcpu_backbone = FIELD_GET(W521_FEATURE_VCPU_BACKBONE,
+ hw_config_def0);
+ p_attr->support_vcore_backbone = FIELD_GET(W521_FEATURE_VCORE_BACKBONE,
+ hw_config_def0);
+ }
+
+ setup_wave5_interrupts(vpu_dev);
return 0;
}
@@ -380,12 +434,18 @@ int wave5_vpu_init(struct device *dev, u8 *fw, size_t size)
common_vb = &vpu_dev->common_mem;
code_base = common_vb->daddr;
+
+ if (vpu_dev->product_code == WAVE515_CODE)
+ code_size = WAVE515_MAX_CODE_BUF_SIZE;
+ else
+ code_size = WAVE521_MAX_CODE_BUF_SIZE;
+
/* ALIGN TO 4KB */
- code_size = (WAVE5_MAX_CODE_BUF_SIZE & ~0xfff);
+ code_size &= ~0xfff;
if (code_size < size * 2)
return -EINVAL;
- temp_base = common_vb->daddr + WAVE5_TEMPBUF_OFFSET;
+ temp_base = code_base + code_size;
temp_size = WAVE5_TEMPBUF_SIZE;
ret = wave5_vdi_write_memory(vpu_dev, common_vb, 0, fw, size);
@@ -413,22 +473,15 @@ int wave5_vpu_init(struct device *dev, u8 *fw, size_t size)
/* These register must be reset explicitly */
vpu_write_reg(vpu_dev, W5_HW_OPTION, 0);
- wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0);
- wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0);
- vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0);
-
- /* Encoder interrupt */
- reg_val = BIT(INT_WAVE5_ENC_SET_PARAM);
- reg_val |= BIT(INT_WAVE5_ENC_PIC);
- reg_val |= BIT(INT_WAVE5_BSBUF_FULL);
- /* Decoder interrupt */
- reg_val |= BIT(INT_WAVE5_INIT_SEQ);
- reg_val |= BIT(INT_WAVE5_DEC_PIC);
- reg_val |= BIT(INT_WAVE5_BSBUF_EMPTY);
- vpu_write_reg(vpu_dev, W5_VPU_VINT_ENABLE, reg_val);
+
+ if (vpu_dev->product_code != WAVE515_CODE) {
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0);
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0);
+ vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0);
+ }
reg_val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0);
- if (FIELD_GET(FEATURE_BACKBONE, reg_val)) {
+ if (FIELD_GET(W521_FEATURE_BACKBONE, reg_val)) {
reg_val = ((WAVE5_PROC_AXI_ID << 28) |
(WAVE5_PRP_AXI_ID << 24) |
(WAVE5_FBD_Y_AXI_ID << 20) |
@@ -440,6 +493,24 @@ int wave5_vpu_init(struct device *dev, u8 *fw, size_t size)
wave5_fio_writel(vpu_dev, W5_BACKBONE_PROG_AXI_ID, reg_val);
}
+ if (vpu_dev->product_code == WAVE515_CODE) {
+ dma_addr_t task_buf_base;
+
+ vpu_write_reg(vpu_dev, W5_CMD_INIT_NUM_TASK_BUF, WAVE515_COMMAND_QUEUE_DEPTH);
+ vpu_write_reg(vpu_dev, W5_CMD_INIT_TASK_BUF_SIZE, WAVE515_ONE_TASKBUF_SIZE);
+
+ for (i = 0; i < WAVE515_COMMAND_QUEUE_DEPTH; i++) {
+ task_buf_base = temp_base + temp_size +
+ (i * WAVE515_ONE_TASKBUF_SIZE);
+ vpu_write_reg(vpu_dev,
+ W5_CMD_INIT_ADDR_TASK_BUF0 + (i * 4),
+ task_buf_base);
+ }
+
+ vpu_write_reg(vpu_dev, W515_CMD_ADDR_SEC_AXI, vpu_dev->sram_buf.daddr);
+ vpu_write_reg(vpu_dev, W515_CMD_SEC_AXI_SIZE, vpu_dev->sram_buf.size);
+ }
+
vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1);
vpu_write_reg(vpu_dev, W5_COMMAND, W5_INIT_VPU);
vpu_write_reg(vpu_dev, W5_VPU_REMAP_CORE_START, 1);
@@ -480,30 +551,41 @@ int wave5_vpu_build_up_dec_param(struct vpu_instance *inst,
return -EINVAL;
}
- p_dec_info->vb_work.size = WAVE521DEC_WORKBUF_SIZE;
+ if (vpu_dev->product == PRODUCT_ID_515)
+ p_dec_info->vb_work.size = WAVE515DEC_WORKBUF_SIZE;
+ else
+ p_dec_info->vb_work.size = WAVE521DEC_WORKBUF_SIZE;
+
ret = wave5_vdi_allocate_dma_memory(inst->dev, &p_dec_info->vb_work);
if (ret)
return ret;
- vpu_write_reg(inst->dev, W5_CMD_DEC_VCORE_INFO, 1);
+ if (inst->dev->product_code != WAVE515_CODE)
+ vpu_write_reg(inst->dev, W5_CMD_DEC_VCORE_INFO, 1);
wave5_vdi_clear_memory(inst->dev, &p_dec_info->vb_work);
vpu_write_reg(inst->dev, W5_ADDR_WORK_BASE, p_dec_info->vb_work.daddr);
vpu_write_reg(inst->dev, W5_WORK_SIZE, p_dec_info->vb_work.size);
- vpu_write_reg(inst->dev, W5_CMD_ADDR_SEC_AXI, vpu_dev->sram_buf.daddr);
- vpu_write_reg(inst->dev, W5_CMD_SEC_AXI_SIZE, vpu_dev->sram_buf.size);
+ if (inst->dev->product_code != WAVE515_CODE) {
+ vpu_write_reg(inst->dev, W5_CMD_ADDR_SEC_AXI, vpu_dev->sram_buf.daddr);
+ vpu_write_reg(inst->dev, W5_CMD_SEC_AXI_SIZE, vpu_dev->sram_buf.size);
+ }
vpu_write_reg(inst->dev, W5_CMD_DEC_BS_START_ADDR, p_dec_info->stream_buf_start_addr);
vpu_write_reg(inst->dev, W5_CMD_DEC_BS_SIZE, p_dec_info->stream_buf_size);
/* NOTE: SDMA reads MSB first */
vpu_write_reg(inst->dev, W5_CMD_BS_PARAM, BITSTREAM_ENDIANNESS_BIG_ENDIAN);
- /* This register must be reset explicitly */
- vpu_write_reg(inst->dev, W5_CMD_EXT_ADDR, 0);
- vpu_write_reg(inst->dev, W5_CMD_NUM_CQ_DEPTH_M1, (COMMAND_QUEUE_DEPTH - 1));
+ if (inst->dev->product_code != WAVE515_CODE) {
+ /* This register must be reset explicitly */
+ vpu_write_reg(inst->dev, W5_CMD_EXT_ADDR, 0);
+ vpu_write_reg(inst->dev, W5_CMD_NUM_CQ_DEPTH_M1,
+ WAVE521_COMMAND_QUEUE_DEPTH - 1);
+ }
+ vpu_write_reg(inst->dev, W5_CMD_ERR_CONCEAL, 0);
ret = send_firmware_command(inst, W5_CREATE_INSTANCE, true, NULL, NULL);
if (ret) {
wave5_vdi_free_dma_memory(vpu_dev, &p_dec_info->vb_work);
@@ -553,7 +635,7 @@ static u32 get_bitstream_options(struct dec_info *info)
int wave5_vpu_dec_init_seq(struct vpu_instance *inst)
{
struct dec_info *p_dec_info = &inst->codec_info->dec_info;
- u32 cmd_option = INIT_SEQ_NORMAL;
+ u32 bs_option, cmd_option = INIT_SEQ_NORMAL;
u32 reg_val, fail_res;
int ret;
@@ -563,7 +645,13 @@ int wave5_vpu_dec_init_seq(struct vpu_instance *inst)
vpu_write_reg(inst->dev, W5_BS_RD_PTR, p_dec_info->stream_rd_ptr);
vpu_write_reg(inst->dev, W5_BS_WR_PTR, p_dec_info->stream_wr_ptr);
- vpu_write_reg(inst->dev, W5_BS_OPTION, get_bitstream_options(p_dec_info));
+ bs_option = get_bitstream_options(p_dec_info);
+
+ /* Without RD_PTR_VALID_FLAG Wave515 ignores RD_PTR value */
+ if (inst->dev->product_code == WAVE515_CODE)
+ bs_option |= BSOPTION_RD_PTR_VALID_FLAG;
+
+ vpu_write_reg(inst->dev, W5_BS_OPTION, bs_option);
vpu_write_reg(inst->dev, W5_COMMAND_OPTION, cmd_option);
vpu_write_reg(inst->dev, W5_CMD_DEC_USER_MASK, p_dec_info->user_data_enable);
@@ -629,10 +717,12 @@ static void wave5_get_dec_seq_result(struct vpu_instance *inst, struct dec_initi
info->profile = FIELD_GET(SEQ_PARAM_PROFILE_MASK, reg_val);
}
- info->vlc_buf_size = vpu_read_reg(inst->dev, W5_RET_VLC_BUF_SIZE);
- info->param_buf_size = vpu_read_reg(inst->dev, W5_RET_PARAM_BUF_SIZE);
- p_dec_info->vlc_buf_size = info->vlc_buf_size;
- p_dec_info->param_buf_size = info->param_buf_size;
+ if (inst->dev->product_code != WAVE515_CODE) {
+ info->vlc_buf_size = vpu_read_reg(inst->dev, W5_RET_VLC_BUF_SIZE);
+ info->param_buf_size = vpu_read_reg(inst->dev, W5_RET_PARAM_BUF_SIZE);
+ p_dec_info->vlc_buf_size = info->vlc_buf_size;
+ p_dec_info->param_buf_size = info->param_buf_size;
+ }
}
int wave5_vpu_dec_get_seq_info(struct vpu_instance *inst, struct dec_initial_info *info)
@@ -734,22 +824,27 @@ int wave5_vpu_dec_register_framebuffer(struct vpu_instance *inst, struct frame_b
pic_size = (init_info->pic_width << 16) | (init_info->pic_height);
- vb_buf.size = (p_dec_info->vlc_buf_size * VLC_BUF_NUM) +
- (p_dec_info->param_buf_size * COMMAND_QUEUE_DEPTH);
- vb_buf.daddr = 0;
+ if (inst->dev->product_code != WAVE515_CODE) {
+ vb_buf.size = (p_dec_info->vlc_buf_size * VLC_BUF_NUM) +
+ (p_dec_info->param_buf_size * WAVE521_COMMAND_QUEUE_DEPTH);
+ vb_buf.daddr = 0;
- if (vb_buf.size != p_dec_info->vb_task.size) {
- wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_task);
- ret = wave5_vdi_allocate_dma_memory(inst->dev, &vb_buf);
- if (ret)
- goto free_fbc_c_tbl_buffers;
+ if (vb_buf.size != p_dec_info->vb_task.size) {
+ wave5_vdi_free_dma_memory(inst->dev,
+ &p_dec_info->vb_task);
+ ret = wave5_vdi_allocate_dma_memory(inst->dev,
+ &vb_buf);
+ if (ret)
+ goto free_fbc_c_tbl_buffers;
- p_dec_info->vb_task = vb_buf;
- }
+ p_dec_info->vb_task = vb_buf;
+ }
- vpu_write_reg(inst->dev, W5_CMD_SET_FB_ADDR_TASK_BUF,
- p_dec_info->vb_task.daddr);
- vpu_write_reg(inst->dev, W5_CMD_SET_FB_TASK_BUF_SIZE, vb_buf.size);
+ vpu_write_reg(inst->dev, W5_CMD_SET_FB_ADDR_TASK_BUF,
+ p_dec_info->vb_task.daddr);
+ vpu_write_reg(inst->dev, W5_CMD_SET_FB_TASK_BUF_SIZE,
+ vb_buf.size);
+ }
} else {
pic_size = (init_info->pic_width << 16) | (init_info->pic_height);
@@ -830,6 +925,43 @@ free_mv_buffers:
return ret;
}
+static u32 wave5_vpu_dec_validate_sec_axi(struct vpu_instance *inst)
+{
+ u32 bitdepth = inst->codec_info->dec_info.initial_info.luma_bitdepth;
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ u32 bit_size = 0, ip_size = 0, lf_size = 0, ret = 0;
+ u32 sram_size = inst->dev->sram_size;
+ u32 width = inst->src_fmt.width;
+
+ if (!sram_size)
+ return 0;
+
+ /*
+ * TODO: calculate bit_size, ip_size, lf_size from width and bitdepth
+ * for Wave521.
+ */
+ if (inst->dev->product_code == WAVE515_CODE) {
+ bit_size = DIV_ROUND_UP(width, 16) * 5 * 8;
+ ip_size = ALIGN(width, 16) * 2 * bitdepth / 8;
+ lf_size = ALIGN(width, 16) * 10 * bitdepth / 8;
+ }
+
+ if (p_dec_info->sec_axi_info.use_bit_enable && sram_size >= bit_size) {
+ ret |= BIT(0);
+ sram_size -= bit_size;
+ }
+
+ if (p_dec_info->sec_axi_info.use_ip_enable && sram_size >= ip_size) {
+ ret |= BIT(9);
+ sram_size -= ip_size;
+ }
+
+ if (p_dec_info->sec_axi_info.use_lf_row_enable && sram_size >= lf_size)
+ ret |= BIT(15);
+
+ return ret;
+}
+
int wave5_vpu_decode(struct vpu_instance *inst, u32 *fail_res)
{
u32 reg_val;
@@ -842,9 +974,7 @@ int wave5_vpu_decode(struct vpu_instance *inst, u32 *fail_res)
vpu_write_reg(inst->dev, W5_BS_OPTION, get_bitstream_options(p_dec_info));
/* secondary AXI */
- reg_val = p_dec_info->sec_axi_info.use_bit_enable |
- (p_dec_info->sec_axi_info.use_ip_enable << 9) |
- (p_dec_info->sec_axi_info.use_lf_row_enable << 15);
+ reg_val = wave5_vpu_dec_validate_sec_axi(inst);
vpu_write_reg(inst->dev, W5_USE_SEC_AXI, reg_val);
/* set attributes of user buffer */
@@ -992,11 +1122,18 @@ int wave5_vpu_re_init(struct device *dev, u8 *fw, size_t size)
common_vb = &vpu_dev->common_mem;
code_base = common_vb->daddr;
+
+ if (vpu_dev->product_code == WAVE515_CODE)
+ code_size = WAVE515_MAX_CODE_BUF_SIZE;
+ else
+ code_size = WAVE521_MAX_CODE_BUF_SIZE;
+
/* ALIGN TO 4KB */
- code_size = (WAVE5_MAX_CODE_BUF_SIZE & ~0xfff);
+ code_size &= ~0xfff;
if (code_size < size * 2)
return -EINVAL;
- temp_base = common_vb->daddr + WAVE5_TEMPBUF_OFFSET;
+
+ temp_base = code_base + code_size;
temp_size = WAVE5_TEMPBUF_SIZE;
old_code_base = vpu_read_reg(vpu_dev, W5_VPU_REMAP_PADDR);
@@ -1030,22 +1167,15 @@ int wave5_vpu_re_init(struct device *dev, u8 *fw, size_t size)
/* These register must be reset explicitly */
vpu_write_reg(vpu_dev, W5_HW_OPTION, 0);
- wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0);
- wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0);
- vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0);
- /* Encoder interrupt */
- reg_val = BIT(INT_WAVE5_ENC_SET_PARAM);
- reg_val |= BIT(INT_WAVE5_ENC_PIC);
- reg_val |= BIT(INT_WAVE5_BSBUF_FULL);
- /* Decoder interrupt */
- reg_val |= BIT(INT_WAVE5_INIT_SEQ);
- reg_val |= BIT(INT_WAVE5_DEC_PIC);
- reg_val |= BIT(INT_WAVE5_BSBUF_EMPTY);
- vpu_write_reg(vpu_dev, W5_VPU_VINT_ENABLE, reg_val);
+ if (vpu_dev->product_code != WAVE515_CODE) {
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0);
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0);
+ vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0);
+ }
reg_val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0);
- if (FIELD_GET(FEATURE_BACKBONE, reg_val)) {
+ if (FIELD_GET(W521_FEATURE_BACKBONE, reg_val)) {
reg_val = ((WAVE5_PROC_AXI_ID << 28) |
(WAVE5_PRP_AXI_ID << 24) |
(WAVE5_FBD_Y_AXI_ID << 20) |
@@ -1057,6 +1187,29 @@ int wave5_vpu_re_init(struct device *dev, u8 *fw, size_t size)
wave5_fio_writel(vpu_dev, W5_BACKBONE_PROG_AXI_ID, reg_val);
}
+ if (vpu_dev->product_code == WAVE515_CODE) {
+ dma_addr_t task_buf_base;
+ u32 i;
+
+ vpu_write_reg(vpu_dev, W5_CMD_INIT_NUM_TASK_BUF,
+ WAVE515_COMMAND_QUEUE_DEPTH);
+ vpu_write_reg(vpu_dev, W5_CMD_INIT_TASK_BUF_SIZE,
+ WAVE515_ONE_TASKBUF_SIZE);
+
+ for (i = 0; i < WAVE515_COMMAND_QUEUE_DEPTH; i++) {
+ task_buf_base = temp_base + temp_size +
+ (i * WAVE515_ONE_TASKBUF_SIZE);
+ vpu_write_reg(vpu_dev,
+ W5_CMD_INIT_ADDR_TASK_BUF0 + (i * 4),
+ task_buf_base);
+ }
+
+ vpu_write_reg(vpu_dev, W515_CMD_ADDR_SEC_AXI,
+ vpu_dev->sram_buf.daddr);
+ vpu_write_reg(vpu_dev, W515_CMD_SEC_AXI_SIZE,
+ vpu_dev->sram_buf.size);
+ }
+
vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1);
vpu_write_reg(vpu_dev, W5_COMMAND, W5_INIT_VPU);
vpu_write_reg(vpu_dev, W5_VPU_REMAP_CORE_START, 1);
@@ -1075,13 +1228,13 @@ int wave5_vpu_re_init(struct device *dev, u8 *fw, size_t size)
return setup_wave5_properties(dev);
}
-static int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uint16_t *code,
- size_t size)
+int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uint16_t *code,
+ size_t size)
{
u32 reg_val;
struct vpu_buf *common_vb;
- dma_addr_t code_base;
- u32 code_size, reason_code;
+ dma_addr_t code_base, temp_base;
+ u32 code_size, temp_size, reason_code;
struct vpu_device *vpu_dev = dev_get_drvdata(dev);
int ret;
@@ -1111,13 +1264,22 @@ static int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uin
common_vb = &vpu_dev->common_mem;
code_base = common_vb->daddr;
+
+ if (vpu_dev->product_code == WAVE515_CODE)
+ code_size = WAVE515_MAX_CODE_BUF_SIZE;
+ else
+ code_size = WAVE521_MAX_CODE_BUF_SIZE;
+
/* ALIGN TO 4KB */
- code_size = (WAVE5_MAX_CODE_BUF_SIZE & ~0xfff);
+ code_size &= ~0xfff;
if (code_size < size * 2) {
dev_err(dev, "size too small\n");
return -EINVAL;
}
+ temp_base = code_base + code_size;
+ temp_size = WAVE5_TEMPBUF_SIZE;
+
/* Power on without DEBUG mode */
vpu_write_reg(vpu_dev, W5_PO_CONF, 0);
@@ -1130,22 +1292,17 @@ static int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uin
/* These register must be reset explicitly */
vpu_write_reg(vpu_dev, W5_HW_OPTION, 0);
- wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0);
- wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0);
- vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0);
- /* Encoder interrupt */
- reg_val = BIT(INT_WAVE5_ENC_SET_PARAM);
- reg_val |= BIT(INT_WAVE5_ENC_PIC);
- reg_val |= BIT(INT_WAVE5_BSBUF_FULL);
- /* Decoder interrupt */
- reg_val |= BIT(INT_WAVE5_INIT_SEQ);
- reg_val |= BIT(INT_WAVE5_DEC_PIC);
- reg_val |= BIT(INT_WAVE5_BSBUF_EMPTY);
- vpu_write_reg(vpu_dev, W5_VPU_VINT_ENABLE, reg_val);
+ if (vpu_dev->product_code != WAVE515_CODE) {
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0);
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0);
+ vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0);
+ }
+
+ setup_wave5_interrupts(vpu_dev);
reg_val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0);
- if (FIELD_GET(FEATURE_BACKBONE, reg_val)) {
+ if (FIELD_GET(W521_FEATURE_BACKBONE, reg_val)) {
reg_val = ((WAVE5_PROC_AXI_ID << 28) |
(WAVE5_PRP_AXI_ID << 24) |
(WAVE5_FBD_Y_AXI_ID << 20) |
@@ -1157,6 +1314,29 @@ static int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uin
wave5_fio_writel(vpu_dev, W5_BACKBONE_PROG_AXI_ID, reg_val);
}
+ if (vpu_dev->product_code == WAVE515_CODE) {
+ dma_addr_t task_buf_base;
+ u32 i;
+
+ vpu_write_reg(vpu_dev, W5_CMD_INIT_NUM_TASK_BUF,
+ WAVE515_COMMAND_QUEUE_DEPTH);
+ vpu_write_reg(vpu_dev, W5_CMD_INIT_TASK_BUF_SIZE,
+ WAVE515_ONE_TASKBUF_SIZE);
+
+ for (i = 0; i < WAVE515_COMMAND_QUEUE_DEPTH; i++) {
+ task_buf_base = temp_base + temp_size +
+ (i * WAVE515_ONE_TASKBUF_SIZE);
+ vpu_write_reg(vpu_dev,
+ W5_CMD_INIT_ADDR_TASK_BUF0 + (i * 4),
+ task_buf_base);
+ }
+
+ vpu_write_reg(vpu_dev, W515_CMD_ADDR_SEC_AXI,
+ vpu_dev->sram_buf.daddr);
+ vpu_write_reg(vpu_dev, W515_CMD_SEC_AXI_SIZE,
+ vpu_dev->sram_buf.size);
+ }
+
vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1);
vpu_write_reg(vpu_dev, W5_COMMAND, W5_WAKEUP_VPU);
/* Start VPU after settings */
@@ -1401,7 +1581,7 @@ int wave5_vpu_build_up_enc_param(struct device *dev, struct vpu_instance *inst,
reg_val = (open_param->line_buf_int_en << 6) | BITSTREAM_ENDIANNESS_BIG_ENDIAN;
vpu_write_reg(inst->dev, W5_CMD_BS_PARAM, reg_val);
vpu_write_reg(inst->dev, W5_CMD_EXT_ADDR, 0);
- vpu_write_reg(inst->dev, W5_CMD_NUM_CQ_DEPTH_M1, (COMMAND_QUEUE_DEPTH - 1));
+ vpu_write_reg(inst->dev, W5_CMD_NUM_CQ_DEPTH_M1, WAVE521_COMMAND_QUEUE_DEPTH - 1);
/* This register must be reset explicitly */
vpu_write_reg(inst->dev, W5_CMD_ENC_SRC_OPTIONS, 0);
@@ -1601,12 +1781,19 @@ int wave5_vpu_enc_init_seq(struct vpu_instance *inst)
if (inst->std == W_AVC_ENC)
vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INTRA_PARAM, p_param->intra_qp |
- ((p_param->intra_period & 0x7ff) << 6) |
- ((p_param->avc_idr_period & 0x7ff) << 17));
+ ((p_param->intra_period & ENC_AVC_INTRA_IDR_PARAM_MASK)
+ << ENC_AVC_INTRA_PERIOD_SHIFT) |
+ ((p_param->avc_idr_period & ENC_AVC_INTRA_IDR_PARAM_MASK)
+ << ENC_AVC_IDR_PERIOD_SHIFT) |
+ (p_param->forced_idr_header_enable
+ << ENC_AVC_FORCED_IDR_HEADER_SHIFT));
else if (inst->std == W_HEVC_ENC)
vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INTRA_PARAM,
- p_param->decoding_refresh_type | (p_param->intra_qp << 3) |
- (p_param->intra_period << 16));
+ p_param->decoding_refresh_type |
+ (p_param->intra_qp << ENC_HEVC_INTRA_QP_SHIFT) |
+ (p_param->forced_idr_header_enable
+ << ENC_HEVC_FORCED_IDR_HEADER_SHIFT) |
+ (p_param->intra_period << ENC_HEVC_INTRA_PERIOD_SHIFT));
reg_val = (p_param->rdo_skip << 2) |
(p_param->lambda_scaling_enable << 3) |
@@ -1855,7 +2042,7 @@ int wave5_vpu_enc_register_framebuffer(struct device *dev, struct vpu_instance *
p_enc_info->vb_sub_sam_buf = vb_sub_sam_buf;
vb_task.size = (p_enc_info->vlc_buf_size * VLC_BUF_NUM) +
- (p_enc_info->param_buf_size * COMMAND_QUEUE_DEPTH);
+ (p_enc_info->param_buf_size * WAVE521_COMMAND_QUEUE_DEPTH);
vb_task.daddr = 0;
if (p_enc_info->vb_task.size == 0) {
ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_task);
@@ -1943,6 +2130,31 @@ free_vb_fbc_y_tbl:
return ret;
}
+static u32 wave5_vpu_enc_validate_sec_axi(struct vpu_instance *inst)
+{
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+ u32 rdo_size = 0, lf_size = 0, ret = 0;
+ u32 sram_size = inst->dev->sram_size;
+
+ if (!sram_size)
+ return 0;
+
+ /*
+ * TODO: calculate rdo_size and lf_size from inst->src_fmt.width and
+ * inst->codec_info->enc_info.open_param.wave_param.internal_bit_depth
+ */
+
+ if (p_enc_info->sec_axi_info.use_enc_rdo_enable && sram_size >= rdo_size) {
+ ret |= BIT(11);
+ sram_size -= rdo_size;
+ }
+
+ if (p_enc_info->sec_axi_info.use_enc_lf_enable && sram_size >= lf_size)
+ ret |= BIT(15);
+
+ return ret;
+}
+
int wave5_vpu_encode(struct vpu_instance *inst, struct enc_param *option, u32 *fail_res)
{
u32 src_frame_format;
@@ -1964,8 +2176,7 @@ int wave5_vpu_encode(struct vpu_instance *inst, struct enc_param *option, u32 *f
vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_AXI_SEL, DEFAULT_SRC_AXI);
/* secondary AXI */
- reg_val = (p_enc_info->sec_axi_info.use_enc_rdo_enable << 11) |
- (p_enc_info->sec_axi_info.use_enc_lf_enable << 15);
+ reg_val = wave5_vpu_enc_validate_sec_axi(inst);
vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_USE_SEC_AXI, reg_val);
vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_REPORT_PARAM, 0);
diff --git a/drivers/media/platform/chips-media/wave5/wave5-regdefine.h b/drivers/media/platform/chips-media/wave5/wave5-regdefine.h
index a15c6b2c3d8b..557344754c4c 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-regdefine.h
+++ b/drivers/media/platform/chips-media/wave5/wave5-regdefine.h
@@ -205,6 +205,9 @@ enum query_opt {
#define W5_ADDR_TEMP_BASE (W5_REG_BASE + 0x011C)
#define W5_TEMP_SIZE (W5_REG_BASE + 0x0120)
#define W5_HW_OPTION (W5_REG_BASE + 0x012C)
+#define W5_CMD_INIT_NUM_TASK_BUF (W5_REG_BASE + 0x0134)
+#define W5_CMD_INIT_ADDR_TASK_BUF0 (W5_REG_BASE + 0x0138)
+#define W5_CMD_INIT_TASK_BUF_SIZE (W5_REG_BASE + 0x0178)
#define W5_SEC_AXI_PARAM (W5_REG_BASE + 0x0180)
/************************************************************************/
@@ -216,7 +219,9 @@ enum query_opt {
#define W5_CMD_DEC_BS_SIZE (W5_REG_BASE + 0x0120)
#define W5_CMD_BS_PARAM (W5_REG_BASE + 0x0124)
#define W5_CMD_ADDR_SEC_AXI (W5_REG_BASE + 0x0130)
+#define W515_CMD_ADDR_SEC_AXI (W5_REG_BASE + 0x0124)
#define W5_CMD_SEC_AXI_SIZE (W5_REG_BASE + 0x0134)
+#define W515_CMD_SEC_AXI_SIZE (W5_REG_BASE + 0x0128)
#define W5_CMD_EXT_ADDR (W5_REG_BASE + 0x0138)
#define W5_CMD_NUM_CQ_DEPTH_M1 (W5_REG_BASE + 0x013C)
#define W5_CMD_ERR_CONCEAL (W5_REG_BASE + 0x0140)
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vdi.c b/drivers/media/platform/chips-media/wave5/wave5-vdi.c
index 3809f70bc0b4..bb13267ced38 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vdi.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-vdi.c
@@ -18,7 +18,11 @@ static int wave5_vdi_allocate_common_memory(struct device *dev)
if (!vpu_dev->common_mem.vaddr) {
int ret;
- vpu_dev->common_mem.size = SIZE_COMMON;
+ if (vpu_dev->product_code == WAVE515_CODE)
+ vpu_dev->common_mem.size = WAVE515_SIZE_COMMON;
+ else
+ vpu_dev->common_mem.size = WAVE521_SIZE_COMMON;
+
ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vpu_dev->common_mem);
if (ret) {
dev_err(dev, "unable to allocate common buffer\n");
@@ -174,16 +178,19 @@ int wave5_vdi_allocate_array(struct vpu_device *vpu_dev, struct vpu_buf *array,
void wave5_vdi_allocate_sram(struct vpu_device *vpu_dev)
{
struct vpu_buf *vb = &vpu_dev->sram_buf;
+ dma_addr_t daddr;
+ void *vaddr;
+ size_t size;
- if (!vpu_dev->sram_pool || !vpu_dev->sram_size)
+ if (!vpu_dev->sram_pool || vb->vaddr)
return;
- if (!vb->vaddr) {
- vb->size = vpu_dev->sram_size;
- vb->vaddr = gen_pool_dma_alloc(vpu_dev->sram_pool, vb->size,
- &vb->daddr);
- if (!vb->vaddr)
- vb->size = 0;
+ size = min_t(size_t, vpu_dev->sram_size, gen_pool_avail(vpu_dev->sram_pool));
+ vaddr = gen_pool_dma_alloc(vpu_dev->sram_pool, size, &daddr);
+ if (vaddr) {
+ vb->vaddr = vaddr;
+ vb->daddr = daddr;
+ vb->size = size;
}
dev_dbg(vpu_dev->dev, "%s: sram daddr: %pad, size: %zu, vaddr: 0x%p\n",
@@ -197,9 +204,7 @@ void wave5_vdi_free_sram(struct vpu_device *vpu_dev)
if (!vb->size || !vb->vaddr)
return;
- if (vb->vaddr)
- gen_pool_free(vpu_dev->sram_pool, (unsigned long)vb->vaddr,
- vb->size);
+ gen_pool_free(vpu_dev->sram_pool, (unsigned long)vb->vaddr, vb->size);
memset(vb, 0, sizeof(*vb));
}
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c
index ef227af72348..fd71f0c43ac3 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c
@@ -5,116 +5,98 @@
* Copyright (C) 2021-2023 CHIPS&MEDIA INC
*/
+#include <linux/pm_runtime.h>
#include "wave5-helper.h"
#define VPU_DEC_DEV_NAME "C&M Wave5 VPU decoder"
#define VPU_DEC_DRV_NAME "wave5-dec"
-#define DEFAULT_SRC_SIZE(width, height) ({ \
- (width) * (height) / 8 * 3; \
-})
+static const struct v4l2_frmsize_stepwise dec_hevc_frmsize = {
+ .min_width = W5_MIN_DEC_PIC_8_WIDTH,
+ .max_width = W5_MAX_DEC_PIC_WIDTH,
+ .step_width = W5_DEC_CODEC_STEP_WIDTH,
+ .min_height = W5_MIN_DEC_PIC_8_HEIGHT,
+ .max_height = W5_MAX_DEC_PIC_HEIGHT,
+ .step_height = W5_DEC_CODEC_STEP_HEIGHT,
+};
+
+static const struct v4l2_frmsize_stepwise dec_h264_frmsize = {
+ .min_width = W5_MIN_DEC_PIC_32_WIDTH,
+ .max_width = W5_MAX_DEC_PIC_WIDTH,
+ .step_width = W5_DEC_CODEC_STEP_WIDTH,
+ .min_height = W5_MIN_DEC_PIC_32_HEIGHT,
+ .max_height = W5_MAX_DEC_PIC_HEIGHT,
+ .step_height = W5_DEC_CODEC_STEP_HEIGHT,
+};
+
+static const struct v4l2_frmsize_stepwise dec_raw_frmsize = {
+ .min_width = W5_MIN_DEC_PIC_8_WIDTH,
+ .max_width = W5_MAX_DEC_PIC_WIDTH,
+ .step_width = W5_DEC_RAW_STEP_WIDTH,
+ .min_height = W5_MIN_DEC_PIC_8_HEIGHT,
+ .max_height = W5_MAX_DEC_PIC_HEIGHT,
+ .step_height = W5_DEC_RAW_STEP_HEIGHT,
+};
static const struct vpu_format dec_fmt_list[FMT_TYPES][MAX_FMTS] = {
[VPU_FMT_TYPE_CODEC] = {
{
.v4l2_pix_fmt = V4L2_PIX_FMT_HEVC,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_hevc_frmsize,
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_H264,
- .max_width = 8192,
- .min_width = 32,
- .max_height = 4320,
- .min_height = 32,
+ .v4l2_frmsize = &dec_h264_frmsize,
},
},
[VPU_FMT_TYPE_RAW] = {
{
.v4l2_pix_fmt = V4L2_PIX_FMT_YUV420,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_raw_frmsize,
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_NV12,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_raw_frmsize,
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_NV21,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_raw_frmsize,
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_YUV422P,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_raw_frmsize,
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_NV16,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_raw_frmsize,
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_NV61,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_raw_frmsize,
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_YUV420M,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_raw_frmsize,
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_NV12M,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_raw_frmsize,
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_NV21M,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_raw_frmsize,
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_YUV422M,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_raw_frmsize,
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_NV16M,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_raw_frmsize,
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_NV61M,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_raw_frmsize,
},
}
};
@@ -233,74 +215,6 @@ static void wave5_handle_src_buffer(struct vpu_instance *inst, dma_addr_t rd_ptr
inst->remaining_consumed_bytes = consumed_bytes;
}
-static void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp, unsigned int width,
- unsigned int height)
-{
- switch (pix_mp->pixelformat) {
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_NV12:
- case V4L2_PIX_FMT_NV21:
- pix_mp->width = round_up(width, 32);
- pix_mp->height = round_up(height, 16);
- pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
- pix_mp->plane_fmt[0].sizeimage = width * height * 3 / 2;
- break;
- case V4L2_PIX_FMT_YUV422P:
- case V4L2_PIX_FMT_NV16:
- case V4L2_PIX_FMT_NV61:
- pix_mp->width = round_up(width, 32);
- pix_mp->height = round_up(height, 16);
- pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
- pix_mp->plane_fmt[0].sizeimage = width * height * 2;
- break;
- case V4L2_PIX_FMT_YUV420M:
- pix_mp->width = round_up(width, 32);
- pix_mp->height = round_up(height, 16);
- pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
- pix_mp->plane_fmt[0].sizeimage = width * height;
- pix_mp->plane_fmt[1].bytesperline = round_up(width, 32) / 2;
- pix_mp->plane_fmt[1].sizeimage = width * height / 4;
- pix_mp->plane_fmt[2].bytesperline = round_up(width, 32) / 2;
- pix_mp->plane_fmt[2].sizeimage = width * height / 4;
- break;
- case V4L2_PIX_FMT_NV12M:
- case V4L2_PIX_FMT_NV21M:
- pix_mp->width = round_up(width, 32);
- pix_mp->height = round_up(height, 16);
- pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
- pix_mp->plane_fmt[0].sizeimage = width * height;
- pix_mp->plane_fmt[1].bytesperline = round_up(width, 32);
- pix_mp->plane_fmt[1].sizeimage = width * height / 2;
- break;
- case V4L2_PIX_FMT_YUV422M:
- pix_mp->width = round_up(width, 32);
- pix_mp->height = round_up(height, 16);
- pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
- pix_mp->plane_fmt[0].sizeimage = width * height;
- pix_mp->plane_fmt[1].bytesperline = round_up(width, 32) / 2;
- pix_mp->plane_fmt[1].sizeimage = width * height / 2;
- pix_mp->plane_fmt[2].bytesperline = round_up(width, 32) / 2;
- pix_mp->plane_fmt[2].sizeimage = width * height / 2;
- break;
- case V4L2_PIX_FMT_NV16M:
- case V4L2_PIX_FMT_NV61M:
- pix_mp->width = round_up(width, 32);
- pix_mp->height = round_up(height, 16);
- pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
- pix_mp->plane_fmt[0].sizeimage = width * height;
- pix_mp->plane_fmt[1].bytesperline = round_up(width, 32);
- pix_mp->plane_fmt[1].sizeimage = width * height;
- break;
- default:
- pix_mp->width = width;
- pix_mp->height = height;
- pix_mp->plane_fmt[0].bytesperline = 0;
- pix_mp->plane_fmt[0].sizeimage = max(DEFAULT_SRC_SIZE(width, height),
- pix_mp->plane_fmt[0].sizeimage);
- break;
- }
-}
-
static int start_decode(struct vpu_instance *inst, u32 *fail_res)
{
struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
@@ -388,6 +302,8 @@ static int handle_dynamic_resolution_change(struct vpu_instance *inst)
}
if (p_dec_info->initial_info_obtained) {
+ const struct vpu_format *vpu_fmt;
+
inst->conf_win.left = initial_info->pic_crop_rect.left;
inst->conf_win.top = initial_info->pic_crop_rect.top;
inst->conf_win.width = initial_info->pic_width -
@@ -395,10 +311,27 @@ static int handle_dynamic_resolution_change(struct vpu_instance *inst)
inst->conf_win.height = initial_info->pic_height -
initial_info->pic_crop_rect.top - initial_info->pic_crop_rect.bottom;
- wave5_update_pix_fmt(&inst->src_fmt, initial_info->pic_width,
- initial_info->pic_height);
- wave5_update_pix_fmt(&inst->dst_fmt, initial_info->pic_width,
- initial_info->pic_height);
+ vpu_fmt = wave5_find_vpu_fmt(inst->src_fmt.pixelformat,
+ dec_fmt_list[VPU_FMT_TYPE_CODEC]);
+ if (!vpu_fmt)
+ return -EINVAL;
+
+ wave5_update_pix_fmt(&inst->src_fmt,
+ VPU_FMT_TYPE_CODEC,
+ initial_info->pic_width,
+ initial_info->pic_height,
+ vpu_fmt->v4l2_frmsize);
+
+ vpu_fmt = wave5_find_vpu_fmt(inst->dst_fmt.pixelformat,
+ dec_fmt_list[VPU_FMT_TYPE_RAW]);
+ if (!vpu_fmt)
+ return -EINVAL;
+
+ wave5_update_pix_fmt(&inst->dst_fmt,
+ VPU_FMT_TYPE_RAW,
+ initial_info->pic_width,
+ initial_info->pic_height,
+ vpu_fmt->v4l2_frmsize);
}
v4l2_event_queue_fh(fh, &vpu_event_src_ch);
@@ -518,6 +451,8 @@ static void wave5_vpu_dec_finish_decode(struct vpu_instance *inst)
if (q_status.report_queue_count == 0 &&
(q_status.instance_queue_count == 0 || dec_info.sequence_changed)) {
dev_dbg(inst->dev->dev, "%s: finishing job.\n", __func__);
+ pm_runtime_mark_last_busy(inst->dev->dev);
+ pm_runtime_put_autosuspend(inst->dev->dev);
v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
}
}
@@ -545,12 +480,12 @@ static int wave5_vpu_dec_enum_framesizes(struct file *f, void *fh, struct v4l2_f
}
fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
- fsize->stepwise.min_width = vpu_fmt->min_width;
- fsize->stepwise.max_width = vpu_fmt->max_width;
- fsize->stepwise.step_width = 1;
- fsize->stepwise.min_height = vpu_fmt->min_height;
- fsize->stepwise.max_height = vpu_fmt->max_height;
- fsize->stepwise.step_height = 1;
+ fsize->stepwise.min_width = vpu_fmt->v4l2_frmsize->min_width;
+ fsize->stepwise.max_width = vpu_fmt->v4l2_frmsize->max_width;
+ fsize->stepwise.step_width = W5_DEC_CODEC_STEP_WIDTH;
+ fsize->stepwise.min_height = vpu_fmt->v4l2_frmsize->min_height;
+ fsize->stepwise.max_height = vpu_fmt->v4l2_frmsize->max_height;
+ fsize->stepwise.step_height = W5_DEC_CODEC_STEP_HEIGHT;
return 0;
}
@@ -573,6 +508,7 @@ static int wave5_vpu_dec_try_fmt_cap(struct file *file, void *fh, struct v4l2_fo
{
struct vpu_instance *inst = wave5_to_vpu_inst(fh);
struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ const struct v4l2_frmsize_stepwise *frmsize;
const struct vpu_format *vpu_fmt;
int width, height;
@@ -586,14 +522,12 @@ static int wave5_vpu_dec_try_fmt_cap(struct file *file, void *fh, struct v4l2_fo
width = inst->dst_fmt.width;
height = inst->dst_fmt.height;
f->fmt.pix_mp.pixelformat = inst->dst_fmt.pixelformat;
- f->fmt.pix_mp.num_planes = inst->dst_fmt.num_planes;
+ frmsize = &dec_raw_frmsize;
} else {
- const struct v4l2_format_info *info = v4l2_format_info(vpu_fmt->v4l2_pix_fmt);
-
- width = clamp(f->fmt.pix_mp.width, vpu_fmt->min_width, vpu_fmt->max_width);
- height = clamp(f->fmt.pix_mp.height, vpu_fmt->min_height, vpu_fmt->max_height);
+ width = f->fmt.pix_mp.width;
+ height = f->fmt.pix_mp.height;
f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt;
- f->fmt.pix_mp.num_planes = info->mem_planes;
+ frmsize = vpu_fmt->v4l2_frmsize;
}
if (p_dec_info->initial_info_obtained) {
@@ -601,9 +535,8 @@ static int wave5_vpu_dec_try_fmt_cap(struct file *file, void *fh, struct v4l2_fo
height = inst->dst_fmt.height;
}
- wave5_update_pix_fmt(&f->fmt.pix_mp, width, height);
- f->fmt.pix_mp.flags = 0;
- f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+ wave5_update_pix_fmt(&f->fmt.pix_mp, VPU_FMT_TYPE_RAW,
+ width, height, frmsize);
f->fmt.pix_mp.colorspace = inst->colorspace;
f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc;
f->fmt.pix_mp.quantization = inst->quantization;
@@ -715,7 +648,9 @@ static int wave5_vpu_dec_enum_fmt_out(struct file *file, void *fh, struct v4l2_f
static int wave5_vpu_dec_try_fmt_out(struct file *file, void *fh, struct v4l2_format *f)
{
struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ const struct v4l2_frmsize_stepwise *frmsize;
const struct vpu_format *vpu_fmt;
+ int width, height;
dev_dbg(inst->dev->dev,
"%s: fourcc: %u width: %u height: %u num_planes: %u colorspace: %u field: %u\n",
@@ -724,20 +659,19 @@ static int wave5_vpu_dec_try_fmt_out(struct file *file, void *fh, struct v4l2_fo
vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, dec_fmt_list[VPU_FMT_TYPE_CODEC]);
if (!vpu_fmt) {
+ width = inst->src_fmt.width;
+ height = inst->src_fmt.height;
f->fmt.pix_mp.pixelformat = inst->src_fmt.pixelformat;
- f->fmt.pix_mp.num_planes = inst->src_fmt.num_planes;
- wave5_update_pix_fmt(&f->fmt.pix_mp, inst->src_fmt.width, inst->src_fmt.height);
+ frmsize = &dec_hevc_frmsize;
} else {
- int width = clamp(f->fmt.pix_mp.width, vpu_fmt->min_width, vpu_fmt->max_width);
- int height = clamp(f->fmt.pix_mp.height, vpu_fmt->min_height, vpu_fmt->max_height);
-
+ width = f->fmt.pix_mp.width;
+ height = f->fmt.pix_mp.height;
f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt;
- f->fmt.pix_mp.num_planes = 1;
- wave5_update_pix_fmt(&f->fmt.pix_mp, width, height);
+ frmsize = vpu_fmt->v4l2_frmsize;
}
- f->fmt.pix_mp.flags = 0;
- f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+ wave5_update_pix_fmt(&f->fmt.pix_mp, VPU_FMT_TYPE_CODEC,
+ width, height, frmsize);
return 0;
}
@@ -745,6 +679,7 @@ static int wave5_vpu_dec_try_fmt_out(struct file *file, void *fh, struct v4l2_fo
static int wave5_vpu_dec_s_fmt_out(struct file *file, void *fh, struct v4l2_format *f)
{
struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ const struct vpu_format *vpu_fmt;
int i, ret;
dev_dbg(inst->dev->dev,
@@ -779,7 +714,13 @@ static int wave5_vpu_dec_s_fmt_out(struct file *file, void *fh, struct v4l2_form
inst->quantization = f->fmt.pix_mp.quantization;
inst->xfer_func = f->fmt.pix_mp.xfer_func;
- wave5_update_pix_fmt(&inst->dst_fmt, f->fmt.pix_mp.width, f->fmt.pix_mp.height);
+ vpu_fmt = wave5_find_vpu_fmt(inst->dst_fmt.pixelformat, dec_fmt_list[VPU_FMT_TYPE_RAW]);
+ if (!vpu_fmt)
+ return -EINVAL;
+
+ wave5_update_pix_fmt(&inst->dst_fmt, VPU_FMT_TYPE_RAW,
+ f->fmt.pix_mp.width, f->fmt.pix_mp.height,
+ vpu_fmt->v4l2_frmsize);
return 0;
}
@@ -1002,6 +943,7 @@ static int wave5_vpu_dec_queue_setup(struct vb2_queue *q, unsigned int *num_buff
struct vpu_instance *inst = vb2_get_drv_priv(q);
struct v4l2_pix_format_mplane inst_format =
(q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? inst->src_fmt : inst->dst_fmt;
+ unsigned int i;
dev_dbg(inst->dev->dev, "%s: num_buffers: %u | num_planes: %u | type: %u\n", __func__,
*num_buffers, *num_planes, q->type);
@@ -1015,31 +957,9 @@ static int wave5_vpu_dec_queue_setup(struct vb2_queue *q, unsigned int *num_buff
if (*num_buffers < inst->fbc_buf_count)
*num_buffers = inst->fbc_buf_count;
- if (*num_planes == 1) {
- if (inst->output_format == FORMAT_422)
- sizes[0] = inst_format.width * inst_format.height * 2;
- else
- sizes[0] = inst_format.width * inst_format.height * 3 / 2;
- dev_dbg(inst->dev->dev, "%s: size[0]: %u\n", __func__, sizes[0]);
- } else if (*num_planes == 2) {
- sizes[0] = inst_format.width * inst_format.height;
- if (inst->output_format == FORMAT_422)
- sizes[1] = inst_format.width * inst_format.height;
- else
- sizes[1] = inst_format.width * inst_format.height / 2;
- dev_dbg(inst->dev->dev, "%s: size[0]: %u | size[1]: %u\n",
- __func__, sizes[0], sizes[1]);
- } else if (*num_planes == 3) {
- sizes[0] = inst_format.width * inst_format.height;
- if (inst->output_format == FORMAT_422) {
- sizes[1] = inst_format.width * inst_format.height / 2;
- sizes[2] = inst_format.width * inst_format.height / 2;
- } else {
- sizes[1] = inst_format.width * inst_format.height / 4;
- sizes[2] = inst_format.width * inst_format.height / 4;
- }
- dev_dbg(inst->dev->dev, "%s: size[0]: %u | size[1]: %u | size[2]: %u\n",
- __func__, sizes[0], sizes[1], sizes[2]);
+ for (i = 0; i < *num_planes; i++) {
+ sizes[i] = inst_format.plane_fmt[i].sizeimage;
+ dev_dbg(inst->dev->dev, "%s: size[%u]: %u\n", __func__, i, sizes[i]);
}
}
@@ -1055,6 +975,22 @@ static int wave5_prepare_fb(struct vpu_instance *inst)
int ret, i;
struct v4l2_m2m_buffer *buf, *n;
struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ u32 bitdepth = inst->codec_info->dec_info.initial_info.luma_bitdepth;
+
+ switch (bitdepth) {
+ case 8:
+ break;
+ case 10:
+ if (inst->std == W_HEVC_DEC &&
+ inst->dev->attr.support_hevc10bit_dec)
+ break;
+
+ fallthrough;
+ default:
+ dev_err(inst->dev->dev, "no support for %d bit depth\n", bitdepth);
+
+ return -EINVAL;
+ }
linear_num = v4l2_m2m_num_dst_bufs_ready(m2m_ctx);
non_linear_num = inst->fbc_buf_count;
@@ -1063,7 +999,7 @@ static int wave5_prepare_fb(struct vpu_instance *inst)
struct frame_buffer *frame = &inst->frame_buf[i];
struct vpu_buf *vframe = &inst->frame_vbuf[i];
- fb_stride = inst->dst_fmt.width;
+ fb_stride = ALIGN(inst->dst_fmt.width * bitdepth / 8, 32);
fb_height = ALIGN(inst->dst_fmt.height, 32);
luma_size = fb_stride * fb_height;
@@ -1382,6 +1318,7 @@ static int wave5_vpu_dec_start_streaming(struct vb2_queue *q, unsigned int count
int ret = 0;
dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type);
+ pm_runtime_resume_and_get(inst->dev->dev);
v4l2_m2m_update_start_streaming_state(m2m_ctx, q);
@@ -1416,7 +1353,8 @@ static int wave5_vpu_dec_start_streaming(struct vb2_queue *q, unsigned int count
if (ret)
goto return_buffers;
- if (inst->state == VPU_INST_STATE_INIT_SEQ) {
+ if (inst->state == VPU_INST_STATE_INIT_SEQ &&
+ inst->dev->product_code == WAVE521C_CODE) {
if (initial_info->luma_bitdepth != 8) {
dev_info(inst->dev->dev, "%s: no support for %d bit depth",
__func__, initial_info->luma_bitdepth);
@@ -1424,14 +1362,17 @@ static int wave5_vpu_dec_start_streaming(struct vb2_queue *q, unsigned int count
goto return_buffers;
}
}
- }
+ }
+ pm_runtime_mark_last_busy(inst->dev->dev);
+ pm_runtime_put_autosuspend(inst->dev->dev);
return ret;
free_bitstream_vbuf:
wave5_vdi_free_dma_memory(inst->dev, &inst->bitstream_vbuf);
return_buffers:
wave5_return_bufs(q, VB2_BUF_STATE_QUEUED);
+ pm_runtime_put_autosuspend(inst->dev->dev);
return ret;
}
@@ -1442,6 +1383,16 @@ static int streamoff_output(struct vb2_queue *q)
struct vb2_v4l2_buffer *buf;
int ret;
dma_addr_t new_rd_ptr;
+ struct dec_output_info dec_info;
+ unsigned int i;
+
+ for (i = 0; i < v4l2_m2m_num_dst_bufs_ready(m2m_ctx); i++) {
+ ret = wave5_vpu_dec_set_disp_flag(inst, i);
+ if (ret)
+ dev_dbg(inst->dev->dev,
+ "%s: Setting display flag of buf index: %u, fail: %d\n",
+ __func__, i, ret);
+ }
while ((buf = v4l2_m2m_src_buf_remove(m2m_ctx))) {
dev_dbg(inst->dev->dev, "%s: (Multiplanar) buf type %4u | index %4u\n",
@@ -1449,6 +1400,11 @@ static int streamoff_output(struct vb2_queue *q)
v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
}
+ while (wave5_vpu_dec_get_output_info(inst, &dec_info) == 0) {
+ if (dec_info.index_frame_display >= 0)
+ wave5_vpu_dec_set_disp_flag(inst, dec_info.index_frame_display);
+ }
+
ret = wave5_vpu_flush_instance(inst);
if (ret)
return ret;
@@ -1517,6 +1473,7 @@ static void wave5_vpu_dec_stop_streaming(struct vb2_queue *q)
bool check_cmd = TRUE;
dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type);
+ pm_runtime_resume_and_get(inst->dev->dev);
while (check_cmd) {
struct queue_status_info q_status;
@@ -1531,7 +1488,7 @@ static void wave5_vpu_dec_stop_streaming(struct vb2_queue *q)
break;
if (wave5_vpu_dec_get_output_info(inst, &dec_output_info))
- dev_dbg(inst->dev->dev, "Getting decoding results from fw, fail\n");
+ dev_dbg(inst->dev->dev, "there is no output info\n");
}
v4l2_m2m_update_stop_streaming_state(m2m_ctx, q);
@@ -1540,12 +1497,13 @@ static void wave5_vpu_dec_stop_streaming(struct vb2_queue *q)
streamoff_output(q);
else
streamoff_capture(q);
+
+ pm_runtime_mark_last_busy(inst->dev->dev);
+ pm_runtime_put_autosuspend(inst->dev->dev);
}
static const struct vb2_ops wave5_vpu_dec_vb2_ops = {
.queue_setup = wave5_vpu_dec_queue_setup,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.buf_queue = wave5_vpu_dec_buf_queue,
.start_streaming = wave5_vpu_dec_start_streaming,
.stop_streaming = wave5_vpu_dec_stop_streaming,
@@ -1554,20 +1512,15 @@ static const struct vb2_ops wave5_vpu_dec_vb2_ops = {
static void wave5_set_default_format(struct v4l2_pix_format_mplane *src_fmt,
struct v4l2_pix_format_mplane *dst_fmt)
{
- unsigned int dst_pix_fmt = dec_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt;
- const struct v4l2_format_info *dst_fmt_info = v4l2_format_info(dst_pix_fmt);
-
src_fmt->pixelformat = dec_fmt_list[VPU_FMT_TYPE_CODEC][0].v4l2_pix_fmt;
- src_fmt->field = V4L2_FIELD_NONE;
- src_fmt->flags = 0;
- src_fmt->num_planes = 1;
- wave5_update_pix_fmt(src_fmt, 720, 480);
-
- dst_fmt->pixelformat = dst_pix_fmt;
- dst_fmt->field = V4L2_FIELD_NONE;
- dst_fmt->flags = 0;
- dst_fmt->num_planes = dst_fmt_info->mem_planes;
- wave5_update_pix_fmt(dst_fmt, 736, 480);
+ wave5_update_pix_fmt(src_fmt, VPU_FMT_TYPE_CODEC,
+ W5_DEF_DEC_PIC_WIDTH, W5_DEF_DEC_PIC_HEIGHT,
+ &dec_hevc_frmsize);
+
+ dst_fmt->pixelformat = dec_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt;
+ wave5_update_pix_fmt(dst_fmt, VPU_FMT_TYPE_RAW,
+ W5_DEF_DEC_PIC_WIDTH, W5_DEF_DEC_PIC_HEIGHT,
+ &dec_raw_frmsize);
}
static int wave5_vpu_dec_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
@@ -1626,7 +1579,7 @@ static void wave5_vpu_dec_device_run(void *priv)
int ret = 0;
dev_dbg(inst->dev->dev, "%s: Fill the ring buffer with new bitstream data", __func__);
-
+ pm_runtime_resume_and_get(inst->dev->dev);
ret = fill_ringbuffer(inst);
if (ret) {
dev_warn(inst->dev->dev, "Filling ring buffer failed\n");
@@ -1709,6 +1662,8 @@ static void wave5_vpu_dec_device_run(void *priv)
finish_job_and_return:
dev_dbg(inst->dev->dev, "%s: leave and finish job", __func__);
+ pm_runtime_mark_last_busy(inst->dev->dev);
+ pm_runtime_put_autosuspend(inst->dev->dev);
v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
}
@@ -1810,7 +1765,6 @@ static int wave5_vpu_open_dec(struct file *filp)
v4l2_fh_add(&inst->v4l2_fh);
INIT_LIST_HEAD(&inst->list);
- list_add_tail(&inst->list, &dev->instances);
inst->v4l2_m2m_dev = inst->dev->v4l2_m2m_dec_dev;
inst->v4l2_fh.m2m_ctx =
@@ -1865,7 +1819,23 @@ static int wave5_vpu_open_dec(struct file *filp)
goto cleanup_inst;
}
- wave5_vdi_allocate_sram(inst->dev);
+ /*
+ * For Wave515 SRAM memory was already allocated
+ * at wave5_vpu_dec_register_device()
+ */
+ if (inst->dev->product_code != WAVE515_CODE)
+ wave5_vdi_allocate_sram(inst->dev);
+
+ ret = mutex_lock_interruptible(&dev->dev_lock);
+ if (ret)
+ goto cleanup_inst;
+
+ if (list_empty(&dev->instances))
+ pm_runtime_use_autosuspend(inst->dev->dev);
+
+ list_add_tail(&inst->list, &dev->instances);
+
+ mutex_unlock(&dev->dev_lock);
return 0;
@@ -1893,6 +1863,13 @@ int wave5_vpu_dec_register_device(struct vpu_device *dev)
struct video_device *vdev_dec;
int ret;
+ /*
+ * Secondary AXI setup for Wave515 is done by INIT_VPU command,
+ * i.e. wave5_vpu_init(), that's why we allocate SRAM memory early.
+ */
+ if (dev->product_code == WAVE515_CODE)
+ wave5_vdi_allocate_sram(dev);
+
vdev_dec = devm_kzalloc(dev->v4l2_dev.dev, sizeof(*vdev_dec), GFP_KERNEL);
if (!vdev_dec)
return -ENOMEM;
@@ -1926,6 +1903,13 @@ int wave5_vpu_dec_register_device(struct vpu_device *dev)
void wave5_vpu_dec_unregister_device(struct vpu_device *dev)
{
+ /*
+ * Here is a freeing pair for Wave515 SRAM memory allocation
+ * happened at wave5_vpu_dec_register_device().
+ */
+ if (dev->product_code == WAVE515_CODE)
+ wave5_vdi_free_sram(dev);
+
video_unregister_device(dev->video_dev_dec);
if (dev->v4l2_m2m_dec_dev)
v4l2_m2m_release(dev->v4l2_m2m_dec_dev);
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c
index 8bbf9d10b467..1e5fc5f8b856 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c
@@ -5,70 +5,90 @@
* Copyright (C) 2021-2023 CHIPS&MEDIA INC
*/
+#include <linux/pm_runtime.h>
#include "wave5-helper.h"
#define VPU_ENC_DEV_NAME "C&M Wave5 VPU encoder"
#define VPU_ENC_DRV_NAME "wave5-enc"
+static const struct v4l2_frmsize_stepwise enc_frmsize[FMT_TYPES] = {
+ [VPU_FMT_TYPE_CODEC] = {
+ .min_width = W5_MIN_ENC_PIC_WIDTH,
+ .max_width = W5_MAX_ENC_PIC_WIDTH,
+ .step_width = W5_ENC_CODEC_STEP_WIDTH,
+ .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ .max_height = W5_MAX_ENC_PIC_HEIGHT,
+ .step_height = W5_ENC_CODEC_STEP_HEIGHT,
+ },
+ [VPU_FMT_TYPE_RAW] = {
+ .min_width = W5_MIN_ENC_PIC_WIDTH,
+ .max_width = W5_MAX_ENC_PIC_WIDTH,
+ .step_width = W5_ENC_RAW_STEP_WIDTH,
+ .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ .max_height = W5_MAX_ENC_PIC_HEIGHT,
+ .step_height = W5_ENC_RAW_STEP_HEIGHT,
+ },
+};
+
static const struct vpu_format enc_fmt_list[FMT_TYPES][MAX_FMTS] = {
[VPU_FMT_TYPE_CODEC] = {
{
.v4l2_pix_fmt = V4L2_PIX_FMT_HEVC,
- .max_width = W5_MAX_ENC_PIC_WIDTH,
- .min_width = W5_MIN_ENC_PIC_WIDTH,
- .max_height = W5_MAX_ENC_PIC_HEIGHT,
- .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_CODEC],
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_H264,
- .max_width = W5_MAX_ENC_PIC_WIDTH,
- .min_width = W5_MIN_ENC_PIC_WIDTH,
- .max_height = W5_MAX_ENC_PIC_HEIGHT,
- .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_CODEC],
},
},
[VPU_FMT_TYPE_RAW] = {
{
.v4l2_pix_fmt = V4L2_PIX_FMT_YUV420,
- .max_width = W5_MAX_ENC_PIC_WIDTH,
- .min_width = W5_MIN_ENC_PIC_WIDTH,
- .max_height = W5_MAX_ENC_PIC_HEIGHT,
- .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW],
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_NV12,
- .max_width = W5_MAX_ENC_PIC_WIDTH,
- .min_width = W5_MIN_ENC_PIC_WIDTH,
- .max_height = W5_MAX_ENC_PIC_HEIGHT,
- .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW],
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_NV21,
- .max_width = W5_MAX_ENC_PIC_WIDTH,
- .min_width = W5_MIN_ENC_PIC_WIDTH,
- .max_height = W5_MAX_ENC_PIC_HEIGHT,
- .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW],
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_YUV420M,
- .max_width = W5_MAX_ENC_PIC_WIDTH,
- .min_width = W5_MIN_ENC_PIC_WIDTH,
- .max_height = W5_MAX_ENC_PIC_HEIGHT,
- .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW],
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_NV12M,
- .max_width = W5_MAX_ENC_PIC_WIDTH,
- .min_width = W5_MIN_ENC_PIC_WIDTH,
- .max_height = W5_MAX_ENC_PIC_HEIGHT,
- .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW],
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_NV21M,
- .max_width = W5_MAX_ENC_PIC_WIDTH,
- .min_width = W5_MIN_ENC_PIC_WIDTH,
- .max_height = W5_MAX_ENC_PIC_HEIGHT,
- .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW],
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422P,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW],
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV16,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW],
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV61,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW],
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422M,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW],
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV16M,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW],
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV61M,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW],
},
}
};
@@ -105,46 +125,6 @@ invalid_state_switch:
return -EINVAL;
}
-static void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp, unsigned int width,
- unsigned int height)
-{
- switch (pix_mp->pixelformat) {
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_NV12:
- case V4L2_PIX_FMT_NV21:
- pix_mp->width = width;
- pix_mp->height = height;
- pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
- pix_mp->plane_fmt[0].sizeimage = round_up(width, 32) * height * 3 / 2;
- break;
- case V4L2_PIX_FMT_YUV420M:
- pix_mp->width = width;
- pix_mp->height = height;
- pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
- pix_mp->plane_fmt[0].sizeimage = round_up(width, 32) * height;
- pix_mp->plane_fmt[1].bytesperline = round_up(width, 32) / 2;
- pix_mp->plane_fmt[1].sizeimage = round_up(width, 32) * height / 4;
- pix_mp->plane_fmt[2].bytesperline = round_up(width, 32) / 2;
- pix_mp->plane_fmt[2].sizeimage = round_up(width, 32) * height / 4;
- break;
- case V4L2_PIX_FMT_NV12M:
- case V4L2_PIX_FMT_NV21M:
- pix_mp->width = width;
- pix_mp->height = height;
- pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
- pix_mp->plane_fmt[0].sizeimage = round_up(width, 32) * height;
- pix_mp->plane_fmt[1].bytesperline = round_up(width, 32);
- pix_mp->plane_fmt[1].sizeimage = round_up(width, 32) * height / 2;
- break;
- default:
- pix_mp->width = width;
- pix_mp->height = height;
- pix_mp->plane_fmt[0].bytesperline = 0;
- pix_mp->plane_fmt[0].sizeimage = width * height / 8 * 3;
- break;
- }
-}
-
static int start_encode(struct vpu_instance *inst, u32 *fail_res)
{
struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
@@ -153,13 +133,26 @@ static int start_encode(struct vpu_instance *inst, u32 *fail_res)
struct vb2_v4l2_buffer *dst_buf;
struct frame_buffer frame_buf;
struct enc_param pic_param;
- u32 stride = ALIGN(inst->dst_fmt.width, 32);
- u32 luma_size = (stride * inst->dst_fmt.height);
- u32 chroma_size = ((stride / 2) * (inst->dst_fmt.height / 2));
+ const struct v4l2_format_info *info;
+ u32 stride = inst->src_fmt.plane_fmt[0].bytesperline;
+ u32 luma_size = 0;
+ u32 chroma_size = 0;
memset(&pic_param, 0, sizeof(struct enc_param));
memset(&frame_buf, 0, sizeof(struct frame_buffer));
+ info = v4l2_format_info(inst->src_fmt.pixelformat);
+ if (!info)
+ return -EINVAL;
+
+ if (info->mem_planes == 1) {
+ luma_size = stride * inst->dst_fmt.height;
+ chroma_size = luma_size / (info->hdiv * info->vdiv);
+ } else {
+ luma_size = inst->src_fmt.plane_fmt[0].sizeimage;
+ chroma_size = inst->src_fmt.plane_fmt[1].sizeimage;
+ }
+
dst_buf = v4l2_m2m_next_dst_buf(m2m_ctx);
if (!dst_buf) {
dev_dbg(inst->dev->dev, "%s: No destination buffer found\n", __func__);
@@ -359,13 +352,8 @@ static int wave5_vpu_enc_enum_framesizes(struct file *f, void *fh, struct v4l2_f
return -EINVAL;
}
- fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
- fsize->stepwise.min_width = vpu_fmt->min_width;
- fsize->stepwise.max_width = vpu_fmt->max_width;
- fsize->stepwise.step_width = 1;
- fsize->stepwise.min_height = vpu_fmt->min_height;
- fsize->stepwise.max_height = vpu_fmt->max_height;
- fsize->stepwise.step_height = 1;
+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ fsize->stepwise = enc_frmsize[VPU_FMT_TYPE_CODEC];
return 0;
}
@@ -390,7 +378,9 @@ static int wave5_vpu_enc_enum_fmt_cap(struct file *file, void *fh, struct v4l2_f
static int wave5_vpu_enc_try_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
{
struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ const struct v4l2_frmsize_stepwise *frmsize;
const struct vpu_format *vpu_fmt;
+ int width, height;
dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n",
__func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
@@ -398,20 +388,19 @@ static int wave5_vpu_enc_try_fmt_cap(struct file *file, void *fh, struct v4l2_fo
vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, enc_fmt_list[VPU_FMT_TYPE_CODEC]);
if (!vpu_fmt) {
+ width = inst->dst_fmt.width;
+ height = inst->dst_fmt.height;
f->fmt.pix_mp.pixelformat = inst->dst_fmt.pixelformat;
- f->fmt.pix_mp.num_planes = inst->dst_fmt.num_planes;
- wave5_update_pix_fmt(&f->fmt.pix_mp, inst->dst_fmt.width, inst->dst_fmt.height);
+ frmsize = &enc_frmsize[VPU_FMT_TYPE_CODEC];
} else {
- int width = clamp(f->fmt.pix_mp.width, vpu_fmt->min_width, vpu_fmt->max_width);
- int height = clamp(f->fmt.pix_mp.height, vpu_fmt->min_height, vpu_fmt->max_height);
-
+ width = f->fmt.pix_mp.width;
+ height = f->fmt.pix_mp.height;
f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt;
- f->fmt.pix_mp.num_planes = 1;
- wave5_update_pix_fmt(&f->fmt.pix_mp, width, height);
+ frmsize = vpu_fmt->v4l2_frmsize;
}
- f->fmt.pix_mp.flags = 0;
- f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+ wave5_update_pix_fmt(&f->fmt.pix_mp, VPU_FMT_TYPE_CODEC,
+ width, height, frmsize);
f->fmt.pix_mp.colorspace = inst->colorspace;
f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc;
f->fmt.pix_mp.quantization = inst->quantization;
@@ -498,7 +487,9 @@ static int wave5_vpu_enc_enum_fmt_out(struct file *file, void *fh, struct v4l2_f
static int wave5_vpu_enc_try_fmt_out(struct file *file, void *fh, struct v4l2_format *f)
{
struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ const struct v4l2_frmsize_stepwise *frmsize;
const struct vpu_format *vpu_fmt;
+ int width, height;
dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n",
__func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
@@ -506,28 +497,27 @@ static int wave5_vpu_enc_try_fmt_out(struct file *file, void *fh, struct v4l2_fo
vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, enc_fmt_list[VPU_FMT_TYPE_RAW]);
if (!vpu_fmt) {
+ width = inst->src_fmt.width;
+ height = inst->src_fmt.height;
f->fmt.pix_mp.pixelformat = inst->src_fmt.pixelformat;
- f->fmt.pix_mp.num_planes = inst->src_fmt.num_planes;
- wave5_update_pix_fmt(&f->fmt.pix_mp, inst->src_fmt.width, inst->src_fmt.height);
+ frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW];
} else {
- int width = clamp(f->fmt.pix_mp.width, vpu_fmt->min_width, vpu_fmt->max_width);
- int height = clamp(f->fmt.pix_mp.height, vpu_fmt->min_height, vpu_fmt->max_height);
- const struct v4l2_format_info *info = v4l2_format_info(vpu_fmt->v4l2_pix_fmt);
-
+ width = f->fmt.pix_mp.width;
+ height = f->fmt.pix_mp.height;
f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt;
- f->fmt.pix_mp.num_planes = info->mem_planes;
- wave5_update_pix_fmt(&f->fmt.pix_mp, width, height);
+ frmsize = vpu_fmt->v4l2_frmsize;
}
- f->fmt.pix_mp.flags = 0;
- f->fmt.pix_mp.field = V4L2_FIELD_NONE;
-
+ wave5_update_pix_fmt(&f->fmt.pix_mp, VPU_FMT_TYPE_RAW,
+ width, height, frmsize);
return 0;
}
static int wave5_vpu_enc_s_fmt_out(struct file *file, void *fh, struct v4l2_format *f)
{
struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ const struct vpu_format *vpu_fmt;
+ const struct v4l2_format_info *info;
int i, ret;
dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n",
@@ -549,16 +539,20 @@ static int wave5_vpu_enc_s_fmt_out(struct file *file, void *fh, struct v4l2_form
inst->src_fmt.plane_fmt[i].sizeimage = f->fmt.pix_mp.plane_fmt[i].sizeimage;
}
- if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12 ||
- inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12M) {
- inst->cbcr_interleave = true;
- inst->nv21 = false;
- } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21 ||
- inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21M) {
- inst->cbcr_interleave = true;
+ info = v4l2_format_info(inst->src_fmt.pixelformat);
+ if (!info)
+ return -EINVAL;
+
+ inst->cbcr_interleave = (info->comp_planes == 2) ? true : false;
+
+ switch (inst->src_fmt.pixelformat) {
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV21M:
+ case V4L2_PIX_FMT_NV61:
+ case V4L2_PIX_FMT_NV61M:
inst->nv21 = true;
- } else {
- inst->cbcr_interleave = false;
+ break;
+ default:
inst->nv21 = false;
}
@@ -567,7 +561,15 @@ static int wave5_vpu_enc_s_fmt_out(struct file *file, void *fh, struct v4l2_form
inst->quantization = f->fmt.pix_mp.quantization;
inst->xfer_func = f->fmt.pix_mp.xfer_func;
- wave5_update_pix_fmt(&inst->dst_fmt, f->fmt.pix_mp.width, f->fmt.pix_mp.height);
+ vpu_fmt = wave5_find_vpu_fmt(inst->dst_fmt.pixelformat, enc_fmt_list[VPU_FMT_TYPE_CODEC]);
+ if (!vpu_fmt)
+ return -EINVAL;
+
+ wave5_update_pix_fmt(&inst->dst_fmt, VPU_FMT_TYPE_CODEC,
+ f->fmt.pix_mp.width, f->fmt.pix_mp.height,
+ vpu_fmt->v4l2_frmsize);
+ inst->conf_win.width = inst->dst_fmt.width;
+ inst->conf_win.height = inst->dst_fmt.height;
return 0;
}
@@ -583,12 +585,17 @@ static int wave5_vpu_enc_g_selection(struct file *file, void *fh, struct v4l2_se
switch (s->target) {
case V4L2_SEL_TGT_CROP_DEFAULT:
case V4L2_SEL_TGT_CROP_BOUNDS:
- case V4L2_SEL_TGT_CROP:
s->r.left = 0;
s->r.top = 0;
s->r.width = inst->dst_fmt.width;
s->r.height = inst->dst_fmt.height;
break;
+ case V4L2_SEL_TGT_CROP:
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = inst->conf_win.width;
+ s->r.height = inst->conf_win.height;
+ break;
default:
return -EINVAL;
}
@@ -611,8 +618,10 @@ static int wave5_vpu_enc_s_selection(struct file *file, void *fh, struct v4l2_se
s->r.left = 0;
s->r.top = 0;
- s->r.width = inst->src_fmt.width;
- s->r.height = inst->src_fmt.height;
+ s->r.width = min(s->r.width, inst->dst_fmt.width);
+ s->r.height = min(s->r.height, inst->dst_fmt.height);
+
+ inst->conf_win = s->r;
return 0;
}
@@ -1061,6 +1070,9 @@ static int wave5_vpu_enc_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
inst->enc_param.entropy_coding_mode = ctrl->val;
break;
+ case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR:
+ inst->enc_param.forced_idr_header_enable = ctrl->val;
+ break;
case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:
break;
default:
@@ -1125,13 +1137,23 @@ static void wave5_vpu_enc_buf_queue(struct vb2_buffer *vb)
v4l2_m2m_buf_queue(m2m_ctx, vbuf);
}
-static void wave5_set_enc_openparam(struct enc_open_param *open_param,
- struct vpu_instance *inst)
+static int wave5_set_enc_openparam(struct enc_open_param *open_param,
+ struct vpu_instance *inst)
{
struct enc_wave_param input = inst->enc_param;
+ const struct v4l2_format_info *info;
u32 num_ctu_row = ALIGN(inst->dst_fmt.height, 64) / 64;
u32 num_mb_row = ALIGN(inst->dst_fmt.height, 16) / 16;
+ info = v4l2_format_info(inst->src_fmt.pixelformat);
+ if (!info)
+ return -EINVAL;
+
+ if (info->hdiv == 2 && info->vdiv == 1)
+ open_param->src_format = FORMAT_422;
+ else
+ open_param->src_format = FORMAT_420;
+
open_param->wave_param.gop_preset_idx = PRESET_IDX_IPP_SINGLE;
open_param->wave_param.hvs_qp_scale = 2;
open_param->wave_param.hvs_max_delta_qp = 10;
@@ -1147,8 +1169,8 @@ static void wave5_set_enc_openparam(struct enc_open_param *open_param,
open_param->wave_param.lambda_scaling_enable = 1;
open_param->line_buf_int_en = true;
- open_param->pic_width = inst->dst_fmt.width;
- open_param->pic_height = inst->dst_fmt.height;
+ open_param->pic_width = inst->conf_win.width;
+ open_param->pic_height = inst->conf_win.height;
open_param->frame_rate_info = inst->frame_rate;
open_param->rc_enable = inst->rc_enable;
if (inst->rc_enable) {
@@ -1219,6 +1241,9 @@ static void wave5_set_enc_openparam(struct enc_open_param *open_param,
else
open_param->wave_param.intra_refresh_arg = num_ctu_row;
}
+ open_param->wave_param.forced_idr_header_enable = input.forced_idr_header_enable;
+
+ return 0;
}
static int initialize_sequence(struct vpu_instance *inst)
@@ -1247,7 +1272,7 @@ static int initialize_sequence(struct vpu_instance *inst)
__func__, initial_info.min_frame_buffer_count,
initial_info.min_src_frame_count);
inst->min_src_buf_count = initial_info.min_src_frame_count +
- COMMAND_QUEUE_DEPTH;
+ WAVE521_COMMAND_QUEUE_DEPTH;
ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl,
V4L2_CID_MIN_BUFFERS_FOR_OUTPUT);
@@ -1306,6 +1331,7 @@ static int wave5_vpu_enc_start_streaming(struct vb2_queue *q, unsigned int count
struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
int ret = 0;
+ pm_runtime_resume_and_get(inst->dev->dev);
v4l2_m2m_update_start_streaming_state(m2m_ctx, q);
if (inst->state == VPU_INST_STATE_NONE && q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
@@ -1313,7 +1339,12 @@ static int wave5_vpu_enc_start_streaming(struct vb2_queue *q, unsigned int count
memset(&open_param, 0, sizeof(struct enc_open_param));
- wave5_set_enc_openparam(&open_param, inst);
+ ret = wave5_set_enc_openparam(&open_param, inst);
+ if (ret) {
+ dev_dbg(inst->dev->dev, "%s: wave5_set_enc_openparam, fail: %d\n",
+ __func__, ret);
+ goto return_buffers;
+ }
ret = wave5_vpu_enc_open(inst, &open_param);
if (ret) {
@@ -1360,9 +1391,13 @@ static int wave5_vpu_enc_start_streaming(struct vb2_queue *q, unsigned int count
if (ret)
goto return_buffers;
+ pm_runtime_mark_last_busy(inst->dev->dev);
+ pm_runtime_put_autosuspend(inst->dev->dev);
return 0;
return_buffers:
wave5_return_bufs(q, VB2_BUF_STATE_QUEUED);
+ pm_runtime_mark_last_busy(inst->dev->dev);
+ pm_runtime_put_autosuspend(inst->dev->dev);
return ret;
}
@@ -1404,6 +1439,7 @@ static void wave5_vpu_enc_stop_streaming(struct vb2_queue *q)
*/
dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type);
+ pm_runtime_resume_and_get(inst->dev->dev);
if (wave5_vpu_both_queues_are_streaming(inst))
switch_state(inst, VPU_INST_STATE_STOP);
@@ -1428,12 +1464,13 @@ static void wave5_vpu_enc_stop_streaming(struct vb2_queue *q)
streamoff_output(inst, q);
else
streamoff_capture(inst, q);
+
+ pm_runtime_mark_last_busy(inst->dev->dev);
+ pm_runtime_put_autosuspend(inst->dev->dev);
}
static const struct vb2_ops wave5_vpu_enc_vb2_ops = {
.queue_setup = wave5_vpu_enc_queue_setup,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.buf_queue = wave5_vpu_enc_buf_queue,
.start_streaming = wave5_vpu_enc_start_streaming,
.stop_streaming = wave5_vpu_enc_stop_streaming,
@@ -1442,20 +1479,15 @@ static const struct vb2_ops wave5_vpu_enc_vb2_ops = {
static void wave5_set_default_format(struct v4l2_pix_format_mplane *src_fmt,
struct v4l2_pix_format_mplane *dst_fmt)
{
- unsigned int src_pix_fmt = enc_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt;
- const struct v4l2_format_info *src_fmt_info = v4l2_format_info(src_pix_fmt);
-
- src_fmt->pixelformat = src_pix_fmt;
- src_fmt->field = V4L2_FIELD_NONE;
- src_fmt->flags = 0;
- src_fmt->num_planes = src_fmt_info->mem_planes;
- wave5_update_pix_fmt(src_fmt, 416, 240);
+ src_fmt->pixelformat = enc_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt;
+ wave5_update_pix_fmt(src_fmt, VPU_FMT_TYPE_RAW,
+ W5_DEF_ENC_PIC_WIDTH, W5_DEF_ENC_PIC_HEIGHT,
+ &enc_frmsize[VPU_FMT_TYPE_RAW]);
dst_fmt->pixelformat = enc_fmt_list[VPU_FMT_TYPE_CODEC][0].v4l2_pix_fmt;
- dst_fmt->field = V4L2_FIELD_NONE;
- dst_fmt->flags = 0;
- dst_fmt->num_planes = 1;
- wave5_update_pix_fmt(dst_fmt, 416, 240);
+ wave5_update_pix_fmt(dst_fmt, VPU_FMT_TYPE_CODEC,
+ W5_DEF_ENC_PIC_WIDTH, W5_DEF_ENC_PIC_HEIGHT,
+ &enc_frmsize[VPU_FMT_TYPE_CODEC]);
}
static int wave5_vpu_enc_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
@@ -1474,6 +1506,7 @@ static void wave5_vpu_enc_device_run(void *priv)
u32 fail_res = 0;
int ret = 0;
+ pm_runtime_resume_and_get(inst->dev->dev);
switch (inst->state) {
case VPU_INST_STATE_PIC_RUN:
ret = start_encode(inst, &fail_res);
@@ -1487,6 +1520,8 @@ static void wave5_vpu_enc_device_run(void *priv)
break;
}
dev_dbg(inst->dev->dev, "%s: leave with active job", __func__);
+ pm_runtime_mark_last_busy(inst->dev->dev);
+ pm_runtime_put_autosuspend(inst->dev->dev);
return;
default:
WARN(1, "Execution of a job in state %s is invalid.\n",
@@ -1494,6 +1529,8 @@ static void wave5_vpu_enc_device_run(void *priv)
break;
}
dev_dbg(inst->dev->dev, "%s: leave and finish job", __func__);
+ pm_runtime_mark_last_busy(inst->dev->dev);
+ pm_runtime_put_autosuspend(inst->dev->dev);
v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
}
@@ -1554,7 +1591,6 @@ static int wave5_vpu_open_enc(struct file *filp)
v4l2_fh_add(&inst->v4l2_fh);
INIT_LIST_HEAD(&inst->list);
- list_add_tail(&inst->list, &dev->instances);
inst->v4l2_m2m_dev = inst->dev->v4l2_m2m_enc_dev;
inst->v4l2_fh.m2m_ctx =
@@ -1702,6 +1738,9 @@ static int wave5_vpu_open_enc(struct file *filp)
0, 1, 1, 0);
v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 32, 1, 1);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR,
+ 0, 1, 1, 0);
if (v4l2_ctrl_hdl->error) {
ret = -ENODEV;
@@ -1712,6 +1751,8 @@ static int wave5_vpu_open_enc(struct file *filp)
v4l2_ctrl_handler_setup(v4l2_ctrl_hdl);
wave5_set_default_format(&inst->src_fmt, &inst->dst_fmt);
+ inst->conf_win.width = inst->dst_fmt.width;
+ inst->conf_win.height = inst->dst_fmt.height;
inst->colorspace = V4L2_COLORSPACE_REC709;
inst->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
inst->quantization = V4L2_QUANTIZATION_DEFAULT;
@@ -1729,6 +1770,17 @@ static int wave5_vpu_open_enc(struct file *filp)
wave5_vdi_allocate_sram(inst->dev);
+ ret = mutex_lock_interruptible(&dev->dev_lock);
+ if (ret)
+ goto cleanup_inst;
+
+ if (list_empty(&dev->instances))
+ pm_runtime_use_autosuspend(inst->dev->dev);
+
+ list_add_tail(&inst->list, &dev->instances);
+
+ mutex_unlock(&dev->dev_lock);
+
return 0;
cleanup_inst:
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu.c b/drivers/media/platform/chips-media/wave5/wave5-vpu.c
index 1b3df5b04249..e1715d3f43b0 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpu.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpu.c
@@ -10,6 +10,8 @@
#include <linux/clk.h>
#include <linux/firmware.h>
#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
#include "wave5-vpu.h"
#include "wave5-regdefine.h"
#include "wave5-vpuconfig.h"
@@ -24,8 +26,12 @@
struct wave5_match_data {
int flags;
const char *fw_name;
+ u32 sram_size;
};
+static int vpu_poll_interval = 5;
+module_param(vpu_poll_interval, int, 0644);
+
int wave5_vpu_wait_interrupt(struct vpu_instance *inst, unsigned int timeout)
{
int ret;
@@ -40,7 +46,7 @@ int wave5_vpu_wait_interrupt(struct vpu_instance *inst, unsigned int timeout)
return 0;
}
-static irqreturn_t wave5_vpu_irq_thread(int irq, void *dev_id)
+static void wave5_vpu_handle_irq(void *dev_id)
{
u32 seq_done;
u32 cmd_done;
@@ -48,42 +54,73 @@ static irqreturn_t wave5_vpu_irq_thread(int irq, void *dev_id)
struct vpu_instance *inst;
struct vpu_device *dev = dev_id;
- if (wave5_vdi_read_register(dev, W5_VPU_VPU_INT_STS)) {
- irq_reason = wave5_vdi_read_register(dev, W5_VPU_VINT_REASON);
- wave5_vdi_write_register(dev, W5_VPU_VINT_REASON_CLR, irq_reason);
- wave5_vdi_write_register(dev, W5_VPU_VINT_CLEAR, 0x1);
-
- list_for_each_entry(inst, &dev->instances, list) {
- seq_done = wave5_vdi_read_register(dev, W5_RET_SEQ_DONE_INSTANCE_INFO);
- cmd_done = wave5_vdi_read_register(dev, W5_RET_QUEUE_CMD_DONE_INST);
-
- if (irq_reason & BIT(INT_WAVE5_INIT_SEQ) ||
- irq_reason & BIT(INT_WAVE5_ENC_SET_PARAM)) {
- if (seq_done & BIT(inst->id)) {
- seq_done &= ~BIT(inst->id);
- wave5_vdi_write_register(dev, W5_RET_SEQ_DONE_INSTANCE_INFO,
- seq_done);
- complete(&inst->irq_done);
- }
+ irq_reason = wave5_vdi_read_register(dev, W5_VPU_VINT_REASON);
+ seq_done = wave5_vdi_read_register(dev, W5_RET_SEQ_DONE_INSTANCE_INFO);
+ cmd_done = wave5_vdi_read_register(dev, W5_RET_QUEUE_CMD_DONE_INST);
+ wave5_vdi_write_register(dev, W5_VPU_VINT_REASON_CLR, irq_reason);
+ wave5_vdi_write_register(dev, W5_VPU_VINT_CLEAR, 0x1);
+
+ list_for_each_entry(inst, &dev->instances, list) {
+
+ if (irq_reason & BIT(INT_WAVE5_INIT_SEQ) ||
+ irq_reason & BIT(INT_WAVE5_ENC_SET_PARAM)) {
+ if (dev->product_code == WAVE515_CODE &&
+ (cmd_done & BIT(inst->id))) {
+ cmd_done &= ~BIT(inst->id);
+ wave5_vdi_write_register(dev, W5_RET_QUEUE_CMD_DONE_INST,
+ cmd_done);
+ complete(&inst->irq_done);
+ } else if (seq_done & BIT(inst->id)) {
+ seq_done &= ~BIT(inst->id);
+ wave5_vdi_write_register(dev, W5_RET_SEQ_DONE_INSTANCE_INFO,
+ seq_done);
+ complete(&inst->irq_done);
}
+ }
- if (irq_reason & BIT(INT_WAVE5_DEC_PIC) ||
- irq_reason & BIT(INT_WAVE5_ENC_PIC)) {
- if (cmd_done & BIT(inst->id)) {
- cmd_done &= ~BIT(inst->id);
- wave5_vdi_write_register(dev, W5_RET_QUEUE_CMD_DONE_INST,
- cmd_done);
- inst->ops->finish_process(inst);
- }
+ if (irq_reason & BIT(INT_WAVE5_DEC_PIC) ||
+ irq_reason & BIT(INT_WAVE5_ENC_PIC)) {
+ if (cmd_done & BIT(inst->id)) {
+ cmd_done &= ~BIT(inst->id);
+ wave5_vdi_write_register(dev, W5_RET_QUEUE_CMD_DONE_INST,
+ cmd_done);
+ inst->ops->finish_process(inst);
}
-
- wave5_vpu_clear_interrupt(inst, irq_reason);
}
+
+ wave5_vpu_clear_interrupt(inst, irq_reason);
}
+}
+
+static irqreturn_t wave5_vpu_irq_thread(int irq, void *dev_id)
+{
+ struct vpu_device *dev = dev_id;
+
+ if (wave5_vdi_read_register(dev, W5_VPU_VPU_INT_STS))
+ wave5_vpu_handle_irq(dev);
return IRQ_HANDLED;
}
+static void wave5_vpu_irq_work_fn(struct kthread_work *work)
+{
+ struct vpu_device *dev = container_of(work, struct vpu_device, work);
+
+ if (wave5_vdi_read_register(dev, W5_VPU_VPU_INT_STS))
+ wave5_vpu_handle_irq(dev);
+}
+
+static enum hrtimer_restart wave5_vpu_timer_callback(struct hrtimer *timer)
+{
+ struct vpu_device *dev =
+ container_of(timer, struct vpu_device, hrtimer);
+
+ kthread_queue_work(dev->worker, &dev->work);
+ hrtimer_forward_now(timer, ns_to_ktime(vpu_poll_interval * NSEC_PER_MSEC));
+
+ return HRTIMER_RESTART;
+}
+
static int wave5_vpu_load_firmware(struct device *dev, const char *fw_name,
u32 *revision)
{
@@ -117,6 +154,45 @@ static int wave5_vpu_load_firmware(struct device *dev, const char *fw_name,
return 0;
}
+static __maybe_unused int wave5_pm_suspend(struct device *dev)
+{
+ struct vpu_device *vpu = dev_get_drvdata(dev);
+
+ if (pm_runtime_suspended(dev))
+ return 0;
+
+ if (vpu->irq < 0)
+ hrtimer_cancel(&vpu->hrtimer);
+
+ wave5_vpu_sleep_wake(dev, true, NULL, 0);
+ clk_bulk_disable_unprepare(vpu->num_clks, vpu->clks);
+
+ return 0;
+}
+
+static __maybe_unused int wave5_pm_resume(struct device *dev)
+{
+ struct vpu_device *vpu = dev_get_drvdata(dev);
+ int ret = 0;
+
+ wave5_vpu_sleep_wake(dev, false, NULL, 0);
+ ret = clk_bulk_prepare_enable(vpu->num_clks, vpu->clks);
+ if (ret) {
+ dev_err(dev, "Enabling clocks, fail: %d\n", ret);
+ return ret;
+ }
+
+ if (vpu->irq < 0 && !hrtimer_active(&vpu->hrtimer))
+ hrtimer_start(&vpu->hrtimer, ns_to_ktime(vpu->vpu_poll_interval * NSEC_PER_MSEC),
+ HRTIMER_MODE_REL_PINNED);
+
+ return ret;
+}
+
+static const struct dev_pm_ops wave5_pm_ops = {
+ SET_RUNTIME_PM_OPS(wave5_pm_suspend, wave5_pm_resume, NULL)
+};
+
static int wave5_vpu_probe(struct platform_device *pdev)
{
int ret;
@@ -151,6 +227,16 @@ static int wave5_vpu_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, dev);
dev->dev = &pdev->dev;
+ dev->resets = devm_reset_control_array_get_optional_exclusive(&pdev->dev);
+ if (IS_ERR(dev->resets)) {
+ return dev_err_probe(&pdev->dev, PTR_ERR(dev->resets),
+ "Failed to get reset control\n");
+ }
+
+ ret = reset_control_deassert(dev->resets);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Failed to deassert resets\n");
+
ret = devm_clk_bulk_get_all(&pdev->dev, &dev->clks);
/* continue without clock, assume externally managed */
@@ -163,20 +249,15 @@ static int wave5_vpu_probe(struct platform_device *pdev)
ret = clk_bulk_prepare_enable(dev->num_clks, dev->clks);
if (ret) {
dev_err(&pdev->dev, "Enabling clocks, fail: %d\n", ret);
- return ret;
- }
-
- ret = of_property_read_u32(pdev->dev.of_node, "sram-size",
- &dev->sram_size);
- if (ret) {
- dev_warn(&pdev->dev, "sram-size not found\n");
- dev->sram_size = 0;
+ goto err_reset_assert;
}
dev->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0);
if (!dev->sram_pool)
dev_warn(&pdev->dev, "sram node not found\n");
+ dev->sram_size = match_data->sram_size;
+
dev->product_code = wave5_vdi_read_register(dev, VPU_PRODUCT_CODE_REGISTER);
ret = wave5_vdi_init(&pdev->dev);
if (ret < 0) {
@@ -185,6 +266,28 @@ static int wave5_vpu_probe(struct platform_device *pdev)
}
dev->product = wave5_vpu_get_product_id(dev);
+ dev->irq = platform_get_irq(pdev, 0);
+ if (dev->irq < 0) {
+ dev_err(&pdev->dev, "failed to get irq resource, falling back to polling\n");
+ hrtimer_setup(&dev->hrtimer, &wave5_vpu_timer_callback, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL_PINNED);
+ dev->worker = kthread_run_worker(0, "vpu_irq_thread");
+ if (IS_ERR(dev->worker)) {
+ dev_err(&pdev->dev, "failed to create vpu irq worker\n");
+ ret = PTR_ERR(dev->worker);
+ goto err_vdi_release;
+ }
+ dev->vpu_poll_interval = vpu_poll_interval;
+ kthread_init_work(&dev->work, wave5_vpu_irq_work_fn);
+ } else {
+ ret = devm_request_threaded_irq(&pdev->dev, dev->irq, NULL,
+ wave5_vpu_irq_thread, IRQF_ONESHOT, "vpu_irq", dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Register interrupt handler, fail: %d\n", ret);
+ goto err_enc_unreg;
+ }
+ }
+
INIT_LIST_HEAD(&dev->instances);
ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
if (ret) {
@@ -207,20 +310,6 @@ static int wave5_vpu_probe(struct platform_device *pdev)
}
}
- dev->irq = platform_get_irq(pdev, 0);
- if (dev->irq < 0) {
- dev_err(&pdev->dev, "failed to get irq resource\n");
- ret = -ENXIO;
- goto err_enc_unreg;
- }
-
- ret = devm_request_threaded_irq(&pdev->dev, dev->irq, NULL,
- wave5_vpu_irq_thread, IRQF_ONESHOT, "vpu_irq", dev);
- if (ret) {
- dev_err(&pdev->dev, "Register interrupt handler, fail: %d\n", ret);
- goto err_enc_unreg;
- }
-
ret = wave5_vpu_load_firmware(&pdev->dev, match_data->fw_name, &fw_revision);
if (ret) {
dev_err(&pdev->dev, "wave5_vpu_load_firmware, fail: %d\n", ret);
@@ -232,6 +321,12 @@ static int wave5_vpu_probe(struct platform_device *pdev)
(match_data->flags & WAVE5_IS_DEC) ? "'DECODE'" : "");
dev_info(&pdev->dev, "Product Code: 0x%x\n", dev->product_code);
dev_info(&pdev->dev, "Firmware Revision: %u\n", fw_revision);
+
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 100);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ wave5_vpu_sleep_wake(&pdev->dev, true, NULL, 0);
+
return 0;
err_enc_unreg:
@@ -246,6 +341,8 @@ err_vdi_release:
wave5_vdi_release(&pdev->dev);
err_clk_dis:
clk_bulk_disable_unprepare(dev->num_clks, dev->clks);
+err_reset_assert:
+ reset_control_assert(dev->resets);
return ret;
}
@@ -254,8 +351,17 @@ static void wave5_vpu_remove(struct platform_device *pdev)
{
struct vpu_device *dev = dev_get_drvdata(&pdev->dev);
+ if (dev->irq < 0) {
+ kthread_destroy_worker(dev->worker);
+ hrtimer_cancel(&dev->hrtimer);
+ }
+
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
mutex_destroy(&dev->dev_lock);
mutex_destroy(&dev->hw_lock);
+ reset_control_assert(dev->resets);
clk_bulk_disable_unprepare(dev->num_clks, dev->clks);
wave5_vpu_enc_unregister_device(dev);
wave5_vpu_dec_unregister_device(dev);
@@ -267,6 +373,7 @@ static void wave5_vpu_remove(struct platform_device *pdev)
static const struct wave5_match_data ti_wave521c_data = {
.flags = WAVE5_IS_ENC | WAVE5_IS_DEC,
.fw_name = "cnm/wave521c_k3_codec_fw.bin",
+ .sram_size = (64 * 1024),
};
static const struct of_device_id wave5_dt_ids[] = {
@@ -279,9 +386,10 @@ static struct platform_driver wave5_vpu_driver = {
.driver = {
.name = VPU_PLATFORM_DEVICE_NAME,
.of_match_table = of_match_ptr(wave5_dt_ids),
+ .pm = &wave5_pm_ops,
},
.probe = wave5_vpu_probe,
- .remove_new = wave5_vpu_remove,
+ .remove = wave5_vpu_remove,
};
module_platform_driver(wave5_vpu_driver);
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu.h b/drivers/media/platform/chips-media/wave5/wave5-vpu.h
index 32b7fd3730b5..3847332551fc 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpu.h
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpu.h
@@ -38,10 +38,7 @@ enum vpu_fmt_type {
struct vpu_format {
unsigned int v4l2_pix_fmt;
- unsigned int max_width;
- unsigned int min_width;
- unsigned int max_height;
- unsigned int min_height;
+ const struct v4l2_frmsize_stepwise *v4l2_frmsize;
};
static inline struct vpu_instance *wave5_to_vpu_inst(struct v4l2_fh *vfh)
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c
index 1a3efb638dde..e5e879a13e8b 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c
@@ -6,6 +6,8 @@
*/
#include <linux/bug.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
#include "wave5-vpuapi.h"
#include "wave5-regdefine.h"
#include "wave5.h"
@@ -73,6 +75,16 @@ int wave5_vpu_flush_instance(struct vpu_instance *inst)
inst->type == VPU_INST_TYPE_DEC ? "DECODER" : "ENCODER", inst->id);
mutex_unlock(&inst->dev->hw_lock);
return -ETIMEDOUT;
+ } else if (ret == -EBUSY) {
+ struct dec_output_info dec_info;
+
+ mutex_unlock(&inst->dev->hw_lock);
+ wave5_vpu_dec_get_output_info(inst, &dec_info);
+ ret = mutex_lock_interruptible(&inst->dev->hw_lock);
+ if (ret)
+ return ret;
+ if (dec_info.index_frame_display > 0)
+ wave5_vpu_dec_set_disp_flag(inst, dec_info.index_frame_display);
}
} while (ret != 0);
mutex_unlock(&inst->dev->hw_lock);
@@ -195,14 +207,20 @@ int wave5_vpu_dec_close(struct vpu_instance *inst, u32 *fail_res)
int retry = 0;
struct vpu_device *vpu_dev = inst->dev;
int i;
+ int inst_count = 0;
+ struct vpu_instance *inst_elm;
*fail_res = 0;
if (!inst->codec_info)
return -EINVAL;
+ pm_runtime_resume_and_get(inst->dev->dev);
+
ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
- if (ret)
+ if (ret) {
+ pm_runtime_put_sync(inst->dev->dev);
return ret;
+ }
do {
ret = wave5_vpu_dec_finish_seq(inst, fail_res);
@@ -232,9 +250,14 @@ int wave5_vpu_dec_close(struct vpu_instance *inst, u32 *fail_res)
wave5_vdi_free_dma_memory(vpu_dev, &p_dec_info->vb_task);
+ list_for_each_entry(inst_elm, &vpu_dev->instances, list)
+ inst_count++;
+ if (inst_count == 1)
+ pm_runtime_dont_use_autosuspend(vpu_dev->dev);
+
unlock_and_return:
mutex_unlock(&vpu_dev->hw_lock);
-
+ pm_runtime_put_sync(inst->dev->dev);
return ret;
}
@@ -697,25 +720,33 @@ int wave5_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res)
int ret;
int retry = 0;
struct vpu_device *vpu_dev = inst->dev;
+ int inst_count = 0;
+ struct vpu_instance *inst_elm;
*fail_res = 0;
if (!inst->codec_info)
return -EINVAL;
+ pm_runtime_resume_and_get(inst->dev->dev);
+
ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
- if (ret)
+ if (ret) {
+ pm_runtime_resume_and_get(inst->dev->dev);
return ret;
+ }
do {
ret = wave5_vpu_enc_finish_seq(inst, fail_res);
if (ret < 0 && *fail_res != WAVE5_SYSERR_VPU_STILL_RUNNING) {
dev_warn(inst->dev->dev, "enc_finish_seq timed out\n");
+ pm_runtime_resume_and_get(inst->dev->dev);
mutex_unlock(&vpu_dev->hw_lock);
return ret;
}
if (*fail_res == WAVE5_SYSERR_VPU_STILL_RUNNING &&
retry++ >= MAX_FIRMWARE_CALL_RETRY) {
+ pm_runtime_resume_and_get(inst->dev->dev);
mutex_unlock(&vpu_dev->hw_lock);
return -ETIMEDOUT;
}
@@ -734,7 +765,13 @@ int wave5_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res)
wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_task);
+ list_for_each_entry(inst_elm, &vpu_dev->instances, list)
+ inst_count++;
+ if (inst_count == 1)
+ pm_runtime_dont_use_autosuspend(vpu_dev->dev);
+
mutex_unlock(&vpu_dev->hw_lock);
+ pm_runtime_put_sync(inst->dev->dev);
return 0;
}
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
index 352f6e904e50..45615c15beca 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
@@ -18,6 +18,7 @@
#include "wave5-vdi.h"
enum product_id {
+ PRODUCT_ID_515,
PRODUCT_ID_521,
PRODUCT_ID_511,
PRODUCT_ID_517,
@@ -327,6 +328,7 @@ struct vpu_attr {
u32 support_backbone: 1;
u32 support_avc10bit_enc: 1;
u32 support_hevc10bit_enc: 1;
+ u32 support_hevc10bit_dec: 1;
u32 support_vcore_backbone: 1;
u32 support_vcpu_backbone: 1;
};
@@ -566,6 +568,7 @@ struct enc_wave_param {
u32 lambda_scaling_enable: 1; /* enable lambda scaling using custom GOP */
u32 transform8x8_enable: 1; /* enable 8x8 intra prediction and 8x8 transform */
u32 mb_level_rc_enable: 1; /* enable MB-level rate control */
+ u32 forced_idr_header_enable: 1; /* enable header encoding before IDR frame */
};
struct enc_open_param {
@@ -756,7 +759,12 @@ struct vpu_device {
u32 product_code;
struct ida inst_ida;
struct clk_bulk_data *clks;
+ struct hrtimer hrtimer;
+ struct kthread_work work;
+ struct kthread_worker *worker;
+ int vpu_poll_interval;
int num_clks;
+ struct reset_control *resets;
};
struct vpu_instance;
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h b/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h
index d9751eedb0f9..1ea9f5f31499 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h
@@ -8,6 +8,7 @@
#ifndef _VPU_CONFIG_H_
#define _VPU_CONFIG_H_
+#define WAVE515_CODE 0x5150
#define WAVE517_CODE 0x5170
#define WAVE537_CODE 0x5370
#define WAVE511_CODE 0x5110
@@ -21,19 +22,39 @@
((c) == WAVE517_CODE || (c) == WAVE537_CODE || \
(c) == WAVE511_CODE || (c) == WAVE521_CODE || \
(c) == WAVE521E1_CODE || (c) == WAVE521C_CODE || \
- (c) == WAVE521C_DUAL_CODE); \
+ (c) == WAVE521C_DUAL_CODE) || (c) == WAVE515_CODE; \
})
#define WAVE517_WORKBUF_SIZE (2 * 1024 * 1024)
#define WAVE521ENC_WORKBUF_SIZE (128 * 1024) //HEVC 128K, AVC 40K
#define WAVE521DEC_WORKBUF_SIZE (1784 * 1024)
+#define WAVE515DEC_WORKBUF_SIZE (2 * 1024 * 1024)
#define MAX_NUM_INSTANCE 32
-#define W5_MIN_ENC_PIC_WIDTH 256
-#define W5_MIN_ENC_PIC_HEIGHT 128
-#define W5_MAX_ENC_PIC_WIDTH 8192
-#define W5_MAX_ENC_PIC_HEIGHT 8192
+#define W5_DEF_DEC_PIC_WIDTH 720U
+#define W5_DEF_DEC_PIC_HEIGHT 480U
+#define W5_MIN_DEC_PIC_8_WIDTH 8U
+#define W5_MIN_DEC_PIC_8_HEIGHT 8U
+#define W5_MIN_DEC_PIC_32_WIDTH 32U
+#define W5_MIN_DEC_PIC_32_HEIGHT 32U
+#define W5_MAX_DEC_PIC_WIDTH 8192U
+#define W5_MAX_DEC_PIC_HEIGHT 4320U
+#define W5_DEC_CODEC_STEP_WIDTH 1U
+#define W5_DEC_CODEC_STEP_HEIGHT 1U
+#define W5_DEC_RAW_STEP_WIDTH 32U
+#define W5_DEC_RAW_STEP_HEIGHT 16U
+
+#define W5_DEF_ENC_PIC_WIDTH 416U
+#define W5_DEF_ENC_PIC_HEIGHT 240U
+#define W5_MIN_ENC_PIC_WIDTH 256U
+#define W5_MIN_ENC_PIC_HEIGHT 128U
+#define W5_MAX_ENC_PIC_WIDTH 8192U
+#define W5_MAX_ENC_PIC_HEIGHT 8192U
+#define W5_ENC_CODEC_STEP_WIDTH 8U
+#define W5_ENC_CODEC_STEP_HEIGHT 8U
+#define W5_ENC_RAW_STEP_WIDTH 32U
+#define W5_ENC_RAW_STEP_HEIGHT 16U
// application specific configuration
#define VPU_ENC_TIMEOUT 60000
@@ -49,17 +70,21 @@
/************************************************************************/
#define VLC_BUF_NUM (2)
-#define COMMAND_QUEUE_DEPTH (2)
+#define WAVE521_COMMAND_QUEUE_DEPTH (2)
+#define WAVE515_COMMAND_QUEUE_DEPTH (4)
#define W5_REMAP_INDEX0 0
#define W5_REMAP_INDEX1 1
#define W5_REMAP_MAX_SIZE (1024 * 1024)
-#define WAVE5_MAX_CODE_BUF_SIZE (2 * 1024 * 1024)
-#define WAVE5_TEMPBUF_OFFSET WAVE5_MAX_CODE_BUF_SIZE
+#define WAVE521_MAX_CODE_BUF_SIZE (2 * 1024 * 1024)
+#define WAVE515_MAX_CODE_BUF_SIZE (1024 * 1024)
#define WAVE5_TEMPBUF_SIZE (1024 * 1024)
-#define SIZE_COMMON (WAVE5_MAX_CODE_BUF_SIZE + WAVE5_TEMPBUF_SIZE)
+#define WAVE521_SIZE_COMMON (WAVE521_MAX_CODE_BUF_SIZE + WAVE5_TEMPBUF_SIZE)
+#define WAVE515_ONE_TASKBUF_SIZE (8 * 1024 * 1024)
+#define WAVE515_SIZE_COMMON (WAVE515_MAX_CODE_BUF_SIZE + WAVE5_TEMPBUF_SIZE + \
+ WAVE515_COMMAND_QUEUE_DEPTH * WAVE515_ONE_TASKBUF_SIZE)
//=====4. VPU REPORT MEMORY ======================//
diff --git a/drivers/media/platform/chips-media/wave5/wave5.h b/drivers/media/platform/chips-media/wave5/wave5.h
index 063028eccd3b..2caab356f3e1 100644
--- a/drivers/media/platform/chips-media/wave5/wave5.h
+++ b/drivers/media/platform/chips-media/wave5/wave5.h
@@ -22,6 +22,12 @@
*/
#define BSOPTION_ENABLE_EXPLICIT_END BIT(0)
#define BSOPTION_HIGHLIGHT_STREAM_END BIT(1)
+/*
+ * When RD_PTR_VALID_FLAG is 0 Wave515 ignores RD_PTR value and starts to
+ * decode from the access unit end position of the last decoded picture in
+ * bitstream buffer.
+ */
+#define BSOPTION_RD_PTR_VALID_FLAG BIT(31)
/*
* Currently the driver only supports hardware with little endian but for source
@@ -56,6 +62,9 @@ int wave5_vpu_get_version(struct vpu_device *vpu_dev, u32 *revision);
int wave5_vpu_init(struct device *dev, u8 *fw, size_t size);
+int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uint16_t *code,
+ size_t size);
+
int wave5_vpu_reset(struct device *dev, enum sw_reset_mode reset_mode);
int wave5_vpu_build_up_dec_param(struct vpu_instance *inst, struct dec_open_param *param);