dm: pci: Add APIs to find capability and extended capability

This introduces two new APIs dm_pci_find_capability() and
dm_pci_find_ext_capability() to get PCI capability address and
PCI express extended capability address for a given PCI device.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Bin Meng 2018-08-03 01:14:52 -07:00 committed by Simon Glass
parent 5d544f962f
commit dac01fd89d
2 changed files with 114 additions and 0 deletions

View File

@ -1320,6 +1320,74 @@ void *dm_pci_map_bar(struct udevice *dev, int bar, int flags)
return dm_pci_bus_to_virt(dev, pci_bus_addr, flags, 0, MAP_NOCACHE);
}
int dm_pci_find_capability(struct udevice *dev, int cap)
{
u16 status;
u8 header_type;
int ttl = PCI_FIND_CAP_TTL;
u8 id;
u16 ent;
u8 pos;
dm_pci_read_config16(dev, PCI_STATUS, &status);
if (!(status & PCI_STATUS_CAP_LIST))
return 0;
dm_pci_read_config8(dev, PCI_HEADER_TYPE, &header_type);
if ((header_type & 0x7f) == PCI_HEADER_TYPE_CARDBUS)
pos = PCI_CB_CAPABILITY_LIST;
else
pos = PCI_CAPABILITY_LIST;
dm_pci_read_config8(dev, pos, &pos);
while (ttl--) {
if (pos < PCI_STD_HEADER_SIZEOF)
break;
pos &= ~3;
dm_pci_read_config16(dev, pos, &ent);
id = ent & 0xff;
if (id == 0xff)
break;
if (id == cap)
return pos;
pos = (ent >> 8);
}
return 0;
}
int dm_pci_find_ext_capability(struct udevice *dev, int cap)
{
u32 header;
int ttl;
int pos = PCI_CFG_SPACE_SIZE;
/* minimum 8 bytes per capability */
ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
dm_pci_read_config32(dev, pos, &header);
/*
* If we have no capabilities, this is indicated by cap ID,
* cap version and next pointer all being 0.
*/
if (header == 0)
return 0;
while (ttl--) {
if (PCI_EXT_CAP_ID(header) == cap)
return pos;
pos = PCI_EXT_CAP_NEXT(header);
if (pos < PCI_CFG_SPACE_SIZE)
break;
dm_pci_read_config32(dev, pos, &header);
}
return 0;
}
UCLASS_DRIVER(pci) = {
.id = UCLASS_PCI,
.name = "pci",

View File

@ -17,6 +17,7 @@
* Under PCI, each device has 256 bytes of configuration address space,
* of which the first 64 bytes are standardized as follows:
*/
#define PCI_STD_HEADER_SIZEOF 64
#define PCI_VENDOR_ID 0x00 /* 16 bits */
#define PCI_DEVICE_ID 0x02 /* 16 bits */
#define PCI_COMMAND 0x04 /* 16 bits */
@ -1311,6 +1312,51 @@ pci_addr_t dm_pci_phys_to_bus(struct udevice *dev, phys_addr_t addr,
*/
void *dm_pci_map_bar(struct udevice *dev, int bar, int flags);
/**
* dm_pci_find_capability() - find a capability
*
* Tell if a device supports a given PCI capability. Returns the
* address of the requested capability structure within the device's
* PCI configuration space or 0 in case the device does not support it.
*
* Possible values for @cap:
*
* %PCI_CAP_ID_MSI Message Signalled Interrupts
* %PCI_CAP_ID_PCIX PCI-X
* %PCI_CAP_ID_EXP PCI Express
* %PCI_CAP_ID_MSIX MSI-X
*
* See PCI_CAP_ID_xxx for the complete capability ID codes.
*
* @dev: PCI device to query
* @cap: capability code
* @return: capability address or 0 if not supported
*/
int dm_pci_find_capability(struct udevice *dev, int cap);
/**
* dm_pci_find_ext_capability() - find an extended capability
*
* Tell if a device supports a given PCI express extended capability.
* Returns the address of the requested extended capability structure
* within the device's PCI configuration space or 0 in case the device
* does not support it.
*
* Possible values for @cap:
*
* %PCI_EXT_CAP_ID_ERR Advanced Error Reporting
* %PCI_EXT_CAP_ID_VC Virtual Channel
* %PCI_EXT_CAP_ID_DSN Device Serial Number
* %PCI_EXT_CAP_ID_PWR Power Budgeting
*
* See PCI_EXT_CAP_ID_xxx for the complete extended capability ID codes.
*
* @dev: PCI device to query
* @cap: extended capability code
* @return: extended capability address or 0 if not supported
*/
int dm_pci_find_ext_capability(struct udevice *dev, int cap);
#define dm_pci_virt_to_bus(dev, addr, flags) \
dm_pci_phys_to_bus(dev, (virt_to_phys(addr)), (flags))
#define dm_pci_bus_to_virt(dev, addr, flags, len, map_flags) \