lynxpoint: move all pcie device handling to pcie.c
Some of the pcie logic was located in pch.c as well as pcie.c. Move all pcie logic to the same pcie.c file. This is a straight cut-and-paste (no logic changes) except for a rename from pch_pcie_enable() -> pch_pcie_enable_dev(). Change-Id: I338c53039b95f255ab9ced313c51193a9d34b404 Signed-off-by: Aaron Durbin <adurbin@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/59277 Reviewed-by: Duncan Laurie <dlaurie@chromium.org> Reviewed-on: http://review.coreboot.org/4251 Tested-by: build bot (Jenkins) Reviewed-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
This commit is contained in:
parent
3fcd356464
commit
60f820835f
|
@ -289,198 +289,13 @@ void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue)
|
|||
pch_iobp_write(address, data);
|
||||
}
|
||||
|
||||
/* Check if any port in set X to X+3 is enabled */
|
||||
static int pch_pcie_check_set_enabled(device_t dev)
|
||||
{
|
||||
device_t port;
|
||||
int port_func;
|
||||
int dev_func = PCI_FUNC(dev->path.pci.devfn);
|
||||
|
||||
printk(BIOS_DEBUG, "%s: check set enabled\n", dev_path(dev));
|
||||
|
||||
/* Go through static device tree list of devices
|
||||
* because enumeration is still in progress */
|
||||
for (port = all_devices; port; port = port->next) {
|
||||
/* Only care about PCIe root ports */
|
||||
if (PCI_SLOT(port->path.pci.devfn) !=
|
||||
PCI_SLOT(dev->path.pci.devfn))
|
||||
continue;
|
||||
|
||||
/* Check if port is in range and enabled */
|
||||
port_func = PCI_FUNC(port->path.pci.devfn);
|
||||
if (port_func >= dev_func &&
|
||||
port_func < (dev_func + 4) &&
|
||||
port->enabled)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* None of the ports in this set are enabled */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* RPFN is a write-once register so keep a copy until it is written */
|
||||
static u32 new_rpfn;
|
||||
|
||||
/* Swap function numbers assigned to two PCIe Root Ports */
|
||||
static void pch_pcie_function_swap(u8 old_fn, u8 new_fn)
|
||||
{
|
||||
u32 old_rpfn = new_rpfn;
|
||||
|
||||
printk(BIOS_DEBUG, "PCH: Remap PCIe function %d to %d\n",
|
||||
old_fn, new_fn);
|
||||
|
||||
new_rpfn &= ~(RPFN_FNMASK(old_fn) | RPFN_FNMASK(new_fn));
|
||||
|
||||
/* Old function set to new function and disabled */
|
||||
new_rpfn |= RPFN_FNSET(old_fn, RPFN_FNGET(old_rpfn, new_fn));
|
||||
new_rpfn |= RPFN_FNSET(new_fn, RPFN_FNGET(old_rpfn, old_fn));
|
||||
}
|
||||
|
||||
/* Update devicetree with new Root Port function number assignment */
|
||||
static void pch_pcie_devicetree_update(void)
|
||||
{
|
||||
device_t dev;
|
||||
|
||||
/* Update the function numbers in the static devicetree */
|
||||
for (dev = all_devices; dev; dev = dev->next) {
|
||||
u8 new_devfn;
|
||||
|
||||
/* Only care about PCH PCIe root ports */
|
||||
if (PCI_SLOT(dev->path.pci.devfn) !=
|
||||
PCH_PCIE_DEV_SLOT)
|
||||
continue;
|
||||
|
||||
/* Determine the new devfn for this port */
|
||||
new_devfn = PCI_DEVFN(PCH_PCIE_DEV_SLOT,
|
||||
RPFN_FNGET(new_rpfn,
|
||||
PCI_FUNC(dev->path.pci.devfn)));
|
||||
|
||||
if (dev->path.pci.devfn != new_devfn) {
|
||||
printk(BIOS_DEBUG,
|
||||
"PCH: PCIe map %02x.%1x -> %02x.%1x\n",
|
||||
PCI_SLOT(dev->path.pci.devfn),
|
||||
PCI_FUNC(dev->path.pci.devfn),
|
||||
PCI_SLOT(new_devfn), PCI_FUNC(new_devfn));
|
||||
|
||||
dev->path.pci.devfn = new_devfn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Special handling for PCIe Root Port devices */
|
||||
static void pch_pcie_enable(device_t dev)
|
||||
{
|
||||
struct southbridge_intel_lynxpoint_config *config = dev->chip_info;
|
||||
u32 reg32;
|
||||
|
||||
/*
|
||||
* Save a copy of the Root Port Function Number map when
|
||||
* starting to walk the list of PCIe Root Ports so it can
|
||||
* be updated locally and written out when the last port
|
||||
* has been processed.
|
||||
*/
|
||||
if (PCI_FUNC(dev->path.pci.devfn) == 0) {
|
||||
new_rpfn = RCBA32(RPFN);
|
||||
|
||||
/*
|
||||
* Enable Root Port coalescing if the first port is disabled
|
||||
* or the other devices will not be enumerated by the OS.
|
||||
*/
|
||||
if (!dev->enabled)
|
||||
config->pcie_port_coalesce = 1;
|
||||
|
||||
if (config->pcie_port_coalesce)
|
||||
printk(BIOS_INFO,
|
||||
"PCH: PCIe Root Port coalescing is enabled\n");
|
||||
}
|
||||
|
||||
if (!dev->enabled) {
|
||||
printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
|
||||
|
||||
/*
|
||||
* PCIE Power Savings for PantherPoint and CougarPoint/B1+
|
||||
*
|
||||
* If PCIe 0-3 disabled set Function 0 0xE2[0] = 1
|
||||
* If PCIe 4-7 disabled set Function 4 0xE2[0] = 1
|
||||
*
|
||||
* This check is done here instead of pcie driver
|
||||
* because the pcie driver enable() handler is not
|
||||
* called unless the device is enabled.
|
||||
*/
|
||||
if ((PCI_FUNC(dev->path.pci.devfn) == 0 ||
|
||||
PCI_FUNC(dev->path.pci.devfn) == 4)) {
|
||||
/* Handle workaround for PPT and CPT/B1+ */
|
||||
if (!pch_pcie_check_set_enabled(dev)) {
|
||||
u8 reg8 = pci_read_config8(dev, 0xe2);
|
||||
reg8 |= 1;
|
||||
pci_write_config8(dev, 0xe2, reg8);
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable Clock Gating for shared PCIe resources
|
||||
* before disabling this particular port.
|
||||
*/
|
||||
pci_write_config8(dev, 0xe1, 0x3c);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Do not claim downstream transactions for PCIe ports */
|
||||
new_rpfn |= RPFN_HIDE(PCI_FUNC(dev->path.pci.devfn));
|
||||
|
||||
/* Disable this device if possible */
|
||||
pch_disable_devfn(dev);
|
||||
} else {
|
||||
int fn;
|
||||
|
||||
/*
|
||||
* Check if there is a lower disabled port to swap with this
|
||||
* port in order to maintain linear order starting at zero.
|
||||
*/
|
||||
if (config->pcie_port_coalesce) {
|
||||
for (fn=0; fn < PCI_FUNC(dev->path.pci.devfn); fn++) {
|
||||
if (!(new_rpfn & RPFN_HIDE(fn)))
|
||||
continue;
|
||||
|
||||
/* Swap places with this function */
|
||||
pch_pcie_function_swap(
|
||||
PCI_FUNC(dev->path.pci.devfn), fn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable SERR */
|
||||
reg32 = pci_read_config32(dev, PCI_COMMAND);
|
||||
reg32 |= PCI_COMMAND_SERR;
|
||||
pci_write_config32(dev, PCI_COMMAND, reg32);
|
||||
}
|
||||
|
||||
/*
|
||||
* When processing the last PCIe root port we can now
|
||||
* update the Root Port Function Number and Hide register.
|
||||
*/
|
||||
if (PCI_FUNC(dev->path.pci.devfn) == 7) {
|
||||
printk(BIOS_SPEW, "PCH: RPFN 0x%08x -> 0x%08x\n",
|
||||
RCBA32(RPFN), new_rpfn);
|
||||
RCBA32(RPFN) = new_rpfn;
|
||||
|
||||
/* Update static devictree with new function numbers */
|
||||
if (config->pcie_port_coalesce)
|
||||
pch_pcie_devicetree_update();
|
||||
}
|
||||
}
|
||||
|
||||
void pch_enable(device_t dev)
|
||||
{
|
||||
u32 reg32;
|
||||
|
||||
/* PCH PCIe Root Ports get special handling */
|
||||
if (PCI_SLOT(dev->path.pci.devfn) == PCH_PCIE_DEV_SLOT)
|
||||
return pch_pcie_enable(dev);
|
||||
return pch_pcie_enable_dev(dev);
|
||||
|
||||
if (!dev->enabled) {
|
||||
printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
|
||||
|
|
|
@ -166,6 +166,7 @@ void pch_disable_devfn(device_t dev);
|
|||
u32 pch_iobp_read(u32 address);
|
||||
void pch_iobp_write(u32 address, u32 data);
|
||||
void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue);
|
||||
void pch_pcie_enable_dev(device_t dev);
|
||||
#if CONFIG_ELOG
|
||||
void pch_log_state(void);
|
||||
#endif
|
||||
|
|
|
@ -25,6 +25,191 @@
|
|||
#include <device/pci_ids.h>
|
||||
#include "pch.h"
|
||||
|
||||
/* Check if any port in set X to X+3 is enabled */
|
||||
static int pch_pcie_check_set_enabled(device_t dev)
|
||||
{
|
||||
device_t port;
|
||||
int port_func;
|
||||
int dev_func = PCI_FUNC(dev->path.pci.devfn);
|
||||
|
||||
printk(BIOS_DEBUG, "%s: check set enabled\n", dev_path(dev));
|
||||
|
||||
/* Go through static device tree list of devices
|
||||
* because enumeration is still in progress */
|
||||
for (port = all_devices; port; port = port->next) {
|
||||
/* Only care about PCIe root ports */
|
||||
if (PCI_SLOT(port->path.pci.devfn) !=
|
||||
PCI_SLOT(dev->path.pci.devfn))
|
||||
continue;
|
||||
|
||||
/* Check if port is in range and enabled */
|
||||
port_func = PCI_FUNC(port->path.pci.devfn);
|
||||
if (port_func >= dev_func &&
|
||||
port_func < (dev_func + 4) &&
|
||||
port->enabled)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* None of the ports in this set are enabled */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* RPFN is a write-once register so keep a copy until it is written */
|
||||
static u32 new_rpfn;
|
||||
|
||||
/* Swap function numbers assigned to two PCIe Root Ports */
|
||||
static void pch_pcie_function_swap(u8 old_fn, u8 new_fn)
|
||||
{
|
||||
u32 old_rpfn = new_rpfn;
|
||||
|
||||
printk(BIOS_DEBUG, "PCH: Remap PCIe function %d to %d\n",
|
||||
old_fn, new_fn);
|
||||
|
||||
new_rpfn &= ~(RPFN_FNMASK(old_fn) | RPFN_FNMASK(new_fn));
|
||||
|
||||
/* Old function set to new function and disabled */
|
||||
new_rpfn |= RPFN_FNSET(old_fn, RPFN_FNGET(old_rpfn, new_fn));
|
||||
new_rpfn |= RPFN_FNSET(new_fn, RPFN_FNGET(old_rpfn, old_fn));
|
||||
}
|
||||
|
||||
/* Update devicetree with new Root Port function number assignment */
|
||||
static void pch_pcie_devicetree_update(void)
|
||||
{
|
||||
device_t dev;
|
||||
|
||||
/* Update the function numbers in the static devicetree */
|
||||
for (dev = all_devices; dev; dev = dev->next) {
|
||||
u8 new_devfn;
|
||||
|
||||
/* Only care about PCH PCIe root ports */
|
||||
if (PCI_SLOT(dev->path.pci.devfn) !=
|
||||
PCH_PCIE_DEV_SLOT)
|
||||
continue;
|
||||
|
||||
/* Determine the new devfn for this port */
|
||||
new_devfn = PCI_DEVFN(PCH_PCIE_DEV_SLOT,
|
||||
RPFN_FNGET(new_rpfn,
|
||||
PCI_FUNC(dev->path.pci.devfn)));
|
||||
|
||||
if (dev->path.pci.devfn != new_devfn) {
|
||||
printk(BIOS_DEBUG,
|
||||
"PCH: PCIe map %02x.%1x -> %02x.%1x\n",
|
||||
PCI_SLOT(dev->path.pci.devfn),
|
||||
PCI_FUNC(dev->path.pci.devfn),
|
||||
PCI_SLOT(new_devfn), PCI_FUNC(new_devfn));
|
||||
|
||||
dev->path.pci.devfn = new_devfn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Special handling for PCIe Root Port devices */
|
||||
void pch_pcie_enable_dev(device_t dev)
|
||||
{
|
||||
struct southbridge_intel_lynxpoint_config *config = dev->chip_info;
|
||||
u32 reg32;
|
||||
|
||||
/*
|
||||
* Save a copy of the Root Port Function Number map when
|
||||
* starting to walk the list of PCIe Root Ports so it can
|
||||
* be updated locally and written out when the last port
|
||||
* has been processed.
|
||||
*/
|
||||
if (PCI_FUNC(dev->path.pci.devfn) == 0) {
|
||||
new_rpfn = RCBA32(RPFN);
|
||||
|
||||
/*
|
||||
* Enable Root Port coalescing if the first port is disabled
|
||||
* or the other devices will not be enumerated by the OS.
|
||||
*/
|
||||
if (!dev->enabled)
|
||||
config->pcie_port_coalesce = 1;
|
||||
|
||||
if (config->pcie_port_coalesce)
|
||||
printk(BIOS_INFO,
|
||||
"PCH: PCIe Root Port coalescing is enabled\n");
|
||||
}
|
||||
|
||||
if (!dev->enabled) {
|
||||
printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
|
||||
|
||||
/*
|
||||
* PCIE Power Savings for PantherPoint and CougarPoint/B1+
|
||||
*
|
||||
* If PCIe 0-3 disabled set Function 0 0xE2[0] = 1
|
||||
* If PCIe 4-7 disabled set Function 4 0xE2[0] = 1
|
||||
*
|
||||
* This check is done here instead of pcie driver
|
||||
* because the pcie driver enable() handler is not
|
||||
* called unless the device is enabled.
|
||||
*/
|
||||
if ((PCI_FUNC(dev->path.pci.devfn) == 0 ||
|
||||
PCI_FUNC(dev->path.pci.devfn) == 4)) {
|
||||
/* Handle workaround for PPT and CPT/B1+ */
|
||||
if (!pch_pcie_check_set_enabled(dev)) {
|
||||
u8 reg8 = pci_read_config8(dev, 0xe2);
|
||||
reg8 |= 1;
|
||||
pci_write_config8(dev, 0xe2, reg8);
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable Clock Gating for shared PCIe resources
|
||||
* before disabling this particular port.
|
||||
*/
|
||||
pci_write_config8(dev, 0xe1, 0x3c);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Do not claim downstream transactions for PCIe ports */
|
||||
new_rpfn |= RPFN_HIDE(PCI_FUNC(dev->path.pci.devfn));
|
||||
|
||||
/* Disable this device if possible */
|
||||
pch_disable_devfn(dev);
|
||||
} else {
|
||||
int fn;
|
||||
|
||||
/*
|
||||
* Check if there is a lower disabled port to swap with this
|
||||
* port in order to maintain linear order starting at zero.
|
||||
*/
|
||||
if (config->pcie_port_coalesce) {
|
||||
for (fn=0; fn < PCI_FUNC(dev->path.pci.devfn); fn++) {
|
||||
if (!(new_rpfn & RPFN_HIDE(fn)))
|
||||
continue;
|
||||
|
||||
/* Swap places with this function */
|
||||
pch_pcie_function_swap(
|
||||
PCI_FUNC(dev->path.pci.devfn), fn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable SERR */
|
||||
reg32 = pci_read_config32(dev, PCI_COMMAND);
|
||||
reg32 |= PCI_COMMAND_SERR;
|
||||
pci_write_config32(dev, PCI_COMMAND, reg32);
|
||||
}
|
||||
|
||||
/*
|
||||
* When processing the last PCIe root port we can now
|
||||
* update the Root Port Function Number and Hide register.
|
||||
*/
|
||||
if (PCI_FUNC(dev->path.pci.devfn) == 7) {
|
||||
printk(BIOS_SPEW, "PCH: RPFN 0x%08x -> 0x%08x\n",
|
||||
RCBA32(RPFN), new_rpfn);
|
||||
RCBA32(RPFN) = new_rpfn;
|
||||
|
||||
/* Update static devictree with new function numbers */
|
||||
if (config->pcie_port_coalesce)
|
||||
pch_pcie_devicetree_update();
|
||||
}
|
||||
}
|
||||
|
||||
static void pch_pcie_pm_early(struct device *dev)
|
||||
{
|
||||
/* RPC has been moved. It is in PCI config space now. */
|
||||
|
|
Loading…
Reference in New Issue