dm: pcie: designware: add correct ATU handling
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> Signed-off-by: Stefan Roese <sr@denx.de>
This commit is contained in:
parent
81cf7c8d45
commit
b8478fcd04
@ -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)
|
||||
@ -125,6 +129,34 @@ static int pcie_dw_get_link_width(const void *regs_base)
|
||||
PCIE_LINK_STATUS_WIDTH_MASK) >> PCIE_LINK_STATUS_WIDTH_OFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -387,34 +429,6 @@ static int pcie_dw_mvebu_pcie_link_up(const void *regs_base, u32 cap_speed)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user