SPDX: Convert all of our single license tags to Linux Kernel style
[oweals/u-boot.git] / board / synopsys / hsdk / env-lib.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2018 Synopsys, Inc. All rights reserved.
4  * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
5  */
6
7 #include "env-lib.h"
8
9 #define MAX_CMD_LEN     25
10
11 static void env_clear_common(u32 index, const struct env_map_common *map)
12 {
13         map[index].val->val = 0;
14         map[index].val->set = false;
15 }
16
17 static int env_read_common(u32 index, const struct env_map_common *map)
18 {
19         u32 val;
20
21         if (!env_get_yesno(map[index].env_name)) {
22                 if (map[index].type == ENV_HEX) {
23                         val = (u32)env_get_hex(map[index].env_name, 0);
24                         debug("ENV: %s: = %#x\n", map[index].env_name, val);
25                 } else {
26                         val = (u32)env_get_ulong(map[index].env_name, 10, 0);
27                         debug("ENV: %s: = %d\n", map[index].env_name, val);
28                 }
29
30                 map[index].val->val = val;
31                 map[index].val->set = true;
32         }
33
34         return 0;
35 }
36
37 static void env_clear_core(u32 index, const struct env_map_percpu *map)
38 {
39         for (u32 i = 0; i < NR_CPUS; i++) {
40                 (*map[index].val)[i].val = 0;
41                 (*map[index].val)[i].set = false;
42         }
43 }
44
45 static int env_read_core(u32 index, const struct env_map_percpu *map)
46 {
47         u32 val;
48         char command[MAX_CMD_LEN];
49
50         for (u32 i = 0; i < NR_CPUS; i++) {
51                 sprintf(command, "%s_%u", map[index].env_name, i);
52                 if (!env_get_yesno(command)) {
53                         if (map[index].type == ENV_HEX) {
54                                 val = (u32)env_get_hex(command, 0);
55                                 debug("ENV: %s: = %#x\n", command, val);
56                         } else {
57                                 val = (u32)env_get_ulong(command, 10, 0);
58                                 debug("ENV: %s: = %d\n", command, val);
59                         }
60
61                         (*map[index].val)[i].val = val;
62                         (*map[index].val)[i].set = true;
63                 }
64         }
65
66         return 0;
67 }
68
69 static int env_validate_common(u32 index, const struct env_map_common *map)
70 {
71         u32 value = map[index].val->val;
72         bool set = map[index].val->set;
73         u32 min = map[index].min;
74         u32 max = map[index].max;
75
76         /* Check if environment is mandatory */
77         if (map[index].mandatory && !set) {
78                 pr_err("Variable \'%s\' is mandatory, but it is not defined\n",
79                        map[index].env_name);
80
81                 return -EINVAL;
82         }
83
84         /* Check environment boundary */
85         if (set && (value < min || value > max)) {
86                 if (map[index].type == ENV_HEX)
87                         pr_err("Variable \'%s\' must be between %#x and %#x\n",
88                                map[index].env_name, min, max);
89                 else
90                         pr_err("Variable \'%s\' must be between %u and %u\n",
91                                map[index].env_name, min, max);
92
93                 return -EINVAL;
94         }
95
96         return 0;
97 }
98
99 static int env_validate_core(u32 index, const struct env_map_percpu *map,
100                              bool (*cpu_used)(u32))
101 {
102         u32 value;
103         bool set;
104         bool mandatory = map[index].mandatory;
105         u32 min, max;
106
107         for (u32 i = 0; i < NR_CPUS; i++) {
108                 set = (*map[index].val)[i].set;
109                 value = (*map[index].val)[i].val;
110
111                 /* Check if environment is mandatory */
112                 if (cpu_used(i) && mandatory && !set) {
113                         pr_err("CPU %u is used, but \'%s_%u\' is not defined\n",
114                                i, map[index].env_name, i);
115
116                         return -EINVAL;
117                 }
118
119                 min = map[index].min[i];
120                 max = map[index].max[i];
121
122                 /* Check environment boundary */
123                 if (set && (value < min || value > max)) {
124                         if (map[index].type == ENV_HEX)
125                                 pr_err("Variable \'%s_%u\' must be between %#x and %#x\n",
126                                        map[index].env_name, i, min, max);
127                         else
128                                 pr_err("Variable \'%s_%u\' must be between %d and %d\n",
129                                        map[index].env_name, i, min, max);
130
131                         return -EINVAL;
132                 }
133         }
134
135         return 0;
136 }
137
138 void envs_cleanup_core(const struct env_map_percpu *map)
139 {
140         /* Cleanup env struct first */
141         for (u32 i = 0; map[i].env_name; i++)
142                 env_clear_core(i, map);
143 }
144
145 void envs_cleanup_common(const struct env_map_common *map)
146 {
147         /* Cleanup env struct first */
148         for (u32 i = 0; map[i].env_name; i++)
149                 env_clear_common(i, map);
150 }
151
152 int envs_read_common(const struct env_map_common *map)
153 {
154         int ret;
155
156         for (u32 i = 0; map[i].env_name; i++) {
157                 ret = env_read_common(i, map);
158                 if (ret)
159                         return ret;
160         }
161
162         return 0;
163 }
164
165 int envs_validate_common(const struct env_map_common *map)
166 {
167         int ret;
168
169         for (u32 i = 0; map[i].env_name; i++) {
170                 ret = env_validate_common(i, map);
171                 if (ret)
172                         return ret;
173         }
174
175         return 0;
176 }
177
178 int envs_read_validate_common(const struct env_map_common *map)
179 {
180         int ret;
181
182         envs_cleanup_common(map);
183
184         ret = envs_read_common(map);
185         if (ret)
186                 return ret;
187
188         ret = envs_validate_common(map);
189         if (ret)
190                 return ret;
191
192         return 0;
193 }
194
195 int envs_read_validate_core(const struct env_map_percpu *map,
196                             bool (*cpu_used)(u32))
197 {
198         int ret;
199
200         envs_cleanup_core(map);
201
202         for (u32 i = 0; map[i].env_name; i++) {
203                 ret = env_read_core(i, map);
204                 if (ret)
205                         return ret;
206         }
207
208         for (u32 i = 0; map[i].env_name; i++) {
209                 ret = env_validate_core(i, map, cpu_used);
210                 if (ret)
211                         return ret;
212         }
213
214         return 0;
215 }
216
217 int envs_process_and_validate(const struct env_map_common *common,
218                               const struct env_map_percpu *core,
219                               bool (*cpu_used)(u32))
220 {
221         int ret;
222
223         ret = envs_read_validate_common(common);
224         if (ret)
225                 return ret;
226
227         ret = envs_read_validate_core(core, cpu_used);
228         if (ret)
229                 return ret;
230
231         return 0;
232 }
233
234 static int args_envs_read_search(const struct env_map_common *map,
235                                  int argc, char *const argv[])
236 {
237         for (int i = 0; map[i].env_name; i++) {
238                 if (!strcmp(argv[0], map[i].env_name))
239                         return i;
240         }
241
242         pr_err("Unexpected argument '%s', can't parse\n", argv[0]);
243
244         return -ENOENT;
245 }
246
247 static int arg_read_set(const struct env_map_common *map, u32 i, int argc,
248                         char *const argv[])
249 {
250         char *endp = argv[1];
251
252         if (map[i].type == ENV_HEX)
253                 map[i].val->val = simple_strtoul(argv[1], &endp, 16);
254         else
255                 map[i].val->val = simple_strtoul(argv[1], &endp, 10);
256
257         map[i].val->set = true;
258
259         if (*endp == '\0')
260                 return 0;
261
262         pr_err("Unexpected argument '%s', can't parse\n", argv[1]);
263
264         map[i].val->set = false;
265
266         return -EINVAL;
267 }
268
269 int args_envs_enumerate(const struct env_map_common *map, int enum_by,
270                         int argc, char *const argv[])
271 {
272         u32 i;
273
274         if (argc % enum_by) {
275                 pr_err("unexpected argument number: %d\n", argc);
276                 return -EINVAL;
277         }
278
279         while (argc > 0) {
280                 i = args_envs_read_search(map, argc, argv);
281                 if (i < 0)
282                         return i;
283
284                 debug("ARG: found '%s' with index %d\n", map[i].env_name, i);
285
286                 if (i < 0) {
287                         pr_err("unknown arg: %s\n", argv[0]);
288                         return -EINVAL;
289                 }
290
291                 if (arg_read_set(map, i, argc, argv))
292                         return -EINVAL;
293
294                 debug("ARG: value.s '%s' == %#x\n", argv[1], map[i].val->val);
295
296                 argc -= enum_by;
297                 argv += enum_by;
298         }
299
300         return 0;
301 }