mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-03-15 19:51:37 +00:00
- Marvell/PCI: Fix size of the configuration cache and disallow ROM BAR setting in pci_mvebu.c & pci-aardvark.c (Pali & Marek)
This commit is contained in:
commit
5a59f634e9
2 changed files with 61 additions and 48 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue