From 3064c5411946bceaa71e912920bfed3a9991f32e Mon Sep 17 00:00:00 2001 From: Pedro Custodio Date: Tue, 14 Aug 2018 16:28:44 +0100 Subject: module: MHUv2 support Change-Id: I3335f0511b2bb00811ebb317273ff693b1dc903b Signed-off-by: Elieva Pignat Signed-off-by: Chris Kay --- module/mhu2/include/mod_mhu2.h | 66 ++++++++++ module/mhu2/src/Makefile | 11 ++ module/mhu2/src/mhu2.h | 67 ++++++++++ module/mhu2/src/mod_mhu2.c | 292 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 436 insertions(+) create mode 100644 module/mhu2/include/mod_mhu2.h create mode 100644 module/mhu2/src/Makefile create mode 100644 module/mhu2/src/mhu2.h create mode 100644 module/mhu2/src/mod_mhu2.c diff --git a/module/mhu2/include/mod_mhu2.h b/module/mhu2/include/mod_mhu2.h new file mode 100644 index 00000000..3f87e780 --- /dev/null +++ b/module/mhu2/include/mod_mhu2.h @@ -0,0 +1,66 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2017-2019, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * Message Handling Unit (MHU) v2 Device Driver. + */ + +#ifndef MOD_MHU2_H +#define MOD_MHU2_H + +#include +#include + +/*! + * \addtogroup GroupModules Modules + * @{ + */ + +/*! + * \defgroup GroupMHUv2 Message Handling Unit (MHU) v2 Driver + * @{ + */ + +/*! + * \brief MHU v2 api indicies + */ +enum mod_mhu2_api_idx { + /*! SMT driver API */ + MOD_MHU2_API_IDX_SMT_DRIVER, + /*! Number of APIs */ + MOD_MHU2_API_IDX_COUNT, +}; + +/*! + * \brief MHU v2 device + * + * \details Abstract representation of a bidirectional MHU channel that consists + * of a single receive interrupt line and a pair of register sets, one for + * each direction of communication. + */ +struct mod_mhu2_channel_config { + /*! IRQ number of the receive interrupt line */ + unsigned int irq; + + /*! Base address of the registers of the incoming MHU */ + uintptr_t recv; + + /*! Base address of the registers of the outgoing MHU */ + uintptr_t send; + + /*! Channel number */ + unsigned int channel; +}; + +/*! + * @} + */ + +/*! + * @} + */ + +#endif /* MOD_MHU2_H */ diff --git a/module/mhu2/src/Makefile b/module/mhu2/src/Makefile new file mode 100644 index 00000000..0e44a3cc --- /dev/null +++ b/module/mhu2/src/Makefile @@ -0,0 +1,11 @@ +# +# Arm SCP/MCP Software +# Copyright (c) 2017-2019, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +BS_LIB_NAME := MHU2 +BS_LIB_SOURCES := mod_mhu2.c + +include $(BS_DIR)/lib.mk diff --git a/module/mhu2/src/mhu2.h b/module/mhu2/src/mhu2.h new file mode 100644 index 00000000..38bbec03 --- /dev/null +++ b/module/mhu2/src/mhu2.h @@ -0,0 +1,67 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2017-2019, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MHU2_H +#define MHU2_H + +#include +#include + +#define CHANNEL_MAX 124 + +struct mhu2_id_reg { + FWK_R uint32_t PID4; + uint8_t RESERVED1[0x10 - 0x4]; + FWK_R uint32_t PID0; + FWK_R uint32_t PID1; + FWK_R uint32_t PID2; + FWK_R uint32_t PID3; + FWK_R uint32_t COMPID0; + FWK_R uint32_t COMPID1; + FWK_R uint32_t COMPID2; + FWK_R uint32_t COMPID3; +}; + +struct mhu2_send_channel_reg { + FWK_R uint32_t STAT; + uint8_t RESERVED0[0xC - 0x4]; + FWK_W uint32_t STAT_SET; + uint8_t RESERVED1[0x20 - 0x10]; +}; + +struct mhu2_send_reg { + struct mhu2_send_channel_reg channel[CHANNEL_MAX]; + FWK_R uint32_t MSG_NO_CAP; + FWK_RW uint32_t RESP_CFG; + FWK_RW uint32_t ACCESS_REQUEST; + FWK_R uint32_t ACCESS_READY; + FWK_R uint32_t INT_ACCESS_STAT; + FWK_W uint32_t INT_ACCESS_CLR; + FWK_W uint32_t INT_ACCESS_EN; + uint8_t RESERVED0[0xFD0 - 0xF9C]; + struct mhu2_id_reg id; +}; + +struct mhu2_recv_channel_reg { + FWK_R uint32_t STAT; + FWK_R uint32_t STAT_PEND; + FWK_W uint32_t STAT_CLEAR; + uint8_t RESERVED0[0x10 - 0x0C]; + FWK_R uint32_t MASK; + FWK_W uint32_t MASK_SET; + FWK_W uint32_t MASK_CLEAR; + uint8_t RESERVED1[0x20 - 0x1C]; +}; + +struct mhu2_recv_reg { + struct mhu2_recv_channel_reg channel[CHANNEL_MAX]; + FWK_R uint32_t MSG_NO_CAP; + uint8_t RESERVED0[0xFD0 - 0xF84]; + struct mhu2_id_reg id; +}; + +#endif /* MHU2_H */ diff --git a/module/mhu2/src/mod_mhu2.c b/module/mhu2/src/mod_mhu2.c new file mode 100644 index 00000000..8e776c2f --- /dev/null +++ b/module/mhu2/src/mod_mhu2.c @@ -0,0 +1,292 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2017-2019, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * Message Handling Unit (MHU) v2 Device Driver. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MHU_SLOT_COUNT_MAX 32 + +struct mhu2_smt_channel { + fwk_id_t id; + const struct mod_smt_driver_input_api *api; +}; + +/* MHU channel context */ +struct mhu2_channel_ctx { + /* Pointer to the channel configuration */ + const struct mod_mhu2_channel_config *config; + + /* Pointer to send register set */ + struct mhu2_send_reg *send; + + /* Pointers to channel-specific register sets */ + struct mhu2_send_channel_reg *send_channel; + struct mhu2_recv_channel_reg *recv_channel; + + /* 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 channel */ + struct mhu2_smt_channel *smt_channel_table; +}; + +/* MHU v2 context */ +static struct mhu2_ctx { + /* Table of channel contexts */ + struct mhu2_channel_ctx *channel_ctx_table; + + /* Number of channels in the channel context table*/ + unsigned int channel_count; +} ctx; + +static void mhu2_isr(uintptr_t ctx_param) +{ + struct mhu2_channel_ctx *channel_ctx = (struct mhu2_channel_ctx *)ctx_param; + unsigned int slot; + struct mhu2_smt_channel *smt_channel; + + assert(channel_ctx != NULL); + + while (channel_ctx->recv_channel->STAT != 0) { + slot = __builtin_ctz(channel_ctx->recv_channel->STAT); + + /* + * If the slot is bound to an SMT channel, signal the message to the + * SMT channel. + */ + if (channel_ctx->bound_slots & (1 << slot)) { + smt_channel = &channel_ctx->smt_channel_table[slot]; + smt_channel->api->signal_message(smt_channel->id); + } + + /* Acknowledge the interrupt */ + channel_ctx->recv_channel->STAT_CLEAR = 1 << slot; + } +} + +/* + * SMT module driver API + */ + +static int raise_interrupt(fwk_id_t slot_id) +{ + int status; + unsigned int slot; + struct mhu2_channel_ctx *channel_ctx; + struct mhu2_send_reg *send; + + status = fwk_module_check_call(slot_id); + if (status != FWK_SUCCESS) + return status; + + channel_ctx = &ctx.channel_ctx_table[fwk_id_get_element_idx(slot_id)]; + slot = fwk_id_get_sub_element_idx(slot_id); + send = channel_ctx->send; + + /* Turn on receiver */ + send->ACCESS_REQUEST = 1; + while (send->ACCESS_READY != 1) + continue; + + channel_ctx->send_channel->STAT_SET |= (1 << slot); + + /* Signal that the receiver is no longer needed */ + send->ACCESS_REQUEST = 0; + + return FWK_SUCCESS; +} + +static const struct mod_smt_driver_api mhu2_mod_smt_driver_api = { + .raise_interrupt = raise_interrupt, +}; + +/* + * Framework handlers + */ + +static int mhu2_init(fwk_id_t module_id, + unsigned int channel_count, + const void *unused) +{ + if (channel_count == 0) { + /* There must be at least 1 mhu channel */ + assert(false); + return FWK_E_PARAM; + } + + ctx.channel_ctx_table = fwk_mm_calloc(channel_count, + sizeof(ctx.channel_ctx_table[0])); + if (ctx.channel_ctx_table == NULL) { + /* Unable to allocate memory for channel context table */ + assert(false); + return FWK_E_NOMEM; + } + + ctx.channel_count = channel_count; + + return FWK_SUCCESS; +} + +static int mhu2_channel_init(fwk_id_t channel_id, + unsigned int slot_count, + const void *data) +{ + const struct mod_mhu2_channel_config *config = data; + struct mhu2_channel_ctx *channel_ctx; + struct mhu2_recv_reg *recv_reg; + + if ((config == NULL) || (config->recv == 0) || (config->send == 0)) { + assert(false); + return FWK_E_DATA; + } + + channel_ctx = &ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)]; + channel_ctx->send = (struct mhu2_send_reg *)config->send; + + if (config->channel >= channel_ctx->send->MSG_NO_CAP) { + assert(false); + return FWK_E_DATA; + } + + channel_ctx->config = config; + channel_ctx->slot_count = slot_count; + channel_ctx->send_channel = &channel_ctx->send->channel[config->channel]; + recv_reg = (struct mhu2_recv_reg *)config->recv; + channel_ctx->recv_channel = &recv_reg->channel[config->channel]; + + channel_ctx->smt_channel_table = + fwk_mm_calloc(slot_count, sizeof(channel_ctx->smt_channel_table[0])); + if (channel_ctx->smt_channel_table == NULL) { + assert(false); + return FWK_E_NOMEM; + } + + return FWK_SUCCESS; +} + +static int mhu2_bind(fwk_id_t id, unsigned int round) +{ + int status; + struct mhu2_channel_ctx *channel_ctx; + unsigned int slot; + struct mhu2_smt_channel *smt_channel; + + if ((round == 1) && fwk_id_is_type(id, FWK_ID_TYPE_ELEMENT)) { + channel_ctx = &ctx.channel_ctx_table[fwk_id_get_element_idx(id)]; + + for (slot = 0; slot < MHU_SLOT_COUNT_MAX; slot++) { + if (!(channel_ctx->bound_slots & (1 << slot))) + continue; + + smt_channel = &channel_ctx->smt_channel_table[slot]; + + status = fwk_module_bind(smt_channel->id, + FWK_ID_API(FWK_MODULE_IDX_SMT, + MOD_SMT_API_IDX_DRIVER_INPUT), + &smt_channel->api); + if (status != FWK_SUCCESS) { + /* Unable to bind back to SMT channel */ + assert(false); + return status; + } + } + } + + return FWK_SUCCESS; +} + +static int mhu2_process_bind_request(fwk_id_t source_id, + fwk_id_t target_id, + fwk_id_t api_id, + const void **api) +{ + struct mhu2_channel_ctx *channel_ctx; + unsigned int slot; + + if (!fwk_id_is_type(target_id, FWK_ID_TYPE_SUB_ELEMENT)) { + /* + * Something tried to bind to the module or an element. Only binding to + * a slot (sub-element) is allowed. + */ + assert(false); + return FWK_E_ACCESS; + } + + channel_ctx = &ctx.channel_ctx_table[fwk_id_get_element_idx(target_id)]; + slot = fwk_id_get_sub_element_idx(target_id); + + if (channel_ctx->bound_slots & (1 << slot)) { + /* Something tried to bind to a slot that has already been bound to */ + assert(false); + return FWK_E_ACCESS; + } + + channel_ctx->smt_channel_table[slot].id = source_id; + channel_ctx->bound_slots |= 1 << slot; + + *api = &mhu2_mod_smt_driver_api; + + return FWK_SUCCESS; +} + +static int mhu2_start(fwk_id_t id) +{ + int status; + struct mhu2_channel_ctx *channel_ctx; + + if (fwk_id_get_type(id) == FWK_ID_TYPE_MODULE) + return FWK_SUCCESS; + + channel_ctx = &ctx.channel_ctx_table[fwk_id_get_element_idx(id)]; + + if (channel_ctx->bound_slots != 0) { + status = fwk_interrupt_set_isr_param(channel_ctx->config->irq, + &mhu2_isr, + (uintptr_t)channel_ctx); + if (status != FWK_SUCCESS) { + /* Failed to set isr */ + assert(false); + return status; + } + status = fwk_interrupt_enable(channel_ctx->config->irq); + if (status != FWK_SUCCESS) { + /* Failed to enable isr */ + assert(false); + return status; + } + } + + return FWK_SUCCESS; +} + +/* MHU v2 module definition */ +const struct fwk_module module_mhu2 = { + .name = "MHU2", + .type = FWK_MODULE_TYPE_DRIVER, + .api_count = MOD_MHU2_API_IDX_COUNT, + .init = mhu2_init, + .element_init = mhu2_channel_init, + .bind = mhu2_bind, + .start = mhu2_start, + .process_bind_request = mhu2_process_bind_request, +}; -- cgit v1.2.3