1
0
mirror of https://github.com/physwizz/a155-U-u1.git synced 2025-10-07 10:09:34 +00:00
Files
physwizz 99537be4e2 first
2024-03-11 06:53:12 +11:00

249 lines
5.5 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2020 MediaTek Inc.
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/string.h>
#include "vpu_cmd.h"
#include "vpu_cmn.h"
#include "vpu_algo.h"
#include "vpu_debug.h"
static uint32_t prop_info_data_length;
const size_t g_vpu_prop_type_size[VPU_NUM_PROP_TYPES] = {
[VPU_PROP_TYPE_CHAR] = sizeof(char),
[VPU_PROP_TYPE_INT32] = sizeof(int32_t),
[VPU_PROP_TYPE_FLOAT] = sizeof(int32_t),
[VPU_PROP_TYPE_INT64] = sizeof(int64_t),
[VPU_PROP_TYPE_DOUBLE] = sizeof(int64_t)
};
struct vpu_prop_desc g_vpu_prop_descs[VPU_NUM_PROPS] = {
#define INS_PROP(id, name, type, count, access) \
{ VPU_PROP_ ## id, VPU_PROP_TYPE_ ## type, \
VPU_PROP_ACCESS_ ## access, 0, count, name }
INS_PROP(RESERVED, "reserved", INT32, 256, RDONLY),
#undef INS_PROP
};
/* called by vpu_init(), calculating prop_info_data_length */
void vpu_init_algo(void)
{
int i = 0;
unsigned int offset = 0;
unsigned int prop_data_length;
struct vpu_prop_desc *prop_desc;
for (i = 0; i < VPU_NUM_PROPS; i++) {
prop_desc = &g_vpu_prop_descs[i];
prop_desc->offset = offset;
prop_data_length = prop_desc->count *
g_vpu_prop_type_size[prop_desc->type];
offset += prop_data_length;
}
/* the total length = last offset + last data length */
prop_info_data_length = offset;
vpu_alg_debug("%s: prop_info_data_length: %x\n",
__func__, prop_info_data_length);
}
static struct __vpu_algo *vpu_alg_get(struct vpu_algo_list *al,
const char *name, struct __vpu_algo *alg)
{
if (alg) {
kref_get(&alg->ref);
goto out;
}
if (!name)
goto out;
/* search from tail, so that existing algorithm can be
* overidden by dynamic loaded ones.
**/
spin_lock(&al->lock);
list_for_each_entry_reverse(alg, &al->a, list) {
if (!strcmp(alg->a.name, name)) {
/* found, reference count++ */
kref_get(&alg->ref);
goto unlock;
}
}
alg = NULL;
unlock:
spin_unlock(&al->lock);
out:
if (alg)
vpu_alg_debug("%s: vpu%d: %s: %s: ref: %d builtin: %d\n",
__func__, al->vd->id, al->name, alg->a.name,
kref_read(&alg->ref), alg->builtin);
else
vpu_alg_debug("%s: vpu%d: %s: %s was not found\n",
__func__, al->vd->id, al->name, name);
return alg;
}
static void vpu_alg_release(struct kref *ref)
{
struct __vpu_algo *alg
= container_of(ref, struct __vpu_algo, ref);
struct vpu_algo_list *al = alg->al;
spin_lock(&al->lock);
list_del(&alg->list);
al->cnt--;
spin_unlock(&al->lock);
vpu_alg_debug("%s: vpu%d: %s: %s, algo_cnt: %d builtin: %d\n",
__func__, al->vd->id, al->name, alg->a.name,
al->cnt, alg->builtin);
/* free __vpu_algo memory */
vpu_alg_free(container_of(ref, struct __vpu_algo, ref));
}
static void vpu_alg_put(struct __vpu_algo *alg)
{
vpu_alg_debug("%s: vpu%d: %s: %s: ref: %d builtin: %d\n",
__func__, alg->al->vd->id, alg->al->name, alg->a.name,
kref_read(&alg->ref), alg->builtin);
kref_put(&alg->ref, alg->al->ops->release);
}
/**
* vpu_alg_unload() - unload currently loaded algorithm of
* command priority "prio" from vpu
* @vd: vpu device
* @prio: command priority
*
* vpu_cmd_lock() must be locked before calling this function
*/
static void vpu_alg_unload(struct vpu_algo_list *al, int prio)
{
struct __vpu_algo *alg;
if (!al)
return;
alg = vpu_cmd_alg(al->vd, prio);
if (!alg)
return;
al->ops->put(alg);
vpu_cmd_alg_clr(al->vd, prio);
}
/**
* vpu_alg_load() - load an algortihm for normal priority(0)
* d2d execution
* @vd: vpu device
*
* Automatically unload currently loaded algortihm, and
* load given one.
* vpu_cmd_lock() must be locked before calling this function
*/
static int vpu_alg_load(struct vpu_algo_list *al, const char *name,
struct __vpu_algo *alg, int prio)
{
int ret = 0;
alg = al->ops->get(al, name, alg);
if (!alg) {
vpu_alg_debug("%s: vpu%d: %s: \"%s\" was not found\n",
__func__, al->vd->id, al->name, name);
return -ENOENT;
}
al->ops->unload(al, prio);
if (al->ops->hw_init) {
ret = al->ops->hw_init(al, alg);
if (ret) {
pr_info("%s: vpu%d: %s: hw_init: %d\n",
__func__, al->vd->id, al->name, ret);
al->ops->put(alg);
goto out;
}
}
vpu_cmd_alg_set(al->vd, prio, alg);
out:
return ret;
}
struct __vpu_algo *vpu_alg_alloc(struct vpu_algo_list *al)
{
struct __vpu_algo *algo;
algo = kzalloc(sizeof(struct __vpu_algo) +
prop_info_data_length, GFP_KERNEL);
if (!algo)
return NULL;
algo->a.info.ptr = (uintptr_t) algo + sizeof(struct __vpu_algo);
algo->a.info.length = prop_info_data_length;
algo->builtin = false;
algo->al = al;
INIT_LIST_HEAD(&algo->list);
kref_init(&algo->ref); /* init count = 1 */
return algo;
}
void vpu_alg_free(struct __vpu_algo *alg)
{
struct vpu_device *vd = alg->al->vd;
struct device *dev = vd->dev;
struct vpu_mem_ops *mops = vd_mops(vd);
mops->free(dev, &alg->prog);
mops->free(dev, &alg->iram);
kfree(alg);
}
int vpu_alloc_request(struct vpu_request **rreq)
{
struct vpu_request *req;
req = kzalloc(sizeof(struct vpu_request), GFP_KERNEL);
if (!req)
return -ENOMEM;
*rreq = req;
return 0;
}
int vpu_free_request(struct vpu_request *req)
{
if (req != NULL)
kfree(req);
return 0;
}
struct vpu_algo_ops vpu_normal_aops = {
.load = vpu_alg_load,
.unload = vpu_alg_unload,
.get = vpu_alg_get,
.put = vpu_alg_put,
.release = vpu_alg_release,
.hw_init = vpu_hw_alg_init,
};
struct vpu_algo_ops vpu_prelaod_aops = {
.load = vpu_alg_load,
.unload = vpu_alg_unload,
.get = vpu_alg_get,
.put = vpu_alg_put,
.release = vpu_alg_release,
.hw_init = NULL,
};