Message ID | 1518629123-7889-1-git-send-email-igall@marvell.com |
---|---|
State | Accepted |
Commit | b8478fcd042686f7fe35edd30cc14f876762543c |
Delegated to: | Stefan Roese |
Headers | show |
Series | [U-Boot] dm: pcie: designware: add correct ATU handling | expand |
On 14.02.2018 18:25, igall@marvell.com wrote: > From: Igal Liberman <igall@marvell.com> > > Currently, ATU (address translation unit) implementation doesn't > support translate addresses > 32 bits. > > This patch allows to configure ATU correctly for different > memory accesses (memory, configuration and IO). > The same approach is used in Linux Kernel. > > Signed-off-by: Igal Liberman <igall@marvell.com> > --- > drivers/pci/pcie_dw_mvebu.c | 91 +++++++++++++++++++++++++++++---------------- > 1 file changed, 58 insertions(+), 33 deletions(-) > > diff --git a/drivers/pci/pcie_dw_mvebu.c b/drivers/pci/pcie_dw_mvebu.c > index a198855..a0032b7 100644 > --- a/drivers/pci/pcie_dw_mvebu.c > +++ b/drivers/pci/pcie_dw_mvebu.c > @@ -111,6 +111,10 @@ struct pcie_dw_mvebu { > void *cfg_base; > fdt_size_t cfg_size; > int first_busno; > + > + /* IO and MEM PCI regions */ > + struct pci_region io; > + struct pci_region mem; > }; > > static int pcie_dw_get_link_speed(const void *regs_base) > @@ -126,6 +130,34 @@ static int pcie_dw_get_link_width(const void *regs_base) > } > > /** > + * pcie_dw_prog_outbound_atu() - Configure ATU for outbound accesses > + * > + * @pcie: Pointer to the PCI controller state > + * @index: ATU region index > + * @type: ATU accsess type > + * @cpu_addr: the physical address for the translation entry > + * @pci_addr: the pcie bus address for the translation entry > + * @size: the size of the translation entry > + */ > +static void pcie_dw_prog_outbound_atu(struct pcie_dw_mvebu *pcie, int index, > + int type, u64 cpu_addr, u64 pci_addr, > + u32 size) > +{ > + writel(PCIE_ATU_REGION_OUTBOUND | index, > + pcie->ctrl_base + PCIE_ATU_VIEWPORT); > + writel(lower_32_bits(cpu_addr), pcie->ctrl_base + PCIE_ATU_LOWER_BASE); > + writel(upper_32_bits(cpu_addr), pcie->ctrl_base + PCIE_ATU_UPPER_BASE); > + writel(lower_32_bits(cpu_addr + size - 1), > + pcie->ctrl_base + PCIE_ATU_LIMIT); > + writel(lower_32_bits(pci_addr), > + pcie->ctrl_base + PCIE_ATU_LOWER_TARGET); > + writel(upper_32_bits(pci_addr), > + pcie->ctrl_base + PCIE_ATU_UPPER_TARGET); > + writel(type, pcie->ctrl_base + PCIE_ATU_CR1); > + writel(PCIE_ATU_ENABLE, pcie->ctrl_base + PCIE_ATU_CR2); > +} > + > +/** > * set_cfg_address() - Configure the PCIe controller config space access > * > * @pcie: Pointer to the PCI controller state > @@ -143,27 +175,29 @@ static uintptr_t set_cfg_address(struct pcie_dw_mvebu *pcie, > pci_dev_t d, uint where) > { > uintptr_t va_address; > + u32 atu_type; > > /* > * Region #0 is used for Outbound CFG space access. > * Direction = Outbound > * Region Index = 0 > */ > - writel(0, pcie->ctrl_base + PCIE_ATU_VIEWPORT); > > if (PCI_BUS(d) == (pcie->first_busno + 1)) > /* For local bus, change TLP Type field to 4. */ > - writel(PCIE_ATU_TYPE_CFG0, pcie->ctrl_base + PCIE_ATU_CR1); > + atu_type = PCIE_ATU_TYPE_CFG0; > else > /* Otherwise, change TLP Type field to 5. */ > - writel(PCIE_ATU_TYPE_CFG1, pcie->ctrl_base + PCIE_ATU_CR1); > + atu_type = PCIE_ATU_TYPE_CFG1; > > if (PCI_BUS(d) == pcie->first_busno) { > /* Accessing root port configuration space. */ > va_address = (uintptr_t)pcie->ctrl_base; > } else { > d = PCI_MASK_BUS(d) | (PCI_BUS(d) - pcie->first_busno); > - writel(d << 8, pcie->ctrl_base + PCIE_ATU_LOWER_TARGET); > + pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0, > + atu_type, (u64)pcie->cfg_base, > + d << 8, pcie->cfg_size); > va_address = (uintptr_t)pcie->cfg_base; > } > > @@ -231,6 +265,10 @@ static int pcie_dw_mvebu_read_config(struct udevice *bus, pci_dev_t bdf, > debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value); > *valuep = pci_conv_32_to_size(value, offset, size); > > + pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0, > + PCIE_ATU_TYPE_IO, pcie->io.phys_start, > + pcie->io.bus_start, pcie->io.size); > + > return 0; > } > > @@ -272,6 +310,10 @@ static int pcie_dw_mvebu_write_config(struct udevice *bus, pci_dev_t bdf, > value = pci_conv_size_to_32(old, value, offset, size); > writel(value, va_address); > > + pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0, > + PCIE_ATU_TYPE_IO, pcie->io.phys_start, > + pcie->io.bus_start, pcie->io.size); > + > return 0; > } > > @@ -388,34 +430,6 @@ static int pcie_dw_mvebu_pcie_link_up(const void *regs_base, u32 cap_speed) > } > > /** > - * pcie_dw_regions_setup() - iATU region setup > - * > - * @pcie: Pointer to the PCI controller state > - * > - * Configure the iATU regions in the PCIe controller for outbound access. > - */ > -static void pcie_dw_regions_setup(struct pcie_dw_mvebu *pcie) > -{ > - /* > - * Region #0 is used for Outbound CFG space access. > - * Direction = Outbound > - * Region Index = 0 > - */ > - writel(0, pcie->ctrl_base + PCIE_ATU_VIEWPORT); > - > - writel((u32)(uintptr_t)pcie->cfg_base, pcie->ctrl_base > - + PCIE_ATU_LOWER_BASE); > - writel(0, pcie->ctrl_base + PCIE_ATU_UPPER_BASE); > - writel((u32)(uintptr_t)pcie->cfg_base + pcie->cfg_size, > - pcie->ctrl_base + PCIE_ATU_LIMIT); > - > - writel(0, pcie->ctrl_base + PCIE_ATU_LOWER_TARGET); > - writel(0, pcie->ctrl_base + PCIE_ATU_UPPER_TARGET); > - writel(PCIE_ATU_TYPE_CFG0, pcie->ctrl_base + PCIE_ATU_CR1); > - writel(PCIE_ATU_ENABLE, pcie->ctrl_base + PCIE_ATU_CR2); > -} > - > -/** > * pcie_dw_set_host_bars() - Configure the host BARs > * > * @regs_base: A pointer to the PCIe controller registers > @@ -495,7 +509,18 @@ static int pcie_dw_mvebu_probe(struct udevice *dev) > hose->first_busno); > } > > - pcie_dw_regions_setup(pcie); > + /* Store the IO and MEM windows settings for future use by the ATU */ > + pcie->io.phys_start = hose->regions[0].phys_start; /* IO base */ > + pcie->io.bus_start = hose->regions[0].bus_start; /* IO_bus_addr */ > + pcie->io.size = hose->regions[0].size; /* IO size */ > + > + pcie->mem.phys_start = hose->regions[1].phys_start; /* MEM base */ > + pcie->mem.bus_start = hose->regions[1].bus_start; /* MEM_bus_addr */ > + pcie->mem.size = hose->regions[1].size; /* MEM size */ > + > + pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX1, > + PCIE_ATU_TYPE_MEM, pcie->mem.phys_start, > + pcie->mem.bus_start, pcie->mem.size); > > /* Set the CLASS_REV of RC CFG header to PCI_CLASS_BRIDGE_PCI */ > clrsetbits_le32(pcie->ctrl_base + PCI_CLASS_REVISION, > Applied to u-boot-marvell/master. Thanks, Stefan
diff --git a/drivers/pci/pcie_dw_mvebu.c b/drivers/pci/pcie_dw_mvebu.c index a198855..a0032b7 100644 --- a/drivers/pci/pcie_dw_mvebu.c +++ b/drivers/pci/pcie_dw_mvebu.c @@ -111,6 +111,10 @@ struct pcie_dw_mvebu { void *cfg_base; fdt_size_t cfg_size; int first_busno; + + /* IO and MEM PCI regions */ + struct pci_region io; + struct pci_region mem; }; static int pcie_dw_get_link_speed(const void *regs_base) @@ -126,6 +130,34 @@ static int pcie_dw_get_link_width(const void *regs_base) } /** + * pcie_dw_prog_outbound_atu() - Configure ATU for outbound accesses + * + * @pcie: Pointer to the PCI controller state + * @index: ATU region index + * @type: ATU accsess type + * @cpu_addr: the physical address for the translation entry + * @pci_addr: the pcie bus address for the translation entry + * @size: the size of the translation entry + */ +static void pcie_dw_prog_outbound_atu(struct pcie_dw_mvebu *pcie, int index, + int type, u64 cpu_addr, u64 pci_addr, + u32 size) +{ + writel(PCIE_ATU_REGION_OUTBOUND | index, + pcie->ctrl_base + PCIE_ATU_VIEWPORT); + writel(lower_32_bits(cpu_addr), pcie->ctrl_base + PCIE_ATU_LOWER_BASE); + writel(upper_32_bits(cpu_addr), pcie->ctrl_base + PCIE_ATU_UPPER_BASE); + writel(lower_32_bits(cpu_addr + size - 1), + pcie->ctrl_base + PCIE_ATU_LIMIT); + writel(lower_32_bits(pci_addr), + pcie->ctrl_base + PCIE_ATU_LOWER_TARGET); + writel(upper_32_bits(pci_addr), + pcie->ctrl_base + PCIE_ATU_UPPER_TARGET); + writel(type, pcie->ctrl_base + PCIE_ATU_CR1); + writel(PCIE_ATU_ENABLE, pcie->ctrl_base + PCIE_ATU_CR2); +} + +/** * set_cfg_address() - Configure the PCIe controller config space access * * @pcie: Pointer to the PCI controller state @@ -143,27 +175,29 @@ static uintptr_t set_cfg_address(struct pcie_dw_mvebu *pcie, pci_dev_t d, uint where) { uintptr_t va_address; + u32 atu_type; /* * Region #0 is used for Outbound CFG space access. * Direction = Outbound * Region Index = 0 */ - writel(0, pcie->ctrl_base + PCIE_ATU_VIEWPORT); if (PCI_BUS(d) == (pcie->first_busno + 1)) /* For local bus, change TLP Type field to 4. */ - writel(PCIE_ATU_TYPE_CFG0, pcie->ctrl_base + PCIE_ATU_CR1); + atu_type = PCIE_ATU_TYPE_CFG0; else /* Otherwise, change TLP Type field to 5. */ - writel(PCIE_ATU_TYPE_CFG1, pcie->ctrl_base + PCIE_ATU_CR1); + atu_type = PCIE_ATU_TYPE_CFG1; if (PCI_BUS(d) == pcie->first_busno) { /* Accessing root port configuration space. */ va_address = (uintptr_t)pcie->ctrl_base; } else { d = PCI_MASK_BUS(d) | (PCI_BUS(d) - pcie->first_busno); - writel(d << 8, pcie->ctrl_base + PCIE_ATU_LOWER_TARGET); + pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0, + atu_type, (u64)pcie->cfg_base, + d << 8, pcie->cfg_size); va_address = (uintptr_t)pcie->cfg_base; } @@ -231,6 +265,10 @@ static int pcie_dw_mvebu_read_config(struct udevice *bus, pci_dev_t bdf, debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value); *valuep = pci_conv_32_to_size(value, offset, size); + pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0, + PCIE_ATU_TYPE_IO, pcie->io.phys_start, + pcie->io.bus_start, pcie->io.size); + return 0; } @@ -272,6 +310,10 @@ static int pcie_dw_mvebu_write_config(struct udevice *bus, pci_dev_t bdf, value = pci_conv_size_to_32(old, value, offset, size); writel(value, va_address); + pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0, + PCIE_ATU_TYPE_IO, pcie->io.phys_start, + pcie->io.bus_start, pcie->io.size); + return 0; } @@ -388,34 +430,6 @@ static int pcie_dw_mvebu_pcie_link_up(const void *regs_base, u32 cap_speed) } /** - * pcie_dw_regions_setup() - iATU region setup - * - * @pcie: Pointer to the PCI controller state - * - * Configure the iATU regions in the PCIe controller for outbound access. - */ -static void pcie_dw_regions_setup(struct pcie_dw_mvebu *pcie) -{ - /* - * Region #0 is used for Outbound CFG space access. - * Direction = Outbound - * Region Index = 0 - */ - writel(0, pcie->ctrl_base + PCIE_ATU_VIEWPORT); - - writel((u32)(uintptr_t)pcie->cfg_base, pcie->ctrl_base - + PCIE_ATU_LOWER_BASE); - writel(0, pcie->ctrl_base + PCIE_ATU_UPPER_BASE); - writel((u32)(uintptr_t)pcie->cfg_base + pcie->cfg_size, - pcie->ctrl_base + PCIE_ATU_LIMIT); - - writel(0, pcie->ctrl_base + PCIE_ATU_LOWER_TARGET); - writel(0, pcie->ctrl_base + PCIE_ATU_UPPER_TARGET); - writel(PCIE_ATU_TYPE_CFG0, pcie->ctrl_base + PCIE_ATU_CR1); - writel(PCIE_ATU_ENABLE, pcie->ctrl_base + PCIE_ATU_CR2); -} - -/** * pcie_dw_set_host_bars() - Configure the host BARs * * @regs_base: A pointer to the PCIe controller registers @@ -495,7 +509,18 @@ static int pcie_dw_mvebu_probe(struct udevice *dev) hose->first_busno); } - pcie_dw_regions_setup(pcie); + /* Store the IO and MEM windows settings for future use by the ATU */ + pcie->io.phys_start = hose->regions[0].phys_start; /* IO base */ + pcie->io.bus_start = hose->regions[0].bus_start; /* IO_bus_addr */ + pcie->io.size = hose->regions[0].size; /* IO size */ + + pcie->mem.phys_start = hose->regions[1].phys_start; /* MEM base */ + pcie->mem.bus_start = hose->regions[1].bus_start; /* MEM_bus_addr */ + pcie->mem.size = hose->regions[1].size; /* MEM size */ + + pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX1, + PCIE_ATU_TYPE_MEM, pcie->mem.phys_start, + pcie->mem.bus_start, pcie->mem.size); /* Set the CLASS_REV of RC CFG header to PCI_CLASS_BRIDGE_PCI */ clrsetbits_le32(pcie->ctrl_base + PCI_CLASS_REVISION,