1 | /*␊ |
2 | *␊ |
3 | * Copyright 2008 by Islam M. Ahmed Zaid. All rights reserved.␊ |
4 | *␊ |
5 | */␊ |
6 | ␊ |
7 | #include "libsaio.h"␊ |
8 | #include "bootstruct.h"␊ |
9 | #include "pci.h"␊ |
10 | ␊ |
11 | uint32_t pci_config_read(uint32_t pci_addr, uint8_t reg, uint8_t bytes)␊ |
12 | {␊ |
13 | ␉uint32_t data = -1;␊ |
14 | ␊ |
15 | ␉pci_addr |= reg & ~3;␊ |
16 | ␉outl(PCI_ADDR_REG, pci_addr);␊ |
17 | ␊ |
18 | ␉switch (bytes)␊ |
19 | ␉{␊ |
20 | ␉␉case 1:␊ |
21 | ␉␉␉data = inb(PCI_DATA_REG + (reg & 3));␊ |
22 | ␉␉␉break;␊ |
23 | ␉␉case 2:␊ |
24 | ␉␉␉data = inw(PCI_DATA_REG + (reg & 2));␊ |
25 | ␉␉␉break;␊ |
26 | ␉␉case 4:␊ |
27 | ␉␉␉data = inl(PCI_DATA_REG);␊ |
28 | ␉␉␉break;␊ |
29 | ␉}␊ |
30 | ␊ |
31 | ␉return data;␊ |
32 | }␊ |
33 | ␊ |
34 | void pci_config_write(uint32_t pci_addr, uint8_t reg, uint32_t data, uint8_t bytes)␊ |
35 | {␊ |
36 | ␉pci_addr |= reg & ~3;␊ |
37 | ␉outl(PCI_ADDR_REG, pci_addr);␊ |
38 | ␊ |
39 | ␉switch (bytes)␊ |
40 | ␉{␊ |
41 | ␉␉case 1:␊ |
42 | ␉␉␉outb(PCI_DATA_REG + (reg & 3), data);␊ |
43 | ␉␉␉break;␊ |
44 | ␉␉case 2:␊ |
45 | ␉␉␉outw(PCI_DATA_REG + (reg & 2), data);␊ |
46 | ␉␉␉break;␊ |
47 | ␉␉case 4:␊ |
48 | ␉␉␉outl(PCI_DATA_REG, data);␊ |
49 | ␉␉␉break;␊ |
50 | ␉}␊ |
51 | }␊ |
52 | ␊ |
53 | pci_dt_t *root_pci_dev;␊ |
54 | ␊ |
55 | void scan_pci_bus(pci_dt_t *start, uint8_t bus)␊ |
56 | {␊ |
57 | ␉uint8_t dev, func, secondary_bus, header_type;␊ |
58 | ␉uint32_t id, pci_addr;␊ |
59 | ␉pci_dt_t *new;␊ |
60 | ␉pci_dt_t **current = &start->children;␊ |
61 | ␉␊ |
62 | ␉for (dev = 0; dev < 32; dev++)␊ |
63 | ␉␉for (func = 0; func < 8; func++)␊ |
64 | ␉␉{␊ |
65 | ␉␉␉pci_addr = PCIADDR(bus, dev, func);␊ |
66 | ␉␉␉id = pci_config_read32(pci_addr, PCI_VENDOR_ID);␊ |
67 | ␉␉␉if (!id || id == 0xffffffff)␊ |
68 | ␉␉␉␉continue;␊ |
69 | ␊ |
70 | ␉␉␉new = (pci_dt_t*)malloc(sizeof(pci_dt_t));␊ |
71 | ␉␉␉if (!new)␊ |
72 | ␉␉␉␉return;␊ |
73 | ␉␉␉memset(new, 0, sizeof(pci_dt_t));␊ |
74 | ␉␉␉␊ |
75 | ␉␉␉new->dev.addr␉= pci_addr;␊ |
76 | ␉␉␉new->vendor_id␉= id & 0xffff;␊ |
77 | ␉␉␉new->device_id␉= (id >> 16) & 0xffff;␊ |
78 | ␉␉␉new->class_id␉= pci_config_read16(pci_addr, PCI_CLASS_DEVICE);␊ |
79 | ␉␉␉new->parent␉␉= start;␊ |
80 | ␊ |
81 | ␉␉␉header_type = pci_config_read8(pci_addr, PCI_HEADER_TYPE);␊ |
82 | ␉␉␉switch (header_type & 0x7f)␊ |
83 | ␉␉␉{␊ |
84 | ␉␉␉␉case PCI_HEADER_TYPE_BRIDGE:␊ |
85 | ␉␉␉␉case PCI_HEADER_TYPE_CARDBUS:␊ |
86 | ␉␉␉␉␉secondary_bus = pci_config_read8(pci_addr, PCI_SECONDARY_BUS);␊ |
87 | ␉␉␉␉␉if (secondary_bus != 0)␊ |
88 | ␉␉␉␉␉␉scan_pci_bus(new, secondary_bus);␊ |
89 | ␉␉␉␉␉break;␊ |
90 | ␉␉␉}␊ |
91 | ␊ |
92 | ␉␉␉*current = new;␊ |
93 | ␉␉␉current = &new->next;␊ |
94 | ␊ |
95 | ␉␉␉if ((func == 0) && ((header_type & 0x80) == 0))␊ |
96 | ␉␉␉␉break;␊ |
97 | ␉␉}␊ |
98 | }␊ |
99 | ␊ |
100 | void enable_pci_devs(void)␊ |
101 | {␊ |
102 | ␉uint16_t id;␊ |
103 | ␉uint32_t rcba, *fd;␊ |
104 | ␊ |
105 | ␉id = pci_config_read16(PCIADDR(0, 0x00, 0), 0x00);␊ |
106 | ␉/* make sure we're on Intel chipset */␊ |
107 | ␉if (id != 0x8086)␊ |
108 | ␉␉return;␊ |
109 | ␉rcba = pci_config_read32(PCIADDR(0, 0x1f, 0), 0xf0) & ~1;␊ |
110 | ␉fd = (uint32_t *)(rcba + 0x3418);␊ |
111 | ␉/* set SMBus Disable (SD) to 0 */␊ |
112 | ␉*fd &= ~0x8;␊ |
113 | ␉/* and all devices? */␊ |
114 | ␉//*fd = 0x1;␊ |
115 | }␊ |
116 | ␊ |
117 | void build_pci_dt(void)␊ |
118 | {␊ |
119 | ␉root_pci_dev = malloc(sizeof(pci_dt_t));␊ |
120 | ␉␊ |
121 | ␉if (!root_pci_dev)␊ |
122 | ␉␉return;␊ |
123 | ␉␊ |
124 | ␉bzero(root_pci_dev, sizeof(pci_dt_t));␊ |
125 | ␉enable_pci_devs();␊ |
126 | ␉scan_pci_bus(root_pci_dev, 0);␊ |
127 | }␊ |
128 | ␊ |
129 | char dev_path[80];␊ |
130 | ␊ |
131 | char *get_pci_dev_path(pci_dt_t *pci_dt)␊ |
132 | {␊ |
133 | ␉pci_dt_t *current, *end;␊ |
134 | ␉char tmp[30];␊ |
135 | ␊ |
136 | ␉dev_path[0] = 0;␊ |
137 | ␉end = root_pci_dev;␊ |
138 | ␊ |
139 | ␉while (end != pci_dt)␊ |
140 | ␉{␊ |
141 | ␉␉current = pci_dt;␊ |
142 | ␉␉while (current->parent != end)␊ |
143 | ␉␉␉current = current->parent;␉␉␉␊ |
144 | ␉␉end = current;␊ |
145 | ␊ |
146 | ␉␉sprintf(tmp, "%s/Pci(0x%x,0x%x)",␊ |
147 | ␉␉␉(current->parent == root_pci_dev) ? "PciRoot(0x0)" : "",␊ |
148 | ␉␉␉current->dev.bits.dev, current->dev.bits.func);␊ |
149 | ␉␉strcat(dev_path, tmp);␊ |
150 | ␉}␊ |
151 | ␊ |
152 | ␉return dev_path;␊ |
153 | }␊ |
154 | ␊ |
155 | void dump_pci_dt(pci_dt_t *pci_dt)␊ |
156 | {␊ |
157 | ␉pci_dt_t *current = pci_dt;␊ |
158 | ␊ |
159 | ␉while (current)␊ |
160 | ␉{␊ |
161 | ␉␉printf("%02x:%02x.%x [%04x] [%04x:%04x] :: %s\n", ␊ |
162 | ␉␉␉current->dev.bits.bus, current->dev.bits.dev, current->dev.bits.func, ␊ |
163 | ␉␉␉current->class_id, current->vendor_id, current->device_id, ␊ |
164 | ␉␉␉get_pci_dev_path(current));␊ |
165 | ␉␉dump_pci_dt(current->children);␊ |
166 | ␉␉current = current->next;␊ |
167 | ␉}␊ |
168 | }␊ |
169 | ␊ |
170 | ␊ |
171 | void lspci(const char *booterParam)␊ |
172 | {␊ |
173 | ␉if(bootArgs->Video.v_display == VGA_TEXT_MODE)␊ |
174 | ␉{ ␊ |
175 | ␉␉setActiveDisplayPage(1);␊ |
176 | ␉␉clearScreenRows(0, 24);␊ |
177 | ␉␉setCursorPosition(0, 0, 1);␊ |
178 | ␉}␊ |
179 | ␉␉␊ |
180 | ␉dump_pci_dt(root_pci_dev->children);␊ |
181 | ␉␊ |
182 | ␉printf("(Press a key to continue...)");␊ |
183 | ␉getc();␊ |
184 | ␉␊ |
185 | ␉if(bootArgs->Video.v_display == VGA_TEXT_MODE)␊ |
186 | ␉␉setActiveDisplayPage(0);␊ |
187 | }␊ |
188 | ␊ |
189 | int check_vga_nvidia(pci_dt_t *pci_dt)␊ |
190 | {␊ |
191 | ␉pci_dt_t *current = pci_dt;␊ |
192 | ␉while (current)␊ |
193 | ␉{␊ |
194 | ␉␉if(current->vendor_id == PCI_CLASS_DISPLAY_VGA)␊ |
195 | ␉␉␉if(current->class_id == PCI_VENDOR_ID_NVIDIA)␊ |
196 | ␉␉␉␉return 1;␊ |
197 | ␉␉␊ |
198 | ␉␉check_vga_nvidia(current->children);␊ |
199 | ␉␉current = current->next;␊ |
200 | ␉}␊ |
201 | ␉return 0;␊ |
202 | }␊ |
203 | ␊ |
204 | |