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;