198 lines
5.2 KiB
C
198 lines
5.2 KiB
C
|
/*
|
||
|
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||
|
*
|
||
|
* SPDX-License-Identifier: Apache-2.0
|
||
|
*
|
||
|
* Change Logs:
|
||
|
* Date Author Notes
|
||
|
* 2022-10-19 GuEe-GUI first version
|
||
|
*/
|
||
|
|
||
|
#include <drivers/ofw_raw.h>
|
||
|
|
||
|
int fdt_add_subnode_possible(void *fdt, int parentoffset, const char *name)
|
||
|
{
|
||
|
int nodeoffset;
|
||
|
|
||
|
if ((nodeoffset = fdt_add_subnode(fdt, parentoffset, name)) < 0)
|
||
|
{
|
||
|
fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + FDT_PADDING_SIZE);
|
||
|
nodeoffset = fdt_add_subnode(fdt, parentoffset, name);
|
||
|
}
|
||
|
|
||
|
return nodeoffset;
|
||
|
}
|
||
|
|
||
|
int fdt_add_mem_rsv_possible(void *fdt, size_t addr, size_t size)
|
||
|
{
|
||
|
int err = 0;
|
||
|
|
||
|
if (fdt_add_mem_rsv(fdt, addr, size) < 0)
|
||
|
{
|
||
|
fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + FDT_PADDING_SIZE);
|
||
|
err = fdt_add_mem_rsv(fdt, addr, size);
|
||
|
}
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
int fdt_setprop_uxx(void *fdt, int nodeoffset, const char *name, uint64_t val, bool is_u64)
|
||
|
{
|
||
|
int err;
|
||
|
|
||
|
if (is_u64)
|
||
|
{
|
||
|
err = fdt_setprop_u64(fdt, nodeoffset, name, val);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
err = fdt_setprop_u32(fdt, nodeoffset, name, (uint32_t)val);
|
||
|
}
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
#define FDT_RAW_GET_VAL_FLAG(std_type, s, sz) \
|
||
|
int fdt_getprop_##std_type##sz(void *fdt, int nodeoffset, \
|
||
|
const char *name, s##int##sz##_t *out_value, int *lenp) \
|
||
|
{ \
|
||
|
int err = -FDT_ERR_NOTFOUND; \
|
||
|
if (fdt && nodeoffset >= 0 && name && out_value) \
|
||
|
{ \
|
||
|
const fdt##sz##_t *ptr; \
|
||
|
if ((ptr = fdt_getprop(fdt, nodeoffset, name, lenp))) \
|
||
|
{ \
|
||
|
*out_value = fdt##sz##_to_cpu(*ptr); \
|
||
|
err = 0; \
|
||
|
} \
|
||
|
} \
|
||
|
return err; \
|
||
|
}
|
||
|
|
||
|
#define FDT_RAW_GET_VAL(size) \
|
||
|
FDT_RAW_GET_VAL_FLAG(u, u, size) \
|
||
|
FDT_RAW_GET_VAL_FLAG(s, , size)
|
||
|
|
||
|
FDT_RAW_GET_VAL(64)
|
||
|
FDT_RAW_GET_VAL(32)
|
||
|
FDT_RAW_GET_VAL(16)
|
||
|
FDT_RAW_GET_VAL(8)
|
||
|
|
||
|
#undef FDT_RAW_GET_VAL
|
||
|
#undef FDT_RAW_GET_VAL_FLAG
|
||
|
|
||
|
int fdt_io_addr_cells(void *fdt, int nodeoffset)
|
||
|
{
|
||
|
int cells = -1;
|
||
|
int parentoffset = fdt_parent_offset(fdt, nodeoffset);
|
||
|
|
||
|
for (; parentoffset >= 0 ; parentoffset = fdt_parent_offset(fdt, parentoffset))
|
||
|
{
|
||
|
const fdt32_t *cells_tmp = fdt_getprop(fdt, parentoffset, "#address-cells", NULL);
|
||
|
|
||
|
if (cells_tmp)
|
||
|
{
|
||
|
cells = fdt32_to_cpu(*cells_tmp);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (cells < 0)
|
||
|
{
|
||
|
cells = fdt_address_cells(fdt, nodeoffset);
|
||
|
}
|
||
|
|
||
|
return cells;
|
||
|
}
|
||
|
|
||
|
int fdt_io_size_cells(void *fdt, int nodeoffset)
|
||
|
{
|
||
|
int cells = -1;
|
||
|
int parentoffset = fdt_parent_offset(fdt, nodeoffset);
|
||
|
|
||
|
for (; parentoffset >= 0 ; parentoffset = fdt_parent_offset(fdt, parentoffset))
|
||
|
{
|
||
|
const fdt32_t *cells_tmp = fdt_getprop(fdt, parentoffset, "#size-cells", NULL);
|
||
|
|
||
|
if (cells_tmp)
|
||
|
{
|
||
|
cells = fdt32_to_cpu(*cells_tmp);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (cells < 0)
|
||
|
{
|
||
|
cells = fdt_size_cells(fdt, nodeoffset);
|
||
|
}
|
||
|
|
||
|
return cells;
|
||
|
}
|
||
|
|
||
|
int fdt_install_initrd(void *fdt, char *os_name, size_t initrd_addr, size_t initrd_size)
|
||
|
{
|
||
|
int err = -FDT_ERR_NOTFOUND;
|
||
|
int chosen_offset = -1, root_off = fdt_path_offset(fdt, "/");
|
||
|
|
||
|
if (root_off >= 0)
|
||
|
{
|
||
|
chosen_offset = fdt_subnode_offset(fdt, root_off, "chosen");
|
||
|
|
||
|
if (chosen_offset == -FDT_ERR_NOTFOUND)
|
||
|
{
|
||
|
chosen_offset = fdt_add_subnode_possible(fdt, root_off, "chosen");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (chosen_offset >= 0)
|
||
|
{
|
||
|
uint64_t addr, size;
|
||
|
|
||
|
err = 0;
|
||
|
|
||
|
/* Update the entry */
|
||
|
for (int i = fdt_num_mem_rsv(fdt) - 1; i >= 0; --i)
|
||
|
{
|
||
|
fdt_get_mem_rsv(fdt, i, &addr, &size);
|
||
|
|
||
|
if (addr == initrd_addr)
|
||
|
{
|
||
|
fdt_del_mem_rsv(fdt, i);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Add the memory */
|
||
|
if (fdt_add_mem_rsv(fdt, initrd_addr, initrd_size) < 0)
|
||
|
{
|
||
|
/* Move the memory */
|
||
|
fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + FDT_PADDING_SIZE);
|
||
|
|
||
|
if (fdt_add_mem_rsv(fdt, initrd_addr, initrd_size) < 0)
|
||
|
{
|
||
|
err = -FDT_ERR_NOSPACE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!err)
|
||
|
{
|
||
|
size_t name_len;
|
||
|
char initrd_name[64];
|
||
|
bool is_u64 = (fdt_io_addr_cells(fdt, root_off) == 2);
|
||
|
|
||
|
if (!os_name)
|
||
|
{
|
||
|
os_name = "rt-thread";
|
||
|
}
|
||
|
|
||
|
name_len = strlen(initrd_name);
|
||
|
|
||
|
strncpy(&initrd_name[name_len], ",initrd-start", sizeof(initrd_name) - name_len);
|
||
|
fdt_setprop_uxx(fdt, chosen_offset, initrd_name, initrd_addr, is_u64);
|
||
|
|
||
|
strncpy(&initrd_name[name_len], ",initrd-end", sizeof(initrd_name) - name_len);
|
||
|
fdt_setprop_uxx(fdt, chosen_offset, initrd_name, initrd_addr + initrd_size, is_u64);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return err;
|
||
|
}
|