#include #include #include <74xx_7xx.h> #ifdef DEBUG #undef DEBUG #endif #ifdef DEBUG #define PRINTF(format, args...) _printf(format , ## args) #else #define PRINTF(format, argc...) #endif static pci_dev_t to_pci(int bus, int devfn) { return PCI_BDF(bus, (devfn>>3), devfn&3); } int mypci_find_device(int vendor, int product, int index) { return pci_find_device(vendor, product, index); } int mypci_bus(int device) { return PCI_BUS(device); } int mypci_devfn(int device) { return (PCI_DEV(device)<<3) | PCI_FUNC(device); } #define mypci_read_func(type, size) \ type mypci_read_cfg_##size##(int bus, int devfn, int offset) \ { \ type c; \ pci_read_config_##size##(to_pci(bus, devfn), offset, &c); \ return c; \ } #define mypci_write_func(type, size) \ void mypci_write_cfg_##size##(int bus, int devfn, int offset, int value) \ { \ pci_write_config_##size##(to_pci(bus, devfn), offset, value); \ } mypci_read_func(u8,byte); mypci_read_func(u16,word); mypci_write_func(u8,byte); mypci_write_func(u16,word); u32 mypci_read_cfg_long(int bus, int devfn, int offset) { u32 c; pci_read_config_dword(to_pci(bus, devfn), offset, &c); return c; } void mypci_write_cfg_long(int bus, int devfn, int offset, int value) { pci_write_config_dword(to_pci(bus, devfn), offset, value); } void _printf(const char *fmt, ...) { va_list args; char buf[CFG_PBSIZE]; va_start(args, fmt); (void)vsprintf(buf, fmt, args); va_end(args); printf(buf); } char *_getenv(char *name) { return getenv(name); } unsigned long get_bar_size(pci_dev_t dev, int offset) { u32 bar_back, bar_value; /* Save old BAR value */ pci_read_config_dword(dev, offset, &bar_back); /* Write all 1's. */ pci_write_config_dword(dev, offset, ~0); /* Now read back the relevant bits */ pci_read_config_dword(dev, offset, &bar_value); /* Restore original value */ pci_write_config_dword(dev, offset, bar_back); if (bar_value == 0) return 0xFFFFFFFF; /* This BAR is disabled */ if ((bar_value & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) { /* This is a memory space BAR. Mask it out so we get the size of it */ return ~(bar_value & PCI_BASE_ADDRESS_MEM_MASK) + 1; } /* Not suitable */ return 0xFFFFFFFF; } void enable_compatibility_hole(void) { u8 cfg; pci_dev_t art = PCI_BDF(0,0,0); pci_read_config_byte(art, 0x54, &cfg); /* cfg |= 0x08; */ cfg |= 0x20; pci_write_config_byte(art, 0x54, cfg); } void disable_compatibility_hole(void) { u8 cfg; pci_dev_t art = PCI_BDF(0,0,0); pci_read_config_byte(art, 0x54, &cfg); /* cfg &= ~0x08; */ cfg &= ~0x20; pci_write_config_byte(art, 0x54, cfg); } void map_rom(pci_dev_t dev, u32 address) { pci_write_config_dword(dev, PCI_ROM_ADDRESS, address|PCI_ROM_ADDRESS_ENABLE); } void unmap_rom(pci_dev_t dev) { pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0); } void bat_map(u8 batnum, u32 address, u32 length) { u32 temp = address; address &= 0xFFFE0000; temp &= 0x0001FFFF; length = (length - 1 ) >> 17; length <<= 2; switch (batnum) { case 0: __asm volatile ("mtdbatu 0, %0" : : "r" (address | length | 3)); __asm volatile ("mtdbatl 0, %0" : : "r" (address | 0x22)); break; case 1: __asm volatile ("mtdbatu 1, %0" : : "r" (address | length | 3)); __asm volatile ("mtdbatl 1, %0" : : "r" (address | 0x22)); break; case 2: __asm volatile ("mtdbatu 2, %0" : : "r" (address | length | 3)); __asm volatile ("mtdbatl 2, %0" : : "r" (address | 0x22)); break; case 3: __asm volatile ("mtdbatu 3, %0" : : "r" (address | length | 3)); __asm volatile ("mtdbatl 3, %0" : : "r" (address | 0x22)); break; } } int find_image(u32 rom_address, u32 rom_size, void **image, u32 *image_size); int attempt_map_rom(pci_dev_t dev, void *copy_address) { u32 rom_size = 0; u32 rom_address = 0; u32 bar_size = 0; u32 bar_backup = 0; int i,j; void *image = 0; u32 image_size = 0; int did_correct = 0; u32 prefetch_addr = 0; u32 prefetch_size = 0; u32 prefetch_idx = 0; /* Get the size of the expansion rom */ pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0xFFFFFFFF); pci_read_config_dword(dev, PCI_ROM_ADDRESS, &rom_size); if ((rom_size & 0x01) == 0) { PRINTF("No ROM\n"); return 0; } rom_size &= 0xFFFFF800; rom_size = (~rom_size)+1; PRINTF("ROM Size is %dK\n", rom_size/1024); /* * Try to find a place for the ROM. We always attempt to use * one of the card's bases for this, as this will be in any * bridge's resource range as well as being free of conflicts * with other cards. In a graphics card it is very unlikely * that there won't be any base address that is large enough to * hold the rom. * * FIXME: To work around this, theoretically the largest base * could be used if none is found in the loop below. */ for (i = PCI_BASE_ADDRESS_0; i <= PCI_BASE_ADDRESS_5; i += 4) { bar_size = get_bar_size(dev, i); PRINTF("PCI_BASE_ADDRESS_%d is %dK large\n", (i - PCI_BASE_ADDRESS_0)/4, bar_size/1024); if (bar_size != 0xFFFFFFFF && bar_size >= rom_size) { PRINTF("Found a match for rom size\n"); pci_read_config_dword(dev, i, &rom_address); rom_address &= 0xFFFFFFF0; if (rom_address != 0 && rom_address != 0xFFFFFFF0) break; } } if (rom_address == 0 || rom_address == 0xFFFFFFF0) { PRINTF("No suitable rom address found\n"); return 0; } /* Disable the BAR */ pci_read_config_dword(dev, i, &bar_backup); pci_write_config_dword(dev, i, 0); /* Map ROM */ pci_write_config_dword(dev, PCI_ROM_ADDRESS, rom_address | PCI_ROM_ADDRESS_ENABLE); /* Copy the rom to a place in the emulator space */ PRINTF("Claiming BAT 2\n"); bat_map(2, rom_address, rom_size); /* show_bat_mapping(); */ if (0 == find_image(rom_address, rom_size, &image, &image_size)) { PRINTF("No x86 BIOS image found\n"); return 0; } PRINTF("Copying %ld bytes from 0x%lx to 0x%lx\n", (long)image_size, (long)image, (long)copy_address); /* memcpy(copy_address, rom_address, rom_size); */ { unsigned char *from = (unsigned char *)image; /* rom_address; */ unsigned char *to = (unsigned char *)copy_address; for (j=0; j>16, (prefetch_addr+prefetch_size)>>16); */ /* pci_write_config_word(bridge, PCI_PREF_MEMORY_BASE, (prefetch_addr>>16)); */ /* pci_write_config_word(bridge, PCI_PREF_MEMORY_LIMIT, (prefetch_addr+prefetch_size)>>16); */ } pci_write_config_word(bridge, PCI_PREF_MEMORY_BASE, 0x1000); pci_write_config_word(bridge, PCI_PREF_MEMORY_LIMIT, 0x0000); pci_write_config_byte(bridge, 0xD0, 0x0A); pci_write_config_byte(bridge, 0xD3, 0x04); /* * Set the interrupt pin to 0 */ #if 0 pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 0); pci_write_config_byte(dev, PCI_INTERRUPT_PIN, 0); #endif pci_write_config_byte(bridge, PCI_INTERRUPT_LINE, 0); pci_write_config_byte(bridge, PCI_INTERRUPT_PIN, 0); } } /* Finally, enable the card's IO and memory response */ pci_write_config_dword(dev, PCI_COMMAND, PCI_COMMAND_MEMORY | PCI_COMMAND_IO); pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0); pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0); return 1; } int find_image(u32 rom_address, u32 rom_size, void **image, u32 *image_size) { int i = 0; unsigned char *rom = (unsigned char *)rom_address; /* if (*rom != 0x55 || *(rom+1) != 0xAA) return 0; /* No bios rom this is, yes. */ */ for (;;) { unsigned short pci_data_offset = *(rom+0x18) + 256 * *(rom+0x19); unsigned short pci_image_length = (*(rom+pci_data_offset+0x10) + 256 * *(rom+pci_data_offset+0x11)) * 512; unsigned char pci_image_type = *(rom+pci_data_offset+0x14); if (*rom != 0x55 || *(rom+1) != 0xAA) { PRINTF("Invalid header this is\n"); return 0; } PRINTF("Image %i: Type %d (%s)\n", i++, pci_image_type, pci_image_type==0 ? "x86" : pci_image_type==1 ? "OpenFirmware" : "Unknown"); if (pci_image_type == 0) { *image = rom; *image_size = pci_image_length; return 1; } if (*(rom+pci_data_offset+0x15) & 0x80) { PRINTF("LAST image encountered, no image found\n"); return 0; } rom += pci_image_length; } } void show_bat_mapping(void) { u32 dbat0u, dbat0l, ibat0u, ibat0l; u32 dbat1u, dbat1l, ibat1u, ibat1l; u32 dbat2u, dbat2l, ibat2u, ibat2l; u32 dbat3u, dbat3l, ibat3u, ibat3l; u32 msr, hid0, l2cr_reg; __asm volatile ("mfdbatu %0,0" : "=r" (dbat0u)); __asm volatile ("mfdbatl %0,0" : "=r" (dbat0l)); __asm volatile ("mfibatu %0,0" : "=r" (ibat0u)); __asm volatile ("mfibatl %0,0" : "=r" (ibat0l)); __asm volatile ("mfdbatu %0,1" : "=r" (dbat1u)); __asm volatile ("mfdbatl %0,1" : "=r" (dbat1l)); __asm volatile ("mfibatu %0,1" : "=r" (ibat1u)); __asm volatile ("mfibatl %0,1" : "=r" (ibat1l)); __asm volatile ("mfdbatu %0,2" : "=r" (dbat2u)); __asm volatile ("mfdbatl %0,2" : "=r" (dbat2l)); __asm volatile ("mfibatu %0,2" : "=r" (ibat2u)); __asm volatile ("mfibatl %0,2" : "=r" (ibat2l)); __asm volatile ("mfdbatu %0,3" : "=r" (dbat3u)); __asm volatile ("mfdbatl %0,3" : "=r" (dbat3l)); __asm volatile ("mfibatu %0,3" : "=r" (ibat3u)); __asm volatile ("mfibatl %0,3" : "=r" (ibat3l)); __asm volatile ("mfmsr %0" : "=r" (msr)); __asm volatile ("mfspr %0,1008": "=r" (hid0)); __asm volatile ("mfspr %0,1017": "=r" (l2cr_reg)); printf("dbat0u: %08x dbat0l: %08x ibat0u: %08x ibat0l: %08x\n", dbat0u, dbat0l, ibat0u, ibat0l); printf("dbat1u: %08x dbat1l: %08x ibat1u: %08x ibat1l: %08x\n", dbat1u, dbat1l, ibat1u, ibat1l); printf("dbat2u: %08x dbat2l: %08x ibat2u: %08x ibat2l: %08x\n", dbat2u, dbat2l, ibat2u, ibat2l); printf("dbat3u: %08x dbat3l: %08x ibat3u: %08x ibat3l: %08x\n", dbat3u, dbat3l, ibat3u, ibat3l); printf("\nMSR: %08x HID0: %08x L2CR: %08x \n", msr,hid0, l2cr_reg); } void remove_init_data(void) { char *s; /* Invalidate and disable data cache */ invalidate_l1_data_cache(); dcache_disable(); s = getenv("x86_cache"); if (!s) { icache_enable(); dcache_enable(); } else if (s) { if (strcmp(s, "dcache")==0) { dcache_enable(); } else if (strcmp(s, "icache") == 0) { icache_enable(); } else if (strcmp(s, "on")== 0 || strcmp(s, "both") == 0) { dcache_enable(); icache_enable(); } } /* show_bat_mapping();*/ }