diff --git a/src/southbridge/intel/lynxpoint/pch.c b/src/southbridge/intel/lynxpoint/pch.c index cc3718d444..58c68cdf05 100644 --- a/src/southbridge/intel/lynxpoint/pch.c +++ b/src/southbridge/intel/lynxpoint/pch.c @@ -83,10 +83,18 @@ u16 get_gpiobase(void) #ifndef __SMM__ -/* Set bit in Function Disble register to hide this device */ -static void pch_hide_devfn(unsigned devfn) +/* Put device in D3Hot Power State */ +static void pch_enable_d3hot(device_t dev) { - switch (devfn) { + u32 reg32 = pci_read_config32(dev, PCH_PCS); + reg32 |= PCH_PCS_PS_D3HOT; + pci_write_config32(dev, PCH_PCS, reg32); +} + +/* Set bit in Function Disble register to hide this device */ +static void pch_hide_devfn(device_t dev) +{ + switch (dev->path.pci.devfn) { case PCI_DEVFN(19, 0): /* Audio DSP */ RCBA32_OR(FD, PCH_DISABLE_ADSPD); break; @@ -94,24 +102,31 @@ static void pch_hide_devfn(unsigned devfn) RCBA32_OR(FD, PCH_DISABLE_XHCI); break; case PCI_DEVFN(21, 0): /* DMA */ + pch_enable_d3hot(dev); pch_iobp_update(SIO_IOBP_FUNCDIS0, ~0UL, SIO_IOBP_FUNCDIS_DIS); break; case PCI_DEVFN(21, 1): /* I2C0 */ + pch_enable_d3hot(dev); pch_iobp_update(SIO_IOBP_FUNCDIS1, ~0UL, SIO_IOBP_FUNCDIS_DIS); break; case PCI_DEVFN(21, 2): /* I2C1 */ + pch_enable_d3hot(dev); pch_iobp_update(SIO_IOBP_FUNCDIS2, ~0UL, SIO_IOBP_FUNCDIS_DIS); break; case PCI_DEVFN(21, 3): /* SPI0 */ + pch_enable_d3hot(dev); pch_iobp_update(SIO_IOBP_FUNCDIS3, ~0UL, SIO_IOBP_FUNCDIS_DIS); break; case PCI_DEVFN(21, 4): /* SPI1 */ + pch_enable_d3hot(dev); pch_iobp_update(SIO_IOBP_FUNCDIS4, ~0UL, SIO_IOBP_FUNCDIS_DIS); break; case PCI_DEVFN(21, 5): /* UART0 */ + pch_enable_d3hot(dev); pch_iobp_update(SIO_IOBP_FUNCDIS5, ~0UL, SIO_IOBP_FUNCDIS_DIS); break; case PCI_DEVFN(21, 6): /* UART1 */ + pch_enable_d3hot(dev); pch_iobp_update(SIO_IOBP_FUNCDIS6, ~0UL, SIO_IOBP_FUNCDIS_DIS); break; case PCI_DEVFN(22, 0): /* MEI #1 */ @@ -127,6 +142,7 @@ static void pch_hide_devfn(unsigned devfn) RCBA32_OR(FD2, PCH_DISABLE_KT); break; case PCI_DEVFN(23, 0): /* SDIO */ + pch_enable_d3hot(dev); pch_iobp_update(SIO_IOBP_FUNCDIS7, ~0UL, SIO_IOBP_FUNCDIS_DIS); break; case PCI_DEVFN(25, 0): /* Gigabit Ethernet */ @@ -146,7 +162,7 @@ static void pch_hide_devfn(unsigned devfn) case PCI_DEVFN(28, 5): /* PCI Express Root Port 6 */ case PCI_DEVFN(28, 6): /* PCI Express Root Port 7 */ case PCI_DEVFN(28, 7): /* PCI Express Root Port 8 */ - RCBA32_OR(FD, PCH_DISABLE_PCIE(PCI_FUNC(devfn))); + RCBA32_OR(FD, PCH_DISABLE_PCIE(PCI_FUNC(dev->path.pci.devfn))); break; case PCI_DEVFN(29, 0): /* EHCI #1 */ RCBA32_OR(FD, PCH_DISABLE_EHCI1); @@ -404,7 +420,7 @@ static void pch_pcie_enable(device_t dev) new_rpfn |= RPFN_HIDE(PCI_FUNC(dev->path.pci.devfn)); /* Hide this device if possible */ - pch_hide_devfn(dev->path.pci.devfn); + pch_hide_devfn(dev); } else { int fn; @@ -463,7 +479,7 @@ void pch_enable(device_t dev) pci_write_config32(dev, PCI_COMMAND, reg32); /* Hide this device if possible */ - pch_hide_devfn(dev->path.pci.devfn); + pch_hide_devfn(dev); } else { /* Enable SERR */ reg32 = pci_read_config32(dev, PCI_COMMAND); diff --git a/src/southbridge/intel/lynxpoint/pch.h b/src/southbridge/intel/lynxpoint/pch.h index ca1d8b1b68..b01fdc04cb 100644 --- a/src/southbridge/intel/lynxpoint/pch.h +++ b/src/southbridge/intel/lynxpoint/pch.h @@ -218,6 +218,10 @@ void set_gpio(int gpio_num, int value); #define SEE (1 << 1) #define PERE (1 << 0) +/* Power Management Control and Status */ +#define PCH_PCS 0x84 +#define PCH_PCS_PS_D3HOT 3 + #define PCH_EHCI1_DEV PCI_DEV(0, 0x1d, 0) #define PCH_EHCI2_DEV PCI_DEV(0, 0x1a, 0) #define PCH_ME_DEV PCI_DEV(0, 0x16, 0) @@ -377,6 +381,8 @@ void set_gpio(int gpio_num, int value); #define SIO_ID_UART1 6 /* D21:F6 */ #define SIO_ID_SDIO 7 /* D23:F0 */ +#define SIO_REG_PPR_CLOCK 0x800 +#define SIO_REG_PPR_CLOCK_EN (1 << 0) #define SIO_REG_PPR_RST 0x804 #define SIO_REG_PPR_RST_ASSERT 0x3 #define SIO_REG_PPR_GEN 0x808 diff --git a/src/southbridge/intel/lynxpoint/serialio.c b/src/southbridge/intel/lynxpoint/serialio.c index 11d6a36b44..8257cc2f6f 100644 --- a/src/southbridge/intel/lynxpoint/serialio.c +++ b/src/southbridge/intel/lynxpoint/serialio.c @@ -29,6 +29,22 @@ #include "pch.h" #include "nvs.h" +/* Set D3Hot Power State in ACPI mode */ +static void serialio_enable_d3hot(struct device *dev) +{ + u32 reg32 = pci_read_config32(dev, PCH_PCS); + reg32 |= PCH_PCS_PS_D3HOT; + pci_write_config32(dev, PCH_PCS, reg32); +} + +/* Enable clock in PCI mode */ +static void serialio_enable_clock(struct resource *bar0) +{ + u32 reg32 = read32(bar0->base + SIO_REG_PPR_CLOCK); + reg32 |= SIO_REG_PPR_CLOCK_EN; + write32(bar0->base + SIO_REG_PPR_CLOCK, reg32); +} + /* Put Serial IO D21:F0-F6 device into desired mode. */ static void serialio_d21_mode(int sio_index, int int_pin, int acpi_mode) { @@ -143,9 +159,15 @@ static void serialio_init(struct device *dev) struct southbridge_intel_lynxpoint_config *config = dev->chip_info; struct resource *bar0, *bar1; int sio_index = -1; + u32 reg32; printk(BIOS_DEBUG, "Initializing Serial IO device\n"); + /* Ensure memory and bus master are enabled */ + reg32 = pci_read_config32(dev, PCI_COMMAND); + reg32 |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; + pci_write_config32(dev, PCI_COMMAND, reg32); + /* Find BAR0 and BAR1 */ bar0 = find_resource(dev, PCI_BASE_ADDRESS_0); if (!bar0) @@ -154,6 +176,11 @@ static void serialio_init(struct device *dev) if (!bar1) return; + if (!config->sio_acpi_mode) + serialio_enable_clock(bar0); + else if (dev->path.pci.devfn != PCI_DEVFN(21, 0)) + serialio_enable_d3hot(dev); /* all but SDMA */ + switch (dev->path.pci.devfn) { case PCI_DEVFN(21, 0): /* SDMA */ sio_index = SIO_ID_SDMA; @@ -241,9 +268,9 @@ static struct pci_operations pci_ops = { }; static struct device_operations device_ops = { - .read_resources = pci_bus_read_resources, + .read_resources = pci_dev_read_resources, .set_resources = pci_dev_set_resources, - .enable_resources = pci_bus_enable_resources, + .enable_resources = pci_dev_enable_resources, .init = serialio_init, .ops_pci = &pci_ops, };