]>
git.ipfire.org Git - thirdparty/u-boot.git/blob - lib/acpi/acpi_table.c
1 // SPDX-License-Identifier: GPL-2.0+
3 * Generic code used to generate ACPI tables
5 * Copyright 2019 Google LLC
12 #include <tables_csum.h>
13 #include <version_string.h>
14 #include <acpi/acpi_table.h>
15 #include <asm/global_data.h>
19 * OEM_REVISION is 32-bit unsigned number. It should be increased only when
20 * changing software version. Therefore it should not depend on build time.
21 * U-Boot calculates it from U-Boot version and represent it in hexadecimal
22 * notation. As U-Boot version is in form year.month set low 8 bits to 0x01
23 * to have valid date. So for U-Boot version 2021.04 OEM_REVISION is set to
26 #define OEM_REVISION ((((version_num / 1000) % 10) << 28) | \
27 (((version_num / 100) % 10) << 24) | \
28 (((version_num / 10) % 10) << 20) | \
29 ((version_num % 10) << 16) | \
30 (((version_num_patch / 10) % 10) << 12) | \
31 ((version_num_patch % 10) << 8) | \
34 int acpi_create_dmar(struct acpi_dmar
*dmar
, enum dmar_flags flags
)
36 struct acpi_table_header
*header
= &dmar
->header
;
41 ret
= uclass_first_device_err(UCLASS_CPU
, &cpu
);
43 return log_msg_ret("cpu", ret
);
44 ret
= cpu_get_info(cpu
, &info
);
46 return log_msg_ret("info", ret
);
47 memset((void *)dmar
, 0, sizeof(struct acpi_dmar
));
49 /* Fill out header fields. */
50 acpi_fill_header(&dmar
->header
, "DMAR");
51 header
->length
= sizeof(struct acpi_dmar
);
52 header
->revision
= acpi_get_table_revision(ACPITAB_DMAR
);
54 dmar
->host_address_width
= info
.address_width
- 1;
60 int acpi_get_table_revision(enum acpi_tables table
)
64 return ACPI_FADT_REV_ACPI_3_0
;
66 return ACPI_MADT_REV_ACPI_3_0
;
68 return ACPI_MCFG_REV_ACPI_3_0
;
70 /* This version and the rest are open-coded */
74 case ACPITAB_SSDT
: /* ACPI 3.0 upto 6.3: 2 */
76 case ACPITAB_SRAT
: /* ACPI 2.0: 1, ACPI 3.0: 2, ACPI 4.0 to 6.3: 3 */
77 return 1; /* TODO Should probably be upgraded to 2 */
80 case ACPITAB_SLIT
: /* ACPI 2.0 upto 6.3: 1 */
82 case ACPITAB_SPMI
: /* IMPI 2.0 */
84 case ACPITAB_HPET
: /* Currently 1. Table added in ACPI 2.0 */
86 case ACPITAB_VFCT
: /* ACPI 2.0/3.0/4.0: 1 */
89 return IVRS_FORMAT_FIXED
;
92 case ACPITAB_FACS
: /* ACPI 2.0/3.0: 1, ACPI 4.0 to 6.3: 2 */
94 case ACPITAB_RSDT
: /* ACPI 1.0 upto 6.3: 1 */
96 case ACPITAB_XSDT
: /* ACPI 2.0 upto 6.3: 1 */
98 case ACPITAB_RSDP
: /* ACPI 2.0 upto 6.3: 2 */
113 void acpi_fill_header(struct acpi_table_header
*header
, char *signature
)
115 memcpy(header
->signature
, signature
, 4);
116 memcpy(header
->oem_id
, OEM_ID
, 6);
117 memcpy(header
->oem_table_id
, OEM_TABLE_ID
, 8);
118 header
->oem_revision
= OEM_REVISION
;
119 memcpy(header
->creator_id
, ASLC_ID
, 4);
122 void acpi_align(struct acpi_ctx
*ctx
)
124 ctx
->current
= (void *)ALIGN((ulong
)ctx
->current
, 16);
127 void acpi_align64(struct acpi_ctx
*ctx
)
129 ctx
->current
= (void *)ALIGN((ulong
)ctx
->current
, 64);
132 void acpi_inc(struct acpi_ctx
*ctx
, uint amount
)
134 ctx
->current
+= amount
;
137 void acpi_inc_align(struct acpi_ctx
*ctx
, uint amount
)
139 ctx
->current
+= amount
;
144 * Add an ACPI table to the RSDT (and XSDT) structure, recalculate length
147 int acpi_add_table(struct acpi_ctx
*ctx
, void *table
)
150 struct acpi_rsdt
*rsdt
;
151 struct acpi_xsdt
*xsdt
;
153 /* The RSDT is mandatory while the XSDT is not */
156 /* This should always be MAX_ACPI_TABLES */
157 entries_num
= ARRAY_SIZE(rsdt
->entry
);
159 for (i
= 0; i
< entries_num
; i
++) {
160 if (rsdt
->entry
[i
] == 0)
164 if (i
>= entries_num
) {
165 log_err("ACPI: Error: too many tables\n");
169 /* Add table to the RSDT */
170 rsdt
->entry
[i
] = nomap_to_sysmem(table
);
172 /* Fix RSDT length or the kernel will assume invalid entries */
173 rsdt
->header
.length
= sizeof(struct acpi_table_header
) +
174 (sizeof(u32
) * (i
+ 1));
176 /* Re-calculate checksum */
177 rsdt
->header
.checksum
= 0;
178 rsdt
->header
.checksum
= table_compute_checksum((u8
*)rsdt
,
179 rsdt
->header
.length
);
182 * And now the same thing for the XSDT. We use the same index as for
183 * now we want the XSDT and RSDT to always be in sync in U-Boot
187 /* Add table to the XSDT */
188 xsdt
->entry
[i
] = nomap_to_sysmem(table
);
190 /* Fix XSDT length */
191 xsdt
->header
.length
= sizeof(struct acpi_table_header
) +
192 (sizeof(u64
) * (i
+ 1));
194 /* Re-calculate checksum */
195 xsdt
->header
.checksum
= 0;
196 xsdt
->header
.checksum
= table_compute_checksum((u8
*)xsdt
,
197 xsdt
->header
.length
);
202 void acpi_create_dbg2(struct acpi_dbg2_header
*dbg2
,
203 int port_type
, int port_subtype
,
204 struct acpi_gen_regaddr
*address
, u32 address_size
,
205 const char *device_path
)
208 struct acpi_dbg2_device
*device
;
210 struct acpi_table_header
*header
;
215 /* Fill out header fields. */
216 current
= (uintptr_t)dbg2
;
217 memset(dbg2
, '\0', sizeof(struct acpi_dbg2_header
));
218 header
= &dbg2
->header
;
220 header
->revision
= acpi_get_table_revision(ACPITAB_DBG2
);
221 acpi_fill_header(header
, "DBG2");
222 header
->creator_revision
= ASL_REVISION
;
224 /* One debug device defined */
225 dbg2
->devices_offset
= sizeof(struct acpi_dbg2_header
);
226 dbg2
->devices_count
= 1;
227 current
+= sizeof(struct acpi_dbg2_header
);
229 /* Device comes after the header */
230 device
= (struct acpi_dbg2_device
*)current
;
231 memset(device
, 0, sizeof(struct acpi_dbg2_device
));
232 current
+= sizeof(struct acpi_dbg2_device
);
234 device
->revision
= 0;
235 device
->address_count
= 1;
236 device
->port_type
= port_type
;
237 device
->port_subtype
= port_subtype
;
239 /* Base Address comes after device structure */
240 memcpy((void *)current
, address
, sizeof(struct acpi_gen_regaddr
));
241 device
->base_address_offset
= current
- (uintptr_t)device
;
242 current
+= sizeof(struct acpi_gen_regaddr
);
244 /* Address Size comes after address structure */
245 dbg2_addr_size
= (uint32_t *)current
;
246 device
->address_size_offset
= current
- (uintptr_t)device
;
247 *dbg2_addr_size
= address_size
;
248 current
+= sizeof(uint32_t);
250 /* Namespace string comes last, use '.' if not provided */
251 path
= device_path
? : ".";
252 /* Namespace string length includes NULL terminator */
253 path_len
= strlen(path
) + 1;
254 namespace = (char *)current
;
255 device
->namespace_string_length
= path_len
;
256 device
->namespace_string_offset
= current
- (uintptr_t)device
;
257 strncpy(namespace, path
, path_len
);
260 /* Update structure lengths and checksum */
261 device
->length
= current
- (uintptr_t)device
;
262 header
->length
= current
- (uintptr_t)dbg2
;
263 header
->checksum
= table_compute_checksum(dbg2
, header
->length
);