summaryrefslogtreecommitdiff
path: root/sys/dev/fdt/dwpcie.c
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2021-06-24 09:34:18 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2021-06-24 09:34:18 +0000
commit26870a50c51a498f7481de6354b6e925f5187a31 (patch)
tree2723557de6527ad51dccb0246f4ac2d2cc1fab94 /sys/dev/fdt/dwpcie.c
parent78c38fe1f0794fa515596c53e5fdfd52c6d5524d (diff)
Add support for the 64-bit prefetchable memory window.
ok patrick@
Diffstat (limited to 'sys/dev/fdt/dwpcie.c')
-rw-r--r--sys/dev/fdt/dwpcie.c97
1 files changed, 74 insertions, 23 deletions
diff --git a/sys/dev/fdt/dwpcie.c b/sys/dev/fdt/dwpcie.c
index 55647d2ca7b..71f48fc2470 100644
--- a/sys/dev/fdt/dwpcie.c
+++ b/sys/dev/fdt/dwpcie.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dwpcie.c,v 1.32 2021/06/18 12:12:22 kettenis Exp $ */
+/* $OpenBSD: dwpcie.c,v 1.33 2021/06/24 09:34:17 kettenis Exp $ */
/*
* Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org>
*
@@ -62,6 +62,7 @@
#define IATU_VIEWPORT_INDEX0 0
#define IATU_VIEWPORT_INDEX1 1
#define IATU_VIEWPORT_INDEX2 2
+#define IATU_VIEWPORT_INDEX3 3
#define IATU_OFFSET_VIEWPORT 0x904
#define IATU_OFFSET_UNROLL(x) (0x200 * (x))
#define IATU_REGION_CTRL_1 0x000
@@ -201,6 +202,9 @@ struct dwpcie_softc {
bus_addr_t sc_mem_base;
bus_addr_t sc_mem_bus_addr;
bus_size_t sc_mem_size;
+ bus_addr_t sc_pmem_base;
+ bus_addr_t sc_pmem_bus_addr;
+ bus_size_t sc_pmem_size;
int sc_node;
int sc_acells;
@@ -269,6 +273,8 @@ int dwpcie_g12a_link_up(struct dwpcie_softc *);
int dwpcie_imx8mq_init(struct dwpcie_softc *);
int dwpcie_imx8mq_intr(void *);
+int dwpcie_fu740_init(struct dwpcie_softc *);
+
void dwpcie_attach_hook(struct device *, struct device *,
struct pcibus_attach_args *);
int dwpcie_bus_maxdevs(void *, int);
@@ -415,6 +421,7 @@ dwpcie_attach_deferred(struct device *self)
struct pcibus_attach_args pba;
bus_addr_t iobase, iolimit;
bus_addr_t membase, memlimit;
+ bus_addr_t pmembase, pmemlimit;
uint32_t bus_range[2];
pcireg_t bir, blr, csr;
int i, error = 0;
@@ -426,6 +433,8 @@ dwpcie_attach_deferred(struct device *self)
if (OF_is_compatible(sc->sc_node, "fsl,imx8mm-pcie") ||
OF_is_compatible(sc->sc_node, "fsl,imx8mq-pcie"))
error = dwpcie_imx8mq_init(sc);
+ if (OF_is_compatible(sc->sc_node, "sifive,fu740-pcie"))
+ error = dwpcie_fu740_init(sc);
if (error != 0) {
bus_space_unmap(sc->sc_iot, sc->sc_conf_ioh, sc->sc_conf_size);
bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ctrl_size);
@@ -442,7 +451,6 @@ dwpcie_attach_deferred(struct device *self)
}
/* Set up address translation for I/O space. */
- sc->sc_io_bus_addr = sc->sc_mem_bus_addr = -1;
for (i = 0; i < sc->sc_nranges; i++) {
if ((sc->sc_ranges[i].flags & 0x03000000) == 0x01000000 &&
sc->sc_ranges[i].size > 0) {
@@ -456,15 +464,37 @@ dwpcie_attach_deferred(struct device *self)
sc->sc_mem_bus_addr = sc->sc_ranges[i].pci_base;
sc->sc_mem_size = sc->sc_ranges[i].size;
}
+ if ((sc->sc_ranges[i].flags & 0x03000000) == 0x03000000 &&
+ sc->sc_ranges[i].size > 0) {
+ sc->sc_pmem_base = sc->sc_ranges[i].phys_base;
+ sc->sc_pmem_bus_addr = sc->sc_ranges[i].pci_base;
+ sc->sc_pmem_size = sc->sc_ranges[i].size;
+ }
+ }
+ if (sc->sc_mem_size == 0) {
+ printf("%s: no memory mapped I/O window\n",
+ sc->sc_dev.dv_xname);
+ return;
}
+ /*
+ * Disable prefetchable memory mapped I/O window if we don't
+ * have enough viewports to enable it.
+ */
+ if (sc->sc_num_viewport < 4)
+ sc->sc_pmem_size = 0;
+
dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX0,
IATU_REGION_CTRL_1_TYPE_MEM, sc->sc_mem_base,
sc->sc_mem_bus_addr, sc->sc_mem_size);
- if (sc->sc_num_viewport > 2)
+ if (sc->sc_num_viewport > 2 && sc->sc_io_size > 0)
dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX2,
IATU_REGION_CTRL_1_TYPE_IO, sc->sc_io_base,
sc->sc_io_bus_addr, sc->sc_io_size);
+ if (sc->sc_num_viewport > 3 && sc->sc_pmem_size > 0)
+ dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX3,
+ IATU_REGION_CTRL_1_TYPE_MEM, sc->sc_pmem_base,
+ sc->sc_pmem_bus_addr, sc->sc_pmem_size);
/* Enable modification of read-only bits. */
HSET4(sc, MISC_CONTROL_1, MISC_CONTROL_1_DBI_RO_WR_EN);
@@ -500,16 +530,6 @@ dwpcie_attach_deferred(struct device *self)
bir |= (bus_range[1] << 16);
HWRITE4(sc, PPB_REG_BUSINFO, bir);
- /* Initialize I/O window. */
- iobase = sc->sc_io_bus_addr;
- iolimit = iobase + sc->sc_io_size - 1;
- blr = iolimit & PPB_IO_MASK;
- blr |= (iobase >> PPB_IO_SHIFT);
- HWRITE4(sc, PPB_REG_IOSTATUS, blr);
- blr = (iobase & 0xffff0000) >> 16;
- blr |= iolimit & 0xffff0000;
- HWRITE4(sc, PPB_REG_IO_HI, blr);
-
/* Initialize memory mapped I/O window. */
membase = sc->sc_mem_bus_addr;
memlimit = membase + sc->sc_mem_size - 1;
@@ -517,16 +537,39 @@ dwpcie_attach_deferred(struct device *self)
blr |= (membase >> PPB_MEM_SHIFT);
HWRITE4(sc, PPB_REG_MEM, blr);
- /* Reset prefetchable memory mapped I/O window. */
- HWRITE4(sc, PPB_REG_PREFMEM, 0x0000ffff);
- HWRITE4(sc, PPB_REG_PREFBASE_HI32, 0);
- HWRITE4(sc, PPB_REG_PREFLIM_HI32, 0);
+ /* Initialize I/O window. */
+ if (sc->sc_io_size > 0) {
+ iobase = sc->sc_io_bus_addr;
+ iolimit = iobase + sc->sc_io_size - 1;
+ blr = iolimit & PPB_IO_MASK;
+ blr |= (iobase >> PPB_IO_SHIFT);
+ HWRITE4(sc, PPB_REG_IOSTATUS, blr);
+ blr = (iobase & 0xffff0000) >> 16;
+ blr |= iolimit & 0xffff0000;
+ HWRITE4(sc, PPB_REG_IO_HI, blr);
+ } else {
+ HWRITE4(sc, PPB_REG_IOSTATUS, 0x000000ff);
+ HWRITE4(sc, PPB_REG_IO_HI, 0x0000ffff);
+ }
+
+ /* Initialize prefetchable memory mapped I/O window. */
+ if (sc->sc_pmem_size > 0) {
+ pmembase = sc->sc_pmem_bus_addr;
+ pmemlimit = pmembase + sc->sc_pmem_size - 1;
+ blr = pmemlimit & PPB_MEM_MASK;
+ blr |= (pmembase >> PPB_MEM_SHIFT);
+ HWRITE4(sc, PPB_REG_PREFMEM, blr);
+ HWRITE4(sc, PPB_REG_PREFBASE_HI32, pmembase >> 32);
+ HWRITE4(sc, PPB_REG_PREFLIM_HI32, pmemlimit >> 32);
+ } else {
+ HWRITE4(sc, PPB_REG_PREFMEM, 0x0000ffff);
+ HWRITE4(sc, PPB_REG_PREFBASE_HI32, 0);
+ HWRITE4(sc, PPB_REG_PREFLIM_HI32, 0);
+ }
- csr = PCI_COMMAND_MASTER_ENABLE;
- if (iolimit > iobase)
+ csr = PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE;
+ if (sc->sc_io_size > 0)
csr |= PCI_COMMAND_IO_ENABLE;
- if (memlimit > membase)
- csr |= PCI_COMMAND_MEM_ENABLE;
HWRITE4(sc, PCI_COMMAND_STATUS_REG, csr);
memcpy(&sc->sc_bus_iot, sc->sc_iot, sizeof(sc->sc_bus_iot));
@@ -1002,6 +1045,14 @@ dwpcie_imx8mq_intr(void *arg)
return 0;
}
+int
+dwpcie_fu740_init(struct dwpcie_softc *sc)
+{
+ sc->sc_num_viewport = 8;
+
+ return 0;
+}
+
void
dwpcie_atu_config(struct dwpcie_softc *sc, int index, int type,
uint64_t cpu_addr, uint64_t pci_addr, uint64_t size)
@@ -1109,7 +1160,7 @@ dwpcie_conf_read(void *v, pcitag_t tag, int reg)
ret = bus_space_read_4(sc->sc_iot, sc->sc_conf_ioh, reg);
- if (sc->sc_num_viewport <= 2) {
+ if (sc->sc_num_viewport <= 2 && sc->sc_io_size > 0) {
dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX1,
IATU_REGION_CTRL_1_TYPE_IO, sc->sc_io_base,
sc->sc_io_bus_addr, sc->sc_io_size);
@@ -1143,7 +1194,7 @@ dwpcie_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data)
bus_space_write_4(sc->sc_iot, sc->sc_conf_ioh, reg, data);
- if (sc->sc_num_viewport <= 2) {
+ if (sc->sc_num_viewport <= 2 && sc->sc_io_size > 0) {
dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX1,
IATU_REGION_CTRL_1_TYPE_IO, sc->sc_io_base,
sc->sc_io_bus_addr, sc->sc_io_size);