⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pci.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
    if (CYG_PCI_CFG_BAR_SPACE_MEM != (flags & CYG_PCI_CFG_BAR_SPACE_MASK))
        return false;

    // Check type of memory requested...
    mem_type = CYG_PRI_CFG_BAR_MEM_TYPE_MASK & flags;

    // We don't handle <1MB devices optimally yet.
    if (CYG_PRI_CFG_BAR_MEM_TYPE_1M == mem_type
        && (aligned_addr + size) > 1024*1024)
        return false;

    // Update the resource pointer and return values.
    *base = aligned_addr+size;
    *assigned_addr = aligned_addr;

    dev_info->base_map[bar] = (cyg_uint32) 
        (aligned_addr+HAL_PCI_PHYSICAL_MEMORY_BASE) & 0xffffffff;

    // If a 64bit region, store upper 32 bits in the next bar.
    // Note: The CPU is not necessarily able to access the region
    // linearly - it may have to do it in segments. Driver must handle that.
    if (CYG_PRI_CFG_BAR_MEM_TYPE_64 == mem_type) {
        dev_info->base_map[bar+1] = (cyg_uint32) 
            ((aligned_addr+HAL_PCI_PHYSICAL_MEMORY_BASE) >> 32) & 0xffffffff;
    }
    
    return true;
}

cyg_bool
cyg_pci_allocate_memory( cyg_pci_device *dev_info, cyg_uint32 bar,
                         CYG_PCI_ADDRESS64 *base)
{
    cyg_uint8 bus = CYG_PCI_DEV_GET_BUS(dev_info->devid);
    cyg_uint8 devfn = CYG_PCI_DEV_GET_DEVFN(dev_info->devid);
    CYG_PCI_ADDRESS64 assigned_addr;
    cyg_bool ret;

    // Check that device is inactive.
    if ((dev_info->command & CYG_PCI_CFG_COMMAND_ACTIVE) != 0)
        return false;

    // Allocate memory space for the device.
    ret = cyg_pci_allocate_memory_priv(dev_info, bar, base, &assigned_addr);

    if (ret) {
        // Map the device and update the BAR in the dev_info structure.
        cyg_pcihw_write_config_uint32(bus, devfn,
                                      CYG_PCI_CFG_BAR_BASE+4*bar, 
                                      (cyg_uint32) 
                                      (assigned_addr & 0xffffffff));
        cyg_pcihw_read_config_uint32(bus, devfn,
                                     CYG_PCI_CFG_BAR_BASE+4*bar, 
                                     &dev_info->base_address[bar]);

        // Handle upper 32 bits if necessary.
        if (dev_info->base_size[bar] & CYG_PRI_CFG_BAR_MEM_TYPE_64) {
            cyg_pcihw_write_config_uint32(bus, devfn,
                                          CYG_PCI_CFG_BAR_BASE+4*(bar+1), 
                                          (cyg_uint32) 
                                          ((assigned_addr >> 32)& 0xffffffff));
            cyg_pcihw_read_config_uint32(bus, devfn,
                                         CYG_PCI_CFG_BAR_BASE+4*(bar+1), 
                                         &dev_info->base_address[bar+1]);
        }
    }

    return ret;
}    

cyg_bool
cyg_pci_allocate_io_priv( cyg_pci_device *dev_info, cyg_uint32 bar, 
                          CYG_PCI_ADDRESS32 *base, 
                          CYG_PCI_ADDRESS32 *assigned_addr)
{
    cyg_uint32 flags, size;
    CYG_PCI_ADDRESS32 aligned_addr;

    // Get the probed size and flags
    flags = dev_info->base_size[bar];

    // Decode size
    size = (~(flags & CYG_PRI_CFG_BAR_IO_MASK))+1;

    // Calculate address we will assign the device.
    // This can be made more clever.
    // For now, simply align to required size.
    aligned_addr = (*base+size-1) & ~(size-1);

    // Is the request for IO space?
    if (CYG_PCI_CFG_BAR_SPACE_IO != (flags & CYG_PCI_CFG_BAR_SPACE_MASK))
        return false;

    // Update the resource pointer and return values.
    *base = aligned_addr+size;
    dev_info->base_map[bar] = aligned_addr+HAL_PCI_PHYSICAL_IO_BASE;
    *assigned_addr = aligned_addr;

    return true;
}


cyg_bool
cyg_pci_allocate_io( cyg_pci_device *dev_info, cyg_uint32 bar, 
                     CYG_PCI_ADDRESS32 *base)
{
    cyg_uint8 bus = CYG_PCI_DEV_GET_BUS(dev_info->devid);
    cyg_uint8 devfn = CYG_PCI_DEV_GET_DEVFN(dev_info->devid);
    CYG_PCI_ADDRESS32 assigned_addr;
    cyg_bool ret;
    
    // Check that device is inactive.
    if ((dev_info->command & CYG_PCI_CFG_COMMAND_ACTIVE) != 0)
        return false;

    // Allocate IO space for the device.
    ret = cyg_pci_allocate_io_priv(dev_info, bar, base, &assigned_addr);

    if (ret) {
        // Map the device and update the BAR in the dev_info structure.
        cyg_pcihw_write_config_uint32(bus, devfn,
                                      CYG_PCI_CFG_BAR_BASE+4*bar, 
                                      assigned_addr);
        cyg_pcihw_read_config_uint32(bus, devfn,
                                     CYG_PCI_CFG_BAR_BASE+4*bar, 
                                     &dev_info->base_address[bar]);
    }

    return ret;
}

