Initial support for USB, UHCI, and USB Keyboards.
[seabios.git] / src / pci.c
1 // PCI config space access functions.
2 //
3 // Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2002  MandrakeSoft S.A.
5 //
6 // This file may be distributed under the terms of the GNU LGPLv3 license.
7
8 #include "pci.h" // pci_config_writel
9 #include "ioport.h" // outl
10 #include "util.h" // dprintf
11 #include "config.h" // CONFIG_*
12 #include "pci_regs.h" // PCI_VENDOR_ID
13 #include "pci_ids.h" // PCI_CLASS_DISPLAY_VGA
14
15 void pci_config_writel(u16 bdf, u32 addr, u32 val)
16 {
17     outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
18     outl(val, PORT_PCI_DATA);
19 }
20
21 void pci_config_writew(u16 bdf, u32 addr, u16 val)
22 {
23     outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
24     outw(val, PORT_PCI_DATA + (addr & 2));
25 }
26
27 void pci_config_writeb(u16 bdf, u32 addr, u8 val)
28 {
29     outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
30     outb(val, PORT_PCI_DATA + (addr & 3));
31 }
32
33 u32 pci_config_readl(u16 bdf, u32 addr)
34 {
35     outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
36     return inl(PORT_PCI_DATA);
37 }
38
39 u16 pci_config_readw(u16 bdf, u32 addr)
40 {
41     outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
42     return inw(PORT_PCI_DATA + (addr & 2));
43 }
44
45 u8 pci_config_readb(u16 bdf, u32 addr)
46 {
47     outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
48     return inb(PORT_PCI_DATA + (addr & 3));
49 }
50
51 int
52 pci_next(int bdf, int *pmax)
53 {
54     if (pci_bdf_to_fn(bdf) == 1
55         && (pci_config_readb(bdf-1, PCI_HEADER_TYPE) & 0x80) == 0)
56         // Last found device wasn't a multi-function device - skip to
57         // the next device.
58         bdf += 7;
59
60     int max = *pmax;
61     for (;;) {
62         if (bdf >= max) {
63             if (CONFIG_PCI_ROOT1 && bdf <= (CONFIG_PCI_ROOT1 << 8))
64                 bdf = CONFIG_PCI_ROOT1 << 8;
65             else if (CONFIG_PCI_ROOT2 && bdf <= (CONFIG_PCI_ROOT2 << 8))
66                 bdf = CONFIG_PCI_ROOT2 << 8;
67             else
68                 return -1;
69             *pmax = max = bdf + 0x0100;
70         }
71
72         u16 v = pci_config_readw(bdf, PCI_VENDOR_ID);
73         if (v != 0x0000 && v != 0xffff)
74             // Device is present.
75             break;
76
77         if (pci_bdf_to_fn(bdf) == 0)
78             bdf += 8;
79         else
80             bdf += 1;
81     }
82
83     // Check if found device is a bridge.
84     u32 v = pci_config_readb(bdf, PCI_HEADER_TYPE);
85     v &= 0x7f;
86     if (v == PCI_HEADER_TYPE_BRIDGE || v == PCI_HEADER_TYPE_CARDBUS) {
87         v = pci_config_readl(bdf, PCI_PRIMARY_BUS);
88         int newmax = (v & 0xff00) + 0x0100;
89         if (newmax > max)
90             *pmax = newmax;
91     }
92
93     return bdf;
94 }
95
96 // Find a vga device with legacy address decoding enabled.
97 int
98 pci_find_vga()
99 {
100     int bdf = 0x0000, max = 0x0100;
101     for (;;) {
102         if (bdf >= max) {
103             if (CONFIG_PCI_ROOT1 && bdf <= (CONFIG_PCI_ROOT1 << 8))
104                 bdf = CONFIG_PCI_ROOT1 << 8;
105             else if (CONFIG_PCI_ROOT2 && bdf <= (CONFIG_PCI_ROOT2 << 8))
106                 bdf = CONFIG_PCI_ROOT2 << 8;
107             else
108                 return -1;
109             max = bdf + 0x0100;
110         }
111
112         u16 cls = pci_config_readw(bdf, PCI_CLASS_DEVICE);
113         if (cls == 0x0000 || cls == 0xffff) {
114             // Device not present.
115             if (pci_bdf_to_fn(bdf) == 0)
116                 bdf += 8;
117             else
118                 bdf += 1;
119             continue;
120         }
121         if (cls == PCI_CLASS_DISPLAY_VGA) {
122             u16 cmd = pci_config_readw(bdf, PCI_COMMAND);
123             if (cmd & PCI_COMMAND_IO && cmd & PCI_COMMAND_MEMORY)
124                 // Found active vga card
125                 return bdf;
126         }
127
128         // Check if device is a bridge.
129         u8 hdr = pci_config_readb(bdf, PCI_HEADER_TYPE);
130         u8 ht = hdr & 0x7f;
131         if (ht == PCI_HEADER_TYPE_BRIDGE || ht == PCI_HEADER_TYPE_CARDBUS) {
132             u32 ctrl = pci_config_readb(bdf, PCI_BRIDGE_CONTROL);
133             if (ctrl & PCI_BRIDGE_CTL_VGA) {
134                 // Found a VGA enabled bridge.
135                 u32 pbus = pci_config_readl(bdf, PCI_PRIMARY_BUS);
136                 bdf = (pbus & 0xff00);
137                 max = bdf + 0x100;
138                 continue;
139             }
140         }
141
142         if (pci_bdf_to_fn(bdf) == 0 && (hdr & 0x80) == 0)
143             // Last found device wasn't a multi-function device - skip to
144             // the next device.
145             bdf += 8;
146         else
147             bdf += 1;
148     }
149 }
150
151 // Search for a device with the specified vendor and device ids.
152 int
153 pci_find_device(u16 vendid, u16 devid)
154 {
155     u32 id = (devid << 16) | vendid;
156     int bdf, max;
157     foreachpci(bdf, max) {
158         u32 v = pci_config_readl(bdf, PCI_VENDOR_ID);
159         if (v != id)
160             continue;
161         // Found it.
162         return bdf;
163     }
164     return -1;
165 }
166
167 // Search for a device with the specified class id.
168 int
169 pci_find_class(u16 classid)
170 {
171     int bdf, max;
172     foreachpci(bdf, max) {
173         u16 v = pci_config_readw(bdf, PCI_CLASS_DEVICE);
174         if (v != classid)
175             continue;
176         // Found it.
177         return bdf;
178     }
179     return -1;
180 }
181
182 void
183 pci_set_bus_master(u16 bdf)
184 {
185     u16 val = pci_config_readw(bdf, PCI_COMMAND);
186     val |= PCI_COMMAND_MASTER;
187     pci_config_writew(bdf, PCI_COMMAND, val);
188 }