libtx2bpmp: Change HSP public interface

Following from the previous BPMP interface commit, this also changes the
HSP interface so that it makes it easier to integrate with the interface
registration service.
diff --git a/libtx2bpmp/include/tx2bpmp/hsp.h b/libtx2bpmp/include/tx2bpmp/hsp.h
index 2c524d3..7533a60 100644
--- a/libtx2bpmp/include/tx2bpmp/hsp.h
+++ b/libtx2bpmp/include/tx2bpmp/hsp.h
@@ -13,10 +13,17 @@
 #pragma once
 
 #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; }                                       \
+        if (!hsp->function) { ZF_LOGE(#function " function is not implemented"); return -ENOSYS; }  \
+    } while(0)
+
 /*
  * This is a very basic driver implementation of the TX2 HSP mechanisms. So
  * far, this only supports the doorbell functionality of the HSP mechanisms.
@@ -45,8 +52,10 @@
 };
 
 typedef struct tx2_hsp {
-    void *hsp_base;
-    void *doorbell_base;
+    void *data;
+    int (*ring)(void *data, enum tx2_doorbell_id db_id);
+    int (*check)(void *data, enum tx2_doorbell_id db_id);
+    int (*destroy)(void *data);
 } tx2_hsp_t;
 
 /*
@@ -62,12 +71,15 @@
 /*
  * Destroys an initialised TX2 HSP interface.
  *
- * @param io_ops The same IO ops interface that was used to initialise the HSP interface.
  * @param hsp Initialised HSP interface that will be destroyed.
  *
  * @return 0 on success, otherwise an error code.
  */
-int tx2_hsp_destroy(ps_io_ops_t *io_ops, tx2_hsp_t *hsp);
+static inline int tx2_hsp_destroy(tx2_hsp_t *hsp)
+{
+    __HSP_CHECK_ARGS(destroy);
+    return hsp->destroy(hsp->data);
+}
 
 /*
  * Rings the doorbell of a specific device module.
@@ -77,7 +89,11 @@
  *
  * @return 0 on success, otherwise an error code.
  */
-int tx2_hsp_doorbell_ring(tx2_hsp_t *hsp, enum tx2_doorbell_id db_id);
+static inline int tx2_hsp_doorbell_ring(tx2_hsp_t *hsp, enum tx2_doorbell_id db_id)
+{
+    __HSP_CHECK_ARGS(ring);
+    return hsp->ring(hsp->data, db_id);
+}
 
 /*
  * Checks if a specific device module has rung our doorbell.
@@ -87,4 +103,8 @@
  *
  * @return 0 on success, otherwise an error code.
  */
-int tx2_hsp_doorbell_check(tx2_hsp_t *hsp, enum tx2_doorbell_id db_id);
+static inline int tx2_hsp_doorbell_check(tx2_hsp_t *hsp, enum tx2_doorbell_id db_id)
+{
+    __HSP_CHECK_ARGS(check);
+    return hsp->check(hsp->check, db_id);
+}
diff --git a/libtx2bpmp/src/hsp.c b/libtx2bpmp/src/hsp.c
index 3735f76..82b3d4c 100644
--- a/libtx2bpmp/src/hsp.c
+++ b/libtx2bpmp/src/hsp.c
@@ -32,6 +32,12 @@
 #define HSP_BITMAP_TZ_SECURE_SHFIT 0
 #define HSP_BITMAP_TZ_NONSECURE_SHIFT 16
 
+typedef struct tx2_hsp_priv {
+    ps_io_ops_t *io_ops;
+    void *hsp_base;
+    void *doorbell_base;
+} tx2_hsp_priv_t;
+
 enum dbell_reg_offset {
     DBELL_TRIGGER = 0x0,
     DBELL_ENABLE = 0x4,
@@ -68,96 +74,62 @@
     return false;
 }
 
-static uint32_t *tx2_hsp_get_doorbell_register(tx2_hsp_t *hsp, enum tx2_doorbell_id db_id,
-                                               enum dbell_reg_offset offset)
+static uint32_t *hsp_get_doorbell_register(tx2_hsp_priv_t *hsp, enum tx2_doorbell_id db_id,
+                                           enum dbell_reg_offset offset)
 {
     assert(hsp);
     assert(DBELL_TRIGGER <= offset && offset <= DBELL_PENDING);
     return hsp->doorbell_base + db_id * HSP_DOORBELL_BLOCK_STRIDE + offset;
 }
 
-int tx2_hsp_init(ps_io_ops_t *io_ops, tx2_hsp_t *hsp)
+static int hsp_destroy(void *data)
 {
-    if (!io_ops || !hsp) {
-        ZF_LOGE("Arguments are NULL!");
-        return -EINVAL;
+    tx2_hsp_priv_t *hsp_priv = data;
+
+    /* 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);
     }
 
-    hsp->hsp_base = ps_pmem_map(io_ops, tx2_hsp_region, false, PS_MEM_NORMAL);
-    if (!hsp->hsp_base) {
-        ZF_LOGE("Failed to map tx2 HSP module");
-        return -ENOMEM;
-    }
+    ps_io_ops_t *temp_ops = hsp_priv->io_ops;
 
-    /* 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 +
-     * (1+ nSM/2 + nSS + nAS) * 64 KiB + {db} * 0x100. */
-
-    int num_sm = 0, num_ss = 0, num_as = 0;
-
-    uint32_t *int_dim_reg = hsp->hsp_base + HSP_INT_DIMENSION_OFFSET;
-
-    num_sm = (*int_dim_reg >> HSP_INT_DIMENSION_SM_SHIFT) & HSP_INT_DIMENSION_NUM_MASK;
-    num_ss = (*int_dim_reg >> HSP_INT_DIMENSION_SS_SHIFT) & HSP_INT_DIMENSION_NUM_MASK;
-    num_as = (*int_dim_reg >> HSP_INT_DIMENSION_AS_SHIFT) & HSP_INT_DIMENSION_NUM_MASK;
-
-    hsp->doorbell_base = hsp->hsp_base + (1 + (num_sm / 2) + num_ss + num_as) * 0x10000;
+    ZF_LOGF_IF(ps_free(&temp_ops->malloc_ops, sizeof(*hsp_priv), hsp_priv),
+               "Failed to de-allocate the private data for HSP");
 
     return 0;
 }
 
-int tx2_hsp_destroy(ps_io_ops_t *io_ops, tx2_hsp_t *hsp)
+static int hsp_doorbell_ring(void *data, enum tx2_doorbell_id db_id)
 {
-    if (!io_ops || !hsp) {
-        ZF_LOGE("Arguments are NULL!");
-        return -EINVAL;
-    }
-
-    if (hsp->hsp_base) {
-        ps_io_unmap(&io_ops->io_mapper, hsp->hsp_base, tx2_hsp_region.length);
-    }
-
-    return 0;
-}
-
-int tx2_hsp_doorbell_ring(tx2_hsp_t *hsp, enum tx2_doorbell_id db_id)
-{
-    if (!hsp) {
-        ZF_LOGE("Arguments are NULL!");
-        return -EINVAL;
-    }
-
     if (!check_doorbell_id_is_valid(db_id)) {
         ZF_LOGE("Invalid doorbell ID!");
         return -EINVAL;
     }
 
+    tx2_hsp_priv_t *hsp_priv = data;
 
     /* Write any value to the trigger register to 'ring' the doorbell */
-    uint32_t *trigger_reg = tx2_hsp_get_doorbell_register(hsp, db_id, DBELL_TRIGGER);
+    uint32_t *trigger_reg = hsp_get_doorbell_register(hsp_priv, db_id, DBELL_TRIGGER);
     assert(trigger_reg);
     *trigger_reg = 1;
 
     return 0;
 }
 
-int tx2_hsp_doorbell_check(tx2_hsp_t *hsp, enum tx2_doorbell_id db_id)
+static int hsp_doorbell_check(void *data, enum tx2_doorbell_id db_id)
 {
-    if (!hsp) {
-        ZF_LOGE("Arguments are NULL!");
-        return -EINVAL;
-    }
-
     if (!check_doorbell_id_is_valid(db_id)) {
         ZF_LOGE("Invalid doorbell ID!");
         return -EINVAL;
     }
 
+    tx2_hsp_priv_t *hsp_priv = data;
+
     /* Checking if the doorbell has been 'rung' requires checking for proper
      * bit in the bitfield. The bitfield is also split into TrustZone secure
      * and TZ non-secure. Refer to Figure 75 in Section 14.8.5 for further details. */
-    uint32_t *pending_reg = tx2_hsp_get_doorbell_register(hsp, db_id, DBELL_PENDING);
+    uint32_t *pending_reg = hsp_get_doorbell_register(hsp_priv, db_id, DBELL_PENDING);
 
     enum dbell_bitmap_offset bitmap_offset;
     switch (db_id) {
@@ -191,3 +163,51 @@
 
     return (is_pending != 0);
 }
+
+int tx2_hsp_init(ps_io_ops_t *io_ops, tx2_hsp_t *hsp)
+{
+    if (!io_ops || !hsp) {
+        ZF_LOGE("Arguments are NULL!");
+        return -EINVAL;
+    }
+
+    int error = 0;
+
+    tx2_hsp_priv_t *hsp_priv = NULL;
+    error = ps_calloc(&io_ops->malloc_ops, 1, sizeof(*hsp_priv), (void **) &hsp_priv);
+    if (error) {
+        ZF_LOGE("Failed to allocate memory for private data for the HSP");
+        return -ENOMEM;
+    }
+
+    hsp_priv->hsp_base = ps_pmem_map(io_ops, tx2_hsp_region, false, PS_MEM_NORMAL);
+    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),
+                   "Failed to clean-up after a failed initialisation for the HSP");
+        return -ENOMEM;
+    }
+
+    /* 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 +
+     * (1+ nSM/2 + nSS + nAS) * 64 KiB + {db} * 0x100. */
+
+    int num_sm = 0, num_ss = 0, num_as = 0;
+
+    uint32_t *int_dim_reg = hsp_priv->hsp_base + HSP_INT_DIMENSION_OFFSET;
+
+    num_sm = (*int_dim_reg >> HSP_INT_DIMENSION_SM_SHIFT) & HSP_INT_DIMENSION_NUM_MASK;
+    num_ss = (*int_dim_reg >> HSP_INT_DIMENSION_SS_SHIFT) & HSP_INT_DIMENSION_NUM_MASK;
+    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;
+    hsp->check = hsp_doorbell_check;
+    hsp->destroy = hsp_destroy;
+
+    return 0;
+}