diff options
Diffstat (limited to 'src/northbridge/via/vx900/pcie.c')
-rw-r--r-- | src/northbridge/via/vx900/pcie.c | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/src/northbridge/via/vx900/pcie.c b/src/northbridge/via/vx900/pcie.c new file mode 100644 index 0000000000..109e5c9ffe --- /dev/null +++ b/src/northbridge/via/vx900/pcie.c @@ -0,0 +1,123 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com> + * + * 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, either version 2 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include <arch/io.h> +#include <console/console.h> +#include <device/pci.h> +#include <device/pciexp.h> +#include <device/pci_ids.h> + +#include "vx900.h" + +/** + * @file pcie.c + * + * STATUS: + * We do part of the sequence to initialize the PCIE link. The problem is that + * the reset signal for each slot is connected to a GPO pin, but We don't know + * which GPO pin. We need to figure out which GPIO pin is hooked to which slot, + * and have a mechanism to specify this per-mainboard (devicetree.cb). + * + * There is currently no timeout detection mechanism for when a link comes up. + * If the link never comes up, we hang. + */ + +static void vx900_pcie_link_init(device_t dev) +{ + u8 reg8; + u32 reg32; + + u8 fn = dev->path.pci.devfn & 0x07; + + /* Step 1 : Check for presence of PCIE device */ + reg8 = pci_read_config8(dev, 0x5a); + + if (reg8 & (1 << 6)) + printk(BIOS_DEBUG, "Card detected in PEX%i\n", fn); + else + return; + + /* Step 2: Wait for device to enter L0 state */ + /* FIXME: implement timeout detection */ + while (0x8a != pci_read_config8(dev, 0x1c3)) ; + + /* Step 3: Clear PCIe error status, then check for failures */ + pci_write_config32(dev, 0x104, 0xffffffff); + reg32 = pci_read_config32(dev, 0x104); + if (0 != reg32) { + printk(BIOS_DEBUG, "PEX init error. flags 0x%.8x\n", reg32); + return; + } + + pci_write_config32(dev, 0x110, 0xffffffff); + reg32 = pci_read_config32(dev, 0x110); + if (0 != reg32) + printk(BIOS_DEBUG, "PEX errors. flags 0x%.8x\n", reg32); + + pci_write_config8(dev, 0xa4, 0xff); + if (pci_read_config8(dev, 0x4a) & (1 << 3)) + print_debug("Unsupported request detected.\n"); + + pci_write_config8(dev, 0x15a, 0xff); + if (pci_read_config8(dev, 0x15a) & (1 << 1)) + print_debug("Negotiation pending.\n"); + + /* Step 4: Read vendor ID */ + /* FIXME: Do we want to run through the whole sequence and delay boot + * by several seconds if the device does not respond properly the first + * time? */ +} + +static void vx900_pex_dev_set_resources(device_t dev) +{ + assign_resources(dev->link_list); +} + +static void vx900_pex_init(device_t dev) +{ + /* FIXME: For some reason, PEX0 hangs on init. Find issue, fix it. */ + if ((dev->path.pci.devfn & 0x7) == 0) + return; + + vx900_pcie_link_init(dev); +} + +static struct device_operations vx900_pex_ops = { + .read_resources = pci_bus_read_resources, + .set_resources = vx900_pex_dev_set_resources, + .enable_resources = pci_bus_enable_resources, + .init = vx900_pex_init, + .scan_bus = pciexp_scan_bridge, + .reset_bus = pci_bus_reset, +}; + +static const unsigned short pci_device_ids[] = { + PCI_DEVICE_ID_VIA_VX900_PEX1, + PCI_DEVICE_ID_VIA_VX900_PEX2, + PCI_DEVICE_ID_VIA_VX900_PEX3, + PCI_DEVICE_ID_VIA_VX900_PEX4, + 0, +}; + +static const struct pci_driver pex_driver __pci_driver = { + .ops = &vx900_pex_ops, + .vendor = PCI_VENDOR_ID_VIA, + .devices = pci_device_ids, + +}; |