aboutsummaryrefslogtreecommitdiff
path: root/src/soc/amd/picasso/acpi.c
diff options
context:
space:
mode:
authorMartin Roth <martinroth@chromium.org>2019-04-22 14:55:16 -0600
committerMartin Roth <martinroth@google.com>2019-07-02 14:11:11 +0000
commit5c354b9979c7e7ad9af668bad0e1b6a5c3003d26 (patch)
treec597ef067e0d6eb65c2ba7e4b5e754f49e65572c /src/soc/amd/picasso/acpi.c
parent76378b3c01b52f4d4184284d3d07bf63fef2ca17 (diff)
soc/amd/picasso: Create picasso as a copy of stoneyridge
So that everyone can see what's being updated from stoney, we're starting with a direct copy of the stoney directory. There are arguments both for and against doing it this way, but I believe This the most transparent way. We've moved much of the duplicated stoney code into the soc/amd/common directory and will continue that work as it becomes obvious that we have unchanged code between the SOCs. Makefile.inc has been renamed as makefile.inc so that it won't build in jenkins until the directory is updated. Other than that change, this is an exact copy of the stoneyridge SOC directory which will be updated in the follow-on commits in the patch train. TEST=None BUG=b:130804851 Signed-off-by: Martin Roth <martinroth@chromium.org> Change-Id: I6809bd1eea304f76dd9000c079b3ed09f94dbd3b Reviewed-on: https://review.coreboot.org/c/coreboot/+/32407 Reviewed-by: Richard Spiegel <richard.spiegel@silverbackltd.com> Reviewed-by: Angel Pons <th3fanbus@gmail.com> Reviewed-by: Edward O'Callaghan <quasisec@chromium.org> Reviewed-by: HAOUAS Elyes <ehaouas@noos.fr> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Diffstat (limited to 'src/soc/amd/picasso/acpi.c')
-rw-r--r--src/soc/amd/picasso/acpi.c406
1 files changed, 406 insertions, 0 deletions
diff --git a/src/soc/amd/picasso/acpi.c b/src/soc/amd/picasso/acpi.c
new file mode 100644
index 0000000000..d1ea24ffd5
--- /dev/null
+++ b/src/soc/amd/picasso/acpi.c
@@ -0,0 +1,406 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2012, 2017 Advanced Micro Devices, Inc.
+ * Copyright (C) 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * ACPI - create the Fixed ACPI Description Tables (FADT)
+ */
+
+#include <string.h>
+#include <console/console.h>
+#include <arch/acpi.h>
+#include <arch/acpigen.h>
+#include <device/pci_ops.h>
+#include <arch/ioapic.h>
+#include <cpu/x86/smm.h>
+#include <cbmem.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <amdblocks/acpimmio.h>
+#include <amdblocks/acpi.h>
+#include <soc/acpi.h>
+#include <soc/pci_devs.h>
+#include <soc/southbridge.h>
+#include <soc/northbridge.h>
+#include <soc/nvs.h>
+#include <soc/gpio.h>
+#include <version.h>
+
+unsigned long acpi_fill_madt(unsigned long current)
+{
+ /* create all subtables for processors */
+ current = acpi_create_madt_lapics(current);
+
+ /* Write Kern IOAPIC, only one */
+ current += acpi_create_madt_ioapic((acpi_madt_ioapic_t *)current,
+ CONFIG_MAX_CPUS, IO_APIC_ADDR, 0);
+
+ current += acpi_create_madt_ioapic((acpi_madt_ioapic_t *)current,
+ CONFIG_MAX_CPUS+1, IO_APIC2_ADDR, 24);
+
+ /* 0: mean bus 0--->ISA */
+ /* 0: PIC 0 */
+ /* 2: APIC 2 */
+ /* 5 mean: 0101 --> Edge-triggered, Active high */
+ current += acpi_create_madt_irqoverride((acpi_madt_irqoverride_t *)
+ current, 0, 0, 2, 0);
+ current += acpi_create_madt_irqoverride((acpi_madt_irqoverride_t *)
+ current, 0, 9, 9, 0xf);
+
+ /* create all subtables for processors */
+ current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *)current,
+ 0xff, 5, 1);
+ /* 1: LINT1 connect to NMI */
+
+ return current;
+}
+
+/*
+ * Reference section 5.2.9 Fixed ACPI Description Table (FADT)
+ * in the ACPI 3.0b specification.
+ */
+void acpi_create_fadt(acpi_fadt_t *fadt, acpi_facs_t *facs, void *dsdt)
+{
+ acpi_header_t *header = &(fadt->header);
+
+ printk(BIOS_DEBUG, "pm_base: 0x%04x\n", STONEYRIDGE_ACPI_IO_BASE);
+
+ /* Prepare the header */
+ memset((void *)fadt, 0, sizeof(acpi_fadt_t));
+ memcpy(header->signature, "FACP", 4);
+ header->length = sizeof(acpi_fadt_t);
+ header->revision = get_acpi_table_revision(FADT);
+ memcpy(header->oem_id, OEM_ID, 6);
+ memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
+ memcpy(header->asl_compiler_id, ASLC, 4);
+ header->asl_compiler_revision = asl_revision;
+
+ fadt->firmware_ctrl = (u32) facs;
+ fadt->dsdt = (u32) dsdt;
+ fadt->reserved = 0; /* reserved, should be 0 ACPI 3.0 */
+ fadt->preferred_pm_profile = FADT_PM_PROFILE;
+ fadt->sci_int = 9; /* IRQ 09 - ACPI SCI */
+
+ if (CONFIG(HAVE_SMI_HANDLER)) {
+ fadt->smi_cmd = APM_CNT;
+ fadt->acpi_enable = APM_CNT_ACPI_ENABLE;
+ fadt->acpi_disable = APM_CNT_ACPI_DISABLE;
+ fadt->s4bios_req = 0; /* Not supported */
+ fadt->pstate_cnt = 0; /* Not supported */
+ fadt->cst_cnt = 0; /* Not supported */
+ acpi_disable_sci();
+ } else {
+ fadt->smi_cmd = 0; /* disable system management mode */
+ fadt->acpi_enable = 0; /* unused if SMI_CMD = 0 */
+ fadt->acpi_disable = 0; /* unused if SMI_CMD = 0 */
+ fadt->s4bios_req = 0; /* unused if SMI_CMD = 0 */
+ fadt->pstate_cnt = 0; /* unused if SMI_CMD = 0 */
+ fadt->cst_cnt = 0x00; /* unused if SMI_CMD = 0 */
+ acpi_enable_sci();
+ }
+
+ fadt->pm1a_evt_blk = ACPI_PM_EVT_BLK;
+ fadt->pm1b_evt_blk = 0x0000;
+ fadt->pm1a_cnt_blk = ACPI_PM1_CNT_BLK;
+ fadt->pm1b_cnt_blk = 0x0000;
+ fadt->pm2_cnt_blk = 0x0000;
+ fadt->pm_tmr_blk = ACPI_PM_TMR_BLK;
+ fadt->gpe0_blk = ACPI_GPE0_BLK;
+ fadt->gpe1_blk = 0x0000; /* No gpe1 block */
+
+ fadt->pm1_evt_len = 4; /* 32 bits */
+ fadt->pm1_cnt_len = 2; /* 16 bits */
+ fadt->pm2_cnt_len = 0;
+ fadt->pm_tmr_len = 4; /* 32 bits */
+ fadt->gpe0_blk_len = 8; /* 64 bits */
+ fadt->gpe1_blk_len = 0;
+ fadt->gpe1_base = 0;
+
+ fadt->p_lvl2_lat = ACPI_FADT_C2_NOT_SUPPORTED;
+ fadt->p_lvl3_lat = ACPI_FADT_C3_NOT_SUPPORTED;
+ fadt->flush_size = 0; /* set to 0 if WBINVD is 1 in flags */
+ fadt->flush_stride = 0; /* set to 0 if WBINVD is 1 in flags */
+ fadt->duty_offset = 1; /* CLK_VAL bits 3:1 */
+ fadt->duty_width = 3; /* CLK_VAL bits 3:1 */
+ fadt->day_alrm = 0; /* 0x7d these have to be */
+ fadt->mon_alrm = 0; /* 0x7e added to cmos.layout */
+ fadt->century = 0; /* 0x7f to make rtc alarm work */
+ fadt->iapc_boot_arch = FADT_BOOT_ARCH; /* See table 5-10 */
+ fadt->res2 = 0; /* reserved, MUST be 0 ACPI 3.0 */
+ fadt->flags = ACPI_FADT_WBINVD | /* See table 5-10 ACPI 3.0a spec */
+ ACPI_FADT_C1_SUPPORTED |
+ ACPI_FADT_SLEEP_BUTTON |
+ ACPI_FADT_S4_RTC_WAKE |
+ ACPI_FADT_32BIT_TIMER |
+ ACPI_FADT_RESET_REGISTER |
+ ACPI_FADT_PCI_EXPRESS_WAKE |
+ ACPI_FADT_PLATFORM_CLOCK |
+ ACPI_FADT_S4_RTC_VALID |
+ ACPI_FADT_REMOTE_POWER_ON;
+
+ /* Format is from 5.2.3.1: Generic Address Structure */
+ /* reset_reg: see section 4.7.3.6 ACPI 3.0a spec */
+ /* 8 bit write of value 0x06 to 0xCF9 in IO space */
+ fadt->reset_reg.space_id = ACPI_ADDRESS_SPACE_IO;
+ fadt->reset_reg.bit_width = 8;
+ fadt->reset_reg.bit_offset = 0;
+ fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
+ fadt->reset_reg.addrl = SYS_RESET;
+ fadt->reset_reg.addrh = 0x0;
+
+ fadt->reset_value = 6;
+
+ fadt->ARM_boot_arch = 0; /* MUST be 0 ACPI 3.0 */
+ fadt->FADT_MinorVersion = 0; /* MUST be 0 ACPI 3.0 */
+
+ fadt->x_firmware_ctl_l = 0; /* set to 0 if firmware_ctrl is used */
+ fadt->x_firmware_ctl_h = 0;
+ fadt->x_dsdt_l = (u32) dsdt;
+ fadt->x_dsdt_h = 0;
+
+ fadt->x_pm1a_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
+ fadt->x_pm1a_evt_blk.bit_width = 32;
+ fadt->x_pm1a_evt_blk.bit_offset = 0;
+ fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
+ fadt->x_pm1a_evt_blk.addrl = ACPI_PM_EVT_BLK;
+ fadt->x_pm1a_evt_blk.addrh = 0x0;
+
+ fadt->x_pm1b_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
+ fadt->x_pm1b_evt_blk.bit_width = 0;
+ fadt->x_pm1b_evt_blk.bit_offset = 0;
+ fadt->x_pm1b_evt_blk.access_size = 0;
+ fadt->x_pm1b_evt_blk.addrl = 0x0;
+ fadt->x_pm1b_evt_blk.addrh = 0x0;
+
+
+ fadt->x_pm1a_cnt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
+ fadt->x_pm1a_cnt_blk.bit_width = 16;
+ fadt->x_pm1a_cnt_blk.bit_offset = 0;
+ fadt->x_pm1a_cnt_blk.access_size = 0;
+ fadt->x_pm1a_cnt_blk.addrl = ACPI_PM1_CNT_BLK;
+ fadt->x_pm1a_cnt_blk.addrh = 0x0;
+
+ fadt->x_pm1b_cnt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
+ fadt->x_pm1b_cnt_blk.bit_width = 0;
+ fadt->x_pm1b_cnt_blk.bit_offset = 0;
+ fadt->x_pm1b_cnt_blk.access_size = 0;
+ fadt->x_pm1b_cnt_blk.addrl = 0x0;
+ fadt->x_pm1b_cnt_blk.addrh = 0x0;
+
+ /*
+ * Note: Under this current AMD C state implementation, this is no
+ * longer used and should not be reported to OS.
+ */
+ fadt->x_pm2_cnt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
+ fadt->x_pm2_cnt_blk.bit_width = 0;
+ fadt->x_pm2_cnt_blk.bit_offset = 0;
+ fadt->x_pm2_cnt_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
+ fadt->x_pm2_cnt_blk.addrl = 0;
+ fadt->x_pm2_cnt_blk.addrh = 0x0;
+
+
+ fadt->x_pm_tmr_blk.space_id = ACPI_ADDRESS_SPACE_IO;
+ fadt->x_pm_tmr_blk.bit_width = 32;
+ fadt->x_pm_tmr_blk.bit_offset = 0;
+ fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
+ fadt->x_pm_tmr_blk.addrl = ACPI_PM_TMR_BLK;
+ fadt->x_pm_tmr_blk.addrh = 0x0;
+
+
+ fadt->x_gpe0_blk.space_id = ACPI_ADDRESS_SPACE_IO;
+ fadt->x_gpe0_blk.bit_width = 64; /* EventStatus + Event Enable */
+ fadt->x_gpe0_blk.bit_offset = 0;
+ fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
+ fadt->x_gpe0_blk.addrl = ACPI_GPE0_BLK;
+ fadt->x_gpe0_blk.addrh = 0x0;
+
+
+ fadt->x_gpe1_blk.space_id = ACPI_ADDRESS_SPACE_IO;
+ fadt->x_gpe1_blk.bit_width = 0;
+ fadt->x_gpe1_blk.bit_offset = 0;
+ fadt->x_gpe1_blk.access_size = 0;
+ fadt->x_gpe1_blk.addrl = 0;
+ fadt->x_gpe1_blk.addrh = 0x0;
+
+ header->checksum = acpi_checksum((void *)fadt, sizeof(acpi_fadt_t));
+}
+
+void generate_cpu_entries(struct device *device)
+{
+ int cores, cpu;
+
+ /* Stoney Ridge is single node, just report # of cores */
+ cores = pci_read_config32(SOC_NB_DEV, NB_CAPABILITIES2) & CMP_CAP_MASK;
+ cores++; /* number of cores is CmpCap+1 */
+
+ printk(BIOS_DEBUG, "ACPI \\_PR report %d core(s)\n", cores);
+
+ /* Generate BSP \_PR.P000 */
+ acpigen_write_processor(0, ACPI_GPE0_BLK, 6);
+ acpigen_pop_len();
+
+ /* Generate AP \_PR.Pxxx */
+ for (cpu = 1; cpu < cores; cpu++) {
+ acpigen_write_processor(cpu, 0, 0);
+ acpigen_pop_len();
+ }
+}
+
+unsigned long southbridge_write_acpi_tables(struct device *device,
+ unsigned long current,
+ struct acpi_rsdp *rsdp)
+{
+ return acpi_write_hpet(device, current, rsdp);
+}
+
+static void acpi_create_gnvs(struct global_nvs_t *gnvs)
+{
+ /* Clear out GNVS. */
+ memset(gnvs, 0, sizeof(*gnvs));
+
+ if (CONFIG(CONSOLE_CBMEM))
+ gnvs->cbmc = (uintptr_t)cbmem_find(CBMEM_ID_CONSOLE);
+
+ if (CONFIG(CHROMEOS)) {
+ /* Initialize Verified Boot data */
+ chromeos_init_chromeos_acpi(&gnvs->chromeos);
+ gnvs->chromeos.vbt2 = ACTIVE_ECFW_RO;
+ }
+
+ /* Set unknown wake source */
+ gnvs->pm1i = ~0ULL;
+ gnvs->gpei = ~0ULL;
+
+ /* CPU core count */
+ gnvs->pcnt = dev_count_cpu();
+}
+
+void southbridge_inject_dsdt(struct device *device)
+{
+ struct global_nvs_t *gnvs;
+
+ gnvs = cbmem_find(CBMEM_ID_ACPI_GNVS);
+
+ if (gnvs) {
+ acpi_create_gnvs(gnvs);
+
+ /* Add it to DSDT */
+ acpigen_write_scope("\\");
+ acpigen_write_name_dword("NVSA", (uintptr_t)gnvs);
+ acpigen_pop_len();
+ }
+}
+
+static void acpigen_soc_get_gpio_in_local5(uintptr_t addr)
+{
+ /*
+ * Store (\_SB.GPR2 (addr), Local5)
+ * \_SB.GPR2 is used to read control byte 2 from control register.
+ * / It is defined in gpio_lib.asl.
+ */
+ acpigen_write_store();
+ acpigen_emit_namestring("\\_SB.GPR2");
+ acpigen_write_integer(addr);
+ acpigen_emit_byte(LOCAL5_OP);
+}
+
+static int acpigen_soc_get_gpio_val(unsigned int gpio_num, uint32_t mask)
+{
+ if (gpio_num >= SOC_GPIO_TOTAL_PINS) {
+ printk(BIOS_WARNING, "Warning: Pin %d should be smaller than"
+ " %d\n", gpio_num, SOC_GPIO_TOTAL_PINS);
+ return -1;
+ }
+ uintptr_t addr = (uintptr_t) gpio_get_address(gpio_num);
+
+ acpigen_soc_get_gpio_in_local5(addr);
+
+ /* If (And (Local5, mask)) */
+ acpigen_write_if_and(LOCAL5_OP, mask);
+
+ /* Store (One, Local0) */
+ acpigen_write_store_ops(ONE_OP, LOCAL0_OP);
+
+ acpigen_pop_len(); /* If */
+
+ /* Else */
+ acpigen_write_else();
+
+ /* Store (Zero, Local0) */
+ acpigen_write_store_ops(ZERO_OP, LOCAL0_OP);
+
+ acpigen_pop_len(); /* Else */
+
+ return 0;
+}
+
+static int acpigen_soc_set_gpio_val(unsigned int gpio_num, uint32_t val)
+{
+ if (gpio_num >= SOC_GPIO_TOTAL_PINS) {
+ printk(BIOS_WARNING, "Warning: Pin %d should be smaller than"
+ " %d\n", gpio_num, SOC_GPIO_TOTAL_PINS);
+ return -1;
+ }
+ uintptr_t addr = (uintptr_t) gpio_get_address(gpio_num);
+
+ /* Store (0x40, Local0) */
+ acpigen_write_store();
+ acpigen_write_integer(GPIO_PIN_OUT);
+ acpigen_emit_byte(LOCAL0_OP);
+
+ acpigen_soc_get_gpio_in_local5(addr);
+
+ if (val) {
+ /* Or (Local5, GPIO_PIN_OUT, Local5) */
+ acpigen_write_or(LOCAL5_OP, LOCAL0_OP, LOCAL5_OP);
+ } else {
+ /* Not (GPIO_PIN_OUT, Local6) */
+ acpigen_write_not(LOCAL0_OP, LOCAL6_OP);
+
+ /* And (Local5, Local6, Local5) */
+ acpigen_write_and(LOCAL5_OP, LOCAL6_OP, LOCAL5_OP);
+ }
+
+ /*
+ * SB.GPW2 (addr, Local5)
+ * \_SB.GPW2 is used to write control byte in control register
+ * / byte 2. It is defined in gpio_lib.asl.
+ */
+ acpigen_emit_namestring("\\_SB.GPW2");
+ acpigen_write_integer(addr);
+ acpigen_emit_byte(LOCAL5_OP);
+
+ return 0;
+}
+
+int acpigen_soc_read_rx_gpio(unsigned int gpio_num)
+{
+ return acpigen_soc_get_gpio_val(gpio_num, GPIO_PIN_IN);
+}
+
+int acpigen_soc_get_tx_gpio(unsigned int gpio_num)
+{
+ return acpigen_soc_get_gpio_val(gpio_num, GPIO_PIN_OUT);
+}
+
+int acpigen_soc_set_tx_gpio(unsigned int gpio_num)
+{
+ return acpigen_soc_set_gpio_val(gpio_num, 1);
+}
+
+int acpigen_soc_clear_tx_gpio(unsigned int gpio_num)
+{
+ return acpigen_soc_set_gpio_val(gpio_num, 0);
+}