summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/soc/intel/baytrail/baytrail/iomap.h1
-rw-r--r--src/soc/intel/baytrail/southcluster.c27
2 files changed, 28 insertions, 0 deletions
diff --git a/src/soc/intel/baytrail/baytrail/iomap.h b/src/soc/intel/baytrail/baytrail/iomap.h
index fa341058fb..d46a0feb9e 100644
--- a/src/soc/intel/baytrail/baytrail/iomap.h
+++ b/src/soc/intel/baytrail/baytrail/iomap.h
@@ -31,6 +31,7 @@
#define PUNIT_BASE_ADDRESS 0xfed05000
#define RCBA_BASE_ADDRESS 0xfed1c000
#define HPET_BASE_ADDRESS 0xfed00000
+#define TEMP_BASE_ADDRESS 0xfd000000
/* IO Port base */
#define ACPI_BASE_ADDRESS 0x0400
diff --git a/src/soc/intel/baytrail/southcluster.c b/src/soc/intel/baytrail/southcluster.c
index 42349fac4e..c71ab7ea58 100644
--- a/src/soc/intel/baytrail/southcluster.c
+++ b/src/soc/intel/baytrail/southcluster.c
@@ -238,10 +238,37 @@ static inline void set_d3hot_bits(device_t dev, int offset)
pci_write_config8(dev, offset + 4, reg8);
}
+/* Parts of the audio subsystem are powered by the HDA device. Therefore, one
+ * cannot put HDA into D3Hot. Instead perform this workaround to make some of
+ * the audio paths work for LPE audio. */
+static void hda_work_around(device_t dev)
+{
+ unsigned long gctl = TEMP_BASE_ADDRESS + 0x8;
+
+ /* Need to set magic register 0x43 to 0xd7 in config space. */
+ pci_write_config8(dev, 0x43, 0xd7);
+
+ /* Need to set bit 0 of GCTL to take the device out of reset. However,
+ * that requires setting up the 64-bit BAR. */
+ pci_write_config32(dev, PCI_BASE_ADDRESS_0, TEMP_BASE_ADDRESS);
+ pci_write_config32(dev, PCI_BASE_ADDRESS_1, 0);
+ pci_write_config8(dev, PCI_COMMAND, PCI_COMMAND_MEMORY);
+ write32(gctl, read32(gctl) | 0x1);
+ pci_write_config8(dev, PCI_COMMAND, 0);
+ pci_write_config32(dev, PCI_BASE_ADDRESS_0, 0);
+}
+
static int place_device_in_d3hot(device_t dev)
{
unsigned offset;
+ /* Parts of the HDA block are used for LPE audio as well.
+ * Therefore assume the HDA will never be put into D3Hot. */
+ if (dev->path.pci.devfn == PCI_DEVFN(HDA_DEV, HDA_FUNC)) {
+ hda_work_around(dev);
+ return 0;
+ }
+
offset = pci_find_capability(dev, PCI_CAP_ID_PM);
if (offset != 0) {