From 0b143d8ab2b84219552d652e46619360a38888d1 Mon Sep 17 00:00:00 2001 From: Alex Marginean Date: Fri, 7 Jun 2019 11:24:23 +0300 Subject: drivers: pci: add map_bar support for Enhanced Allocation Makes dm_pci_map_bar API available for integrated PCI devices that support Enhanced Allocation instead of the original PCI BAR mechanism. Signed-off-by: Alex Marginean Reviewed-by: Bin Meng --- drivers/pci/pci-uclass.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index cf1e7617ae..389aec15ce 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -1341,10 +1341,56 @@ pci_addr_t dm_pci_phys_to_bus(struct udevice *dev, phys_addr_t phys_addr, return bus_addr; } +static void *dm_pci_map_ea_bar(struct udevice *dev, int bar, int flags, + int ea_off) +{ + int ea_cnt, i, entry_size; + int bar_id = (bar - PCI_BASE_ADDRESS_0) >> 2; + u32 ea_entry; + phys_addr_t addr; + + /* EA capability structure header */ + dm_pci_read_config32(dev, ea_off, &ea_entry); + ea_cnt = (ea_entry >> 16) & PCI_EA_NUM_ENT_MASK; + ea_off += PCI_EA_FIRST_ENT; + + for (i = 0; i < ea_cnt; i++, ea_off += entry_size) { + /* Entry header */ + dm_pci_read_config32(dev, ea_off, &ea_entry); + entry_size = ((ea_entry & PCI_EA_ES) + 1) << 2; + + if (((ea_entry & PCI_EA_BEI) >> 4) != bar_id) + continue; + + /* Base address, 1st DW */ + dm_pci_read_config32(dev, ea_off + 4, &ea_entry); + addr = ea_entry & PCI_EA_FIELD_MASK; + if (ea_entry & PCI_EA_IS_64) { + /* Base address, 2nd DW, skip over 4B MaxOffset */ + dm_pci_read_config32(dev, ea_off + 12, &ea_entry); + addr |= ((u64)ea_entry) << 32; + } + + /* size ignored for now */ + return map_physmem(addr, flags, 0); + } + + return 0; +} + void *dm_pci_map_bar(struct udevice *dev, int bar, int flags) { pci_addr_t pci_bus_addr; u32 bar_response; + int ea_off; + + /* + * if the function supports Enhanced Allocation use that instead of + * BARs + */ + ea_off = dm_pci_find_capability(dev, PCI_CAP_ID_EA); + if (ea_off) + return dm_pci_map_ea_bar(dev, bar, flags, ea_off); /* read BAR address */ dm_pci_read_config32(dev, bar, &bar_response); -- cgit From b8e1f8270ca9667e84eaa4049e006c27e37f3cca Mon Sep 17 00:00:00 2001 From: Alex Marginean Date: Fri, 7 Jun 2019 11:24:25 +0300 Subject: drivers: pci: add API to issue FLR on a PCI function if supported Adds dm_pci_flr API that issues a Function Level reset on a PCI-e function, if FLR is supported. Signed-off-by: Alex Marginean Reviewed-by: Bin Meng --- drivers/pci/pci-uclass.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 389aec15ce..c74ebf6a76 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -1494,6 +1494,30 @@ int dm_pci_find_ext_capability(struct udevice *dev, int cap) return dm_pci_find_next_ext_capability(dev, 0, cap); } +int dm_pci_flr(struct udevice *dev) +{ + int pcie_off; + u32 cap; + + /* look for PCI Express Capability */ + pcie_off = dm_pci_find_capability(dev, PCI_CAP_ID_EXP); + if (!pcie_off) + return -ENOENT; + + /* check FLR capability */ + dm_pci_read_config32(dev, pcie_off + PCI_EXP_DEVCAP, &cap); + if (!(cap & PCI_EXP_DEVCAP_FLR)) + return -ENOENT; + + dm_pci_clrset_config16(dev, pcie_off + PCI_EXP_DEVCTL, 0, + PCI_EXP_DEVCTL_BCR_FLR); + + /* wait 100ms, per PCI spec */ + mdelay(100); + + return 0; +} + UCLASS_DRIVER(pci) = { .id = UCLASS_PCI, .name = "pci", -- cgit