summaryrefslogtreecommitdiff
path: root/board/MAI/bios_emulator/glue.c
diff options
context:
space:
mode:
Diffstat (limited to 'board/MAI/bios_emulator/glue.c')
-rw-r--r--board/MAI/bios_emulator/glue.c528
1 files changed, 528 insertions, 0 deletions
diff --git a/board/MAI/bios_emulator/glue.c b/board/MAI/bios_emulator/glue.c
new file mode 100644
index 0000000..b765ed5
--- /dev/null
+++ b/board/MAI/bios_emulator/glue.c
@@ -0,0 +1,528 @@
+#include <common.h>
+#include <pci.h>
+#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<image_size /*rom_size*/; j++)
+ {
+ *to++ = *from++;
+ }
+ }
+
+ PRINTF("Copy is done\n");
+
+ /* Unmap the ROM and restore the BAR */
+ pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0);
+ pci_write_config_dword(dev, i, bar_backup);
+
+ /* FIXME: */
+ bat_map(2, 0x80000000, 256*1024*1024);
+ show_bat_mapping();
+
+ /*
+ * Since most cards can probably only do 16 bit IO addressing, we
+ * correct their IO base into an appropriate value.
+ * This should do for most.
+ */
+ for (i = PCI_BASE_ADDRESS_0; i <= PCI_BASE_ADDRESS_5; i += 4)
+ {
+ unsigned long value;
+ pci_read_config_dword(dev, i, &value);
+ if (value & 0x01) /* IO */
+ {
+ did_correct = 1;
+ pci_write_config_dword(dev, i, 0x1001);
+ break;
+ }
+
+ if (value & PCI_BASE_ADDRESS_MEM_PREFETCH)
+ {
+ prefetch_idx = i;
+ prefetch_addr = value & PCI_BASE_ADDRESS_MEM_MASK;
+ prefetch_size = get_bar_size(dev, i);
+ }
+ }
+
+ if (1) /* did_correct) */
+ {
+ extern pci_dev_t pci_find_bridge_for_bus(struct pci_controller *hose, int busnr);
+ int busnr = PCI_BUS(dev);
+ if (busnr)
+ {
+ pci_dev_t bridge;
+ PRINTF("Need to correct bridge device for IO range change\n");
+ bridge = pci_find_bridge_for_bus(NULL, busnr);
+ if (bridge == PCI_ANY_ID)
+ {
+ PRINTF("Didn't find bridge. Hope that's OK\n");
+ }
+ else
+ {
+ /*
+ * Set upper I/O base/limit to 0
+ */
+ pci_write_config_byte(bridge, 0x30, 0x00);
+ pci_write_config_byte(bridge, 0x31, 0x00);
+ pci_write_config_byte(bridge, 0x32, 0x00);
+ pci_write_config_byte(bridge, 0x33, 0x00);
+ if (did_correct)
+ {
+ /*
+ * set lower I/O base to 1000
+ * That is, bits 0:3 are set to 0001 by default.
+ * bits 7:4 contain I/O address bits 15:12
+ * all others are assumed 0.
+ */
+ pci_write_config_byte(bridge, 0x1C, 0x11);
+ /*
+ * Set lower I/O limit to 1FFF
+ * That is, bits 0:3 are reserved and always 0000
+ * Bits 7:4 contain I/O address bits 15:12
+ * All others are assumed F.
+ */
+ pci_write_config_byte(bridge, 0x1D, 0x10);
+ pci_write_config_byte(bridge, 0x0D, 0x20);
+ PRINTF("Corrected bridge resource range of bridge at %02x:%02x:%02x\n",
+ PCI_BUS(bridge), PCI_DEV(bridge), PCI_FUNC(bridge));
+
+ }
+ else
+ {
+ /*
+ * This card doesn't have I/O, we disable I/O forwarding
+ */
+ pci_write_config_byte(bridge, 0x1C, 0x11);
+ pci_write_config_byte(bridge, 0x1D, 0x00);
+ pci_write_config_byte(bridge, PCI_INTERRUPT_LINE, 0);
+ pci_write_config_byte(bridge, PCI_INTERRUPT_PIN, 0);
+ pci_write_config_dword(bridge, PCI_COMMAND, PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_IO);
+ PRINTF("Disabled bridge resource range of bridge at %02x:%02x:%02x\n",
+ PCI_BUS(bridge), PCI_DEV(bridge), PCI_FUNC(bridge));
+
+ }
+ }
+ /*
+ * Correct the prefetchable memory base, which is not set correctly by
+ * the U-Boot autoconfig stuff
+ */
+ if (prefetch_idx)
+ {
+/* PRINTF("Setting prefetchable range to %x, %x (%x and %x)\n", */
+/* prefetch_addr, prefetch_addr+prefetch_size, */
+/* prefetch_addr>>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)
+{
+#ifdef DEBUG
+ 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);
+#endif
+}
+
+
+
+void remove_init_data(void)
+{
+ char *s;
+ u32 batl = ((CFG_SDRAM_BASE+0x100000) | BATL_PP_RW);
+ u32 batu =((CFG_SDRAM_BASE+0x100000) | BATU_BL_256M | BATU_VS | BATU_VP);
+#if 0 /* already done in board_init_r() */
+ void *data = (void *)(CFG_INIT_RAM_ADDR+CFG_INIT_DATA_OFFSET);
+ unsigned char data2[CFG_INIT_DATA_SIZE];
+
+ /* Make a copy of the data */
+ memcpy(data2, data, CFG_INIT_DATA_SIZE);
+#endif /* 0 */
+
+ /* Invalidate and disable data cache */
+ invalidate_l1_data_cache();
+ dcache_disable();
+
+#if 0
+ /* Copy to the real RAM address */
+ memcpy(data, data2, CFG_INIT_DATA_SIZE);
+#endif
+
+ /*printf("Before ICache enable\n");
+ show_bat_mapping();*/
+
+ __asm volatile ("isync \n"
+ "mtdbatu 2,%2 \n"
+ "mtdbatl 2,%2 \n"
+ "mtdbatu 1,%0 \n"
+ "mtdbatl 1,%1 \n"
+ "sync \n"
+ "isync \n"
+ : : "r" (batu), "r" (batl), "r" (0));
+
+ /* show_bat_mapping(); */
+ s = getenv("x86_cache");
+
+ if (!s || (s && strcmp(s, "on")==0))
+ {
+ icache_enable();
+ dcache_enable();
+ }
+
+}