blob: 640dc79c0f1e97b333b5ccea0fcde915da114d39 [file] [log] [blame]
Mariusz Szafranskia4041332017-08-02 17:28:17 +02001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2007 - 2009 coresystems GmbH
5 * Copyright (C) 2013 Google Inc.
6 * Copyright (C) 2014 - 2017 Intel Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 */
18
19#include <arch/acpi.h>
20#include <arch/acpigen.h>
21#include <arch/smp/mpspec.h>
Aaron Durbin64031672018-04-21 14:45:32 -060022#include <compiler.h>
Mariusz Szafranskia4041332017-08-02 17:28:17 +020023#include <cpu/x86/smm.h>
24#include <string.h>
25#include <device/pci.h>
26#include <cpu/cpu.h>
27#include <cbmem.h>
28
29#include <soc/acpi.h>
30#include <soc/cpu.h>
31#include <soc/soc_util.h>
32#include <soc/pmc.h>
33#include <soc/systemagent.h>
34
35void acpi_init_gnvs(global_nvs_t *gnvs)
36{
37 /* CPU core count */
38 gnvs->pcnt = dev_count_cpu();
39
40 /* Top of Low Memory (start of resource allocation) */
41 gnvs->tolm = top_of_32bit_ram();
42
43#if IS_ENABLED(CONFIG_CONSOLE_CBMEM)
44 /* Update the mem console pointer. */
45 gnvs->cbmc = (u32)cbmem_find(CBMEM_ID_CONSOLE);
46#endif
47
48 /* MMIO Low/High & TSEG base and length */
49 gnvs->mmiob = (u32)get_top_of_low_memory();
50 gnvs->mmiol = (u32)(get_pciebase() - 1);
51 gnvs->mmiohb = (u64)get_top_of_upper_memory();
52 gnvs->mmiohl = (u64)(((u64)1 << CONFIG_CPU_ADDR_BITS) - 1);
53 gnvs->tsegb = (u32)get_tseg_memory();
54 gnvs->tsegl = (u32)(get_top_of_low_memory() - get_tseg_memory());
55}
56
57static int acpi_sci_irq(void)
58{
59 int scis, sci_irq;
Elyes HAOUAS2ec41832018-05-27 17:40:58 +020060 struct device *dev = get_pmc_dev();
Mariusz Szafranskia4041332017-08-02 17:28:17 +020061
62 if (!dev)
63 return 0;
64
65 /* Determine how SCI is routed. */
66 scis = pci_read_config32(dev, PMC_ACPI_CNT) & PMC_ACPI_CNT_SCIS_MASK;
67 switch (scis) {
68 case PMC_ACPI_CNT_SCIS_IRQ9:
69 case PMC_ACPI_CNT_SCIS_IRQ10:
70 case PMC_ACPI_CNT_SCIS_IRQ11:
71 sci_irq = scis - PMC_ACPI_CNT_SCIS_IRQ9 + 9;
72 break;
73 case PMC_ACPI_CNT_SCIS_IRQ20:
74 case PMC_ACPI_CNT_SCIS_IRQ21:
75 case PMC_ACPI_CNT_SCIS_IRQ22:
76 case PMC_ACPI_CNT_SCIS_IRQ23:
77 sci_irq = scis - PMC_ACPI_CNT_SCIS_IRQ20 + 20;
78 break;
79 default:
80 printk(BIOS_DEBUG, "Invalid SCI route! Defaulting to IRQ9.\n");
81 sci_irq = 9;
82 break;
83 }
84
85 printk(BIOS_DEBUG, "SCI is IRQ%d\n", sci_irq);
86 return sci_irq;
87}
88
89unsigned long acpi_fill_mcfg(unsigned long current)
90{
91 u32 pciexbar_reg;
92 int max_buses;
93
94 pciexbar_reg = get_pciebase();
95 max_buses = get_pcielength();
96
97 if (!pciexbar_reg)
98 return current;
99
100 current += acpi_create_mcfg_mmconfig((acpi_mcfg_mmconfig_t *)current,
101 pciexbar_reg, 0x0, 0x0,
102 (u8)(max_buses - 1));
103
104 return current;
105}
106
107void acpi_fill_in_fadt(acpi_fadt_t *fadt)
108{
109 u16 pmbase = get_pmbase();
110
111 /* System Management */
112 fadt->sci_int = acpi_sci_irq();
113#if IS_ENABLED(CONFIG_HAVE_SMI_HANDLER)
114 fadt->smi_cmd = APM_CNT;
115 fadt->acpi_enable = APM_CNT_ACPI_ENABLE;
116 fadt->acpi_disable = APM_CNT_ACPI_DISABLE;
117#else
118 fadt->smi_cmd = 0x00;
119 fadt->acpi_enable = 0x00;
120 fadt->acpi_disable = 0x00;
121#endif
122
123 /* Power Control */
124 fadt->s4bios_req = 0x0;
125 fadt->pstate_cnt = 0;
126
127 fadt->pm1a_evt_blk = pmbase + PM1_STS;
128 fadt->pm1b_evt_blk = 0x0;
129 fadt->pm1a_cnt_blk = pmbase + PM1_CNT;
130 fadt->pm1b_cnt_blk = 0x0;
131 fadt->pm2_cnt_blk = pmbase + PM2_CNT;
132 fadt->pm_tmr_blk = pmbase + PM1_TMR;
133 fadt->gpe0_blk = pmbase + GPE0_STS;
134 fadt->gpe1_blk = 0;
135
136 /* Control Registers - Length */
137 fadt->pm1_evt_len = 4;
138 fadt->pm1_cnt_len = 2;
139 fadt->pm2_cnt_len = 1;
140 fadt->pm_tmr_len = 4;
141 fadt->gpe0_blk_len = 8;
142 fadt->gpe1_blk_len = 0;
143 fadt->gpe1_base = 0;
144 fadt->cst_cnt = 0;
145 fadt->p_lvl2_lat = ACPI_FADT_C2_NOT_SUPPORTED;
146 fadt->p_lvl3_lat = ACPI_FADT_C3_NOT_SUPPORTED;
147 fadt->flush_size = 0; /* set to 0 if WBINVD is 1 in flags */
148 fadt->flush_stride = 0; /* set to 0 if WBINVD is 1 in flags */
149 fadt->duty_offset = 1;
150 fadt->duty_width = 0;
151
152 /* RTC Registers */
153 fadt->day_alrm = 0x0D;
154 fadt->mon_alrm = 0x00;
155 fadt->century = 0x00;
156 fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042;
157
158 fadt->flags = ACPI_FADT_WBINVD | ACPI_FADT_C1_SUPPORTED |
159 ACPI_FADT_C2_MP_SUPPORTED | ACPI_FADT_SLEEP_BUTTON |
160 ACPI_FADT_RESET_REGISTER | ACPI_FADT_SLEEP_TYPE |
161 ACPI_FADT_S4_RTC_WAKE | ACPI_FADT_PLATFORM_CLOCK;
162
163 /* Reset Register */
164 fadt->reset_reg.space_id = ACPI_ADDRESS_SPACE_IO;
165 fadt->reset_reg.bit_width = 8;
166 fadt->reset_reg.bit_offset = 0;
167 fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
168 fadt->reset_reg.addrl = 0xCF9;
169 fadt->reset_reg.addrh = 0x00;
170 fadt->reset_value = 6;
171
172 /* PM1 Status & PM1 Enable */
173 fadt->x_pm1a_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
174 fadt->x_pm1a_evt_blk.bit_width = 32;
175 fadt->x_pm1a_evt_blk.bit_offset = 0;
176 fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
177 fadt->x_pm1a_evt_blk.addrl = fadt->pm1a_evt_blk;
178 fadt->x_pm1a_evt_blk.addrh = 0x00;
179
180 fadt->x_pm1b_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
181 fadt->x_pm1b_evt_blk.bit_width = 0;
182 fadt->x_pm1b_evt_blk.bit_offset = 0;
183 fadt->x_pm1b_evt_blk.access_size = 0;
184 fadt->x_pm1b_evt_blk.addrl = fadt->pm1b_evt_blk;
185 fadt->x_pm1b_evt_blk.addrh = 0x00;
186
187 /* PM1 Control Registers */
188 fadt->x_pm1a_cnt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
189 fadt->x_pm1a_cnt_blk.bit_width = 16;
190 fadt->x_pm1a_cnt_blk.bit_offset = 0;
191 fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
192 fadt->x_pm1a_cnt_blk.addrl = fadt->pm1a_cnt_blk;
193 fadt->x_pm1a_cnt_blk.addrh = 0x00;
194
195 fadt->x_pm1b_cnt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
196 fadt->x_pm1b_cnt_blk.bit_width = 0;
197 fadt->x_pm1b_cnt_blk.bit_offset = 0;
198 fadt->x_pm1b_cnt_blk.access_size = 0;
199 fadt->x_pm1b_cnt_blk.addrl = fadt->pm1b_cnt_blk;
200 fadt->x_pm1b_cnt_blk.addrh = 0x00;
201
202 /* PM2 Control Registers */
203 fadt->x_pm2_cnt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
204 fadt->x_pm2_cnt_blk.bit_width = 8;
205 fadt->x_pm2_cnt_blk.bit_offset = 0;
206 fadt->x_pm2_cnt_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
207 fadt->x_pm2_cnt_blk.addrl = fadt->pm2_cnt_blk;
208 fadt->x_pm2_cnt_blk.addrh = 0x00;
209
210 /* PM1 Timer Register */
211 fadt->x_pm_tmr_blk.space_id = ACPI_ADDRESS_SPACE_IO;
212 fadt->x_pm_tmr_blk.bit_width = 32;
213 fadt->x_pm_tmr_blk.bit_offset = 0;
214 fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
215 fadt->x_pm_tmr_blk.addrl = fadt->pm_tmr_blk;
216 fadt->x_pm_tmr_blk.addrh = 0x00;
217
218 /* General-Purpose Event Registers */
219 fadt->x_gpe0_blk.space_id = ACPI_ADDRESS_SPACE_IO;
220 fadt->x_gpe0_blk.bit_width = 64; /* EventStatus + EventEnable */
221 fadt->x_gpe0_blk.bit_offset = 0;
222 fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
223 fadt->x_gpe0_blk.addrl = fadt->gpe0_blk;
224 fadt->x_gpe0_blk.addrh = 0x00;
225
226 fadt->x_gpe1_blk.space_id = ACPI_ADDRESS_SPACE_IO;
227 fadt->x_gpe1_blk.bit_width = 0;
228 fadt->x_gpe1_blk.bit_offset = 0;
229 fadt->x_gpe1_blk.access_size = 0;
230 fadt->x_gpe1_blk.addrl = fadt->gpe1_blk;
231 fadt->x_gpe1_blk.addrh = 0x00;
232}
233
Elyes HAOUAS2ec41832018-05-27 17:40:58 +0200234void generate_cpu_entries(struct device *device)
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200235{
236 int core;
237 int pcontrol_blk = get_pmbase(), plen = 6;
238 int num_cpus = get_cpu_count();
239
240 for (core = 0; core < num_cpus; core++) {
241 if (core > 0) {
242 pcontrol_blk = 0;
243 plen = 0;
244 }
245
246 /* Generate processor \_PR.CPUx */
247 acpigen_write_processor(core, pcontrol_blk, plen);
248
249 /* Generate P-state tables */
250
251 /* Generate C-state tables */
252
253 /* Generate T-state tables */
254
255 acpigen_pop_len();
256 }
257}
258
259unsigned long acpi_madt_irq_overrides(unsigned long current)
260{
261 int sci_irq = acpi_sci_irq();
262 acpi_madt_irqoverride_t *irqovr;
263 uint16_t sci_flags = MP_IRQ_TRIGGER_LEVEL;
264
265 /* INT_SRC_OVR */
266 irqovr = (acpi_madt_irqoverride_t *)current;
267 current += acpi_create_madt_irqoverride(irqovr, 0, 0, 2, 0);
268
269 if (sci_irq >= 20)
270 sci_flags |= MP_IRQ_POLARITY_LOW;
271 else
272 sci_flags |= MP_IRQ_POLARITY_HIGH;
273
274 irqovr = (acpi_madt_irqoverride_t *)current;
275 current += acpi_create_madt_irqoverride(irqovr, 0, (u8)sci_irq, sci_irq,
276 sci_flags);
277
278 return current;
279}
280
Elyes HAOUAS2ec41832018-05-27 17:40:58 +0200281unsigned long southcluster_write_acpi_tables(struct device *device,
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200282 unsigned long current,
283 struct acpi_rsdp *rsdp)
284{
285 acpi_header_t *ssdt2;
286
287 current = acpi_write_hpet(device, current, rsdp);
288 current = (ALIGN(current, 16));
289
290 ssdt2 = (acpi_header_t *)current;
291 memset(ssdt2, 0, sizeof(acpi_header_t));
292 acpi_create_serialio_ssdt(ssdt2);
293 if (ssdt2->length) {
294 current += ssdt2->length;
295 acpi_add_table(rsdp, ssdt2);
296 printk(BIOS_DEBUG, "ACPI: * SSDT2 @ %p Length %x\n", ssdt2,
297 ssdt2->length);
298 current = (ALIGN(current, 16));
299 } else {
300 ssdt2 = NULL;
301 printk(BIOS_DEBUG, "ACPI: * SSDT2 not generated.\n");
302 }
303
304 printk(BIOS_DEBUG, "current = %lx\n", current);
305
306 return current;
307}
308
Elyes HAOUAS2ec41832018-05-27 17:40:58 +0200309void southcluster_inject_dsdt(struct device *device)
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200310{
311 global_nvs_t *gnvs;
312
313 gnvs = cbmem_find(CBMEM_ID_ACPI_GNVS);
314 if (!gnvs) {
315 gnvs = cbmem_add(CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
316 if (gnvs)
317 memset(gnvs, 0, sizeof(*gnvs));
318 }
319
320 if (gnvs) {
321 acpi_create_gnvs(gnvs);
322 acpi_save_gnvs((unsigned long)gnvs);
323 /* And tell SMI about it */
324 smm_setup_structures(gnvs, NULL, NULL);
325
326 /* Add it to DSDT. */
327 acpigen_write_scope("\\");
328 acpigen_write_name_dword("NVSA", (u32)gnvs);
329 acpigen_pop_len();
330 }
331}
332
Aaron Durbin64031672018-04-21 14:45:32 -0600333__weak void acpi_create_serialio_ssdt(acpi_header_t *ssdt) {}