1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include "device.h"
16#ifdef CONFIG_COREBOOT_V2
17#include "compat/rtas.h"
18#else
19#include "rtas.h"
20#endif
21#include <string.h>
22#include "debug.h"
23
24#include <device/device.h>
25#include <device/pci.h>
26#include <device/pci_ops.h>
27#include <device/resource.h>
28
29
30biosemu_device_t bios_device;
31
32translate_address_t translate_address_array[11];
33u8 taa_last_entry;
34
35typedef struct {
36 u8 info;
37 u8 bus;
38 u8 devfn;
39 u8 cfg_space_offset;
40 u64 address;
41 u64 size;
42} __attribute__ ((__packed__)) assigned_address_t;
43
44#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
45
46
47void
48biosemu_dev_get_addr_info(void)
49{
50 int taa_index = 0;
51 int i = 0;
52 struct resource *r;
53 u8 bus = bios_device.dev->bus->link;
54 u16 devfn = bios_device.dev->path.pci.devfn;
55
56 bios_device.bus = bus;
57 bios_device.devfn = devfn;
58
59 DEBUG_PRINTF("bus: %x, devfn: %x\n", bus, devfn);
60 for (i = 0; i < bios_device.dev->resources; i++) {
61 r = &bios_device.dev->resource[i];
62 translate_address_array[taa_index].info = r->flags;
63 translate_address_array[taa_index].bus = bus;
64 translate_address_array[taa_index].devfn = devfn;
65 translate_address_array[taa_index].cfg_space_offset =
66 r->index;
67 translate_address_array[taa_index].address = r->base;
68 translate_address_array[taa_index].size = r->size;
69
70 translate_address_array[taa_index].address_offset = 0;
71 taa_index++;
72 }
73
74 translate_address_array[taa_index].info = IORESOURCE_MEM | IORESOURCE_READONLY;
75 translate_address_array[taa_index].bus = bus;
76 translate_address_array[taa_index].devfn = devfn;
77 translate_address_array[taa_index].cfg_space_offset = 0x30;
78 translate_address_array[taa_index].address = bios_device.dev->rom_address;
79 translate_address_array[taa_index].size = 0;
80
81 translate_address_array[taa_index].address_offset = 0;
82 taa_index++;
83
84 if ((bios_device.dev->class & 0xFF0000) == 0x030000) {
85 DEBUG_PRINTF("%s: VGA device found, adding legacy resources... \n", __func__);
86
87 translate_address_array[taa_index].info = IORESOURCE_FIXED | IORESOURCE_IO;
88 translate_address_array[taa_index].bus = bus;
89 translate_address_array[taa_index].devfn = devfn;
90 translate_address_array[taa_index].cfg_space_offset = 0;
91 translate_address_array[taa_index].address = 0x3b0;
92 translate_address_array[taa_index].size = 0xc;
93
94 translate_address_array[taa_index].address_offset = 0;
95 taa_index++;
96
97 translate_address_array[taa_index].info = IORESOURCE_FIXED | IORESOURCE_IO;
98 translate_address_array[taa_index].bus = bus;
99 translate_address_array[taa_index].devfn = devfn;
100 translate_address_array[taa_index].cfg_space_offset = 0;
101 translate_address_array[taa_index].address = 0x3c0;
102 translate_address_array[taa_index].size = 0x20;
103
104 translate_address_array[taa_index].address_offset = 0;
105 taa_index++;
106
107 translate_address_array[taa_index].info = IORESOURCE_FIXED | IORESOURCE_MEM;
108 translate_address_array[taa_index].bus = bus;
109 translate_address_array[taa_index].devfn = devfn;
110 translate_address_array[taa_index].cfg_space_offset = 0;
111 translate_address_array[taa_index].address = 0xa0000;
112 translate_address_array[taa_index].size = 0x20000;
113
114 translate_address_array[taa_index].address_offset = 0;
115 taa_index++;
116 }
117
118 taa_last_entry = taa_index - 1;
119#ifdef CONFIG_DEBUG
120
121 printf("translate_address_array: \n");
122 translate_address_t ta;
123 for (i = 0; i <= taa_last_entry; i++) {
124 ta = translate_address_array[i];
125 printf
126 ("%d: info: %08lx bus: %02x devfn: %02x cfg_space_offset: %02x\n\taddr: %016llx\n\toffs: %016llx\n\tsize: %016llx\n",
127 i, ta.info, ta.bus, ta.devfn, ta.cfg_space_offset,
128 ta.address, ta.address_offset, ta.size);
129 }
130#endif
131}
132#else
133
134void translate_address_dev(u64 *, phandle_t);
135u64 get_puid(phandle_t node);
136
137
138
139
140void
141biosemu_dev_get_addr_info(void)
142{
143
144 int32_t len;
145
146 assigned_address_t buf[11];
147 len =
148 of_getprop(bios_device.phandle, "assigned-addresses", buf,
149 sizeof(buf));
150 bios_device.bus = buf[0].bus;
151 bios_device.devfn = buf[0].devfn;
152 DEBUG_PRINTF("bus: %x, devfn: %x\n", bios_device.bus,
153 bios_device.devfn);
154
155
156 int i = 0;
157
158 int taa_index = 0;
159 u64 address_offset;
160 for (i = 0; i < (len / sizeof(assigned_address_t)); i++, taa_index++) {
161
162 translate_address_array[taa_index].info = buf[i].info;
163 translate_address_array[taa_index].bus = buf[i].bus;
164 translate_address_array[taa_index].devfn = buf[i].devfn;
165 translate_address_array[taa_index].cfg_space_offset =
166 buf[i].cfg_space_offset;
167 translate_address_array[taa_index].address = buf[i].address;
168 translate_address_array[taa_index].size = buf[i].size;
169
170 address_offset = buf[i].address;
171 translate_address_dev(&address_offset, bios_device.phandle);
172 translate_address_array[taa_index].address_offset =
173 address_offset - buf[i].address;
174 }
175
176 len = of_getprop(bios_device.phandle, "reg", buf, sizeof(buf));
177 for (i = 0; i < (len / sizeof(assigned_address_t)); i++) {
178 if ((buf[i].size == 0) || (buf[i].cfg_space_offset != 0)) {
179
180
181
182
183 continue;
184 }
185
186 translate_address_array[taa_index].info = buf[i].info;
187 translate_address_array[taa_index].bus = buf[i].bus;
188 translate_address_array[taa_index].devfn = buf[i].devfn;
189 translate_address_array[taa_index].cfg_space_offset =
190 buf[i].cfg_space_offset;
191 translate_address_array[taa_index].address = buf[i].address;
192 translate_address_array[taa_index].size = buf[i].size;
193
194 address_offset = buf[i].address;
195 translate_address_dev(&address_offset, bios_device.phandle);
196 translate_address_array[taa_index].address_offset =
197 address_offset - buf[i].address;
198 taa_index++;
199 }
200
201 taa_last_entry = taa_index - 1;
202#ifdef CONFIG_DEBUG
203
204 printf("translate_address_array: \n");
205 translate_address_t ta;
206 for (i = 0; i <= taa_last_entry; i++) {
207 ta = translate_address_array[i];
208 printf
209 ("%d: %02x%02x%02x%02x\n\taddr: %016llx\n\toffs: %016llx\n\tsize: %016llx\n",
210 i, ta.info, ta.bus, ta.devfn, ta.cfg_space_offset,
211 ta.address, ta.address_offset, ta.size);
212 }
213#endif
214}
215#endif
216
217
218
219
220
221void
222biosemu_dev_find_vmem_addr(void)
223{
224 int i = 0;
225 translate_address_t ta;
226 s8 tai_np = -1, tai_p = -1;
227
228 for (i = taa_last_entry; i >= 0; i--) {
229 ta = translate_address_array[i];
230 if ((ta.cfg_space_offset >= 0x10)
231 && (ta.cfg_space_offset <= 0x24)) {
232
233 if ((ta.info & 0x03) >= 0x02) {
234
235 tai_np = i;
236 if ((ta.info & 0x40) != 0) {
237
238 tai_p = i;
239 }
240 }
241 }
242 }
243 if (tai_p != -1) {
244 ta = translate_address_array[tai_p];
245 bios_device.vmem_addr = ta.address;
246 bios_device.vmem_size = ta.size;
247 DEBUG_PRINTF
248 ("%s: Found prefetchable Virtual Legacy Memory BAR: %llx, size: %llx\n",
249 __func__, bios_device.vmem_addr,
250 bios_device.vmem_size);
251 } else if (tai_np != -1) {
252 ta = translate_address_array[tai_np];
253 bios_device.vmem_addr = ta.address;
254 bios_device.vmem_size = ta.size;
255 DEBUG_PRINTF
256 ("%s: Found non-prefetchable Virtual Legacy Memory BAR: %llx, size: %llx",
257 __func__, bios_device.vmem_addr,
258 bios_device.vmem_size);
259 }
260
261
262}
263
264#ifndef CONFIG_PCI_OPTION_ROM_RUN_YABEL
265void
266biosemu_dev_get_puid(void)
267{
268
269 bios_device.puid = get_puid(bios_device.phandle);
270 DEBUG_PRINTF("puid: 0x%llx\n", bios_device.puid);
271}
272#endif
273
274void
275biosemu_dev_get_device_vendor_id(void)
276{
277
278 u32 pci_config_0;
279#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
280 pci_config_0 = pci_read_config32(bios_device.dev, 0x0);
281#else
282 pci_config_0 =
283 rtas_pci_config_read(bios_device.puid, 4, bios_device.bus,
284 bios_device.devfn, 0x0);
285#endif
286 bios_device.pci_device_id =
287 (u16) ((pci_config_0 & 0xFFFF0000) >> 16);
288 bios_device.pci_vendor_id = (u16) (pci_config_0 & 0x0000FFFF);
289 DEBUG_PRINTF("PCI Device ID: %04x, PCI Vendor ID: %x\n",
290 bios_device.pci_device_id, bios_device.pci_vendor_id);
291}
292
293
294
295
296
297
298
299u8
300biosemu_dev_check_exprom(unsigned long rom_base_addr)
301{
302 int i = 0;
303 translate_address_t ta;
304 u16 pci_ds_offset;
305 pci_data_struct_t pci_ds;
306 if (rom_base_addr == 0) {
307
308 for (i = 0; i <= taa_last_entry; i++) {
309 ta = translate_address_array[i];
310 if (ta.cfg_space_offset == 0x30) {
311
312 rom_base_addr = ta.address + ta.address_offset;
313 break;
314 }
315 }
316 }
317
318
319
320 do {
321 if (rom_base_addr == 0) {
322 printf("Error: no Expansion ROM address found!\n");
323 return -1;
324 }
325 set_ci();
326 u16 rom_signature = in16le((void *) rom_base_addr);
327 clr_ci();
328 if (rom_signature != 0xaa55) {
329 printf
330 ("Error: invalid Expansion ROM signature: %02x!\n",
331 *((u16 *) rom_base_addr));
332 return -1;
333 }
334 set_ci();
335
336 pci_ds_offset = in16le((void *) (rom_base_addr + 0x18));
337
338 memcpy(&pci_ds, (void *) (rom_base_addr + pci_ds_offset),
339 sizeof(pci_ds));
340 clr_ci();
341#ifdef CONFIG_DEBUG
342 DEBUG_PRINTF("PCI Data Structure @%lx:\n",
343 rom_base_addr + pci_ds_offset);
344 dump((void *) &pci_ds, sizeof(pci_ds));
345#endif
346 if (strncmp((const char *) pci_ds.signature, "PCIR", 4) != 0) {
347 printf("Invalid PCI Data Structure found!\n");
348 break;
349 }
350
351 pci_ds.vendor_id = in16le(&pci_ds.vendor_id);
352 pci_ds.device_id = in16le(&pci_ds.device_id);
353 pci_ds.img_length = in16le(&pci_ds.img_length);
354 pci_ds.pci_ds_length = in16le(&pci_ds.pci_ds_length);
355 if (pci_ds.vendor_id != bios_device.pci_vendor_id) {
356 printf
357 ("Image has invalid Vendor ID: %04x, expected: %04x\n",
358 pci_ds.vendor_id, bios_device.pci_vendor_id);
359 break;
360 }
361 if (pci_ds.device_id != bios_device.pci_device_id) {
362 printf
363 ("Image has invalid Device ID: %04x, expected: %04x\n",
364 pci_ds.device_id, bios_device.pci_device_id);
365 break;
366 }
367 DEBUG_PRINTF("Image Length: %d\n", pci_ds.img_length * 512);
368 DEBUG_PRINTF("Image Code Type: %d\n", pci_ds.code_type);
369 if (pci_ds.code_type == 0) {
370
371
372 bios_device.img_addr = rom_base_addr;
373 bios_device.img_size = pci_ds.img_length * 512;
374
375 break;
376 } else {
377
378 rom_base_addr += pci_ds.img_length * 512;
379 }
380 if ((pci_ds.indicator & 0x80) == 0x80) {
381
382 DEBUG_PRINTF("Last PCI Expansion ROM Image found.\n");
383 break;
384 }
385 }
386 while (bios_device.img_addr == 0);
387
388 if (bios_device.img_addr == 0) {
389 printf("Error: no valid x86 Expansion ROM Image found!\n");
390 return -1;
391 }
392 return 0;
393}
394
395u8
396biosemu_dev_init(struct device * device)
397{
398 u8 rval = 0;
399
400#ifdef CONFIG_COREBOOT_V2
401 DEBUG_PRINTF("%s\n", __func__);
402#else
403 DEBUG_PRINTF("%s(%s)\n", __func__, device->dtsname);
404#endif
405 memset(&bios_device, 0, sizeof(bios_device));
406
407#ifndef CONFIG_PCI_OPTION_ROM_RUN_YABEL
408 bios_device.ihandle = of_open(device_name);
409 if (bios_device.ihandle == 0) {
410 DEBUG_PRINTF("%s is no valid device!\n", device_name);
411 return -1;
412 }
413 bios_device.phandle = of_finddevice(device_name);
414#else
415 bios_device.dev = device;
416#endif
417 biosemu_dev_get_addr_info();
418#ifndef CONFIG_PCI_OPTION_ROM_RUN_YABEL
419 biosemu_dev_find_vmem_addr();
420 biosemu_dev_get_puid();
421#endif
422 biosemu_dev_get_device_vendor_id();
423 return rval;
424}
425
426
427
428
429
430u8
431biosemu_dev_translate_address(unsigned long * addr)
432{
433 int i = 0;
434 translate_address_t ta;
435#ifndef CONFIG_PCI_OPTION_ROM_RUN_YABEL
436
437
438
439
440
441
442 if ((bios_device.vmem_size > 0)
443 && ((*addr >= 0xA0000) && (*addr < 0xB8000))) {
444 *addr = (*addr - 0xA0000) * 4 + 2 + bios_device.vmem_addr;
445 }
446 if ((bios_device.vmem_size > 0)
447 && ((*addr >= 0xB8000) && (*addr < 0xC0000))) {
448 u8 shift = *addr & 1;
449 *addr &= 0xfffffffe;
450 *addr = (*addr - 0xB8000) * 4 + shift + bios_device.vmem_addr;
451 }
452#endif
453 for (i = 0; i <= taa_last_entry; i++) {
454 ta = translate_address_array[i];
455 if ((*addr >= ta.address) && (*addr <= (ta.address + ta.size))) {
456 *addr += ta.address_offset;
457 return 1;
458 }
459 }
460 return 0;
461}
462