198 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			198 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/*
 | 
						|
 * 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;
 | 
						|
}
 |