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 <l-lakshmanan@ti.com>
This commit is contained in:
parent
33cb179b4f
commit
7fc6e331d8
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
143
drivers/mm/mm_drv_ti_rat.c
Normal file
143
drivers/mm/mm_drv_ti_rat.c
Normal file
|
@ -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 <zephyr/drivers/mm/rat.h>
|
||||
#include <zephyr/drivers/mm/system_mm.h>
|
||||
#include <zephyr/sys/__assert.h>
|
||||
|
||||
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;
|
||||
}
|
87
include/zephyr/drivers/mm/rat.h
Normal file
87
include/zephyr/drivers/mm/rat.h
Normal file
|
@ -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 <stdint.h>
|
||||
|
||||
#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_ */
|
|
@ -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 <zephyr/drivers/mm/system_mm.h>
|
||||
#endif
|
||||
|
||||
#ifndef _ASMLANGUAGE
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue