-/* $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>
*
#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
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;
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);
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;
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);
}
/* 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) {
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);
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;
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));
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)
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);
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);