Merge branch 'master' of git://git.denx.de/u-boot-mmc
[platform/kernel/u-boot.git] / arch / sandbox / cpu / state.c
1 /*
2  * Copyright (c) 2011-2012 The Chromium OS Authors.
3  * SPDX-License-Identifier:     GPL-2.0+
4  */
5
6 #include <common.h>
7 #include <errno.h>
8 #include <fdtdec.h>
9 #include <os.h>
10 #include <asm/state.h>
11
12 /* Main state record for the sandbox */
13 static struct sandbox_state main_state;
14 static struct sandbox_state *state;     /* Pointer to current state record */
15
16 void state_record_exit(enum exit_type_id exit_type)
17 {
18         state->exit_type = exit_type;
19 }
20
21 static int state_ensure_space(int extra_size)
22 {
23         void *blob = state->state_fdt;
24         int used, size, free;
25         void *buf;
26         int ret;
27
28         used = fdt_off_dt_strings(blob) + fdt_size_dt_strings(blob);
29         size = fdt_totalsize(blob);
30         free = size - used;
31         if (free > extra_size)
32                 return 0;
33
34         size = used + extra_size;
35         buf = os_malloc(size);
36         if (!buf)
37                 return -ENOMEM;
38
39         ret = fdt_open_into(blob, buf, size);
40         if (ret) {
41                 os_free(buf);
42                 return -EIO;
43         }
44
45         os_free(blob);
46         state->state_fdt = buf;
47         return 0;
48 }
49
50 static int state_read_file(struct sandbox_state *state, const char *fname)
51 {
52         int size;
53         int ret;
54         int fd;
55
56         size = os_get_filesize(fname);
57         if (size < 0) {
58                 printf("Cannot find sandbox state file '%s'\n", fname);
59                 return -ENOENT;
60         }
61         state->state_fdt = os_malloc(size);
62         if (!state->state_fdt) {
63                 puts("No memory to read sandbox state\n");
64                 return -ENOMEM;
65         }
66         fd = os_open(fname, OS_O_RDONLY);
67         if (fd < 0) {
68                 printf("Cannot open sandbox state file '%s'\n", fname);
69                 ret = -EPERM;
70                 goto err_open;
71         }
72         if (os_read(fd, state->state_fdt, size) != size) {
73                 printf("Cannot read sandbox state file '%s'\n", fname);
74                 ret = -EIO;
75                 goto err_read;
76         }
77         os_close(fd);
78
79         return 0;
80 err_read:
81         os_close(fd);
82 err_open:
83         os_free(state->state_fdt);
84         state->state_fdt = NULL;
85
86         return ret;
87 }
88
89 /***
90  * sandbox_read_state_nodes() - Read state associated with a driver
91  *
92  * This looks through all compatible nodes and calls the read function on
93  * each one, to read in the state.
94  *
95  * If nothing is found, it still calls the read function once, to set up a
96  * single global state for that driver.
97  *
98  * @state: Sandbox state
99  * @io: Method to use for reading state
100  * @blob: FDT containing state
101  * @return 0 if OK, -EINVAL if the read function returned failure
102  */
103 int sandbox_read_state_nodes(struct sandbox_state *state,
104                              struct sandbox_state_io *io, const void *blob)
105 {
106         int count;
107         int node;
108         int ret;
109
110         debug("   - read %s\n", io->name);
111         if (!io->read)
112                 return 0;
113
114         node = -1;
115         count = 0;
116         while (blob) {
117                 node = fdt_node_offset_by_compatible(blob, node, io->compat);
118                 if (node < 0)
119                         return 0;       /* No more */
120                 debug("   - read node '%s'\n", fdt_get_name(blob, node, NULL));
121                 ret = io->read(blob, node);
122                 if (ret) {
123                         printf("Unable to read state for '%s'\n", io->compat);
124                         return -EINVAL;
125                 }
126                 count++;
127         }
128
129         /*
130          * If we got no saved state, call the read function once without a
131          * node, to set up the global state.
132          */
133         if (count == 0) {
134                 debug("   - read global\n");
135                 ret = io->read(NULL, -1);
136                 if (ret) {
137                         printf("Unable to read global state for '%s'\n",
138                                io->name);
139                         return -EINVAL;
140                 }
141         }
142
143         return 0;
144 }
145
146 int sandbox_read_state(struct sandbox_state *state, const char *fname)
147 {
148         struct sandbox_state_io *io;
149         const void *blob;
150         bool got_err;
151         int ret;
152
153         if (state->read_state && fname) {
154                 ret = state_read_file(state, fname);
155                 if (ret == -ENOENT && state->ignore_missing_state_on_read)
156                         ret = 0;
157                 if (ret)
158                         return ret;
159         }
160
161         /* Call all the state read funtcions */
162         got_err = false;
163         blob = state->state_fdt;
164         io = ll_entry_start(struct sandbox_state_io, state_io);
165         for (; io < ll_entry_end(struct sandbox_state_io, state_io); io++) {
166                 ret = sandbox_read_state_nodes(state, io, blob);
167                 if (ret < 0)
168                         got_err = true;
169         }
170
171         if (state->read_state && fname) {
172                 debug("Read sandbox state from '%s'%s\n", fname,
173                       got_err ? " (with errors)" : "");
174         }
175
176         return got_err ? -1 : 0;
177 }
178
179 /***
180  * sandbox_write_state_node() - Write state associated with a driver
181  *
182  * This calls the write function to write out global state for that driver.
183  *
184  * TODO(sjg@chromium.org): Support writing out state from multiple drivers
185  * of the same time. We don't need this yet,and it will be much easier to
186  * do when driver model is available.
187  *
188  * @state: Sandbox state
189  * @io: Method to use for writing state
190  * @return 0 if OK, -EIO if there is a fatal error (such as out of space
191  * for adding the data), -EINVAL if the write function failed.
192  */
193 int sandbox_write_state_node(struct sandbox_state *state,
194                              struct sandbox_state_io *io)
195 {
196         void *blob;
197         int node;
198         int ret;
199
200         if (!io->write)
201                 return 0;
202
203         ret = state_ensure_space(SANDBOX_STATE_MIN_SPACE);
204         if (ret) {
205                 printf("Failed to add more space for state\n");
206                 return -EIO;
207         }
208
209         /* The blob location can change when the size increases */
210         blob = state->state_fdt;
211         node = fdt_node_offset_by_compatible(blob, -1, io->compat);
212         if (node == -FDT_ERR_NOTFOUND) {
213                 node = fdt_add_subnode(blob, 0, io->name);
214                 if (node < 0) {
215                         printf("Cannot create node '%s': %s\n", io->name,
216                                fdt_strerror(node));
217                         return -EIO;
218                 }
219
220                 if (fdt_setprop_string(blob, node, "compatible", io->compat)) {
221                         puts("Cannot set compatible\n");
222                         return -EIO;
223                 }
224         } else if (node < 0) {
225                 printf("Cannot access node '%s': %s\n", io->name,
226                        fdt_strerror(node));
227                 return -EIO;
228         }
229         debug("Write state for '%s' to node %d\n", io->compat, node);
230         ret = io->write(blob, node);
231         if (ret) {
232                 printf("Unable to write state for '%s'\n", io->compat);
233                 return -EINVAL;
234         }
235
236         return 0;
237 }
238
239 int sandbox_write_state(struct sandbox_state *state, const char *fname)
240 {
241         struct sandbox_state_io *io;
242         bool got_err;
243         int size;
244         int ret;
245         int fd;
246
247         /* Create a state FDT if we don't have one */
248         if (!state->state_fdt) {
249                 size = 0x4000;
250                 state->state_fdt = os_malloc(size);
251                 if (!state->state_fdt) {
252                         puts("No memory to create FDT\n");
253                         return -ENOMEM;
254                 }
255                 ret = fdt_create_empty_tree(state->state_fdt, size);
256                 if (ret < 0) {
257                         printf("Cannot create empty state FDT: %s\n",
258                                fdt_strerror(ret));
259                         ret = -EIO;
260                         goto err_create;
261                 }
262         }
263
264         /* Call all the state write funtcions */
265         got_err = false;
266         io = ll_entry_start(struct sandbox_state_io, state_io);
267         ret = 0;
268         for (; io < ll_entry_end(struct sandbox_state_io, state_io); io++) {
269                 ret = sandbox_write_state_node(state, io);
270                 if (ret == -EIO)
271                         break;
272                 else if (ret)
273                         got_err = true;
274         }
275
276         if (ret == -EIO) {
277                 printf("Could not write sandbox state\n");
278                 goto err_create;
279         }
280
281         ret = fdt_pack(state->state_fdt);
282         if (ret < 0) {
283                 printf("Cannot pack state FDT: %s\n", fdt_strerror(ret));
284                 ret = -EINVAL;
285                 goto err_create;
286         }
287         size = fdt_totalsize(state->state_fdt);
288         fd = os_open(fname, OS_O_WRONLY | OS_O_CREAT);
289         if (fd < 0) {
290                 printf("Cannot open sandbox state file '%s'\n", fname);
291                 ret = -EIO;
292                 goto err_create;
293         }
294         if (os_write(fd, state->state_fdt, size) != size) {
295                 printf("Cannot write sandbox state file '%s'\n", fname);
296                 ret = -EIO;
297                 goto err_write;
298         }
299         os_close(fd);
300
301         debug("Wrote sandbox state to '%s'%s\n", fname,
302               got_err ? " (with errors)" : "");
303
304         return 0;
305 err_write:
306         os_close(fd);
307 err_create:
308         os_free(state->state_fdt);
309
310         return ret;
311 }
312
313 int state_setprop(int node, const char *prop_name, const void *data, int size)
314 {
315         void *blob;
316         int len;
317         int ret;
318
319         fdt_getprop(state->state_fdt, node, prop_name, &len);
320
321         /* Add space for the new property, its name and some overhead */
322         ret = state_ensure_space(size - len + strlen(prop_name) + 32);
323         if (ret)
324                 return ret;
325
326         /* This should succeed, barring a mutiny */
327         blob = state->state_fdt;
328         ret = fdt_setprop(blob, node, prop_name, data, size);
329         if (ret) {
330                 printf("%s: Unable to set property '%s' in node '%s': %s\n",
331                        __func__, prop_name, fdt_get_name(blob, node, NULL),
332                         fdt_strerror(ret));
333                 return -ENOSPC;
334         }
335
336         return 0;
337 }
338
339 struct sandbox_state *state_get_current(void)
340 {
341         assert(state);
342         return state;
343 }
344
345 int state_init(void)
346 {
347         state = &main_state;
348
349         state->ram_size = CONFIG_SYS_SDRAM_SIZE;
350         state->ram_buf = os_malloc(state->ram_size);
351         assert(state->ram_buf);
352
353         /*
354          * Example of how to use GPIOs:
355          *
356          * sandbox_gpio_set_direction(170, 0);
357          * sandbox_gpio_set_value(170, 0);
358          */
359         return 0;
360 }
361
362 int state_uninit(void)
363 {
364         int err;
365
366         state = &main_state;
367
368         if (state->write_ram_buf) {
369                 err = os_write_ram_buf(state->ram_buf_fname);
370                 if (err) {
371                         printf("Failed to write RAM buffer\n");
372                         return err;
373                 }
374         }
375
376         if (state->write_state) {
377                 if (sandbox_write_state(state, state->state_fname)) {
378                         printf("Failed to write sandbox state\n");
379                         return -1;
380                 }
381         }
382
383         if (state->state_fdt)
384                 os_free(state->state_fdt);
385         memset(state, '\0', sizeof(*state));
386
387         return 0;
388 }