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