// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
 */

#include <linux/vmalloc.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/mtd/mtd.h>
#include <linux/amlogic/aml_rsv.h>
#include <linux/amlogic/key_manage.h>

static struct meson_rsv_info_t *meson_rsv_key;

/*
 * This function reads the u-boot keys.
 */
s32 amlnf_key_read(u8 *buf, u32 len, u32 *actual_length)
{
	struct meson_rsv_info_t *aml_key = meson_rsv_key;
	u8 *key_ptr = NULL;
	u32 keysize = 0;

	if (!meson_rsv_key) {
		pr_info("%s(): amlnf key not ready yet!",
			__func__);
		return -EFAULT;
	}

	keysize = aml_key->size;
	*actual_length = keysize;

	if (len > keysize) {
		/*
		 *No return here! keep consistent, should memset zero
		 *for the rest.
		 */
		pr_info("%s read key len exceed,len 0x%x,keysize 0x%x\n",
			__func__, len, keysize);
		memset(buf + keysize, 0, len - keysize);
	}

	key_ptr = kzalloc(aml_key->size, GFP_KERNEL);
	if (!key_ptr)
		return -ENOMEM;

	meson_rsv_key_read(key_ptr, keysize);
	memcpy(buf, key_ptr, min_t(int, keysize, len));

	kfree(key_ptr);
	return 0;
}

/*
 * This function write the keys.
 */
s32 amlnf_key_write(u8 *buf, u32 len, u32 *actual_length)
{
	struct meson_rsv_info_t *aml_key = meson_rsv_key;
	/*struct mtd_info *mtd = aml_chip->mtd;*/
	u8 *key_ptr = NULL;
	u32 keysize = 0;
	int error = 0;

	if (!meson_rsv_key) {
		pr_info("%s(): amlnf key not ready yet!",
			__func__);
		return -EFAULT;
	}

	keysize = aml_key->size;
	*actual_length = keysize;

	if (len > keysize) {
		/*
		 *No return here! keep consistent, should memset zero
		 *for the rest.
		 */
		pr_info("%s write key len exceed,len 0x%x,keysize 0x%x\n",
			__func__, len, keysize);
		memset(buf + keysize, 0, len - keysize);
	}

	key_ptr = kzalloc(aml_key->size, GFP_KERNEL);
	if (!key_ptr)
		return -ENOMEM;

	memcpy(key_ptr, buf, keysize);
	error = meson_rsv_key_write(key_ptr, len);

	kfree(key_ptr);
	return error;
}

int amlnf_key_erase(void)
{
	int ret = 0;

	if (!meson_rsv_key) {
		pr_info("%s amlnf not ready yet!\n", __func__);
		return -1;
	}

	return ret;
}

int meson_rsv_register_unifykey(struct meson_rsv_info_t *key)
{
	int ret = 0;
	struct unifykey_type *uk_type;

	uk_type = kzalloc(sizeof(*uk_type), GFP_KERNEL);
	if (!uk_type)
		return -ENOMEM;

	uk_type->ops = kzalloc(sizeof(*uk_type->ops), GFP_KERNEL);
	if (!uk_type->ops) {
		ret = -ENOMEM;
		goto exit;
	}

	/* avoid null */
	meson_rsv_key = key;

	/**need test**/
	uk_type->storage_type = UNIFYKEY_STORAGE_TYPE_NAND;
	/*
	 * pr_info("%s key func read: 0x%px, write: 0x%px\n",
	 *	__func__, amlnf_key_read, amlnf_key_write);
	 */
	uk_type->ops->read = amlnf_key_read;
	uk_type->ops->write = amlnf_key_write;
	/*
	 *pr_info("%s key func read: 0x%px, write: 0x%px\n",
	 *__func__, uk_type->ops->read, uk_type->ops->write);
	 */
	ret = register_unifykey_types(uk_type);

	kfree(uk_type->ops);
exit:
	kfree(uk_type);
	return ret;
}

