Merge tag 'u-boot-rockchip-20200501' of https://gitlab.denx.de/u-boot/custodians...
[platform/kernel/u-boot.git] / lib / acpi / acpi_table.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Generic code used to generate ACPI tables
4  *
5  * Copyright 2019 Google LLC
6  */
7
8 #include <common.h>
9 #include <dm.h>
10 #include <cpu.h>
11 #include <mapmem.h>
12 #include <tables_csum.h>
13 #include <version.h>
14 #include <acpi/acpi_table.h>
15 #include <dm/acpi.h>
16
17 int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags)
18 {
19         struct acpi_table_header *header = &dmar->header;
20         struct cpu_info info;
21         struct udevice *cpu;
22         int ret;
23
24         ret = uclass_first_device(UCLASS_CPU, &cpu);
25         if (ret)
26                 return log_msg_ret("cpu", ret);
27         ret = cpu_get_info(cpu, &info);
28         if (ret)
29                 return log_msg_ret("info", ret);
30         memset((void *)dmar, 0, sizeof(struct acpi_dmar));
31
32         /* Fill out header fields. */
33         acpi_fill_header(&dmar->header, "DMAR");
34         header->length = sizeof(struct acpi_dmar);
35         header->revision = acpi_get_table_revision(ACPITAB_DMAR);
36
37         dmar->host_address_width = info.address_width - 1;
38         dmar->flags = flags;
39
40         return 0;
41 }
42
43 int acpi_get_table_revision(enum acpi_tables table)
44 {
45         switch (table) {
46         case ACPITAB_FADT:
47                 return ACPI_FADT_REV_ACPI_3_0;
48         case ACPITAB_MADT:
49                 return ACPI_MADT_REV_ACPI_3_0;
50         case ACPITAB_MCFG:
51                 return ACPI_MCFG_REV_ACPI_3_0;
52         case ACPITAB_TCPA:
53                 /* This version and the rest are open-coded */
54                 return 2;
55         case ACPITAB_TPM2:
56                 return 4;
57         case ACPITAB_SSDT: /* ACPI 3.0 upto 6.3: 2 */
58                 return 2;
59         case ACPITAB_SRAT: /* ACPI 2.0: 1, ACPI 3.0: 2, ACPI 4.0 to 6.3: 3 */
60                 return 1; /* TODO Should probably be upgraded to 2 */
61         case ACPITAB_DMAR:
62                 return 1;
63         case ACPITAB_SLIT: /* ACPI 2.0 upto 6.3: 1 */
64                 return 1;
65         case ACPITAB_SPMI: /* IMPI 2.0 */
66                 return 5;
67         case ACPITAB_HPET: /* Currently 1. Table added in ACPI 2.0 */
68                 return 1;
69         case ACPITAB_VFCT: /* ACPI 2.0/3.0/4.0: 1 */
70                 return 1;
71         case ACPITAB_IVRS:
72                 return IVRS_FORMAT_FIXED;
73         case ACPITAB_DBG2:
74                 return 0;
75         case ACPITAB_FACS: /* ACPI 2.0/3.0: 1, ACPI 4.0 to 6.3: 2 */
76                 return 1;
77         case ACPITAB_RSDT: /* ACPI 1.0 upto 6.3: 1 */
78                 return 1;
79         case ACPITAB_XSDT: /* ACPI 2.0 upto 6.3: 1 */
80                 return 1;
81         case ACPITAB_RSDP: /* ACPI 2.0 upto 6.3: 2 */
82                 return 2;
83         case ACPITAB_HEST:
84                 return 1;
85         case ACPITAB_NHLT:
86                 return 5;
87         case ACPITAB_BERT:
88                 return 1;
89         case ACPITAB_SPCR:
90                 return 2;
91         default:
92                 return -EINVAL;
93         }
94 }
95
96 void acpi_fill_header(struct acpi_table_header *header, char *signature)
97 {
98         memcpy(header->signature, signature, 4);
99         memcpy(header->oem_id, OEM_ID, 6);
100         memcpy(header->oem_table_id, OEM_TABLE_ID, 8);
101         header->oem_revision = U_BOOT_BUILD_DATE;
102         memcpy(header->aslc_id, ASLC_ID, 4);
103 }
104
105 void acpi_align(struct acpi_ctx *ctx)
106 {
107         ctx->current = (void *)ALIGN((ulong)ctx->current, 16);
108 }
109
110 void acpi_align64(struct acpi_ctx *ctx)
111 {
112         ctx->current = (void *)ALIGN((ulong)ctx->current, 64);
113 }
114
115 void acpi_inc(struct acpi_ctx *ctx, uint amount)
116 {
117         ctx->current += amount;
118 }
119
120 void acpi_inc_align(struct acpi_ctx *ctx, uint amount)
121 {
122         ctx->current += amount;
123         acpi_align(ctx);
124 }
125
126 /**
127  * Add an ACPI table to the RSDT (and XSDT) structure, recalculate length
128  * and checksum.
129  */
130 int acpi_add_table(struct acpi_ctx *ctx, void *table)
131 {
132         int i, entries_num;
133         struct acpi_rsdt *rsdt;
134         struct acpi_xsdt *xsdt;
135
136         /* The RSDT is mandatory while the XSDT is not */
137         rsdt = ctx->rsdt;
138
139         /* This should always be MAX_ACPI_TABLES */
140         entries_num = ARRAY_SIZE(rsdt->entry);
141
142         for (i = 0; i < entries_num; i++) {
143                 if (rsdt->entry[i] == 0)
144                         break;
145         }
146
147         if (i >= entries_num) {
148                 log_err("ACPI: Error: too many tables\n");
149                 return -E2BIG;
150         }
151
152         /* Add table to the RSDT */
153         rsdt->entry[i] = map_to_sysmem(table);
154
155         /* Fix RSDT length or the kernel will assume invalid entries */
156         rsdt->header.length = sizeof(struct acpi_table_header) +
157                                 (sizeof(u32) * (i + 1));
158
159         /* Re-calculate checksum */
160         rsdt->header.checksum = 0;
161         rsdt->header.checksum = table_compute_checksum((u8 *)rsdt,
162                                                        rsdt->header.length);
163
164         /*
165          * And now the same thing for the XSDT. We use the same index as for
166          * now we want the XSDT and RSDT to always be in sync in U-Boot
167          */
168         xsdt = ctx->xsdt;
169
170         /* Add table to the XSDT */
171         xsdt->entry[i] = map_to_sysmem(table);
172
173         /* Fix XSDT length */
174         xsdt->header.length = sizeof(struct acpi_table_header) +
175                                 (sizeof(u64) * (i + 1));
176
177         /* Re-calculate checksum */
178         xsdt->header.checksum = 0;
179         xsdt->header.checksum = table_compute_checksum((u8 *)xsdt,
180                                                        xsdt->header.length);
181
182         return 0;
183 }
184
185 static void acpi_write_rsdp(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt,
186                             struct acpi_xsdt *xsdt)
187 {
188         memset(rsdp, 0, sizeof(struct acpi_rsdp));
189
190         memcpy(rsdp->signature, RSDP_SIG, 8);
191         memcpy(rsdp->oem_id, OEM_ID, 6);
192
193         rsdp->length = sizeof(struct acpi_rsdp);
194         rsdp->rsdt_address = map_to_sysmem(rsdt);
195
196         rsdp->xsdt_address = map_to_sysmem(xsdt);
197         rsdp->revision = ACPI_RSDP_REV_ACPI_2_0;
198
199         /* Calculate checksums */
200         rsdp->checksum = table_compute_checksum(rsdp, 20);
201         rsdp->ext_checksum = table_compute_checksum(rsdp,
202                                                     sizeof(struct acpi_rsdp));
203 }
204
205 static void acpi_write_rsdt(struct acpi_rsdt *rsdt)
206 {
207         struct acpi_table_header *header = &rsdt->header;
208
209         /* Fill out header fields */
210         acpi_fill_header(header, "RSDT");
211         header->length = sizeof(struct acpi_rsdt);
212         header->revision = 1;
213
214         /* Entries are filled in later, we come with an empty set */
215
216         /* Fix checksum */
217         header->checksum = table_compute_checksum(rsdt,
218                                                   sizeof(struct acpi_rsdt));
219 }
220
221 static void acpi_write_xsdt(struct acpi_xsdt *xsdt)
222 {
223         struct acpi_table_header *header = &xsdt->header;
224
225         /* Fill out header fields */
226         acpi_fill_header(header, "XSDT");
227         header->length = sizeof(struct acpi_xsdt);
228         header->revision = 1;
229
230         /* Entries are filled in later, we come with an empty set */
231
232         /* Fix checksum */
233         header->checksum = table_compute_checksum(xsdt,
234                                                   sizeof(struct acpi_xsdt));
235 }
236
237 void acpi_setup_base_tables(struct acpi_ctx *ctx, void *start)
238 {
239         ctx->current = start;
240
241         /* Align ACPI tables to 16 byte */
242         acpi_align(ctx);
243         gd->arch.acpi_start = map_to_sysmem(ctx->current);
244
245         /* We need at least an RSDP and an RSDT Table */
246         ctx->rsdp = ctx->current;
247         acpi_inc_align(ctx, sizeof(struct acpi_rsdp));
248         ctx->rsdt = ctx->current;
249         acpi_inc_align(ctx, sizeof(struct acpi_rsdt));
250         ctx->xsdt = ctx->current;
251         acpi_inc_align(ctx, sizeof(struct acpi_xsdt));
252
253         /* clear all table memory */
254         memset((void *)start, '\0', ctx->current - start);
255
256         acpi_write_rsdp(ctx->rsdp, ctx->rsdt, ctx->xsdt);
257         acpi_write_rsdt(ctx->rsdt);
258         acpi_write_xsdt(ctx->xsdt);
259         /*
260          * Per ACPI spec, the FACS table address must be aligned to a 64 byte
261          * boundary (Windows checks this, but Linux does not).
262          */
263         acpi_align64(ctx);
264 }