blob: e969a044a125ae147ccc36cba3254767ab86d5b2 [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.
Julien Viard de Galbertcf2b72f2018-04-05 11:24:45 +02007 * Copyright (C) 2018 Online SAS
Mariusz Szafranskia4041332017-08-02 17:28:17 +02008 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 */
19
20#include <arch/acpi.h>
21#include <arch/acpigen.h>
Elyes HAOUASd2b9ec12018-10-27 09:41:02 +020022#include <arch/cpu.h>
Mariusz Szafranskia4041332017-08-02 17:28:17 +020023#include <arch/smp/mpspec.h>
24#include <cpu/x86/smm.h>
25#include <string.h>
26#include <device/pci.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020027#include <device/pci_ops.h>
Mariusz Szafranskia4041332017-08-02 17:28:17 +020028#include <cbmem.h>
Elyes HAOUAS20eaef02019-03-29 17:45:28 +010029#include <console/console.h>
Julien Viard de Galbertcf2b72f2018-04-05 11:24:45 +020030#include <intelblocks/acpi.h>
Mariusz Szafranskia4041332017-08-02 17:28:17 +020031#include <soc/acpi.h>
32#include <soc/cpu.h>
33#include <soc/soc_util.h>
34#include <soc/pmc.h>
35#include <soc/systemagent.h>
36
Julien Viard de Galbertcf2b72f2018-04-05 11:24:45 +020037#define MWAIT_RES(state, sub_state) \
38 { \
39 .addrl = (((state) << 4) | (sub_state)), \
40 .space_id = ACPI_ADDRESS_SPACE_FIXED, \
41 .bit_width = ACPI_FFIXEDHW_VENDOR_INTEL, \
42 .bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT, \
43 .access_size = ACPI_FFIXEDHW_FLAG_HW_COORD, \
44 }
45
46#define CSTATE_RES(address_space, width, offset, address) \
47 { \
48 .space_id = address_space, \
49 .bit_width = width, \
50 .bit_offset = offset, \
51 .addrl = address, \
52 }
53
54static acpi_cstate_t cstate_map[] = {
55 {
56 /* C1 */
57 .ctype = 1, /* ACPI C1 */
58 .latency = 2,
59 .power = 1000,
60 .resource = MWAIT_RES(0, 0),
61 },
62 {
63 .ctype = 2, /* ACPI C2 */
64 .latency = 10,
65 .power = 10,
66 .resource = CSTATE_RES(ACPI_ADDRESS_SPACE_IO, 8, 0,
67 ACPI_BASE_ADDRESS + 0x14),
68 },
69 {
70 .ctype = 3, /* ACPI C3 */
71 .latency = 50,
72 .power = 10,
73 .resource = CSTATE_RES(ACPI_ADDRESS_SPACE_IO, 8, 0,
74 ACPI_BASE_ADDRESS + 0x15),
75 }
76};
77
Mariusz Szafranskia4041332017-08-02 17:28:17 +020078void acpi_init_gnvs(global_nvs_t *gnvs)
79{
80 /* CPU core count */
81 gnvs->pcnt = dev_count_cpu();
82
83 /* Top of Low Memory (start of resource allocation) */
84 gnvs->tolm = top_of_32bit_ram();
85
Julius Wernercd49cce2019-03-05 16:53:33 -080086#if CONFIG(CONSOLE_CBMEM)
Mariusz Szafranskia4041332017-08-02 17:28:17 +020087 /* Update the mem console pointer. */
88 gnvs->cbmc = (u32)cbmem_find(CBMEM_ID_CONSOLE);
89#endif
90
91 /* MMIO Low/High & TSEG base and length */
92 gnvs->mmiob = (u32)get_top_of_low_memory();
93 gnvs->mmiol = (u32)(get_pciebase() - 1);
94 gnvs->mmiohb = (u64)get_top_of_upper_memory();
95 gnvs->mmiohl = (u64)(((u64)1 << CONFIG_CPU_ADDR_BITS) - 1);
96 gnvs->tsegb = (u32)get_tseg_memory();
97 gnvs->tsegl = (u32)(get_top_of_low_memory() - get_tseg_memory());
98}
99
Julien Viard de Galbertcf2b72f2018-04-05 11:24:45 +0200100uint32_t soc_read_sci_irq_select(void)
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200101{
Elyes HAOUAS2ec41832018-05-27 17:40:58 +0200102 struct device *dev = get_pmc_dev();
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200103
104 if (!dev)
105 return 0;
106
Julien Viard de Galbertcf2b72f2018-04-05 11:24:45 +0200107 return pci_read_config32(dev, PMC_ACPI_CNT);
108}
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200109
Julien Viard de Galbertcf2b72f2018-04-05 11:24:45 +0200110acpi_cstate_t *soc_get_cstate_map(size_t *entries)
111{
112 *entries = ARRAY_SIZE(cstate_map);
113 return cstate_map;
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200114}
115
116unsigned long acpi_fill_mcfg(unsigned long current)
117{
118 u32 pciexbar_reg;
119 int max_buses;
120
121 pciexbar_reg = get_pciebase();
122 max_buses = get_pcielength();
123
124 if (!pciexbar_reg)
125 return current;
126
127 current += acpi_create_mcfg_mmconfig((acpi_mcfg_mmconfig_t *)current,
128 pciexbar_reg, 0x0, 0x0,
129 (u8)(max_buses - 1));
130
131 return current;
132}
133
Julien Viard de Galbertcf2b72f2018-04-05 11:24:45 +0200134__attribute__ ((weak)) void motherboard_fill_fadt(acpi_fadt_t *fadt)
135{
136}
137
138void soc_fill_fadt(acpi_fadt_t *fadt)
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200139{
140 u16 pmbase = get_pmbase();
141
142 /* System Management */
Julius Wernercd49cce2019-03-05 16:53:33 -0800143 if (!CONFIG(HAVE_SMI_HANDLER)) {
Julien Viard de Galbertcf2b72f2018-04-05 11:24:45 +0200144 fadt->smi_cmd = 0x00;
145 fadt->acpi_enable = 0x00;
146 fadt->acpi_disable = 0x00;
147 }
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200148
149 /* Power Control */
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200150 fadt->pm2_cnt_blk = pmbase + PM2_CNT;
151 fadt->pm_tmr_blk = pmbase + PM1_TMR;
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200152 fadt->gpe1_blk = 0;
153
154 /* Control Registers - Length */
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200155 fadt->pm2_cnt_len = 1;
156 fadt->pm_tmr_len = 4;
157 fadt->gpe0_blk_len = 8;
158 fadt->gpe1_blk_len = 0;
159 fadt->gpe1_base = 0;
160 fadt->cst_cnt = 0;
161 fadt->p_lvl2_lat = ACPI_FADT_C2_NOT_SUPPORTED;
162 fadt->p_lvl3_lat = ACPI_FADT_C3_NOT_SUPPORTED;
163 fadt->flush_size = 0; /* set to 0 if WBINVD is 1 in flags */
164 fadt->flush_stride = 0; /* set to 0 if WBINVD is 1 in flags */
165 fadt->duty_offset = 1;
166 fadt->duty_width = 0;
167
168 /* RTC Registers */
169 fadt->day_alrm = 0x0D;
170 fadt->mon_alrm = 0x00;
171 fadt->century = 0x00;
172 fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042;
173
174 fadt->flags = ACPI_FADT_WBINVD | ACPI_FADT_C1_SUPPORTED |
175 ACPI_FADT_C2_MP_SUPPORTED | ACPI_FADT_SLEEP_BUTTON |
176 ACPI_FADT_RESET_REGISTER | ACPI_FADT_SLEEP_TYPE |
177 ACPI_FADT_S4_RTC_WAKE | ACPI_FADT_PLATFORM_CLOCK;
178
179 /* Reset Register */
180 fadt->reset_reg.space_id = ACPI_ADDRESS_SPACE_IO;
181 fadt->reset_reg.bit_width = 8;
182 fadt->reset_reg.bit_offset = 0;
183 fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
184 fadt->reset_reg.addrl = 0xCF9;
185 fadt->reset_reg.addrh = 0x00;
186 fadt->reset_value = 6;
187
188 /* PM1 Status & PM1 Enable */
189 fadt->x_pm1a_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
190 fadt->x_pm1a_evt_blk.bit_width = 32;
191 fadt->x_pm1a_evt_blk.bit_offset = 0;
192 fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
193 fadt->x_pm1a_evt_blk.addrl = fadt->pm1a_evt_blk;
194 fadt->x_pm1a_evt_blk.addrh = 0x00;
195
196 fadt->x_pm1b_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
197 fadt->x_pm1b_evt_blk.bit_width = 0;
198 fadt->x_pm1b_evt_blk.bit_offset = 0;
199 fadt->x_pm1b_evt_blk.access_size = 0;
200 fadt->x_pm1b_evt_blk.addrl = fadt->pm1b_evt_blk;
201 fadt->x_pm1b_evt_blk.addrh = 0x00;
202
203 /* PM1 Control Registers */
204 fadt->x_pm1a_cnt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
205 fadt->x_pm1a_cnt_blk.bit_width = 16;
206 fadt->x_pm1a_cnt_blk.bit_offset = 0;
207 fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
208 fadt->x_pm1a_cnt_blk.addrl = fadt->pm1a_cnt_blk;
209 fadt->x_pm1a_cnt_blk.addrh = 0x00;
210
211 fadt->x_pm1b_cnt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
212 fadt->x_pm1b_cnt_blk.bit_width = 0;
213 fadt->x_pm1b_cnt_blk.bit_offset = 0;
214 fadt->x_pm1b_cnt_blk.access_size = 0;
215 fadt->x_pm1b_cnt_blk.addrl = fadt->pm1b_cnt_blk;
216 fadt->x_pm1b_cnt_blk.addrh = 0x00;
217
218 /* PM2 Control Registers */
219 fadt->x_pm2_cnt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
220 fadt->x_pm2_cnt_blk.bit_width = 8;
221 fadt->x_pm2_cnt_blk.bit_offset = 0;
222 fadt->x_pm2_cnt_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
223 fadt->x_pm2_cnt_blk.addrl = fadt->pm2_cnt_blk;
224 fadt->x_pm2_cnt_blk.addrh = 0x00;
225
226 /* PM1 Timer Register */
227 fadt->x_pm_tmr_blk.space_id = ACPI_ADDRESS_SPACE_IO;
228 fadt->x_pm_tmr_blk.bit_width = 32;
229 fadt->x_pm_tmr_blk.bit_offset = 0;
230 fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
231 fadt->x_pm_tmr_blk.addrl = fadt->pm_tmr_blk;
232 fadt->x_pm_tmr_blk.addrh = 0x00;
233
234 /* General-Purpose Event Registers */
235 fadt->x_gpe0_blk.space_id = ACPI_ADDRESS_SPACE_IO;
236 fadt->x_gpe0_blk.bit_width = 64; /* EventStatus + EventEnable */
237 fadt->x_gpe0_blk.bit_offset = 0;
238 fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
239 fadt->x_gpe0_blk.addrl = fadt->gpe0_blk;
240 fadt->x_gpe0_blk.addrh = 0x00;
241
242 fadt->x_gpe1_blk.space_id = ACPI_ADDRESS_SPACE_IO;
243 fadt->x_gpe1_blk.bit_width = 0;
244 fadt->x_gpe1_blk.bit_offset = 0;
245 fadt->x_gpe1_blk.access_size = 0;
246 fadt->x_gpe1_blk.addrl = fadt->gpe1_blk;
247 fadt->x_gpe1_blk.addrh = 0x00;
Julien Viard de Galbertcf2b72f2018-04-05 11:24:45 +0200248
249 motherboard_fill_fadt(fadt);
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200250}
251
Julien Viard de Galbert595202c2018-03-29 14:01:01 +0200252static acpi_tstate_t denverton_tss_table[] = {
253 { 100, 1000, 0, 0x00, 0 },
254 { 88, 875, 0, 0x1e, 0 },
255 { 75, 750, 0, 0x1c, 0 },
256 { 63, 625, 0, 0x1a, 0 },
257 { 50, 500, 0, 0x18, 0 },
258 { 38, 375, 0, 0x16, 0 },
259 { 25, 250, 0, 0x14, 0 },
260 { 13, 125, 0, 0x12, 0 },
261};
262
263acpi_tstate_t *soc_get_tss_table(int *entries)
264{
265 *entries = ARRAY_SIZE(denverton_tss_table);
266 return denverton_tss_table;
267}
268
269void soc_power_states_generation(int core_id, int cores_per_package)
270{
271 generate_p_state_entries(core_id, cores_per_package);
272
273 generate_t_state_entries(core_id, cores_per_package);
274}
275
Julien Viard de Galbertcf2b72f2018-04-05 11:24:45 +0200276int soc_madt_sci_irq_polarity(int sci)
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200277{
Julien Viard de Galbertcf2b72f2018-04-05 11:24:45 +0200278 if (sci >= 20)
279 return MP_IRQ_POLARITY_LOW;
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200280 else
Julien Viard de Galbertcf2b72f2018-04-05 11:24:45 +0200281 return MP_IRQ_POLARITY_HIGH;
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200282}
283
Elyes HAOUAS2ec41832018-05-27 17:40:58 +0200284unsigned long southcluster_write_acpi_tables(struct device *device,
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200285 unsigned long current,
286 struct acpi_rsdp *rsdp)
287{
288 acpi_header_t *ssdt2;
289
290 current = acpi_write_hpet(device, current, rsdp);
291 current = (ALIGN(current, 16));
292
293 ssdt2 = (acpi_header_t *)current;
294 memset(ssdt2, 0, sizeof(acpi_header_t));
295 acpi_create_serialio_ssdt(ssdt2);
296 if (ssdt2->length) {
297 current += ssdt2->length;
298 acpi_add_table(rsdp, ssdt2);
299 printk(BIOS_DEBUG, "ACPI: * SSDT2 @ %p Length %x\n", ssdt2,
300 ssdt2->length);
301 current = (ALIGN(current, 16));
302 } else {
303 ssdt2 = NULL;
304 printk(BIOS_DEBUG, "ACPI: * SSDT2 not generated.\n");
305 }
306
307 printk(BIOS_DEBUG, "current = %lx\n", current);
308
309 return current;
310}
311
Elyes HAOUAS2ec41832018-05-27 17:40:58 +0200312void southcluster_inject_dsdt(struct device *device)
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200313{
314 global_nvs_t *gnvs;
315
316 gnvs = cbmem_find(CBMEM_ID_ACPI_GNVS);
317 if (!gnvs) {
318 gnvs = cbmem_add(CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
319 if (gnvs)
320 memset(gnvs, 0, sizeof(*gnvs));
321 }
322
323 if (gnvs) {
324 acpi_create_gnvs(gnvs);
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200325 /* And tell SMI about it */
326 smm_setup_structures(gnvs, NULL, NULL);
327
328 /* Add it to DSDT. */
329 acpigen_write_scope("\\");
330 acpigen_write_name_dword("NVSA", (u32)gnvs);
331 acpigen_pop_len();
332 }
333}
334
Aaron Durbin64031672018-04-21 14:45:32 -0600335__weak void acpi_create_serialio_ssdt(acpi_header_t *ssdt) {}