diff options
Diffstat (limited to 'board/MAI/bios_emulator/glue.c')
| -rw-r--r-- | board/MAI/bios_emulator/glue.c | 528 | 
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 000000000..b765ed54c --- /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(); +    } + +} |