// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2019 MediaTek Inc.
 */
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/slab.h>

#include <common/mdla_device.h>
#include <common/mdla_cmd_proc.h>
#include <interface/mdla_cmd_data_v2_0.h>
#include <utilities/mdla_debug.h>

static int mdla_cmd_dummy_run(void *run_cmd,
			struct mdla_dev *mdla_info,
			struct apusys_cmd_hnd *apusys_hd,
			bool secure, uint32_t data)
{
	mdla_cmd_debug("%s() !!!\n", __func__);
	return 0;
}

static int mdla_cmd_dummy_ut_run_sync(void *cmd_data, void *wait_cmd,
					struct mdla_dev *mdla_info)
{
	mdla_cmd_debug("%s() !!!\n", __func__);
	return 0;
}

static void mdla_cmd_dumy_lock_ops(struct mdla_dev *mdla_device) {}

static struct mdla_cmd_ops mdla_command = {
	.run_sync     = mdla_cmd_dummy_run,
	.ut_run_sync  = mdla_cmd_dummy_ut_run_sync,
	.lock         = mdla_cmd_dumy_lock_ops,
	.unlock       = mdla_cmd_dumy_lock_ops,
	.list_lock    = mdla_cmd_dumy_lock_ops,
	.list_unlock  = mdla_cmd_dumy_lock_ops,
};

static void mdla_cmd_lock(struct mdla_dev *mdla_device)
{
	mutex_lock(&mdla_device->cmd_lock);
}

static void mdla_cmd_unlock(struct mdla_dev *mdla_device)
{
	mutex_unlock(&mdla_device->cmd_lock);
}

static void mdla_cmd_list_lock(struct mdla_dev *mdla_device)
{
	mutex_lock(&mdla_device->cmd_list_lock);
}

static void mdla_cmd_list_unlock(struct mdla_dev *mdla_device)
{
	mutex_unlock(&mdla_device->cmd_list_lock);
}

static void mdla_delete_ce(struct kref *kref)
{
	struct command_entry *ce =
			container_of(kref, struct command_entry, refcount);

	kfree(ce);
}

void mdla_cmd_setup(run_sync_t sync, ut_run_sync_t ut_sync)
{
	if (sync)
		mdla_command.run_sync = sync;

	if (ut_sync)
		mdla_command.ut_run_sync = ut_sync;

	mdla_command.lock           = mdla_cmd_lock;
	mdla_command.unlock         = mdla_cmd_unlock;
	mdla_command.list_lock      = mdla_cmd_list_lock;
	mdla_command.list_unlock    = mdla_cmd_list_unlock;
}

const struct mdla_cmd_ops *mdla_cmd_ops_get(void)
{
	return &mdla_command;
}

static bool mdla_cmd_check_dummy(uint64_t out_end,
	struct command_entry *ce)
{
	return false;
}

static int mdla_cmd_dumy_load_ops(void *model)
{
	return 0;
}

static int mdla_cmd_dumy_param_ops(void *user, void *data)
{
	return 0;
}

static int mdla_cmd_dumy_release_ops(void *user)
{
	return 0;
}

static int mdla_cmd_dummy_ops(u32 a0) { return 0; }
static unsigned long mdla_cmd_dummy_uint_int(u32 a0) { return 0; }
static void mdla_cmd_dummy_info(u32 a0) {}
static int mdla_cmd_dummy_ce_ops(u32 a0, struct command_entry *a1)
{
	return 0;
}

static struct command_entry *mdla_alloc_ce(void)
{
	struct command_entry *ce;

	ce = kzalloc(sizeof(struct command_entry), GFP_ATOMIC);
	if (ce)
		kref_init(&ce->refcount);

	return ce;
}

static void mdla_free_ce(struct command_entry *ce)
{
	struct mdla_scheduler *sched = mdla_get_device(0)->sched;
	unsigned long flags;

	spin_lock_irqsave(&sched->lock, flags);
	kref_put(&ce->refcount, mdla_cmd_plat_cb()->del_ce);
	spin_unlock_irqrestore(&sched->lock, flags);
}

static struct mdla_cmd_cb_func mdla_command_callback = {

	.pre_cmd_handle			= mdla_cmd_dummy_ce_ops,
	.pre_cmd_info			= mdla_cmd_dummy_info,
	.check_cmd_valid		= mdla_cmd_check_dummy,
	.process_command		= mdla_cmd_dummy_ce_ops,
	.process_command_no_lock	= mdla_cmd_dummy_ce_ops,
	.post_cmd_handle		= mdla_cmd_dummy_ce_ops,
	.post_cmd_info			= mdla_cmd_dummy_info,
	.wait_cmd_handle		= mdla_cmd_dummy_ce_ops,
	.get_wait_time			= mdla_cmd_dummy_uint_int,
	.get_irq_num			= mdla_cmd_dummy_ops,
	.wait_cmd_hw_detect		= mdla_cmd_dummy_ops,
	.post_cmd_hw_detect		= mdla_cmd_dummy_ops,
	.suspend_cb			= mdla_cmd_dummy_ops,
	.resume_cb			= mdla_cmd_dummy_ops,
	.check_resource			= mdla_cmd_dummy_ops,

	.alloc_ce			= mdla_alloc_ce,
	.free_ce			= mdla_free_ce,
	.del_ce				= mdla_delete_ce,
	.load_model			= mdla_cmd_dumy_load_ops,
	.unload_model			= mdla_cmd_dumy_load_ops,
	.update_model_param		= mdla_cmd_dumy_param_ops,
	.reset_model_param		= mdla_cmd_dumy_param_ops,
	.release_model_param		= mdla_cmd_dumy_release_ops,
};


struct mdla_cmd_cb_func *mdla_cmd_plat_cb(void)
{
	return &mdla_command_callback;
}
