Implement address translation. Makes I/O space access work.
authorkettenis <kettenis@openbsd.org>
Tue, 21 Aug 2018 22:16:42 +0000 (22:16 +0000)
committerkettenis <kettenis@openbsd.org>
Tue, 21 Aug 2018 22:16:42 +0000 (22:16 +0000)
sys/dev/fdt/dwpcie.c

index fdd5f29..a27f4fb 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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>
  *
@@ -39,6 +39,7 @@
 #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
@@ -105,6 +106,9 @@ struct dwpcie_softc {
        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;
@@ -161,6 +165,11 @@ void       dwpcie_intr_disestablish(void *, void *);
 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)
 {
@@ -289,13 +298,23 @@ 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;
@@ -315,8 +334,8 @@ dwpcie_attach(struct device *parent, struct device *self, void *aux)
 
        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;
@@ -332,8 +351,8 @@ dwpcie_attach(struct device *parent, struct device *self, void *aux)
 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);
@@ -359,7 +378,7 @@ dwpcie_armada8k_init(struct dwpcie_softc *sc)
        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);
@@ -367,6 +386,25 @@ dwpcie_armada8k_init(struct dwpcie_softc *sc)
        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;
@@ -631,3 +669,47 @@ dwpcie_intr_disestablish(void *v, void *cookie)
 {
        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;
+}