mirror of
https://xff.cz/git/u-boot/
synced 2025-10-27 08:33:10 +01:00
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:
committed by
Stefan Roese
parent
81cf7c8d45
commit
b8478fcd04
@@ -111,6 +111,10 @@ struct pcie_dw_mvebu {
|
|||||||
void *cfg_base;
|
void *cfg_base;
|
||||||
fdt_size_t cfg_size;
|
fdt_size_t cfg_size;
|
||||||
int first_busno;
|
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)
|
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_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
|
* 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)
|
pci_dev_t d, uint where)
|
||||||
{
|
{
|
||||||
uintptr_t va_address;
|
uintptr_t va_address;
|
||||||
|
u32 atu_type;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Region #0 is used for Outbound CFG space access.
|
* Region #0 is used for Outbound CFG space access.
|
||||||
* Direction = Outbound
|
* Direction = Outbound
|
||||||
* Region Index = 0
|
* Region Index = 0
|
||||||
*/
|
*/
|
||||||
writel(0, pcie->ctrl_base + PCIE_ATU_VIEWPORT);
|
|
||||||
|
|
||||||
if (PCI_BUS(d) == (pcie->first_busno + 1))
|
if (PCI_BUS(d) == (pcie->first_busno + 1))
|
||||||
/* For local bus, change TLP Type field to 4. */
|
/* 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
|
else
|
||||||
/* Otherwise, change TLP Type field to 5. */
|
/* 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) {
|
if (PCI_BUS(d) == pcie->first_busno) {
|
||||||
/* Accessing root port configuration space. */
|
/* Accessing root port configuration space. */
|
||||||
va_address = (uintptr_t)pcie->ctrl_base;
|
va_address = (uintptr_t)pcie->ctrl_base;
|
||||||
} else {
|
} else {
|
||||||
d = PCI_MASK_BUS(d) | (PCI_BUS(d) - pcie->first_busno);
|
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;
|
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);
|
debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
|
||||||
*valuep = pci_conv_32_to_size(value, offset, size);
|
*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;
|
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);
|
value = pci_conv_size_to_32(old, value, offset, size);
|
||||||
writel(value, va_address);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,34 +429,6 @@ static int pcie_dw_mvebu_pcie_link_up(const void *regs_base, u32 cap_speed)
|
|||||||
return 1;
|
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
|
* 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);
|
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 */
|
/* Set the CLASS_REV of RC CFG header to PCI_CLASS_BRIDGE_PCI */
|
||||||
clrsetbits_le32(pcie->ctrl_base + PCI_CLASS_REVISION,
|
clrsetbits_le32(pcie->ctrl_base + PCI_CLASS_REVISION,
|
||||||
|
|||||||
Reference in New Issue
Block a user