The branch main has been updated by jrtc27:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=f240dfff229d1f1ff502f59901ef2b9364ca55d9

commit f240dfff229d1f1ff502f59901ef2b9364ca55d9
Author:     Jessica Clarke <[email protected]>
AuthorDate: 2021-07-21 04:50:50 +0000
Commit:     Jessica Clarke <[email protected]>
CommitDate: 2021-07-21 04:50:50 +0000

    pci_dw: Support modern "unroll" iATU mode
    
    This supersedes the old legacy mode where a viewport register was used
    to mux multiple regions behind a single set of registers, and is used on
    the SiFive FU740.
    
    Reviewed by:    mmel
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D31029
---
 sys/dev/pci/pci_dw.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 sys/dev/pci/pci_dw.h | 18 ++++++++++
 2 files changed, 114 insertions(+), 3 deletions(-)

diff --git a/sys/dev/pci/pci_dw.c b/sys/dev/pci/pci_dw.c
index 3aa6c4326d67..90f992e83fce 100644
--- a/sys/dev/pci/pci_dw.c
+++ b/sys/dev/pci/pci_dw.c
@@ -73,6 +73,11 @@ __FBSDID("$FreeBSD$");
 #define        DBI_RD2(sc, reg)        pci_dw_dbi_rd2((sc)->dev, reg)
 #define        DBI_RD4(sc, reg)        pci_dw_dbi_rd4((sc)->dev, reg)
 
+#define        IATU_UR_WR4(sc, reg, val)       \
+    bus_write_4((sc)->iatu_ur_res, (sc)->iatu_ur_offset + (reg), (val))
+#define        IATU_UR_RD4(sc, reg)            \
+    bus_read_4((sc)->iatu_ur_res, (sc)->iatu_ur_offset + (reg))
+
 #define        PCI_BUS_SHIFT           20
 #define        PCI_SLOT_SHIFT          15
 #define        PCI_FUNC_SHIFT          12
@@ -168,9 +173,52 @@ pci_dw_check_dev(struct pci_dw_softc *sc, u_int bus, u_int 
slot, u_int func,
        return (true);
 }
 
-/* Map one uoutbound ATU region */
+static bool
+pci_dw_detect_atu_unroll(struct pci_dw_softc *sc)
+{
+       return (DBI_RD4(sc, DW_IATU_VIEWPORT) == 0xFFFFFFFFU);
+}
+
 static int
-pci_dw_map_out_atu(struct pci_dw_softc *sc, int idx, int type,
+pci_dw_map_out_atu_unroll(struct pci_dw_softc *sc, int idx, int type,
+    uint64_t pa, uint64_t pci_addr, uint32_t size)
+{
+       uint32_t reg;
+       int i;
+
+       if (size == 0)
+               return (0);
+
+       IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, LWR_BASE_ADDR),
+           pa & 0xFFFFFFFF);
+       IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, UPPER_BASE_ADDR),
+           (pa >> 32) & 0xFFFFFFFF);
+       IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, LIMIT_ADDR),
+           (pa + size - 1) & 0xFFFFFFFF);
+       IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, LWR_TARGET_ADDR),
+           pci_addr & 0xFFFFFFFF);
+       IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, UPPER_TARGET_ADDR),
+           (pci_addr  >> 32) & 0xFFFFFFFF);
+       IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, CTRL1),
+           IATU_CTRL1_TYPE(type));
+       IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, CTRL2),
+           IATU_CTRL2_REGION_EN);
+
+       /* Wait until setup becomes valid */
+       for (i = 10; i > 0; i--) {
+               reg = IATU_UR_RD4(sc, DW_IATU_UR_REG(idx, CTRL2));
+               if (reg & IATU_CTRL2_REGION_EN)
+                       return (0);
+               DELAY(5);
+       }
+
+       device_printf(sc->dev,
+           "Cannot map outbound region %d in unroll mode iATU\n", idx);
+       return (ETIMEDOUT);
+}
+
+static int
+pci_dw_map_out_atu_legacy(struct pci_dw_softc *sc, int idx, int type,
     uint64_t pa, uint64_t pci_addr, uint32_t size)
 {
        uint32_t reg;
@@ -195,11 +243,25 @@ pci_dw_map_out_atu(struct pci_dw_softc *sc, int idx, int 
type,
                        return (0);
                DELAY(5);
        }
+
        device_printf(sc->dev,
-           "Cannot map outbound region(%d) in iATU\n", idx);
+           "Cannot map outbound region %d in legacy mode iATU\n", idx);
        return (ETIMEDOUT);
 }
 
