diff options
author | Tushar Khandelwal <tushar.khandelwal@arm.com> | 2019-07-05 16:04:42 +0100 |
---|---|---|
committer | Tushar Khandelwal <tushar.khandelwal@arm.com> | 2019-09-04 11:37:10 +0100 |
commit | 6f4663c671aed2ff2d88801c1cccd94de4339ead (patch) | |
tree | 5f7b1dbff5068d53179dafe6233699c3994603f6 | |
parent | ad1b1bb3577cbaa50e70b02083dd8c14eee39157 (diff) |
add mailbox handling unit controller module
Change-Id: I39790ac981e44944011b60d3eb6dacff1ea37c60
Signed-off-by: Tushar Khandelwal <tushar.khandelwal@arm.com>
-rw-r--r-- | framework/src/Makefile | 2 | ||||
-rwxr-xr-x | product/corstone-700/firmware/config_mhuv2.c | 71 | ||||
-rw-r--r-- | product/corstone-700/firmware/firmware.mk | 6 | ||||
-rwxr-xr-x | product/corstone-700/module/mhuv2/include/mod_mhuv2.h | 98 | ||||
-rwxr-xr-x | product/corstone-700/module/mhuv2/src/Makefile | 10 | ||||
-rwxr-xr-x | product/corstone-700/module/mhuv2/src/mod_mhuv2.c | 256 |
6 files changed, 441 insertions, 2 deletions
diff --git a/framework/src/Makefile b/framework/src/Makefile index 78a5175..c3df936 100644 --- a/framework/src/Makefile +++ b/framework/src/Makefile @@ -26,6 +26,8 @@ endif BS_LIB_INCLUDES += $(ARCH_DIR)/include BS_LIB_INCLUDES += $(FWK_DIR)/include +BS_LIB_INCLUDES += $(FWK_DIR)/../module/mhuv2/include BS_LIB_INCLUDES += $(FWK_DIR)/../module/log/include BS_LIB_INCLUDES += $(FWK_DIR)/../product/corstone-700/include/ + include $(BS_DIR)/lib.mk diff --git a/product/corstone-700/firmware/config_mhuv2.c b/product/corstone-700/firmware/config_mhuv2.c new file mode 100755 index 0000000..74ef8ca --- /dev/null +++ b/product/corstone-700/firmware/config_mhuv2.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + + +#include <fwk_element.h> +#include <fwk_id.h> +#include <fwk_module.h> +#include <mod_mhuv2.h> +#include <escm3_irq.h> +#include <escm3_mmap.h> + +static const struct fwk_element mhu_element_table[] = { + [ES_H_MHU0_DEVICE_IDX] = { + .name = "MHU0_H", + .sub_element_count = 1, + .data = &((struct mod_mhu2_channel_config) { + .irq = HESMHU0_Combined_IRQn, + .recv = MHU0_H_ES_BASE, + .send = MHU0_ES_H_BASE, + .channel = 0, + }) + }, + + [ES_H_MHU1_DEVICE_IDX] = { + .name = "MHU1_H", + .sub_element_count = 1, + .data = &((struct mod_mhu2_channel_config) { + .irq = HESMHU1_Combined_IRQn, + .recv = MHU1_H_ES_BASE, + .send = MHU1_ES_H_BASE, + .channel = 0, + }) + }, + + [ES_SE_MHU0_DEVICE_IDX] = { + .name = "MHU0_SE", + .sub_element_count = 1, + .data = &((struct mod_mhu2_channel_config) { + .irq = SEESMHU0_Combined_IRQn, + .recv = MHU0_SE_ES_BASE, + .send = MHU0_ES_SE_BASE, + .channel = 0, + }) + }, + + [ES_SE_MHU1_DEVICE_IDX] = { + .name = "MHU1_SE", + .sub_element_count = 1, + .data = &((struct mod_mhu2_channel_config) { + .irq = SEESMHU1_Combined_IRQn, + .recv = MHU1_SE_ES_BASE, + .send = MHU1_ES_SE_BASE, + .channel = 0, + }) + }, + + [ES_MHU_DEVICE_IDX_COUNT] = {}, +}; + +static const struct fwk_element *mhu_get_element_table(fwk_id_t module_id) +{ + return mhu_element_table; +} + +struct fwk_module_config config_mhuv2 = { + .get_element_table = mhu_get_element_table, +}; diff --git a/product/corstone-700/firmware/firmware.mk b/product/corstone-700/firmware/firmware.mk index 022eddd..cdd374a 100644 --- a/product/corstone-700/firmware/firmware.mk +++ b/product/corstone-700/firmware/firmware.mk @@ -11,9 +11,11 @@ BS_FIRMWARE_HAS_OPENAMP := yes BS_FIRMWARE_MODULES := \ pl011 \ - log + log \ + mhuv2 BS_FIRMWARE_SOURCES := \ - config_log.c + config_log.c \ + config_mhuv2.c include $(BS_DIR)/firmware.mk diff --git a/product/corstone-700/module/mhuv2/include/mod_mhuv2.h b/product/corstone-700/module/mhuv2/include/mod_mhuv2.h new file mode 100755 index 0000000..cc8af7f --- /dev/null +++ b/product/corstone-700/module/mhuv2/include/mod_mhuv2.h @@ -0,0 +1,98 @@ +/* + * + * Copyright (c) 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 <stdint.h> +#include <fwk_macros.h> + +#define CHANNEL_MAX 124 + +enum mod_mhu2_api_idx { + MOD_MHU2_API_IDX_DRIVER, + MOD_MHU2_API_IDX_COUNT, +}; + +struct mod_mhu2_channel_config { + /*! IRQ number of the receive interrupt line */ + unsigned int irq; + + /*! Indicates whether interrupt is within NVIC or a collated IRQ */ + bool irq_is_collated; + + /*! 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; +}; + + +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; +}; + +struct mod_mhu_driver_api { + int (*send_message) (fwk_id_t slot_id, uint32_t message); + fwk_id_t (*lookup_channel) (uint32_t dst); +}; + +#endif /* MOD_MHU2_H */ diff --git a/product/corstone-700/module/mhuv2/src/Makefile b/product/corstone-700/module/mhuv2/src/Makefile new file mode 100755 index 0000000..4e5c1d7 --- /dev/null +++ b/product/corstone-700/module/mhuv2/src/Makefile @@ -0,0 +1,10 @@ +# +# Copyright (c) 2019, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +BS_LIB_NAME := MHU2 +BS_LIB_SOURCES := mod_mhuv2.c + +include $(BS_DIR)/lib.mk diff --git a/product/corstone-700/module/mhuv2/src/mod_mhuv2.c b/product/corstone-700/module/mhuv2/src/mod_mhuv2.c new file mode 100755 index 0000000..dccd890 --- /dev/null +++ b/product/corstone-700/module/mhuv2/src/mod_mhuv2.c @@ -0,0 +1,256 @@ +/* + * + * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * Message Handling Unit (MHU) v2 Device Driver. + */ +#include <assert.h> +#include <stddef.h> +#include <stdint.h> +#include <fwk_errno.h> +#include <fwk_id.h> +#include <fwk_interrupt.h> +#include <fwk_mm.h> +#include <fwk_module.h> +#include <fwk_module_idx.h> +#include <mod_mhuv2.h> +#include <mod_log.h> +#include <openamp/rpmsg_internal.h> +#include <openamp/rpmsg_client.h> + +#define MHU_V2_INT_EN_OFS 0xF98 +#define MHU_V2_AIDR_OFS 0xFCC + +#define MHU_V2_CHCOMB (1 << 2) + +#define MHU_V2_AIDR_MINOR(_reg) ((_reg) & 0xF) + +/* 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; + fwk_id_t channel_id; + struct rpmsg_endpoint *ept; + const struct mod_log_api *log_api; +}; + +/* 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; + struct rpmsg_device *rdev; +} ctx; + +static void mhu2_isr(uintptr_t ctx_param) +{ + struct mhu2_channel_ctx *channel_ctx = (struct mhu2_channel_ctx *)ctx_param; + uint32_t message; + assert(channel_ctx != NULL); + + message = channel_ctx->recv_channel->STAT; + + channel_ctx->log_api->log(MOD_LOG_GROUP_INFO, + "MHUv2: Message from \'%s\': 0x%x\n", + fwk_module_get_name(channel_ctx->channel_id), + message); + channel_ctx->ept->cb(channel_ctx->ept, &message, 4, RPMSG_ADDR_ANY, NULL); + channel_ctx->recv_channel->STAT_CLEAR = message; +} + +static fwk_id_t lookup_channel(uint32_t dst) { + struct mhu2_channel_ctx *channel_ctx; + int ch_i = -1; + for(unsigned int i = 0; i < ctx.channel_count; i++) { + channel_ctx = &ctx.channel_ctx_table[i]; + if(channel_ctx->config->send == dst) { + ch_i = i; + break; + } + } + assert(ch_i != -1); + return fwk_id_build_element_id(FWK_ID_MODULE(FWK_MODULE_IDX_MHUV2), ch_i); +} + +static int send_message(fwk_id_t channel_id, uint32_t message) +{ + int status; + struct mhu2_channel_ctx *channel_ctx; + struct mhu2_send_reg *send; + + status = fwk_module_check_call(channel_id); + if (status != FWK_SUCCESS) + return status; + + channel_ctx = &ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)]; + send = channel_ctx->send; + + /* Turn on receiver */ + send->ACCESS_REQUEST = 1; + while (send->ACCESS_READY != 1) + continue; + channel_ctx->send_channel->STAT_SET = message; + + /* Signal that the receiver is no longer needed */ + send->ACCESS_REQUEST = 0; + + return FWK_SUCCESS; +} + +static const struct mod_mhu_driver_api mhu2_mod_driver_api = { + .send_message = send_message, + .lookup_channel = lookup_channel, +}; + +/* + * 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.rdev = init_rpmsg(); + ctx.channel_count = channel_count; + + return FWK_SUCCESS; +} + +static int mhu2_channel_init(fwk_id_t channel_id, + unsigned int unused, + 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->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->channel_id = channel_id; + channel_ctx->ept = endpoint_create(ctx.rdev, (void *)channel_ctx->send); + + const uint32_t aidr = *(uint32_t*)((void*)channel_ctx->recv_channel + MHU_V2_AIDR_OFS); + if(MHU_V2_AIDR_MINOR(aidr) >= 1) { + // Enable combined receiver interrupt for MHUv2.1 + uint32_t* reg_inten = ((void*)channel_ctx->recv_channel + MHU_V2_INT_EN_OFS); + *reg_inten = MHU_V2_CHCOMB; + } + + return FWK_SUCCESS; +} + +static int mhu2_bind(fwk_id_t id, unsigned int round) +{ + int status; + struct mhu2_channel_ctx *channel_ctx; + + if ((round == 1) && fwk_id_is_type(id, FWK_ID_TYPE_ELEMENT)) { + channel_ctx = &ctx.channel_ctx_table[fwk_id_get_element_idx(id)]; + + status = fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_LOG), + FWK_ID_API(FWK_MODULE_IDX_LOG, 0), + &channel_ctx->log_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) +{ + *api = &mhu2_mod_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)]; + + // Route IRQ to NVIC + 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; + } + + + channel_ctx->log_api->log(MOD_LOG_GROUP_INFO, "MHUv2 module \'%s\' started\n", + fwk_module_get_name(id)); + + return FWK_SUCCESS; +} + +/* MHU v2 module definition */ +const struct fwk_module module_mhuv2 = { + .name = "MHUV2", + .type = FWK_MODULE_TYPE_DRIVER, + .api_count = MOD_MHU2_API_IDX_COUNT, + .init = mhu2_init, + .element_init = mhu2_channel_init, + .start = mhu2_start, + .bind = mhu2_bind, + .process_bind_request = mhu2_process_bind_request, +}; |