[OFW] Support ID map interface (#8994)

The OFW map id is always use in DMA, PCI, IOMMU
bus system to find the device identity. this is
a access interface.

Signed-off-by: GuEe-GUI <2991707448@qq.com>
This commit is contained in:
GUI 2024-05-28 09:54:03 +08:00 committed by GitHub
parent 8c6c9205b0
commit f035188094
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 135 additions and 0 deletions

View File

@ -205,6 +205,9 @@ struct rt_ofw_node *rt_ofw_get_alias_node(const char *tag, int id);
int rt_ofw_get_alias_id(struct rt_ofw_node *np, const char *tag);
int rt_ofw_get_alias_last_id(const char *tag);
rt_err_t rt_ofw_map_id(struct rt_ofw_node *np, rt_uint32_t id, const char *map_name, const char *map_mask_name,
struct rt_ofw_node **ref_np, rt_uint32_t *out_id);
struct rt_ofw_node *rt_ofw_append_child(struct rt_ofw_node *parent, const char *full_name);
rt_err_t rt_ofw_append_prop(struct rt_ofw_node *np, const char *name, int length, void *value);

View File

@ -1224,6 +1224,138 @@ int rt_ofw_get_alias_last_id(const char *tag)
return id;
}
static rt_err_t ofw_map_id(struct rt_ofw_node *np, rt_uint32_t id, const char *map_name, const char *map_mask_name,
const fdt32_t *map, rt_ssize_t map_len, struct rt_ofw_node **ref_np, rt_uint32_t *out_id)
{
rt_err_t err = RT_EOK;
rt_uint32_t masked_id, map_mask;
/* Select all bits default */
map_mask = 0xffffffff;
if (map_mask_name)
{
rt_ofw_prop_read_u32(np, map_mask_name, &map_mask);
}
masked_id = map_mask & id;
for (; map_len > 0; map_len -= 4 * sizeof(*map), map += 4)
{
struct rt_ofw_node *phandle_node;
rt_uint32_t id_base = fdt32_to_cpu(*(map + 0));
rt_uint32_t phandle = fdt32_to_cpu(*(map + 1));
rt_uint32_t out_base = fdt32_to_cpu(*(map + 2));
rt_uint32_t id_len = fdt32_to_cpu(*(map + 3));
if (id_base & ~map_mask)
{
LOG_E("%s: Invalid %s translation - %s(0x%x) for id-base = 0x%x",
np->full_name, map_name, map_mask_name, map_mask, id_base);
err = -RT_ERROR;
break;
}
if (masked_id < id_base || masked_id >= id_base + id_len)
{
continue;
}
phandle_node = rt_ofw_find_node_by_phandle((rt_phandle)phandle);
if (!phandle_node)
{
err = -RT_EEMPTY;
break;
}
if (ref_np)
{
if (*ref_np)
{
rt_ofw_node_put(phandle_node);
}
else
{
*ref_np = phandle_node;
}
if (*ref_np != phandle_node)
{
continue;
}
}
if (out_id)
{
*out_id = masked_id - id_base + out_base;
}
LOG_D("%s: Get %s translation - %s(0x%x) for id-base = 0x%x, out-base = 0x%x, length = %d, id: 0x%x -> 0x%x",
np->full_name, map_name, map_mask_name, map_mask,
id_base, out_base, id_len, id, masked_id - id_base + out_base);
break;
}
if (map_len <= 0)
{
LOG_I("%s: No %s translation for id(0x%x) on %s", np->full_name, map_name,
id, ref_np && *ref_np ? *ref_np : RT_NULL);
/* Bypasses translation */
if (out_id)
{
*out_id = id;
}
}
return err;
}
rt_err_t rt_ofw_map_id(struct rt_ofw_node *np, rt_uint32_t id, const char *map_name, const char *map_mask_name,
struct rt_ofw_node **ref_np, rt_uint32_t *out_id)
{
rt_err_t err;
if (np && map_name && (ref_np || out_id))
{
rt_ssize_t map_len;
const fdt32_t *map = rt_ofw_prop_read_raw(np, map_name, &map_len);
if (!map)
{
if (ref_np)
{
err = -RT_EEMPTY;
}
else
{
*out_id = id;
}
err = RT_EOK;
}
else if (!map_len || map_len % (4 * sizeof(*map)))
{
LOG_E("%s: Invalid %s length = %u", np->full_name, map_name, map_len);
err = -RT_EINVAL;
}
else
{
err = ofw_map_id(np, id, map_name, map_mask_name, map, map_len, ref_np, out_id);
}
}
else
{
err = -RT_EINVAL;
}
return err;
}
struct rt_ofw_node *rt_ofw_append_child(struct rt_ofw_node *parent, const char *full_name)
{
rt_phandle phandle;