1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include "libfdt.h"
7 #include "dtb_node.h"
8 
dtb_node_find_and_add_subnode(void * fdt,char * name)9 static off_t dtb_node_find_and_add_subnode(void *fdt, char* name)
10 {
11     off_t chosen_offset = 0;
12 
13     chosen_offset = fdt_subnode_offset(fdt, 0, name);
14 
15     if (chosen_offset == -FDT_ERR_NOTFOUND)
16     {
17         chosen_offset = fdt_add_subnode(fdt, 0, name);
18     }
19 
20     return chosen_offset;
21 }
22 
dtb_node_set_linux_cmdline(void * fdt,char * cmdline)23 size_t dtb_node_set_linux_cmdline(void *fdt, char *cmdline)
24 {
25     off_t chosen_offset;
26     size_t cmdline_size;
27 
28     if (cmdline == NULL || fdt == NULL)
29     {
30         goto end;
31     }
32 
33     chosen_offset = dtb_node_find_and_add_subnode(fdt, "chosen");
34     cmdline_size = strlen(cmdline);
35 
36     /* install bootargs */
37     if (chosen_offset >= 0 || chosen_offset == -FDT_ERR_EXISTS)
38     {
39         if (fdt_setprop(fdt, chosen_offset, "bootargs", cmdline, cmdline_size) < 0)
40         {
41             fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + FDT_DTB_PAD_SIZE);
42             fdt_setprop(fdt, chosen_offset, "bootargs", cmdline, cmdline_size);
43         }
44     }
45 
46 end:
47     return fdt_totalsize(fdt);
48 }
49 
dtb_node_set_linux_initrd(void * fdt,uint64_t initrd_addr,size_t initrd_size)50 size_t dtb_node_set_linux_initrd(void *fdt, uint64_t initrd_addr, size_t initrd_size)
51 {
52     uint64_t addr, size_ptr;
53     off_t chosen_offset;
54     int i;
55 
56     if (fdt == NULL)
57     {
58         goto end;
59     }
60 
61     chosen_offset = dtb_node_find_and_add_subnode(fdt, "chosen");
62 
63     /* update the entry */
64     for (i = fdt_num_mem_rsv(fdt) - 1; i >= 0; --i)
65     {
66         fdt_get_mem_rsv(fdt, i, &addr, &size_ptr);
67         if (addr == initrd_addr)
68         {
69             fdt_del_mem_rsv(fdt, i);
70             break;
71         }
72     }
73 
74     /* add the memory */
75     if (fdt_add_mem_rsv(fdt, initrd_addr, initrd_size) < 0)
76     {
77         /* move the memory */
78         fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + FDT_DTB_PAD_SIZE);
79         if (fdt_add_mem_rsv(fdt, initrd_addr, initrd_size) < 0)
80         {
81             goto end;
82         }
83     }
84 
85     /* install initrd */
86     if (chosen_offset >= 0 || chosen_offset == -FDT_ERR_EXISTS)
87     {
88         chosen_offset = fdt_path_offset(fdt, "/chosen");
89 
90         if (IN_64BITS_MODE)
91         {
92             fdt_setprop_u64(fdt, chosen_offset, "linux,initrd-start", initrd_addr);
93             fdt_setprop_u64(fdt, chosen_offset, "linux,initrd-end", initrd_addr + initrd_size);
94         }
95         else
96         {
97             fdt_setprop_u32(fdt, chosen_offset, "linux,initrd-start", initrd_addr);
98             fdt_setprop_u32(fdt, chosen_offset, "linux,initrd-end", initrd_addr + initrd_size);
99         }
100     }
101 
102 end:
103     return fdt_totalsize(fdt);
104 }
105 
dtb_node_set_dtb_property(void * fdt,char * pathname,char * property_name,uint32_t * cells,size_t cells_size)106 size_t dtb_node_set_dtb_property(void *fdt, char *pathname, char *property_name, uint32_t *cells, size_t cells_size)
107 {
108     int node_off;
109 
110     if (fdt == NULL)
111     {
112         goto end;
113     }
114 
115     node_off = fdt_path_offset(fdt, pathname);
116 
117     if (node_off >= 0 && cells_size != 0)
118     {
119         fdt_setprop(fdt, node_off, property_name, cells, cells_size);
120     }
121 
122 end:
123     return fdt_totalsize(fdt);
124 }
125 
dtb_node_add_dtb_memreserve(void * fdt,uint64_t address,uint64_t size)126 size_t dtb_node_add_dtb_memreserve(void *fdt, uint64_t address, uint64_t size)
127 {
128     if (fdt == NULL)
129     {
130         goto end;
131     }
132 
133     fdt_add_mem_rsv(fdt, address, size);
134 
135 end:
136     return fdt_totalsize(fdt);
137 }
138 
dtb_node_del_dtb_memreserve(void * fdt,uint64_t address)139 size_t dtb_node_del_dtb_memreserve(void *fdt, uint64_t address)
140 {
141     int i;
142     int num_mem_rsvmap;
143     uint32_t off_mem_rsvmap;
144     struct fdt_reserve_entry *rsvmap;
145 
146     if (fdt == NULL)
147     {
148         goto end;
149     }
150 
151     num_mem_rsvmap = fdt_num_mem_rsv(fdt);
152     off_mem_rsvmap = fdt_off_mem_rsvmap(fdt);
153     rsvmap = (struct fdt_reserve_entry *)((char *)fdt + off_mem_rsvmap);
154 
155     for (i = 0; i < num_mem_rsvmap; ++i)
156     {
157         if (address == fdt64_to_cpu(rsvmap[i].address))
158         {
159             fdt_del_mem_rsv(fdt, i);
160             break;
161         }
162     }
163 
164 end:
165     return fdt_totalsize(fdt);
166 }
167