blob: f9e9162545e87e29ee6f736da1e0c7219a892ad4 [file] [log] [blame]
Patrick Georgi11f00792020-03-04 15:10:45 +01001/* SPDX-License-Identifier: GPL-2.0-only */
Stefan Reinauer688b3852004-01-28 16:56:14 +00002/*
Martin Roth20bbd812019-08-30 21:09:37 -06003 * coreboot ACPI Table support
Stefan Reinauer777224c2005-01-19 14:06:41 +00004 */
5
Stefan Reinauer14e22772010-04-27 06:56:47 +00006/*
Stefan Reinauer777224c2005-01-19 14:06:41 +00007 * Each system port implementing ACPI has to provide two functions:
Stefan Reinauer14e22772010-04-27 06:56:47 +00008 *
Stefan Reinauer777224c2005-01-19 14:06:41 +00009 * write_acpi_tables()
10 * acpi_dump_apics()
Stefan Reinauer14e22772010-04-27 06:56:47 +000011 *
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000012 * See Kontron 986LCD-M port for a good example of an ACPI implementation
13 * in coreboot.
Ronald G. Minnich02fa3b22004-10-06 17:33:54 +000014 */
Stefan Reinauer688b3852004-01-28 16:56:14 +000015
Furquan Shaikh76cedd22020-05-02 10:24:23 -070016#include <acpi/acpi.h>
Naresh Solanki6920c6f2023-09-13 12:01:58 +020017#include <acpi/acpi_iort.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -070018#include <acpi/acpi_ivrs.h>
19#include <acpi/acpigen.h>
Jianjun Wang8565b94a2022-03-02 10:20:26 +080020#include <cbfs.h>
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000021#include <cbmem.h>
Elyes HAOUASe2d152c2019-06-21 07:06:50 +020022#include <commonlib/helpers.h>
Jianjun Wang8565b94a2022-03-02 10:20:26 +080023#include <console/console.h>
Duncan Laurie11290c42012-10-03 19:07:05 -070024#include <cpu/cpu.h>
Jianjun Wang8565b94a2022-03-02 10:20:26 +080025#include <device/mmio.h>
26#include <device/pci.h>
Arthur Heymans736d4d22023-06-30 15:37:38 +020027#include <drivers/uart/pl011.h>
Jianjun Wang8565b94a2022-03-02 10:20:26 +080028#include <string.h>
Elyes HAOUAScdd2f632021-02-11 19:37:11 +010029#include <types.h>
Elyes HAOUAS26071aa2019-02-15 08:21:33 +010030#include <version.h>
Ronald G. Minnich02fa3b22004-10-06 17:33:54 +000031
Patrick Rudolphcfe08ff2019-09-10 15:40:47 +020032static acpi_rsdp_t *valid_rsdp(acpi_rsdp_t *rsdp);
33
Ronald G. Minnich02fa3b22004-10-06 17:33:54 +000034u8 acpi_checksum(u8 *table, u32 length)
Stefan Reinauer688b3852004-01-28 16:56:14 +000035{
Uwe Hermann622824c2010-11-19 15:14:42 +000036 u8 ret = 0;
Stefan Reinauer688b3852004-01-28 16:56:14 +000037 while (length--) {
38 ret += *table;
39 table++;
40 }
Stefan Reinauera7648c22004-01-29 17:31:34 +000041 return -ret;
Stefan Reinauer688b3852004-01-28 16:56:14 +000042}
43
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000044/**
Uwe Hermann622824c2010-11-19 15:14:42 +000045 * Add an ACPI table to the RSDT (and XSDT) structure, recalculate length
46 * and checksum.
Stefan Reinauer06feb882004-02-03 16:11:35 +000047 */
Stefan Reinauerb657a3c2009-07-21 21:38:33 +000048void acpi_add_table(acpi_rsdp_t *rsdp, void *table)
Stefan Reinauer688b3852004-01-28 16:56:14 +000049{
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000050 int i, entries_num;
Stefan Reinauerb657a3c2009-07-21 21:38:33 +000051 acpi_rsdt_t *rsdt;
Arthur Heymansc2830c92023-08-22 12:50:43 +020052 acpi_xsdt_t *xsdt;
Stefan Reinauerb657a3c2009-07-21 21:38:33 +000053
Arthur Heymansd8f2dce2023-06-22 13:42:36 +020054 /* The 32bit RSDT may not be valid if tables live above 4GiB */
Stefan Reinauerdefee172015-06-18 01:11:19 -070055 rsdt = (acpi_rsdt_t *)(uintptr_t)rsdp->rsdt_address;
Arthur Heymansd8f2dce2023-06-22 13:42:36 +020056 xsdt = (acpi_xsdt_t *)(uintptr_t)rsdp->xsdt_address;
Stefan Reinauer14e22772010-04-27 06:56:47 +000057
Uwe Hermann622824c2010-11-19 15:14:42 +000058 /* This should always be MAX_ACPI_TABLES. */
Arthur Heymansd8f2dce2023-06-22 13:42:36 +020059 entries_num = ARRAY_SIZE(xsdt->entry);
Stefan Reinauer14e22772010-04-27 06:56:47 +000060
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000061 for (i = 0; i < entries_num; i++) {
Arthur Heymansd8f2dce2023-06-22 13:42:36 +020062 if (xsdt->entry[i] == 0)
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000063 break;
Stefan Reinauer688b3852004-01-28 16:56:14 +000064 }
65
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000066 if (i >= entries_num) {
Uwe Hermann622824c2010-11-19 15:14:42 +000067 printk(BIOS_ERR, "ACPI: Error: Could not add ACPI table, "
Cristian Măgherușan-Stanciuba482812011-07-02 00:57:07 +030068 "too many tables.\n");
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000069 return;
70 }
71
Arthur Heymansd8f2dce2023-06-22 13:42:36 +020072 /* Add table to the XSDT. */
73 xsdt->entry[i] = (u64)(uintptr_t)table;
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000074
Arthur Heymansd8f2dce2023-06-22 13:42:36 +020075 /* Fix XSDT length or the kernel will assume invalid entries. */
76 xsdt->header.length = sizeof(acpi_header_t) + (sizeof(u64) * (i + 1));
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000077
Uwe Hermann622824c2010-11-19 15:14:42 +000078 /* Re-calculate checksum. */
Arthur Heymansd8f2dce2023-06-22 13:42:36 +020079 xsdt->header.checksum = 0; /* Hope this won't get optimized away */
80 xsdt->header.checksum = acpi_checksum((u8 *)xsdt, xsdt->header.length);
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000081
Uwe Hermann622824c2010-11-19 15:14:42 +000082 /*
Arthur Heymansd8f2dce2023-06-22 13:42:36 +020083 * And now the same thing for the RSDT. We use the same index as for
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000084 * now we want the XSDT and RSDT to always be in sync in coreboot.
85 */
Arthur Heymansd8f2dce2023-06-22 13:42:36 +020086 if (rsdt && (uintptr_t)table < UINT32_MAX) {
87 /* Add table to the RSDT. */
88 rsdt->entry[i] = (u32)(uintptr_t)table;
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000089
Arthur Heymansd8f2dce2023-06-22 13:42:36 +020090 /* Fix RSDT length. */
91 rsdt->header.length = sizeof(acpi_header_t) + (sizeof(u32) * (i + 1));
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000092
Uwe Hermann622824c2010-11-19 15:14:42 +000093 /* Re-calculate checksum. */
Arthur Heymansd8f2dce2023-06-22 13:42:36 +020094 rsdt->header.checksum = 0;
95 rsdt->header.checksum = acpi_checksum((u8 *)rsdt, rsdt->header.length);
Stefan Reinauerc0ac7e92009-11-10 22:17:15 +000096 }
97
Uwe Hermann622824c2010-11-19 15:14:42 +000098 printk(BIOS_DEBUG, "ACPI: added table %d/%d, length now %d\n",
Arthur Heymansd8f2dce2023-06-22 13:42:36 +020099 i + 1, entries_num, xsdt->header.length);
Stefan Reinauer688b3852004-01-28 16:56:14 +0000100}
101
Arthur Heymansadb80072023-06-28 09:56:00 +0200102static enum cb_err acpi_fill_header(acpi_header_t *header, const char name[4],
103 enum acpi_tables table, uint32_t size)
104{
105 if (!header)
106 return CB_ERR;
107
108 /* Fill out header fields. */
109 memcpy(header->signature, name, 4);
110 memcpy(header->oem_id, OEM_ID, 6);
111 memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
112 memcpy(header->asl_compiler_id, ASLC, 4);
113
114 header->asl_compiler_revision = asl_revision;
115 header->revision = get_acpi_table_revision(table);
116 header->length = size;
117
118 return CB_SUCCESS;
119}
120
Naresh Solanki4d0b1842023-08-25 12:58:11 +0200121static int acpi_create_mcfg_mmconfig(acpi_mcfg_mmconfig_t *mmconfig, u64 base,
Cristian Măgherușan-Stanciuba482812011-07-02 00:57:07 +0300122 u16 seg_nr, u8 start, u8 end)
Stefan Reinauer26d431a2009-01-20 19:17:51 +0000123{
Vladimir Serbinenko60fccdc2014-10-05 11:05:16 +0200124 memset(mmconfig, 0, sizeof(*mmconfig));
Rudolf Mareke6409f22007-11-03 12:50:26 +0000125 mmconfig->base_address = base;
Rudolf Mareke6409f22007-11-03 12:50:26 +0000126 mmconfig->pci_segment_group_number = seg_nr;
127 mmconfig->start_bus_number = start;
128 mmconfig->end_bus_number = end;
Uwe Hermann622824c2010-11-19 15:14:42 +0000129
130 return sizeof(acpi_mcfg_mmconfig_t);
Rudolf Mareke6409f22007-11-03 12:50:26 +0000131}
132
Arthur Heymans01af0f82023-06-27 11:58:04 +0200133static void acpi_create_madt(acpi_header_t *header, void *unused)
Stefan Reinauer06feb882004-02-03 16:11:35 +0000134{
Arthur Heymans01af0f82023-06-27 11:58:04 +0200135 acpi_madt_t *madt = (acpi_madt_t *)header;
Uwe Hermann622824c2010-11-19 15:14:42 +0000136 unsigned long current = (unsigned long)madt + sizeof(acpi_madt_t);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000137
Arthur Heymansadb80072023-06-28 09:56:00 +0200138 if (acpi_fill_header(header, "APIC", MADT, sizeof(acpi_madt_t)) != CB_SUCCESS)
John Zhao2ba303e2019-05-28 16:48:14 -0700139 return;
140
Arthur Heymanscd46e5f2023-06-22 21:34:16 +0200141 current = acpi_arch_fill_madt(madt, current);
Kyösti Mälkki10bdee12023-04-11 01:00:17 +0300142
143 if (CONFIG(ACPI_CUSTOM_MADT))
Kyösti Mälkkia5fa5342022-11-18 13:23:52 +0200144 current = acpi_fill_madt(current);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000145
Arthur Heymans01af0f82023-06-27 11:58:04 +0200146 /* (Re)calculate length . */
Uwe Hermann622824c2010-11-19 15:14:42 +0000147 header->length = current - (unsigned long)madt;
Stefan Reinauer06feb882004-02-03 16:11:35 +0000148}
149
Kyösti Mälkkib54388d2021-02-14 15:09:45 +0200150static unsigned long acpi_fill_mcfg(unsigned long current)
151{
152 current += acpi_create_mcfg_mmconfig((acpi_mcfg_mmconfig_t *)current,
Shelley Chen4e9bb332021-10-20 15:43:45 -0700153 CONFIG_ECAM_MMCONF_BASE_ADDRESS, 0, 0,
154 CONFIG_ECAM_MMCONF_BUS_NUMBER - 1);
Kyösti Mälkkib54388d2021-02-14 15:09:45 +0200155 return current;
156}
157
Uwe Hermann622824c2010-11-19 15:14:42 +0000158/* MCFG is defined in the PCI Firmware Specification 3.0. */
Arthur Heymans01af0f82023-06-27 11:58:04 +0200159static void acpi_create_mcfg(acpi_header_t *header, void *unused)
Rudolf Mareke6409f22007-11-03 12:50:26 +0000160{
Arthur Heymans01af0f82023-06-27 11:58:04 +0200161 acpi_mcfg_t *mcfg = (acpi_mcfg_t *)header;
Uwe Hermann622824c2010-11-19 15:14:42 +0000162 unsigned long current = (unsigned long)mcfg + sizeof(acpi_mcfg_t);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000163
Arthur Heymansadb80072023-06-28 09:56:00 +0200164
165 if (acpi_fill_header(header, "MCFG", MCFG, sizeof(acpi_mcfg_t)) != CB_SUCCESS)
John Zhao2ba303e2019-05-28 16:48:14 -0700166 return;
167
Shelley Chen4e9bb332021-10-20 15:43:45 -0700168 if (CONFIG(ECAM_MMCONF_SUPPORT))
Kyösti Mälkkib54388d2021-02-14 15:09:45 +0200169 current = acpi_fill_mcfg(current);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000170
Arthur Heymans01af0f82023-06-27 11:58:04 +0200171 /* (Re)calculate length */
Uwe Hermann622824c2010-11-19 15:14:42 +0000172 header->length = current - (unsigned long)mcfg;
Rudolf Mareke6409f22007-11-03 12:50:26 +0000173}
174
Vladimir Serbinenkof44ac132015-05-20 19:52:01 +0200175static void *get_tcpa_log(u32 *size)
176{
177 const struct cbmem_entry *ce;
178 const u32 tcpa_default_log_len = 0x10000;
179 void *lasa;
Philipp Deppenwiese791ba972018-07-30 01:15:20 +0200180 ce = cbmem_entry_find(CBMEM_ID_TCPA_TCG_LOG);
Vladimir Serbinenkof44ac132015-05-20 19:52:01 +0200181 if (ce) {
182 lasa = cbmem_entry_start(ce);
183 *size = cbmem_entry_size(ce);
184 printk(BIOS_DEBUG, "TCPA log found at %p\n", lasa);
185 return lasa;
186 }
Philipp Deppenwiese791ba972018-07-30 01:15:20 +0200187 lasa = cbmem_add(CBMEM_ID_TCPA_TCG_LOG, tcpa_default_log_len);
Vladimir Serbinenkof44ac132015-05-20 19:52:01 +0200188 if (!lasa) {
189 printk(BIOS_ERR, "TCPA log creation failed\n");
190 return NULL;
191 }
192
193 printk(BIOS_DEBUG, "TCPA log created at %p\n", lasa);
Lee Leahy024b13d2017-03-16 13:41:11 -0700194 memset(lasa, 0, tcpa_default_log_len);
Vladimir Serbinenkof44ac132015-05-20 19:52:01 +0200195
196 *size = tcpa_default_log_len;
197 return lasa;
198}
199
Arthur Heymans01af0f82023-06-27 11:58:04 +0200200static void acpi_create_tcpa(acpi_header_t *header, void *unused)
Vladimir Serbinenkof44ac132015-05-20 19:52:01 +0200201{
Arthur Heymans01af0f82023-06-27 11:58:04 +0200202 if (!CONFIG(TPM1))
203 return;
204
205 acpi_tcpa_t *tcpa = (acpi_tcpa_t *)header;
Vladimir Serbinenkof44ac132015-05-20 19:52:01 +0200206 u32 tcpa_log_len;
207 void *lasa;
208
Vladimir Serbinenkof44ac132015-05-20 19:52:01 +0200209 lasa = get_tcpa_log(&tcpa_log_len);
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700210 if (!lasa)
Vladimir Serbinenkof44ac132015-05-20 19:52:01 +0200211 return;
Vladimir Serbinenkof44ac132015-05-20 19:52:01 +0200212
Arthur Heymansadb80072023-06-28 09:56:00 +0200213 if (acpi_fill_header(header, "TCPA", TCPA, sizeof(acpi_tcpa_t)) != CB_SUCCESS)
John Zhao2ba303e2019-05-28 16:48:14 -0700214 return;
215
Vladimir Serbinenkof44ac132015-05-20 19:52:01 +0200216 tcpa->platform_class = 0;
217 tcpa->laml = tcpa_log_len;
Elyes Haouas3141fbad2022-11-18 15:22:32 +0100218 tcpa->lasa = (uintptr_t)lasa;
Vladimir Serbinenkof44ac132015-05-20 19:52:01 +0200219}
220
Michał Żygowski6e8692e2018-11-22 16:57:50 +0100221static void *get_tpm2_log(u32 *size)
222{
223 const struct cbmem_entry *ce;
224 const u32 tpm2_default_log_len = 0x10000;
225 void *lasa;
226 ce = cbmem_entry_find(CBMEM_ID_TPM2_TCG_LOG);
227 if (ce) {
228 lasa = cbmem_entry_start(ce);
229 *size = cbmem_entry_size(ce);
230 printk(BIOS_DEBUG, "TPM2 log found at %p\n", lasa);
231 return lasa;
232 }
233 lasa = cbmem_add(CBMEM_ID_TPM2_TCG_LOG, tpm2_default_log_len);
234 if (!lasa) {
235 printk(BIOS_ERR, "TPM2 log creation failed\n");
236 return NULL;
237 }
238
239 printk(BIOS_DEBUG, "TPM2 log created at %p\n", lasa);
240 memset(lasa, 0, tpm2_default_log_len);
241
242 *size = tpm2_default_log_len;
243 return lasa;
244}
245
Arthur Heymans01af0f82023-06-27 11:58:04 +0200246static void acpi_create_tpm2(acpi_header_t *header, void *unused)
Philipp Deppenwiese296164e02018-10-18 15:39:34 +0200247{
Arthur Heymans01af0f82023-06-27 11:58:04 +0200248 if (!CONFIG(TPM2))
249 return;
250
251 acpi_tpm2_t *tpm2 = (acpi_tpm2_t *)header;
Michał Żygowski6e8692e2018-11-22 16:57:50 +0100252 u32 tpm2_log_len;
253 void *lasa;
Philipp Deppenwiese296164e02018-10-18 15:39:34 +0200254
Michał Żygowski6e8692e2018-11-22 16:57:50 +0100255 /*
256 * Some payloads like SeaBIOS depend on log area to use TPM2.
257 * Get the memory size and address of TPM2 log area or initialize it.
258 */
259 lasa = get_tpm2_log(&tpm2_log_len);
260 if (!lasa)
261 tpm2_log_len = 0;
262
Arthur Heymansadb80072023-06-28 09:56:00 +0200263 if (acpi_fill_header(header, "TPM2", TPM2, sizeof(acpi_tpm2_t)) != CB_SUCCESS)
John Zhao2ba303e2019-05-28 16:48:14 -0700264 return;
265
Philipp Deppenwiese296164e02018-10-18 15:39:34 +0200266 /* Hard to detect for coreboot. Just set it to 0 */
267 tpm2->platform_class = 0;
Christian Walter26e0d4c2019-07-14 15:47:23 +0200268 if (CONFIG(CRB_TPM)) {
269 /* Must be set to 7 for CRB Support */
270 tpm2->control_area = CONFIG_CRB_TPM_BASE_ADDRESS + 0x40;
271 tpm2->start_method = 7;
272 } else {
273 /* Must be set to 0 for FIFO interface support */
274 tpm2->control_area = 0;
275 tpm2->start_method = 6;
276 }
Philipp Deppenwiese296164e02018-10-18 15:39:34 +0200277 memset(tpm2->msp, 0, sizeof(tpm2->msp));
278
Michał Żygowski6e8692e2018-11-22 16:57:50 +0100279 /* Fill the log area size and start address fields. */
280 tpm2->laml = tpm2_log_len;
Elyes Haouas3141fbad2022-11-18 15:22:32 +0100281 tpm2->lasa = (uintptr_t)lasa;
Philipp Deppenwiese296164e02018-10-18 15:39:34 +0200282}
283
Duncan Laurie37319032016-05-26 12:47:05 -0700284static void acpi_ssdt_write_cbtable(void)
285{
286 const struct cbmem_entry *cbtable;
287 uintptr_t base;
288 uint32_t size;
289
290 cbtable = cbmem_entry_find(CBMEM_ID_CBTABLE);
291 if (!cbtable)
292 return;
293 base = (uintptr_t)cbmem_entry_start(cbtable);
294 size = cbmem_entry_size(cbtable);
295
296 acpigen_write_device("CTBL");
297 acpigen_write_coreboot_hid(COREBOOT_ACPI_ID_CBTABLE);
298 acpigen_write_name_integer("_UID", 0);
Matt DeVillierce10b6f2022-10-15 11:52:54 -0500299 acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_ON);
Duncan Laurie37319032016-05-26 12:47:05 -0700300 acpigen_write_name("_CRS");
301 acpigen_write_resourcetemplate_header();
302 acpigen_write_mem32fixed(0, base, size);
303 acpigen_write_resourcetemplate_footer();
304 acpigen_pop_len();
305}
306
Arthur Heymans01af0f82023-06-27 11:58:04 +0200307static void acpi_create_ssdt_generator(acpi_header_t *ssdt, void *unused)
Rudolf Marek293b5f52009-02-01 18:35:15 +0000308{
Uwe Hermann622824c2010-11-19 15:14:42 +0000309 unsigned long current = (unsigned long)ssdt + sizeof(acpi_header_t);
310
Arthur Heymansadb80072023-06-28 09:56:00 +0200311 if (acpi_fill_header(ssdt, "SSDT", SSDT, sizeof(acpi_header_t)) != CB_SUCCESS)
312 return;
Rudolf Marek293b5f52009-02-01 18:35:15 +0000313
Elyes Haouas3141fbad2022-11-18 15:22:32 +0100314 acpigen_set_current((char *)current);
Duncan Laurie37319032016-05-26 12:47:05 -0700315
316 /* Write object to declare coreboot tables */
317 acpi_ssdt_write_cbtable();
318
Vladimir Serbinenko2d7bd8a2014-08-30 19:28:05 +0200319 {
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100320 struct device *dev;
Vladimir Serbinenko2d7bd8a2014-08-30 19:28:05 +0200321 for (dev = all_devices; dev; dev = dev->next)
Karthikeyan Ramasubramaniand1c0f952020-11-02 16:26:52 -0700322 if (dev->enabled && dev->ops && dev->ops->acpi_fill_ssdt)
Nico Huber68680dd2020-03-31 17:34:52 +0200323 dev->ops->acpi_fill_ssdt(dev);
Elyes Haouas3141fbad2022-11-18 15:22:32 +0100324 current = (unsigned long)acpigen_get_current();
Vladimir Serbinenko2d7bd8a2014-08-30 19:28:05 +0200325 }
Rudolf Marek293b5f52009-02-01 18:35:15 +0000326
Uwe Hermann622824c2010-11-19 15:14:42 +0000327 /* (Re)calculate length and checksum. */
Rudolf Marek293b5f52009-02-01 18:35:15 +0000328 ssdt->length = current - (unsigned long)ssdt;
Rudolf Marek293b5f52009-02-01 18:35:15 +0000329}
330
Uwe Hermann622824c2010-11-19 15:14:42 +0000331int acpi_create_srat_mem(acpi_srat_mem_t *mem, u8 node, u32 basek, u32 sizek,
Cristian Măgherușan-Stanciuba482812011-07-02 00:57:07 +0300332 u32 flags)
Stefan Reinauerf622d592005-11-26 16:56:05 +0000333{
Uwe Hermann622824c2010-11-19 15:14:42 +0000334 mem->type = 1; /* Memory affinity structure */
335 mem->length = sizeof(acpi_srat_mem_t);
336 mem->base_address_low = (basek << 10);
337 mem->base_address_high = (basek >> (32 - 10));
338 mem->length_low = (sizek << 10);
339 mem->length_high = (sizek >> (32 - 10));
340 mem->proximity_domain = node;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000341 mem->flags = flags;
Stefan Reinauerf622d592005-11-26 16:56:05 +0000342
Uwe Hermann622824c2010-11-19 15:14:42 +0000343 return mem->length;
Stefan Reinauerf622d592005-11-26 16:56:05 +0000344}
345
Jonathan Zhang3164b642021-04-21 17:51:31 -0700346int acpi_create_srat_gia_pci(acpi_srat_gia_t *gia, u32 proximity_domain,
347 u16 seg, u8 bus, u8 dev, u8 func, u32 flags)
348{
349 gia->type = ACPI_SRAT_STRUCTURE_GIA;
350 gia->length = sizeof(acpi_srat_gia_t);
351 gia->proximity_domain = proximity_domain;
352 gia->dev_handle_type = ACPI_SRAT_GIA_DEV_HANDLE_PCI;
353 /* First two bytes has segment number */
354 memcpy(gia->dev_handle, &seg, 2);
355 gia->dev_handle[2] = bus; /* Byte 2 has bus number */
356 /* Byte 3 has bits 7:3 for dev, bits 2:0 for func */
357 gia->dev_handle[3] = PCI_SLOT(dev) | PCI_FUNC(func);
358 gia->flags = flags;
359
360 return gia->length;
361}
362
Uwe Hermann622824c2010-11-19 15:14:42 +0000363/* http://www.microsoft.com/whdc/system/sysinternals/sratdwn.mspx */
Vladimir Serbinenko5e597572014-10-11 23:45:40 +0200364void acpi_create_srat(acpi_srat_t *srat,
365 unsigned long (*acpi_fill_srat)(unsigned long current))
Stefan Reinauerf622d592005-11-26 16:56:05 +0000366{
Uwe Hermann622824c2010-11-19 15:14:42 +0000367 acpi_header_t *header = &(srat->header);
368 unsigned long current = (unsigned long)srat + sizeof(acpi_srat_t);
Stefan Reinauerf622d592005-11-26 16:56:05 +0000369
Uwe Hermann622824c2010-11-19 15:14:42 +0000370 memset((void *)srat, 0, sizeof(acpi_srat_t));
Stefan Reinauerf622d592005-11-26 16:56:05 +0000371
Arthur Heymansadb80072023-06-28 09:56:00 +0200372 if (acpi_fill_header(header, "SRAT", SRAT, sizeof(acpi_srat_t)) != CB_SUCCESS)
John Zhao2ba303e2019-05-28 16:48:14 -0700373 return;
374
Uwe Hermann622824c2010-11-19 15:14:42 +0000375 srat->resv = 1; /* Spec: Reserved to 1 for backwards compatibility. */
Stefan Reinauerf622d592005-11-26 16:56:05 +0000376
Uwe Hermann622824c2010-11-19 15:14:42 +0000377 current = acpi_fill_srat(current);
Stefan Reinauerf622d592005-11-26 16:56:05 +0000378
Uwe Hermann622824c2010-11-19 15:14:42 +0000379 /* (Re)calculate length and checksum. */
380 header->length = current - (unsigned long)srat;
381 header->checksum = acpi_checksum((void *)srat, header->length);
Stefan Reinauerf622d592005-11-26 16:56:05 +0000382}
383
Jonathan Zhang3dcafa82022-05-11 13:11:20 -0700384int acpi_create_cedt_chbs(acpi_cedt_chbs_t *chbs, u32 uid, u32 cxl_ver, u64 base)
385{
386 memset((void *)chbs, 0, sizeof(acpi_cedt_chbs_t));
387
388 chbs->type = ACPI_CEDT_STRUCTURE_CHBS;
389 chbs->length = sizeof(acpi_cedt_chbs_t);
390 chbs->uid = uid;
391 chbs->cxl_ver = cxl_ver;
392 chbs->base = base;
393
394 /*
395 * CXL spec 2.0 section 9.14.1.2 "CXL CHBS"
396 * CXL 1.1 spec compliant host bridge: 8KB
397 * CXL 2.0 spec compliant host bridge: 64KB
398 */
399 if (cxl_ver == ACPI_CEDT_CHBS_CXL_VER_1_1)
400 chbs->len = 8 * KiB;
401 else if (cxl_ver == ACPI_CEDT_CHBS_CXL_VER_2_0)
402 chbs->len = 64 * KiB;
403 else
404 printk(BIOS_ERR, "ACPI(%s:%s): Incorrect CXL version:%d\n", __FILE__, __func__,
405 cxl_ver);
406
407 return chbs->length;
408}
409
410int acpi_create_cedt_cfmws(acpi_cedt_cfmws_t *cfmws, u64 base_hpa, u64 window_size, u8 eniw,
411 u32 hbig, u16 restriction, u16 qtg_id, const u32 *interleave_target)
412{
413 memset((void *)cfmws, 0, sizeof(acpi_cedt_cfmws_t));
414
415 cfmws->type = ACPI_CEDT_STRUCTURE_CFMWS;
416
417 u8 niw = 0;
418 if (eniw >= 8)
419 printk(BIOS_ERR, "ACPI(%s:%s): Incorrect eniw::%d\n", __FILE__, __func__, eniw);
420 else
421 /* NIW = 2 ** ENIW */
422 niw = 0x1 << eniw;
423 /* 36 + 4 * NIW */
424 cfmws->length = sizeof(acpi_cedt_cfmws_t) + 4 * niw;
425
426 cfmws->base_hpa = base_hpa;
427 cfmws->window_size = window_size;
428 cfmws->eniw = eniw;
429
430 // 0: Standard Modulo Arithmetic. Other values reserved.
431 cfmws->interleave_arithmetic = 0;
432
433 cfmws->hbig = hbig;
434 cfmws->restriction = restriction;
435 cfmws->qtg_id = qtg_id;
436 memcpy(&cfmws->interleave_target, interleave_target, 4 * niw);
437
438 return cfmws->length;
439}
440
441void acpi_create_cedt(acpi_cedt_t *cedt, unsigned long (*acpi_fill_cedt)(unsigned long current))
442{
443 acpi_header_t *header = &(cedt->header);
444 unsigned long current = (unsigned long)cedt + sizeof(acpi_cedt_t);
445
446 memset((void *)cedt, 0, sizeof(acpi_cedt_t));
447
Arthur Heymansadb80072023-06-28 09:56:00 +0200448 if (acpi_fill_header(header, "CEDT", CEDT, sizeof(acpi_cedt_t)) != CB_SUCCESS)
Jonathan Zhang3dcafa82022-05-11 13:11:20 -0700449 return;
450
Jonathan Zhang3dcafa82022-05-11 13:11:20 -0700451 current = acpi_fill_cedt(current);
452
453 /* (Re)calculate length and checksum. */
454 header->length = current - (unsigned long)cedt;
455 header->checksum = acpi_checksum((void *)cedt, header->length);
456}
457
Jonathan Zhang2a4e1f42021-04-01 11:43:37 -0700458int acpi_create_hmat_mpda(acpi_hmat_mpda_t *mpda, u32 initiator, u32 memory)
459{
460 memset((void *)mpda, 0, sizeof(acpi_hmat_mpda_t));
461
462 mpda->type = 0; /* Memory Proximity Domain Attributes structure */
463 mpda->length = sizeof(acpi_hmat_mpda_t);
464 /*
465 * Proximity Domain for Attached Initiator field is valid.
466 * Bit 1 and bit 2 are reserved since HMAT revision 2.
467 */
468 mpda->flags = (1 << 0);
469 mpda->proximity_domain_initiator = initiator;
470 mpda->proximity_domain_memory = memory;
471
472 return mpda->length;
473}
474
475void acpi_create_hmat(acpi_hmat_t *hmat,
476 unsigned long (*acpi_fill_hmat)(unsigned long current))
477{
478 acpi_header_t *header = &(hmat->header);
479 unsigned long current = (unsigned long)hmat + sizeof(acpi_hmat_t);
480
481 memset((void *)hmat, 0, sizeof(acpi_hmat_t));
482
Arthur Heymansadb80072023-06-28 09:56:00 +0200483 if (acpi_fill_header(header, "HMAT", HMAT, sizeof(acpi_hmat_t)) != CB_SUCCESS)
Jonathan Zhang2a4e1f42021-04-01 11:43:37 -0700484 return;
485
Jonathan Zhang2a4e1f42021-04-01 11:43:37 -0700486 current = acpi_fill_hmat(current);
487
488 /* (Re)calculate length and checksum. */
489 header->length = current - (unsigned long)hmat;
490 header->checksum = acpi_checksum((void *)hmat, header->length);
491}
492
Uwe Hermann622824c2010-11-19 15:14:42 +0000493/* http://h21007.www2.hp.com/portal/download/files/unprot/Itanium/slit.pdf */
Vladimir Serbinenko5e597572014-10-11 23:45:40 +0200494void acpi_create_slit(acpi_slit_t *slit,
495 unsigned long (*acpi_fill_slit)(unsigned long current))
Yinghai Lud4b278c2006-10-04 20:46:15 +0000496{
Uwe Hermann622824c2010-11-19 15:14:42 +0000497 acpi_header_t *header = &(slit->header);
498 unsigned long current = (unsigned long)slit + sizeof(acpi_slit_t);
Yinghai Lud4b278c2006-10-04 20:46:15 +0000499
Uwe Hermann622824c2010-11-19 15:14:42 +0000500 memset((void *)slit, 0, sizeof(acpi_slit_t));
Yinghai Lud4b278c2006-10-04 20:46:15 +0000501
Arthur Heymansadb80072023-06-28 09:56:00 +0200502 if (acpi_fill_header(header, "SLIT", SLIT, sizeof(acpi_slit_t)) != CB_SUCCESS)
John Zhao2ba303e2019-05-28 16:48:14 -0700503 return;
504
Uwe Hermann622824c2010-11-19 15:14:42 +0000505 current = acpi_fill_slit(current);
Yinghai Lud4b278c2006-10-04 20:46:15 +0000506
Uwe Hermann622824c2010-11-19 15:14:42 +0000507 /* (Re)calculate length and checksum. */
508 header->length = current - (unsigned long)slit;
509 header->checksum = acpi_checksum((void *)slit, header->length);
Yinghai Lud4b278c2006-10-04 20:46:15 +0000510}
511
Rocky Phaguraeff07132021-01-10 15:42:50 -0800512/*
513 * This method adds the ACPI error injection capability. It fills the default information.
514 * HW dependent code (caller) can modify the defaults upon return. If no changes are necessary
515 * and the defaults are acceptable then caller can simply add the table (acpi_add_table).
516 * INPUTS:
517 * einj - ptr to the starting location of EINJ table
518 * actions - number of actions to trigger an error (HW dependent)
519 * addr - address of trigger action table. This should be ACPI reserved memory and it will be
520 * shared between OS and FW.
521 */
522void acpi_create_einj(acpi_einj_t *einj, uintptr_t addr, u8 actions)
523{
524 int i;
525 acpi_header_t *header = &(einj->header);
526 acpi_injection_header_t *inj_header = &(einj->inj_header);
527 acpi_einj_smi_t *einj_smi = (acpi_einj_smi_t *)addr;
528 acpi_einj_trigger_table_t *tat;
529 if (!header)
530 return;
531
532 printk(BIOS_DEBUG, "%s einj_smi = %p\n", __func__, einj_smi);
533 memset(einj_smi, 0, sizeof(acpi_einj_smi_t));
Jonathan Zhangd5d9b282022-11-07 17:30:14 -0800534 tat = (acpi_einj_trigger_table_t *)((uint8_t *)einj_smi + sizeof(acpi_einj_smi_t));
Rocky Phaguraeff07132021-01-10 15:42:50 -0800535 tat->header_size = 16;
536 tat->revision = 0;
537 tat->table_size = sizeof(acpi_einj_trigger_table_t) +
538 sizeof(acpi_einj_action_table_t) * actions - 1;
539 tat->entry_count = actions;
540 printk(BIOS_DEBUG, "%s trigger_action_table = %p\n", __func__, tat);
541
542 for (i = 0; i < actions; i++) {
543 tat->trigger_action[i].action = TRIGGER_ERROR;
544 tat->trigger_action[i].instruction = NO_OP;
545 tat->trigger_action[i].flags = FLAG_IGNORE;
546 tat->trigger_action[i].reg.space_id = ACPI_ADDRESS_SPACE_MEMORY;
547 tat->trigger_action[i].reg.bit_width = 64;
548 tat->trigger_action[i].reg.bit_offset = 0;
549 tat->trigger_action[i].reg.access_size = ACPI_ACCESS_SIZE_QWORD_ACCESS;
550 tat->trigger_action[i].reg.addr = 0;
551 tat->trigger_action[i].value = 0;
552 tat->trigger_action[i].mask = 0xFFFFFFFF;
553 }
554
555 acpi_einj_action_table_t default_actions[ACTION_COUNT] = {
556 [0] = {
557 .action = BEGIN_INJECT_OP,
558 .instruction = WRITE_REGISTER_VALUE,
559 .flags = FLAG_PRESERVE,
560 .reg = EINJ_REG_MEMORY((u64)(uintptr_t)&einj_smi->op_state),
561 .value = 0,
562 .mask = 0xFFFFFFFF
563 },
564 [1] = {
565 .action = GET_TRIGGER_ACTION_TABLE,
566 .instruction = READ_REGISTER,
567 .flags = FLAG_IGNORE,
568 .reg = EINJ_REG_MEMORY((u64)(uintptr_t)&einj_smi->trigger_action_table),
569 .value = 0,
570 .mask = 0xFFFFFFFFFFFFFFFF
571 },
572 [2] = {
573 .action = SET_ERROR_TYPE,
574 .instruction = WRITE_REGISTER,
575 .flags = FLAG_PRESERVE,
576 .reg = EINJ_REG_MEMORY((u64)(uintptr_t)&einj_smi->err_inject[0]),
577 .value = 0,
578 .mask = 0xFFFFFFFF
579 },
580 [3] = {
581 .action = GET_ERROR_TYPE,
582 .instruction = READ_REGISTER,
583 .flags = FLAG_IGNORE,
584 .reg = EINJ_REG_MEMORY((u64)(uintptr_t)&einj_smi->err_inj_cap),
585 .value = 0,
586 .mask = 0xFFFFFFFF
587 },
588 [4] = {
589 .action = END_INJECT_OP,
590 .instruction = WRITE_REGISTER_VALUE,
591 .flags = FLAG_PRESERVE,
592 .reg = EINJ_REG_MEMORY((u64)(uintptr_t)&einj_smi->op_state),
593 .value = 0,
594 .mask = 0xFFFFFFFF
595
596 },
597 [5] = {
598 .action = EXECUTE_INJECT_OP,
599 .instruction = WRITE_REGISTER_VALUE,
600 .flags = FLAG_PRESERVE,
601 .reg = EINJ_REG_IO(),
602 .value = 0x9a,
603 .mask = 0xFFFF,
604 },
605 [6] = {
606 .action = CHECK_BUSY_STATUS,
607 .instruction = READ_REGISTER_VALUE,
608 .flags = FLAG_IGNORE,
609 .reg = EINJ_REG_MEMORY((u64)(uintptr_t)&einj_smi->op_status),
610 .value = 1,
611 .mask = 1,
612 },
613 [7] = {
614 .action = GET_CMD_STATUS,
615 .instruction = READ_REGISTER,
616 .flags = FLAG_PRESERVE,
617 .reg = EINJ_REG_MEMORY((u64)(uintptr_t)&einj_smi->cmd_sts),
618 .value = 0,
619 .mask = 0x1fe,
620 },
621 [8] = {
622 .action = SET_ERROR_TYPE_WITH_ADDRESS,
623 .instruction = WRITE_REGISTER,
624 .flags = FLAG_PRESERVE,
625 .reg = EINJ_REG_MEMORY((u64)(uintptr_t)&einj_smi->setaddrtable),
626 .value = 1,
627 .mask = 0xffffffff
628 }
629 };
630
631 einj_smi->err_inj_cap = ACPI_EINJ_DEFAULT_CAP;
Elyes Haouas3141fbad2022-11-18 15:22:32 +0100632 einj_smi->trigger_action_table = (u64)(uintptr_t)tat;
Rocky Phaguraeff07132021-01-10 15:42:50 -0800633
634 for (i = 0; i < ACTION_COUNT; i++)
635 printk(BIOS_DEBUG, "default_actions[%d].reg.addr is %llx\n", i,
636 default_actions[i].reg.addr);
637
Rocky Phagurab46a9e52021-05-21 13:34:03 -0700638 memset((void *)einj, 0, sizeof(*einj));
Rocky Phaguraeff07132021-01-10 15:42:50 -0800639
Arthur Heymansadb80072023-06-28 09:56:00 +0200640 if (acpi_fill_header(header, "EINJ", EINJ, sizeof(acpi_einj_t)) != CB_SUCCESS)
641 return;
Rocky Phaguraeff07132021-01-10 15:42:50 -0800642
Rocky Phaguraeff07132021-01-10 15:42:50 -0800643 inj_header->einj_header_size = sizeof(acpi_injection_header_t);
644 inj_header->entry_count = ACTION_COUNT;
645
646 printk(BIOS_DEBUG, "%s einj->action_table = %p\n",
647 __func__, einj->action_table);
648 memcpy((void *)einj->action_table, (void *)default_actions, sizeof(einj->action_table));
Rocky Phagurab46a9e52021-05-21 13:34:03 -0700649 header->checksum = acpi_checksum((void *)einj, sizeof(*einj));
Rocky Phaguraeff07132021-01-10 15:42:50 -0800650}
651
Furquan Shaikh0f007d82020-04-24 06:41:18 -0700652void acpi_create_vfct(const struct device *device,
Himanshu Sahdev7f1da072019-10-21 15:27:19 +0530653 acpi_vfct_t *vfct,
Furquan Shaikh0f007d82020-04-24 06:41:18 -0700654 unsigned long (*acpi_fill_vfct)(const struct device *device,
Himanshu Sahdev7f1da072019-10-21 15:27:19 +0530655 acpi_vfct_t *vfct_struct, unsigned long current))
Patrick Rudolpha5c2ac62016-03-31 20:04:23 +0200656{
657 acpi_header_t *header = &(vfct->header);
Himanshu Sahdev7f1da072019-10-21 15:27:19 +0530658 unsigned long current = (unsigned long)vfct + sizeof(acpi_vfct_t);
Patrick Rudolpha5c2ac62016-03-31 20:04:23 +0200659
Himanshu Sahdev7f1da072019-10-21 15:27:19 +0530660 memset((void *)vfct, 0, sizeof(acpi_vfct_t));
Patrick Rudolpha5c2ac62016-03-31 20:04:23 +0200661
Arthur Heymansadb80072023-06-28 09:56:00 +0200662 if (acpi_fill_header(header, "VFCT", VFCT, sizeof(acpi_vfct_t)) != CB_SUCCESS)
John Zhao2ba303e2019-05-28 16:48:14 -0700663 return;
664
Patrick Rudolpha5c2ac62016-03-31 20:04:23 +0200665 current = acpi_fill_vfct(device, vfct, current);
666
Kyösti Mälkkifb493792019-06-30 06:29:52 +0300667 /* If no BIOS image, return with header->length == 0. */
668 if (!vfct->VBIOSImageOffset)
669 return;
670
Patrick Rudolpha5c2ac62016-03-31 20:04:23 +0200671 /* (Re)calculate length and checksum. */
672 header->length = current - (unsigned long)vfct;
673 header->checksum = acpi_checksum((void *)vfct, header->length);
674}
675
Furquan Shaikh0f007d82020-04-24 06:41:18 -0700676void acpi_create_ipmi(const struct device *device,
Patrick Rudolph9d98e5a2019-06-14 19:00:04 +0200677 struct acpi_spmi *spmi,
678 const u16 ipmi_revision,
679 const acpi_addr_t *addr,
680 const enum acpi_ipmi_interface_type type,
681 const s8 gpe_interrupt,
682 const u32 apic_interrupt,
683 const u32 uid)
684{
685 acpi_header_t *header = &(spmi->header);
686 memset((void *)spmi, 0, sizeof(struct acpi_spmi));
687
Arthur Heymansadb80072023-06-28 09:56:00 +0200688 if (acpi_fill_header(header, "SPMI", SPMI, sizeof(struct acpi_spmi)) != CB_SUCCESS)
689 return;
Patrick Rudolph9d98e5a2019-06-14 19:00:04 +0200690
691 spmi->reserved = 1;
692
693 if (device->path.type == DEVICE_PATH_PCI) {
694 spmi->pci_device_flag = ACPI_IPMI_PCI_DEVICE_FLAG;
695 spmi->pci_bus = device->bus->secondary;
696 spmi->pci_device = device->path.pci.devfn >> 3;
697 spmi->pci_function = device->path.pci.devfn & 0x7;
698 } else if (type != IPMI_INTERFACE_SSIF) {
699 memcpy(spmi->uid, &uid, sizeof(spmi->uid));
700 }
701
702 spmi->base_address = *addr;
703 spmi->specification_revision = ipmi_revision;
704
705 spmi->interface_type = type;
706
707 if (gpe_interrupt >= 0 && gpe_interrupt < 32) {
708 spmi->gpe = gpe_interrupt;
709 spmi->interrupt_type |= ACPI_IPMI_INT_TYPE_SCI;
710 }
711 if (apic_interrupt > 0) {
712 spmi->global_system_interrupt = apic_interrupt;
713 spmi->interrupt_type |= ACPI_IPMI_INT_TYPE_APIC;
714 }
715
716 /* Calculate checksum. */
717 header->checksum = acpi_checksum((void *)spmi, header->length);
718}
719
Timothy Pearsonff8ccf02015-08-11 17:48:32 -0500720void acpi_create_ivrs(acpi_ivrs_t *ivrs,
Lee Leahy6f80ccc2017-03-16 15:18:22 -0700721 unsigned long (*acpi_fill_ivrs)(acpi_ivrs_t *ivrs_struct,
722 unsigned long current))
Timothy Pearsonff8ccf02015-08-11 17:48:32 -0500723{
724 acpi_header_t *header = &(ivrs->header);
725 unsigned long current = (unsigned long)ivrs + sizeof(acpi_ivrs_t);
726
727 memset((void *)ivrs, 0, sizeof(acpi_ivrs_t));
728
Arthur Heymansadb80072023-06-28 09:56:00 +0200729 if (acpi_fill_header(header, "IVRS", IVRS, sizeof(acpi_ivrs_t)) != CB_SUCCESS)
John Zhao2ba303e2019-05-28 16:48:14 -0700730 return;
731
Timothy Pearsonff8ccf02015-08-11 17:48:32 -0500732 current = acpi_fill_ivrs(ivrs, current);
733
734 /* (Re)calculate length and checksum. */
735 header->length = current - (unsigned long)ivrs;
736 header->checksum = acpi_checksum((void *)ivrs, header->length);
737}
738
Jason Glenesk61624b22020-11-02 20:06:23 -0800739void acpi_create_crat(struct acpi_crat_header *crat,
740 unsigned long (*acpi_fill_crat)(struct acpi_crat_header *crat_struct,
741 unsigned long current))
742{
743 acpi_header_t *header = &(crat->header);
744 unsigned long current = (unsigned long)crat + sizeof(struct acpi_crat_header);
745
746 memset((void *)crat, 0, sizeof(struct acpi_crat_header));
747
Arthur Heymansadb80072023-06-28 09:56:00 +0200748 if (acpi_fill_header(header, "CRAT", CRAT, sizeof(struct acpi_crat_header)) != CB_SUCCESS)
Jason Glenesk61624b22020-11-02 20:06:23 -0800749 return;
750
Jason Glenesk61624b22020-11-02 20:06:23 -0800751 current = acpi_fill_crat(crat, current);
752
753 /* (Re)calculate length and checksum. */
754 header->length = current - (unsigned long)crat;
755 header->checksum = acpi_checksum((void *)crat, header->length);
756}
757
Arthur Heymans9368cf92023-04-25 16:07:49 +0200758static void acpi_create_dbg2(acpi_dbg2_header_t *dbg2,
Duncan Lauriee4a36c72017-11-11 19:33:25 -0800759 int port_type, int port_subtype,
760 acpi_addr_t *address, uint32_t address_size,
761 const char *device_path)
762{
763 uintptr_t current;
764 acpi_dbg2_device_t *device;
765 uint32_t *dbg2_addr_size;
766 acpi_header_t *header;
767 size_t path_len;
768 const char *path;
769 char *namespace;
770
771 /* Fill out header fields. */
772 current = (uintptr_t)dbg2;
773 memset(dbg2, 0, sizeof(acpi_dbg2_header_t));
774 header = &(dbg2->header);
John Zhao2ba303e2019-05-28 16:48:14 -0700775
Arthur Heymansadb80072023-06-28 09:56:00 +0200776 if (acpi_fill_header(header, "DBG2", DBG2, sizeof(acpi_dbg2_header_t)) != CB_SUCCESS)
John Zhao2ba303e2019-05-28 16:48:14 -0700777 return;
778
Duncan Lauriee4a36c72017-11-11 19:33:25 -0800779 /* One debug device defined */
780 dbg2->devices_offset = sizeof(acpi_dbg2_header_t);
781 dbg2->devices_count = 1;
782 current += sizeof(acpi_dbg2_header_t);
783
784 /* Device comes after the header */
785 device = (acpi_dbg2_device_t *)current;
786 memset(device, 0, sizeof(acpi_dbg2_device_t));
787 current += sizeof(acpi_dbg2_device_t);
788
789 device->revision = 0;
790 device->address_count = 1;
791 device->port_type = port_type;
792 device->port_subtype = port_subtype;
793
794 /* Base Address comes after device structure */
795 memcpy((void *)current, address, sizeof(acpi_addr_t));
796 device->base_address_offset = current - (uintptr_t)device;
797 current += sizeof(acpi_addr_t);
798
799 /* Address Size comes after address structure */
800 dbg2_addr_size = (uint32_t *)current;
801 device->address_size_offset = current - (uintptr_t)device;
802 *dbg2_addr_size = address_size;
803 current += sizeof(uint32_t);
804
805 /* Namespace string comes last, use '.' if not provided */
806 path = device_path ? : ".";
807 /* Namespace string length includes NULL terminator */
808 path_len = strlen(path) + 1;
809 namespace = (char *)current;
810 device->namespace_string_length = path_len;
811 device->namespace_string_offset = current - (uintptr_t)device;
812 strncpy(namespace, path, path_len);
813 current += path_len;
814
815 /* Update structure lengths and checksum */
816 device->length = current - (uintptr_t)device;
817 header->length = current - (uintptr_t)dbg2;
818 header->checksum = acpi_checksum((uint8_t *)dbg2, header->length);
819}
820
Arthur Heymans736d4d22023-06-30 15:37:38 +0200821static unsigned long acpi_write_dbg2_uart(acpi_rsdp_t *rsdp, unsigned long current,
822 int space_id, uint64_t base, uint32_t size,
823 int access_size, const char *name)
Duncan Lauriee4a36c72017-11-11 19:33:25 -0800824{
825 acpi_dbg2_header_t *dbg2 = (acpi_dbg2_header_t *)current;
Duncan Lauriee4a36c72017-11-11 19:33:25 -0800826 acpi_addr_t address;
827
Arthur Heymans736d4d22023-06-30 15:37:38 +0200828 memset(&address, 0, sizeof(address));
829
830 address.space_id = space_id;
831 address.addrl = (uint32_t)base;
832 address.addrh = (uint32_t)((base >> 32) & 0xffffffff);
833 address.access_size = access_size;
834
835 int subtype;
836 /* 16550-compatible with parameters defined in Generic Address Structure */
837 if (CONFIG(DRIVERS_UART_8250IO) || CONFIG(DRIVERS_UART_8250MEM))
838 subtype = ACPI_DBG2_PORT_SERIAL_16550;
839 else if (CONFIG(DRIVERS_UART_PL011))
840 subtype = ACPI_DBG2_PORT_SERIAL_ARM_PL011;
841 else
842 return current;
843
844 acpi_create_dbg2(dbg2,
845 ACPI_DBG2_PORT_SERIAL,
846 subtype,
847 &address, size,
848 name);
849
850 if (dbg2->header.length) {
851 current += dbg2->header.length;
852 current = acpi_align_current(current);
853 acpi_add_table(rsdp, dbg2);
854 }
855
856 return current;
857}
858
859unsigned long acpi_write_dbg2_pci_uart(acpi_rsdp_t *rsdp, unsigned long current,
860 const struct device *dev, uint8_t access_size)
861{
862 struct resource *res;
863
Duncan Lauriee4a36c72017-11-11 19:33:25 -0800864 if (!dev) {
Wim Vervoorn6cd52432020-02-03 14:41:46 +0100865 printk(BIOS_DEBUG, "%s: Device not found\n", __func__);
Duncan Lauriee4a36c72017-11-11 19:33:25 -0800866 return current;
867 }
Mario Scheithauerf1eb0ea2017-11-21 13:52:53 +0100868 if (!dev->enabled) {
869 printk(BIOS_INFO, "%s: Device not enabled\n", __func__);
870 return current;
871 }
Angel Pons32d09be2021-11-03 13:27:45 +0100872 res = probe_resource(dev, PCI_BASE_ADDRESS_0);
Duncan Lauriee4a36c72017-11-11 19:33:25 -0800873 if (!res) {
874 printk(BIOS_ERR, "%s: Unable to find resource for %s\n",
875 __func__, dev_path(dev));
876 return current;
877 }
878
Arthur Heymans736d4d22023-06-30 15:37:38 +0200879 int space_id;
Duncan Lauriee4a36c72017-11-11 19:33:25 -0800880 if (res->flags & IORESOURCE_IO)
Arthur Heymans736d4d22023-06-30 15:37:38 +0200881 space_id = ACPI_ADDRESS_SPACE_IO;
Duncan Lauriee4a36c72017-11-11 19:33:25 -0800882 else if (res->flags & IORESOURCE_MEM)
Arthur Heymans736d4d22023-06-30 15:37:38 +0200883 space_id = ACPI_ADDRESS_SPACE_MEMORY;
Duncan Lauriee4a36c72017-11-11 19:33:25 -0800884 else {
885 printk(BIOS_ERR, "%s: Unknown address space type\n", __func__);
886 return current;
887 }
888
Arthur Heymans736d4d22023-06-30 15:37:38 +0200889 return acpi_write_dbg2_uart(rsdp, current, space_id, res->base, res->size, access_size, acpi_device_path(dev));
890}
Duncan Lauriee4a36c72017-11-11 19:33:25 -0800891
Arthur Heymans736d4d22023-06-30 15:37:38 +0200892unsigned long acpi_pl011_write_dbg2_uart(acpi_rsdp_t *rsdp, unsigned long current,
893 uint64_t base, const char *name)
894{
895 return acpi_write_dbg2_uart(rsdp, current, ACPI_ADDRESS_SPACE_MEMORY, base,
896 sizeof(struct pl011_uart), ACPI_ACCESS_SIZE_DWORD_ACCESS,
897 name);
Duncan Lauriee4a36c72017-11-11 19:33:25 -0800898}
899
Zheng Bao3ea3fbe2023-11-20 14:17:25 +0800900unsigned long acpi_16550_mmio32_write_dbg2_uart(acpi_rsdp_t *rsdp, unsigned long current,
901 uint64_t base, const char *name)
902{
903 return acpi_write_dbg2_uart(rsdp, current, ACPI_ADDRESS_SPACE_MEMORY, base,
904 0x100, ACPI_ACCESS_SIZE_DWORD_ACCESS,
905 name);
906}
907
Arthur Heymans01af0f82023-06-27 11:58:04 +0200908static void acpi_create_facs(void *header)
Ronald G. Minnich02fa3b22004-10-06 17:33:54 +0000909{
Arthur Heymans01af0f82023-06-27 11:58:04 +0200910 acpi_facs_t *facs = header;
Ronald G. Minnich02fa3b22004-10-06 17:33:54 +0000911
Stefan Reinauercdfe3762009-07-21 22:15:43 +0000912 memcpy(facs->signature, "FACS", 4);
Ronald G. Minnich02fa3b22004-10-06 17:33:54 +0000913 facs->length = sizeof(acpi_facs_t);
914 facs->hardware_signature = 0;
915 facs->firmware_waking_vector = 0;
916 facs->global_lock = 0;
917 facs->flags = 0;
918 facs->x_firmware_waking_vector_l = 0;
919 facs->x_firmware_waking_vector_h = 0;
Marc Jones93a51762018-08-22 18:57:24 -0600920 facs->version = get_acpi_table_revision(FACS);
Ronald G. Minnich02fa3b22004-10-06 17:33:54 +0000921}
Stefan Reinauer777224c2005-01-19 14:06:41 +0000922
Vladimir Serbinenko351fefc2014-10-26 20:42:08 +0100923static void acpi_write_rsdt(acpi_rsdt_t *rsdt, char *oem_id, char *oem_table_id)
Stefan Reinauer14e22772010-04-27 06:56:47 +0000924{
Uwe Hermann622824c2010-11-19 15:14:42 +0000925 acpi_header_t *header = &(rsdt->header);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000926
Arthur Heymansadb80072023-06-28 09:56:00 +0200927 if (acpi_fill_header(header, "RSDT", RSDT, sizeof(acpi_rsdt_t)) != CB_SUCCESS)
John Zhao2ba303e2019-05-28 16:48:14 -0700928 return;
929
Uwe Hermann622824c2010-11-19 15:14:42 +0000930 /* Entries are filled in later, we come with an empty set. */
Stefan Reinauer688b3852004-01-28 16:56:14 +0000931
Uwe Hermann622824c2010-11-19 15:14:42 +0000932 /* Fix checksum. */
Stefan Reinauerb657a3c2009-07-21 21:38:33 +0000933 header->checksum = acpi_checksum((void *)rsdt, sizeof(acpi_rsdt_t));
Stefan Reinauer688b3852004-01-28 16:56:14 +0000934}
935
Vladimir Serbinenko351fefc2014-10-26 20:42:08 +0100936static void acpi_write_xsdt(acpi_xsdt_t *xsdt, char *oem_id, char *oem_table_id)
Stefan Reinauer14e22772010-04-27 06:56:47 +0000937{
Uwe Hermann622824c2010-11-19 15:14:42 +0000938 acpi_header_t *header = &(xsdt->header);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000939
Arthur Heymansadb80072023-06-28 09:56:00 +0200940 if (acpi_fill_header(header, "XSDT", XSDT, sizeof(acpi_xsdt_t)) != CB_SUCCESS)
John Zhao2ba303e2019-05-28 16:48:14 -0700941 return;
942
Uwe Hermann622824c2010-11-19 15:14:42 +0000943 /* Entries are filled in later, we come with an empty set. */
Stefan Reinauerb657a3c2009-07-21 21:38:33 +0000944
Uwe Hermann622824c2010-11-19 15:14:42 +0000945 /* Fix checksum. */
Stefan Reinauerb657a3c2009-07-21 21:38:33 +0000946 header->checksum = acpi_checksum((void *)xsdt, sizeof(acpi_xsdt_t));
947}
948
Vladimir Serbinenko351fefc2014-10-26 20:42:08 +0100949static void acpi_write_rsdp(acpi_rsdp_t *rsdp, acpi_rsdt_t *rsdt,
950 acpi_xsdt_t *xsdt, char *oem_id)
Stefan Reinauer688b3852004-01-28 16:56:14 +0000951{
Stefan Reinauerd18faac2009-11-05 18:06:43 +0000952 memset(rsdp, 0, sizeof(acpi_rsdp_t));
Uwe Hermann622824c2010-11-19 15:14:42 +0000953
Stefan Reinauer688b3852004-01-28 16:56:14 +0000954 memcpy(rsdp->signature, RSDP_SIG, 8);
Vladimir Serbinenko351fefc2014-10-26 20:42:08 +0100955 memcpy(rsdp->oem_id, oem_id, 6);
Uwe Hermann622824c2010-11-19 15:14:42 +0000956
957 rsdp->length = sizeof(acpi_rsdp_t);
Stefan Reinauerdefee172015-06-18 01:11:19 -0700958 rsdp->rsdt_address = (uintptr_t)rsdt;
Uwe Hermann622824c2010-11-19 15:14:42 +0000959
960 /*
961 * Revision: ACPI 1.0: 0, ACPI 2.0/3.0/4.0: 2.
962 *
963 * Some OSes expect an XSDT to be present for RSD PTR revisions >= 2.
964 * If we don't have an ACPI XSDT, force ACPI 1.0 (and thus RSD PTR
965 * revision 0).
Stefan Reinauerb657a3c2009-07-21 21:38:33 +0000966 */
967 if (xsdt == NULL) {
Uwe Hermann622824c2010-11-19 15:14:42 +0000968 rsdp->revision = 0;
Stefan Reinauerb657a3c2009-07-21 21:38:33 +0000969 } else {
Stefan Reinauerdefee172015-06-18 01:11:19 -0700970 rsdp->xsdt_address = (u64)(uintptr_t)xsdt;
Marc Jones93a51762018-08-22 18:57:24 -0600971 rsdp->revision = get_acpi_table_revision(RSDP);
Stefan Reinauerb657a3c2009-07-21 21:38:33 +0000972 }
Uwe Hermann622824c2010-11-19 15:14:42 +0000973
974 /* Calculate checksums. */
975 rsdp->checksum = acpi_checksum((void *)rsdp, 20);
976 rsdp->ext_checksum = acpi_checksum((void *)rsdp, sizeof(acpi_rsdp_t));
Stefan Reinauer688b3852004-01-28 16:56:14 +0000977}
978
Lee Leahy6f80ccc2017-03-16 15:18:22 -0700979unsigned long acpi_create_hest_error_source(acpi_hest_t *hest,
980 acpi_hest_esd_t *esd, u16 type, void *data, u16 data_len)
zbaocaf494c82012-04-13 13:57:14 +0800981{
982 acpi_header_t *header = &(hest->header);
983 acpi_hest_hen_t *hen;
984 void *pos;
985 u16 len;
986
987 pos = esd;
988 memset(pos, 0, sizeof(acpi_hest_esd_t));
989 len = 0;
990 esd->type = type; /* MCE */
991 esd->source_id = hest->error_source_count;
992 esd->flags = 0; /* FIRMWARE_FIRST */
993 esd->enabled = 1;
994 esd->prealloc_erecords = 1;
995 esd->max_section_per_record = 0x1;
996
997 len += sizeof(acpi_hest_esd_t);
998 pos = esd + 1;
999
1000 switch (type) {
1001 case 0: /* MCE */
1002 break;
1003 case 1: /* CMC */
Elyes Haouas3141fbad2022-11-18 15:22:32 +01001004 hen = (acpi_hest_hen_t *)(pos);
zbaocaf494c82012-04-13 13:57:14 +08001005 memset(pos, 0, sizeof(acpi_hest_hen_t));
1006 hen->type = 3; /* SCI? */
1007 hen->length = sizeof(acpi_hest_hen_t);
Lee Leahy6f80ccc2017-03-16 15:18:22 -07001008 hen->conf_we = 0; /* Configuration Write Enable. */
zbaocaf494c82012-04-13 13:57:14 +08001009 hen->poll_interval = 0;
1010 hen->vector = 0;
1011 hen->sw2poll_threshold_val = 0;
1012 hen->sw2poll_threshold_win = 0;
1013 hen->error_threshold_val = 0;
1014 hen->error_threshold_win = 0;
1015 len += sizeof(acpi_hest_hen_t);
1016 pos = hen + 1;
1017 break;
1018 case 2: /* NMI */
1019 case 6: /* AER Root Port */
1020 case 7: /* AER Endpoint */
1021 case 8: /* AER Bridge */
1022 case 9: /* Generic Hardware Error Source. */
1023 /* TODO: */
1024 break;
1025 default:
1026 printk(BIOS_DEBUG, "Invalid type of Error Source.");
1027 break;
1028 }
Lee Leahy024b13d2017-03-16 13:41:11 -07001029 hest->error_source_count++;
zbaocaf494c82012-04-13 13:57:14 +08001030
1031 memcpy(pos, data, data_len);
1032 len += data_len;
John Zhao2ba303e2019-05-28 16:48:14 -07001033 if (header)
1034 header->length += len;
zbaocaf494c82012-04-13 13:57:14 +08001035
1036 return len;
1037}
1038
1039/* ACPI 4.0 */
Vladimir Serbinenko807127f2014-11-09 13:36:18 +01001040void acpi_write_hest(acpi_hest_t *hest,
1041 unsigned long (*acpi_fill_hest)(acpi_hest_t *hest))
zbaocaf494c82012-04-13 13:57:14 +08001042{
1043 acpi_header_t *header = &(hest->header);
1044
1045 memset(hest, 0, sizeof(acpi_hest_t));
1046
Arthur Heymansadb80072023-06-28 09:56:00 +02001047 if (acpi_fill_header(header, "HEST", HEST, sizeof(acpi_hest_t)) != CB_SUCCESS)
John Zhao2ba303e2019-05-28 16:48:14 -07001048 return;
1049
zbaocaf494c82012-04-13 13:57:14 +08001050 acpi_fill_hest(hest);
1051
1052 /* Calculate checksums. */
1053 header->checksum = acpi_checksum((void *)hest, header->length);
1054}
1055
Marshall Dawson1d8d3692018-09-04 13:45:26 -06001056/* ACPI 3.0b */
Arthur Heymans01af0f82023-06-27 11:58:04 +02001057static void acpi_create_bert(acpi_header_t *header, void *unused)
Marshall Dawson1d8d3692018-09-04 13:45:26 -06001058{
Arthur Heymans01af0f82023-06-27 11:58:04 +02001059 if (!CONFIG(ACPI_BERT))
1060 return;
Marshall Dawson1d8d3692018-09-04 13:45:26 -06001061
Arthur Heymans01af0f82023-06-27 11:58:04 +02001062 acpi_bert_t *bert = (acpi_bert_t *)header;
Marshall Dawson1d8d3692018-09-04 13:45:26 -06001063
Arthur Heymans01af0f82023-06-27 11:58:04 +02001064 void *region;
1065 size_t size;
1066 if (acpi_soc_get_bert_region(&region, &size) != CB_SUCCESS)
1067 return;
1068
Arthur Heymansadb80072023-06-28 09:56:00 +02001069 if (acpi_fill_header(header, "BERT", BERT, sizeof(acpi_bert_t)) != CB_SUCCESS)
1070 return;
Marshall Dawson1d8d3692018-09-04 13:45:26 -06001071
Arthur Heymans01af0f82023-06-27 11:58:04 +02001072 bert->error_region = (uintptr_t)region;
1073 bert->region_length = (size_t)size;
Marshall Dawson1d8d3692018-09-04 13:45:26 -06001074}
1075
Angel Pons79572e42020-07-13 00:17:43 +02001076__weak void arch_fill_fadt(acpi_fadt_t *fadt) { }
Kyösti Mälkkif9aac922020-05-30 16:16:28 +03001077__weak void soc_fill_fadt(acpi_fadt_t *fadt) { }
Kyösti Mälkki02fd15d2020-06-02 03:34:43 +03001078__weak void mainboard_fill_fadt(acpi_fadt_t *fadt) { }
Kyösti Mälkkif9aac922020-05-30 16:16:28 +03001079
Arthur Heymans01af0f82023-06-27 11:58:04 +02001080static acpi_header_t *dsdt;
1081static void acpi_create_fadt(acpi_header_t *header, void *arg1)
Vladimir Serbinenkoc21e0732014-10-16 12:48:19 +02001082{
Arthur Heymans01af0f82023-06-27 11:58:04 +02001083 acpi_fadt_t *fadt = (acpi_fadt_t *)header;
1084 acpi_facs_t *facs = (acpi_facs_t *)(*(acpi_facs_t **)arg1);
John Zhao2ba303e2019-05-28 16:48:14 -07001085
Arthur Heymansadb80072023-06-28 09:56:00 +02001086 if (acpi_fill_header(header, "FACP", FADT, sizeof(acpi_fadt_t)) != CB_SUCCESS)
John Zhao2ba303e2019-05-28 16:48:14 -07001087 return;
1088
Elyes Haouas532e0432022-02-21 18:13:58 +01001089 fadt->FADT_MinorVersion = get_acpi_fadt_minor_version();
Arthur Heymans8473e8f2023-06-29 20:26:39 +02001090 if ((uintptr_t)facs <= UINT32_MAX)
1091 fadt->firmware_ctrl = (uintptr_t)facs;
1092 else
1093 fadt->x_firmware_ctl_h = (uint32_t)((uint64_t)(uintptr_t)facs >> 32);
1094 fadt->x_firmware_ctl_l = (uint32_t)(uintptr_t)facs;
Kyösti Mälkkid4acee82020-06-03 07:20:55 +03001095
Arthur Heymans8473e8f2023-06-29 20:26:39 +02001096 if ((uintptr_t)dsdt <= UINT32_MAX)
1097 fadt->dsdt = (uintptr_t)dsdt;
1098 else
1099 fadt->x_dsdt_h = (uint32_t)((uint64_t)(uintptr_t)dsdt >> 32);
1100 fadt->x_dsdt_l = (uint32_t)(uintptr_t)dsdt;
Vladimir Serbinenkoc21e0732014-10-16 12:48:19 +02001101
Kyösti Mälkkid4acee82020-06-03 07:20:55 +03001102 /* should be 0 ACPI 3.0 */
1103 fadt->reserved = 0;
1104
Kyösti Mälkki67c48a32023-04-14 10:20:03 +03001105 /* P_LVLx latencies are not used as CPU _CST will override them. */
1106 fadt->p_lvl2_lat = ACPI_FADT_C2_NOT_SUPPORTED;
1107 fadt->p_lvl3_lat = ACPI_FADT_C3_NOT_SUPPORTED;
1108
Kyösti Mälkki9ff97972023-04-14 15:37:27 +03001109 /* Use CPU _PTC instead to provide P_CNT details. */
1110 fadt->duty_offset = 0;
1111 fadt->duty_width = 0;
1112
Kyösti Mälkkie0d38682020-06-07 12:01:58 +03001113 fadt->preferred_pm_profile = acpi_get_preferred_pm_profile();
Vladimir Serbinenkoc21e0732014-10-16 12:48:19 +02001114
Angel Pons79572e42020-07-13 00:17:43 +02001115 arch_fill_fadt(fadt);
1116
Vladimir Serbinenkoab83ef02014-10-25 15:18:25 +02001117 acpi_fill_fadt(fadt);
Vladimir Serbinenkoc21e0732014-10-16 12:48:19 +02001118
Kyösti Mälkkif9aac922020-05-30 16:16:28 +03001119 soc_fill_fadt(fadt);
Kyösti Mälkki02fd15d2020-06-02 03:34:43 +03001120 mainboard_fill_fadt(fadt);
Vladimir Serbinenkoc21e0732014-10-16 12:48:19 +02001121}
Vladimir Serbinenkoc21e0732014-10-16 12:48:19 +02001122
Arthur Heymans01af0f82023-06-27 11:58:04 +02001123static void acpi_create_lpit(acpi_header_t *header, void *unused)
Michael Niewöhnerf0a44ae2021-01-01 21:04:09 +01001124{
Arthur Heymans01af0f82023-06-27 11:58:04 +02001125 if (!CONFIG(ACPI_LPIT))
1126 return;
Michael Niewöhnerf0a44ae2021-01-01 21:04:09 +01001127
Arthur Heymans01af0f82023-06-27 11:58:04 +02001128 acpi_lpit_t *lpit = (acpi_lpit_t *)header;
1129 unsigned long current = (unsigned long)lpit + sizeof(acpi_lpit_t);
Michael Niewöhnerf0a44ae2021-01-01 21:04:09 +01001130
Arthur Heymansadb80072023-06-28 09:56:00 +02001131 if (acpi_fill_header(header, "LPIT", LPIT, sizeof(acpi_lpit_t)) != CB_SUCCESS)
Michael Niewöhnerf0a44ae2021-01-01 21:04:09 +01001132 return;
1133
Michael Niewöhnerf0a44ae2021-01-01 21:04:09 +01001134 current = acpi_fill_lpit(current);
1135
Arthur Heymans01af0f82023-06-27 11:58:04 +02001136 /* (Re)calculate length. */
Michael Niewöhnerf0a44ae2021-01-01 21:04:09 +01001137 header->length = current - (unsigned long)lpit;
Michael Niewöhnerf0a44ae2021-01-01 21:04:09 +01001138}
1139
Arthur Heymans2e3cb632023-06-30 15:01:08 +02001140static void acpi_create_gtdt(acpi_header_t *header, void *unused)
1141{
1142 if (!CONFIG(ACPI_GTDT))
1143 return;
1144
1145 acpi_gtdt_t *gtdt = (acpi_gtdt_t *)header;
1146 unsigned long current = (unsigned long)gtdt + sizeof(acpi_gtdt_t);
1147
1148 if (acpi_fill_header(header, "GTDT", GTDT, sizeof(acpi_gtdt_t)) != CB_SUCCESS)
1149 return;
1150
1151 /* Fill out header fields. */
1152 gtdt->platform_timer_offset = sizeof(acpi_gtdt_t);
1153
1154 acpi_soc_fill_gtdt(gtdt);
1155 current = acpi_soc_gtdt_add_timers(&gtdt->platform_timer_count, current);
1156
1157 /* (Re)calculate length. */
1158 header->length = current - (unsigned long)gtdt;
1159}
1160
1161unsigned long acpi_gtdt_add_timer_block(unsigned long current, const uint64_t address,
1162 struct acpi_gtdt_timer_entry *timers, size_t number)
1163{
1164 struct acpi_gtdt_timer_block *block = (struct acpi_gtdt_timer_block *)current;
1165 memset(block, 0, sizeof(struct acpi_gtdt_timer_block));
1166
1167 assert(number < 8 && number != 0);
1168 const size_t entries_size = number * sizeof(struct acpi_gtdt_timer_entry);
1169
1170 block->header.type = ACPI_GTDT_TYPE_TIMER_BLOCK;
1171 block->header.length = sizeof(struct acpi_gtdt_timer_block)
1172 + entries_size;
1173 block->block_address = address;
1174 block->timer_count = number;
1175 block->timer_offset = sizeof(struct acpi_gtdt_timer_block);
1176 current += sizeof(struct acpi_gtdt_timer_block);
1177 memcpy((void *)current, timers, entries_size);
1178 current += entries_size;
1179 return current;
1180}
1181
1182unsigned long acpi_gtdt_add_watchdog(unsigned long current, uint64_t refresh_frame,
1183 uint64_t control_frame, uint32_t gsiv, uint32_t flags)
1184{
1185 struct acpi_gtdt_watchdog *wd = (struct acpi_gtdt_watchdog *)current;
1186 memset(wd, 0, sizeof(struct acpi_gtdt_watchdog));
1187
1188 wd->header.type = ACPI_GTDT_TYPE_WATCHDOG;
1189 wd->header.length = sizeof(struct acpi_gtdt_watchdog);
1190 wd->refresh_frame_address = refresh_frame;
1191 wd->control_frame_address = control_frame;
1192 wd->timer_interrupt = gsiv;
1193 wd->timer_flags = flags;
1194
1195 return current + sizeof(struct acpi_gtdt_watchdog);
1196}
1197
Naresh Solanki6920c6f2023-09-13 12:01:58 +02001198static void acpi_create_iort(acpi_header_t *header, void *unused)
1199{
1200 if (!CONFIG(ACPI_IORT))
1201 return;
1202
1203 acpi_iort_t *iort = (acpi_iort_t *)header;
1204 unsigned long current = (unsigned long)iort + sizeof(acpi_iort_t);
1205
1206 if (acpi_fill_header(header, "IORT", IORT, sizeof(acpi_iort_t)) != CB_SUCCESS)
1207 return;
1208
1209 iort->node_count = 0;
1210 iort->node_offset = current - (unsigned long)iort;
1211
1212 current = acpi_soc_fill_iort(iort, current);
1213
1214 /* (Re)calculate length */
1215 header->length = current - (unsigned long)iort;
1216}
1217
Michael Niewöhnerf0a44ae2021-01-01 21:04:09 +01001218unsigned long acpi_create_lpi_desc_ncst(acpi_lpi_desc_ncst_t *lpi_desc, uint16_t uid)
1219{
1220 memset(lpi_desc, 0, sizeof(acpi_lpi_desc_ncst_t));
1221 lpi_desc->header.length = sizeof(acpi_lpi_desc_ncst_t);
1222 lpi_desc->header.type = ACPI_LPI_DESC_TYPE_NATIVE_CSTATE;
1223 lpi_desc->header.uid = uid;
1224
1225 return lpi_desc->header.length;
1226}
1227
David Milosevicd9822742023-09-22 14:34:28 +02001228static void acpi_create_pptt(acpi_header_t *header, void *unused)
1229{
1230 if (!CONFIG(ACPI_PPTT))
1231 return;
1232
1233 if (acpi_fill_header(header, "PPTT", PPTT, sizeof(acpi_pptt_t)) != CB_SUCCESS)
1234 return;
1235
1236 acpi_pptt_t *pptt = (acpi_pptt_t *)header;
1237 acpi_create_pptt_body(pptt);
1238}
1239
Arthur Heymans90464072023-06-07 12:53:50 +02001240static uint8_t acpi_spcr_type(void)
1241{
1242 /* 16550-compatible with parameters defined in Generic Address Structure */
1243 if (CONFIG(DRIVERS_UART_8250IO) || CONFIG(DRIVERS_UART_8250MEM))
1244 return 0x12;
1245 if (CONFIG(DRIVERS_UART_PL011))
1246 return 0x3;
1247
1248 printk(BIOS_ERR, "%s: unknown serial type\n", __func__);
1249 return 0xff;
1250}
1251
Arthur Heymans01af0f82023-06-27 11:58:04 +02001252static void acpi_create_spcr(acpi_header_t *header, void *unused)
Arthur Heymans90464072023-06-07 12:53:50 +02001253{
Arthur Heymans01af0f82023-06-27 11:58:04 +02001254 acpi_spcr_t *spcr = (acpi_spcr_t *)header;
Arthur Heymans90464072023-06-07 12:53:50 +02001255 struct lb_serial serial;
1256
Arthur Heymans90464072023-06-07 12:53:50 +02001257 if (!CONFIG(CONSOLE_SERIAL))
1258 return;
1259
1260 if (fill_lb_serial(&serial) != CB_SUCCESS)
1261 return;
1262
Arthur Heymansadb80072023-06-28 09:56:00 +02001263 if (acpi_fill_header(header, "SPCR", SPCR, sizeof(acpi_spcr_t)) != CB_SUCCESS)
1264 return;
Arthur Heymans90464072023-06-07 12:53:50 +02001265
1266 spcr->interface_type = acpi_spcr_type();
1267 assert(serial.type == LB_SERIAL_TYPE_IO_MAPPED
1268 || serial.type == LB_SERIAL_TYPE_MEMORY_MAPPED);
1269 spcr->base_address.space_id = serial.type == LB_SERIAL_TYPE_IO_MAPPED ?
1270 ACPI_ADDRESS_SPACE_IO : ACPI_ADDRESS_SPACE_MEMORY;
1271 spcr->base_address.bit_width = serial.regwidth * 8;
1272 spcr->base_address.bit_offset = 0;
1273 switch (serial.regwidth) {
1274 case 1:
1275 spcr->base_address.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
1276 break;
1277 case 2:
1278 spcr->base_address.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
1279 break;
1280 case 4:
1281 spcr->base_address.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
1282 break;
1283 default:
1284 printk(BIOS_ERR, "%s, Invalid serial regwidth\n", __func__);
1285 }
1286
1287 spcr->base_address.addrl = serial.baseaddr;
1288 spcr->base_address.addrh = 0;
1289 spcr->interrupt_type = 0;
1290 spcr->irq = 0;
1291 spcr->configured_baudrate = 0; /* Have the OS use whatever is currently set */
1292 spcr->parity = 0;
1293 spcr->stop_bits = 1;
1294 spcr->flow_control = 0;
1295 spcr->terminal_type = 2; /* 2 = VT-UTF8 */
1296 spcr->language = 0;
1297 spcr->pci_did = 0xffff;
1298 spcr->pci_vid = 0xffff;
Nico Huberfeb27dc2023-06-28 20:09:30 +02001299
1300 header->checksum = acpi_checksum((void *)spcr, header->length);
Arthur Heymans90464072023-06-07 12:53:50 +02001301}
1302
Aaron Durbin64031672018-04-21 14:45:32 -06001303unsigned long __weak fw_cfg_acpi_tables(unsigned long start)
Vladimir Serbinenko41877d82014-09-01 22:18:01 +02001304{
1305 return 0;
1306}
1307
Raul E Rangel6b446b92021-11-19 11:38:35 -07001308void preload_acpi_dsdt(void)
1309{
1310 const char *file = CONFIG_CBFS_PREFIX "/dsdt.aml";
1311
1312 if (!CONFIG(CBFS_PRELOAD))
1313 return;
1314
1315 printk(BIOS_DEBUG, "Preloading %s\n", file);
1316 cbfs_preload(file);
1317}
1318
Arthur Heymans01af0f82023-06-27 11:58:04 +02001319static void acpi_create_dsdt(acpi_header_t *header, void *dsdt_file_arg)
1320{
1321 dsdt = header;
1322 acpi_header_t *dsdt_file = *(acpi_header_t **)dsdt_file_arg;
1323 unsigned long current = (unsigned long)header;
1324
1325 dsdt = (acpi_header_t *)current;
1326 memcpy(dsdt, dsdt_file, sizeof(acpi_header_t));
1327 if (dsdt->length >= sizeof(acpi_header_t)) {
1328 current += sizeof(acpi_header_t);
1329
1330 acpigen_set_current((char *)current);
1331
1332 if (CONFIG(ACPI_SOC_NVS))
1333 acpi_fill_gnvs();
1334 if (CONFIG(CHROMEOS_NVS))
1335 acpi_fill_cnvs();
1336
1337 for (const struct device *dev = all_devices; dev; dev = dev->next)
1338 if (dev->ops && dev->ops->acpi_inject_dsdt)
1339 dev->ops->acpi_inject_dsdt(dev);
1340 current = (unsigned long)acpigen_get_current();
1341 memcpy((char *)current,
1342 (char *)dsdt_file + sizeof(acpi_header_t),
1343 dsdt->length - sizeof(acpi_header_t));
1344 current += dsdt->length - sizeof(acpi_header_t);
1345
1346 /* (Re)calculate length. */
1347 dsdt->length = current - (unsigned long)dsdt;
1348 }
1349}
1350
1351static void acpi_create_slic(acpi_header_t *header, void *slic_file_arg)
1352{
1353 acpi_header_t *slic_file = *(acpi_header_t **)slic_file_arg;
1354 acpi_header_t *slic = header;
1355 if (slic_file)
1356 memcpy(slic, slic_file, slic_file->length);
1357}
1358
Arthur Heymans2e7e2d92022-03-03 22:28:27 +01001359static uintptr_t coreboot_rsdp;
1360
1361uintptr_t get_coreboot_rsdp(void)
1362{
1363 return coreboot_rsdp;
1364}
1365
Arthur Heymans0ad766c2023-06-07 10:45:59 +02001366static void acpixtract_compatible_hexdump(const void *memory, size_t length)
1367{
1368 size_t i, j;
1369 uint8_t *line;
1370 size_t num_bytes;
1371
1372 for (i = 0; i < length; i += 16) {
1373 num_bytes = MIN(length - i, 16);
1374 line = ((uint8_t *)memory) + i;
1375
1376 printk(BIOS_SPEW, " %04zX:", i);
1377 for (j = 0; j < num_bytes; j++)
1378 printk(BIOS_SPEW, " %02x", line[j]);
1379 for (; j < 16; j++)
1380 printk(BIOS_SPEW, " ");
1381 printk(BIOS_SPEW, " ");
1382 for (j = 0; j < num_bytes; j++)
1383 printk(BIOS_SPEW, "%c",
1384 isprint(line[j]) ? line[j] : '.');
1385 printk(BIOS_SPEW, "\n");
1386 }
1387}
1388
1389static void acpidump_print(void *table_ptr)
1390{
Felix Held67b3c8f2023-08-03 01:08:14 +02001391 if (table_ptr == NULL)
1392 return;
Arthur Heymans0ad766c2023-06-07 10:45:59 +02001393 const acpi_header_t *header = (acpi_header_t *)table_ptr;
1394 const size_t table_size = header->length;
1395 printk(BIOS_SPEW, "%.4s @ 0x0000000000000000\n", header->signature);
1396 acpixtract_compatible_hexdump(table_ptr, table_size);
1397 printk(BIOS_SPEW, "\n");
1398}
1399
Arthur Heymans7ebebf72023-06-17 14:08:46 +02001400unsigned long write_acpi_tables(const unsigned long start)
Vladimir Serbinenko2d7bd8a2014-08-30 19:28:05 +02001401{
1402 unsigned long current;
1403 acpi_rsdp_t *rsdp;
Arthur Heymans0ad766c2023-06-07 10:45:59 +02001404 acpi_rsdt_t *rsdt = NULL;
1405 acpi_xsdt_t *xsdt = NULL;
Arthur Heymans0ad766c2023-06-07 10:45:59 +02001406 acpi_facs_t *facs = NULL;
Arthur Heymans01af0f82023-06-27 11:58:04 +02001407 acpi_header_t *slic_file;
Arthur Heymans0ad766c2023-06-07 10:45:59 +02001408 acpi_header_t *ssdt = NULL;
Arthur Heymans01af0f82023-06-27 11:58:04 +02001409 acpi_header_t *dsdt_file;
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +11001410 struct device *dev;
Vladimir Serbinenko41877d82014-09-01 22:18:01 +02001411 unsigned long fw;
Vladimir Serbinenko36f8d272015-05-31 12:31:59 +02001412 size_t slic_size, dsdt_size;
Vladimir Serbinenko351fefc2014-10-26 20:42:08 +01001413 char oem_id[6], oem_table_id[8];
Vladimir Serbinenko2d7bd8a2014-08-30 19:28:05 +02001414
Arthur Heymans01af0f82023-06-27 11:58:04 +02001415 const struct acpi_table_generator {
1416 void (*create_table)(acpi_header_t *table, void *arg);
1417 void *args;
1418 size_t min_size;
1419 } tables[] = {
1420 { acpi_create_dsdt, &dsdt_file, sizeof(acpi_header_t) },
1421 { acpi_create_fadt, &facs, sizeof(acpi_fadt_t) },
1422 { acpi_create_slic, &slic_file, sizeof(acpi_header_t) },
1423 { acpi_create_ssdt_generator, NULL, sizeof(acpi_header_t) },
1424 { acpi_create_mcfg, NULL, sizeof(acpi_mcfg_t) },
1425 { acpi_create_tcpa, NULL, sizeof(acpi_tcpa_t) },
1426 { acpi_create_tpm2, NULL, sizeof(acpi_tpm2_t) },
1427 { acpi_create_lpit, NULL, sizeof(acpi_lpit_t) },
1428 { acpi_create_madt, NULL, sizeof(acpi_header_t) },
1429 { acpi_create_bert, NULL, sizeof(acpi_bert_t) },
1430 { acpi_create_spcr, NULL, sizeof(acpi_spcr_t) },
Arthur Heymans2e3cb632023-06-30 15:01:08 +02001431 { acpi_create_gtdt, NULL, sizeof(acpi_gtdt_t) },
David Milosevicd9822742023-09-22 14:34:28 +02001432 { acpi_create_pptt, NULL, sizeof(acpi_pptt_t) },
Naresh Solanki6920c6f2023-09-13 12:01:58 +02001433 { acpi_create_iort, NULL, sizeof(acpi_iort_t) },
Arthur Heymans01af0f82023-06-27 11:58:04 +02001434 };
1435
Vladimir Serbinenko2d7bd8a2014-08-30 19:28:05 +02001436 current = start;
1437
1438 /* Align ACPI tables to 16byte */
Aaron Durbin07a1b282015-12-10 17:07:38 -06001439 current = acpi_align_current(current);
Vladimir Serbinenko2d7bd8a2014-08-30 19:28:05 +02001440
Patrick Rudolphcfe08ff2019-09-10 15:40:47 +02001441 /* Special case for qemu */
Vladimir Serbinenko41877d82014-09-01 22:18:01 +02001442 fw = fw_cfg_acpi_tables(current);
Patrick Rudolphcfe08ff2019-09-10 15:40:47 +02001443 if (fw) {
1444 rsdp = NULL;
1445 /* Find RSDP. */
1446 for (void *p = (void *)current; p < (void *)fw; p += 16) {
1447 if (valid_rsdp((acpi_rsdp_t *)p)) {
1448 rsdp = p;
Bin Mengf3027b82023-05-09 15:21:49 +08001449 coreboot_rsdp = (uintptr_t)rsdp;
Patrick Rudolphcfe08ff2019-09-10 15:40:47 +02001450 break;
1451 }
1452 }
1453 if (!rsdp)
1454 return fw;
1455
Arthur Heymansc2830c92023-08-22 12:50:43 +02001456 current = fw;
1457 current = acpi_align_current(current);
1458 if (rsdp->xsdt_address == 0) {
1459 xsdt = (acpi_xsdt_t *)current;
1460 current += sizeof(acpi_xsdt_t);
1461 current = acpi_align_current(current);
1462
1463 /*
1464 * Qemu only creates an RSDT.
1465 * Add an XSDT based on the existing RSDT entries.
1466 */
1467 acpi_rsdt_t *existing_rsdt = (acpi_rsdt_t *)(uintptr_t)rsdp->rsdt_address;
1468 acpi_write_rsdp(rsdp, existing_rsdt, xsdt, oem_id);
1469 acpi_write_xsdt(xsdt, oem_id, oem_table_id);
1470 /*
1471 * Copy existing entries to the new XSDT. This will override existing
1472 * RSDT entries with the same value.
1473 */
1474 for (int i = 0; existing_rsdt->entry[i]; i++)
1475 acpi_add_table(rsdp, (void *)(uintptr_t)existing_rsdt->entry[i]);
1476
1477 }
1478
Patrick Rudolphcfe08ff2019-09-10 15:40:47 +02001479 /* Add BOOT0000 for Linux google firmware driver */
1480 printk(BIOS_DEBUG, "ACPI: * SSDT\n");
Arthur Heymansc2830c92023-08-22 12:50:43 +02001481 ssdt = (acpi_header_t *)current;
1482 current += sizeof(acpi_header_t);
Patrick Rudolphcfe08ff2019-09-10 15:40:47 +02001483
1484 memset((void *)ssdt, 0, sizeof(acpi_header_t));
1485
1486 memcpy(&ssdt->signature, "SSDT", 4);
1487 ssdt->revision = get_acpi_table_revision(SSDT);
1488 memcpy(&ssdt->oem_id, OEM_ID, 6);
1489 memcpy(&ssdt->oem_table_id, oem_table_id, 8);
1490 ssdt->oem_revision = 42;
1491 memcpy(&ssdt->asl_compiler_id, ASLC, 4);
1492 ssdt->asl_compiler_revision = asl_revision;
1493 ssdt->length = sizeof(acpi_header_t);
1494
Elyes Haouas3141fbad2022-11-18 15:22:32 +01001495 acpigen_set_current((char *)current);
Patrick Rudolphcfe08ff2019-09-10 15:40:47 +02001496
1497 /* Write object to declare coreboot tables */
1498 acpi_ssdt_write_cbtable();
1499
1500 /* (Re)calculate length and checksum. */
1501 ssdt->length = current - (unsigned long)ssdt;
1502 ssdt->checksum = acpi_checksum((void *)ssdt, ssdt->length);
1503
Arthur Heymans01af0f82023-06-27 11:58:04 +02001504 acpi_create_ssdt_generator(ssdt, NULL);
Patrick Rudolphcfe08ff2019-09-10 15:40:47 +02001505
1506 acpi_add_table(rsdp, ssdt);
1507
Vladimir Serbinenko41877d82014-09-01 22:18:01 +02001508 return fw;
Patrick Rudolphcfe08ff2019-09-10 15:40:47 +02001509 }
Vladimir Serbinenko41877d82014-09-01 22:18:01 +02001510
Julius Werner834b3ec2020-03-04 16:52:08 -08001511 dsdt_file = cbfs_map(CONFIG_CBFS_PREFIX "/dsdt.aml", &dsdt_size);
Vladimir Serbinenko36f8d272015-05-31 12:31:59 +02001512 if (!dsdt_file) {
1513 printk(BIOS_ERR, "No DSDT file, skipping ACPI tables\n");
Arthur Heymans0600aa62023-06-17 14:13:54 +02001514 return start;
Vladimir Serbinenko36f8d272015-05-31 12:31:59 +02001515 }
1516
1517 if (dsdt_file->length > dsdt_size
Elyes HAOUAS7d87e762016-10-03 22:11:07 +02001518 || dsdt_file->length < sizeof(acpi_header_t)
Vladimir Serbinenko36f8d272015-05-31 12:31:59 +02001519 || memcmp(dsdt_file->signature, "DSDT", 4) != 0) {
1520 printk(BIOS_ERR, "Invalid DSDT file, skipping ACPI tables\n");
Grzegorz Bernacki042ac352023-04-21 13:19:58 +00001521 cbfs_unmap(dsdt_file);
Arthur Heymans0600aa62023-06-17 14:13:54 +02001522 return start;
Vladimir Serbinenko36f8d272015-05-31 12:31:59 +02001523 }
1524
Julius Werner834b3ec2020-03-04 16:52:08 -08001525 slic_file = cbfs_map(CONFIG_CBFS_PREFIX "/slic", &slic_size);
Vladimir Serbinenko2cb29782015-05-31 11:32:09 +02001526 if (slic_file
1527 && (slic_file->length > slic_size
Elyes HAOUAS7d87e762016-10-03 22:11:07 +02001528 || slic_file->length < sizeof(acpi_header_t)
Benjamin Doron2b2dc0c2020-09-12 02:55:57 +00001529 || (memcmp(slic_file->signature, "SLIC", 4) != 0
1530 && memcmp(slic_file->signature, "MSDM", 4) != 0))) {
Grzegorz Bernacki042ac352023-04-21 13:19:58 +00001531 cbfs_unmap(slic_file);
Vladimir Serbinenko351fefc2014-10-26 20:42:08 +01001532 slic_file = 0;
1533 }
1534
1535 if (slic_file) {
1536 memcpy(oem_id, slic_file->oem_id, 6);
1537 memcpy(oem_table_id, slic_file->oem_table_id, 8);
1538 } else {
1539 memcpy(oem_id, OEM_ID, 6);
1540 memcpy(oem_table_id, ACPI_TABLE_CREATOR, 8);
1541 }
1542
Vladimir Serbinenko2d7bd8a2014-08-30 19:28:05 +02001543 printk(BIOS_INFO, "ACPI: Writing ACPI tables at %lx.\n", start);
1544
Arthur Heymansd8f2dce2023-06-22 13:42:36 +02001545 /* We need at least an RSDP, RSDT for ACPI 1.0 compat, otherwise XSDT */
Elyes Haouas3141fbad2022-11-18 15:22:32 +01001546 rsdp = (acpi_rsdp_t *)current;
Arthur Heymans2e7e2d92022-03-03 22:28:27 +01001547 coreboot_rsdp = (uintptr_t)rsdp;
Vladimir Serbinenko2d7bd8a2014-08-30 19:28:05 +02001548 current += sizeof(acpi_rsdp_t);
Aaron Durbin07a1b282015-12-10 17:07:38 -06001549 current = acpi_align_current(current);
Arthur Heymansd8f2dce2023-06-22 13:42:36 +02001550 if (current + sizeof(acpi_rsdt_t) - 1 <= UINT32_MAX) {
1551 rsdt = (acpi_rsdt_t *)current;
1552 current += sizeof(acpi_rsdt_t);
1553 current = acpi_align_current(current);
1554 } else {
1555 printk(BIOS_INFO, "Not adding RSDT because tables reside above 4G.");
1556 }
1557
Elyes Haouas3141fbad2022-11-18 15:22:32 +01001558 xsdt = (acpi_xsdt_t *)current;
Vladimir Serbinenko2d7bd8a2014-08-30 19:28:05 +02001559 current += sizeof(acpi_xsdt_t);
Aaron Durbin07a1b282015-12-10 17:07:38 -06001560 current = acpi_align_current(current);
Vladimir Serbinenko2d7bd8a2014-08-30 19:28:05 +02001561
1562 /* clear all table memory */
Elyes Haouas3141fbad2022-11-18 15:22:32 +01001563 memset((void *)start, 0, current - start);
Vladimir Serbinenko2d7bd8a2014-08-30 19:28:05 +02001564
Vladimir Serbinenko351fefc2014-10-26 20:42:08 +01001565 acpi_write_rsdp(rsdp, rsdt, xsdt, oem_id);
1566 acpi_write_rsdt(rsdt, oem_id, oem_table_id);
1567 acpi_write_xsdt(xsdt, oem_id, oem_table_id);
Vladimir Serbinenko2d7bd8a2014-08-30 19:28:05 +02001568
Arthur Heymans6af72612023-06-29 20:25:32 +02001569 if (ENV_X86) {
1570 printk(BIOS_DEBUG, "ACPI: * FACS\n");
1571 current = ALIGN_UP(current, 64);
1572 facs = (acpi_facs_t *)current;
1573 current += sizeof(acpi_facs_t);
1574 current = acpi_align_current(current);
1575 acpi_create_facs(facs);
1576 }
Vladimir Serbinenko2d7bd8a2014-08-30 19:28:05 +02001577
Arthur Heymans01af0f82023-06-27 11:58:04 +02001578 for (size_t i = 0; i < ARRAY_SIZE(tables); i++) {
1579 acpi_header_t *header = (acpi_header_t *)current;
1580 memset(header, 0, tables[i].min_size);
1581 tables[i].create_table(header, tables[i].args);
1582 if (header->length < tables[i].min_size)
1583 continue;
1584 header->checksum = 0;
1585 header->checksum = acpi_checksum((void *)header, header->length);
1586 current += header->length;
Aaron Durbin07a1b282015-12-10 17:07:38 -06001587 current = acpi_align_current(current);
Kyösti Mälkki0bcdd402023-07-06 14:47:07 +03001588
1589 if (tables[i].create_table == acpi_create_dsdt)
1590 continue;
1591
Arthur Heymans01af0f82023-06-27 11:58:04 +02001592 printk(BIOS_DEBUG, "ACPI: * %.4s\n", header->signature);
1593 acpi_add_table(rsdp, header);
Vladimir Serbinenko351fefc2014-10-26 20:42:08 +01001594 }
Vladimir Serbinenko2d7bd8a2014-08-30 19:28:05 +02001595
Grzegorz Bernacki042ac352023-04-21 13:19:58 +00001596 /*
1597 * cbfs_unmap() uses mem_pool_free() which works correctly only
1598 * if freeing is done in reverse order than memory allocation.
1599 * This is why unmapping of dsdt_file must be done after
1600 * unmapping slic file.
1601 */
Arthur Heymans01af0f82023-06-27 11:58:04 +02001602 cbfs_unmap(slic_file);
Grzegorz Bernacki042ac352023-04-21 13:19:58 +00001603 cbfs_unmap(dsdt_file);
1604
Vladimir Serbinenko2d7bd8a2014-08-30 19:28:05 +02001605 printk(BIOS_DEBUG, "current = %lx\n", current);
1606
1607 for (dev = all_devices; dev; dev = dev->next) {
1608 if (dev->ops && dev->ops->write_acpi_tables) {
Lee Leahy6f80ccc2017-03-16 15:18:22 -07001609 current = dev->ops->write_acpi_tables(dev, current,
1610 rsdp);
Aaron Durbin07a1b282015-12-10 17:07:38 -06001611 current = acpi_align_current(current);
Vladimir Serbinenko2d7bd8a2014-08-30 19:28:05 +02001612 }
1613 }
1614
1615 printk(BIOS_INFO, "ACPI: done.\n");
Arthur Heymans0ad766c2023-06-07 10:45:59 +02001616
1617 if (CONFIG(DEBUG_ACPICA_COMPATIBLE)) {
1618 printk(BIOS_DEBUG, "Printing ACPI tables in ACPICA compatible format\n");
Arthur Heymans1cdeaea2023-07-06 16:24:50 +02001619 if (facs)
1620 acpidump_print(facs);
1621 acpidump_print(dsdt);
Arthur Heymans3e523b42023-06-15 17:04:16 +02001622 for (size_t i = 0; xsdt->entry[i] != 0; i++) {
1623 acpidump_print((void *)(uintptr_t)xsdt->entry[i]);
Arthur Heymans0ad766c2023-06-07 10:45:59 +02001624 }
1625 printk(BIOS_DEBUG, "Done printing ACPI tables in ACPICA compatible format\n");
1626 }
1627
Vladimir Serbinenko2d7bd8a2014-08-30 19:28:05 +02001628 return current;
1629}
Vladimir Serbinenko2d7bd8a2014-08-30 19:28:05 +02001630
Rudolf Marek33cafe52009-04-13 18:07:02 +00001631static acpi_rsdp_t *valid_rsdp(acpi_rsdp_t *rsdp)
1632{
1633 if (strncmp((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0)
1634 return NULL;
1635
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001636 printk(BIOS_DEBUG, "Looking on %p for valid checksum\n", rsdp);
Rudolf Marek33cafe52009-04-13 18:07:02 +00001637
1638 if (acpi_checksum((void *)rsdp, 20) != 0)
1639 return NULL;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001640 printk(BIOS_DEBUG, "Checksum 1 passed\n");
Rudolf Marek33cafe52009-04-13 18:07:02 +00001641
1642 if ((rsdp->revision > 1) && (acpi_checksum((void *)rsdp,
1643 rsdp->length) != 0))
1644 return NULL;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001645 printk(BIOS_DEBUG, "Checksum 2 passed all OK\n");
Rudolf Marek33cafe52009-04-13 18:07:02 +00001646
1647 return rsdp;
1648}
1649
Rudolf Marek33cafe52009-04-13 18:07:02 +00001650void *acpi_find_wakeup_vector(void)
1651{
1652 char *p, *end;
Arthur Heymansd8f2dce2023-06-22 13:42:36 +02001653 acpi_xsdt_t *xsdt;
Rudolf Marek33cafe52009-04-13 18:07:02 +00001654 acpi_facs_t *facs;
Martin Rothc5f49262012-12-14 19:17:55 -07001655 acpi_fadt_t *fadt = NULL;
Kyösti Mälkki072d436b2016-06-17 08:44:40 +03001656 acpi_rsdp_t *rsdp = NULL;
Uwe Hermann622824c2010-11-19 15:14:42 +00001657 void *wake_vec;
Rudolf Marek33cafe52009-04-13 18:07:02 +00001658 int i;
1659
Kyösti Mälkkib8c7ea02020-11-17 16:41:38 +02001660 if (!acpi_is_wakeup_s3())
Rudolf Marek33cafe52009-04-13 18:07:02 +00001661 return NULL;
1662
Uwe Hermann622824c2010-11-19 15:14:42 +00001663 printk(BIOS_DEBUG, "Trying to find the wakeup vector...\n");
Rudolf Marek33cafe52009-04-13 18:07:02 +00001664
Uwe Hermann622824c2010-11-19 15:14:42 +00001665 /* Find RSDP. */
1666 for (p = (char *)0xe0000; p < (char *)0xfffff; p += 16) {
Lee Leahy0b5678f2017-03-16 16:01:40 -07001667 rsdp = valid_rsdp((acpi_rsdp_t *)p);
1668 if (rsdp)
Rudolf Marek33cafe52009-04-13 18:07:02 +00001669 break;
1670 }
1671
Angel Pons98a68ad2018-11-04 12:25:25 +01001672 if (rsdp == NULL) {
1673 printk(BIOS_ALERT,
1674 "No RSDP found, wake up from S3 not possible.\n");
Rudolf Marek33cafe52009-04-13 18:07:02 +00001675 return NULL;
Angel Pons98a68ad2018-11-04 12:25:25 +01001676 }
Rudolf Marek33cafe52009-04-13 18:07:02 +00001677
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001678 printk(BIOS_DEBUG, "RSDP found at %p\n", rsdp);
Arthur Heymansd8f2dce2023-06-22 13:42:36 +02001679 xsdt = (acpi_xsdt_t *)(uintptr_t)rsdp->xsdt_address;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001680
Arthur Heymansd8f2dce2023-06-22 13:42:36 +02001681 end = (char *)xsdt + xsdt->header.length;
1682 printk(BIOS_DEBUG, "XSDT found at %p ends at %p\n", xsdt, end);
Rudolf Marek33cafe52009-04-13 18:07:02 +00001683
Arthur Heymansd8f2dce2023-06-22 13:42:36 +02001684 for (i = 0; ((char *)&xsdt->entry[i]) < end; i++) {
1685 fadt = (acpi_fadt_t *)(uintptr_t)xsdt->entry[i];
Stefan Reinauercdfe3762009-07-21 22:15:43 +00001686 if (strncmp((char *)fadt, "FACP", 4) == 0)
Rudolf Marek33cafe52009-04-13 18:07:02 +00001687 break;
1688 fadt = NULL;
1689 }
1690
Angel Pons98a68ad2018-11-04 12:25:25 +01001691 if (fadt == NULL) {
1692 printk(BIOS_ALERT,
1693 "No FADT found, wake up from S3 not possible.\n");
Rudolf Marek33cafe52009-04-13 18:07:02 +00001694 return NULL;
Angel Pons98a68ad2018-11-04 12:25:25 +01001695 }
Rudolf Marek33cafe52009-04-13 18:07:02 +00001696
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001697 printk(BIOS_DEBUG, "FADT found at %p\n", fadt);
Arthur Heymansa07b09a2023-07-05 12:53:10 +02001698 facs = (acpi_facs_t *)(uintptr_t)((uint64_t)fadt->x_firmware_ctl_l
1699 | (uint64_t)fadt->x_firmware_ctl_h << 32);
Rudolf Marek33cafe52009-04-13 18:07:02 +00001700
Stefan Reinauer7e9771c2009-04-22 08:17:38 +00001701 if (facs == NULL) {
Angel Pons98a68ad2018-11-04 12:25:25 +01001702 printk(BIOS_ALERT,
1703 "No FACS found, wake up from S3 not possible.\n");
Rudolf Marek33cafe52009-04-13 18:07:02 +00001704 return NULL;
Stefan Reinauer7e9771c2009-04-22 08:17:38 +00001705 }
Rudolf Marek33cafe52009-04-13 18:07:02 +00001706
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001707 printk(BIOS_DEBUG, "FACS found at %p\n", facs);
Stefan Reinauer71a30182015-07-30 16:28:13 -07001708 wake_vec = (void *)(uintptr_t)facs->firmware_waking_vector;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001709 printk(BIOS_DEBUG, "OS waking vector is %p\n", wake_vec);
Uwe Hermann622824c2010-11-19 15:14:42 +00001710
Rudolf Marek33cafe52009-04-13 18:07:02 +00001711 return wake_vec;
1712}
1713
Aaron Durbin64031672018-04-21 14:45:32 -06001714__weak int acpi_get_gpe(int gpe)
Duncan Laurie1f6e6812016-09-19 12:04:19 -07001715{
1716 return -1; /* implemented by SOC */
1717}
Marc Jones93a51762018-08-22 18:57:24 -06001718
Elyes Haouas8b950f42022-02-16 12:08:16 +01001719u8 get_acpi_fadt_minor_version(void)
1720{
1721 return ACPI_FADT_MINOR_VERSION_0;
1722}
1723
Marc Jones93a51762018-08-22 18:57:24 -06001724int get_acpi_table_revision(enum acpi_tables table)
1725{
1726 switch (table) {
1727 case FADT:
Elyes Haouas8b950f42022-02-16 12:08:16 +01001728 return ACPI_FADT_REV_ACPI_6;
Elyes HAOUASf288b392018-11-11 15:22:30 +01001729 case MADT: /* ACPI 3.0: 2, ACPI 4.0/5.0: 3, ACPI 6.2b/6.3: 5 */
Patrick Rudolph56a3ef22020-03-24 17:29:49 +01001730 return 3;
Marc Jones93a51762018-08-22 18:57:24 -06001731 case MCFG:
1732 return 1;
1733 case TCPA:
1734 return 2;
Philipp Deppenwiese296164e02018-10-18 15:39:34 +02001735 case TPM2:
1736 return 4;
Martin Roth0949e732021-10-01 14:28:22 -06001737 case SSDT: /* ACPI 3.0 up to 6.3: 2 */
Marc Jones93a51762018-08-22 18:57:24 -06001738 return 2;
Jonathan Zhanga3311b92022-12-01 17:13:41 -08001739 case SRAT: /* ACPI 2.0: 1, ACPI 3.0: 2, ACPI 4.0 up to 6.4: 3 */
1740 return 3;
Jonathan Zhang2a4e1f42021-04-01 11:43:37 -07001741 case HMAT: /* ACPI 6.4: 2 */
1742 return 2;
Marc Jones93a51762018-08-22 18:57:24 -06001743 case DMAR:
1744 return 1;
Martin Roth0949e732021-10-01 14:28:22 -06001745 case SLIT: /* ACPI 2.0 up to 6.3: 1 */
Marc Jones93a51762018-08-22 18:57:24 -06001746 return 1;
Patrick Rudolph9d98e5a2019-06-14 19:00:04 +02001747 case SPMI: /* IMPI 2.0 */
1748 return 5;
Marc Jones93a51762018-08-22 18:57:24 -06001749 case HPET: /* Currently 1. Table added in ACPI 2.0. */
1750 return 1;
Elyes HAOUASf288b392018-11-11 15:22:30 +01001751 case VFCT: /* ACPI 2.0/3.0/4.0: 1 */
Marc Jones93a51762018-08-22 18:57:24 -06001752 return 1;
1753 case IVRS:
Jason Glenesk1916f892020-07-24 02:51:30 -07001754 return IVRS_FORMAT_MIXED;
Marc Jones93a51762018-08-22 18:57:24 -06001755 case DBG2:
1756 return 0;
Martin Roth0949e732021-10-01 14:28:22 -06001757 case FACS: /* ACPI 2.0/3.0: 1, ACPI 4.0 up to 6.3: 2 */
Marc Jones93a51762018-08-22 18:57:24 -06001758 return 1;
Martin Roth0949e732021-10-01 14:28:22 -06001759 case RSDT: /* ACPI 1.0 up to 6.3: 1 */
Marc Jones93a51762018-08-22 18:57:24 -06001760 return 1;
Martin Roth0949e732021-10-01 14:28:22 -06001761 case XSDT: /* ACPI 2.0 up to 6.3: 1 */
Marc Jones93a51762018-08-22 18:57:24 -06001762 return 1;
Martin Roth0949e732021-10-01 14:28:22 -06001763 case RSDP: /* ACPI 2.0 up to 6.3: 2 */
Marc Jones93a51762018-08-22 18:57:24 -06001764 return 2;
Rocky Phaguraeff07132021-01-10 15:42:50 -08001765 case EINJ:
1766 return 1;
Marc Jones93a51762018-08-22 18:57:24 -06001767 case HEST:
1768 return 1;
1769 case NHLT:
1770 return 5;
Marshall Dawson44705c62018-09-04 13:47:15 -06001771 case BERT:
1772 return 1;
Jonathan Zhanga3311b92022-12-01 17:13:41 -08001773 case CEDT: /* CXL 3.0 section 9.17.1 */
1774 return 1;
Jason Glenesk61624b22020-11-02 20:06:23 -08001775 case CRAT:
1776 return 1;
Michael Niewöhnerf0a44ae2021-01-01 21:04:09 +01001777 case LPIT: /* ACPI 5.1 up to 6.3: 0 */
1778 return 0;
Arthur Heymans90464072023-06-07 12:53:50 +02001779 case SPCR:
1780 return 4;
Arthur Heymans2e3cb632023-06-30 15:01:08 +02001781 case GTDT:
1782 return 3;
David Milosevicd9822742023-09-22 14:34:28 +02001783 case PPTT: /* ACPI 6.4 */
1784 return 3;
Naresh Solanki6920c6f2023-09-13 12:01:58 +02001785 case IORT: /* IO Remapping Table E.e */
1786 return 6;
Marc Jones93a51762018-08-22 18:57:24 -06001787 default:
1788 return -1;
1789 }
1790 return -1;
1791}