// SPDX-License-Identifier: BSD-2-Clause
/*
 * Copyright (C) 2016 Freescale Semiconductor, Inc.
 * Copyright 2017-2019 NXP
 *
 * Peng Fan <peng.fan@nxp.com>
 */

#include <console.h>
#include <io.h>
#include <imx.h>
#include <mm/core_mmu.h>
#include <mm/core_memprot.h>
#include <platform_config.h>

static int imx_cpu_type = -1;
static int imx_soc_revision = -1;

#define CPU_TYPE(reg)		((reg & 0x00FF0000) >> 16)
#define SOC_REV_MAJOR(reg)	(((reg & 0x0000FF00) >> 8) + 1)
#define SOC_REV_MINOR(reg)	(reg & 0x0000000F)

static void imx_digproc(void)
{
	uint32_t digprog = 0;
	vaddr_t __maybe_unused anatop_addr = 0;

#if defined(CFG_MX7ULP)
	digprog = SOC_MX7ULP << 16;
#elif defined(CFG_MX8QX)
	digprog = SOC_MX8QX << 16;
#elif defined(CFG_MX8QM)
	digprog = SOC_MX8QM << 16;
#else
	anatop_addr = core_mmu_get_va(ANATOP_BASE, MEM_AREA_IO_SEC);

	if (!anatop_addr)
		return;

	digprog = io_read32(anatop_addr + DIGPROG_OFFSET);
#endif
	/* Set the CPU type */
	imx_cpu_type = CPU_TYPE(digprog);

#ifdef CFG_MX7
	imx_soc_revision = digprog & 0xFF;
#else
	/* Set the SOC revision: = (Major + 1)[11:4] | (Minor[3:0]) */
	imx_soc_revision =
		(SOC_REV_MAJOR(digprog) << 4) | SOC_REV_MINOR(digprog);
#endif
}

static uint32_t imx_soc_rev_major(void)
{
	if (imx_soc_revision < 0)
		imx_digproc();

	return imx_soc_revision >> 4;
}

static uint32_t imx_soc_type(void)
{
	if (imx_cpu_type < 0)
		imx_digproc();

	return imx_cpu_type;
}

bool soc_is_imx6sl(void)
{
	return imx_soc_type() == SOC_MX6SL;
}

bool soc_is_imx6sll(void)
{
	return imx_soc_type() == SOC_MX6SLL;
}

bool soc_is_imx6sx(void)
{
	return imx_soc_type() == SOC_MX6SX;
}

bool soc_is_imx6ul(void)
{
	return imx_soc_type() == SOC_MX6UL;
}

bool soc_is_imx6ull(void)
{
	return imx_soc_type() == SOC_MX6ULL;
}

bool soc_is_imx6sdl(void)
{
	return imx_soc_type() == SOC_MX6DL;
}

bool soc_is_imx6dq(void)
{
	return (imx_soc_type() == SOC_MX6Q) && (imx_soc_rev_major() == 1);
}

bool soc_is_imx6dqp(void)
{
	return (imx_soc_type() == SOC_MX6Q) && (imx_soc_rev_major() == 2);
}

bool soc_is_imx6(void)
{
	return ((imx_soc_type() == SOC_MX6SX) ||
			(imx_soc_type() == SOC_MX6UL) ||
			(imx_soc_type() == SOC_MX6ULL) ||
			(imx_soc_type() == SOC_MX6DL) ||
			(imx_soc_type() == SOC_MX6Q));
}

bool soc_is_imx7ds(void)
{
	return imx_soc_type() == SOC_MX7D;
}

bool soc_is_imx7ulp(void)
{
	return imx_soc_type() == SOC_MX7ULP;
}
