aboutsummaryrefslogtreecommitdiff
path: root/product/morello
diff options
context:
space:
mode:
authorAnurag Koul <anurag.koul@arm.com>2020-06-09 15:21:56 +0100
committerjimqui01 <54316584+jimqui01@users.noreply.github.com>2020-09-15 17:03:53 +0100
commit6692e56d78e38aad58af382a3faa5f2d142d7e31 (patch)
treec9bc45d5c17d400106ee6fbe8302b3e1c4295a62 /product/morello
parentd490f22a679365133e11f1db8dfe88ea730f61d4 (diff)
morello: add morello_mhu module
This patch adds a module, morello_mhu, which is based on core mhu module but is modified to work for Morello platform until SCMI agent support is added. Change-Id: I653f515d513011c10e1131b30ee0ba33fd1ef3ff Signed-off-by: Anurag Koul <anurag.koul@arm.com> Co-authored-by: Manoj Kumar <manoj.kumar3@arm.com>
Diffstat (limited to 'product/morello')
-rw-r--r--product/morello/include/morello_mcp_mhu.h16
-rw-r--r--product/morello/module/morello_mhu/include/internal/mhu.h31
-rw-r--r--product/morello/module/morello_mhu/include/mod_mhu.h54
-rw-r--r--product/morello/module/morello_mhu/src/Makefile11
-rw-r--r--product/morello/module/morello_mhu/src/mod_mhu.c264
5 files changed, 376 insertions, 0 deletions
diff --git a/product/morello/include/morello_mcp_mhu.h b/product/morello/include/morello_mcp_mhu.h
new file mode 100644
index 00000000..baafedb6
--- /dev/null
+++ b/product/morello/include/morello_mcp_mhu.h
@@ -0,0 +1,16 @@
+/*
+ * Arm SCP/MCP Software
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MORELLO_MCP_MHU_H
+#define MORELLO_MCP_MHU_H
+
+enum mcp_morello_mhu_device_idx {
+ MORELLO_MHU_DEVICE_IDX_S_SCP,
+ MORELLO_MHU_DEVICE_IDX_COUNT,
+};
+
+#endif /* MORELLO_MCP_MHU_H */
diff --git a/product/morello/module/morello_mhu/include/internal/mhu.h b/product/morello/module/morello_mhu/include/internal/mhu.h
new file mode 100644
index 00000000..ec9fe2e7
--- /dev/null
+++ b/product/morello/module/morello_mhu/include/internal/mhu.h
@@ -0,0 +1,31 @@
+/*
+ * Arm SCP/MCP Software
+ * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef INTERNAL_MHU_H
+#define INTERNAL_MHU_H
+
+#include <mod_mhu.h>
+
+#include <fwk_macros.h>
+
+#include <stdint.h>
+
+/*!
+ * \brief MHU Register Definitions
+ */
+struct mhu_reg {
+ /*! Status register */
+ FWK_R uint32_t STAT;
+ uint32_t RESERVED0;
+ /*! Set register (sets the value of STAT) */
+ FWK_W uint32_t SET;
+ uint32_t RESERVED1;
+ /*! Clear register (clears STAT) */
+ FWK_W uint32_t CLEAR;
+};
+
+#endif /* INTERNAL_MHU_H */
diff --git a/product/morello/module/morello_mhu/include/mod_mhu.h b/product/morello/module/morello_mhu/include/mod_mhu.h
new file mode 100644
index 00000000..8b74e4a6
--- /dev/null
+++ b/product/morello/module/morello_mhu/include/mod_mhu.h
@@ -0,0 +1,54 @@
+/*
+ * Arm SCP/MCP Software
+ * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Description:
+ * Message Handling Unit (MHU) Device Driver.
+ */
+
+#ifndef MOD_MHU_H
+#define MOD_MHU_H
+
+#include <fwk_macros.h>
+
+#include <stdint.h>
+
+/*!
+ * \addtogroup GroupMORELLOModule MORELLO Product Modules
+ * @{
+ */
+
+/*!
+ * \defgroup GroupMORELLOMHU MORELLO Message Handling Unit (MHU) Driver
+ * @{
+ */
+
+/*!
+ * \brief MHU device
+ *
+ * \details Abstract representation of a bidirectional MHU device that consists
+ * of a single receive interrupt line and a pair of register sets, one for
+ * each direction of communication.
+ */
+struct mod_mhu_device_config {
+ /*! IRQ number of the receive interrupt line */
+ unsigned int irq;
+
+ /*! Base address of the registers of the incoming MHU */
+ uintptr_t in;
+
+ /*! Base address of the registers of the outgoing MHU */
+ uintptr_t out;
+};
+
+/*!
+ * @}
+ */
+
+/*!
+ * @}
+ */
+
+#endif /* MOD_MHU_H */
diff --git a/product/morello/module/morello_mhu/src/Makefile b/product/morello/module/morello_mhu/src/Makefile
new file mode 100644
index 00000000..356bc110
--- /dev/null
+++ b/product/morello/module/morello_mhu/src/Makefile
@@ -0,0 +1,11 @@
+#
+# Arm SCP/MCP Software
+# Copyright (c) 2017-2020, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BS_LIB_NAME := MORELLO MHU
+BS_LIB_SOURCES := mod_mhu.c
+
+include $(BS_DIR)/lib.mk
diff --git a/product/morello/module/morello_mhu/src/mod_mhu.c b/product/morello/module/morello_mhu/src/mod_mhu.c
new file mode 100644
index 00000000..e811e9cf
--- /dev/null
+++ b/product/morello/module/morello_mhu/src/mod_mhu.c
@@ -0,0 +1,264 @@
+/*
+ * Arm SCP/MCP Software
+ * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Description:
+ * Message Handling Unit (MHU) Device Driver.
+ */
+
+#include <internal/mhu.h>
+
+#include <mod_mhu.h>
+#include <mod_smt.h>
+
+#include <fwk_id.h>
+#include <fwk_interrupt.h>
+#include <fwk_mm.h>
+#include <fwk_module.h>
+#include <fwk_module_idx.h>
+#include <fwk_status.h>
+
+#include <stddef.h>
+#include <stdint.h>
+
+/*
+ * Maximum number of slots per MHU device. The maximum number of slots is 31 and
+ * not 32 because bit [31] in the MHU STAT register is reserved in secure MHUs
+ * for indicating that a non-secure access attempt occurred. This reservation
+ * also applies to non-secure MHUs for consistency, though the bit is unused.
+ */
+#define MHU_SLOT_COUNT_MAX 31
+
+struct mhu_smt_channel {
+ fwk_id_t id;
+ struct mod_smt_driver_input_api *api;
+};
+
+/* MHU device context */
+struct mhu_device_ctx {
+ /* Pointer to the device configuration */
+ const struct mod_mhu_device_config *config;
+
+ /* Number of slots (represented by sub-elements) */
+ unsigned int slot_count;
+
+ /* Mask of slots that are bound to an SMT channel */
+ uint32_t bound_slots;
+
+ /* Table of SMT channels bound to the device */
+ struct mhu_smt_channel *smt_channel_table;
+};
+
+/* MHU context */
+struct mhu_ctx {
+ /* Table of device contexts */
+ struct mhu_device_ctx *device_ctx_table;
+
+ /* Number of devices in the device context table*/
+ unsigned int device_count;
+};
+
+static struct mhu_ctx mhu_ctx;
+
+static void mhu_isr(void)
+{
+ int status;
+ unsigned int interrupt;
+ unsigned int device_idx;
+ struct mhu_device_ctx *device_ctx;
+ struct mhu_reg *reg;
+ unsigned int slot;
+ struct mhu_smt_channel *smt_channel;
+
+ status = fwk_interrupt_get_current(&interrupt);
+ if (status != FWK_SUCCESS)
+ return;
+
+ for (device_idx = 0; device_idx < mhu_ctx.device_count; device_idx++) {
+ device_ctx = &mhu_ctx.device_ctx_table[device_idx];
+ if (device_ctx->config->irq == interrupt)
+ break;
+ }
+
+ if (device_idx >= mhu_ctx.device_count)
+ return;
+
+ reg = (struct mhu_reg *)device_ctx->config->in;
+
+ /* Loop over all the slots */
+ while (reg->STAT != 0) {
+ slot = __builtin_ctz(reg->STAT);
+
+ /*
+ * If the slot is bound to an SMT channel, signal the message to the
+ * SMT channel.
+ */
+ if (device_ctx->bound_slots & (1 << slot)) {
+ smt_channel = &device_ctx->smt_channel_table[slot];
+ smt_channel->api->signal_message(smt_channel->id);
+ }
+
+ /* Acknowledge the interrupt */
+ reg->CLEAR = 1 << slot;
+ }
+}
+
+/*
+ * SMT module driver API
+ */
+
+static int raise_interrupt(fwk_id_t slot_id)
+{
+ struct mhu_device_ctx *device_ctx;
+ unsigned int slot;
+ struct mhu_reg *reg;
+
+ device_ctx = &mhu_ctx.device_ctx_table[fwk_id_get_element_idx(slot_id)];
+ slot = fwk_id_get_sub_element_idx(slot_id);
+ reg = (struct mhu_reg *)device_ctx->config->out;
+
+ reg->SET |= (1 << slot);
+
+ return FWK_SUCCESS;
+}
+
+const struct mod_smt_driver_api mhu_mod_smt_driver_api = {
+ .raise_interrupt = raise_interrupt,
+};
+
+/*
+ * Framework handlers
+ */
+
+static int mhu_init(
+ fwk_id_t module_id,
+ unsigned int device_count,
+ const void *unused)
+{
+ if (device_count == 0)
+ return FWK_E_PARAM;
+
+ mhu_ctx.device_ctx_table =
+ fwk_mm_calloc(device_count, sizeof(mhu_ctx.device_ctx_table[0]));
+ if (mhu_ctx.device_ctx_table == NULL)
+ return FWK_E_NOMEM;
+
+ mhu_ctx.device_count = device_count;
+
+ return FWK_SUCCESS;
+}
+
+static int mhu_device_init(
+ fwk_id_t device_id,
+ unsigned int slot_count,
+ const void *data)
+{
+ struct mod_mhu_device_config *config = (struct mod_mhu_device_config *)data;
+ struct mhu_device_ctx *device_ctx;
+
+ if ((config->in == 0) || (config->out == 0))
+ return FWK_E_PARAM;
+
+ device_ctx = &mhu_ctx.device_ctx_table[fwk_id_get_element_idx(device_id)];
+
+ device_ctx->smt_channel_table =
+ fwk_mm_calloc(slot_count, sizeof(device_ctx->smt_channel_table[0]));
+ if (device_ctx->smt_channel_table == NULL)
+ return FWK_E_NOMEM;
+
+ device_ctx->config = config;
+ device_ctx->slot_count = slot_count;
+
+ return FWK_SUCCESS;
+}
+
+static int mhu_bind(fwk_id_t id, unsigned int round)
+{
+ int status;
+ struct mhu_device_ctx *device_ctx;
+ unsigned int slot;
+ struct mhu_smt_channel *smt_channel;
+
+ if ((round == 1) && fwk_id_is_type(id, FWK_ID_TYPE_ELEMENT)) {
+ device_ctx = &mhu_ctx.device_ctx_table[fwk_id_get_element_idx(id)];
+
+ for (slot = 0; slot < MHU_SLOT_COUNT_MAX; slot++) {
+ if (!(device_ctx->bound_slots & (1 << slot)))
+ continue;
+
+ smt_channel = &device_ctx->smt_channel_table[slot];
+
+ status = fwk_module_bind(
+ smt_channel->id,
+ FWK_ID_API(
+ FWK_MODULE_IDX_MORELLO_SMT, MOD_SMT_API_IDX_DRIVER_INPUT),
+ &smt_channel->api);
+ if (status != FWK_SUCCESS)
+ return status;
+ }
+ }
+
+ return FWK_SUCCESS;
+}
+
+static int mhu_process_bind_request(
+ fwk_id_t source_id,
+ fwk_id_t target_id,
+ fwk_id_t api_id,
+ const void **api)
+{
+ struct mhu_device_ctx *device_ctx;
+ unsigned int slot;
+
+ if (!fwk_id_is_type(target_id, FWK_ID_TYPE_SUB_ELEMENT))
+ return FWK_E_ACCESS;
+
+ device_ctx = &mhu_ctx.device_ctx_table[fwk_id_get_element_idx(target_id)];
+ slot = fwk_id_get_sub_element_idx(target_id);
+
+ if (device_ctx->bound_slots & (1 << slot))
+ return FWK_E_ACCESS;
+
+ device_ctx->smt_channel_table[slot].id = source_id;
+ device_ctx->bound_slots |= 1 << slot;
+
+ *api = &mhu_mod_smt_driver_api;
+
+ return FWK_SUCCESS;
+}
+
+static int mhu_start(fwk_id_t id)
+{
+ int status;
+ struct mhu_device_ctx *device_ctx;
+
+ if (fwk_id_get_type(id) == FWK_ID_TYPE_MODULE)
+ return FWK_SUCCESS;
+
+ device_ctx = &mhu_ctx.device_ctx_table[fwk_id_get_element_idx(id)];
+
+ if (device_ctx->bound_slots != 0) {
+ status = fwk_interrupt_set_isr(device_ctx->config->irq, &mhu_isr);
+ if (status != FWK_SUCCESS)
+ return status;
+ status = fwk_interrupt_enable(device_ctx->config->irq);
+ if (status != FWK_SUCCESS)
+ return status;
+ }
+
+ return FWK_SUCCESS;
+}
+
+/* MHU module definition */
+const struct fwk_module module_morello_mhu = {
+ .name = "MORELLO MHU",
+ .type = FWK_MODULE_TYPE_DRIVER,
+ .api_count = 1,
+ .init = mhu_init,
+ .element_init = mhu_device_init,
+ .bind = mhu_bind,
+ .start = mhu_start,
+ .process_bind_request = mhu_process_bind_request,
+};