blob: ef9f636d31bfe435692699c5e5f9418dc75dc517 [file] [log] [blame]
Alexandru Gagniuc23211b02013-06-09 16:06:07 -05001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <arch/io.h>
21#include <console/console.h>
22#include <device/pci.h>
23#include <device/pciexp.h>
24#include <device/pci_ids.h>
25
26#include "vx900.h"
27
28/**
Martin Roth543888d2015-01-06 10:20:42 -070029 * @file vx900/pcie.c
Alexandru Gagniuc23211b02013-06-09 16:06:07 -050030 *
31 * STATUS:
32 * We do part of the sequence to initialize the PCIE link. The problem is that
33 * the reset signal for each slot is connected to a GPO pin, but We don't know
34 * which GPO pin. We need to figure out which GPIO pin is hooked to which slot,
35 * and have a mechanism to specify this per-mainboard (devicetree.cb).
36 *
37 * There is currently no timeout detection mechanism for when a link comes up.
38 * If the link never comes up, we hang.
39 */
40
41static void vx900_pcie_link_init(device_t dev)
42{
43 u8 reg8;
44 u32 reg32;
45
46 u8 fn = dev->path.pci.devfn & 0x07;
47
48 /* Step 1 : Check for presence of PCIE device */
49 reg8 = pci_read_config8(dev, 0x5a);
50
51 if (reg8 & (1 << 6))
52 printk(BIOS_DEBUG, "Card detected in PEX%i\n", fn);
53 else
54 return;
55
56 /* Step 2: Wait for device to enter L0 state */
57 /* FIXME: implement timeout detection */
58 while (0x8a != pci_read_config8(dev, 0x1c3)) ;
59
60 /* Step 3: Clear PCIe error status, then check for failures */
61 pci_write_config32(dev, 0x104, 0xffffffff);
62 reg32 = pci_read_config32(dev, 0x104);
63 if (0 != reg32) {
64 printk(BIOS_DEBUG, "PEX init error. flags 0x%.8x\n", reg32);
65 return;
66 }
67
68 pci_write_config32(dev, 0x110, 0xffffffff);
69 reg32 = pci_read_config32(dev, 0x110);
70 if (0 != reg32)
71 printk(BIOS_DEBUG, "PEX errors. flags 0x%.8x\n", reg32);
72
73 pci_write_config8(dev, 0xa4, 0xff);
74 if (pci_read_config8(dev, 0x4a) & (1 << 3))
Stefan Reinauer65b72ab2015-01-05 12:59:54 -080075 printk(BIOS_DEBUG, "Unsupported request detected.\n");
Alexandru Gagniuc23211b02013-06-09 16:06:07 -050076
77 pci_write_config8(dev, 0x15a, 0xff);
78 if (pci_read_config8(dev, 0x15a) & (1 << 1))
Stefan Reinauer65b72ab2015-01-05 12:59:54 -080079 printk(BIOS_DEBUG, "Negotiation pending.\n");
Alexandru Gagniuc23211b02013-06-09 16:06:07 -050080
81 /* Step 4: Read vendor ID */
82 /* FIXME: Do we want to run through the whole sequence and delay boot
83 * by several seconds if the device does not respond properly the first
84 * time? */
85}
86
87static void vx900_pex_dev_set_resources(device_t dev)
88{
89 assign_resources(dev->link_list);
90}
91
92static void vx900_pex_init(device_t dev)
93{
94 /* FIXME: For some reason, PEX0 hangs on init. Find issue, fix it. */
95 if ((dev->path.pci.devfn & 0x7) == 0)
96 return;
97
98 vx900_pcie_link_init(dev);
99}
100
101static struct device_operations vx900_pex_ops = {
102 .read_resources = pci_bus_read_resources,
103 .set_resources = vx900_pex_dev_set_resources,
104 .enable_resources = pci_bus_enable_resources,
105 .init = vx900_pex_init,
106 .scan_bus = pciexp_scan_bridge,
107 .reset_bus = pci_bus_reset,
108};
109
110static const unsigned short pci_device_ids[] = {
111 PCI_DEVICE_ID_VIA_VX900_PEX1,
112 PCI_DEVICE_ID_VIA_VX900_PEX2,
113 PCI_DEVICE_ID_VIA_VX900_PEX3,
114 PCI_DEVICE_ID_VIA_VX900_PEX4,
115 0,
116};
117
118static const struct pci_driver pex_driver __pci_driver = {
119 .ops = &vx900_pex_ops,
120 .vendor = PCI_VENDOR_ID_VIA,
121 .devices = pci_device_ids,
122
123};