diff --git a/product/neoverse-rd/interface/address_remapper/doc/address_remapper.md b/interface/address_remapper/doc/address_remapper.md similarity index 100% rename from product/neoverse-rd/interface/address_remapper/doc/address_remapper.md rename to interface/address_remapper/doc/address_remapper.md diff --git a/product/neoverse-rd/interface/address_remapper/interface_address_remapper.h b/interface/address_remapper/interface_address_remapper.h similarity index 100% rename from product/neoverse-rd/interface/address_remapper/interface_address_remapper.h rename to interface/address_remapper/interface_address_remapper.h diff --git a/module/CMakeLists.txt b/module/CMakeLists.txt index 325246b2f1f0b0e556514f8434b4a59696a7fc81..ffdde5db8ab777fadb28e1a9c2b9bf6ada2fa7f1 100644 --- a/module/CMakeLists.txt +++ b/module/CMakeLists.txt @@ -35,6 +35,7 @@ list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/dmc500") list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/dmc620") list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/dvfs") list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/dw_apb_i2c") +list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/atu_mmio") list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/gtimer") list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/i2c") list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/isys_rom") diff --git a/module/atu_mmio/CMakeLists.txt b/module/atu_mmio/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..28cbee09b685010043ba5c6297ae98de05156f14 --- /dev/null +++ b/module/atu_mmio/CMakeLists.txt @@ -0,0 +1,17 @@ +# +# Arm SCP/MCP Software +# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# +add_library(${SCP_MODULE_TARGET} SCP_MODULE) + +target_include_directories(${SCP_MODULE_TARGET} + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" + PUBLIC "${CMAKE_SOURCE_DIR}/interface/address_remapper/" + PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") + +target_sources(${SCP_MODULE_TARGET} + PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/mod_atu_mmio.c") + +target_link_libraries(${SCP_MODULE_TARGET} PRIVATE module-atu) diff --git a/module/atu_mmio/Module.cmake b/module/atu_mmio/Module.cmake new file mode 100644 index 0000000000000000000000000000000000000000..6d86533172dc6d2fcb58dfc9ac03e18f04aca92c --- /dev/null +++ b/module/atu_mmio/Module.cmake @@ -0,0 +1,10 @@ +# +# Arm SCP/MCP Software +# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +set(SCP_MODULE "atu-mmio") + +set(SCP_MODULE_TARGET "module-atu-mmio") diff --git a/module/atu_mmio/include/mod_atu_mmio.h b/module/atu_mmio/include/mod_atu_mmio.h new file mode 100644 index 0000000000000000000000000000000000000000..298e09645ad08773a4e82c5686763810a289952b --- /dev/null +++ b/module/atu_mmio/include/mod_atu_mmio.h @@ -0,0 +1,73 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * ATU MMIO module acts as an interface for accessing addresses that are + * outside the addressable memory map of the processor. It does not need + * permanent mapping in the ATU. It works by reserving a carveout used for + * mapping it to any region outside the processor's address space. Memory + * space and exposing API for byte, halfword, word and doubleword Read/Write + * APIs. These APIs maps a given address to the reserved carveout window and + * then performs the Read/Write operation. If the subsequent address falls + * within the window, then the address mapping step is skipped and performs + * the Read/Write operation directly. + */ + +#ifndef MOD_ATU_MMIO_H +#define MOD_ATU_MMIO_H + +#include + +#include +#include + +/*! + * \addtogroup GroupModules Modules + * \{ + */ + +/*! + * \ingroup GroupModules Modules + * \defgroup GroupModuleAtuMmio ATU MMIO + * + * \brief ATU MMIO module. + * + * \details This module implements Address Remapper. + * \{ + */ + +/*! + * \brief Module API indices. + */ +enum mod_atu_mmio_api_idx { + /*! Interface to byte, halfword, word and double word read write APIs. */ + MOD_ATU_MMIO_API_IDX_MEM_RW, + /*! Total API count. */ + MOD_ATU_MMIO_API_IDX_MAX, +}; + +/*! + * \brief ATU MMIO module configuration data. + */ +struct mod_atu_mmio_config { + /*! Base address of the carveout used for remapping. */ + uintptr_t window_address; + /*! Size of the carveout. */ + uintptr_t map_size; + /*! ATU module ID. */ + fwk_id_t atu_id; + /*! API in the ATU module used for remapping. */ + fwk_id_t atu_api_id; +}; + +/*! + * \} + */ + +/*! + * \} + */ +#endif /* MOD_ATU_MMIO_H */ diff --git a/module/atu_mmio/src/mod_atu_mmio.c b/module/atu_mmio/src/mod_atu_mmio.c new file mode 100644 index 0000000000000000000000000000000000000000..4f4df66ed1cd0d1da38e1b2b23f830b3f1a4062f --- /dev/null +++ b/module/atu_mmio/src/mod_atu_mmio.c @@ -0,0 +1,322 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * ATU MMIO module. + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#define MOD_NAME "[ATU MMIO] " + +/*! + * \brief Width of the Read/Write operation. + */ +enum atu_mmio_read_write_width { + /* 8 bit Read/Write operation. */ + ATU_MMIO_RW_WIDTH_BYTE = 1, + /* 16 bit Read/Write operation. */ + ATU_MMIO_RW_WIDTH_HALFWORD, + /* 32 bit Read/Write operation. */ + ATU_MMIO_RW_WIDTH_WORD, + /* 64 bit Read/Write operation. */ + ATU_MMIO_RW_WIDTH_DOUBLEWORD, +}; + +/*! Module Context. */ +struct atu_mmio_context { + /*! Module config. */ + const struct mod_atu_mmio_config *config; + /*! Address translation unit APIs. */ + struct mod_atu_api *atu_api; + /*! Current mapped physical address in the ATU. */ + uint64_t current_mapped_phys_address; + /*! Region index of the mapping in ATU. */ + uint8_t mapped_index; +}; + +static struct atu_mmio_context ctx; + +/*! Return the width of the data type. */ +static size_t get_width(enum atu_mmio_read_write_width width) +{ + size_t size; + + switch (width) { + case ATU_MMIO_RW_WIDTH_BYTE: + size = sizeof(uint8_t); + break; + + case ATU_MMIO_RW_WIDTH_HALFWORD: + size = sizeof(uint16_t); + break; + + case ATU_MMIO_RW_WIDTH_WORD: + size = sizeof(uint32_t); + break; + + case ATU_MMIO_RW_WIDTH_DOUBLEWORD: + size = sizeof(uint64_t); + break; + + default: + size = 0; + fwk_unexpected(); + break; + }; + + return size; +} + +/* Check if the address fall within previously mapped window. */ +static bool is_addr_mapped(uint64_t address, size_t size) +{ + return (address >= ctx.current_mapped_phys_address) && + ((address + size) < + (ctx.current_mapped_phys_address + ctx.config->map_size)); +} + +/* Maps the address if it does not fall within previously mapped region. */ +static uintptr_t map_region( + uint64_t request_phy_address, + enum atu_mmio_read_write_width width) +{ + struct atu_region_map atu_map; + uint64_t aligned_request_phy_address; + int status; + + if (!is_addr_mapped(request_phy_address, get_width(width))) { + /* + * A single ATU translation region is used to provide MMIO operations. + * In order to prevent stale value reads when the ATU region is used to + * map a different target address, flush and invalidate the cache before + * unmapping the region. + */ +#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) + SCB_CleanInvalidateDCache_by_Addr( + (uintptr_t)(ctx.config->window_address), ctx.config->map_size); +#endif + + if (ctx.current_mapped_phys_address != 0) { + status = ctx.atu_api->remove_region( + ctx.mapped_index, + ctx.config->atu_id, + FWK_ID_MODULE(FWK_MODULE_IDX_ATU_MMIO)); + if (status != FWK_SUCCESS) { + fwk_unexpected(); + } + } + + /* + * Align the physical address if it is not aligned with the translation + * window. + */ + aligned_request_phy_address = request_phy_address - + (request_phy_address & (ctx.config->map_size - 1)); + atu_map.region_owner_id = FWK_ID_MODULE(FWK_MODULE_IDX_ATU_MMIO); + /* TODO: Support for allowing non root PAS. */ + atu_map.attributes = ATU_ENCODE_ATTRIBUTES_ROOT_PAS; + atu_map.log_addr_base = ctx.config->window_address; + atu_map.region_size = ctx.config->map_size; + atu_map.phy_addr_base = aligned_request_phy_address; + + status = ctx.atu_api->add_region( + &atu_map, ctx.config->atu_id, &ctx.mapped_index); + if (status != FWK_SUCCESS) { + fwk_unexpected(); + } + + ctx.current_mapped_phys_address = aligned_request_phy_address; + } + + /* Return the adjusted mapped address. */ + return ctx.config->window_address + + (request_phy_address - ctx.current_mapped_phys_address); +} + +/* Generic function for read operation. */ +static uint64_t atu_mmio_read_value( + uint64_t address, + enum atu_mmio_read_write_width width) +{ + uintptr_t mapped_logical_address; + uint64_t value; + + mapped_logical_address = map_region(address, width); + + switch (width) { + case ATU_MMIO_RW_WIDTH_BYTE: + value = fwk_mmio_read_8(mapped_logical_address); + break; + + case ATU_MMIO_RW_WIDTH_HALFWORD: + value = fwk_mmio_read_16(mapped_logical_address); + break; + + case ATU_MMIO_RW_WIDTH_WORD: + value = fwk_mmio_read_32(mapped_logical_address); + break; + + case ATU_MMIO_RW_WIDTH_DOUBLEWORD: + value = fwk_mmio_read_64(mapped_logical_address); + break; + + default: + fwk_unexpected(); + value = 0; + break; + }; + + return value; +} + +/* Generic fucntion for write operation. */ +static void atu_mmio_write_value( + uint64_t address, + uint64_t value, + enum atu_mmio_read_write_width width) +{ + uintptr_t mapped_log_address; + + mapped_log_address = map_region(address, width); + + switch (width) { + case ATU_MMIO_RW_WIDTH_BYTE: + fwk_mmio_write_8(mapped_log_address, (uint8_t)value); + break; + + case ATU_MMIO_RW_WIDTH_HALFWORD: + fwk_mmio_write_16(mapped_log_address, (uint16_t)value); + break; + + case ATU_MMIO_RW_WIDTH_WORD: + fwk_mmio_write_32(mapped_log_address, (uint32_t)value); + break; + + case ATU_MMIO_RW_WIDTH_DOUBLEWORD: + fwk_mmio_write_64(mapped_log_address, value); + break; + + default: + fwk_unexpected(); + break; + }; +} + +static uint8_t atu_mmio_read8(uint64_t address) +{ + return (uint8_t)atu_mmio_read_value(address, ATU_MMIO_RW_WIDTH_BYTE); +} + +static uint16_t atu_mmio_read16(uint64_t address) +{ + return (uint16_t)atu_mmio_read_value(address, ATU_MMIO_RW_WIDTH_HALFWORD); +} + +static uint32_t atu_mmio_read32(uint64_t address) +{ + return (uint32_t)atu_mmio_read_value(address, ATU_MMIO_RW_WIDTH_WORD); +} + +static uint64_t atu_mmio_read64(uint64_t address) +{ + return atu_mmio_read_value(address, ATU_MMIO_RW_WIDTH_DOUBLEWORD); +} + +static void atu_mmio_write8(uint64_t address, uint8_t value) +{ + atu_mmio_write_value(address, value, ATU_MMIO_RW_WIDTH_BYTE); +} + +static void atu_mmio_write16(uint64_t address, uint16_t value) +{ + atu_mmio_write_value(address, value, ATU_MMIO_RW_WIDTH_HALFWORD); +} + +static void atu_mmio_write32(uint64_t address, uint32_t value) +{ + atu_mmio_write_value(address, value, ATU_MMIO_RW_WIDTH_WORD); +} + +static void atu_mmio_write64(uint64_t address, uint64_t value) +{ + atu_mmio_write_value(address, value, ATU_MMIO_RW_WIDTH_DOUBLEWORD); +} + +struct interface_address_remapper_rw_api rw_api = { + .read8 = atu_mmio_read8, + .read16 = atu_mmio_read16, + .read32 = atu_mmio_read32, + .read64 = atu_mmio_read64, + .write8 = atu_mmio_write8, + .write16 = atu_mmio_write16, + .write32 = atu_mmio_write32, + .write64 = atu_mmio_write64, +}; + +/* + * Framework handlers. + */ +static int atu_mmio_init( + fwk_id_t module_id, + unsigned int element_count, + const void *config) +{ + ctx.config = config; + return FWK_SUCCESS; +} + +static int atu_mmio_bind(fwk_id_t id, unsigned int round) +{ + return fwk_module_bind( + ctx.config->atu_id, ctx.config->atu_api_id, &ctx.atu_api); +} + +static int atu_mmio_process_bind_request( + fwk_id_t requester_id, + fwk_id_t id, + fwk_id_t api_id, + const void **api) +{ + enum mod_atu_mmio_api_idx api_idx; + int status; + + if (!fwk_module_is_valid_module_id(id)) { + return FWK_E_PARAM; + } + + api_idx = (enum mod_atu_mmio_api_idx)fwk_id_get_api_idx(api_id); + switch (api_idx) { + case MOD_ATU_MMIO_API_IDX_MEM_RW: + *api = &rw_api; + status = FWK_SUCCESS; + break; + default: + status = FWK_E_PARAM; + break; + }; + + return status; +} + +const struct fwk_module module_atu_mmio = { + .type = FWK_MODULE_TYPE_DRIVER, + .init = atu_mmio_init, + .api_count = MOD_ATU_MMIO_API_IDX_MAX, + .bind = atu_mmio_bind, + .process_bind_request = atu_mmio_process_bind_request, +}; diff --git a/product/neoverse-rd/rdn2/module/apremap/CMakeLists.txt b/product/neoverse-rd/rdn2/module/apremap/CMakeLists.txt index 1b73e0d1e1a201ab4cb861eccf62fe9cb9d199bd..ff26e2a22281502d1fb8c67535de86bf95545a94 100644 --- a/product/neoverse-rd/rdn2/module/apremap/CMakeLists.txt +++ b/product/neoverse-rd/rdn2/module/apremap/CMakeLists.txt @@ -9,7 +9,7 @@ add_library(${SCP_MODULE_TARGET} SCP_MODULE) target_include_directories(${SCP_MODULE_TARGET} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" - PUBLIC "${CMAKE_SOURCE_DIR}/product/neoverse-rd/interface/address_remapper/") + PUBLIC "${CMAKE_SOURCE_DIR}/interface/address_remapper/") target_sources(${SCP_MODULE_TARGET} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/mod_apremap.c") diff --git a/product/neoverse-rd/rdv3/scp_ramfw/CMakeLists.txt b/product/neoverse-rd/rdv3/scp_ramfw/CMakeLists.txt index d3b8eb827c53f3a106e7a78ada364effced97665..165ab077085d86090381556603dc653e62ea2007 100644 --- a/product/neoverse-rd/rdv3/scp_ramfw/CMakeLists.txt +++ b/product/neoverse-rd/rdv3/scp_ramfw/CMakeLists.txt @@ -24,6 +24,7 @@ target_sources( PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/config_system_power.c" "${CMAKE_CURRENT_SOURCE_DIR}/config_armv7m_mpu.c" "${CMAKE_CURRENT_SOURCE_DIR}/config_atu.c" + "${CMAKE_CURRENT_SOURCE_DIR}/config_atu_mmio.c" "${CMAKE_CURRENT_SOURCE_DIR}/config_power_domain.c" "${CMAKE_CURRENT_SOURCE_DIR}/config_ppu_v1.c" "${CMAKE_CURRENT_SOURCE_DIR}/config_mhu3.c" diff --git a/product/neoverse-rd/rdv3/scp_ramfw/Firmware.cmake b/product/neoverse-rd/rdv3/scp_ramfw/Firmware.cmake index ab4996c1ee8c5b33ab9c086e5a6188bda7ba0cc7..18e3bf38bbb0307eccfbeacb118500f795cfd16e 100644 --- a/product/neoverse-rd/rdv3/scp_ramfw/Firmware.cmake +++ b/product/neoverse-rd/rdv3/scp_ramfw/Firmware.cmake @@ -40,6 +40,7 @@ list(PREPEND SCP_MODULE_PATHS list(APPEND SCP_MODULES "armv7m-mpu") list(APPEND SCP_MODULES "pl011") list(APPEND SCP_MODULES "atu") +list(APPEND SCP_MODULES "atu-mmio") list(APPEND SCP_MODULES "ppu-v1") list(APPEND SCP_MODULES "system-power") list(APPEND SCP_MODULES "power-domain") diff --git a/product/neoverse-rd/rdv3/scp_ramfw/config_atu_mmio.c b/product/neoverse-rd/rdv3/scp_ramfw/config_atu_mmio.c new file mode 100644 index 0000000000000000000000000000000000000000..2cf09b8b712b07977ae121d51b48722c110b6543 --- /dev/null +++ b/product/neoverse-rd/rdv3/scp_ramfw/config_atu_mmio.c @@ -0,0 +1,30 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * Configuration data for module 'atu_mmio'. + */ + +#include "scp_css_mmap.h" + +#include +#include + +#include +#include +#include +#include + +static struct mod_atu_mmio_config atu_mmio_module_config = { + .window_address = SCP_ATW0_ATU_MMIO_BASE, + .map_size = SCP_ATW0_ATU_MMIO_SIZE, + .atu_id = FWK_ID_ELEMENT(FWK_MODULE_IDX_ATU, 0), + .atu_api_id = FWK_ID_API(FWK_MODULE_IDX_ATU, MOD_ATU_API_IDX_ATU), +}; + +struct fwk_module_config config_atu_mmio = { + .data = &atu_mmio_module_config, +}; diff --git a/product/neoverse-rd/rdv3/scp_ramfw/include/scp_css_mmap.h b/product/neoverse-rd/rdv3/scp_ramfw/include/scp_css_mmap.h index fe33d2f898139dea2ef7922ae4e14886aa2f740e..eb0c936918c54bb7b8f9b207e1a568f8366f12ae 100644 --- a/product/neoverse-rd/rdv3/scp_ramfw/include/scp_css_mmap.h +++ b/product/neoverse-rd/rdv3/scp_ramfw/include/scp_css_mmap.h @@ -44,7 +44,10 @@ /* * Offsets within SCP's Address Translation Window0 - * __________________________ 0x78500000 + * __________________________ 0x78600000 + * | | + * | ATU MMIO (1M) | + * |__________________________| 0x78500000 * | | * | RSM_SRAM (4MB) | * |__________________________| 0x78100000 @@ -63,6 +66,7 @@ #define SCP_ATW0_AP_PERIPHERAL_SRAM_SIZE (128 * FWK_MIB) #define SCP_ATW0_AP_PERIPHERAL_GPC_SMMU_SIZE (1 * FWK_MIB) #define SCP_ATW0_SYSTEM_CONTROL_SRAM_SIZE (4 * FWK_MIB) +#define SCP_ATW0_ATU_MMIO_SIZE (1 * FWK_MIB) #define SCP_ATW0_LCP_AND_CLUSTER_UTILITY_BASE \ SCP_ADDRESS_TRANSLATION_WINDOW0_BASE @@ -74,6 +78,8 @@ #define SCP_ATW0_SYSTEM_CONTROL_SRAM_BASE \ (SCP_ATW0_AP_PERIPHERAL_GPC_SMMU_BASE + \ SCP_ATW0_AP_PERIPHERAL_GPC_SMMU_SIZE) +#define SCP_ATW0_ATU_MMIO_BASE \ + (SCP_ATW0_SYSTEM_CONTROL_SRAM_BASE + SCP_ATW0_SYSTEM_CONTROL_SRAM_SIZE) /* * Offsets within SCP's Address Translation Window1