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 <dlaurie@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/199892 Reviewed-by: Aaron Durbin <adurbin@chromium.org>
This commit is contained in:
parent
f8c54c70f1
commit
e8e986b0ba
10 changed files with 326 additions and 4 deletions
|
|
@ -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
|
||||
|
|
|
|||
63
src/soc/intel/broadwell/acpi/adsp.asl
Normal file
63
src/soc/intel/broadwell/acpi/adsp.asl
Normal file
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
152
src/soc/intel/broadwell/adsp.c
Normal file
152
src/soc/intel/broadwell/adsp.c
Normal file
|
|
@ -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 <cbmem.h>
|
||||
#include <console/console.h>
|
||||
#include <device/device.h>
|
||||
#include <device/pci.h>
|
||||
#include <device/pci_ids.h>
|
||||
#include <device/pci_ops.h>
|
||||
#include <arch/io.h>
|
||||
#include <delay.h>
|
||||
#include <broadwell/adsp.h>
|
||||
#include <broadwell/device_nvs.h>
|
||||
#include <broadwell/iobp.h>
|
||||
#include <broadwell/nvs.h>
|
||||
#include <broadwell/pch.h>
|
||||
#include <broadwell/ramstage.h>
|
||||
#include <broadwell/rcba.h>
|
||||
#include <chip.h>
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
56
src/soc/intel/broadwell/broadwell/adsp.h
Normal file
56
src/soc/intel/broadwell/broadwell/adsp.h
Normal file
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <arch/io.h>
|
||||
#include <delay.h>
|
||||
#include <soc/intel/common/hda_verb.h>
|
||||
#include <broadwell/pch.h>
|
||||
#include <broadwell/ramstage.h>
|
||||
#include <broadwell/rcba.h>
|
||||
|
||||
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue