diff options
author | 2025-03-08 22:04:20 +0800 | |
---|---|---|
committer | 2025-03-08 22:04:20 +0800 | |
commit | a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a (patch) | |
tree | 84f21bd0bf7071bc5fc7dd989e77d7ceb5476682 /arch/mips/generic/yamon-dt.c | |
download | ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.tar.gz ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.zip |
Initial commit: OpenHarmony-v4.0-ReleaseOpenHarmony-v4.0-Release
Diffstat (limited to 'arch/mips/generic/yamon-dt.c')
-rw-r--r-- | arch/mips/generic/yamon-dt.c | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/arch/mips/generic/yamon-dt.c b/arch/mips/generic/yamon-dt.c new file mode 100644 index 000000000..a07a5edbc --- /dev/null +++ b/arch/mips/generic/yamon-dt.c | |||
@@ -0,0 +1,232 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * Copyright (C) 2016 Imagination Technologies | ||
4 | * Author: Paul Burton <paul.burton@mips.com> | ||
5 | */ | ||
6 | |||
7 | #define pr_fmt(fmt) "yamon-dt: " fmt | ||
8 | |||
9 | #include <linux/bug.h> | ||
10 | #include <linux/errno.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/libfdt.h> | ||
13 | #include <linux/printk.h> | ||
14 | |||
15 | #include <asm/fw/fw.h> | ||
16 | #include <asm/yamon-dt.h> | ||
17 | |||
18 | #define MAX_MEM_ARRAY_ENTRIES 2 | ||
19 | |||
20 | __init int yamon_dt_append_cmdline(void *fdt) | ||
21 | { | ||
22 | int err, chosen_off; | ||
23 | |||
24 | /* find or add chosen node */ | ||
25 | chosen_off = fdt_path_offset(fdt, "/chosen"); | ||
26 | if (chosen_off == -FDT_ERR_NOTFOUND) | ||
27 | chosen_off = fdt_add_subnode(fdt, 0, "chosen"); | ||
28 | if (chosen_off < 0) { | ||
29 | pr_err("Unable to find or add DT chosen node: %d\n", | ||
30 | chosen_off); | ||
31 | return chosen_off; | ||
32 | } | ||
33 | |||
34 | err = fdt_setprop_string(fdt, chosen_off, "bootargs", fw_getcmdline()); | ||
35 | if (err) { | ||
36 | pr_err("Unable to set bootargs property: %d\n", err); | ||
37 | return err; | ||
38 | } | ||
39 | |||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | static unsigned int __init gen_fdt_mem_array( | ||
44 | const struct yamon_mem_region *regions, | ||
45 | __be32 *mem_array, | ||
46 | unsigned int max_entries, | ||
47 | unsigned long memsize) | ||
48 | { | ||
49 | const struct yamon_mem_region *mr; | ||
50 | unsigned long size; | ||
51 | unsigned int entries = 0; | ||
52 | |||
53 | for (mr = regions; mr->size && memsize; ++mr) { | ||
54 | if (entries >= max_entries) { | ||
55 | pr_warn("Number of regions exceeds max %u\n", | ||
56 | max_entries); | ||
57 | break; | ||
58 | } | ||
59 | |||
60 | /* How much of the remaining RAM fits in the next region? */ | ||
61 | size = min_t(unsigned long, memsize, mr->size); | ||
62 | memsize -= size; | ||
63 | |||
64 | /* Emit a memory region */ | ||
65 | *(mem_array++) = cpu_to_be32(mr->start); | ||
66 | *(mem_array++) = cpu_to_be32(size); | ||
67 | ++entries; | ||
68 | |||
69 | /* Discard the next mr->discard bytes */ | ||
70 | memsize -= min_t(unsigned long, memsize, mr->discard); | ||
71 | } | ||
72 | return entries; | ||
73 | } | ||
74 | |||
75 | __init int yamon_dt_append_memory(void *fdt, | ||
76 | const struct yamon_mem_region *regions) | ||
77 | { | ||
78 | unsigned long phys_memsize = 0, memsize; | ||
79 | __be32 mem_array[2 * MAX_MEM_ARRAY_ENTRIES]; | ||
80 | unsigned int mem_entries; | ||
81 | int i, err, mem_off; | ||
82 | char *var, param_name[10], *var_names[] = { | ||
83 | "ememsize", "memsize", | ||
84 | }; | ||
85 | |||
86 | /* find memory size from the bootloader environment */ | ||
87 | for (i = 0; i < ARRAY_SIZE(var_names); i++) { | ||
88 | var = fw_getenv(var_names[i]); | ||
89 | if (!var) | ||
90 | continue; | ||
91 | |||
92 | err = kstrtoul(var, 0, &phys_memsize); | ||
93 | if (!err) | ||
94 | break; | ||
95 | |||
96 | pr_warn("Failed to read the '%s' env variable '%s'\n", | ||
97 | var_names[i], var); | ||
98 | } | ||
99 | |||
100 | if (!phys_memsize) { | ||
101 | pr_warn("The bootloader didn't provide memsize: defaulting to 32MB\n"); | ||
102 | phys_memsize = 32 << 20; | ||
103 | } | ||
104 | |||
105 | /* default to using all available RAM */ | ||
106 | memsize = phys_memsize; | ||
107 | |||
108 | /* allow the user to override the usable memory */ | ||
109 | for (i = 0; i < ARRAY_SIZE(var_names); i++) { | ||
110 | snprintf(param_name, sizeof(param_name), "%s=", var_names[i]); | ||
111 | var = strstr(arcs_cmdline, param_name); | ||
112 | if (!var) | ||
113 | continue; | ||
114 | |||
115 | memsize = memparse(var + strlen(param_name), NULL); | ||
116 | } | ||
117 | |||
118 | /* if the user says there's more RAM than we thought, believe them */ | ||
119 | phys_memsize = max_t(unsigned long, phys_memsize, memsize); | ||
120 | |||
121 | /* find or add a memory node */ | ||
122 | mem_off = fdt_path_offset(fdt, "/memory"); | ||
123 | if (mem_off == -FDT_ERR_NOTFOUND) | ||
124 | mem_off = fdt_add_subnode(fdt, 0, "memory"); | ||
125 | if (mem_off < 0) { | ||
126 | pr_err("Unable to find or add memory DT node: %d\n", mem_off); | ||
127 | return mem_off; | ||
128 | } | ||
129 | |||
130 | err = fdt_setprop_string(fdt, mem_off, "device_type", "memory"); | ||
131 | if (err) { | ||
132 | pr_err("Unable to set memory node device_type: %d\n", err); | ||
133 | return err; | ||
134 | } | ||
135 | |||
136 | mem_entries = gen_fdt_mem_array(regions, mem_array, | ||
137 | MAX_MEM_ARRAY_ENTRIES, phys_memsize); | ||
138 | err = fdt_setprop(fdt, mem_off, "reg", | ||
139 | mem_array, mem_entries * 2 * sizeof(mem_array[0])); | ||
140 | if (err) { | ||
141 | pr_err("Unable to set memory regs property: %d\n", err); | ||
142 | return err; | ||
143 | } | ||
144 | |||
145 | mem_entries = gen_fdt_mem_array(regions, mem_array, | ||
146 | MAX_MEM_ARRAY_ENTRIES, memsize); | ||
147 | err = fdt_setprop(fdt, mem_off, "linux,usable-memory", | ||
148 | mem_array, mem_entries * 2 * sizeof(mem_array[0])); | ||
149 | if (err) { | ||
150 | pr_err("Unable to set linux,usable-memory property: %d\n", err); | ||
151 | return err; | ||
152 | } | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | __init int yamon_dt_serial_config(void *fdt) | ||
158 | { | ||
159 | const char *yamontty, *mode_var; | ||
160 | char mode_var_name[9], path[20], parity; | ||
161 | unsigned int uart, baud, stop_bits; | ||
162 | bool hw_flow; | ||
163 | int chosen_off, err; | ||
164 | |||
165 | yamontty = fw_getenv("yamontty"); | ||
166 | if (!yamontty || !strcmp(yamontty, "tty0")) { | ||
167 | uart = 0; | ||
168 | } else if (!strcmp(yamontty, "tty1")) { | ||
169 | uart = 1; | ||
170 | } else { | ||
171 | pr_warn("yamontty environment variable '%s' invalid\n", | ||
172 | yamontty); | ||
173 | uart = 0; | ||
174 | } | ||
175 | |||
176 | baud = stop_bits = 0; | ||
177 | parity = 0; | ||
178 | hw_flow = false; | ||
179 | |||
180 | snprintf(mode_var_name, sizeof(mode_var_name), "modetty%u", uart); | ||
181 | mode_var = fw_getenv(mode_var_name); | ||
182 | if (mode_var) { | ||
183 | while (mode_var[0] >= '0' && mode_var[0] <= '9') { | ||
184 | baud *= 10; | ||
185 | baud += mode_var[0] - '0'; | ||
186 | mode_var++; | ||
187 | } | ||
188 | if (mode_var[0] == ',') | ||
189 | mode_var++; | ||
190 | if (mode_var[0]) | ||
191 | parity = mode_var[0]; | ||
192 | if (mode_var[0] == ',') | ||
193 | mode_var++; | ||
194 | if (mode_var[0]) | ||
195 | stop_bits = mode_var[0] - '0'; | ||
196 | if (mode_var[0] == ',') | ||
197 | mode_var++; | ||
198 | if (!strcmp(mode_var, "hw")) | ||
199 | hw_flow = true; | ||
200 | } | ||
201 | |||
202 | if (!baud) | ||
203 | baud = 38400; | ||
204 | |||
205 | if (parity != 'e' && parity != 'n' && parity != 'o') | ||
206 | parity = 'n'; | ||
207 | |||
208 | if (stop_bits != 7 && stop_bits != 8) | ||
209 | stop_bits = 8; | ||
210 | |||
211 | WARN_ON(snprintf(path, sizeof(path), "serial%u:%u%c%u%s", | ||
212 | uart, baud, parity, stop_bits, | ||
213 | hw_flow ? "r" : "") >= sizeof(path)); | ||
214 | |||
215 | /* find or add chosen node */ | ||
216 | chosen_off = fdt_path_offset(fdt, "/chosen"); | ||
217 | if (chosen_off == -FDT_ERR_NOTFOUND) | ||
218 | chosen_off = fdt_add_subnode(fdt, 0, "chosen"); | ||
219 | if (chosen_off < 0) { | ||
220 | pr_err("Unable to find or add DT chosen node: %d\n", | ||
221 | chosen_off); | ||
222 | return chosen_off; | ||
223 | } | ||
224 | |||
225 | err = fdt_setprop_string(fdt, chosen_off, "stdout-path", path); | ||
226 | if (err) { | ||
227 | pr_err("Unable to set stdout-path property: %d\n", err); | ||
228 | return err; | ||
229 | } | ||
230 | |||
231 | return 0; | ||
232 | } | ||