• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #include "eeprom_emulation.h"
13 #include "hpm_crc32.h"
14 
15 #define E2P_OFFSET(TYPE, MEMBER) ((uint32_t)(&(((TYPE *)0)->MEMBER)))
16 #define E2P_SWAP(a, b)\
17 do {\
18     uint32_t tmp = (a);\
19     (a) = (b);\
20     (b) = tmp;\
21 } while (0)
22 
23 static e2p_block e2p_info_table[E2P_MAX_VAR_CNT];
24 
e2p_print_info(e2p_t * e2p)25 static void e2p_print_info(e2p_t *e2p)
26 {
27     uint32_t info_count;
28     uint32_t valid_count = E2P_MAX_VAR_CNT;
29 
30     info_count = (e2p->config.start_addr + e2p->config.sector_cnt * e2p->config.erase_size - e2p->p_info) / sizeof(e2p_block) - 2;
31     for (int i = 0; i < E2P_MAX_VAR_CNT; i++) {
32         if (e2p_info_table[i].block_id == E2P_EARSED_ID) {
33             valid_count = i;
34             break;
35         }
36     }
37 
38     e2p_info("------------ flash->eeprom init ok -----------\n");
39     e2p_info("start address: 0x%08x", e2p->config.start_addr);
40     e2p_info("sector count: %u", e2p->config.sector_cnt);
41     e2p_info("flash earse granularity: %u", e2p->config.erase_size);
42     e2p_info("version: 0x%x", e2p->config.version);
43     e2p_info("end address: 0x%08x", e2p->config.start_addr + e2p->config.sector_cnt * e2p->config.erase_size);
44     e2p_info("data write addr = 0x%08x, info write addr = 0x%08x, remain flash size = 0x%x\n", \
45             e2p->p_data, e2p->p_info, e2p->remain_size);
46     e2p_info("valid count percent info count( %u / %u )\n", valid_count, info_count);
47     e2p_info("----------------------------------------------\n");
48 }
49 
e2p_table_update(e2p_block * block)50 static hpm_stat_t e2p_table_update(e2p_block *block)
51 {
52     uint32_t i = 0;
53 
54     if (block->valid_state == e2p_invalid)
55         return E2P_STATUS_OK;
56 
57     for ( ; i < E2P_MAX_VAR_CNT; i++) {
58         if (e2p_info_table[i].block_id == E2P_EARSED_ID)
59             break;
60         if (e2p_info_table[i].block_id == block->block_id) {
61             e2p_trace("block_id[0x%08x] multiple write, flush api solve repeat\n", block->block_id);
62             break;
63         }
64     }
65 
66     if (i == E2P_MAX_VAR_CNT)
67         return E2P_ERROR_MUL_VAR;
68 
69     memcpy(&e2p_info_table[i], block, sizeof(e2p_block));
70     return E2P_STATUS_OK;
71 }
72 
e2p_config_info(e2p_t * e2p)73 static void e2p_config_info(e2p_t *e2p)
74 {
75     e2p_block block;
76     e2p_config_t *cfg = &e2p->config;
77     uint32_t end_addr = cfg->start_addr + cfg->sector_cnt * cfg->erase_size;
78 
79     memset(&block, E2P_EARSED_VAR, sizeof(e2p_block));
80     block.block_id = cfg->version;
81     block.data_addr = E2P_MAGIC_ID;
82     cfg->flash_write((uint8_t *)&block, end_addr - sizeof(e2p_block), sizeof(e2p_block));
83     e2p_trace("e2p info has been config\n");
84 }
85 
e2p_data_crc_calc(uint16_t length,uint8_t * data)86 static uint32_t e2p_data_crc_calc(uint16_t length, uint8_t *data)
87 {
88     return crc32(data, (uint32_t)length);
89 }
90 
e2p_retrieve_info(uint32_t block_id,e2p_block * block)91 static hpm_stat_t e2p_retrieve_info(uint32_t block_id, e2p_block *block)
92 {
93     int i = 0;
94 
95     if (block_id == E2P_EARSED_ID)
96         return E2P_ERROR_BAD_ID;
97 
98     for ( ; i < E2P_MAX_VAR_CNT; i++) {
99         if (e2p_info_table[i].block_id == block_id) {
100             e2p_trace("find read block, pos at table[%u]\n", i);
101             memcpy(block, &e2p_info_table[i], sizeof(e2p_block));
102             break;
103         }
104     }
105 
106     return (i == E2P_MAX_VAR_CNT ? E2P_ERROR_BAD_ID : E2P_STATUS_OK);
107 }
108 
109 
e2p_write_private(e2p_t * e2p,uint32_t block_id,uint16_t length,uint8_t * data)110 static hpm_stat_t e2p_write_private(e2p_t *e2p, uint32_t block_id, uint16_t length, uint8_t *data)
111 {
112     int ret = 0;
113     e2p_block block;
114     e2p_config_t *cfg = &e2p->config;
115 
116     if (e2p->remain_size < length + sizeof(e2p_block)) {
117         e2p_trace("no enough flash\n");
118         return E2P_ERROR_NO_MEM;
119     }
120 
121     block.block_id = block_id;
122     block.data_addr = e2p->p_data;
123     block.length = length;
124     block.valid_state = e2p_valid;
125     block.crc = e2p_data_crc_calc(length, data);
126 
127     if (E2P_STATUS_OK != cfg->flash_write(data, e2p->p_data, length)) {
128         e2p_trace("flash write data error\n");
129         return E2P_ERROR;
130     }
131     e2p->p_data += length;
132     e2p->remain_size -= length;
133 
134     if (E2P_STATUS_OK != cfg->flash_write((uint8_t *)&block, e2p->p_info, sizeof(e2p_block))) {
135         e2p_trace("flash write info error\n");
136         return E2P_ERROR;
137     }
138     e2p->p_info -= sizeof(e2p_block);
139     e2p->remain_size -= sizeof(e2p_block);
140 
141     ret = e2p_table_update(&block);
142     if (E2P_STATUS_OK != ret)
143         return ret;
144 
145     e2p_info("block_id[0x%08x] success write, data addr=0x%08x, remain size=0x%08x crc=0x%08x\n", block.block_id, block.data_addr, e2p->remain_size, block.crc);
146     return E2P_STATUS_OK;
147 }
148 
e2p_info_table_sort(void)149 static int e2p_info_table_sort(void)
150 {
151     int count = 0;
152     e2p_block block;
153 
154     do {
155         if (e2p_info_table[count].block_id == E2P_EARSED_ID) {
156             break;
157         }
158         count++;
159     } while (count < E2P_MAX_VAR_CNT);
160 
161     if (count == 0)
162         return count;
163 
164     for (int i = 0; i < count; i++) {
165         memcpy(&block, &e2p_info_table[i], sizeof(e2p_block));
166         for (int j = i + 1; j < count; j++) {
167             if (e2p_info_table[j].data_addr < block.data_addr) {
168                 E2P_SWAP(e2p_info_table[j].block_id, block.block_id);
169                 E2P_SWAP(e2p_info_table[j].data_addr, block.data_addr);
170                 E2P_SWAP(e2p_info_table[j].length, block.length);
171                 E2P_SWAP(e2p_info_table[j].valid_state, block.valid_state);
172                 E2P_SWAP(e2p_info_table[j].crc, block.crc);
173             }
174         }
175         memcpy(&e2p_info_table[i], &block, sizeof(e2p_block));
176     }
177 
178     return count;
179 }
180 
e2p_earse_info_sector(e2p_t * e2p)181 static void e2p_earse_info_sector(e2p_t *e2p)
182 {
183     uint32_t data_sec_num, info_sec_num;
184     uint32_t addr, size;
185     e2p_config_t *cfg = &e2p->config;
186 
187     data_sec_num = (e2p->p_data - cfg->start_addr) / cfg->erase_size;
188     info_sec_num = (e2p->p_info - cfg->start_addr) / cfg->erase_size;
189     addr = e2p->p_info - (e2p->p_info % cfg->erase_size);
190     size = (cfg->sector_cnt - info_sec_num) * cfg->erase_size;
191 
192     e2p_trace("data_sector=%u, info_sector=%u, addr=0x%08x, size=0x%08x", data_sec_num, info_sec_num, addr, size);
193 
194     if (data_sec_num < info_sec_num) {
195         cfg->flash_erase(addr, size);
196     } else {
197         uint8_t data_buf[cfg->erase_size];
198         uint32_t remain_size = e2p->p_info % cfg->erase_size;
199         memset(data_buf, E2P_EARSED_VAR, sizeof(data_buf));
200 
201         e2p_trace("data tail[0x%08x] and info tail[0x%08x] in same sector\n", e2p->p_data, e2p->p_info);
202         cfg->flash_read(data_buf, addr, remain_size);
203         cfg->flash_erase(addr, size);
204         cfg->flash_write(data_buf, addr, sizeof(data_buf));
205     }
206 }
207 
e2p_config(e2p_t * e2p)208 hpm_stat_t e2p_config(e2p_t *e2p)
209 {
210     if (e2p->config.erase_size == 0 || e2p->config.sector_cnt == 0) {
211         e2p_info("config error erase_size = %u, sector_cnt = %u\n", e2p->config.erase_size, e2p->config.sector_cnt);
212         return E2P_ERROR_INIT_ERR;
213     }
214 
215     if (e2p->config.flash_read == NULL || e2p->config.flash_write == NULL || e2p->config.flash_erase == NULL) {
216         e2p_info("Not register operate function read = %p, write = %p, erase = %p", \
217                       e2p->config.flash_read, e2p->config.flash_write, e2p->config.flash_erase);
218         return E2P_ERROR_INIT_ERR;
219     }
220 
221     e2p_block block;
222     e2p_config_t *cfg = &e2p->config;
223 
224     e2p->p_data = cfg->start_addr;
225     e2p->p_info = cfg->start_addr + cfg->sector_cnt * cfg->erase_size - 2 * sizeof(e2p_block);
226     e2p->remain_size = e2p->p_info - e2p->p_data;
227     memset(e2p_info_table, E2P_EARSED_VAR, sizeof(e2p_info_table));
228 
229     cfg->flash_read((uint8_t *)&block, e2p->p_info + sizeof(e2p_block), sizeof(e2p_block));
230     e2p_trace("read data, block_id=%x, addr=%x, length=%x, valid_state=%x, crc=%x\n", \
231               block.block_id, block.data_addr, block.length, block.valid_state, block.crc);
232 
233     if (block.block_id != cfg->version || block.data_addr != E2P_MAGIC_ID) {
234         e2p_info("check version failed, begin earse all sector, it will take some time\n");
235         cfg->flash_erase(e2p->p_data, cfg->sector_cnt * cfg->erase_size);
236         e2p_config_info(e2p);
237         e2p_print_info(e2p);
238         return E2P_STATUS_OK;
239     }
240 
241     while (1) {
242         block.data_addr = e2p->p_info;
243         block.length = sizeof(e2p_block);
244 
245         cfg->flash_read((uint8_t *)&block, block.data_addr, block.length);
246         if (block.block_id == E2P_EARSED_ID)
247             break;
248 
249         int ret = e2p_table_update(&block);
250         if (E2P_STATUS_OK != ret)
251             return ret;
252 
253         e2p->p_data += block.length;
254         e2p->p_info -= sizeof(e2p_block);
255         e2p->remain_size -= (block.length + sizeof(e2p_block));
256 
257         if (e2p->remain_size < 2 * sizeof(e2p_block)) {
258             e2p_trace("remain flash is not enough\n");
259             return E2P_ERROR_NO_MEM;
260         }
261     }
262 
263     e2p_print_info(e2p);
264     return E2P_STATUS_OK;
265 }
266 
e2p_flush(e2p_t * e2p,uint8_t flag)267 hpm_stat_t e2p_flush(e2p_t *e2p, uint8_t flag)
268 {
269     if (e2p->config.erase_size < e2p->remain_size && flag == 0) {
270         e2p_trace("no need arrange flash\n");
271         return E2P_STATUS_OK;
272     }
273     e2p_config_t *cfg = &e2p->config;
274 
275     e2p_earse_info_sector(e2p);
276 
277     e2p->p_data = cfg->start_addr;
278     e2p->p_info = cfg->start_addr + cfg->sector_cnt * cfg->erase_size - 2 * sizeof(e2p_block);
279     e2p->remain_size = e2p->p_info - e2p->p_data;
280 
281     int read_len = 0;
282     int count = 0;
283     uint32_t head, tail;
284     uint8_t read_buf[cfg->erase_size * 2];
285     int valid_num = e2p_info_table_sort();
286 
287     tail = e2p->p_data;
288     for (int i = 0; i < valid_num;) {
289         head = tail;
290 
291         while (1) {
292             if (e2p_info_table[i].block_id == E2P_EARSED_ID || i >= valid_num) {
293                 e2p_trace("e2p blank[%u], need flush num[%u]\n", i, valid_num);
294                 break;
295             }
296             cfg->flash_read(read_buf + read_len, e2p_info_table[i].data_addr, e2p_info_table[i].length);
297             read_len += e2p_info_table[i].length;
298             tail = e2p_info_table[i].data_addr + e2p_info_table[i].length;
299             i++;
300             if (read_len >= cfg->erase_size)
301                 break;
302         }
303 
304         e2p_trace("---- transfer data to buffer: len=%u\n", read_len);
305 
306         do {
307             cfg->flash_erase(head, cfg->erase_size);
308             head += cfg->erase_size;
309         } while (head + cfg->erase_size <= tail);
310 
311         tail = head;
312         uint8_t *pdata = read_buf;
313         while (count < i) {
314             if (e2p_info_table[count].block_id == E2P_EARSED_ID || e2p->p_data + e2p_info_table[i].length >= tail) {
315                 e2p_trace("write back suspend, write stop at 0x%08x/0x0%x\n", e2p->p_data, read_len);
316                 break;
317             }
318 
319             e2p_write_private(e2p, e2p_info_table[count].block_id, e2p_info_table[count].length, pdata);
320             pdata += e2p_info_table[count].length;
321             count++;
322         }
323 
324         e2p_trace("-----write data back: len=%u\n", pdata - read_buf);
325 
326         read_len -= (pdata - read_buf);
327         if (read_len)
328             memmove(read_buf, pdata, read_len);
329     }
330 
331     while (tail < e2p->p_info - cfg->erase_size) {
332         cfg->flash_erase(tail, cfg->erase_size);
333         tail += cfg->erase_size;
334     }
335 
336     uint8_t *ptr = read_buf;
337     while (read_len) {
338         e2p_trace("remain write back[%u], block_id[%x], data_addr[%x], length[%u], valid_state[%u], crc[%x]\n", \
339             count, e2p_info_table[count].block_id, e2p_info_table[count].data_addr, e2p_info_table[count].length, e2p_info_table[count].valid_state, e2p_info_table[count].crc);
340         e2p_write_private(e2p, e2p_info_table[count].block_id, e2p_info_table[count].length, ptr);
341         read_len -= e2p_info_table[count].length;
342         ptr += e2p_info_table[count].length;
343         count++;
344     }
345 
346     e2p_config_info(e2p);
347     return E2P_STATUS_OK;
348 }
349 
e2p_write(e2p_t * e2p,uint32_t block_id,uint16_t length,uint8_t * data)350 hpm_stat_t e2p_write(e2p_t *e2p, uint32_t block_id, uint16_t length, uint8_t *data)
351 {
352     if (e2p->remain_size < length + sizeof(e2p_block)) {
353         e2p_flush(e2p, E2P_FLUSH_BEGIN);
354         if (e2p->remain_size < length + sizeof(e2p_block)) {
355             e2p_trace("no enough flash write\n");
356             return E2P_ERROR_NO_MEM;
357         }
358     }
359 
360     return e2p_write_private(e2p, block_id, length, data);
361 }
362 
e2p_read(e2p_t * e2p,uint32_t block_id,uint16_t length,uint8_t * data)363 hpm_stat_t e2p_read(e2p_t *e2p, uint32_t block_id, uint16_t length, uint8_t *data)
364 {
365     e2p_block block;
366     int ret = 0;
367 
368     ret = e2p_retrieve_info(block_id, &block);
369     if (ret != E2P_STATUS_OK)
370         return ret;
371 
372     uint8_t tmp[block.length];
373     e2p->config.flash_read(tmp, block.data_addr, block.length);
374 
375     if (block.crc != e2p_data_crc_calc(block.length, tmp)) {
376         e2p_trace("crc check error, data addr = 0x%08x, crc = 0x%08x", block.data_addr, block.crc);
377         return E2P_ERROR;
378     }
379 
380     length > block.length ? (length=block.length) : length;
381     memmove(data, tmp, length);
382     return E2P_STATUS_OK;
383 }
384 
e2p_format(e2p_t * e2p)385 void e2p_format(e2p_t *e2p)
386 {
387     e2p_config_t *cfg = &e2p->config;
388 
389     cfg->flash_erase(cfg->start_addr, cfg->sector_cnt * cfg->erase_size);
390 }
391 
e2p_generate_id(const char * name)392 uint32_t e2p_generate_id(const char *name)
393 {
394     return (name[0] << 24) | (name[1] << 16) | (name[2] << 8) | (name[3]);
395 }
396 
397 
e2p_show_info(e2p_t * e2p)398 void e2p_show_info(e2p_t *e2p)
399 {
400     e2p_print_info(e2p);
401 }
402