libtx2bpmp: Use device tree for addresses

Extract MMIO addresses from the provided device tree.  Also use
PS_DRIVER_MODULE_DEFINE for registering the tx2_bpmp driver as a driver
with the framework for initialization.
diff --git a/libtx2bpmp/CMakeLists.txt b/libtx2bpmp/CMakeLists.txt
index f08dc48..cb02f86 100644
--- a/libtx2bpmp/CMakeLists.txt
+++ b/libtx2bpmp/CMakeLists.txt
@@ -19,4 +19,4 @@
 add_library(tx2bpmp STATIC EXCLUDE_FROM_ALL ${deps})
 
 target_include_directories(tx2bpmp PUBLIC include)
-target_link_libraries(tx2bpmp muslc platsupport)
+target_link_libraries(tx2bpmp muslc platsupport "-Wl,--undefined=bpmp_ptr")
diff --git a/libtx2bpmp/include/tx2bpmp/bpmp.h b/libtx2bpmp/include/tx2bpmp/bpmp.h
index df83ed5..a471751 100644
--- a/libtx2bpmp/include/tx2bpmp/bpmp.h
+++ b/libtx2bpmp/include/tx2bpmp/bpmp.h
@@ -47,11 +47,6 @@
  * @file
  */
 
-#define TX2_BPMP_TX_SHMEM_PADDR 0x3004e000
-#define TX2_BPMP_TX_SHMEM_SIZE 0x1000
-#define TX2_BPMP_RX_SHMEM_PADDR 0x3004f000
-#define TX2_BPMP_RX_SHMEM_SIZE 0x1000
-
 #define __BPMP_CHECK_ARGS(function) \
     do {                                                                            \
         if (!bpmp) { ZF_LOGE("bpmp is NULL"); return -EINVAL; }                     \
diff --git a/libtx2bpmp/include/tx2bpmp/hsp.h b/libtx2bpmp/include/tx2bpmp/hsp.h
index 7533a60..ee8aebf 100644
--- a/libtx2bpmp/include/tx2bpmp/hsp.h
+++ b/libtx2bpmp/include/tx2bpmp/hsp.h
@@ -15,9 +15,6 @@
 #include <platsupport/io.h>
 #include <utils/util.h>
 
-#define TX2_HSP_PADDR 0x3c00000
-#define TX2_HSP_SIZE 0xa0000
-
 #define __HSP_CHECK_ARGS(function)                                                                  \
     do {                                                                                            \
         if (!hsp) { ZF_LOGE("hsp is NULL"); return -EINVAL; }                                       \
@@ -66,7 +63,7 @@
  *
  * @return 0 on success, otherwise an error code.
  */
-int tx2_hsp_init(ps_io_ops_t *io_ops, tx2_hsp_t *hsp);
+int tx2_hsp_init(ps_io_ops_t *io_ops, tx2_hsp_t *hsp, const char *fdt_path);
 
 /*
  * Destroys an initialised TX2 HSP interface.
diff --git a/libtx2bpmp/src/bpmp.c b/libtx2bpmp/src/bpmp.c
index ef6fab1..d7e6d69 100644
--- a/libtx2bpmp/src/bpmp.c
+++ b/libtx2bpmp/src/bpmp.c
@@ -20,6 +20,8 @@
 #include <string.h>
 
 #include <platsupport/pmem.h>
+#include <platsupport/fdt.h>
+#include <platsupport/driver_module.h>
 #include <tx2bpmp/bpmp.h>
 #include <tx2bpmp/hsp.h>
 #include <tx2bpmp/ivc.h>
@@ -44,20 +46,9 @@
     struct tegra_ivc ivc;
     void *tx_base; // Virtual address base of the TX shared memory channel
     void *rx_base; // Virtual address base of the RX shared memory channel
+    pmem_region_t bpmp_shmems[NUM_SHMEM];
 };
 
-pmem_region_t bpmp_shmems[NUM_SHMEM] = {
-    {
-        .type = PMEM_TYPE_DEVICE,
-        .base_addr = TX2_BPMP_TX_SHMEM_PADDR,
-        .length = TX2_BPMP_TX_SHMEM_SIZE
-    },
-    {
-        .type = PMEM_TYPE_DEVICE,
-        .base_addr = TX2_BPMP_RX_SHMEM_PADDR,
-        .length = TX2_BPMP_RX_SHMEM_SIZE
-    }
-};
 
 static bool bpmp_initialised = false;
 static unsigned int bpmp_refcount = 0;
@@ -158,16 +149,39 @@
 
     /* Unmapping the shared memory also destroys the IVC */
     if (bpmp_priv->tx_base) {
-        ps_io_unmap(&bpmp_priv->io_ops->io_mapper, bpmp_priv->tx_base, bpmp_shmems[TX_SHMEM].length);
+        ps_io_unmap(&bpmp_priv->io_ops->io_mapper, bpmp_priv->tx_base, bpmp_data.bpmp_shmems[TX_SHMEM].length);
     }
 
     if (bpmp_priv->rx_base) {
-        ps_io_unmap(&bpmp_priv->io_ops->io_mapper, bpmp_priv->rx_base, bpmp_shmems[RX_SHMEM].length);
+        ps_io_unmap(&bpmp_priv->io_ops->io_mapper, bpmp_priv->rx_base, bpmp_data.bpmp_shmems[RX_SHMEM].length);
     }
 
     return 0;
 }
 
+static int allocate_register_callback(pmem_region_t pmem, unsigned curr_num, size_t num_regs, void *token)
+{
+    if (curr_num == 1) {
+        bpmp_data.tx_base = ps_pmem_map(bpmp_data.io_ops, pmem, false, PS_MEM_NORMAL);
+        if (!bpmp_data.tx_base) {
+            ZF_LOGE("Failed to map the TX BPMP channel");
+            return -EIO;
+        }
+        bpmp_data.bpmp_shmems[TX_SHMEM] = pmem;
+
+    } else if (curr_num == 2) {
+        bpmp_data.rx_base = ps_pmem_map(bpmp_data.io_ops, pmem, false, PS_MEM_NORMAL);
+        if (!bpmp_data.rx_base) {
+            ZF_LOGE("Failed to map the RX BPMP channel");
+            return -EIO;
+        }
+        bpmp_data.bpmp_shmems[RX_SHMEM] = pmem;
+
+    }
+    return 0;
+}
+
+
 int tx2_bpmp_init(ps_io_ops_t *io_ops, struct tx2_bpmp *bpmp)
 {
     if (!io_ops || !bpmp) {
@@ -185,7 +199,7 @@
     /* Not sure if this is too long or too short. */
     unsigned long timeout = TIMEOUT_THRESHOLD;
 
-    ret = tx2_hsp_init(io_ops, &bpmp_data.hsp);
+    ret = tx2_hsp_init(io_ops, &bpmp_data.hsp, "/tegra-hsp@3c00000");
     if (ret) {
         ZF_LOGE("Failed to initialise the HSP device for BPMP");
         return ret;
@@ -194,19 +208,23 @@
     bpmp_data.io_ops = io_ops;
 
     bpmp_data.hsp_initialised = true;
+    ps_fdt_cookie_t *cookie = NULL;
 
-    bpmp_data.tx_base = ps_pmem_map(io_ops, bpmp_shmems[TX_SHMEM], false, PS_MEM_NORMAL);
-    if (!bpmp_data.tx_base) {
-        ZF_LOGE("Failed to map the TX BPMP channel");
-        ret = -ENOMEM;
-        goto fail;
+    ret = ps_fdt_read_path(&io_ops->io_fdt, &io_ops->malloc_ops, "/bpmp", &cookie);
+    if (ret) {
+        ZF_LOGE("Failed to find %s in device tree", "/bpmp");
+        return -ENODEV;
     }
 
-    bpmp_data.rx_base = ps_pmem_map(io_ops, bpmp_shmems[RX_SHMEM], false, PS_MEM_NORMAL);
-    if (!bpmp_data.rx_base) {
-        ZF_LOGE("Failed to map the RX BPMP channel");
-        ret = -ENOMEM;
-        goto fail;
+    /* walk the registers and allocate them */
+    ret = ps_fdt_walk_registers(&io_ops->io_fdt, cookie, allocate_register_callback, NULL);
+    if (ret) {
+        ZF_LOGE("Failed to walk fdt node");
+        return -ENODEV;
+    }
+    ret = ps_fdt_cleanup_cookie(&io_ops->malloc_ops, cookie);
+    if (ret) {
+        return -ENODEV;
     }
 
     ret = tegra_ivc_init(&bpmp_data.ivc, (unsigned long) bpmp_data.rx_base, (unsigned long) bpmp_data.tx_base,
@@ -229,6 +247,12 @@
         ret = -ETIMEDOUT;
         goto fail;
     }
+    ret = ps_interface_register(&io_ops->interface_registration_ops, TX2_BPMP_INTERFACE,
+                                  bpmp, NULL);
+    if (ret) {
+        ZF_LOGE("Failed to register the BPMP interface");
+        goto fail;
+    }
 
 success:
     bpmp_refcount++;
@@ -237,6 +261,7 @@
     bpmp->call = bpmp_call;
     bpmp->destroy = bpmp_destroy;
     bpmp_initialised = true;
+    /* Register this BPMP interface so that the reset driver can access it */
 
     return 0;
 
@@ -246,3 +271,27 @@
 }
 
 
+
+int tx2_bpmp_init_module(ps_io_ops_t *io_ops, const char *device_path) {
+    struct tx2_bpmp *bpmp;
+    int error = ps_calloc(&io_ops->malloc_ops, 1, sizeof(*bpmp), (void **)&bpmp);
+    if (error) {
+        ZF_LOGE("Failed to allocate struct for tx2_bpmp");
+        return -1;
+    }
+    error =  tx2_bpmp_init(io_ops, bpmp);
+    if (error) {
+        ZF_LOGE("Failed to initialize bpmp driver");
+        return -1;
+    }
+    return 0;
+
+}
+
+static const char*compatible_strings[] = {
+    "nvidia,tegra186-bpmp",
+    NULL
+};
+
+
+PS_DRIVER_MODULE_DEFINE(bpmp, compatible_strings, tx2_bpmp_init_module);
diff --git a/libtx2bpmp/src/hsp.c b/libtx2bpmp/src/hsp.c
index 82b3d4c..7251af9 100644
--- a/libtx2bpmp/src/hsp.c
+++ b/libtx2bpmp/src/hsp.c
@@ -16,6 +16,7 @@
 #include <stdbool.h>
 
 #include <platsupport/pmem.h>
+#include <platsupport/fdt.h>
 #include <tx2bpmp/hsp.h>
 #include <utils/util.h>
 
@@ -36,6 +37,7 @@
     ps_io_ops_t *io_ops;
     void *hsp_base;
     void *doorbell_base;
+    pmem_region_t tx2_hsp_region;
 } tx2_hsp_priv_t;
 
 enum dbell_reg_offset {
@@ -60,11 +62,6 @@
     APE_BIT = BIT(11)
 };
 
-static pmem_region_t tx2_hsp_region = {
-    .type = PMEM_TYPE_DEVICE,
-    .base_addr = TX2_HSP_PADDR,
-    .length = TX2_HSP_SIZE
-};
 
 static bool check_doorbell_id_is_valid(enum tx2_doorbell_id db_id)
 {
@@ -89,7 +86,7 @@
     /* The doorbell base is just an offset from the hsp base, so we only need
      * to deallocate the hsp base */
     if (hsp_priv->hsp_base) {
-        ps_io_unmap(&hsp_priv->io_ops->io_mapper, hsp_priv->hsp_base, tx2_hsp_region.length);
+        ps_io_unmap(&hsp_priv->io_ops->io_mapper, hsp_priv->hsp_base, hsp_priv->tx2_hsp_region.length);
     }
 
     ps_io_ops_t *temp_ops = hsp_priv->io_ops;
@@ -164,7 +161,22 @@
     return (is_pending != 0);
 }
 
-int tx2_hsp_init(ps_io_ops_t *io_ops, tx2_hsp_t *hsp)
+static int allocate_register_callback(pmem_region_t pmem, unsigned curr_num, size_t num_regs, void *token)
+{
+    assert(token != NULL);
+    tx2_hsp_priv_t *hsp_priv = token;
+    /* There's only one register region to map, map it in */
+    assert(num_regs == 1 && curr_num == 0);
+    hsp_priv->hsp_base = ps_pmem_map(hsp_priv->io_ops, pmem, false, PS_MEM_NORMAL);
+    if (hsp_priv->hsp_base == NULL) {
+        return -EIO;
+    }
+    hsp_priv->tx2_hsp_region = pmem;
+    return 0;
+}
+
+
+int tx2_hsp_init(ps_io_ops_t *io_ops, tx2_hsp_t *hsp, const char *path)
 {
     if (!io_ops || !hsp) {
         ZF_LOGE("Arguments are NULL!");
@@ -179,8 +191,22 @@
         ZF_LOGE("Failed to allocate memory for private data for the HSP");
         return -ENOMEM;
     }
+    hsp_priv->io_ops = io_ops;
 
-    hsp_priv->hsp_base = ps_pmem_map(io_ops, tx2_hsp_region, false, PS_MEM_NORMAL);
+    ps_fdt_cookie_t *cookie = NULL;
+    error = ps_fdt_read_path(&io_ops->io_fdt, &io_ops->malloc_ops, path, &cookie);
+    if (error) {
+        ZF_LOGE("Failed to find %s in device tree", path);
+        return -ENODEV;
+    }
+
+    /* walk the registers and allocate them */
+    error = ps_fdt_walk_registers(&io_ops->io_fdt, cookie, allocate_register_callback, hsp_priv);
+    if (error) {
+        ZF_LOGE("Failed to walk fdt node");
+        return -ENODEV;
+    }
+
     if (!hsp_priv->hsp_base) {
         ZF_LOGE("Failed to map tx2 HSP module");
         ZF_LOGF_IF(ps_free(&io_ops->malloc_ops, sizeof(*hsp_priv), hsp_priv),
@@ -188,6 +214,12 @@
         return -ENOMEM;
     }
 
+    error = ps_fdt_cleanup_cookie(&io_ops->malloc_ops, cookie);
+    if (error) {
+        return -ENODEV;
+    }
+
+
     /* Get the base addr of the doorbell
      * Section 14.8.5: All doorbell registers are in a single page, doorbell
      * {db} has a register range starting at DB{db}_BASE = HSP_{inst}_BASE +
@@ -202,7 +234,6 @@
     num_as = (*int_dim_reg >> HSP_INT_DIMENSION_AS_SHIFT) & HSP_INT_DIMENSION_NUM_MASK;
 
     hsp_priv->doorbell_base = hsp_priv->hsp_base + (1 + (num_sm / 2) + num_ss + num_as) * 0x10000;
-    hsp_priv->io_ops = io_ops;
 
     hsp->data = hsp_priv;
     hsp->ring = hsp_doorbell_ring;