x86: acpi: Support generation of the HPET table

Add an implementation of the HPET (High Precision Event Timer) ACPI
table. Since this is x86-specific, put it in an x86-specific file

Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h
index 733085c..7047ee6 100644
--- a/arch/x86/include/asm/acpi_table.h
+++ b/arch/x86/include/asm/acpi_table.h
@@ -37,6 +37,16 @@
 u32 acpi_fill_csrt(u32 current);
 
 /**
+ * acpi_write_hpet() - Write out a HPET table
+ *
+ * Write out the table for High-Precision Event Timers
+ *
+ * @ctx: Current ACPI context
+ * @return 0 if OK, -ve on error
+ */
+int acpi_write_hpet(struct acpi_ctx *ctx);
+
+/**
  * acpi_create_gnvs() - Create a GNVS (Global Non Volatile Storage) table
  *
  * @gnvs: Table to fill in
diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
index 36ef3e5..0080c96 100644
--- a/arch/x86/lib/acpi_table.c
+++ b/arch/x86/lib/acpi_table.c
@@ -529,3 +529,62 @@
 {
 	return acpi_rsdp_addr;
 }
+
+/**
+ * acpi_write_hpet() - Write out a HPET table
+ *
+ * Write out the table for High-Precision Event Timers
+ *
+ * @hpet: Place to put HPET table
+ */
+static int acpi_create_hpet(struct acpi_hpet *hpet)
+{
+	struct acpi_table_header *header = &hpet->header;
+	struct acpi_gen_regaddr *addr = &hpet->addr;
+
+	/*
+	 * See IA-PC HPET (High Precision Event Timers) Specification v1.0a
+	 * https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/software-developers-hpet-spec-1-0a.pdf
+	 */
+	memset((void *)hpet, '\0', sizeof(struct acpi_hpet));
+
+	/* Fill out header fields. */
+	acpi_fill_header(header, "HPET");
+
+	header->aslc_revision = ASL_REVISION;
+	header->length = sizeof(struct acpi_hpet);
+	header->revision = acpi_get_table_revision(ACPITAB_HPET);
+
+	/* Fill out HPET address */
+	addr->space_id = 0;  /* Memory */
+	addr->bit_width = 64;
+	addr->bit_offset = 0;
+	addr->addrl = CONFIG_HPET_ADDRESS & 0xffffffff;
+	addr->addrh = ((unsigned long long)CONFIG_HPET_ADDRESS) >> 32;
+
+	hpet->id = *(u32 *)CONFIG_HPET_ADDRESS;
+	hpet->number = 0;
+	hpet->min_tick = 0; /* HPET_MIN_TICKS */
+
+	header->checksum = table_compute_checksum(hpet,
+						  sizeof(struct acpi_hpet));
+
+	return 0;
+}
+
+int acpi_write_hpet(struct acpi_ctx *ctx)
+{
+	struct acpi_hpet *hpet;
+	int ret;
+
+	log_debug("ACPI:    * HPET\n");
+
+	hpet = ctx->current;
+	acpi_inc_align(ctx, sizeof(struct acpi_hpet));
+	acpi_create_hpet(hpet);
+	ret = acpi_add_table(ctx, hpet);
+	if (ret)
+		return log_msg_ret("add", ret);
+
+	return 0;
+}