Merge tag 'efi-2022-01-rc4-4' of https://source.denx.de/u-boot/custodians/u-boot-efi
[platform/kernel/u-boot.git] / lib / acpi / acpi_table.c
index 4e354d3..d168540 100644 (file)
@@ -8,12 +8,31 @@
 #include <common.h>
 #include <dm.h>
 #include <cpu.h>
+#include <log.h>
 #include <mapmem.h>
 #include <tables_csum.h>
+#include <timestamp.h>
 #include <version.h>
 #include <acpi/acpi_table.h>
+#include <asm/global_data.h>
 #include <dm/acpi.h>
 
+/*
+ * OEM_REVISION is 32-bit unsigned number. It should be increased only when
+ * changing software version. Therefore it should not depend on build time.
+ * U-Boot calculates it from U-Boot version and represent it in hexadecimal
+ * notation. As U-Boot version is in form year.month set low 8 bits to 0x01
+ * to have valid date. So for U-Boot version 2021.04 OEM_REVISION is set to
+ * value 0x20210401.
+ */
+#define OEM_REVISION ((((U_BOOT_VERSION_NUM / 1000) % 10) << 28) | \
+                     (((U_BOOT_VERSION_NUM / 100) % 10) << 24) | \
+                     (((U_BOOT_VERSION_NUM / 10) % 10) << 20) | \
+                     ((U_BOOT_VERSION_NUM % 10) << 16) | \
+                     (((U_BOOT_VERSION_NUM_PATCH / 10) % 10) << 12) | \
+                     ((U_BOOT_VERSION_NUM_PATCH % 10) << 8) | \
+                     0x01)
+
 int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags)
 {
        struct acpi_table_header *header = &dmar->header;
@@ -98,7 +117,7 @@ void acpi_fill_header(struct acpi_table_header *header, char *signature)
        memcpy(header->signature, signature, 4);
        memcpy(header->oem_id, OEM_ID, 6);
        memcpy(header->oem_table_id, OEM_TABLE_ID, 8);
-       header->oem_revision = U_BOOT_BUILD_DATE;
+       header->oem_revision = OEM_REVISION;
        memcpy(header->aslc_id, ASLC_ID, 4);
 }
 
@@ -165,7 +184,7 @@ int acpi_add_table(struct acpi_ctx *ctx, void *table)
         * And now the same thing for the XSDT. We use the same index as for
         * now we want the XSDT and RSDT to always be in sync in U-Boot
         */
-       xsdt = map_sysmem(ctx->rsdp->xsdt_address, sizeof(*xsdt));
+       xsdt = ctx->xsdt;
 
        /* Add table to the XSDT */
        xsdt->entry[i] = map_to_sysmem(table);
@@ -181,3 +200,149 @@ int acpi_add_table(struct acpi_ctx *ctx, void *table)
 
        return 0;
 }
