// 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 <linux/pm_runtime.h>
#include <linux/delay.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 mutex_ret = 0;
int retry = 0;
mutex_ret = mutex_lock_interruptible(&inst->dev->hw_lock);
if (mutex_ret)
return mutex_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;
} 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);
mutex_ret = mutex_lock_interruptible(&inst->dev->hw_lock);
if (mutex_ret)
return mutex_ret;
if (dec_info.index_frame_display >= 0) {
mutex_unlock(&inst->dev->hw_lock);
wave5_vpu_dec_set_disp_flag(inst, dec_info.index_frame_display);
mutex_ret = mutex_lock_interruptible(&inst->dev->hw_lock);
if (mutex_ret)
return mutex_ret;
}
}
} 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