/* SPDX-License-Identifier: GPL-2.0-only */

#include <console/console.h>
#include <fsp/api.h>
#include <fsp/util.h>
#include <soc/intel/common/reset.h>
#include <stdint.h>

static const uint8_t fsp_reset_guid[16] = {
	0xff, 0x97, 0x05, 0xea, 0x58, 0x88, 0xca, 0x41,
	0xbb, 0xc1, 0xfe, 0x18, 0xfc, 0xd2, 0x8e, 0x22
};

static const uint8_t fsp_global_reset_guid[16] = {
	0x4c, 0x1b, 0xb3, 0x9d, 0xef, 0xf5, 0xbb, 0x48,
	0x94, 0x2b, 0x18, 0x1f, 0x7e, 0x3a, 0x3e, 0x40
};

/* Platform Reset String as per Intel FSP is "PCH RESET" in unicode */
#define PLATFORM_RESET_STRING_LENGTH  20

struct pch_reset_data {
	char reserved[PLATFORM_RESET_STRING_LENGTH];
	efi_guid_t global_reset_uid;
};

/* This structure is used to provide information about PCH Reset */
struct fsp_reset_hob {
	EFI_RESET_TYPE   reset_type;
	struct pch_reset_data   reset_data;
};

void chipset_handle_reset(uint32_t status)
{
	if (status == CONFIG_FSP_STATUS_GLOBAL_RESET) {
		printk(BIOS_DEBUG, "GLOBAL RESET!\n");
		global_reset();
	}

	printk(BIOS_ERR, "unhandled reset type %x\n", status);
	die("unknown reset type");
}

static uint32_t fsp_reset_type_to_status(EFI_RESET_TYPE reset_type)
{
	uint32_t status;

	switch (reset_type) {
	case EfiResetCold:
		status = FSP_STATUS_RESET_REQUIRED_COLD;
		break;
	case EfiResetWarm:
		status = FSP_STATUS_RESET_REQUIRED_WARM;
		break;
	default:
		printk(BIOS_ERR, "unhandled reset type %x\n", reset_type);
		die("unknown reset type");
	}

	return status;
}

/*
 * Return PCH Reset Status
 * The return status can be between EfiResetCold, EfiResetWarm, EfiResetShutdown
 * or EfiResetPlatformSpecific.
 *
 * If reset type is `EfiResetPlatformSpecific` then relying on pch_reset_data structure
 * to know if the reset type is a global reset.
 */
uint32_t fsp_get_pch_reset_status(void)
{
	size_t size;
	const struct fsp_reset_hob *hob = fsp_find_extension_hob_by_guid(fsp_reset_guid, &size);
	if (!hob)
		return 0;

	if ((hob->reset_type == EfiResetPlatformSpecific) &&
		 fsp_guid_compare((void *)&(hob->reset_data.global_reset_uid),
			 fsp_global_reset_guid))
		return CONFIG_FSP_STATUS_GLOBAL_RESET;

	return fsp_reset_type_to_status(hob->reset_type);
}
