uboot/arch/x86/lib/acpi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
   4 */
   5
   6#include <common.h>
   7#include <log.h>
   8#include <acpi/acpi_table.h>
   9#include <asm/io.h>
  10#include <asm/tables.h>
  11
  12static struct acpi_rsdp *acpi_valid_rsdp(struct acpi_rsdp *rsdp)
  13{
  14        if (strncmp((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0)
  15                return NULL;
  16
  17        debug("Looking on %p for valid checksum\n", rsdp);
  18
  19        if (table_compute_checksum((void *)rsdp, 20) != 0)
  20                return NULL;
  21        debug("acpi rsdp checksum 1 passed\n");
  22
  23        if ((rsdp->revision > 1) &&
  24            (table_compute_checksum((void *)rsdp, rsdp->length) != 0))
  25                return NULL;
  26        debug("acpi rsdp checksum 2 passed\n");
  27
  28        return rsdp;
  29}
  30
  31struct acpi_fadt *acpi_find_fadt(void)
  32{
  33        char *p, *end;
  34        struct acpi_rsdp *rsdp = NULL;
  35        struct acpi_rsdt *rsdt;
  36        struct acpi_fadt *fadt = NULL;
  37        int i;
  38
  39        /* Find RSDP */
  40        for (p = (char *)ROM_TABLE_ADDR; p < (char *)ROM_TABLE_END; p += 16) {
  41                rsdp = acpi_valid_rsdp((struct acpi_rsdp *)p);
  42                if (rsdp)
  43                        break;
  44        }
  45
  46        if (!rsdp)
  47                return NULL;
  48
  49        debug("RSDP found at %p\n", rsdp);
  50        rsdt = (struct acpi_rsdt *)(uintptr_t)rsdp->rsdt_address;
  51
  52        end = (char *)rsdt + rsdt->header.length;
  53        debug("RSDT found at %p ends at %p\n", rsdt, end);
  54
  55        for (i = 0; ((char *)&rsdt->entry[i]) < end; i++) {
  56                fadt = (struct acpi_fadt *)(uintptr_t)rsdt->entry[i];
  57                if (strncmp((char *)fadt, "FACP", 4) == 0)
  58                        break;
  59                fadt = NULL;
  60        }
  61
  62        if (!fadt)
  63                return NULL;
  64
  65        debug("FADT found at %p\n", fadt);
  66        return fadt;
  67}
  68
  69void *acpi_find_wakeup_vector(struct acpi_fadt *fadt)
  70{
  71        struct acpi_facs *facs;
  72        void *wake_vec;
  73
  74        debug("Trying to find the wakeup vector...\n");
  75
  76        facs = (struct acpi_facs *)(uintptr_t)fadt->firmware_ctrl;
  77
  78        if (!facs) {
  79                debug("No FACS found, wake up from S3 not possible.\n");
  80                return NULL;
  81        }
  82
  83        debug("FACS found at %p\n", facs);
  84        wake_vec = (void *)(uintptr_t)facs->firmware_waking_vector;
  85        debug("OS waking vector is %p\n", wake_vec);
  86
  87        return wake_vec;
  88}
  89
  90void enter_acpi_mode(int pm1_cnt)
  91{
  92        u16 val = inw(pm1_cnt);
  93
  94        /*
  95         * PM1_CNT register bit0 selects the power management event to be
  96         * either an SCI or SMI interrupt. When this bit is set, then power
  97         * management events will generate an SCI interrupt. When this bit
  98         * is reset power management events will generate an SMI interrupt.
  99         *
 100         * Per ACPI spec, it is the responsibility of the hardware to set
 101         * or reset this bit. OSPM always preserves this bit position.
 102         *
 103         * U-Boot does not support SMI. And we don't have plan to support
 104         * anything running in SMM within U-Boot. To create a legacy-free
 105         * system, and expose ourselves to OSPM as working under ACPI mode
 106         * already, turn this bit on.
 107         */
 108        outw(val | PM1_CNT_SCI_EN, pm1_cnt);
 109}
 110