+
+void acpi_write_rsdp(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt,
+                    struct acpi_xsdt *xsdt)
+{
+       memset(rsdp, 0, sizeof(struct acpi_rsdp));
+
+       memcpy(rsdp->signature, RSDP_SIG, 8);
+       memcpy(rsdp->oem_id, OEM_ID, 6);
+
+       rsdp->length = sizeof(struct acpi_rsdp);
+       rsdp->rsdt_address = map_to_sysmem(rsdt);
+
+       rsdp->xsdt_address = map_to_sysmem(xsdt);
+       rsdp->revision = ACPI_RSDP_REV_ACPI_2_0;
+
+       /* Calculate checksums */
+       rsdp->checksum = table_compute_checksum(rsdp, 20);
+       rsdp->ext_checksum = table_compute_checksum(rsdp,
+                                                   sizeof(struct acpi_rsdp));
+}
+
+static void acpi_write_rsdt(struct acpi_rsdt *rsdt)
+{
+       struct acpi_table_header *header = &rsdt->header;
+
+       /* Fill out header fields */
+       acpi_fill_header(header, "RSDT");
+       header->length = sizeof(struct acpi_rsdt);
+       header->revision = 1;
+
+       /* Entries are filled in later, we come with an empty set */
+
+       /* Fix checksum */
+       header->checksum = table_compute_checksum(rsdt,
+                                                 sizeof(struct acpi_rsdt));
+}
+
+static void acpi_write_xsdt(struct acpi_xsdt *xsdt)
+{
+       struct acpi_table_header *header = &xsdt->header;
+
+       /* Fill out header fields */
+       acpi_fill_header(header, "XSDT");
+       header->length = sizeof(struct acpi_xsdt);
+       header->revision = 1;
+
+       /* Entries are filled in later, we come with an empty set */
+
+       /* Fix checksum */
+       header->checksum = table_compute_checksum(xsdt,
+                                                 sizeof(struct acpi_xsdt));
+}
+
+void acpi_setup_base_tables(struct acpi_ctx *ctx, void *start)
+{
+       ctx->base = start;
+       ctx->current = start;
+
+       /* Align ACPI tables to 16 byte */
+       acpi_align(ctx);
+       gd->arch.acpi_start = map_to_sysmem(ctx->current);
+
+       /* We need at least an RSDP and an RSDT Table */
+       ctx->rsdp = ctx->current;
+       acpi_inc_align(ctx, sizeof(struct acpi_rsdp));
+       ctx->rsdt = ctx->current;
+       acpi_inc_align(ctx, sizeof(struct acpi_rsdt));
+       ctx->xsdt = ctx->current;
+       acpi_inc_align(ctx, sizeof(struct acpi_xsdt));
+
+       /* clear all table memory */
+       memset((void *)start, '\0', ctx->current - start);
+
+       acpi_write_rsdp(ctx->rsdp, ctx->rsdt, ctx->xsdt);
+       acpi_write_rsdt(ctx->rsdt);
+       acpi_write_xsdt(ctx->xsdt);
+       /*
+        * Per ACPI spec, the FACS table address must be aligned to a 64 byte
+        * boundary (Windows checks this, but Linux does not).
+        */
+       acpi_align64(ctx);
+}
+
+void acpi_create_dbg2(struct acpi_dbg2_header *dbg2,
+                     int port_type, int port_subtype,
+                     struct acpi_gen_regaddr *address, u32 address_size,
+                     const char *device_path)
+{
+       uintptr_t current;
+       struct acpi_dbg2_device *device;
+       u32 *dbg2_addr_size;
+       struct acpi_table_header *header;
+       size_t path_len;
+       const char *path;
+       char *namespace;
+
+       /* Fill out header fields. */
+       current = (uintptr_t)dbg2;
+       memset(dbg2, '\0', sizeof(struct acpi_dbg2_header));
+       header = &dbg2->header;
+
+       header->revision = acpi_get_table_revision(ACPITAB_DBG2);
+       acpi_fill_header(header, "DBG2");
+       header->aslc_revision = ASL_REVISION;
+
+       /* One debug device defined */
+       dbg2->devices_offset = sizeof(struct acpi_dbg2_header);
+       dbg2->devices_count = 1;
+       current += sizeof(struct acpi_dbg2_header);
+
+       /* Device comes after the header */
+       device = (struct acpi_dbg2_device *)current;
+       memset(device, 0, sizeof(struct acpi_dbg2_device));
+       current += sizeof(struct acpi_dbg2_device);
+
+       device->revision = 0;
+       device->address_count = 1;
+       device->port_type = port_type;
+       device->port_subtype = port_subtype;
+
+       /* Base Address comes after device structure */
+       memcpy((void *)current, address, sizeof(struct acpi_gen_regaddr));
+       device->base_address_offset = current - (uintptr_t)device;
+       current += sizeof(struct acpi_gen_regaddr);
+
+       /* Address Size comes after address structure */
+       dbg2_addr_size = (uint32_t *)current;
+       device->address_size_offset = current - (uintptr_t)device;
+       *dbg2_addr_size = address_size;
+       current += sizeof(uint32_t);
+
+       /* Namespace string comes last, use '.' if not provided */
+       path = device_path ? : ".";
+       /* Namespace string length includes NULL terminator */
+       path_len = strlen(path) + 1;
+       namespace = (char *)current;
+       device->namespace_string_length = path_len;
+       device->namespace_string_offset = current - (uintptr_t)device;
+       strncpy(namespace, path, path_len);
+       current += path_len;
+
+       /* Update structure lengths and checksum */
+       device->length = current - (uintptr_t)device;
+       header->length = current - (uintptr_t)dbg2;
+       header->checksum = table_compute_checksum(dbg2, header->length);
+}