summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2021-12-15 15:14:20 +0300
committerTom Rini <trini@konsulko.com>2021-12-15 15:14:20 +0300
commit5a59f634e9943a8a7743ca9808f8e29308b876a8 (patch)
tree1f7a8423a4cf9d8b67c333aecdbbee5d81709318
parentcfbd2bc695b87434e52e1b1073756b823f18f09d (diff)
parentfed5beca18f3562c4404de5f76fefdd3e06a46f5 (diff)
downloadu-boot-5a59f634e9943a8a7743ca9808f8e29308b876a8.tar.xz
Merge https://source.denx.de/u-boot/custodians/u-boot-marvell
- Marvell/PCI: Fix size of the configuration cache and disallow ROM BAR setting in pci_mvebu.c & pci-aardvark.c (Pali & Marek)
-rw-r--r--drivers/pci/pci-aardvark.c54
-rw-r--r--drivers/pci/pci_mvebu.c55
2 files changed, 61 insertions, 48 deletions
diff --git a/drivers/pci/pci-aardvark.c b/drivers/pci/pci-aardvark.c
index 4e94b776c5..a92f00d0af 100644
--- a/drivers/pci/pci-aardvark.c
+++ b/drivers/pci/pci-aardvark.c
@@ -202,7 +202,7 @@ struct pcie_advk {
int sec_busno;
struct udevice *dev;
struct gpio_desc reset_gpio;
- u32 cfgcache[0x34 - 0x10];
+ u32 cfgcache[(0x3c - 0x10) / 4];
bool cfgcrssve;
};
@@ -389,20 +389,19 @@ static int pcie_advk_read_config(const struct udevice *bus, pci_dev_t bdf,
}
/*
- * The configuration space of the PCI Bridge on primary (local) bus is
+ * The configuration space of the PCI Bridge on primary (first) bus is
* not accessible via PIO transfers like all other PCIe devices. PCI
* Bridge config registers are available directly in Aardvark memory
- * space starting at offset zero. Moreover PCI Bridge registers in the
- * range 0x10 - 0x34 are not available and register 0x38 (Expansion ROM
- * Base Address) is at offset 0x30.
- * We therefore read configuration space content of the primary PCI
- * Bridge from our virtual cache.
+ * space starting at offset zero. The PCI Bridge config space is of
+ * Type 0, but the BAR registers (including ROM BAR) don't have the same
+ * meaning as in the PCIe specification. Therefore do not access BAR
+ * registers and non-common registers (those which have different
+ * meaning for Type 0 and Type 1 config space) of the primary PCI Bridge
+ * and instead read their content from driver virtual cfgcache[].
*/
if (busno == pcie->first_busno) {
- if (offset >= 0x10 && offset < 0x34)
+ if ((offset >= 0x10 && offset < 0x34) || (offset >= 0x38 && offset < 0x3c))
data = pcie->cfgcache[(offset - 0x10) / 4];
- else if ((offset & ~3) == PCI_ROM_ADDRESS1)
- data = advk_readl(pcie, PCIE_CORE_EXP_ROM_BAR_REG);
else
data = advk_readl(pcie, offset & ~3);
@@ -576,23 +575,22 @@ static int pcie_advk_write_config(struct udevice *bus, pci_dev_t bdf,
}
/*
- * As explained in pcie_advk_read_config(), for the configuration
- * space of the primary PCI Bridge, we write the content into virtual
- * cache.
+ * As explained in pcie_advk_read_config(), PCI Bridge config registers
+ * are available directly in Aardvark memory space starting at offset
+ * zero. Type 1 specific registers are not available, so we write their
+ * content only into driver virtual cfgcache[].
*/
if (busno == pcie->first_busno) {
- if (offset >= 0x10 && offset < 0x34) {
+ if ((offset >= 0x10 && offset < 0x34) ||
+ (offset >= 0x38 && offset < 0x3c)) {
data = pcie->cfgcache[(offset - 0x10) / 4];
data = pci_conv_size_to_32(data, value, offset, size);
/* This PCI bridge does not have configurable bars */
if ((offset & ~3) == PCI_BASE_ADDRESS_0 ||
- (offset & ~3) == PCI_BASE_ADDRESS_1)
+ (offset & ~3) == PCI_BASE_ADDRESS_1 ||
+ (offset & ~3) == PCI_ROM_ADDRESS1)
data = 0x0;
pcie->cfgcache[(offset - 0x10) / 4] = data;
- } else if ((offset & ~3) == PCI_ROM_ADDRESS1) {
- data = advk_readl(pcie, PCIE_CORE_EXP_ROM_BAR_REG);
- data = pci_conv_size_to_32(data, value, offset, size);
- advk_writel(pcie, data, PCIE_CORE_EXP_ROM_BAR_REG);
} else {
data = advk_readl(pcie, offset & ~3);
data = pci_conv_size_to_32(data, value, offset, size);
@@ -830,12 +828,20 @@ static int pcie_advk_setup_hw(struct pcie_advk *pcie)
*
* Note that this Aardvark PCI Bridge does not have a compliant Type 1
* Configuration Space and it even cannot be accessed via Aardvark's
- * PCI config space access method. Something like config space is
+ * PCI config space access method. Aardvark PCI Bridge Config space is
* available in internal Aardvark registers starting at offset 0x0
- * and is reported as Type 0. In range 0x10 - 0x34 it has totally
- * different registers. So our driver reports Header Type as Type 1 and
- * for the above mentioned range redirects access to the virtual
- * cfgcache[] buffer, which avoids changing internal Aardvark registers.
+ * and has format of Type 0 config space.
+ *
+ * Moreover Type 0 BAR registers (ranges 0x10 - 0x28 and 0x30 - 0x34)
+ * have the same format in Marvell's specification as in PCIe
+ * specification, but their meaning is totally different (and not even
+ * the same meaning as explained in the corresponding comment in the
+ * pci_mvebu driver; aardvark is still different).
+ *
+ * So our driver converts Type 0 config space to Type 1 and reports
+ * Header Type as Type 1. Access to BAR registers and to non-existent
+ * Type 1 registers is redirected to the virtual cfgcache[] buffer,
+ * which avoids changing unrelated registers.
*/
reg = advk_readl(pcie, PCIE_CORE_DEV_REV_REG);
reg &= ~0xffffff00;
diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c
index 14cd82db6f..62a4df37a0 100644
--- a/drivers/pci/pci_mvebu.c
+++ b/drivers/pci/pci_mvebu.c
@@ -88,7 +88,7 @@ struct mvebu_pcie {
unsigned int mem_attr;
unsigned int io_target;
unsigned int io_attr;
- u32 cfgcache[0x34 - 0x10];
+ u32 cfgcache[(0x3c - 0x10) / 4];
};
/*
@@ -167,20 +167,20 @@ static int mvebu_pcie_read_config(const struct udevice *bus, pci_dev_t bdf,
}
/*
- * mvebu has different internal registers mapped into PCI config space
- * in range 0x10-0x34 for PCI bridge, so do not access PCI config space
- * for this range and instead read content from driver virtual cfgcache
+ * The configuration space of the PCI Bridge on primary (first) bus is
+ * of Type 0 but the BAR registers (including ROM BAR) don't have the
+ * same meaning as in the PCIe specification. Therefore do not access
+ * BAR registers and non-common registers (those which have different
+ * meaning for Type 0 and Type 1 config space) of the PCI Bridge and
+ * instead read their content from driver virtual cfgcache[].
*/
- if (busno == pcie->first_busno && offset >= 0x10 && offset < 0x34) {
+ if (busno == pcie->first_busno && ((offset >= 0x10 && offset < 0x34) ||
+ (offset >= 0x38 && offset < 0x3c))) {
data = pcie->cfgcache[(offset - 0x10) / 4];
debug("(addr,size,val)=(0x%04x, %d, 0x%08x) from cfgcache\n",
offset, size, data);
*valuep = pci_conv_32_to_size(data, offset, size);
return 0;
- } else if (busno == pcie->first_busno &&
- (offset & ~3) == PCI_ROM_ADDRESS1) {
- /* mvebu has Expansion ROM Base Address (0x38) at offset 0x30 */
- offset -= PCI_ROM_ADDRESS1 - PCIE_EXP_ROM_BAR_OFF;
}
/*
@@ -247,17 +247,21 @@ static int mvebu_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
}
/*
- * mvebu has different internal registers mapped into PCI config space
- * in range 0x10-0x34 for PCI bridge, so do not access PCI config space
- * for this range and instead write content to driver virtual cfgcache
+ * As explained in mvebu_pcie_read_config(), PCI Bridge Type 1 specific
+ * config registers are not available, so we write their content only
+ * into driver virtual cfgcache[].
+ * And as explained in mvebu_pcie_probe(), mvebu has its own specific
+ * way for configuring primary and secondary bus numbers.
*/
- if (busno == pcie->first_busno && offset >= 0x10 && offset < 0x34) {
+ if (busno == pcie->first_busno && ((offset >= 0x10 && offset < 0x34) ||
+ (offset >= 0x38 && offset < 0x3c))) {
debug("Writing to cfgcache only\n");
data = pcie->cfgcache[(offset - 0x10) / 4];
data = pci_conv_size_to_32(data, value, offset, size);
/* mvebu PCI bridge does not have configurable bars */
if ((offset & ~3) == PCI_BASE_ADDRESS_0 ||
- (offset & ~3) == PCI_BASE_ADDRESS_1)
+ (offset & ~3) == PCI_BASE_ADDRESS_1 ||
+ (offset & ~3) == PCI_ROM_ADDRESS1)
data = 0x0;
pcie->cfgcache[(offset - 0x10) / 4] = data;
/* mvebu has its own way how to set PCI primary bus number */
@@ -275,10 +279,6 @@ static int mvebu_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
pcie->sec_busno);
}
return 0;
- } else if (busno == pcie->first_busno &&
- (offset & ~3) == PCI_ROM_ADDRESS1) {
- /* mvebu has Expansion ROM Base Address (0x38) at offset 0x30 */
- offset -= PCI_ROM_ADDRESS1 - PCIE_EXP_ROM_BAR_OFF;
}
/*
@@ -384,13 +384,20 @@ static int mvebu_pcie_probe(struct udevice *dev)
* U-Boot cannot recognize as P2P Bridge.
*
* Note that this mvebu PCI Bridge does not have compliant Type 1
- * Configuration Space. Header Type is reported as Type 0 and in
- * range 0x10-0x34 it has aliased internal mvebu registers 0x10-0x34
- * (e.g. PCIE_BAR_LO_OFF) and register 0x38 is reserved.
+ * Configuration Space. Header Type is reported as Type 0 and it
+ * has format of Type 0 config space.
*
- * Driver for this range redirects access to virtual cfgcache[] buffer
- * which avoids changing internal mvebu registers. And changes Header
- * Type response value to Type 1.
+ * Moreover Type 0 BAR registers (ranges 0x10 - 0x28 and 0x30 - 0x34)
+ * have the same format in Marvell's specification as in PCIe
+ * specification, but their meaning is totally different and they do
+ * different things: they are aliased into internal mvebu registers
+ * (e.g. PCIE_BAR_LO_OFF) and these should not be changed or
+ * reconfigured by pci device drivers.
+ *
+ * So our driver converts Type 0 config space to Type 1 and reports
+ * Header Type as Type 1. Access to BAR registers and to non-existent
+ * Type 1 registers is redirected to the virtual cfgcache[] buffer,
+ * which avoids changing unrelated registers.
*/
reg = readl(pcie->base + PCIE_DEV_REV_OFF);
reg &= ~0xffffff00;