diff --git a/Makefile b/Makefile
new file mode 100644
index 000000000000..4a8fcbc3ea61
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,12 @@
+$(CC) = gcc
+
+all: phat
+
+phat: parse_phat.o
+	$(CC) -Werror -o phat parse_phat.o
+
+parse_phat.o: parse_phat.c
+	$(CC) -c parse_phat.c
+
+clean:
+	rm -rf *.o $(objects) phat
diff --git a/parse_phat.c b/parse_phat.c
new file mode 100644
index 000000000000..4833d92f9acc
--- /dev/null
+++ b/parse_phat.c
@@ -0,0 +1,516 @@
+/*
+ * Tool for Parsing the ACPI PHAT Table.
+ *
+ * Author: Avadhut Naik <Avadhut.Naik@amd.com>
+ *
+ */
+
+#define _GNU_SOURCE
+#include <stdbool.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <argp.h>
+
+#define TOOL_DESCRIPTION "Parse the ACPI PHAT Table."
+#define TOOL_NAME "phat_parser"
+#define ARGS_DOC "<options>"
+
+#define NAMESEG_SIZE		4
+#define OEM_ID_SIZE			6
+#define OEM_TABLE_ID_SIZE	8
+
+#define PHAT_TABLE			"/sys/firmware/acpi/tables/PHAT"
+#define ARRAY_SIZE(x)		(sizeof(x) / sizeof(*(x)))
+#define BIT(nr)				(1UL << (nr))
+
+const char *argp_program_bug_address = "Avadhut Naik <Avadhut.Naik@amd.com>";
+static const char *prefix = "ACPI PHAT: ";
+
+/* Standard ACPI Table Header */
+struct acpi_table_header {
+	char signature[NAMESEG_SIZE];
+	uint32_t length;
+	uint8_t revision;
+	uint8_t checksum;
+	char oem_id[OEM_ID_SIZE];
+	char oem_table_id[OEM_TABLE_ID_SIZE];
+	uint32_t oem_revision;
+	char asl_compiler_id[NAMESEG_SIZE];
+	uint32_t asl_compiler_revision;
+} __attribute((packed));
+
+struct acpi_table_phat {
+	struct acpi_table_header header;
+} __attribute((packed));
+
+/* Common header for PHAT subtables */
+struct acpi_phat_header {
+	uint16_t type;
+	uint16_t length;
+	uint8_t revision;
+} __attribute((packed));
+
+/* Values for Type field above */
+#define ACPI_PHAT_TYPE_FW_VERSION_DATA	0
+#define ACPI_PHAT_TYPE_FW_HEALTH_DATA	1
+#define ACPI_PHAT_TYPE_RESERVED			2   /* 0x02-0xFFFF are reserved */
+
+struct acpi_phat_version_data {
+	struct acpi_phat_header header;
+	uint8_t reserved[3];
+	uint32_t element_count;
+} __attribute((packed));
+
+struct acpi_phat_version_element {
+	uint8_t guid[16];
+	uint64_t version_value;
+	uint32_t producer_id;
+} __attribute((packed));
+
+struct acpi_phat_health_data {
+	struct acpi_phat_header header;
+	uint8_t reserved[2];
+	uint8_t health;
+	uint8_t device_guid[16];
+	uint32_t device_specific_offset; /* Zero if no Device-specific data */
+} __attribute((packed));
+
+/* Values for Health field above */
+#define ACPI_PHAT_ERRORS_FOUND          0
+#define ACPI_PHAT_NO_ERRORS             1
+#define ACPI_PHAT_UNKNOWN_ERRORS        2
+#define ACPI_PHAT_ADVISORY              3
+
+/* Reset Reason Health Record Structure */
+struct acpi_phat_reset_reason {
+	uint8_t supported_reset_sources;
+	uint8_t reset_source;
+	uint8_t reset_sub_source;
+	uint8_t reset_reason;
+	uint16_t vendor_count;
+} __attribute((packed));
+
+/* Reset Reason Health Record GUID */
+static const uint8_t reset_guid[] = {
+	0xe2, 0x4c, 0x01, 0x7a, 0x63, 0xf2, 0x77, 0x4b,
+	0xb8, 0x8a, 0xe6, 0x33, 0x6b, 0x78, 0x2c, 0x14
+};
+
+static struct { uint8_t mask; const char *str; } const reset_sources[] = {
+	{BIT(0), "Unknown source"},
+	{BIT(1), "Hardware Source"},
+	{BIT(2), "Firmware Source"},
+	{BIT(3), "Software initiated reset"},
+	{BIT(4), "Supervisor initiated reset"},
+};
+
+static struct { uint8_t val; const char *str; } const reset_reasons[] = {
+	{0, "UNKNOWN"},
+	{1, "COLD BOOT"},
+	{2, "COLD RESET"},
+	{3, "WARM RESET"},
+	{4, "UPDATE"},
+	{32, "UNEXPECTED RESET"},
+	{33, "FAULT"},
+	{34, "TIMEOUT"},
+	{35, "THERMAL"},
+	{36, "POWER LOSS"},
+	{37, "POWER BUTTON"},
+};
+
+/* Reset Reason Health Record Vendor Data Entry */
+struct acpi_phat_vendor_reset_data {
+	uint8_t vendor_id[16];
+	uint16_t length;
+	uint16_t revision;
+} __attribute((packed));
+
+struct file_descs {
+	int fd;
+	int offset;
+	FILE *fp;
+};
+
+struct arguments {
+	int hex_dump;
+	int op_redir;
+	char *op_file;
+};
+
+static error_t parse_args(int key, char *arg, struct argp_state *state)
+{
+	struct arguments *args = state->input;
+
+	switch (key) {
+	case 'x':
+		args->hex_dump++;
+		break;
+	case 'o':
+		args->op_redir++;
+		args->op_file = arg;
+		break;
+	default:
+		return ARGP_ERR_UNKNOWN;
+	}
+	return 0;
+}
+
+void open_descs(struct file_descs *desc)
+{
+	desc->fd = open(PHAT_TABLE, O_RDONLY);
+
+	if (desc->fd == -1) {
+		printf("Failed to open PHAT Table file. Exiting.\n");
+		exit(0);
+	}
+
+	desc->fp = stdout;
+}
+
+void close_descs(struct file_descs *desc)
+{
+	close(desc->fd);
+	fclose(desc->fp);
+}
+
+unsigned char *get_guid(uint8_t *guid_t)
+{
+	const unsigned char seq[] = {3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15};
+	unsigned char *guid;
+	int bytes;
+	int len;
+	int pos;
+	int idx;
+
+	len = sizeof(seq) * 3;
+	guid = (unsigned char *)calloc(1, len);
+
+	for (idx = 0, pos = 0; idx < 16; idx++) {
+		if (idx == 4 || idx == 6 || idx == 8 || idx == 10) {
+			bytes = snprintf(guid + pos, len - pos, "-");
+			pos += bytes;
+		}
+
+		bytes = snprintf(guid + pos, len - pos, "%2.2x",
+				 guid_t[seq[idx]]);
+		pos += bytes;
+	}
+
+	return guid;
+}
+
+unsigned char *get_hex(const void *buf, size_t buf_len,
+		       int rowsize, bool inc_len, bool ascii)
+{
+	const unsigned char *ptr;
+	unsigned char *str;
+	int alloc_len;
+	int bytes;
+	int r_len;
+	int b_len;
+	int pos;
+	int idx;
+
+	ptr = buf;
+	alloc_len = 4 * buf_len;
+	str = (unsigned char *)calloc(1, alloc_len);
+
+	for (idx = 0, pos = 0, b_len = 0, r_len = 0; idx < buf_len; idx++) {
+		if (r_len == rowsize) {
+			r_len =  0;
+			str[pos++] = '\n';
+		}
+
+		if (r_len == 0 && inc_len) {
+			bytes = snprintf(str + pos, alloc_len - pos, "%4.4x: ", b_len);
+			b_len += rowsize;
+			pos += bytes;
+		}
+
+		bytes = snprintf(str + pos, alloc_len - pos, "%2.2x ",
+				 ptr[idx]);
+		pos += bytes;
+		r_len++;
+	}
+
+	if (ascii) {
+		str[pos++] = '\t';
+		for (idx = 0; idx < buf_len; idx++)
+			str[pos++] = toascii(ptr[idx]);
+	}
+
+	return str;
+}
+
+void phat_version_data_parse(const char *pfx, struct file_descs *desc,
+			     struct acpi_phat_version_data *v_record)
+{
+	struct acpi_phat_version_element element;
+	unsigned char *guid;
+	unsigned char *str;
+	uint32_t offset;
+	char newpfx[64];
+	int idx;
+
+	if (!v_record->element_count) {
+		fprintf(desc->fp, "%sNo PHAT Version Elements found.\n", prefix);
+		return;
+	}
+
+	fprintf(desc->fp, "%sPHAT Version Element:\n", pfx);
+	offset = desc->offset + sizeof(*v_record);
+	snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
+
+	for (idx = 0; idx < v_record->element_count; idx++) {
+		offset += idx * sizeof(element);
+		pread(desc->fd, &element, sizeof(element), offset);
+		guid = get_guid(element.guid);
+		fprintf(desc->fp, "%sComponent ID: %s\n", newpfx, guid);
+		fprintf(desc->fp, "%sVersion: 0x%lx\n", newpfx,
+			element.version_value);
+		str = get_hex(&element.producer_id, sizeof(element.producer_id),
+			      16, false, true);
+		fprintf(desc->fp, "%sProducer ID: %s\n", newpfx, str);
+		free(guid);
+		free(str);
+	}
+}
+
+void phat_vendor_data_parse(const char *pfx, struct file_descs *desc,
+			    struct acpi_phat_reset_reason *rr)
+{
+	struct acpi_phat_vendor_reset_data vdata;
+	unsigned char *guid;
+	unsigned char *str;
+	uint32_t vdata_len;
+	uint32_t offset;
+	char newpfx[64];
+	void *data;
+	int idx;
+
+	fprintf(desc->fp, "%sReset Reason Vendor Data:\n", pfx);
+
+	offset = desc->offset + sizeof(*rr);
+	desc->offset = offset;
+	snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
+
+	for (idx = 0; idx < rr->vendor_count; idx++) {
+		pread(desc->fd, &vdata, sizeof(vdata), offset);
+		guid = get_guid(vdata.vendor_id);
+		fprintf(desc->fp, "%sVendor Data ID: %s\n", newpfx, guid);
+		fprintf(desc->fp, "%sRevision: 0x%x\n", newpfx, vdata.revision);
+
+		offset += sizeof(vdata);
+		vdata_len = vdata.length - sizeof(vdata);
+		data = calloc(1, vdata_len);
+		pread(desc->fd, data, vdata_len, offset);
+		str = get_hex(data, vdata_len, 16, false, false);
+		fprintf(desc->fp, "%sData: %s\n", newpfx, str);
+
+		offset = desc->offset + vdata.length;
+		desc->offset = offset;
+		free(guid);
+		free(data);
+		free(str);
+	}
+}
+
+void phat_reset_reason_parse(const char *pfx, struct file_descs *desc,
+			     struct acpi_phat_health_data *record)
+{
+	struct acpi_phat_reset_reason rr;
+	uint32_t offset;
+	char newpfx[64];
+	int idx;
+
+	offset = desc->offset + record->device_specific_offset;
+	desc->offset = offset;
+	pread(desc->fd, &rr, sizeof(rr), offset);
+	snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
+	fprintf(desc->fp, "%sReset Reason Health Record:\n", pfx);
+
+	for (idx = 0; idx < ARRAY_SIZE(reset_sources); idx++) {
+		if (!rr.reset_source) {
+			fprintf(desc->fp, "%sUnknown Reset Source.\n", newpfx);
+			break;
+		}
+		if (rr.reset_source && reset_sources[idx].mask) {
+			fprintf(desc->fp, "%sReset Source: 0x%x\t%s\n", newpfx,
+				reset_sources[idx].mask, reset_sources[idx].str);
+
+			if (idx == 0x3 && rr.reset_sub_source)
+				fprintf(desc->fp, "%sReset Sub-Source: %s\n", newpfx,
+					rr.reset_sub_source == 0x1 ?
+					"Operating System" : "Hypervisor");
+			break;
+		}
+	}
+
+	for (idx = 0; idx < ARRAY_SIZE(reset_reasons); idx++) {
+		if (rr.reset_reason == reset_reasons[idx].val) {
+			fprintf(desc->fp, "%sReset Reason: 0x%x\t%s\n", newpfx,
+				reset_reasons[idx].val, reset_reasons[idx].str);
+			break;
+		}
+	}
+
+	if (!rr.vendor_count)
+		return;
+
+	phat_vendor_data_parse(newpfx, desc, &rr);
+}
+
+void phat_health_data_parse(const char *pfx, struct file_descs *desc,
+			    struct acpi_phat_health_data *record)
+{
+	unsigned char *guid;
+	unsigned char *str;
+	uint32_t data_len;
+	uint32_t offset;
+	char newpfx[64];
+	void *data;
+
+	fprintf(desc->fp, "%sHealth Records:\n", pfx);
+	snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
+	guid = get_guid(record->device_guid);
+	fprintf(desc->fp, "%sDevice Signature: %s\n", newpfx, guid);
+
+	switch (record->health) {
+	case ACPI_PHAT_ERRORS_FOUND:
+		fprintf(desc->fp, "%sAmHealthy: Errors found\n", newpfx);
+		break;
+	case ACPI_PHAT_NO_ERRORS:
+		fprintf(desc->fp, "%sAmHealthy: No errors found.\n", newpfx);
+		break;
+	case ACPI_PHAT_UNKNOWN_ERRORS:
+		fprintf(desc->fp, "%sAmHealthy: Unknown.\n", newpfx);
+		break;
+	case ACPI_PHAT_ADVISORY:
+		fprintf(desc->fp, "%sAmHealthy: Advisory – additional device-specific data exposed.\n",
+			newpfx);
+		break;
+	default:
+		break;
+	}
+
+	if (!record->device_specific_offset)
+		return;
+
+	if (!memcmp(record->device_guid, reset_guid, 16)) {
+		phat_reset_reason_parse(newpfx, desc, record);
+		return;
+	}
+
+	data_len = record->header.length - sizeof(*record);
+	data = calloc(1, data_len);
+	offset = desc->offset + record->device_specific_offset;
+	pread(desc->fd, data, data_len, offset);
+	snprintf(newpfx, sizeof(newpfx), "%s  ", pfx);
+	str = get_hex(data, data_len, 16, false, false);
+	fprintf(desc->fp, "%sDevice Data: %s\n", newpfx, str);
+	free(guid);
+	free(data);
+	free(str);
+}
+
+void parse_phat_table(struct file_descs *desc,
+		      struct acpi_table_phat *phat_tab)
+{
+	struct acpi_phat_version_data v_record;
+	struct acpi_phat_health_data h_record;
+	uint32_t offset = sizeof(*phat_tab);
+	struct acpi_phat_header header;
+	char pfx[64];
+
+	memset(&v_record, 0, sizeof(v_record));
+	memset(&h_record, 0, sizeof(h_record));
+	snprintf(pfx, sizeof(pfx), "%s ", prefix);
+
+	while (offset < phat_tab->header.length) {
+		pread(desc->fd, &header, sizeof(header), offset);
+		switch (header.type) {
+		case ACPI_PHAT_TYPE_FW_VERSION_DATA:
+			pread(desc->fd, &v_record, sizeof(v_record), offset);
+			desc->offset = offset;
+			phat_version_data_parse(pfx, desc, &v_record);
+			break;
+		case ACPI_PHAT_TYPE_FW_HEALTH_DATA:
+			pread(desc->fd, &h_record, sizeof(h_record), offset);
+			desc->offset = offset;
+			phat_health_data_parse(pfx, desc, &h_record);
+			break;
+		default:
+			break;
+		}
+		offset += header.length;
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	struct acpi_table_phat phat_tab;
+	struct file_descs desc;
+	struct arguments args;
+	unsigned char *phat;
+	unsigned char *str;
+	int idx = -1;
+
+	if (getuid() != 0) {
+		printf("Please run the tool as root. Exiting.\n");
+		return 1;
+	}
+
+	memset(&args, 0, sizeof(args));
+	memset(&desc, 0, sizeof(desc));
+	memset(&phat_tab, 0, sizeof(phat_tab));
+
+	const struct argp_option options[] = {
+		{"hex", 'x', 0, 0, "Hex Dump of the table", 0},
+		{"output", 'o', "FILE", 0,
+		 "Output to FILE instead of standard output", 0},
+		{0, 0, 0, 0, 0, 0},
+	};
+
+	const struct argp argp = {
+		.options = options,
+		.parser = parse_args,
+		.doc = TOOL_DESCRIPTION,
+		.args_doc = ARGS_DOC,
+	};
+
+	argp_parse(&argp, argc, argv, 0, &idx, &args);
+
+	if (idx < 0) {
+		argp_help(&argp, stderr, ARGP_HELP_STD_HELP, TOOL_NAME);
+		return -1;
+	}
+
+	open_descs(&desc);
+
+	if (args.op_redir)
+		desc.fp = fopen(args.op_file, "w+");
+
+	pread(desc.fd, &phat_tab, sizeof(phat_tab), 0);
+
+	if (args.hex_dump) {
+		phat = (unsigned char *)calloc(1, phat_tab.header.length);
+		pread(desc.fd, phat, phat_tab.header.length, 0);
+		str = get_hex(phat, phat_tab.header.length, 16, true, false);
+		fprintf(desc.fp, "%sRaw Table Data: Length: %d (0x%x)\n\n", prefix,
+			phat_tab.header.length, phat_tab.header.length);
+		fprintf(desc.fp, "%s\n\n", str);
+		free(str);
+		free(phat);
+	}
+
+	fprintf(desc.fp, "%sPlatform Telemetry Records\n", prefix);
+
+	parse_phat_table(&desc, &phat_tab);
+
+	close_descs(&desc);
+	return 0;
+}
