📄 pci.c
字号:
//=============================================================================
//
// pci.c
//
// PCI library
//
//=============================================================================
//####COPYRIGHTBEGIN####
//
// -------------------------------------------
// The contents of this file are subject to the Red Hat eCos Public License
// Version 1.1 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://www.redhat.com/
//
// Software distributed under the License is distributed on an "AS IS"
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
// License for the specific language governing rights and limitations under
// the License.
//
// The Original Code is eCos - Embedded Configurable Operating System,
// released September 30, 1998.
//
// The Initial Developer of the Original Code is Red Hat.
// Portions created by Red Hat are
// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
// All Rights Reserved.
// -------------------------------------------
//
//####COPYRIGHTEND####
//=============================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): jskov, from design by nickg
// Contributors: jskov
// Date: 1999-08-09
// Purpose: PCI configuration
// Description:
// PCI bus support library.
// Handles simple resource allocation for devices.
// Can configure 64bit devices, but drivers may need special
// magic to access all of this memory space - this is platform
// specific and the driver must know how to handle it on its own.
//####DESCRIPTIONEND####
//
//=============================================================================
#include <pkgconf/hal.h>
#include <pkgconf/io_pci.h>
#include <cyg/io/pci_hw.h>
// CYG_PCI_PRESENT only gets defined for targets that provide PCI HAL support.
// See pci_hw.h for details.
#ifdef CYG_PCI_PRESENT
#include <cyg/io/pci.h>
#include <cyg/infra/cyg_ass.h>
static cyg_bool cyg_pci_lib_initialized = false;
void
cyg_pci_init( void )
{
if (!cyg_pci_lib_initialized) {
// Initialize the PCI bus, preparing it for general access.
cyg_pcihw_init();
cyg_pci_lib_initialized = true;
}
}
//---------------------------------------------------------------------------
// Common device configuration access functions
void
cyg_pci_get_device_info ( cyg_pci_device_id devid, cyg_pci_device *dev_info )
{
int i;
cyg_uint8 bus = CYG_PCI_DEV_GET_BUS(devid);
cyg_uint8 devfn = CYG_PCI_DEV_GET_DEVFN(devid);
cyg_uint8 header_type;
dev_info->devid = devid;
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_VENDOR,
&dev_info->vendor);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_DEVICE,
&dev_info->device);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_COMMAND,
&dev_info->command);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_STATUS,
&dev_info->status);
cyg_pcihw_read_config_uint32(bus, devfn, CYG_PCI_CFG_CLASS_REV,
&dev_info->class_rev);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_CACHE_LINE_SIZE,
&dev_info->cache_line_size);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_LATENCY_TIMER,
&dev_info->latency_timer);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_HEADER_TYPE,
&header_type);
dev_info->header_type = (cyg_pci_header_type) header_type;
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_BIST,
&dev_info->bist);
if ((dev_info->header_type & CYG_PCI_CFG_HEADER_TYPE_MASK) == CYG_PCI_HEADER_BRIDGE)
dev_info->num_bars = 2;
else
dev_info->num_bars = 6;
for (i = 0; i < dev_info->num_bars; i++)
cyg_pcihw_read_config_uint32(bus, devfn,
CYG_PCI_CFG_BAR_BASE + 4*i,
&dev_info->base_address[i]);
// If device is disabled, probe BARs for sizes.
if ((dev_info->command & CYG_PCI_CFG_COMMAND_ACTIVE) == 0) {
for (i = 0; i < dev_info->num_bars; i++){
cyg_uint32 size;
cyg_pcihw_write_config_uint32(bus, devfn,
CYG_PCI_CFG_BAR_BASE + 4*i,
0xffffffff);
cyg_pcihw_read_config_uint32(bus, devfn,
CYG_PCI_CFG_BAR_BASE + 4*i,
&size);
dev_info->base_size[i] = size;
dev_info->base_map[i] = 0xffffffff;
#ifdef CYGPKG_IO_PCI_DEBUG
printf("BAR %d size = 0x%08x\n", i, dev_info->base_size[i]);
#endif
if (size == 0) {
continue;
}
// Check for a 64bit memory region.
if (CYG_PCI_CFG_BAR_SPACE_MEM ==
(size & CYG_PCI_CFG_BAR_SPACE_MASK)) {
if (size & CYG_PRI_CFG_BAR_MEM_TYPE_64) {
// Clear fields for next BAR - it's the upper 32 bits.
i++;
dev_info->base_size[i] = 0;
dev_info->base_map[i] = 0xffffffff;
}
}
}
} else {
// If the device is already configured. Fill in the base_map.
CYG_PCI_ADDRESS64 tmp_addr;
cyg_uint32 bar;
#ifdef CYGPKG_IO_PCI_DEBUG
printf("Device is already initialized\n");
#endif
for (i = 0; i < dev_info->num_bars; i++){
dev_info->base_size[i] = 0;
bar = dev_info->base_address[i];
if ((bar & CYG_PCI_CFG_BAR_SPACE_MASK) == CYG_PCI_CFG_BAR_SPACE_IO) {
dev_info->base_map[i] = (bar & (CYG_PRI_CFG_BAR_IO_MASK & XSCALE_PCI_IO_SZ_MASK)) + HAL_PCI_PHYSICAL_IO_BASE;
} else {
tmp_addr = bar & (CYG_PRI_CFG_BAR_MEM_MASK & XSCALE_PCI_MEM_SZ_MASK);
if ((bar & CYG_PRI_CFG_BAR_MEM_TYPE_MASK) == CYG_PRI_CFG_BAR_MEM_TYPE_64)
tmp_addr |= ((CYG_PCI_ADDRESS64)(dev_info->base_address[i+1] & CYG_PRI_CFG_BAR_MEM_MASK)) << 32;
tmp_addr += HAL_PCI_PHYSICAL_MEMORY_BASE;
dev_info->base_map[i] = tmp_addr;
if ((bar & CYG_PRI_CFG_BAR_MEM_TYPE_MASK) == CYG_PRI_CFG_BAR_MEM_TYPE_64)
dev_info->base_map[i++] = tmp_addr >> 32;
}
}
}
switch (dev_info->header_type & CYG_PCI_CFG_HEADER_TYPE_MASK) {
case CYG_PCI_HEADER_NORMAL:
cyg_pcihw_read_config_uint32(bus, devfn, CYG_PCI_CFG_CARDBUS_CIS,
&dev_info->header.normal.cardbus_cis);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_SUB_VENDOR,
&dev_info->header.normal.sub_vendor);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_SUB_ID,
&dev_info->header.normal.sub_id);
cyg_pcihw_read_config_uint32(bus, devfn, CYG_PCI_CFG_ROM_ADDRESS,
&dev_info->header.normal.rom_address);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_CAP_LIST,
&dev_info->header.normal.cap_list);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_INT_LINE,
&dev_info->header.normal.int_line);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_INT_PIN,
&dev_info->header.normal.int_pin);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_MIN_GNT,
&dev_info->header.normal.min_gnt);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_MAX_LAT,
&dev_info->header.normal.max_lat);
break;
case CYG_PCI_HEADER_BRIDGE:
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_PRI_BUS,
&dev_info->header.bridge.pri_bus);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_SEC_BUS,
&dev_info->header.bridge.sec_bus);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_SUB_BUS,
&dev_info->header.bridge.sub_bus);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_SEC_LATENCY_TIMER,
&dev_info->header.bridge.sec_latency_timer);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_IO_BASE,
&dev_info->header.bridge.io_base);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_IO_LIMIT,
&dev_info->header.bridge.io_limit);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_SEC_STATUS,
&dev_info->header.bridge.sec_status);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_MEM_BASE,
&dev_info->header.bridge.mem_base);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_MEM_LIMIT,
&dev_info->header.bridge.mem_limit);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_PREFETCH_BASE,
&dev_info->header.bridge.prefetch_base);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_PREFETCH_LIMIT,
&dev_info->header.bridge.prefetch_limit);
cyg_pcihw_read_config_uint32(bus, devfn, CYG_PCI_CFG_PREFETCH_BASE_UPPER32,
&dev_info->header.bridge.prefetch_base_upper32);
cyg_pcihw_read_config_uint32(bus, devfn, CYG_PCI_CFG_PREFETCH_LIMIT_UPPER32,
&dev_info->header.bridge.prefetch_limit_upper32);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_IO_BASE_UPPER16,
&dev_info->header.bridge.io_base_upper16);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_IO_LIMIT_UPPER16,
&dev_info->header.bridge.io_limit_upper16);
cyg_pcihw_read_config_uint32(bus, devfn, CYG_PCI_CFG_BRIDGE_ROM_ADDRESS,
&dev_info->header.bridge.rom_address);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_INT_LINE,
&dev_info->header.bridge.int_line);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_INT_PIN,
&dev_info->header.bridge.int_pin);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_BRIDGE_CONTROL,
&dev_info->header.bridge.control);
break;
case CYG_PCI_HEADER_CARDBUS_BRIDGE:
CYG_FAIL("PCI device header 'cardbus bridge' support not implemented");
break;
default:
CYG_FAIL("Unknown PCI device header type");
break;
}
}
void
cyg_pci_set_device_info ( cyg_pci_device_id devid, cyg_pci_device *dev_info )
{
cyg_uint8 bus = CYG_PCI_DEV_GET_BUS(devid);
cyg_uint8 devfn = CYG_PCI_DEV_GET_DEVFN(devid);
int i;
// Only writable entries are updated.
cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_COMMAND,
dev_info->command);
cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_STATUS,
dev_info->status);
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_CACHE_LINE_SIZE,
dev_info->cache_line_size);
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_LATENCY_TIMER,
dev_info->latency_timer);
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_BIST,
dev_info->bist);
for (i = 0; i < dev_info->num_bars; i++) {
cyg_pcihw_write_config_uint32(bus, devfn, CYG_PCI_CFG_BAR_BASE+4*i,
dev_info->base_address[i]);
}
switch (dev_info->header_type & CYG_PCI_CFG_HEADER_TYPE_MASK) {
case CYG_PCI_HEADER_NORMAL:
cyg_pcihw_write_config_uint32(bus, devfn, CYG_PCI_CFG_CARDBUS_CIS,
dev_info->header.normal.cardbus_cis);
cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_SUB_VENDOR,
dev_info->header.normal.sub_vendor);
cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_SUB_ID,
dev_info->header.normal.sub_id);
cyg_pcihw_write_config_uint32(bus, devfn, CYG_PCI_CFG_ROM_ADDRESS,
dev_info->header.normal.rom_address);
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_INT_LINE,
dev_info->header.normal.int_line);
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_INT_PIN,
dev_info->header.normal.int_pin);
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_MIN_GNT,
dev_info->header.normal.min_gnt);
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_MAX_LAT,
dev_info->header.normal.max_lat);
break;
case CYG_PCI_HEADER_BRIDGE:
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_PRI_BUS,
dev_info->header.bridge.pri_bus);
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_SEC_BUS,
dev_info->header.bridge.sec_bus);
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_SUB_BUS,
dev_info->header.bridge.sub_bus);
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_SEC_LATENCY_TIMER,
dev_info->header.bridge.sec_latency_timer);
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_IO_BASE,
dev_info->header.bridge.io_base);
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_IO_LIMIT,
dev_info->header.bridge.io_limit);
cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_SEC_STATUS,
dev_info->header.bridge.sec_status);
cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_MEM_BASE,
dev_info->header.bridge.mem_base);
cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_MEM_LIMIT,
dev_info->header.bridge.mem_limit);
cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_PREFETCH_BASE,
dev_info->header.bridge.prefetch_base);
cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_PREFETCH_LIMIT,
dev_info->header.bridge.prefetch_limit);
cyg_pcihw_write_config_uint32(bus, devfn, CYG_PCI_CFG_PREFETCH_BASE_UPPER32,
dev_info->header.bridge.prefetch_base_upper32);
cyg_pcihw_write_config_uint32(bus, devfn, CYG_PCI_CFG_PREFETCH_LIMIT_UPPER32,
dev_info->header.bridge.prefetch_limit_upper32);
cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_IO_BASE_UPPER16,
dev_info->header.bridge.io_base_upper16);
cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_IO_LIMIT_UPPER16,
dev_info->header.bridge.io_limit_upper16);
cyg_pcihw_write_config_uint32(bus, devfn, CYG_PCI_CFG_BRIDGE_ROM_ADDRESS,
dev_info->header.bridge.rom_address);
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_INT_LINE,
dev_info->header.bridge.int_line);
cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_BRIDGE_CONTROL,
dev_info->header.bridge.control);
break;
case CYG_PCI_HEADER_CARDBUS_BRIDGE:
CYG_FAIL("PCI device header 'cardbus bridge' support not implemented");
break;
default:
CYG_FAIL("Unknown PCI device header type");
break;
}
// Update values in dev_info.
cyg_pci_get_device_info(devid, dev_info);
}
//---------------------------------------------------------------------------
// Specific device configuration access functions
void
cyg_pci_read_config_uint8( cyg_pci_device_id devid,
cyg_uint8 offset, cyg_uint8 *val)
{
cyg_pcihw_read_config_uint8(CYG_PCI_DEV_GET_BUS(devid),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -