diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2021-06-24 09:34:18 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2021-06-24 09:34:18 +0000 |
commit | 26870a50c51a498f7481de6354b6e925f5187a31 (patch) | |
tree | 2723557de6527ad51dccb0246f4ac2d2cc1fab94 /sys/dev/fdt/dwpcie.c | |
parent | 78c38fe1f0794fa515596c53e5fdfd52c6d5524d (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.c | 97 |
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); |