From e8e986b0ba52bbfc9923d71009fbd31e749ca43f Mon Sep 17 00:00:00 2001 From: Duncan Laurie Date: Wed, 14 May 2014 14:12:53 -0700 Subject: [PATCH] broadwell: Add ramstage driver for ADSP This provides a driver for the ADSP (aka SST -- smart sound tech) that is built into the southbridge in haswell/broadwell. This block shares pins with HDA so they cannot both be enabled at the same time so if HDA is disabled the pins are routed to the ADSP block. The ADSP device needs to be put into ACPI mode so a new block of BARs and enable status is added to the device_nvs structure. The ACPI _HID is expected to be different for haswell and broadwell so a new ACPI method is added to check if the PCH is WildcatPoint and then used in the base ADSP ACPI device definition. BUG=chrome-os-partner:28234 TEST=Build and boot on samus with ADSP device enabled and check firmware log for HDA disabled message and that the HDA PCI device is gone. With sio_acpi_mode=1 the ADSP PCI device is also gone and is instead enumerated by ACPI. Change-Id: I73d950725ce29d44a5da9aab00c7f784ba63f2d1 Signed-off-by: Duncan Laurie Reviewed-on: https://chromium-review.googlesource.com/199892 Reviewed-by: Aaron Durbin --- src/soc/intel/broadwell/Makefile.inc | 1 + src/soc/intel/broadwell/acpi/adsp.asl | 63 ++++++++ src/soc/intel/broadwell/acpi/device_nvs.asl | 3 + src/soc/intel/broadwell/acpi/lpc.asl | 4 +- src/soc/intel/broadwell/acpi/pch.asl | 18 +++ src/soc/intel/broadwell/adsp.c | 152 ++++++++++++++++++ src/soc/intel/broadwell/broadwell/adsp.h | 56 +++++++ .../intel/broadwell/broadwell/device_nvs.h | 7 +- src/soc/intel/broadwell/hda.c | 25 +++ src/soc/intel/broadwell/pch.c | 1 + 10 files changed, 326 insertions(+), 4 deletions(-) create mode 100644 src/soc/intel/broadwell/acpi/adsp.asl create mode 100644 src/soc/intel/broadwell/adsp.c create mode 100644 src/soc/intel/broadwell/broadwell/adsp.h diff --git a/src/soc/intel/broadwell/Makefile.inc b/src/soc/intel/broadwell/Makefile.inc index 88fe92fad8..072ab1ff07 100644 --- a/src/soc/intel/broadwell/Makefile.inc +++ b/src/soc/intel/broadwell/Makefile.inc @@ -10,6 +10,7 @@ subdirs-y += ../../../cpu/intel/microcode subdirs-y += ../../../cpu/intel/turbo ramstage-y += acpi.c +ramstage-y += adsp.c ramstage-y += chip.c ramstage-y += cpu.c ramstage-y += elog.c diff --git a/src/soc/intel/broadwell/acpi/adsp.asl b/src/soc/intel/broadwell/acpi/adsp.asl new file mode 100644 index 0000000000..ba38569f8b --- /dev/null +++ b/src/soc/intel/broadwell/acpi/adsp.asl @@ -0,0 +1,63 @@ +/* + * This file is part of the coreboot project. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +Device (ADSP) +{ + Method (_HID, 0, Serialized) + { + If (\ISWP ()) { + // WildcatPoint + Return ("INT3438") + } + + // LynxPoint-LP + Return ("INT33C2") + } + Name (_UID, 1) + Name (_DDN, "Intel Smart Sound Technology") + + Name (RBUF, ResourceTemplate () + { + Memory32Fixed (ReadWrite, 0x00000000, 0x00100000, BAR0) + Memory32Fixed (ReadWrite, 0x00000000, 0x00001000, BAR1) + Interrupt (ResourceConsumer, Level, ActiveLow, Shared, , , ) {3} + }) + + Method (_CRS, 0, NotSerialized) + { + // Update BAR0 address and length if set in NVS + If (LNotEqual (\S8B0, Zero)) { + CreateDwordField (^RBUF, ^BAR0._BAS, B8A0) + CreateDwordField (^RBUF, ^BAR1._BAS, B8A1) + Store (\S8B0, B8A0) + Store (\S8B1, B8A1) + } + + Return (RBUF) + } + + Method (_STA, 0, NotSerialized) + { + If (LEqual (\S8EN, 0)) { + Return (0x0) + } Else { + Return (0xF) + } + } +} diff --git a/src/soc/intel/broadwell/acpi/device_nvs.asl b/src/soc/intel/broadwell/acpi/device_nvs.asl index d5af2e8cc9..1d2aa78edb 100644 --- a/src/soc/intel/broadwell/acpi/device_nvs.asl +++ b/src/soc/intel/broadwell/acpi/device_nvs.asl @@ -27,6 +27,7 @@ S4EN, 8, // SPI1 Enable S5EN, 8, // UART0 Enable S6EN, 8, // UART1 Enable S7EN, 8, // SDIO Enable +S8EN, 8, // ADSP Enable /* BAR 0 */ @@ -38,6 +39,7 @@ S4B0, 32, // SPI1 BAR0 S5B0, 32, // UART0 BAR0 S6B0, 32, // UART1 BAR0 S7B0, 32, // SDIO BAR0 +S8B0, 32, // ADSP BAR0 /* BAR 1 */ @@ -49,3 +51,4 @@ S4B1, 32, // SPI1 BAR1 S5B1, 32, // UART0 BAR1 S6B1, 32, // UART1 BAR1 S7B1, 32, // SDIO BAR1 +S8B1, 32, // ADSP BAR1 diff --git a/src/soc/intel/broadwell/acpi/lpc.asl b/src/soc/intel/broadwell/acpi/lpc.asl index 2f27d9b252..ae634a3fd6 100644 --- a/src/soc/intel/broadwell/acpi/lpc.asl +++ b/src/soc/intel/broadwell/acpi/lpc.asl @@ -27,10 +27,12 @@ Device (LPCB) OperationRegion(LPC0, PCI_Config, 0x00, 0x100) Field (LPC0, AnyAcc, NoLock, Preserve) { + Offset (0x02), + PDID, 16, // Device ID Offset (0x40), PMBS, 16, // PMBASE Offset (0x48), - GPBS, 16, // GPIOBASE + GPBS, 16, // GPIOBASE Offset (0x60), // Interrupt Routing Registers PRTA, 8, PRTB, 8, diff --git a/src/soc/intel/broadwell/acpi/pch.asl b/src/soc/intel/broadwell/acpi/pch.asl index c48449363e..e40c04269a 100644 --- a/src/soc/intel/broadwell/acpi/pch.asl +++ b/src/soc/intel/broadwell/acpi/pch.asl @@ -39,11 +39,29 @@ Scope (\) , 5, HPTE, 1, // Address Enable } + + /* + * Check PCH type + * Return 1 if PCH is WildcatPoint + * Return 0 if PCH is LynxPoint + */ + Method (ISWP) + { + And (\_SB.PCI0.LPCB.PDID, 0xfff0, Local0) + If (LEqual (Local0, 0x9cc0)) { + Return (1) + } Else { + Return (0) + } + } } // High Definition Audio (Azalia) 0:1b.0 #include "hda.asl" +// ADSP/SST 0:13.0 +#include "adsp.asl" + // PCI Express Ports 0:1c.x #include "pcie.asl" diff --git a/src/soc/intel/broadwell/adsp.c b/src/soc/intel/broadwell/adsp.c new file mode 100644 index 0000000000..2a6dc1744a --- /dev/null +++ b/src/soc/intel/broadwell/adsp.c @@ -0,0 +1,152 @@ +/* + * This file is part of the coreboot project. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void adsp_init(struct device *dev) +{ + config_t *config = dev->chip_info; + struct resource *bar0, *bar1; + u32 tmp32; + + /* Ensure memory and bus master are enabled */ + tmp32 = pci_read_config32(dev, PCI_COMMAND); + tmp32 |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; + pci_write_config32(dev, PCI_COMMAND, tmp32); + + /* Find BAR0 and BAR1 */ + bar0 = find_resource(dev, PCI_BASE_ADDRESS_0); + if (!bar0) + return; + bar1 = find_resource(dev, PCI_BASE_ADDRESS_1); + if (!bar1) + return; + + /* + * Set LTR value in DSP shim LTR control register to 3ms + * SNOOP_REQ[13]=1b SNOOP_SCALE[12:10]=100b (1ms) SNOOP_VAL[9:0]=3h + */ + tmp32 = pch_is_wpt() ? ADSP_SHIM_BASE_WPT : ADSP_SHIM_BASE_LPT; + write32(bar0->base + tmp32 + ADSP_SHIM_LTRC, ADSP_SHIM_LTRC_VALUE); + + /* Program VDRTCTL2 D19:F0:A8[31:0] = 0x00000fff */ + pci_write_config32(dev, ADSP_PCI_VDRTCTL2, ADSP_VDRTCTL2_VALUE); + + /* Program ADSP IOBP VDLDAT1 to 0x040100 */ + pch_iobp_write(ADSP_IOBP_VDLDAT1, ADSP_VDLDAT1_VALUE); + + /* Set D3 Power Gating Enable in D19:F0:A0 based on PCH type */ + tmp32 = pci_read_config32(dev, ADSP_PCI_VDRTCTL0); + if (pch_is_wpt()) { + tmp32 &= ~ADSP_VDRTCTL0_D3PGD_WPT; + tmp32 &= ~ADSP_VDRTCTL0_D3SRAMPGD_WPT; + } else { + tmp32 &= ~ADSP_VDRTCTL0_D3PGD_LPT; + tmp32 &= ~ADSP_VDRTCTL0_D3SRAMPGD_LPT; + } + pci_write_config32(dev, ADSP_PCI_VDRTCTL0, tmp32); + + /* Set PSF Snoop to SA, RCBA+0x3350[10]=1b */ + RCBA32_OR(0x3350, (1 << 10)); + + /* Set DSP IOBP PMCTL 0x1e0=0x3f */ + pch_iobp_write(ADSP_IOBP_PMCTL, ADSP_PMCTL_VALUE); + + if (config->sio_acpi_mode) { + /* Configure for ACPI mode */ + global_nvs_t *gnvs; + + printk(BIOS_INFO, "ADSP: Enable ACPI Mode IRQ3\n"); + + /* Find ACPI NVS to update BARs */ + gnvs = (global_nvs_t *)cbmem_find(CBMEM_ID_ACPI_GNVS); + if (!gnvs) { + printk(BIOS_ERR, "Unable to locate Global NVS\n"); + return; + } + + /* Save BAR0 and BAR1 to ACPI NVS */ + gnvs->dev.bar0[SIO_NVS_ADSP] = (u32)bar0->base; + gnvs->dev.bar1[SIO_NVS_ADSP] = (u32)bar1->base; + gnvs->dev.enable[SIO_NVS_ADSP] = 1; + + /* Set PCI Config Disable Bit */ + pch_iobp_update(ADSP_IOBP_PCICFGCTL, ~0, ADSP_PCICFGCTL_PCICD); + + /* Set interrupt de-assert/assert opcode override to IRQ3 */ + pch_iobp_write(ADSP_IOBP_VDLDAT2, ADSP_IOBP_ACPI_IRQ3); + + /* Enable IRQ3 in RCBA */ + RCBA32_OR(ACPIIRQEN, ADSP_ACPI_IRQEN); + + /* Set ACPI Interrupt Enable Bit */ + pch_iobp_update(ADSP_IOBP_PCICFGCTL, ~ADSP_PCICFGCTL_SPCBAD, + ADSP_PCICFGCTL_ACPIIE); + + /* Put ADSP in D3hot */ + tmp32 = read32(bar1->base + PCH_PCS); + tmp32 |= PCH_PCS_PS_D3HOT; + write32(bar1->base + PCH_PCS, tmp32); + } else { + printk(BIOS_INFO, "ADSP: Enable PCI Mode IRQ23\n"); + + /* Configure for PCI mode */ + pci_write_config32(dev, PCI_INTERRUPT_LINE, ADSP_PCI_IRQ); + + /* Clear ACPI Interrupt Enable Bit */ + pch_iobp_update(ADSP_IOBP_PCICFGCTL, + ~(ADSP_PCICFGCTL_SPCBAD | ADSP_PCICFGCTL_ACPIIE), 0); + } +} + +static struct device_operations adsp_ops = { + .read_resources = &pci_dev_read_resources, + .set_resources = &pci_dev_set_resources, + .enable_resources = &pci_dev_enable_resources, + .init = &adsp_init, + .ops_pci = &broadwell_pci_ops, +}; + +static const unsigned short pci_device_ids[] = { + 0x9c36, /* LynxPoint */ + 0x9cb6, /* WildcatPoint */ + 0 +}; + +static const struct pci_driver pch_adsp __pci_driver = { + .ops = &adsp_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .devices = pci_device_ids, +}; + diff --git a/src/soc/intel/broadwell/broadwell/adsp.h b/src/soc/intel/broadwell/broadwell/adsp.h new file mode 100644 index 0000000000..747a123579 --- /dev/null +++ b/src/soc/intel/broadwell/broadwell/adsp.h @@ -0,0 +1,56 @@ +/* + * This file is part of the coreboot project. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _BROADWELL_ADSP_H_ +#define _BROADWELL_ADSP_H_ + +#define ADSP_PCI_IRQ 23 +#define ADSP_ACPI_IRQ 3 +#define ADSP_ACPI_IRQEN (1 << 3) + +#define ADSP_SHIM_BASE_LPT 0xe7000 +#define ADSP_SHIM_BASE_WPT 0xfb000 +#define ADSP_SHIM_LTRC 0xe0 +#define ADSP_SHIM_LTRC_VALUE 0x3003 +#define ADSP_SHIM_IMC 0x28 +#define ADSP_SHIM_IPCD 0x40 + +#define ADSP_PCI_VDRTCTL0 0xa0 +#define ADSP_VDRTCTL0_D3PGD_LPT (1 << 1) +#define ADSP_VDRTCTL0_D3PGD_WPT (1 << 0) +#define ADSP_VDRTCTL0_D3SRAMPGD_LPT (1 << 2) +#define ADSP_VDRTCTL0_D3SRAMPGD_WPT (1 << 1) +#define ADSP_PCI_VDRTCTL1 0xa4 +#define ADSP_PCI_VDRTCTL2 0xa8 +#define ADSP_VDRTCTL2_VALUE 0x00000fff + +#define ADSP_IOBP_VDLDAT1 0xd7000624 +#define ADSP_VDLDAT1_VALUE 0x00040100 +#define ADSP_IOBP_VDLDAT2 0xd7000628 +#define ADSP_IOBP_ACPI_IRQ3 0xd9d8 +#define ADSP_IOBP_ACPI_IRQ3I 0xd8d9 +#define ADSP_IOBP_ACPI_IRQ4 0xdbda +#define ADSP_IOBP_PMCTL 0xd70001e0 +#define ADSP_PMCTL_VALUE 0x3f +#define ADSP_IOBP_PCICFGCTL 0xd7000500 +#define ADSP_PCICFGCTL_PCICD (1 << 0) +#define ADSP_PCICFGCTL_ACPIIE (1 << 1) +#define ADSP_PCICFGCTL_SPCBAD (1 << 7) + +#endif diff --git a/src/soc/intel/broadwell/broadwell/device_nvs.h b/src/soc/intel/broadwell/broadwell/device_nvs.h index f10f28d35e..7dab40da6a 100644 --- a/src/soc/intel/broadwell/broadwell/device_nvs.h +++ b/src/soc/intel/broadwell/broadwell/device_nvs.h @@ -33,11 +33,12 @@ #define SIO_NVS_UART0 5 #define SIO_NVS_UART1 6 #define SIO_NVS_SDIO 7 +#define SIO_NVS_ADSP 8 typedef struct { - u8 enable[8]; - u32 bar0[8]; - u32 bar1[8]; + u8 enable[9]; + u32 bar0[9]; + u32 bar1[9]; } __attribute__((packed)) device_nvs_t; #endif diff --git a/src/soc/intel/broadwell/hda.c b/src/soc/intel/broadwell/hda.c index 9a9225b479..80caa2c2eb 100644 --- a/src/soc/intel/broadwell/hda.c +++ b/src/soc/intel/broadwell/hda.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -134,11 +135,35 @@ static void hda_init(struct device *dev) } } +static void hda_enable(struct device *dev) +{ + u32 reg32; + + if (!dev->enabled) { + /* Route I/O buffers to ADSP function */ + reg32 = pci_read_config32(dev, 0x42); + reg32 |= (1 << 7) | (1 << 6); + pci_write_config32(dev, 0x42, reg32); + + printk(BIOS_INFO, "HDA disabled, I/O buffers routed to ADSP\n"); + + /* Ensure memory, io, and bus master are all disabled */ + reg32 = pci_read_config32(dev, PCI_COMMAND); + reg32 &= ~(PCI_COMMAND_MASTER | + PCI_COMMAND_MEMORY | PCI_COMMAND_IO); + pci_write_config32(dev, PCI_COMMAND, reg32); + + /* Disable this device */ + pch_disable_devfn(dev); + } +} + static struct device_operations hda_ops = { .read_resources = &pci_dev_read_resources, .set_resources = &pci_dev_set_resources, .enable_resources = &pci_dev_enable_resources, .init = &hda_init, + .enable = &hda_enable, .ops_pci = &broadwell_pci_ops, }; diff --git a/src/soc/intel/broadwell/pch.c b/src/soc/intel/broadwell/pch.c index efb109e832..82390a470b 100644 --- a/src/soc/intel/broadwell/pch.c +++ b/src/soc/intel/broadwell/pch.c @@ -187,6 +187,7 @@ void broadwell_pch_enable_dev(device_t dev) switch (PCI_SLOT(dev->path.pci.devfn)) { case PCH_DEV_SLOT_PCIE: case PCH_DEV_SLOT_EHCI: + case PCH_DEV_SLOT_HDA: return; }