]> rtime.felk.cvut.cz Git - fpga/lx-cpu1/lx-rocon.git/blob - sw/app/rocon/appl_distore.c
RoCoN: implement code to setup FPGA and Tumbl from SPI Flash.
[fpga/lx-cpu1/lx-rocon.git] / sw / app / rocon / appl_distore.c
1 #include <string.h>
2 #include <stdint.h>
3
4 #include "appl_defs.h"
5
6 #include "appl_eeprom.h"
7
8 #ifdef CONFIG_OC_I2C_DRV_SYSLESS
9 #include <i2c_drv.h>
10 extern i2c_drv_t i2c_drv;
11 #endif
12
13 #include "distore_simple.h"
14
15 #include <ul_log.h>
16 extern UL_LOG_CUST(ulogd_distore)
17
18 #ifdef APPL_WITH_TIMEPROG_EEPROM_STORE
19 #include "timeprog.h"
20 extern  timeprog_t appl_timeprog_eeprom_identifier;
21 #endif
22
23 #ifdef CONFIG_OC_I2C_DRV_SYSLESS
24
25 void *(*const appl_distore_reserve_ram)(size_t size);
26
27 typedef struct appl_distore_eeprom_context_t
28 {
29   size_t pos;
30   size_t limit;
31   void *buf;
32   const distore_des_array_t *des;
33   int changed: 1;
34   int write2nd: 1;
35   volatile unsigned char check4change;
36   unsigned char gen_cnt;
37   unsigned short area_start;
38   unsigned short area_size;
39
40   appl_eeprom_chip_context_t *chip;
41 } appl_distore_eeprom_context_t;
42
43 ssize_t appl_distore_eeprom_wrfnc(void *context, const void *buf, size_t count)
44 {
45   appl_distore_eeprom_context_t *c = (appl_distore_eeprom_context_t *) context;
46
47   if (c->limit - c->pos < count)
48     return -1;
49
50   if (memcmp((char *) c->buf + c->pos, buf, count))
51     c->changed = 1;
52
53   memcpy((char *) c->buf + c->pos, buf, count);
54   c->pos += count;
55   return count;
56 }
57
58 ssize_t appl_distore_eeprom_rdfnc(void *context, void *buf, size_t count)
59 {
60   appl_distore_eeprom_context_t *c = (appl_distore_eeprom_context_t *) context;
61
62   if (c->limit - c->pos < count)
63     return -1;
64
65   memcpy(buf, (char *) c->buf + c->pos, count);
66   c->pos += count;
67   return count;
68 }
69
70 unsigned int appl_distore_eeprom_chksum(void *data, size_t size)
71 {
72   unsigned int chksum = 0x1234;
73   unsigned char *p = data;
74
75   while (size --)
76   {
77     chksum = (*p ^ chksum) + (*p << 8) + 1;
78     p++;
79   }
80
81   return chksum;
82 }
83
84 int appl_distore_eeprom_load(appl_distore_eeprom_context_t *c)
85 {
86   const distore_des_array_t *des = c->des;
87   unsigned char u[DISTORE_EEPROM_HEADER_SIZE];
88   size_t ma;
89   unsigned int chksum, load_chksum;
90   int res;
91   unsigned char area_bad[2] = {0, 0};
92   unsigned char area_gen_cnt[2];
93   unsigned int area_limit[2];
94   int area_act;
95
96   if (c->buf == NULL)
97     return -1;
98
99   if (c->chip == NULL)
100     return -1;
101
102   for (area_act = 0; area_act < 2; area_act++)
103   {
104     ma = c->area_start + c->area_size * area_act;
105
106     if (appl_eeprom_chip_load(c->chip, ma, u, DISTORE_EEPROM_HEADER_SIZE) < 0)
107     {
108       return -1;
109     }
110
111     if (u[0] != DISTORE_EEPROM_SIGNATURE)
112     {
113       area_bad[area_act] = 1;
114       ul_logmsg("appl_distore_eeprom_load area %d has bad signature\n", area_act);
115       continue;
116     }
117
118     area_gen_cnt[area_act] = u[1];
119     area_limit[area_act] = u[4] | ((unsigned int) u[5] << 8);
120
121     if (c->area_size < area_limit[area_act])
122     {
123       area_bad[area_act] = 1;
124       ul_logmsg("appl_distore_eeprom_load area %d size 0x%lx < stored size 0x%lx\n", area_act,
125                 (unsigned long) c->area_size, (unsigned long) area_limit[area_act]);
126       continue;
127     }
128
129     ul_logdeb("appl_distore_eeprom_load area %d gen_cnt is 0x%x stored size 0x%lx\n",
130               area_act, u[1], (unsigned long) area_limit[area_act]);
131   }
132
133   area_act = 0;
134
135   if ((ul_cyclic_gt(area_gen_cnt[1], area_gen_cnt[0]) && !area_bad[1]) || area_bad[0])
136     area_act = 1;
137
138   for (; 1; area_bad[area_act] = 1, area_act = area_act ^ 1)
139   {
140     if (area_bad[area_act])
141     {
142       ul_logmsg("appl_distore_eeprom_load no valid area found\n");
143       return -1;
144     }
145
146     c->limit = area_limit[area_act];
147
148     ma = c->area_start + c->area_size * area_act;
149
150     if (appl_eeprom_chip_load(c->chip, ma, c->buf, c->limit) < 0)
151     {
152       continue;
153     }
154
155     chksum = appl_distore_eeprom_chksum((unsigned char *) c->buf + 4, c->limit - 4);
156     load_chksum = * ((unsigned char *) c->buf + 2);
157     load_chksum |= * ((unsigned char *) c->buf + 3) << 8;
158
159     if ((chksum ^ load_chksum) & 0xffff)
160     {
161       ul_logmsg("appl_distore_eeprom_load area %d has bad checksum (0x%04x != 0x%04x)\n",
162                 area_act, chksum & 0xffff, load_chksum);
163       continue;
164     }
165
166     c->write2nd = area_act ^ 1;
167     c->gen_cnt = area_gen_cnt[area_act];
168     ul_logdeb("appl_distore_eeprom_load reading data from %d area\n", area_act);
169
170     c->pos = DISTORE_EEPROM_HEADER_SIZE;
171
172     res = distore_load_data(des, appl_distore_eeprom_rdfnc, c,
173                             DISTORE_LOAD_IGNORE_UNKNOWN | DISTORE_LOAD_IGNORE_WRITE_ERR);
174
175     if (res < 0)
176     {
177       ul_logmsg("appl_distore_eeprom_load data decode from %d area failed\n", area_act);
178       continue;
179     }
180     else
181     {
182       ul_logmsg("appl_distore_eeprom_load decoded from %d area\n", area_act);
183     }
184
185     break;
186   }
187
188   return res;
189 }
190
191 int appl_distore_eeprom_init(appl_distore_eeprom_context_t *c)
192 {
193   const distore_des_array_t *des = c->des;
194   ssize_t sz;
195
196   c->buf = NULL;
197   c->limit = 0;
198   c->pos = 0;
199   sz = distore_count_maxsize(des);
200
201   if (sz < 0)
202     return -1;
203
204   if (sz + DISTORE_EEPROM_HEADER_SIZE >= c->area_size)
205   {
206     ul_logerr("appl_distore max_size %ld > EEPROM target area %ld\n",
207               (unsigned long) sz, (unsigned long) c->area_size);
208     return -1;
209   }
210
211   if (appl_distore_reserve_ram != NULL)
212     c->buf = appl_distore_reserve_ram(c->area_size);
213
214   if (c->buf == NULL)
215     c->buf = malloc(c->area_size);
216
217   if (c->buf == NULL)
218   {
219     ul_logerr("appl_distore_eeprom_init RAM allocation failed\n");
220     return -1;
221   }
222
223   memset(c->buf, 0, c->area_size > 16 ? 16 : c->area_size);
224
225   c->limit = c->area_size;
226
227   return 0;
228 }
229
230 int appl_distore_eeprom_store(appl_distore_eeprom_context_t *c, int forced)
231 {
232   int res;
233   unsigned int chksum;
234   unsigned char u[DISTORE_EEPROM_HEADER_SIZE];
235   const distore_des_array_t *des = c->des;
236
237   if (c->buf == NULL)
238     return -1;
239
240   if (c->chip->tx_inpr > 0)
241     return -2;
242
243   c->check4change = 0;
244
245   c->pos = DISTORE_EEPROM_HEADER_SIZE;
246   c->limit = c->area_size;
247
248   c->changed = 0;
249
250   res = distore_store_data(des, appl_distore_eeprom_wrfnc, c);
251
252   if (res < 0)
253   {
254     return -1;
255   }
256
257   if (!c->changed && !forced)
258     return 0;
259
260   c->limit = c->pos;
261
262   /* The length of the data is part of the area covered by checksum */
263   u[4] = c->limit & 0xff;
264   u[5] = c->limit >> 8;
265   c->pos = 4;
266   appl_distore_eeprom_wrfnc(c, u + 4, 2);
267
268   chksum = appl_distore_eeprom_chksum((unsigned char *) c->buf + 4, c->limit - 4);
269
270   u[0] = DISTORE_EEPROM_SIGNATURE;
271   u[1] = (c->gen_cnt + 1) & 0xff;
272   u[2] = chksum & 0xff;
273   u[3] = (chksum >> 8) & 0xff;
274
275   c->pos = 0;
276   appl_distore_eeprom_wrfnc(c, u, DISTORE_EEPROM_HEADER_SIZE);
277
278   c->pos = 0;
279
280   return 1;
281 }
282
283 #endif /*CONFIG_OC_I2C_DRV_SYSLESS*/
284
285 #ifdef APPL_WITH_DISTORE_EEPROM_USER
286 extern const distore_des_array_t appl_distore_eeprom_user_des;
287
288 appl_eeprom_chip_context_t appl_eeprom_chip_context =
289 {
290   .page_size = DISTORE_EEPROM_PAGE,
291   .i2c_drv = &i2c_drv,
292   .i2c_addr = DISTORE_EEPROM_I2C_ADDR,
293 };
294
295 appl_distore_eeprom_context_t appl_distore_eeprom_user_context =
296 {
297   .des = &appl_distore_eeprom_user_des,
298   .area_start = DISTORE_EEPROM_USER_START,
299   .area_size = DISTORE_EEPROM_USER_SIZE,
300   .chip = &appl_eeprom_chip_context,
301 };
302
303 int appl_distore_eeprom_user_finish_callback(struct appl_eeprom_chip_context_t *chip,
304     void *context, int result)
305 {
306   appl_distore_eeprom_context_t *c = (appl_distore_eeprom_context_t *) context;
307
308   ul_loginf("finished distore save with result %d\n", result);
309
310   if (result >= 0)
311   {
312     c->write2nd = (c->write2nd ^ 1) & 1;
313     c->gen_cnt += 1;
314   }
315
316   return 0;
317 }
318
319 #ifdef APPL_WITH_TIMEPROG_EEPROM_STORE
320 int appl_timeprog_eeprom_store_finish_callback(struct appl_eeprom_chip_context_t *chip,
321     void *context, int result)
322 {
323   timeprog_t *timeprog = (timeprog_t *) context;
324
325   ul_loginf("finished timeprog save with result %d\n", result);
326
327   timeprog->save_rq_state = (result >= 0) ? 0 : -1;
328
329   return 0;
330 }
331 #endif /*APPL_WITH_TIMEPROG_EEPROM_STORE*/
332
333 int appl_distore_user_change_check(void)
334 {
335   int res;
336   unsigned int ma;
337   appl_distore_eeprom_context_t *c = &appl_distore_eeprom_user_context;
338   appl_eeprom_chip_context_t *chip = c->chip;
339   int transfer_pend_fl = 0;
340
341   if (chip->tx_inpr > 0)
342     return 2;
343
344 #ifdef APPL_WITH_TIMEPROG_EEPROM_STORE
345
346   if (chip->opstate == APPL_EEPROM_ST_IDLE)
347   {
348     timeprog_t *timeprog = &appl_timeprog_eeprom_identifier;
349
350     if (timeprog->save_rq_state)
351     {
352       long size_to_store = timeprog_size_to_store(timeprog);
353       res = -1;
354
355       if ((size_to_store > 0) && (size_to_store <= TIMEPROG_EEPROM_STORE_SIZE))
356       {
357         res = appl_eeprom_chip_write_transfer_setup(chip, timeprog->region_start,
358               TIMEPROG_EEPROM_STORE_START, size_to_store,
359               appl_timeprog_eeprom_store_finish_callback, timeprog);
360       }
361
362       if (res < 0)
363       {
364         timeprog->save_rq_state = -1;
365       }
366       else
367       {
368         c->check4change = 1;
369         transfer_pend_fl = 1;
370         timeprog_stored_size = size_to_store;
371       }
372     }
373   }
374
375 #endif /*APPL_WITH_TIMEPROG_EEPROM_STORE*/
376
377   if (c->check4change && !transfer_pend_fl)
378   {
379     res = appl_distore_eeprom_store(c, 0);
380
381     if (res < 0)
382       return -1;
383
384     if (res > 0)
385     {
386       ma = c->area_start;
387
388       if (c->write2nd)
389         ma += c->area_size;
390
391       appl_eeprom_chip_write_transfer_setup(chip, c->buf, ma, c->limit,
392                                             appl_distore_eeprom_user_finish_callback, c);
393     }
394   }
395
396   if (chip->opstate == APPL_EEPROM_ST_IDLE)
397     return 0;
398
399   return appl_eeprom_chip_process(chip);
400 }
401
402 int appl_distore_user_set_check4change(void)
403 {
404   appl_distore_eeprom_context_t *c = &appl_distore_eeprom_user_context;
405
406   c->check4change = 1;
407
408   return 0;
409 }
410
411 int appl_distore_user_restore(void)
412 {
413   appl_distore_eeprom_context_t *c = &appl_distore_eeprom_user_context;
414
415   return appl_distore_eeprom_load(c);
416 }
417
418 #ifdef APPL_WITH_TIMEPROG_EEPROM_STORE
419 int appl_timeprog_eeprom_restore(void)
420 {
421   appl_distore_eeprom_context_t *c = &appl_distore_eeprom_user_context;
422   appl_eeprom_chip_context_t *chip = c->chip;
423   timeprog_t *timeprog = &appl_timeprog_eeprom_identifier;
424   long sz = timeprog_stored_size;
425
426   if ((timeprog->region_limit == NULL) || (timeprog->region_start == NULL))
427     return -1;
428
429   if ((sz <= 0) || (sz > (char *) timeprog->region_limit - (char *) timeprog->region_start))
430     return -1;
431
432   if (sz > TIMEPROG_EEPROM_STORE_SIZE)
433     return -1;
434
435   timeprog->preprocess_state = TIMEPROG_PPST_MODIFIED;
436   __memory_barrier();
437
438   if (appl_eeprom_chip_load(chip, TIMEPROG_EEPROM_STORE_START, timeprog->region_start, sz) < 0)
439   {
440     size_t region_size = timeprog->region_limit - timeprog->region_start;
441     memset(timeprog->region_start, 0, region_size);
442     timeprog->gen_cnt++;
443     return -1;
444   }
445
446   timeprog->gen_cnt++;
447
448   if (!timeprog_actual_is_empty(timeprog))
449     timeprog_end_and_prepare(timeprog);
450
451   return 0;
452 }
453 #endif /*APPL_WITH_TIMEPROG_EEPROM_STORE*/
454
455
456 int appl_distore_init(void)
457 {
458   appl_distore_eeprom_context_t *c = &appl_distore_eeprom_user_context;
459
460   if (appl_eeprom_chip_init(c->chip) < 0)
461   {
462     return -1;
463   }
464
465   return appl_distore_eeprom_init(c);
466 }
467
468 #endif /* APPL_WITH_DISTORE_EEPROM_USER */