aboutsummaryrefslogtreecommitdiff
path: root/drivers/pci
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/fsl_pci_init.c5
-rw-r--r--drivers/pci/pci-aardvark.c18
-rw-r--r--drivers/pci/pci_mpc85xx.c25
-rw-r--r--drivers/pci/pci_mvebu.c76
4 files changed, 77 insertions, 47 deletions
diff --git a/drivers/pci/fsl_pci_init.c b/drivers/pci/fsl_pci_init.c
index e72a60c131..fc3327ec53 100644
--- a/drivers/pci/fsl_pci_init.c
+++ b/drivers/pci/fsl_pci_init.c
@@ -32,6 +32,8 @@ DECLARE_GLOBAL_DATA_PTR;
#include <asm/io.h>
#include <asm/fsl_pci.h>
+#define MAX_PCI_REGIONS 7
+
#ifndef CONFIG_SYS_PCI_MEMORY_BUS
#define CONFIG_SYS_PCI_MEMORY_BUS 0
#endif
@@ -80,6 +82,9 @@ int fsl_setup_hose(struct pci_controller *hose, unsigned long addr)
/* Reset hose to make sure its in a clean state */
memset(hose, 0, sizeof(struct pci_controller));
+ hose->regions = (struct pci_region *)
+ calloc(1, MAX_PCI_REGIONS * sizeof(struct pci_region));
+
pci_setup_indirect(hose, (u32)&pci->cfg_addr, (u32)&pci->cfg_data);
return fsl_is_pci_agent(hose);
diff --git a/drivers/pci/pci-aardvark.c b/drivers/pci/pci-aardvark.c
index 8713b88461..3b9309f52c 100644
--- a/drivers/pci/pci-aardvark.c
+++ b/drivers/pci/pci-aardvark.c
@@ -42,6 +42,10 @@
#define PCIE_CORE_DEV_CTRL_STATS_REG 0xc8
#define PCIE_CORE_DEV_CTRL_STATS_RELAX_ORDER_DISABLE (0 << 4)
#define PCIE_CORE_DEV_CTRL_STATS_SNOOP_DISABLE (0 << 11)
+#define PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SIZE 0x2
+#define PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SIZE_SHIFT 5
+#define PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE 0x2
+#define PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE_SHIFT 12
#define PCIE_CORE_LINK_CTRL_STAT_REG 0xd0
#define PCIE_CORE_LINK_TRAINING BIT(5)
#define PCIE_CORE_ERR_CAPCTL_REG 0x118
@@ -101,6 +105,7 @@
#define LTSSM_SHIFT 24
#define LTSSM_MASK 0x3f
#define LTSSM_L0 0x10
+#define VENDOR_ID_REG (LMI_BASE_ADDR + 0x44)
/* PCIe core controller registers */
#define CTRL_CORE_BASE_ADDR 0x18000
@@ -525,6 +530,15 @@ static int pcie_advk_setup_hw(struct pcie_advk *pcie)
reg |= (IS_RC_MSK << IS_RC_SHIFT);
advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
+ /*
+ * Replace incorrect PCI vendor id value 0x1b4b by correct value 0x11ab.
+ * VENDOR_ID_REG contains vendor id in low 16 bits and subsystem vendor
+ * id in high 16 bits. Updating this register changes readback value of
+ * read-only vendor id bits in PCIE_CORE_DEV_ID_REG register. Workaround
+ * for erratum 4.1: "The value of device and vendor ID is incorrect".
+ */
+ advk_writel(pcie, 0x11ab11ab, VENDOR_ID_REG);
+
/* Set Advanced Error Capabilities and Control PF0 register */
reg = PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX |
PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX_EN |
@@ -534,6 +548,10 @@ static int pcie_advk_setup_hw(struct pcie_advk *pcie)
/* Set PCIe Device Control and Status 1 PF0 register */
reg = PCIE_CORE_DEV_CTRL_STATS_RELAX_ORDER_DISABLE |
+ (PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SIZE <<
+ PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SIZE_SHIFT) |
+ (PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE <<
+ PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE_SHIFT) |
PCIE_CORE_DEV_CTRL_STATS_SNOOP_DISABLE;
advk_writel(pcie, reg, PCIE_CORE_DEV_CTRL_STATS_REG);
diff --git a/drivers/pci/pci_mpc85xx.c b/drivers/pci/pci_mpc85xx.c
index ab6ff45a51..574cb784a8 100644
--- a/drivers/pci/pci_mpc85xx.c
+++ b/drivers/pci/pci_mpc85xx.c
@@ -46,6 +46,7 @@ static int mpc85xx_pci_dm_write_config(struct udevice *dev, pci_dev_t bdf,
return 0;
}
+#ifdef CONFIG_FSL_LAW
static int
mpc85xx_pci_dm_setup_laws(struct pci_region *io, struct pci_region *mem,
struct pci_region *pre)
@@ -68,6 +69,7 @@ mpc85xx_pci_dm_setup_laws(struct pci_region *io, struct pci_region *mem,
return 0;
}
+#endif
static int mpc85xx_pci_dm_probe(struct udevice *dev)
{
@@ -85,22 +87,24 @@ static int mpc85xx_pci_dm_probe(struct udevice *dev)
return -EINVAL;
}
+#ifdef CONFIG_FSL_LAW
mpc85xx_pci_dm_setup_laws(io, mem, pre);
+#endif
pcix = priv->cfg_addr;
/* BAR 1: memory */
- out_be32(&pcix->potar1, (mem->bus_start >> 12) & 0x000fffff);
- out_be32(&pcix->potear1, 0);
- out_be32(&pcix->powbar1, (mem->phys_start >> 12) & 0x000fffff);
- out_be32(&pcix->powbear1, 0);
+ out_be32(&pcix->potar1, mem->bus_start >> 12);
+ out_be32(&pcix->potear1, (u64)mem->bus_start >> 44);
+ out_be32(&pcix->powbar1, mem->phys_start >> 12);
+ out_be32(&pcix->powbear1, (u64)mem->phys_start >> 44);
out_be32(&pcix->powar1, (POWAR_EN | POWAR_MEM_READ |
POWAR_MEM_WRITE | (__ilog2(mem->size) - 1)));
/* BAR 1: IO */
- out_be32(&pcix->potar2, (io->bus_start >> 12) & 0x000fffff);
- out_be32(&pcix->potear2, 0);
- out_be32(&pcix->powbar2, (io->phys_start >> 12) & 0x000fffff);
- out_be32(&pcix->powbear2, 0);
+ out_be32(&pcix->potar2, io->bus_start >> 12);
+ out_be32(&pcix->potear2, (u64)io->bus_start >> 44);
+ out_be32(&pcix->powbar2, io->phys_start >> 12);
+ out_be32(&pcix->powbear2, (u64)io->phys_start >> 44);
out_be32(&pcix->powar2, (POWAR_EN | POWAR_IO_READ |
POWAR_IO_WRITE | (__ilog2(io->size) - 1)));
@@ -130,9 +134,8 @@ static int mpc85xx_pci_of_to_plat(struct udevice *dev)
addr = devfdt_get_addr_index(dev, 0);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
- priv->cfg_addr = (void __iomem *)addr;
- addr += 4;
- priv->cfg_data = (void __iomem *)addr;
+ priv->cfg_addr = (void __iomem *)map_physmem(addr, 0, MAP_NOCACHE);
+ priv->cfg_data = (void __iomem *)((ulong)priv->cfg_addr + 4);
return 0;
}
diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c
index 235d9bb90c..0c1d7cd770 100644
--- a/drivers/pci/pci_mvebu.c
+++ b/drivers/pci/pci_mvebu.c
@@ -79,7 +79,8 @@ struct mvebu_pcie {
u32 lane;
int devfn;
u32 lane_mask;
- pci_dev_t dev;
+ int first_busno;
+ int local_dev;
char name[16];
unsigned int mem_target;
unsigned int mem_attr;
@@ -144,38 +145,47 @@ static inline struct mvebu_pcie *hose_to_pcie(struct pci_controller *hose)
return container_of(hose, struct mvebu_pcie, hose);
}
+static int mvebu_pcie_valid_addr(struct mvebu_pcie *pcie, pci_dev_t bdf)
+{
+ /*
+ * There are two devices visible on local bus:
+ * * on slot configured by function mvebu_pcie_set_local_dev_nr()
+ * (by default this register is set to 0) there is a
+ * "Marvell Memory controller", which isn't useful in root complex
+ * mode,
+ * * on all other slots the real PCIe card connected to the PCIe slot.
+ *
+ * We therefore allow access only to the real PCIe card.
+ */
+ if (PCI_BUS(bdf) == pcie->first_busno &&
+ PCI_DEV(bdf) != !pcie->local_dev)
+ return 0;
+
+ return 1;
+}
+
static int mvebu_pcie_read_config(const struct udevice *bus, pci_dev_t bdf,
uint offset, ulong *valuep,
enum pci_size_t size)
{
struct mvebu_pcie *pcie = dev_get_plat(bus);
- int local_bus = PCI_BUS(pcie->dev);
- int local_dev = PCI_DEV(pcie->dev);
- u32 reg;
u32 data;
- debug("PCIE CFG read: loc_bus=%d loc_dev=%d (b,d,f)=(%2d,%2d,%2d) ",
- local_bus, local_dev, PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+ debug("PCIE CFG read: (b,d,f)=(%2d,%2d,%2d) ",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
- /* Don't access the local host controller via this API */
- if (PCI_BUS(bdf) == local_bus && PCI_DEV(bdf) == local_dev) {
- debug("- skipping host controller\n");
- *valuep = pci_get_ff(size);
- return 0;
- }
-
- /* If local dev is 0, the first other dev can only be 1 */
- if (PCI_BUS(bdf) == local_bus && local_dev == 0 && PCI_DEV(bdf) != 1) {
+ if (!mvebu_pcie_valid_addr(pcie, bdf)) {
debug("- out of range\n");
*valuep = pci_get_ff(size);
return 0;
}
/* write address */
- reg = PCIE_CONF_ADDR(bdf, offset);
- writel(reg, pcie->base + PCIE_CONF_ADDR_OFF);
+ writel(PCIE_CONF_ADDR(bdf, offset), pcie->base + PCIE_CONF_ADDR_OFF);
+
+ /* read data */
data = readl(pcie->base + PCIE_CONF_DATA_OFF);
- debug("(addr,val)=(0x%04x, 0x%08x)\n", offset, data);
+ debug("(addr,size,val)=(0x%04x, %d, 0x%08x)\n", offset, size, data);
*valuep = pci_conv_32_to_size(data, offset, size);
return 0;
@@ -186,27 +196,21 @@ static int mvebu_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
enum pci_size_t size)
{
struct mvebu_pcie *pcie = dev_get_plat(bus);
- int local_bus = PCI_BUS(pcie->dev);
- int local_dev = PCI_DEV(pcie->dev);
u32 data;
- debug("PCIE CFG write: loc_bus=%d loc_dev=%d (b,d,f)=(%2d,%2d,%2d) ",
- local_bus, local_dev, PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
- debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
-
- /* Don't access the local host controller via this API */
- if (PCI_BUS(bdf) == local_bus && PCI_DEV(bdf) == local_dev) {
- debug("- skipping host controller\n");
- return 0;
- }
+ debug("PCIE CFG write: (b,d,f)=(%2d,%2d,%2d) ",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+ debug("(addr,size,val)=(0x%04x, %d, 0x%08lx)\n", offset, size, value);
- /* If local dev is 0, the first other dev can only be 1 */
- if (PCI_BUS(bdf) == local_bus && local_dev == 0 && PCI_DEV(bdf) != 1) {
+ if (!mvebu_pcie_valid_addr(pcie, bdf)) {
debug("- out of range\n");
return 0;
}
+ /* write address */
writel(PCIE_CONF_ADDR(bdf, offset), pcie->base + PCIE_CONF_ADDR_OFF);
+
+ /* write data */
data = pci_conv_size_to_32(0, value, offset, size);
writel(data, pcie->base + PCIE_CONF_DATA_OFF);
@@ -273,7 +277,7 @@ static int mvebu_pcie_probe(struct udevice *dev)
struct mvebu_pcie *pcie = dev_get_plat(dev);
struct udevice *ctlr = pci_get_controller(dev);
struct pci_controller *hose = dev_get_uclass_priv(ctlr);
- static int bus;
+ int bus = dev_seq(dev);
u32 reg;
debug("%s: PCIe %d.%d - up, base %08x\n", __func__,
@@ -284,9 +288,11 @@ static int mvebu_pcie_probe(struct udevice *dev)
readl(pcie->base), mvebu_pcie_get_local_bus_nr(pcie),
mvebu_pcie_get_local_dev_nr(pcie));
+ pcie->first_busno = bus;
+ pcie->local_dev = 1;
+
mvebu_pcie_set_local_bus_nr(pcie, bus);
- mvebu_pcie_set_local_dev_nr(pcie, 0);
- pcie->dev = PCI_BDF(bus, 0, 0);
+ mvebu_pcie_set_local_dev_nr(pcie, pcie->local_dev);
pcie->mem.start = (u32)mvebu_pcie_membase;
pcie->mem.end = pcie->mem.start + PCIE_MEM_SIZE - 1;
@@ -336,8 +342,6 @@ static int mvebu_pcie_probe(struct udevice *dev)
writel(SOC_REGS_PHY_BASE, pcie->base + PCIE_BAR_LO_OFF(0));
writel(0, pcie->base + PCIE_BAR_HI_OFF(0));
- bus++;
-
return 0;
}