-/* $OpenBSD: dwpcie.c,v 1.9 2018/08/06 10:52:30 patrick Exp $ */
+/* $OpenBSD: dwpcie.c,v 1.10 2018/08/21 22:16:42 kettenis Exp $ */
/*
* Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org>
*
#define MISC_CONTROL_1_DBI_RO_WR_EN (1 << 0)
#define IATU_VIEWPORT 0x900
#define IATU_REGION_CTRL_1 0x904
+#define IATU_REGION_CTRL_1_TYPE_IO 2
#define IATU_REGION_CTRL_1_TYPE_CFG0 4
#define IATU_REGION_CTRL_1_TYPE_CFG1 5
#define IATU_REGION_CTRL_2 0x908
struct dwpcie_range *sc_ranges;
int sc_rangeslen;
+ struct bus_space sc_bus_iot;
+ struct bus_space sc_bus_memt;
+
struct arm64_pci_chipset sc_pc;
struct extent *sc_busex;
struct extent *sc_memex;
void *dwpcie_armada8k_intr_establish(void *, pci_intr_handle_t, int,
int (*)(void *), void *, char *);
+int dwpcie_bs_iomap(bus_space_tag_t, bus_addr_t, bus_size_t, int,
+ bus_space_handle_t *);
+int dwpcie_bs_memmap(bus_space_tag_t, bus_addr_t, bus_size_t, int,
+ bus_space_handle_t *);
+
void
dwpcie_attach(struct device *parent, struct device *self, void *aux)
{
extent_free(sc->sc_busex, bus_range[0],
bus_range[1] - bus_range[0] + 1, EX_WAITOK);
- /* Set up memory mapped I/O range. */
+ /* Set up I/O and memory mapped I/O ranges. */
for (i = 0; i < nranges; i++) {
+ if ((sc->sc_ranges[i].flags & 0x03000000) == 0x01000000)
+ extent_free(sc->sc_ioex, sc->sc_ranges[i].pci_base,
+ sc->sc_ranges[i].size, EX_WAITOK);
if ((sc->sc_ranges[i].flags & 0x03000000) == 0x02000000)
extent_free(sc->sc_memex, sc->sc_ranges[i].pci_base,
- sc->sc_ranges[i].size, EX_NOWAIT);
+ sc->sc_ranges[i].size, EX_WAITOK);
}
+ memcpy(&sc->sc_bus_iot, sc->sc_iot, sizeof(sc->sc_bus_iot));
+ sc->sc_bus_iot.bus_private = sc;
+ sc->sc_bus_iot._space_map = dwpcie_bs_iomap;
+ memcpy(&sc->sc_bus_memt, sc->sc_iot, sizeof(sc->sc_bus_memt));
+ sc->sc_bus_memt.bus_private = sc;
+ sc->sc_bus_memt._space_map = dwpcie_bs_memmap;
+
sc->sc_pc.pc_conf_v = sc;
sc->sc_pc.pc_attach_hook = dwpcie_attach_hook;
sc->sc_pc.pc_bus_maxdevs = dwpcie_bus_maxdevs;
memset(&pba, 0, sizeof(pba));
pba.pba_busname = "pci";
- pba.pba_iot = faa->fa_iot;
- pba.pba_memt = faa->fa_iot;
+ pba.pba_iot = &sc->sc_bus_iot;
+ pba.pba_memt = &sc->sc_bus_memt;
pba.pba_dmat = faa->fa_dmat;
pba.pba_pc = &sc->sc_pc;
pba.pba_busex = sc->sc_busex;
void
dwpcie_armada8k_init(struct dwpcie_softc *sc)
{
+ int i, timo, viewport = 0;
uint32_t reg;
- int timo;
if (!dwpcie_armada8k_link_up(sc)) {
reg = HREAD4(sc, PCIE_GLOBAL_CTRL);
HWRITE4(sc, PCIE_AWUSER, reg);
/* Set up addres translation for PCI confg space. */
- HWRITE4(sc, IATU_VIEWPORT, 0);
+ HWRITE4(sc, IATU_VIEWPORT, viewport++);
HWRITE4(sc, IATU_LWR_BASE_ADDR, sc->sc_cfg_addr);
HWRITE4(sc, IATU_UPPER_BASE_ADDR, sc->sc_cfg_addr >> 32);
HWRITE4(sc, IATU_LIMIT_ADDR, sc->sc_cfg_addr + sc->sc_cfg_size - 1);
HWRITE4(sc, IATU_UPPER_TARGET_ADDR, 0);
HWRITE4(sc, IATU_REGION_CTRL_2, IATU_REGION_CTRL_2_REGION_EN);
+ /* Set up address translation for I/O space. */
+ for (i = 0; i < sc->sc_rangeslen; i++) {
+ if ((sc->sc_ranges[i].flags & 0x03000000) != 0x01000000)
+ continue;
+ HWRITE4(sc, IATU_VIEWPORT, viewport++);
+ HWRITE4(sc, IATU_LWR_BASE_ADDR,
+ sc->sc_ranges[i].phys_base);
+ HWRITE4(sc, IATU_UPPER_BASE_ADDR,
+ sc->sc_ranges[i].phys_base >> 32);
+ HWRITE4(sc, IATU_LIMIT_ADDR,
+ sc->sc_ranges[i].phys_base + sc->sc_ranges[i].size - 1);
+ HWRITE4(sc, IATU_LWR_TARGET_ADDR,
+ sc->sc_ranges[i].pci_base);
+ HWRITE4(sc, IATU_UPPER_TARGET_ADDR,
+ sc->sc_ranges[i].pci_base >> 32);
+ HWRITE4(sc, IATU_REGION_CTRL_1, IATU_REGION_CTRL_1_TYPE_IO);
+ HWRITE4(sc, IATU_REGION_CTRL_2, IATU_REGION_CTRL_2_REGION_EN);
+ }
+
if (!dwpcie_armada8k_link_up(sc)) {
reg = HREAD4(sc, PCIE_GLOBAL_CTRL);
reg |= PCIE_GLOBAL_CTRL_APP_LTSSM_EN;
{
panic("%s", __func__);
}
+
+int
+dwpcie_bs_iomap(bus_space_tag_t t, bus_addr_t addr, bus_size_t size,
+ int flags, bus_space_handle_t *bshp)
+{
+ struct dwpcie_softc *sc = t->bus_private;
+ int i;
+
+ for (i = 0; i < sc->sc_rangeslen; i++) {
+ uint64_t pci_start = sc->sc_ranges[i].pci_base;
+ uint64_t pci_end = pci_start + sc->sc_ranges[i].size;
+ uint64_t phys_start = sc->sc_ranges[i].phys_base;
+
+ if ((sc->sc_ranges[i].flags & 0x03000000) == 0x01000000 &&
+ addr >= pci_start && addr + size <= pci_end) {
+ return bus_space_map(sc->sc_iot,
+ addr - pci_start + phys_start, size, flags, bshp);
+ }
+ }
+
+ return ENXIO;
+}
+
+int
+dwpcie_bs_memmap(bus_space_tag_t t, bus_addr_t addr, bus_size_t size,
+ int flags, bus_space_handle_t *bshp)
+{
+ struct dwpcie_softc *sc = t->bus_private;
+ int i;
+
+ for (i = 0; i < sc->sc_rangeslen; i++) {
+ uint64_t pci_start = sc->sc_ranges[i].pci_base;
+ uint64_t pci_end = pci_start + sc->sc_ranges[i].size;
+ uint64_t phys_start = sc->sc_ranges[i].phys_base;
+
+ if ((sc->sc_ranges[i].flags & 0x03000000) == 0x02000000 &&
+ addr >= pci_start && addr + size <= pci_end) {
+ return bus_space_map(sc->sc_iot,
+ addr - pci_start + phys_start, size, flags, bshp);
+ }
+ }
+
+ return ENXIO;
+}