// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2021 MediaTek Inc.
 */

#include "mdw_cmn.h"
#include "mdw_rv.h"
#include "mdw_rv_tag.h"

static int mdw_rv_sw_init(struct mdw_device *mdev)
{
	int ret = 0, i = 0;
	struct mdw_rv_dev *mrdev = (struct mdw_rv_dev *)mdev->dev_specific;
	struct mdw_dinfo *d = NULL;

	/* update device infos */
	for (i = 0; i < MDW_DEV_MAX; i++) {
		if (!test_bit(i, mrdev->dev_mask) || mdev->dinfos[i])
			continue;

		/* setup mdev's info */
		d = kzalloc(sizeof(*d), GFP_KERNEL);
		if (!d)
			goto free_dinfo;

		d->num = mrdev->dev_num[i];
		d->type = i;

		/* meta data */
		memcpy(d->meta, &mrdev->meta_data[i][0], sizeof(d->meta));
		mdw_drv_debug("dev(%u) support (%u)core\n", d->type, d->num);

		mdev->dinfos[i] = d;
		bitmap_set(mdev->dev_mask, i, 1);
	}

	/* update mem infos */
	mrdev = (struct mdw_rv_dev *)mdev->dev_specific;
	memcpy(mdev->mem_mask, mrdev->mem_mask, sizeof(mdev->mem_mask));
	memcpy(mdev->minfos, mrdev->minfos, sizeof(mdev->minfos));

	goto out;

free_dinfo:
	for (i = 0; i < MDW_DEV_MAX; i++) {
		if (mdev->dinfos[i] != NULL) {
			kfree(mdev->dinfos[i]);
			mdev->dinfos[i] = NULL;
		}
	}
	ret = -ENOMEM;
out:
	return 0;
}

static void mdw_rv_sw_deinit(struct mdw_device *mdev)
{
	unsigned int i = 0;

	for (i = 0; i < MDW_DEV_MAX; i++) {
		if (mdev->dinfos[i] != NULL) {
			kfree(mdev->dinfos[i]);
			mdev->dinfos[i] = NULL;
		}
	}
}

static int mdw_rv_late_init(struct mdw_device *mdev)
{
	int ret = 0;

	mdw_rv_tag_init();

	/* init rv device */
	ret = mdw_rv_dev_init(mdev);
	if (ret || !mdev->dev_specific) {
		mdw_drv_err("init mdw rvdev fail(%d)\n", ret);
		goto dev_deinit;
	}

	goto out;

dev_deinit:
	mdw_rv_dev_deinit(mdev);
out:
	return ret;
}

static void mdw_rv_late_deinit(struct mdw_device *mdev)
{
	mdw_rv_dev_deinit(mdev);
	mdw_rv_tag_deinit();
}

static int mdw_rv_run_cmd(struct mdw_fpriv *mpriv, struct mdw_cmd *c)
{
	return mdw_rv_dev_run_cmd(mpriv, c);
}

static int mdw_rv_set_power(struct mdw_device *mdev,
	uint32_t type, uint32_t idx, uint32_t boost)
{
	return -EINVAL;
}

static int mdw_rv_ucmd(struct mdw_device *mdev,
	uint32_t type, void *vaddr, uint32_t size)
{
	return -EINVAL;
}

static int mdw_rv_set_param(struct mdw_device *mdev,
	enum mdw_info_type type, uint32_t val)
{
	struct mdw_rv_dev *mrdev = (struct mdw_rv_dev *)mdev->dev_specific;

	return mdw_rv_dev_set_param(mrdev, type, val);
}

static uint32_t mdw_rv_get_info(struct mdw_device *mdev,
	enum mdw_info_type type)
{
	struct mdw_rv_dev *mrdev = (struct mdw_rv_dev *)mdev->dev_specific;
	int val = 0;

	mdw_rv_dev_get_param(mrdev, type, &val);
	return val;
}

static int mdw_rv_register_device(struct apusys_device *adev)
{
	return 0;
}

static int mdw_rv_unregister_device(struct apusys_device *adev)
{
	return 0;
}

static const struct mdw_dev_func mdw_rv_func = {
	.sw_init = mdw_rv_sw_init,
	.sw_deinit = mdw_rv_sw_deinit,
	.late_init = mdw_rv_late_init,
	.late_deinit = mdw_rv_late_deinit,
	.run_cmd = mdw_rv_run_cmd,
	.set_power = mdw_rv_set_power,
	.ucmd = mdw_rv_ucmd,
	.set_param = mdw_rv_set_param,
	.get_info = mdw_rv_get_info,
	.register_device = mdw_rv_register_device,
	.unregister_device = mdw_rv_unregister_device,
};

void mdw_rv_set_func(struct mdw_device *mdev)
{
	mdev->dev_funcs = &mdw_rv_func;
	mdev->uapi_ver = 3;
}
