| #include <common.h> |
| #include <pci.h> |
| |
| DECLARE_GLOBAL_DATA_PTR; |
| |
| #define DEBUG |
| |
| #ifdef DEBUG |
| #define PRINTF(format, args...) printf(format , ## args) |
| #else |
| #define PRINTF(format, argc...) |
| #endif |
| |
| #ifdef CONFIG_SAM460EX |
| extern struct pci_controller *ppc460_hose; |
| #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); |
| } |
| |
| 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; |
| } |
| |
| #ifdef DEBUG |
| unsigned long get_real_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 0; |
| |
| 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; |
| } |
| |
| if ((bar_value & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) |
| { |
| return ~(bar_value & PCI_BASE_ADDRESS_IO_MASK) + 1; |
| } |
| |
| return 0; |
| } |
| #endif |
| |
| 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) |
| { |
| return; |
| 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; |
| } |
| } |
| |
| void clear_bat2(void) |
| { |
| return; |
| u32 temp = 0; |
| __asm volatile( |
| "mtdbatu 2, %0\n" |
| "mtdbatl 2, %0\n" |
| "mtibatu 2, %0\n" |
| "mtibatl 2, %0\n" |
| : : "r" (temp)); |
| } |
| |
| void find_radeon_values(pci_dev_t dev, u8 * rom_addr) |
| { |
| u16 bios_header; |
| u16 pll_info_block; |
| struct radeon_data |
| { |
| unsigned short ReferenceFrequency; |
| unsigned short ReferenceDivider; |
| unsigned long PLLMin; |
| unsigned long PLLMax; |
| } __attribute__((packed)); |
| u16 vendor; |
| |
| struct radeon_data *rdat; |
| |
| DECLARE_GLOBAL_DATA_PTR; |
| |
| /* If it's an ATI card, get the values needed by the driver */ |
| pci_read_config_word(dev, PCI_VENDOR_ID, &vendor); |
| if (vendor != 0x1002) |
| return; |
| |
| gd->bd->bi_sramstart = malloc(sizeof(struct radeon_data)); |
| rdat = (struct radeon_data *) gd->bd->bi_sramstart; |
| |
| bios_header = rom_addr[0x48] | (rom_addr[0x49]<<8); |
| bios_header += 0x30; |
| pll_info_block = rom_addr[bios_header] | (rom_addr[bios_header+1]<<8); |
| pll_info_block += 0x0e; |
| |
| rdat->ReferenceFrequency = rom_addr[pll_info_block] | (rom_addr[pll_info_block+1]<<8); |
| pll_info_block += 2; |
| |
| rdat->ReferenceDivider = rom_addr[pll_info_block] | (rom_addr[pll_info_block+1]<<8); |
| pll_info_block += 2; |
| |
| rdat->PLLMin = rom_addr[pll_info_block] |
| | (rom_addr[pll_info_block+1]<<8) |
| | (rom_addr[pll_info_block+2]<<16) |
| | (rom_addr[pll_info_block+3]<<14); |
| pll_info_block += 4; |
| |
| rdat->PLLMax = rom_addr[pll_info_block] |
| | (rom_addr[pll_info_block+1]<<8) |
| | (rom_addr[pll_info_block+2]<<16) |
| | (rom_addr[pll_info_block+3]<<14); |
| } |
| |
| |
| int find_image(u32 rom_address, u32 rom_size, void **image, u32 *image_size); |
| |
| #if defined(CONFIG_SAM440EP) |
| #include "radeon_bios.h" |
| |
| void load_compressed_bios(void *copy_address) |
| { |
| memcpy(copy_address, radeon_bios, 65536); |
| } |
| #endif |
| |
| 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; |
| void *image = 0; |
| u32 image_size = 0; |
| u32 prefetch_idx = 0; |
| u32 lower = 0xFFFFFFFF; |
| u32 upper = 0x00000000; |
| u32 mlower = 0xFFFFFFFF; |
| u32 mupper = 0x00000000; |
| int foundimg = 0; |
| int foundmini = 0; |
| u16 vendor = 0; |
| u32 iobase = 0; |
| |
| #ifdef CONFIG_SAM460EX |
| struct pci_region *isaio = ppc460_hose->regions+0; |
| #else |
| struct pci_region *isaio = gd->ppc440_hose->regions+0; |
| #endif |
| |
| //extern int pciauto_region_allocate(struct pci_region* res, |
| // unsigned int size, unsigned int *bar); |
| |
| /* Get the size of the VGA expansion rom */ |
| |
| #if defined(CONFIG_SAM440EP) |
| if(PCI_BUS(dev) == 0 && PCI_DEV(dev) == 0xc) |
| { |
| foundmini = 1; |
| rom_size = 64*1024; |
| PRINTF("FOUNDMINI\n"); |
| } |
| else |
| #endif |
| { |
| 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; |
| } |
| else |
| { |
| 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. |
| */ |
| #ifdef CONFIG_SAM460EX |
| int found_mem64 = 0; |
| u32 tmp, bar_response = 0; |
| |
| //pci_write_config_dword (dev, PCI_BASE_ADDRESS_0, 0xffffffff); |
| //pci_read_config_dword (dev, PCI_BASE_ADDRESS_0, &bar_response); |
| |
| bar_response = get_bar_size(dev, PCI_BASE_ADDRESS_0); |
| |
| if (!bar_response) return 0; |
| |
| if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == |
| PCI_BASE_ADDRESS_MEM_TYPE_64) |
| { |
| u32 bar_response_upper; |
| u64 bar64; |
| |
| bar_response_upper = get_bar_size(dev, PCI_BASE_ADDRESS_0 + 4); |
| bar64 = ((u64)bar_response_upper << 32) | bar_response; |
| |
| bar_size = ~(bar64 & PCI_BASE_ADDRESS_MEM_MASK) + 1; |
| found_mem64 = 1; |
| PRINTF("bar_size = %08x-%08x\n", bar_response_upper, bar_response); |
| rom_address = bar_response; |
| } else |
| { |
| bar_size = (u32)(~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1); |
| PRINTF("bar_size = %08x\n", bar_size); |
| |
| pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &rom_address); |
| rom_address &= 0xFFFFFFF0; |
| } |
| |
| PRINTF("Rom is being mapped to %p\n", rom_address); |
| |
| if (rom_address == 0 || rom_address == 0xFFFFFFF0) |
| { |
| PRINTF("No suitable rom address found\n"); |
| return 0; |
| } |
| |
| /* Disable the BAR */ |
| |
| pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &bar_backup); |
| pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0); |
| if (found_mem64) |
| { |
| pci_read_config_dword(dev, PCI_BASE_ADDRESS_0+4, &tmp); |
| pci_write_config_dword(dev, PCI_BASE_ADDRESS_0+4, 0); |
| } |
| |
| /* Map ROM */ |
| pci_write_config_dword(dev, PCI_ROM_ADDRESS,rom_address | PCI_ROM_ADDRESS_ENABLE); |
| #else |
| 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; |
| } |
| } |
| |
| PRINTF("Rom is being mapped to %p\n", rom_address); |
| |
| 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); |
| |
| #endif |
| |
| /* Copy the rom to a place in the emulator space */ |
| PRINTF("Trying to find an X86 BIOS image in ROM\n"); |
| |
| #if defined(CONFIG_SAM440EP) |
| if (foundmini == 1) |
| { |
| load_compressed_bios(copy_address); |
| } |
| else |
| #endif |
| { |
| foundimg = find_image(rom_address, rom_size, &image, &image_size); |
| |
| PRINTF("find_image return %d\n", foundimg); |
| if (foundimg == 0) |
| { |
| 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; |
| // PRINTF("----- ROM STARTS HERE -----------\n"); |
| // for (j=0; j<image_size /*rom_size*/; j++) |
| // { |
| // //PRINTF("%c", *from); |
| // *to++ = *from++; |
| // } |
| // PRINTF("----- ROM ENDS HERE --------------\n"); |
| // } |
| } |
| |
| PRINTF("Copy is done\n"); |
| |
| /* If it's an ATI card, get the values needed by the driver */ |
| pci_read_config_word(dev, PCI_VENDOR_ID, &vendor); |
| if ( (vendor == 0x1002) || (foundmini == 1) ) |
| find_radeon_values(dev, copy_address); |
| |
| clear_bat2(); |
| |
| /* Unmap the ROM and restore the BAR */ |
| pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0); |
| pci_write_config_dword(dev, i, bar_backup); |
| |
| iobase = isaio->bus_lower; |
| PRINTF("GLUE.C IOBASE = %x\n",iobase); |
| |
| #ifdef DEBUG |
| PRINTF("\n\nCard Summary\n------------\n"); |
| { |
| int x=0; |
| for (i = PCI_BASE_ADDRESS_0; i <= PCI_BASE_ADDRESS_5; i += 4) |
| { |
| u32 bar_size = get_real_size(dev, i); |
| u32 bar; |
| |
| if (bar_size != 0xFFFFFFFF && bar_size != 0x00000000) |
| { |
| pci_read_config_dword(dev, i, &bar); |
| |
| PRINTF("PCI_BASE_ADDRESS_%d: %p-%p", |
| x, bar&0xFFFFFFF0, (bar&0xFFFFFFF0)+bar_size); |
| if ((bar&PCI_BASE_ADDRESS_SPACE)) |
| { |
| PRINTF(" (io)\n"); |
| } |
| else |
| { |
| PRINTF("(memory"); |
| if (bar & PCI_BASE_ADDRESS_MEM_PREFETCH) |
| PRINTF(",prefetch)\n"); |
| else |
| PRINTF(")\n"); |
| } |
| } |
| ++x; |
| } |
| } |
| #endif |
| |
| return 1; |
| } |
| |
| int find_image(u32 rom_address, u32 rom_size, void **image, u32 *image_size) |
| { |
| #ifdef DEBUG |
| int i = 0; |
| #endif |
| unsigned char *rom = (unsigned char *)rom_address; |
| |
| PRINTF("find_image:\n"); |
| PRINTF("rom_address = %p\n", rom_address); |
| |
| /* if (*rom != 0x55 || *(rom+1) != 0xAA) return 0; // No bios rom this is, yes. */ |
| #if 1 |
| { |
| int j; |
| unsigned int length; |
| unsigned int data_offs = *(rom+0x18) + 256* *(rom+0x19); |
| |
| PRINTF("Rom data offset at %p\n", data_offs); |
| PRINTF("Rom header: "); |
| for (j=0; j<0x16; j++) |
| { |
| PRINTF("%02x ", *(rom+j)); |
| } |
| PRINTF("\n"); |
| PRINTF("Image header: "); |
| for (j=0; j<0x16; j++) |
| { |
| PRINTF("%02x ", *(rom+j+data_offs)); |
| } |
| PRINTF("\n"); |
| length = *(rom+data_offs+0x10) + 256* *(rom+data_offs+0x11); |
| PRINTF("length: raw=%d, yields %d\n", length, length*512); |
| } |
| #endif |
| for (;;) |
| { |
| unsigned int pci_data_offset = *(rom+0x18) + 256 * *(rom+0x19); |
| unsigned int 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"); |
| PRINTF("Image size: %d\n", pci_image_length); |
| 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) |
| { |
| } |
| |
| |
| void remove_init_data(void) |
| { |
| //invalidate_l1_data_cache(); |
| dcache_disable(); |
| icache_enable(); |
| //l1dcache_enable(); |
| /* |
| char *s; |
| |
| // Invalidate and disable data cache |
| invalidate_l1_data_cache(); |
| l2cache_invalidate(); |
| dcache_disable(); |
| |
| s = getenv("x86_cache"); |
| |
| if (!s) |
| { |
| icache_enable(); |
| l1dcache_enable(); |
| } |
| else if (s) |
| { |
| if (strcmp(s, "dcache")==0) |
| { |
| l1dcache_enable(); |
| } |
| else if (strcmp(s, "icache") == 0) |
| { |
| icache_enable(); |
| } |
| else if (strcmp(s, "on")== 0 || strcmp(s, "both") == 0) |
| { |
| l1dcache_enable(); |
| icache_enable(); |
| } |
| } |
| |
| l2cache_disable(); |
| // show_bat_mapping(); |
| */ |
| } |
| |