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