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

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/amlogic/cpu_version.h>
#include <linux/printk.h>
#include <linux/string.h>
#include <linux/of_address.h>
#include <linux/io.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>

#define AO_SEC_SD_CFG8		0xe0
#define AO_SEC_SOCINFO_OFFSET	AO_SEC_SD_CFG8
static unsigned char cpu_version[MESON_CPU_VERSION_LVL_MAX + 1];
static int init_done;
static int cpu_id_from_media;

int get_cpu_type_from_media(void)
{
	return cpu_id_from_media;
}
EXPORT_SYMBOL(get_cpu_type_from_media);

void set_cpu_type_from_media(int cpu_id)
{
	if (cpu_id <= 0) {
		pr_err("wrong cpu id from media driver 0x%x.\n", cpu_id);
		return;
	}
	cpu_id_from_media = cpu_id;
}
EXPORT_SYMBOL(set_cpu_type_from_media);

unsigned char get_meson_cpu_version(int level)
{
	if (!init_done) {
		pr_err("too early call %s\n", __func__);
		dump_stack();
		return -1;
	}

	if (level >= 0 && level <= MESON_CPU_VERSION_LVL_MAX)
		return cpu_version[level];
	return 0;
}
EXPORT_SYMBOL(get_meson_cpu_version);

int __init meson_cpu_version_init(void)
{
	struct device_node *np;
	unsigned int socinfo;
	struct regmap *regmap;
	int ret;

	/* look up for chipid node */
	np = of_find_compatible_node(NULL, NULL, "amlogic,meson-gx-ao-secure");
	if (!np)
		return -ENODEV;

	/* node should be a syscon */
	regmap = syscon_node_to_regmap(np);
	of_node_put(np);
	if (IS_ERR(regmap)) {
		pr_err("%s: failed to get regmap\n", __func__);
		return -ENODEV;
	}

	ret = regmap_read(regmap, AO_SEC_SOCINFO_OFFSET, &socinfo);
	if (ret < 0)
		return ret;

	if (!socinfo) {
		pr_err("%s: invalid chipid value\n", __func__);
		return -EINVAL;
	}

	cpu_version[MESON_CPU_VERSION_LVL_MAJOR] = (socinfo >> 24) & 0xff;
	cpu_version[MESON_CPU_VERSION_LVL_MINOR] =  (socinfo >> 8) & 0xff;
	cpu_version[MESON_CPU_VERSION_LVL_PACK] =  (socinfo >> 16) & 0xff;
	cpu_version[MESON_CPU_VERSION_LVL_MISC] = socinfo & 0xff;
	pr_info("chip version = %X:%X - %X:%X\n",
		cpu_version[MESON_CPU_VERSION_LVL_MAJOR],
		cpu_version[MESON_CPU_VERSION_LVL_MINOR],
		cpu_version[MESON_CPU_VERSION_LVL_PACK],
		cpu_version[MESON_CPU_VERSION_LVL_MISC]
	);

	init_done = 1;
	return 0;
}
