Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

134 lines
3.4 KiB

/*
* Copyright 2025 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/init.h>
#include <zephyr/logging/log.h>
#include <addr_translation.h>
#ifdef CONFIG_OPENAMP_VENDOR_ADDR_TRANSLATION_FILE
/*
* In this file get_phys_pages() needs to be defined,
* see example in nxp_addr_translation.h
*/
#include CONFIG_OPENAMP_VENDOR_ADDR_TRANSLATION_FILE
#else
/*
* Return table of base physical addresses for the I/O region
* that starts with the specified physical base address (phys)
*/
static inline const struct phys_pages *get_phys_map(metal_phys_addr_t phys)
{
(void)phys;
return NULL;
}
#endif
static const struct phys_pages *phys_pages;
/**
* @brief Translates an offset within an I/O region to a physical address.
*
* This function first attempts to translate the offset using the driver's
* physical address map. If no valid mapping is found, it falls back to the
* device physical address map.
*
* @param io Pointer to the I/O region.
* @param offset Offset within the I/O region.
*
* @return physical address if valid, otherwise METAL_BAD_PHYS.
*/
static metal_phys_addr_t translate_offset_to_phys(struct metal_io_region *io,
unsigned long offset)
{
(void)io;
size_t i;
metal_phys_addr_t tmp_addr;
size_t tmp_size;
unsigned long tmp_offset = 0;
if (offset > io->size) {
return METAL_BAD_PHYS;
}
for (i = 0; i < phys_pages->no_pages; i++) {
tmp_addr = phys_pages->map[i].addr;
tmp_size = phys_pages->map[i].size;
if ((tmp_offset <= offset) && (offset < tmp_offset + tmp_size)) {
return tmp_addr + (offset - tmp_offset);
}
tmp_offset += tmp_size;
}
return METAL_BAD_PHYS;
}
/**
* @brief Translates a physical address to an offset within an I/O region.
*
* This function first attempts to translate the physical address using the
* driver's address map. If no valid mapping is found, it falls back to the
* device address map.
*
* @param io Pointer to the I/O region.
* @param phys Physical address to translate.
*
* @return offset if valid, otherwise METAL_BAD_OFFSET.
*/
static unsigned long translate_phys_to_offset(struct metal_io_region *io,
metal_phys_addr_t phys)
{
(void)io;
size_t i;
metal_phys_addr_t tmp_addr;
size_t tmp_size;
unsigned long offset = 0;
for (i = 0; i < phys_pages->no_pages; i++) {
tmp_addr = phys_pages->map[i].addr;
tmp_size = phys_pages->map[i].size;
if ((tmp_addr <= phys) && (phys < tmp_addr + tmp_size)) {
offset += (phys - tmp_addr);
return (offset < io->size ? offset : METAL_BAD_OFFSET);
}
offset += tmp_size;
}
/* if not found in local addr, search in remote addr */
offset = 0;
for (i = 0; i < phys_pages->no_pages; i++) {
tmp_addr = phys_pages->map[i].remote_addr;
tmp_size = phys_pages->map[i].size;
if ((phys >= tmp_addr) && (phys < tmp_addr + tmp_size)) {
offset += (phys - tmp_addr);
return (offset < io->size ? offset : METAL_BAD_OFFSET);
}
offset += tmp_size;
}
return METAL_BAD_OFFSET;
}
/* Address translation operations for OpenAMP */
static const struct metal_io_ops openamp_addr_translation_ops = {
.phys_to_offset = translate_phys_to_offset,
.offset_to_phys = translate_offset_to_phys,
};
/**
* @brief Return generic I/O operations
*
* @param phys Physical base address of the I/O region
* @return metal_io_ops struct
*/
const struct metal_io_ops *addr_translation_get_ops(metal_phys_addr_t phys)
{
phys_pages = get_phys_map(phys);
if (!phys_pages) {
return NULL;
}
return &openamp_addr_translation_ops;
}