From 7fc6e331d8a79bc84e5d17e41e684c654d13f841 Mon Sep 17 00:00:00 2001 From: L Lakshmanan Date: Thu, 6 Jul 2023 17:44:43 +0530 Subject: [PATCH] drivers: mm: Add support for TI RAT module using system_mm API Added Region based Address Translation (RAT) module driver. Required by a few Texas Instruments SoCs to fucntion. Uses sys_mm_drv_page_phys_get() API with device_map() for address translation. Signed-off-by: L Lakshmanan --- drivers/mm/CMakeLists.txt | 2 + drivers/mm/Kconfig | 19 ++++ drivers/mm/mm_drv_ti_rat.c | 143 +++++++++++++++++++++++++++++++ include/zephyr/drivers/mm/rat.h | 87 +++++++++++++++++++ include/zephyr/sys/device_mmio.h | 11 ++- 5 files changed, 260 insertions(+), 2 deletions(-) create mode 100644 drivers/mm/mm_drv_ti_rat.c create mode 100644 include/zephyr/drivers/mm/rat.h diff --git a/drivers/mm/CMakeLists.txt b/drivers/mm/CMakeLists.txt index e04fb70d286..98781346a9e 100644 --- a/drivers/mm/CMakeLists.txt +++ b/drivers/mm/CMakeLists.txt @@ -15,3 +15,5 @@ zephyr_sources_ifdef( mm_drv_intel_adsp_regions.c mm_drv_intel_adsp_mtl_tlb.c ) + +zephyr_sources_ifdef(CONFIG_MM_TI_RAT mm_drv_ti_rat.c) diff --git a/drivers/mm/Kconfig b/drivers/mm/Kconfig index 15c418c78a4..f53312b8470 100644 --- a/drivers/mm/Kconfig +++ b/drivers/mm/Kconfig @@ -44,4 +44,23 @@ config MM_DRV_INTEL_ADSP_TLB Driver for the translation lookup buffer on Intel Audio DSP hardware. +config EXTERNAL_ADDRESS_TRANSLATION + bool "Support for external address translation modules" + depends on !MMU + help + This config is intended to support an external address + translation module if required for an SoC. Uses the + sys_mm_drv_page_phys_get() function from the system_mm API. + +if EXTERNAL_ADDRESS_TRANSLATION + +config MM_TI_RAT + bool "Texas Instruments RAT module" + depends on EXTERNAL_ADDRESS_TRANSLATION + help + Enables Region based address translation support + functions specific to TI SoCs. + +endif # EXTERNAL_ADDRESS_TRANSLATION + endif # MM_DRV diff --git a/drivers/mm/mm_drv_ti_rat.c b/drivers/mm/mm_drv_ti_rat.c new file mode 100644 index 00000000000..19fdb6cbb2d --- /dev/null +++ b/drivers/mm/mm_drv_ti_rat.c @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2023 Texas Instruments Incorporated + * Copyright (c) 2023 L Lakshmanan + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Driver handling Region based Address Translation (RAT) + * related functions + * + * RAT is a module that is used by certain Texas Instruments SoCs + * to allow some cores with a 32 bit address space to access + * the full 48 bit SoC address space. This is required for the + * core to be able to use peripherals. + * + * The driver uses the sys_mm_drv_page_phys_get() API to access + * the address space. + */ + +#include +#include +#include + +static struct address_trans_params translate_config; + +/** + * @brief Set registers for the address regions being used + * + * @param addr_translate_config Pointer to config struct for the RAT module + * @param region_num Number of regions being initialised + * @param enable Region status + */ + +static void address_trans_set_region(struct address_trans_params *addr_translate_config, + uint16_t region_num, uint32_t enable) +{ + uint32_t rat_base_addr = addr_translate_config->rat_base_addr; + uint64_t system_addr = addr_translate_config->region_config[region_num].system_addr; + uint32_t local_addr = addr_translate_config->region_config[region_num].local_addr; + uint32_t size = addr_translate_config->region_config[region_num].size; + uint32_t system_addrL, system_addrH; + + if (size > address_trans_region_size_4G) { + size = address_trans_region_size_4G; + } + system_addrL = (uint32_t)(system_addr & ~((uint32_t)((BIT64_MASK(size))))); + system_addrH = (uint32_t)((system_addr >> 32) & 0xFFFF); + local_addr = local_addr & ~((uint32_t)(BIT64_MASK(size))); + + sys_write32(0, RAT_CTRL(rat_base_addr, region_num)); + sys_write32(local_addr, RAT_BASE(rat_base_addr, region_num)); + sys_write32(system_addrL, RAT_TRANS_L(rat_base_addr, region_num)); + sys_write32(system_addrH, RAT_TRANS_H(rat_base_addr, region_num)); + sys_write32(RAT_CTRL_W(enable, size), RAT_CTRL(rat_base_addr, region_num)); +} + +static void address_trans_init(struct address_trans_params *params) +{ + uint32_t i; + + if (params != NULL) { + translate_config = *params; + } + + __ASSERT(translate_config.num_regions < ADDR_TRANSLATE_MAX_REGIONS, + "Exceeding maximum number of regions"); + + for (i = 0; i < translate_config.num_regions; i++) { + __ASSERT(translate_config.rat_base_addr != 0, "RAT base address cannot be 0"); + __ASSERT(translate_config.region_config != NULL, + "RAT region config cannot be NULL"); + + /* enable regions setup by user */ + address_trans_set_region(&translate_config, i, 1); + } +} + +/** + * @brief Initialise RAT module + * + * @param region_config Pointer to config struct for the regions + * @param rat_base_addr Base address for the RAT module + * @param translate_regions Number of regions being initialised + */ + +void sys_mm_drv_ti_rat_init(void *region_config, uint64_t rat_base_addr, uint8_t translate_regions) +{ + translate_config.num_regions = translate_regions; + translate_config.rat_base_addr = rat_base_addr; + translate_config.region_config = (struct address_trans_region_config *)region_config; + + address_trans_init(&translate_config); +} + +int sys_mm_drv_page_phys_get(void *virt, uintptr_t *phys) +{ + if (virt == NULL) { + return -EINVAL; + } + uint64_t pa = ((uint64_t) (virt)); + uintptr_t *va = phys; + + uint32_t found, regionId; + + __ASSERT(translate_config.num_regions < address_trans_MAX_REGIONS, + "Exceeding maximum number of regions"); + + found = 0; + + for (regionId = 0; regionId < translate_config.num_regions; regionId++) { + uint64_t start_addr, end_addr; + uint32_t size_mask; + + size_mask = + ((uint32_t)((BIT64_MASK(translate_config.region_config[regionId].size)))); + + start_addr = translate_config.region_config[regionId].system_addr; + + end_addr = start_addr + size_mask; + + if (pa >= start_addr && pa <= end_addr) { + found = 1; + break; + } + } + if (found) { + /* translate input address to output address */ + uint32_t offset = + pa - translate_config.region_config[regionId].system_addr; + + *va = (void *)(translate_config.region_config[regionId].local_addr + offset); + } else { + /* no mapping found, set output = input with 32b truncation */ + *va = (void *)pa; + } + + if (va == NULL) { + return -EFAULT; + } + return 0; +} diff --git a/include/zephyr/drivers/mm/rat.h b/include/zephyr/drivers/mm/rat.h new file mode 100644 index 00000000000..984c4ef01d4 --- /dev/null +++ b/include/zephyr/drivers/mm/rat.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2023 Texas Instruments Incorporated + * Copyright (c) 2023 L Lakshmanan + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_RAT_H_ +#define ZEPHYR_INCLUDE_RAT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define ADDR_TRANSLATE_MAX_REGIONS (16u) +#define RAT_CTRL(base_addr, i) (volatile uint32_t *)(base_addr + 0x20 + 0x10 * (i)) +#define RAT_BASE(base_addr, i) (volatile uint32_t *)(base_addr + 0x24 + 0x10 * (i)) +#define RAT_TRANS_L(base_addr, i) (volatile uint32_t *)(base_addr + 0x28 + 0x10 * (i)) +#define RAT_TRANS_H(base_addr, i) (volatile uint32_t *)(base_addr + 0x2C + 0x10 * (i)) +#define RAT_CTRL_W(enable, size) (((enable & 0x1) << 31u) | (size & 0x3F)) + +/** + * @brief Enum's to represent different possible region size for the address translate module + */ +enum address_trans_region_size { + address_trans_region_size_1 = 0x0, + address_trans_region_size_2, + address_trans_region_size_4, + address_trans_region_size_8, + address_trans_region_size_16, + address_trans_region_size_32, + address_trans_region_size_64, + address_trans_region_size_128, + address_trans_region_size_256, + address_trans_region_size_512, + address_trans_region_size_1K, + address_trans_region_size_2K, + address_trans_region_size_4K, + address_trans_region_size_8K, + address_trans_region_size_16K, + address_trans_region_size_32K, + address_trans_region_size_64K, + address_trans_region_size_128K, + address_trans_region_size_256K, + address_trans_region_size_512K, + address_trans_region_size_1M, + address_trans_region_size_2M, + address_trans_region_size_4M, + address_trans_region_size_8M, + address_trans_region_size_16M, + address_trans_region_size_32M, + address_trans_region_size_64M, + address_trans_region_size_128M, + address_trans_region_size_256M, + address_trans_region_size_512M, + address_trans_region_size_1G, + address_trans_region_size_2G, + address_trans_region_size_4G +}; + +/** + * @brief Region config structure + */ +struct address_trans_region_config { + uint64_t system_addr; + uint32_t local_addr; + uint32_t size; +}; + +/** + * @brief Parameters for address_trans_init + */ +struct address_trans_params { + uint32_t num_regions; + uint32_t rat_base_addr; + struct address_trans_region_config *region_config; +}; + +void sys_mm_drv_ti_rat_init(void *region_config, uint64_t rat_base_addr, uint8_t translate_regions); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_RAT_H_ */ diff --git a/include/zephyr/sys/device_mmio.h b/include/zephyr/sys/device_mmio.h index bc28c3e91e4..4358e246339 100644 --- a/include/zephyr/sys/device_mmio.h +++ b/include/zephyr/sys/device_mmio.h @@ -33,10 +33,14 @@ * If we have PCIE enabled, this does mean that non-PCIE drivers may waste * a bit of RAM, but systems with PCI express are not RAM constrained. */ -#if defined(CONFIG_MMU) || defined(CONFIG_PCIE) +#if defined(CONFIG_MMU) || defined(CONFIG_PCIE) || defined(CONFIG_EXTERNAL_ADDRESS_TRANSLATION) #define DEVICE_MMIO_IS_IN_RAM #endif +#if defined(CONFIG_EXTERNAL_ADDRESS_TRANSLATION) +#include +#endif + #ifndef _ASMLANGUAGE #include #include @@ -101,8 +105,11 @@ static inline void device_map(mm_reg_t *virt_addr, uintptr_t phys_addr, #else ARG_UNUSED(size); ARG_UNUSED(flags); - +#ifdef CONFIG_EXTERNAL_ADDRESS_TRANSLATION + sys_mm_drv_page_phys_get((void *) phys_addr, virt_addr); +#else *virt_addr = phys_addr; +#endif /* CONFIG_EXTERNAL_ADDRESS_TRANSLATION */ #endif /* CONFIG_MMU */ } #else