acpi.c 2.6 KB

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