+/* Map one outbound ATU region */
+static int
+pci_dw_map_out_atu(struct pci_dw_softc *sc, int idx, int type,
+    uint64_t pa, uint64_t pci_addr, uint32_t size)
+{
+       if (sc->iatu_ur_res)
+               return (pci_dw_map_out_atu_unroll(sc, idx, type, pa,
+                   pci_addr, size));
+       else
+               return (pci_dw_map_out_atu_legacy(sc, idx, type, pa,
+                   pci_addr, size));
+}
+
 static int
 pci_dw_setup_hw(struct pci_dw_softc *sc)
 {
@@ -580,6 +642,7 @@ pci_dw_init(device_t dev)
 {
        struct pci_dw_softc *sc;
        int rv, rid;
+       bool unroll_mode;
 
        sc = device_get_softc(dev);
        sc->dev = dev;
@@ -660,6 +723,36 @@ pci_dw_init(device_t dev)
        if (rv != 0)
                goto out;
 
+       unroll_mode = pci_dw_detect_atu_unroll(sc);
+       if (bootverbose)
+               device_printf(dev, "Using iATU %s mode\n",
+                   unroll_mode ? "unroll" : "legacy");
+       if (unroll_mode) {
+               rid = 0;
+               rv = ofw_bus_find_string_index(sc->node, "reg-names", "atu", 
&rid);
+               if (rv == 0) {
+                       sc->iatu_ur_res = bus_alloc_resource_any(dev,
+                           SYS_RES_MEMORY, &rid, RF_ACTIVE);
+                       if (sc->iatu_ur_res == NULL) {
+                               device_printf(dev,
+                                   "Cannot allocate iATU space (rid: %d)\n",
+                                   rid);
+                               rv = ENXIO;
+                               goto out;
+                       }
+                       sc->iatu_ur_offset = 0;
+                       sc->iatu_ur_size = rman_get_size(sc->iatu_ur_res);
+               } else if (rv == ENOENT) {
+                       sc->iatu_ur_res = sc->dbi_res;
+                       sc->iatu_ur_offset = DW_DEFAULT_IATU_UR_DBI_OFFSET;
+                       sc->iatu_ur_size = DW_DEFAULT_IATU_UR_DBI_SIZE;
+               } else {
+                       device_printf(dev, "Cannot get iATU space memory\n");
+                       rv = ENXIO;
+                       goto out;
+               }
+       }
+
        rv = pci_dw_setup_hw(sc);
        if (rv != 0)
                goto out;
diff --git a/sys/dev/pci/pci_dw.h b/sys/dev/pci/pci_dw.h
index c2c9249449bb..51c4169f74d2 100644
--- a/sys/dev/pci/pci_dw.h
+++ b/sys/dev/pci/pci_dw.h
@@ -63,6 +63,7 @@
 #define        DW_MISC_CONTROL_1               0x8BC
 #define         DBI_RO_WR_EN                           (1 << 0)
 
+/* Legacy (pre-4.80) iATU mode */
 #define        DW_IATU_VIEWPORT                        0x900
 #define         IATU_REGION_INBOUND                    (1U << 31)
 #define         IATU_REGION_INDEX(x)                   ((x) & 0x7)
@@ -80,6 +81,20 @@
 #define        DW_IATU_LWR_TARGET_ADDR         0x918
 #define        DW_IATU_UPPER_TARGET_ADDR       0x91C
 
+/* Modern (4.80+) "unroll" iATU mode */
+#define        DW_IATU_UR_STEP                 0x200
+#define        DW_IATU_UR_REG(r, n)            (r) * DW_IATU_UR_STEP + 
IATU_UR_##n
+#define         IATU_UR_CTRL1                          0x00
+#define         IATU_UR_CTRL2                          0x04
+#define         IATU_UR_LWR_BASE_ADDR                  0x08
+#define         IATU_UR_UPPER_BASE_ADDR                0x0C
+#define         IATU_UR_LIMIT_ADDR                     0x10
+#define         IATU_UR_LWR_TARGET_ADDR                0x14
+#define         IATU_UR_UPPER_TARGET_ADDR              0x18
+
+#define        DW_DEFAULT_IATU_UR_DBI_OFFSET   0x300000
+#define        DW_DEFAULT_IATU_UR_DBI_SIZE     0x1000
+
 struct pci_dw_softc {
        struct ofw_pci_softc    ofw_pci;        /* Must be first */
 
@@ -101,6 +116,9 @@ struct pci_dw_softc {
 
        int                     num_lanes;
        int                     num_viewport;
+       struct resource         *iatu_ur_res;   /* NB: May be dbi_res */
+       bus_addr_t              iatu_ur_offset;
+       bus_size_t              iatu_ur_size;
        bus_addr_t              cfg_pa;         /* PA of config memoty */
        bus_size_t              cfg_size;       /* size of config  region */
 
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to