/* * 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 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; }