Message ID | 20210925225446.1872-3-kabel@kernel.org |
---|---|
State | Awaiting Upstream |
Delegated to: | Stefan Roese |
Headers | show |
Series | A3720 PCIe enhancements | expand |
On Sunday 26 September 2021 00:54:42 Marek Behún wrote: > @@ -355,20 +369,55 @@ static int pcie_advk_read_config(const struct udevice *bus, pci_dev_t bdf, > enum pci_size_t size) > { > struct pcie_advk *pcie = dev_get_priv(bus); > + int busno = PCI_BUS(bdf) - dev_seq(bus); > int retry_count; > bool allow_crs; > + ulong data; > uint reg; > int ret; > > dev_dbg(pcie->dev, "PCIE CFG read: (b,d,f)=(%2d,%2d,%2d) ", > PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); > > - if (!pcie_advk_addr_valid(bdf, pcie->first_busno)) { > + if (!pcie_advk_addr_valid(pcie, busno, PCI_DEV(bdf), PCI_FUNC(bdf))) { > dev_dbg(pcie->dev, "- out of range\n"); > *valuep = pci_get_ff(size); > return 0; > } > > + /* > + * The configuration space of the PCI Bridge on primary (local) 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. > + */ > + if (busno == pcie->first_busno) { > + if (offset >= 0x10 && offset < 0x34) > + 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); > + > + if ((offset & ~3) == (PCI_HEADER_TYPE & ~3)) { > + /* > + * Change Header Type of PCI Bridge device to Type 1 > + * (0x01, used by PCI Bridges) because hardwired value > + * is Type 0 (0x00, used by Endpoint devices). > + */ > + data &= ~0x00ff0000; ^^ There is a small mistake. Header Type is 7-bit value. Upper 8th bit indicates if device is multifunction. So correct mask should be: data &= ~0x007f0000; > + data |= PCI_HEADER_TYPE_BRIDGE << 16; > + } > + > + *valuep = pci_conv_32_to_size(data, offset, size); > + > + return 0; > + } > + > /* > * Returning fabricated CRS value (0xFFFF0001) by PCIe Root Complex to > * OS is allowed only for 4-byte PCI_VENDOR_ID config read request and
On 05.10.21 23:55, Pali Rohár wrote: > On Sunday 26 September 2021 00:54:42 Marek Behún wrote: >> @@ -355,20 +369,55 @@ static int pcie_advk_read_config(const struct udevice *bus, pci_dev_t bdf, >> enum pci_size_t size) >> { >> struct pcie_advk *pcie = dev_get_priv(bus); >> + int busno = PCI_BUS(bdf) - dev_seq(bus); >> int retry_count; >> bool allow_crs; >> + ulong data; >> uint reg; >> int ret; >> >> dev_dbg(pcie->dev, "PCIE CFG read: (b,d,f)=(%2d,%2d,%2d) ", >> PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); >> >> - if (!pcie_advk_addr_valid(bdf, pcie->first_busno)) { >> + if (!pcie_advk_addr_valid(pcie, busno, PCI_DEV(bdf), PCI_FUNC(bdf))) { >> dev_dbg(pcie->dev, "- out of range\n"); >> *valuep = pci_get_ff(size); >> return 0; >> } >> >> + /* >> + * The configuration space of the PCI Bridge on primary (local) 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. >> + */ >> + if (busno == pcie->first_busno) { >> + if (offset >= 0x10 && offset < 0x34) >> + 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); >> + >> + if ((offset & ~3) == (PCI_HEADER_TYPE & ~3)) { >> + /* >> + * Change Header Type of PCI Bridge device to Type 1 >> + * (0x01, used by PCI Bridges) because hardwired value >> + * is Type 0 (0x00, used by Endpoint devices). >> + */ >> + data &= ~0x00ff0000; > ^^ > There is a small mistake. Header Type is 7-bit value. Upper 8th bit > indicates if device is multifunction. So correct mask should be: > > data &= ~0x007f0000; I'll try to get to these (and other) patches today and will fix this while applying. Thanks, Stefan >> + data |= PCI_HEADER_TYPE_BRIDGE << 16; >> + } >> + >> + *valuep = pci_conv_32_to_size(data, offset, size); >> + >> + return 0; >> + } >> + >> /* >> * Returning fabricated CRS value (0xFFFF0001) by PCIe Root Complex to >> * OS is allowed only for 4-byte PCI_VENDOR_ID config read request and Viele Grüße, Stefan
On 26.09.21 00:54, Marek Behún wrote: > From: Pali Rohár <pali@kernel.org> > > Aardvark does not have a real PCIe Root Port device on the root bus. > Instead it has PCIe registers of PCIe Root Port device mapped in > internal Aardvark memory space starting at offset 0xc0. > > The PCIe Root Port itself is normally available as a PCI Bridge device > on the root bus with bus number zero. Aardvark instead has the > configuration registers of this PCI Bridge at offset 0x00 of Aardvark's > memory space, but the class code of this device is Mass Storage > Controller (0x010400), instead of PCI Bridge (0x600400), which causes > U-Boot to fail to recognize it as a P2P Bridge > > Add a hook into the pcie_advk_read_config() / pcie_advk_write_config() > functions to redirect access for root bus from PIO transfer to this > internal Aardvark memory space. This will allow U-Boot to access > configuration space of this PCI Bridge which represents PCIe Root Port. > > Redirect access to PCI Bridge registers in range 0x10 - 0x34 to driver's > internal buffer (cfgcache[]). This is because at those addresses > Aardvark has different registers, incompatible with config space of a > PCI Bridge. > > Redirect access to PCI Bridge register PCI_ROM_ADDRESS1 (0x38) to > Aardvark internal address for that register (0x30). > > When reading PCI Bridge register PCI_HEADER_TYPE, set it explicitly to > value Type 1 (PCI_HEADER_TYPE_BRIDGE) as PCI Bridge must be of Type 1. > > When writing to PCI_PRIMARY_BUS or PCI_SECONDARY_BUS registers on this > PCI Bridge, correctly update driver's first_busno and sec_busno > variables, so that pcie_advk_addr_valid() function can check if address > of any device behind the root bus is valid and that PIO transfers are > started with correct config type (1 vs 0), which is required for > accessing devices behind some PCI bridge after the root bus. > > U-Boot's PCI_PNP code sets primary and secondary bus numbers as relative > to the configured bus number of the root bus. This is done so that > U-Boot can support multiple PCIe host bridges or multiple root port > buses, when internal bus numbers are different. > > Now that root bus is available, update code in pcie_advk_read_config() > and pcie_advk_write_config() functions to correctly calculate real > Aardvark bus number of the target device from U-Boot's bus number as: > busno = PCI_BUS(bdf) - dev_seq(bus) > > Signed-off-by: Pali Rohár <pali@kernel.org> > Reviewed-by: Marek Behún <marek.behun@nic.cz> Reviewed-by: Stefan Roese <sr@denx.de> Thanks, Stefan > --- > drivers/pci/pci-aardvark.c | 143 ++++++++++++++++++++++++++++++++----- > 1 file changed, 124 insertions(+), 19 deletions(-) > > diff --git a/drivers/pci/pci-aardvark.c b/drivers/pci/pci-aardvark.c > index 741e0431e1..692210ded9 100644 > --- a/drivers/pci/pci-aardvark.c > +++ b/drivers/pci/pci-aardvark.c > @@ -39,6 +39,8 @@ > #define PCIE_CORE_CMD_IO_ACCESS_EN BIT(0) > #define PCIE_CORE_CMD_MEM_ACCESS_EN BIT(1) > #define PCIE_CORE_CMD_MEM_IO_REQ_EN BIT(2) > +#define PCIE_CORE_DEV_REV_REG 0x8 > +#define PCIE_CORE_EXP_ROM_BAR_REG 0x30 > #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) > @@ -163,7 +165,7 @@ > #define PCIE_CONFIG_WR_TYPE1 0xb > > /* PCI_BDF shifts 8bit, so we need extra 4bit shift */ > -#define PCIE_BDF(dev) (dev << 4) > +#define PCIE_BDF(b, d, f) (PCI_BDF(b, d, f) << 4) > #define PCIE_CONF_BUS(bus) (((bus) & 0xff) << 20) > #define PCIE_CONF_DEV(dev) (((dev) & 0x1f) << 15) > #define PCIE_CONF_FUNC(fun) (((fun) & 0x7) << 12) > @@ -188,13 +190,17 @@ > * first_busno stores the bus number of the PCIe root-port > * number which may vary depending on the PCIe setup > * (PEX switches etc). > + * @sec_busno: sec_busno stores the bus number for the device behind > + * the PCIe root-port > * @device: The pointer to PCI uclass device. > */ > struct pcie_advk { > void *base; > int first_busno; > + int sec_busno; > struct udevice *dev; > struct gpio_desc reset_gpio; > + u32 cfgcache[0x34 - 0x10]; > }; > > static inline void advk_writel(struct pcie_advk *pcie, uint val, uint reg) > @@ -210,22 +216,30 @@ static inline uint advk_readl(struct pcie_advk *pcie, uint reg) > /** > * pcie_advk_addr_valid() - Check for valid bus address > * > + * @pcie: Pointer to the PCI bus > + * @busno: Bus number of PCI device > + * @dev: Device number of PCI device > + * @func: Function number of PCI device > * @bdf: The PCI device to access > - * @first_busno: Bus number of the PCIe controller root complex > * > - * Return: 1 on valid, 0 on invalid > + * Return: true on valid, false on invalid > */ > -static int pcie_advk_addr_valid(pci_dev_t bdf, int first_busno) > +static bool pcie_advk_addr_valid(struct pcie_advk *pcie, > + int busno, u8 dev, u8 func) > { > + /* On the primary (local) bus there is only one PCI Bridge */ > + if (busno == pcie->first_busno && (dev != 0 || func != 0)) > + return false; > + > /* > - * In PCIE-E only a single device (0) can exist > - * on the local bus. Beyound the local bus, there might be > - * a Switch and everything is possible. > + * In PCI-E only a single device (0) can exist on the secondary bus. > + * Beyond the secondary bus, there might be a Switch and anything is > + * possible. > */ > - if ((PCI_BUS(bdf) == first_busno) && (PCI_DEV(bdf) > 0)) > - return 0; > + if (busno == pcie->sec_busno && dev != 0) > + return false; > > - return 1; > + return true; > } > > /** > @@ -355,20 +369,55 @@ static int pcie_advk_read_config(const struct udevice *bus, pci_dev_t bdf, > enum pci_size_t size) > { > struct pcie_advk *pcie = dev_get_priv(bus); > + int busno = PCI_BUS(bdf) - dev_seq(bus); > int retry_count; > bool allow_crs; > + ulong data; > uint reg; > int ret; > > dev_dbg(pcie->dev, "PCIE CFG read: (b,d,f)=(%2d,%2d,%2d) ", > PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); > > - if (!pcie_advk_addr_valid(bdf, pcie->first_busno)) { > + if (!pcie_advk_addr_valid(pcie, busno, PCI_DEV(bdf), PCI_FUNC(bdf))) { > dev_dbg(pcie->dev, "- out of range\n"); > *valuep = pci_get_ff(size); > return 0; > } > > + /* > + * The configuration space of the PCI Bridge on primary (local) 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. > + */ > + if (busno == pcie->first_busno) { > + if (offset >= 0x10 && offset < 0x34) > + 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); > + > + if ((offset & ~3) == (PCI_HEADER_TYPE & ~3)) { > + /* > + * Change Header Type of PCI Bridge device to Type 1 > + * (0x01, used by PCI Bridges) because hardwired value > + * is Type 0 (0x00, used by Endpoint devices). > + */ > + data &= ~0x00ff0000; > + data |= PCI_HEADER_TYPE_BRIDGE << 16; > + } > + > + *valuep = pci_conv_32_to_size(data, offset, size); > + > + return 0; > + } > + > /* > * Returning fabricated CRS value (0xFFFF0001) by PCIe Root Complex to > * OS is allowed only for 4-byte PCI_VENDOR_ID config read request and > @@ -396,14 +445,14 @@ static int pcie_advk_read_config(const struct udevice *bus, pci_dev_t bdf, > /* Program the control register */ > reg = advk_readl(pcie, PIO_CTRL); > reg &= ~PIO_CTRL_TYPE_MASK; > - if (PCI_BUS(bdf) == pcie->first_busno) > + if (busno == pcie->sec_busno) > reg |= PCIE_CONFIG_RD_TYPE0; > else > reg |= PCIE_CONFIG_RD_TYPE1; > advk_writel(pcie, reg, PIO_CTRL); > > /* Program the address registers */ > - reg = PCIE_BDF(bdf) | PCIE_CONF_REG(offset); > + reg = PCIE_BDF(busno, PCI_DEV(bdf), PCI_FUNC(bdf)) | PCIE_CONF_REG(offset); > advk_writel(pcie, reg, PIO_ADDR_LS); > advk_writel(pcie, 0, PIO_ADDR_MS); > > @@ -491,7 +540,9 @@ static int pcie_advk_write_config(struct udevice *bus, pci_dev_t bdf, > enum pci_size_t size) > { > struct pcie_advk *pcie = dev_get_priv(bus); > + int busno = PCI_BUS(bdf) - dev_seq(bus); > int retry_count; > + ulong data; > uint reg; > int ret; > > @@ -500,11 +551,41 @@ static int pcie_advk_write_config(struct udevice *bus, pci_dev_t bdf, > dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08lx)\n", > offset, size, value); > > - if (!pcie_advk_addr_valid(bdf, pcie->first_busno)) { > + if (!pcie_advk_addr_valid(pcie, busno, PCI_DEV(bdf), PCI_FUNC(bdf))) { > dev_dbg(pcie->dev, "- out of range\n"); > return 0; > } > > + /* > + * As explained in pcie_advk_read_config(), for the configuration > + * space of the primary PCI Bridge, we write the content into virtual > + * cache. > + */ > + if (busno == pcie->first_busno) { > + if (offset >= 0x10 && offset < 0x34) { > + data = pcie->cfgcache[(offset - 0x10) / 4]; > + data = pci_conv_size_to_32(data, value, offset, size); > + 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); > + advk_writel(pcie, data, offset & ~3); > + } > + > + if (offset == PCI_PRIMARY_BUS) > + pcie->first_busno = data & 0xff; > + > + if (offset == PCI_SECONDARY_BUS || > + (offset == PCI_PRIMARY_BUS && size != PCI_SIZE_8)) > + pcie->sec_busno = (data >> 8) & 0xff; > + > + return 0; > + } > + > if (advk_readl(pcie, PIO_START)) { > dev_err(pcie->dev, > "Previous PIO read/write transfer is still running\n"); > @@ -514,14 +595,14 @@ static int pcie_advk_write_config(struct udevice *bus, pci_dev_t bdf, > /* Program the control register */ > reg = advk_readl(pcie, PIO_CTRL); > reg &= ~PIO_CTRL_TYPE_MASK; > - if (PCI_BUS(bdf) == pcie->first_busno) > + if (busno == pcie->sec_busno) > reg |= PCIE_CONFIG_WR_TYPE0; > else > reg |= PCIE_CONFIG_WR_TYPE1; > advk_writel(pcie, reg, PIO_CTRL); > > /* Program the address registers */ > - reg = PCIE_BDF(bdf) | PCIE_CONF_REG(offset); > + reg = PCIE_BDF(busno, PCI_DEV(bdf), PCI_FUNC(bdf)) | PCIE_CONF_REG(offset); > advk_writel(pcie, reg, PIO_ADDR_LS); > advk_writel(pcie, 0, PIO_ADDR_MS); > dev_dbg(pcie->dev, "\tPIO req. - addr = 0x%08x\n", reg); > @@ -590,14 +671,14 @@ static int pcie_advk_wait_for_link(struct pcie_advk *pcie) > /* check if the link is up or not */ > for (retries = 0; retries < LINK_MAX_RETRIES; retries++) { > if (pcie_advk_link_up(pcie)) { > - printf("PCIE-%d: Link up\n", pcie->first_busno); > + printf("PCIe: Link up\n"); > return 0; > } > > udelay(LINK_WAIT_TIMEOUT); > } > > - printf("PCIE-%d: Link down\n", pcie->first_busno); > + printf("PCIe: Link down\n"); > > return -ETIMEDOUT; > } > @@ -716,6 +797,25 @@ static int pcie_advk_setup_hw(struct pcie_advk *pcie) > */ > advk_writel(pcie, 0x11ab11ab, VENDOR_ID_REG); > > + /* > + * Change Class Code of PCI Bridge device to PCI Bridge (0x600400), > + * because default value is Mass Storage Controller (0x010400), causing > + * U-Boot to fail to recognize it as P2P Bridge. > + * > + * 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 > + * 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. > + */ > + reg = advk_readl(pcie, PCIE_CORE_DEV_REV_REG); > + reg &= ~0xffffff00; > + reg |= (PCI_CLASS_BRIDGE_PCI << 8) << 8; > + advk_writel(pcie, reg, PCIE_CORE_DEV_REV_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 | > @@ -857,9 +957,14 @@ static int pcie_advk_probe(struct udevice *dev) > dev_warn(dev, "PCIE Reset on GPIO support is missing\n"); > } > > - pcie->first_busno = dev_seq(dev); > pcie->dev = pci_get_controller(dev); > > + /* PCI Bridge support 32-bit I/O and 64-bit prefetch mem addressing */ > + pcie->cfgcache[(PCI_IO_BASE - 0x10) / 4] = > + PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8); > + pcie->cfgcache[(PCI_PREF_MEMORY_BASE - 0x10) / 4] = > + PCI_PREF_RANGE_TYPE_64 | (PCI_PREF_RANGE_TYPE_64 << 16); > + > return pcie_advk_setup_hw(pcie); > } > > Viele Grüße, Stefan
diff --git a/drivers/pci/pci-aardvark.c b/drivers/pci/pci-aardvark.c index 741e0431e1..692210ded9 100644 --- a/drivers/pci/pci-aardvark.c +++ b/drivers/pci/pci-aardvark.c @@ -39,6 +39,8 @@ #define PCIE_CORE_CMD_IO_ACCESS_EN BIT(0) #define PCIE_CORE_CMD_MEM_ACCESS_EN BIT(1) #define PCIE_CORE_CMD_MEM_IO_REQ_EN BIT(2) +#define PCIE_CORE_DEV_REV_REG 0x8 +#define PCIE_CORE_EXP_ROM_BAR_REG 0x30 #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) @@ -163,7 +165,7 @@ #define PCIE_CONFIG_WR_TYPE1 0xb /* PCI_BDF shifts 8bit, so we need extra 4bit shift */ -#define PCIE_BDF(dev) (dev << 4) +#define PCIE_BDF(b, d, f) (PCI_BDF(b, d, f) << 4) #define PCIE_CONF_BUS(bus) (((bus) & 0xff) << 20) #define PCIE_CONF_DEV(dev) (((dev) & 0x1f) << 15) #define PCIE_CONF_FUNC(fun) (((fun) & 0x7) << 12) @@ -188,13 +190,17 @@ * first_busno stores the bus number of the PCIe root-port * number which may vary depending on the PCIe setup * (PEX switches etc). + * @sec_busno: sec_busno stores the bus number for the device behind + * the PCIe root-port * @device: The pointer to PCI uclass device. */ struct pcie_advk { void *base; int first_busno; + int sec_busno; struct udevice *dev; struct gpio_desc reset_gpio; + u32 cfgcache[0x34 - 0x10]; }; static inline void advk_writel(struct pcie_advk *pcie, uint val, uint reg) @@ -210,22 +216,30 @@ static inline uint advk_readl(struct pcie_advk *pcie, uint reg) /** * pcie_advk_addr_valid() - Check for valid bus address * + * @pcie: Pointer to the PCI bus + * @busno: Bus number of PCI device + * @dev: Device number of PCI device + * @func: Function number of PCI device * @bdf: The PCI device to access - * @first_busno: Bus number of the PCIe controller root complex * - * Return: 1 on valid, 0 on invalid + * Return: true on valid, false on invalid */ -static int pcie_advk_addr_valid(pci_dev_t bdf, int first_busno) +static bool pcie_advk_addr_valid(struct pcie_advk *pcie, + int busno, u8 dev, u8 func) { + /* On the primary (local) bus there is only one PCI Bridge */ + if (busno == pcie->first_busno && (dev != 0 || func != 0)) + return false; + /* - * In PCIE-E only a single device (0) can exist - * on the local bus. Beyound the local bus, there might be - * a Switch and everything is possible. + * In PCI-E only a single device (0) can exist on the secondary bus. + * Beyond the secondary bus, there might be a Switch and anything is + * possible. */ - if ((PCI_BUS(bdf) == first_busno) && (PCI_DEV(bdf) > 0)) - return 0; + if (busno == pcie->sec_busno && dev != 0) + return false; - return 1; + return true; } /** @@ -355,20 +369,55 @@ static int pcie_advk_read_config(const struct udevice *bus, pci_dev_t bdf, enum pci_size_t size) { struct pcie_advk *pcie = dev_get_priv(bus); + int busno = PCI_BUS(bdf) - dev_seq(bus); int retry_count; bool allow_crs; + ulong data; uint reg; int ret; dev_dbg(pcie->dev, "PCIE CFG read: (b,d,f)=(%2d,%2d,%2d) ", PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); - if (!pcie_advk_addr_valid(bdf, pcie->first_busno)) { + if (!pcie_advk_addr_valid(pcie, busno, PCI_DEV(bdf), PCI_FUNC(bdf))) { dev_dbg(pcie->dev, "- out of range\n"); *valuep = pci_get_ff(size); return 0; } + /* + * The configuration space of the PCI Bridge on primary (local) 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. + */ + if (busno == pcie->first_busno) { + if (offset >= 0x10 && offset < 0x34) + 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); + + if ((offset & ~3) == (PCI_HEADER_TYPE & ~3)) { + /* + * Change Header Type of PCI Bridge device to Type 1 + * (0x01, used by PCI Bridges) because hardwired value + * is Type 0 (0x00, used by Endpoint devices). + */ + data &= ~0x00ff0000; + data |= PCI_HEADER_TYPE_BRIDGE << 16; + } + + *valuep = pci_conv_32_to_size(data, offset, size); + + return 0; + } + /* * Returning fabricated CRS value (0xFFFF0001) by PCIe Root Complex to * OS is allowed only for 4-byte PCI_VENDOR_ID config read request and @@ -396,14 +445,14 @@ static int pcie_advk_read_config(const struct udevice *bus, pci_dev_t bdf, /* Program the control register */ reg = advk_readl(pcie, PIO_CTRL); reg &= ~PIO_CTRL_TYPE_MASK; - if (PCI_BUS(bdf) == pcie->first_busno) + if (busno == pcie->sec_busno) reg |= PCIE_CONFIG_RD_TYPE0; else reg |= PCIE_CONFIG_RD_TYPE1; advk_writel(pcie, reg, PIO_CTRL); /* Program the address registers */ - reg = PCIE_BDF(bdf) | PCIE_CONF_REG(offset); + reg = PCIE_BDF(busno, PCI_DEV(bdf), PCI_FUNC(bdf)) | PCIE_CONF_REG(offset); advk_writel(pcie, reg, PIO_ADDR_LS); advk_writel(pcie, 0, PIO_ADDR_MS); @@ -491,7 +540,9 @@ static int pcie_advk_write_config(struct udevice *bus, pci_dev_t bdf, enum pci_size_t size) { struct pcie_advk *pcie = dev_get_priv(bus); + int busno = PCI_BUS(bdf) - dev_seq(bus); int retry_count; + ulong data; uint reg; int ret; @@ -500,11 +551,41 @@ static int pcie_advk_write_config(struct udevice *bus, pci_dev_t bdf, dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08lx)\n", offset, size, value); - if (!pcie_advk_addr_valid(bdf, pcie->first_busno)) { + if (!pcie_advk_addr_valid(pcie, busno, PCI_DEV(bdf), PCI_FUNC(bdf))) { dev_dbg(pcie->dev, "- out of range\n"); return 0; } + /* + * As explained in pcie_advk_read_config(), for the configuration + * space of the primary PCI Bridge, we write the content into virtual + * cache. + */ + if (busno == pcie->first_busno) { + if (offset >= 0x10 && offset < 0x34) { + data = pcie->cfgcache[(offset - 0x10) / 4]; + data = pci_conv_size_to_32(data, value, offset, size); + 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); + advk_writel(pcie, data, offset & ~3); + } + + if (offset == PCI_PRIMARY_BUS) + pcie->first_busno = data & 0xff; + + if (offset == PCI_SECONDARY_BUS || + (offset == PCI_PRIMARY_BUS && size != PCI_SIZE_8)) + pcie->sec_busno = (data >> 8) & 0xff; + + return 0; + } + if (advk_readl(pcie, PIO_START)) { dev_err(pcie->dev, "Previous PIO read/write transfer is still running\n"); @@ -514,14 +595,14 @@ static int pcie_advk_write_config(struct udevice *bus, pci_dev_t bdf, /* Program the control register */ reg = advk_readl(pcie, PIO_CTRL); reg &= ~PIO_CTRL_TYPE_MASK; - if (PCI_BUS(bdf) == pcie->first_busno) + if (busno == pcie->sec_busno) reg |= PCIE_CONFIG_WR_TYPE0; else reg |= PCIE_CONFIG_WR_TYPE1; advk_writel(pcie, reg, PIO_CTRL); /* Program the address registers */ - reg = PCIE_BDF(bdf) | PCIE_CONF_REG(offset); + reg = PCIE_BDF(busno, PCI_DEV(bdf), PCI_FUNC(bdf)) | PCIE_CONF_REG(offset); advk_writel(pcie, reg, PIO_ADDR_LS); advk_writel(pcie, 0, PIO_ADDR_MS); dev_dbg(pcie->dev, "\tPIO req. - addr = 0x%08x\n", reg); @@ -590,14 +671,14 @@ static int pcie_advk_wait_for_link(struct pcie_advk *pcie) /* check if the link is up or not */ for (retries = 0; retries < LINK_MAX_RETRIES; retries++) { if (pcie_advk_link_up(pcie)) { - printf("PCIE-%d: Link up\n", pcie->first_busno); + printf("PCIe: Link up\n"); return 0; } udelay(LINK_WAIT_TIMEOUT); } - printf("PCIE-%d: Link down\n", pcie->first_busno); + printf("PCIe: Link down\n"); return -ETIMEDOUT; } @@ -716,6 +797,25 @@ static int pcie_advk_setup_hw(struct pcie_advk *pcie) */ advk_writel(pcie, 0x11ab11ab, VENDOR_ID_REG); + /* + * Change Class Code of PCI Bridge device to PCI Bridge (0x600400), + * because default value is Mass Storage Controller (0x010400), causing + * U-Boot to fail to recognize it as P2P Bridge. + * + * 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 + * 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. + */ + reg = advk_readl(pcie, PCIE_CORE_DEV_REV_REG); + reg &= ~0xffffff00; + reg |= (PCI_CLASS_BRIDGE_PCI << 8) << 8; + advk_writel(pcie, reg, PCIE_CORE_DEV_REV_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 | @@ -857,9 +957,14 @@ static int pcie_advk_probe(struct udevice *dev) dev_warn(dev, "PCIE Reset on GPIO support is missing\n"); } - pcie->first_busno = dev_seq(dev); pcie->dev = pci_get_controller(dev); + /* PCI Bridge support 32-bit I/O and 64-bit prefetch mem addressing */ + pcie->cfgcache[(PCI_IO_BASE - 0x10) / 4] = + PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8); + pcie->cfgcache[(PCI_PREF_MEMORY_BASE - 0x10) / 4] = + PCI_PREF_RANGE_TYPE_64 | (PCI_PREF_RANGE_TYPE_64 << 16); + return pcie_advk_setup_hw(pcie); }