cyg_bool
cyg_pci_translate_interrupt( cyg_pci_device *dev_info,
                             CYG_ADDRWORD *vec )
{
    cyg_uint8 bus = CYG_PCI_DEV_GET_BUS(dev_info->devid);
    cyg_uint8 devfn = CYG_PCI_DEV_GET_DEVFN(dev_info->devid);

    return cyg_pcihw_translate_interrupt(bus, devfn, vec);
}


// Initialize devices on a given bus and all subordinate busses.
cyg_bool
cyg_pci_configure_bus( cyg_uint8 bus,
		       cyg_uint8 *next_bus )
{
    cyg_uint8 devfn, header_type;
    cyg_pci_device_id devid;
    cyg_pci_device dev_info;

    CYG_PCI_ADDRESS64 mem_start, mem_limit, mem_base;
    CYG_PCI_ADDRESS32 io_start, io_limit, io_base;

    // Scan only this bus for valid devices.
    devid = CYG_PCI_DEV_MAKE_ID(bus, 0) | CYG_PCI_NULL_DEVFN;

#ifdef CYGPKG_IO_PCI_DEBUG
    diag_printf("Configuring bus %d.\n", bus);
#endif

    while (cyg_pci_find_next(devid, &devid) && bus == CYG_PCI_DEV_GET_BUS(devid)) {

        devfn = CYG_PCI_DEV_GET_DEVFN(devid);
	
	// Get the device info
	cyg_pci_get_device_info(devid, &dev_info);

#ifdef CYGPKG_IO_PCI_DEBUG
	diag_printf("\n");
	diag_printf("Configuring PCI Bus   : %d\n", bus);
	diag_printf("            PCI Device: %d\n", CYG_PCI_DEV_GET_DEV(devfn));
	diag_printf("            PCI Func  : %d\n", CYG_PCI_DEV_GET_FN(devfn));
	diag_printf("            Vendor Id : 0x%08X\n", dev_info.vendor);
	diag_printf("            Device Id : 0x%08X\n", dev_info.device);
#endif

	header_type = dev_info.header_type & CYG_PCI_CFG_HEADER_TYPE_MASK;

	// Check for supported header types.
	if (header_type != CYG_PCI_HEADER_NORMAL &&
	    header_type != CYG_PCI_HEADER_BRIDGE) {
	    CYG_FAIL("Unsupported PCI header type");
	    continue;
	}

	// Only PCI-to-PCI bridges
	if (header_type == CYG_PCI_HEADER_BRIDGE &&
	    (dev_info.class_rev >> 8) != CYG_PCI_CLASS_BRIDGE_PCI_PCI) {
	    CYG_FAIL("Unsupported PCI bridge class");
	    continue;
	}

	// Configure the base registers
	if (!cyg_pci_configure_device(&dev_info)) {
	    // Apparently out of resources.
	    CYG_FAIL("cyg_pci_configure_device failed");
	    break;
	}
	
	// Activate non-bridge devices.
	if (header_type != CYG_PCI_HEADER_BRIDGE) {
	    dev_info.command |= (CYG_PCI_CFG_COMMAND_IO 	// enable I/O space
		              | CYG_PCI_CFG_COMMAND_MEMORY	// enable memory space
		              | CYG_PCI_CFG_COMMAND_MASTER); 	// enable bus master
	    cyg_pci_write_config_uint16(dev_info.devid, CYG_PCI_CFG_COMMAND, dev_info.command);
	} else {
	    //  Bridge Configuration

	    // Set up the bus numbers that define the bridge
	    dev_info.header.bridge.pri_bus = bus;
	    cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_PRI_BUS,
					 dev_info.header.bridge.pri_bus);

	    dev_info.header.bridge.sec_bus = *next_bus;
	    cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_SEC_BUS,
					 dev_info.header.bridge.sec_bus);

	    // Temporarily set to maximum so config cycles get passed along.
	    dev_info.header.bridge.sub_bus = CYG_PCI_MAX_BUS - 1;
	    cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_SUB_BUS,
					 dev_info.header.bridge.sub_bus);

	    // increment bus counter
	    *next_bus += 1;

	    // To figure the sizes of the memory and I/O windows, save the
	    // current base of memory and I/O before configuring the bus
	    // or busses on the secondary side of the bridge. After the
	    // secondary side is configured, the difference between the
	    // current values and saved values will tell the size.

	    // For bridges, the memory window must start and end on a 1M
	    // boundary and the I/O window must start and end on a 4K
	    // boundary. We round up the mem and I/O allocation bases
	    // to appropriate boundaries before configuring the secondary
	    // bus. Save the pre-rounded values in case no mem or I/O
	    // is needed we can recover any space lost due to rounding.

	    // round up start of PCI memory space to a 1M boundary
	    mem_base = cyg_pci_memory_base;
	    cyg_pci_memory_base += 0xfffff;
	    cyg_pci_memory_base &= ~0xfffff;
	    mem_start = cyg_pci_memory_base;

	    // round up start of PCI I/O space to a 4 Kbyte start address
	    io_base = cyg_pci_io_base;
	    cyg_pci_io_base += 0xfff;
	    cyg_pci_io_base &= ~0xfff;
	    io_start = cyg_pci_io_base;
		
	    // configure the subordinate PCI bus
	    cyg_pci_configure_bus (dev_info.header.bridge.sec_bus, next_bus);
			
	    // set subordinate bus number to last assigned bus number
	    dev_info.header.bridge.sub_bus = *next_bus - 1;
	    cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_SUB_BUS,
					 dev_info.header.bridge.sub_bus);

	    // Did sub bus configuration use any I/O?
	    if (cyg_pci_io_base > io_start) {

		// round up end of bridge's I/O space to a 4K boundary
		cyg_pci_io_base += 0xfff;
		cyg_pci_io_base &= ~0xfff;
		io_limit = cyg_pci_io_base - 0x1000;

		// Enable I/O cycles across bridge
		dev_info.command |= CYG_PCI_CFG_COMMAND_IO;

		// 32 Bit I/O?
		if ((dev_info.header.bridge.io_base & 0x0f) == 0x01) {
		    // I/O Base Upper 16 Bits Register
		    dev_info.header.bridge.io_base_upper16 = io_start >> 16;
		    cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_IO_BASE_UPPER16,
						 dev_info.header.bridge.io_base_upper16);
		    // I/O Limit Upper 16 Bits Register
		    dev_info.header.bridge.io_limit_upper16 = io_limit >> 16;
		    cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_IO_LIMIT_UPPER16,
						 dev_info.header.bridge.io_limit_upper16);
		}

		// I/O Base Register
		dev_info.header.bridge.io_base = (io_start & 0xf000) >> 8;
		cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_IO_BASE,
					     dev_info.header.bridge.io_base);
		// I/O Limit Register
		dev_info.header.bridge.io_limit = (io_limit & 0xf000) >> 8;
		cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_IO_LIMIT,
					     dev_info.header.bridge.io_limit);

	    } else {
		// No I/O space used on secondary bus.
		// Recover any space lost on unnecessary rounding
		cyg_pci_io_base = io_base;
	    }

	    // Did sub bus configuration use any memory?
	    if (cyg_pci_memory_base > mem_start) {

		// round up end of bridge's PCI memory space to a 1M boundary
		cyg_pci_memory_base += 0xfffff;
		cyg_pci_memory_base &= ~0xfffff;
		mem_limit = cyg_pci_memory_base - 0x100000;

		// Enable memory cycles across bridge
		dev_info.command |= CYG_PCI_CFG_COMMAND_MEMORY;

		// Memory Base Register
		dev_info.header.bridge.mem_base = (mem_start >> 16) & 0xfff0;
		cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_MEM_BASE,
						 dev_info.header.bridge.mem_base);

		// Memory Limit Register
		dev_info.header.bridge.mem_limit = (mem_limit >> 16) & 0xfff0;
		cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_MEM_LIMIT,
						 dev_info.header.bridge.mem_limit);

		// Prefetchable memory not yet supported across bridges.
		// Disable by making limit < base
		{
		    cyg_uint16 tmp_word;

		    tmp_word = 0;
		    cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_PREFETCH_LIMIT,
						 tmp_word);
		    tmp_word = 0xfff0;
		    cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_PREFETCH_BASE,
						 tmp_word);
		}
	    } else {
		// No memory space used on secondary bus.
		// Recover any space lost on unnecessary rounding
		cyg_pci_memory_base = mem_base;
	    }

	    // Setup the bridge command register
	    dev_info.command |= CYG_PCI_CFG_COMMAND_MASTER;
	    dev_info.command |= CYG_PCI_CFG_COMMAND_SERR;
	    cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_COMMAND,
					  dev_info.command);

	    /* Setup the Bridge Control Register */
	    dev_info.header.bridge.control |= CYG_PCI_CFG_BRIDGE_CTL_PARITY;
	    dev_info.header.bridge.control |= CYG_PCI_CFG_BRIDGE_CTL_SERR;
	    dev_info.header.bridge.control |= CYG_PCI_CFG_BRIDGE_CTL_MASTER;
	    cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_BRIDGE_CONTROL,
					  dev_info.header.bridge.control);
	}
    }
#ifdef CYGPKG_IO_PCI_DEBUG
    diag_printf("Finished configuring bus %d.\n", bus);
#endif

    return true;
}


#endif // ifdef CYG_PCI_PRESENT

//-----------------------------------------------------------------------------
// end of pci.c

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -