// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
/*
* Wave5 series multi-standard codec IP - helper functions
*
* Copyright (C) 2021-2023 CHIPS&MEDIA INC
*/
#include <linux/bug.h>
#include "wave5-vpuapi.h"
#include "wave5-regdefine.h"
#include "wave5.h"
#define DECODE_ALL_TEMPORAL_LAYERS 0
#define DECODE_ALL_SPATIAL_LAYERS 0
static int wave5_initialize_vpu(struct device *dev, u8 *code, size_t size)
{
int ret;
struct vpu_device *vpu_dev = dev_get_drvdata(dev);
ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
if (ret)
return ret;
if (wave5_vpu_is_init(vpu_dev)) {
wave5_vpu_re_init(dev, (void *)code, size);
ret = -EBUSY;
goto err_out;
}
ret = wave5_vpu_reset(dev, SW_RESET_ON_BOOT);
if (ret)
goto err_out;
ret = wave5_vpu_init(dev, (void *)code, size);
err_out:
mutex_unlock(&vpu_dev->hw_lock);
return ret;
}
int wave5_vpu_init_with_bitcode(struct device *dev, u8 *bitcode, size_t size)
{
if (!bitcode || size == 0)
return -EINVAL;
return wave5_initialize_vpu(dev, bitcode, size);
}
int wave5_vpu_flush_instance(struct vpu_instance *inst)
{
int ret = 0;
int retry = 0;
ret = mutex_lock_interruptible(&inst->dev->hw_lock);
if (ret)
return ret;
do {
/*
* Repeat the FLUSH command until the firmware reports that the
* VPU isn't running anymore
*/
ret = wave5_vpu_hw_flush_instance(inst);
if (ret < 0 && ret != -EBUSY) {
dev_warn(inst->dev->dev, "Flush of %s instance with id: %d fail: %d\n",
inst->type == VPU_INST_TYPE_DEC ? "DECODER" : "ENCODER", inst->id,
ret);
mutex_unlock(&inst->dev->hw_lock);
return ret;
}
if (ret == -EBUSY && retry++ >= MAX_FIRMWARE_CALL_RETRY) {
dev_warn(inst->dev->dev, "Flush of %s instance with id: %d timed out!\n",
inst->type == VPU_INST_TYPE_DEC ? "DECODER" : "ENCODER", inst->id);
mutex_unlock(&inst->dev->hw_lock);
return -ETIMEDOUT;
}
} while (ret != 0);
mutex_unlock(&inst->dev->hw_lock);
return ret;
}
int wave5_vpu_get_version_info(struct device *dev, u32 *revision, unsigned int *product_id)
{
int ret;
struct vpu_device *vpu_dev = dev_get_drvdata(dev);
ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
if (ret)
return ret;
if (!wave5_vpu_is_init(vpu_dev)) {
ret = -EINVAL;
goto err_out;
}
if (product_id)
*product_id = vpu_dev->product;
ret = wave5_vpu_get_version(vpu_dev, revision);
err_out:
mutex_unlock(&vpu_dev->hw_lock);
return ret;
}
static int wave5_check_dec_open_param(struct vpu_instance *inst, struct dec_open_param *param)
{
if (inst->id >= MAX_NUM_INSTANCE) {
dev_err(inst->dev->dev, "Too many simultaneous instances: %d (max: %u)\n",
inst->id, MAX_NUM_INSTANCE);
return -EOPNOTSUPP;
}
if (param->bitstream_buffer % 8) {
dev_err(inst->dev->dev,
"Bitstream buffer must be aligned to a multiple of 8\n");
return -EINVAL;
}
if (param->bitstream_buffer_size % 1024 ||
param->bitstream_buffer_size < MIN_BITSTREAM_BUFFER_SIZE) {
dev_err(inst->dev->dev,
"Bitstream buffer size must be aligned to a multiple of 1024 and have a minimum size of %d\n",
MIN_BITSTREAM_BUFFER_SIZE);
return -EINVAL;
}
return 0;
}
int wave5_vpu_dec_open(struct vpu_instance *inst, struct dec_open_param *open_param)
{
struct dec_info *p_dec_info;
int ret;
struct vpu_device *vpu_dev = inst->dev;
dma_addr_t buffer_addr;
size_t buffer_size;
ret = wave5_check_dec_open_param(inst, open_param);
if (ret)
return ret;
ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
if (ret)
return ret;
if (!wave5_vpu_is_init(vpu_dev)) {
mutex_unlock(&vpu_dev->hw_lock);
return -ENODEV;
}
p_dec_info = &inst->codec_info->dec_info;
memcpy(&p_dec_info->open_param, open_param, sizeof(struct dec_open_param));
buffer_addr = open_param->bitstream_buffer;
buffer_size = open_param->bitstream_buffer_size;
p_dec_info->stream_wr_ptr = buffer_addr;
p_dec_info->stream_rd_ptr = buffer_addr;
p_dec_info->stream_buf_start_addr = buffer_addr;
p_dec_info->stream_buf_size = buffer_size;
p_dec_info->stream_buf_end_addr = buffer_addr + buffer_size;
p_dec_info->reorder_enable = TRUE;
p_dec_info->temp_id_select_mode = TEMPORAL_ID_MODE_ABSOLUTE;
p_dec_info->target_temp_id = DECODE_ALL_TEMPORAL_LAYERS;
p_dec_info->target_spatial_id = DECODE_ALL_SPATIAL_LAYERS;
ret = wave5_vpu_build_up_dec_param(inst, open_param);
mutex_unlock(&vpu_dev->hw_lock);
return ret;
}
static int reset_auxiliary_buffers(struct vpu_instance *inst, unsigned int index)
{
struct dec_info *p_dec_info = &inst->codec_info->dec_info;
if (index >= MAX_REG_FRAME)
return 1;
if (p_dec_info->vb_mv[index].size == 0 && p_dec_info->vb_fbc_y_tbl[index].size == 0 &&
p_dec_info->vb_fbc_c_tbl[index].size == 0