]> git.ipfire.org Git - people/ms/u-boot.git/blob - board/MAI/bios_emulator/scitech/src/biosemu/warmboot.c
USB: This patch fix readl in ohci swap reg access.
[people/ms/u-boot.git] / board / MAI / bios_emulator / scitech / src / biosemu / warmboot.c
1 /****************************************************************************
2 *
3 * BIOS emulator and interface
4 * to Realmode X86 Emulator Library
5 *
6 * Copyright (C) 1996-1999 SciTech Software, Inc.
7 *
8 * ========================================================================
9 *
10 * Permission to use, copy, modify, distribute, and sell this software and
11 * its documentation for any purpose is hereby granted without fee,
12 * provided that the above copyright notice appear in all copies and that
13 * both that copyright notice and this permission notice appear in
14 * supporting documentation, and that the name of the authors not be used
15 * in advertising or publicity pertaining to distribution of the software
16 * without specific, written prior permission. The authors makes no
17 * representations about the suitability of this software for any purpose.
18 * It is provided "as is" without express or implied warranty.
19 *
20 * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
21 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
22 * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
23 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
24 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
25 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
26 * PERFORMANCE OF THIS SOFTWARE.
27 *
28 * ========================================================================
29 *
30 * Language: ANSI C
31 * Environment: Any
32 * Developer: Kendall Bennett
33 *
34 * Description: Module to implement warm booting of all PCI/AGP controllers
35 * on the bus. We use the x86 real mode emulator to run the
36 * BIOS on the primary and secondary controllers to bring
37 * the cards up.
38 *
39 ****************************************************************************/
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <stdarg.h>
45 #include "biosemu.h"
46 #ifndef _MAX_PATH
47 #define _MAX_PATH 256
48 #endif
49
50 /*------------------------- Global Variables ------------------------------*/
51
52 static PCIDeviceInfo PCI[MAX_PCI_DEVICES];
53 static int NumPCI = -1;
54 static int BridgeIndex[MAX_PCI_DEVICES] = {0};
55 static int NumBridges;
56 static PCIBridgeInfo *AGPBridge = NULL;
57 static int DeviceIndex[MAX_PCI_DEVICES] = {0};
58 static int NumDevices;
59 static u32 debugFlags = 0;
60 static BE_VGAInfo VGAInfo[MAX_PCI_DEVICES] = {{0}};
61 static ibool useV86 = false;
62 static ibool forcePost = false;
63
64 /* Length of the BIOS image */
65
66 #define MAX_BIOSLEN (64 * 1024L)
67 #define FINAL_BIOSLEN (32 * 1024L)
68
69 /* Macro to determine if the VGA is enabled and responding */
70
71 #define VGA_NOT_ACTIVE() (forcePost || (PM_inpb(0x3CC) == 0xFF) || ((PM_inpb(0x3CC) & 0x2) == 0))
72
73 #define ENABLE_DEVICE(device) \
74 PCI_writePCIRegB(0x4,PCI[DeviceIndex[device]].Command | 0x7,device)
75
76 #define DISABLE_DEVICE(device) \
77 PCI_writePCIRegB(0x4,0,device)
78
79 /* Macros to enable and disable AGP VGA resources */
80
81 #define ENABLE_AGP_VGA() \
82 PCI_accessReg(0x3E,AGPBridge->BridgeControl | 0x8,PCI_WRITE_WORD,(PCIDeviceInfo*)AGPBridge)
83
84 #define DISABLE_AGP_VGA() \
85 PCI_accessReg(0x3E,AGPBridge->BridgeControl & ~0x8,PCI_WRITE_WORD,(PCIDeviceInfo*)AGPBridge)
86
87 #define RESTORE_AGP_VGA() \
88 PCI_accessReg(0x3E,AGPBridge->BridgeControl,PCI_WRITE_WORD,(PCIDeviceInfo*)AGPBridge)
89
90 /*-------------------------- Implementation -------------------------------*/
91
92 /****************************************************************************
93 RETURNS:
94 The address to use to map the secondary BIOS (PCI/AGP devices)
95
96 REMARKS:
97 Searches all the PCI base address registers for the device looking for a
98 memory mapping that is large enough to hold our ROM BIOS. We usually end up
99 finding the framebuffer mapping (usually BAR 0x10), and we use this mapping
100 to map the BIOS for the device into. We use a mapping that is already
101 assigned to the device to ensure the memory range will be passed through
102 by any PCI->PCI or AGP->PCI bridge that may be present.
103
104 NOTE: Usually this function is only used for AGP devices, but it may be
105 used for PCI devices that have already been POST'ed and the BIOS
106 ROM base address has been zero'ed out.
107 ****************************************************************************/
108 static ulong PCI_findBIOSAddr(
109 int device)
110 {
111 ulong base,size;
112 int bar;
113
114 for (bar = 0x10; bar <= 0x14; bar++) {
115 base = PCI_readPCIRegL(bar,device) & ~0xFF;
116 if (!(base & 0x1)) {
117 PCI_writePCIRegL(bar,0xFFFFFFFF,device);
118 size = PCI_readPCIRegL(bar,device) & ~0xFF;
119 size = ~size+1;
120 PCI_writePCIRegL(bar,0,device);
121 if (size >= MAX_BIOSLEN)
122 return base;
123 }
124 }
125 return 0;
126 }
127
128 /****************************************************************************
129 REMARKS:
130 Re-writes the PCI base address registers for the secondary PCI controller
131 with the values from our initial PCI bus enumeration. This fixes up the
132 values after we have POST'ed the secondary display controller BIOS, which
133 may have incorrectly re-programmed the base registers the same as the
134 primary display controller (the case for identical S3 cards).
135 ****************************************************************************/
136 static void _PCI_fixupSecondaryBARs(void)
137 {
138 int i;
139
140 for (i = 0; i < NumDevices; i++) {
141 PCI_writePCIRegL(0x10,PCI[DeviceIndex[i]].BaseAddress10,i);
142 PCI_writePCIRegL(0x14,PCI[DeviceIndex[i]].BaseAddress14,i);
143 PCI_writePCIRegL(0x18,PCI[DeviceIndex[i]].BaseAddress18,i);
144 PCI_writePCIRegL(0x1C,PCI[DeviceIndex[i]].BaseAddress1C,i);
145 PCI_writePCIRegL(0x20,PCI[DeviceIndex[i]].BaseAddress20,i);
146 PCI_writePCIRegL(0x24,PCI[DeviceIndex[i]].BaseAddress24,i);
147 }
148 }
149
150 /****************************************************************************
151 RETURNS:
152 True if successfully initialised, false if not.
153
154 REMARKS:
155 This function executes the BIOS POST code on the controller. We assume that
156 at this stage the controller has its I/O and memory space enabled and
157 that all other controllers are in a disabled state.
158 ****************************************************************************/
159 static void PCI_doBIOSPOST(
160 int device,
161 ulong BIOSPhysAddr,
162 void *mappedBIOS,
163 ulong BIOSLen)
164 {
165 RMREGS regs;
166 RMSREGS sregs;
167
168 /* Determine the value to store in AX for BIOS POST */
169 regs.x.ax = (u16)(PCI[DeviceIndex[device]].slot.i >> 8);
170 if (useV86) {
171 /* Post the BIOS using the PM functions (ie: v86 mode on Linux) */
172 if (!PM_doBIOSPOST(regs.x.ax,BIOSPhysAddr,mappedBIOS,BIOSLen)) {
173 /* If the PM function fails, this probably means are we are on */
174 /* DOS and can't re-map the real mode 0xC0000 region. In thise */
175 /* case if the device is the primary, we can use the real */
176 /* BIOS at 0xC0000 directly. */
177 if (device == 0)
178 PM_doBIOSPOST(regs.x.ax,0xC0000,mappedBIOS,BIOSLen);
179 }
180 }
181 else {
182 /* Setup the X86 emulator for the VGA BIOS */
183 BE_setVGA(&VGAInfo[device]);
184
185 /* Execute the BIOS POST code */
186 BE_callRealMode(0xC000,0x0003,&regs,&sregs);
187
188 /* Cleanup and exit */
189 BE_getVGA(&VGAInfo[device]);
190 }
191 }
192
193 /****************************************************************************
194 RETURNS:
195 True if successfully initialised, false if not.
196
197 REMARKS:
198 Loads and POST's the secondary controllers BIOS, directly from the BIOS
199 image we can extract over the PCI bus.
200 ****************************************************************************/
201 static ibool PCI_postControllers(void)
202 {
203 int device;
204 ulong BIOSImageLen,mappedBIOSPhys;
205 uchar *mappedBIOS,*copyOfBIOS;
206 char filename[_MAX_PATH];
207 FILE *f;
208
209 /* Disable the primary display controller and AGP VGA pass-through */
210 DISABLE_DEVICE(0);
211 if (AGPBridge)
212 DISABLE_AGP_VGA();
213
214 /* Now POST all the secondary controllers */
215 for (device = 0; device < NumDevices; device++) {
216 /* Skip the device if it is not enabled (probably an ISA device) */
217 if (DeviceIndex[device] == -1)
218 continue;
219
220 /* Enable secondary display controller. If the secondary controller */
221 /* is on the AGP bus, then enable VGA resources for the AGP device. */
222 ENABLE_DEVICE(device);
223 if (AGPBridge && AGPBridge->SecondayBusNumber == PCI[DeviceIndex[device]].slot.p.Bus)
224 ENABLE_AGP_VGA();
225
226 /* Check if the controller has already been POST'ed */
227 if (VGA_NOT_ACTIVE()) {
228 /* Find a viable place to map the secondary PCI BIOS image and map it */
229 printk("Device %d not enabled, so attempting warm boot it\n", device);
230
231 /* For AGP devices (and PCI devices that do have the ROM base */
232 /* address zero'ed out) we have to map the BIOS to a location */
233 /* that is passed by the AGP bridge to the bus. Some AGP devices */
234 /* have the ROM base address already set up for us, and some */
235 /* do not (we map to one of the existing BAR locations in */
236 /* this case). */
237 mappedBIOS = NULL;
238 if (PCI[DeviceIndex[device]].ROMBaseAddress != 0)
239 mappedBIOSPhys = PCI[DeviceIndex[device]].ROMBaseAddress & ~0xF;
240 else
241 mappedBIOSPhys = PCI_findBIOSAddr(device);
242 printk("Mapping BIOS image to 0x%08X\n", mappedBIOSPhys);
243 mappedBIOS = PM_mapPhysicalAddr(mappedBIOSPhys,MAX_BIOSLEN-1,false);
244 PCI_writePCIRegL(0x30,mappedBIOSPhys | 0x1,device);
245 BIOSImageLen = mappedBIOS[2] * 512;
246 if ((copyOfBIOS = malloc(BIOSImageLen)) == NULL)
247 return false;
248 memcpy(copyOfBIOS,mappedBIOS,BIOSImageLen);
249 PM_freePhysicalAddr(mappedBIOS,MAX_BIOSLEN-1);
250
251 /* Allocate memory to store copy of BIOS from secondary controllers */
252 VGAInfo[device].pciInfo = &PCI[DeviceIndex[device]];
253 VGAInfo[device].BIOSImage = copyOfBIOS;
254 VGAInfo[device].BIOSImageLen = BIOSImageLen;
255
256 /* Restore device mappings */
257 PCI_writePCIRegL(0x30,PCI[DeviceIndex[device]].ROMBaseAddress,device);
258 PCI_writePCIRegL(0x10,PCI[DeviceIndex[device]].BaseAddress10,device);
259 PCI_writePCIRegL(0x14,PCI[DeviceIndex[device]].BaseAddress14,device);
260
261 /* Now execute the BIOS POST for the device */
262 if (copyOfBIOS[0] == 0x55 && copyOfBIOS[1] == 0xAA) {
263 printk("Executing BIOS POST for controller.\n");
264 PCI_doBIOSPOST(device,mappedBIOSPhys,copyOfBIOS,BIOSImageLen);
265 }
266
267 /* Reset the size of the BIOS image to the final size */
268 VGAInfo[device].BIOSImageLen = FINAL_BIOSLEN;
269
270 /* Save the BIOS and interrupt vector information to disk */
271 sprintf(filename,"%s/bios.%02d",PM_getNucleusConfigPath(),device);
272 if ((f = fopen(filename,"wb")) != NULL) {
273 fwrite(copyOfBIOS,1,FINAL_BIOSLEN,f);
274 fwrite(VGAInfo[device].LowMem,1,sizeof(VGAInfo[device].LowMem),f);
275 fclose(f);
276 }
277 }
278 else {
279 /* Allocate memory to store copy of BIOS from secondary controllers */
280 if ((copyOfBIOS = malloc(FINAL_BIOSLEN)) == NULL)
281 return false;
282 VGAInfo[device].pciInfo = &PCI[DeviceIndex[device]];
283 VGAInfo[device].BIOSImage = copyOfBIOS;
284 VGAInfo[device].BIOSImageLen = FINAL_BIOSLEN;
285
286 /* Load the BIOS and interrupt vector information from disk */
287 sprintf(filename,"%s/bios.%02d",PM_getNucleusConfigPath(),device);
288 if ((f = fopen(filename,"rb")) != NULL) {
289 fread(copyOfBIOS,1,FINAL_BIOSLEN,f);
290 fread(VGAInfo[device].LowMem,1,sizeof(VGAInfo[device].LowMem),f);
291 fclose(f);
292 }
293 }
294
295 /* Fix up all the secondary PCI base address registers */
296 /* (restores them all from the values we read previously) */
297 _PCI_fixupSecondaryBARs();
298
299 /* Disable the secondary controller and AGP VGA pass-through */
300 DISABLE_DEVICE(device);
301 if (AGPBridge)
302 DISABLE_AGP_VGA();
303 }
304
305 /* Reenable primary display controller and reset AGP bridge control */
306 if (AGPBridge)
307 RESTORE_AGP_VGA();
308 ENABLE_DEVICE(0);
309
310 /* Free physical BIOS image mapping */
311 PM_freePhysicalAddr(mappedBIOS,MAX_BIOSLEN-1);
312
313 /* Restore the X86 emulator BIOS info to primary controller */
314 if (!useV86)
315 BE_setVGA(&VGAInfo[0]);
316 return true;
317 }
318
319 /****************************************************************************
320 REMARKS:
321 Enumerates the PCI bus and dumps the PCI configuration information to the
322 log file.
323 ****************************************************************************/
324 static void EnumeratePCI(void)
325 {
326 int i,index;
327 PCIBridgeInfo *info;
328
329 printk("Displaying enumeration of PCI bus (%d devices, %d display devices)\n",
330 NumPCI, NumDevices);
331 for (index = 0; index < NumDevices; index++)
332 printk(" Display device %d is PCI device %d\n",index,DeviceIndex[index]);
333 printk("\n");
334 printk("Bus Slot Fnc DeviceID SubSystem Rev Class IRQ Int Cmd\n");
335 for (i = 0; i < NumPCI; i++) {
336 printk("%2d %2d %2d %04X:%04X %04X:%04X %02X %02X:%02X %02X %02X %04X ",
337 PCI[i].slot.p.Bus,
338 PCI[i].slot.p.Device,
339 PCI[i].slot.p.Function,
340 PCI[i].VendorID,
341 PCI[i].DeviceID,
342 PCI[i].SubSystemVendorID,
343 PCI[i].SubSystemID,
344 PCI[i].RevID,
345 PCI[i].BaseClass,
346 PCI[i].SubClass,
347 PCI[i].InterruptLine,
348 PCI[i].InterruptPin,
349 PCI[i].Command);
350 for (index = 0; index < NumDevices; index++) {
351 if (DeviceIndex[index] == i)
352 break;
353 }
354 if (index < NumDevices)
355 printk("<- %d\n", index);
356 else
357 printk("\n");
358 }
359 printk("\n");
360 printk("DeviceID Stat Ifc Cch Lat Hdr BIST\n");
361 for (i = 0; i < NumPCI; i++) {
362 printk("%04X:%04X %04X %02X %02X %02X %02X %02X ",
363 PCI[i].VendorID,
364 PCI[i].DeviceID,
365 PCI[i].Status,
366 PCI[i].Interface,
367 PCI[i].CacheLineSize,
368 PCI[i].LatencyTimer,
369 PCI[i].HeaderType,
370 PCI[i].BIST);
371 for (index = 0; index < NumDevices; index++) {
372 if (DeviceIndex[index] == i)
373 break;
374 }
375 if (index < NumDevices)
376 printk("<- %d\n", index);
377 else
378 printk("\n");
379 }
380 printk("\n");
381 printk("DeviceID Base10h Base14h Base18h Base1Ch Base20h Base24h ROMBase\n");
382 for (i = 0; i < NumPCI; i++) {
383 printk("%04X:%04X %08X %08X %08X %08X %08X %08X %08X ",
384 PCI[i].VendorID,
385 PCI[i].DeviceID,
386 PCI[i].BaseAddress10,
387 PCI[i].BaseAddress14,
388 PCI[i].BaseAddress18,
389 PCI[i].BaseAddress1C,
390 PCI[i].BaseAddress20,
391 PCI[i].BaseAddress24,
392 PCI[i].ROMBaseAddress);
393 for (index = 0; index < NumDevices; index++) {
394 if (DeviceIndex[index] == i)
395 break;
396 }
397 if (index < NumDevices)
398 printk("<- %d\n", index);
399 else
400 printk("\n");
401 }
402 printk("\n");
403 printk("DeviceID BAR10Len BAR14Len BAR18Len BAR1CLen BAR20Len BAR24Len ROMLen\n");
404 for (i = 0; i < NumPCI; i++) {
405 printk("%04X:%04X %08X %08X %08X %08X %08X %08X %08X ",
406 PCI[i].VendorID,
407 PCI[i].DeviceID,
408 PCI[i].BaseAddress10Len,
409 PCI[i].BaseAddress14Len,
410 PCI[i].BaseAddress18Len,
411 PCI[i].BaseAddress1CLen,
412 PCI[i].BaseAddress20Len,
413 PCI[i].BaseAddress24Len,
414 PCI[i].ROMBaseAddressLen);
415 for (index = 0; index < NumDevices; index++) {
416 if (DeviceIndex[index] == i)
417 break;
418 }
419 if (index < NumDevices)
420 printk("<- %d\n", index);
421 else
422 printk("\n");
423 }
424 printk("\n");
425 printk("Displaying enumeration of %d bridge devices\n",NumBridges);
426 printk("\n");
427 printk("DeviceID P# S# B# IOB IOL MemBase MemLimit PreBase PreLimit Ctrl\n");
428 for (i = 0; i < NumBridges; i++) {
429 info = (PCIBridgeInfo*)&PCI[BridgeIndex[i]];
430 printk("%04X:%04X %02X %02X %02X %04X %04X %08X %08X %08X %08X %04X\n",
431 info->VendorID,
432 info->DeviceID,
433 info->PrimaryBusNumber,
434 info->SecondayBusNumber,
435 info->SubordinateBusNumber,
436 ((u16)info->IOBase << 8) & 0xF000,
437 info->IOLimit ?
438 ((u16)info->IOLimit << 8) | 0xFFF : 0,
439 ((u32)info->MemoryBase << 16) & 0xFFF00000,
440 info->MemoryLimit ?
441 ((u32)info->MemoryLimit << 16) | 0xFFFFF : 0,
442 ((u32)info->PrefetchableMemoryBase << 16) & 0xFFF00000,
443 info->PrefetchableMemoryLimit ?
444 ((u32)info->PrefetchableMemoryLimit << 16) | 0xFFFFF : 0,
445 info->BridgeControl);
446 }
447 printk("\n");
448 }
449
450 /****************************************************************************
451 RETURNS:
452 Number of display devices found.
453
454 REMARKS:
455 This function enumerates the number of available display devices on the
456 PCI bus, and returns the number found.
457 ****************************************************************************/
458 static int PCI_enumerateDevices(void)
459 {
460 int i,j;
461 PCIBridgeInfo *info;
462
463 /* If this is the first time we have been called, enumerate all */
464 /* devices on the PCI bus. */
465 if (NumPCI == -1) {
466 for (i = 0; i < MAX_PCI_DEVICES; i++)
467 PCI[i].dwSize = sizeof(PCI[i]);
468 if ((NumPCI = PCI_enumerate(PCI,MAX_PCI_DEVICES)) == 0)
469 return -1;
470
471 /* Build a list of all PCI bridge devices */
472 for (i = 0,NumBridges = 0,BridgeIndex[0] = -1; i < NumPCI; i++) {
473 if (PCI[i].BaseClass == PCI_BRIDGE_CLASS) {
474 if (NumBridges < MAX_PCI_DEVICES)
475 BridgeIndex[NumBridges++] = i;
476 }
477 }
478
479 /* Now build a list of all display class devices */
480 for (i = 0,NumDevices = 1,DeviceIndex[0] = -1; i < NumPCI; i++) {
481 if (PCI_IS_DISPLAY_CLASS(&PCI[i])) {
482 if ((PCI[i].Command & 0x3) == 0x3) {
483 DeviceIndex[0] = i;
484 }
485 else {
486 if (NumDevices < MAX_PCI_DEVICES)
487 DeviceIndex[NumDevices++] = i;
488 }
489 if (PCI[i].slot.p.Bus != 0) {
490 /* This device is on a different bus than the primary */
491 /* PCI bus, so it is probably an AGP device. Find the */
492 /* AGP bus device that controls that bus so we can */
493 /* control it. */
494 for (j = 0; j < NumBridges; j++) {
495 info = (PCIBridgeInfo*)&PCI[BridgeIndex[j]];
496 if (info->SecondayBusNumber == PCI[i].slot.p.Bus) {
497 AGPBridge = info;
498 break;
499 }
500 }
501 }
502 }
503 }
504
505 /* Enumerate all PCI and bridge devices to log file */
506 EnumeratePCI();
507 }
508 return NumDevices;
509 }
510
511 FILE *logfile;
512
513 void printk(const char *fmt, ...)
514 {
515 va_list argptr;
516 va_start(argptr, fmt);
517 vfprintf(logfile, fmt, argptr);
518 fflush(logfile);
519 va_end(argptr);
520 }
521
522 int main(int argc,char *argv[])
523 {
524 while (argc > 1) {
525 if (stricmp(argv[1],"-usev86") == 0) {
526 useV86 = true;
527 }
528 else if (stricmp(argv[1],"-force") == 0) {
529 forcePost = true;
530 }
531 #ifdef DEBUG
532 else if (stricmp(argv[1],"-decode") == 0) {
533 debugFlags |= DEBUG_DECODE_F;
534 }
535 else if (stricmp(argv[1],"-iotrace") == 0) {
536 debugFlags |= DEBUG_IO_TRACE_F;
537 }
538 #endif
539 else {
540 printf("Usage: warmboot [-usev86] [-force] [-decode] [-iotrace]\n");
541 exit(-1);
542 }
543 argc--;
544 argv++;
545 }
546 if ((logfile = fopen("warmboot.log","w")) == NULL)
547 exit(1);
548
549 PM_init();
550 if (!useV86) {
551 /* Initialise the x86 BIOS emulator */
552 BE_init(false,debugFlags,65536,&VGAInfo[0]);
553 }
554
555 /* Enumerate all devices (which POST's them at the same time) */
556 if (PCI_enumerateDevices() < 1) {
557 printk("No PCI display devices found!\n");
558 return -1;
559 }
560
561 /* Post all the display controller BIOS'es */
562 PCI_postControllers();
563
564 /* Cleanup and exit the emulator */
565 if (!useV86)
566 BE_exit();
567 fclose(logfile);
568 return 0;
569 }