123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393 |
- #include <zephyr/types.h>
- #include <strings.h>
- #include <stddef.h>
- #include <sys/types.h>
- #include <device.h>
- #include <sdfs.h>
- #include <storage/flash_map.h>
- #include <partition/partition.h>
- #include <linker/linker-defs.h>
- #include <drivers/flash.h>
- #include <spicache.h>
- #define CACHE_INVALID (0xffffffff)
- #define S_CACHE_SZ (2*1024)
- #define S_CACHE_NUM (16)
- #define L_CACHE_SZ (32*1024)
- #define L_CACHE_NUM (15)
- #define ALL_CACHE_SZ (S_CACHE_SZ*S_CACHE_NUM + L_CACHE_SZ*L_CACHE_NUM)
- #define ALL_CACHE_NUM (S_CACHE_NUM + L_CACHE_NUM)
- #define TBUF_SEC_LEN (CONFIG_SDFS_CACHE_BUF_LEN / 512)
- typedef struct cache_item_s {
- sys_dnode_t node; // used for link list*/
- uint32_t cache_off; // offset in bytes
- uint32_t cache_len; // in bytes
- u8_t *cache_buf; // cache buffer
- uint32_t hit_cnt; // hit count
- } cache_item_t;
- static sys_dlist_t cache_list;
- static uint32_t cache_hit_cnt;
- static uint32_t cache_miss_cnt;
- static cache_item_t __aligned(4) sdfs_cache_item[ALL_CACHE_NUM] __in_section_unique(RES_PSRAM_REGION);
- static char __aligned(4) sdfs_cache_buf[ALL_CACHE_SZ] __in_section_unique(RES_PSRAM_REGION);
- #ifdef CONFIG_SDFS_READ_BY_CACHE
- static char __aligned(4) sdfs_tmp_buf[CONFIG_SDFS_CACHE_BUF_LEN] __in_section_unique(system.bss.sdfs_cache);
- #else
- static char __aligned(4) sdfs_tmp_buf[CONFIG_SDFS_CACHE_BUF_LEN] __in_section_unique(RES_PSRAM_REGION);
- #endif
- static const struct device *g_sd_dev;
- static const struct device *g_nand_dev;
- K_MUTEX_DEFINE(sdfs_mutex);
- static void nand_sd_cache_init(void)
- {
- uint32_t idx;
- cache_item_t *item = sdfs_cache_item;
- u8_t *buf = sdfs_cache_buf;
-
- sys_dlist_init(&cache_list);
- cache_hit_cnt = 0;
- cache_miss_cnt = 0;
- for (idx = 0; idx < ALL_CACHE_NUM; idx ++) {
- // init cache item
- sys_dnode_init(&item->node);
- item->cache_off = CACHE_INVALID;
- if (idx < S_CACHE_NUM) {
- item->cache_len = S_CACHE_SZ;
- } else {
- item->cache_len = L_CACHE_SZ;
- }
- item->cache_buf = buf;
- item->hit_cnt = 0;
- buf += item->cache_len;
- // add cache item to list
- sys_dlist_append(&cache_list, &item->node);
- item ++;
- }
- }
- static cache_item_t* nand_sd_cache_find(uint32_t addr, uint32_t size)
- {
- cache_item_t *item;
- cache_item_t *cache_item = NULL;
- // check size
- if (size > (L_CACHE_SZ - S_CACHE_SZ / 2)) {
- return NULL;
- }
- // find node from first to last
- SYS_DLIST_FOR_EACH_CONTAINER(&cache_list, item, node) {
- if ((item->cache_off <= addr) && ((item->cache_off + item->cache_len) >= (addr + size))) {
- cache_hit_cnt ++;
- item->hit_cnt ++;
- cache_item = item;
- break;
- }
- }
- // move node to first
- if (cache_item && !sys_dlist_is_head(&cache_list, &cache_item->node)) {
- sys_dlist_remove(&cache_item->node);
- sys_dlist_prepend(&cache_list, &cache_item->node);
- }
-
- return cache_item;
- }
- static cache_item_t* nand_sd_cache_alloc(uint32_t addr, uint32_t size)
- {
- cache_item_t *cache_item = (cache_item_t*)sys_dlist_peek_tail(&cache_list);
- uint32_t cache_len;
- // check size
- if (size > (L_CACHE_SZ - S_CACHE_SZ / 2)) {
- return NULL;
- }
- if (size > S_CACHE_SZ / 2) {
- cache_len = L_CACHE_SZ;
- } else {
- cache_len = S_CACHE_SZ;
- }
- // find node from last to first
- while (cache_item) {
- if (cache_item->cache_len == cache_len) {
- cache_miss_cnt ++;
- cache_item->cache_off = addr & ~(S_CACHE_SZ / 2 - 1);
- cache_item->hit_cnt = 0;
- break;
- }
- cache_item = (cache_item_t*)sys_dlist_peek_prev(&cache_list, &cache_item->node);
- }
- // move node to first
- if (cache_item && !sys_dlist_is_head(&cache_list, &cache_item->node)) {
- sys_dlist_remove(&cache_item->node);
- sys_dlist_prepend(&cache_list, &cache_item->node);
- }
- return cache_item;
- }
- static void nand_sd_cache_dump(uint32_t level)
- {
- static uint32_t ratio_saved = 0;
- cache_item_t *item;
- uint32_t ratio = 0;
- if ( (cache_hit_cnt + cache_miss_cnt) > 0) {
- ratio = cache_hit_cnt * 100 / (cache_hit_cnt + cache_miss_cnt);
- }
- if (ratio_saved != ratio) {
- printk("[sdfs_cache] hit=%d, miss=%d, hit-rate=%d%%\n", cache_hit_cnt, cache_miss_cnt, ratio);
- ratio_saved = ratio;
- }
- if (level > 0) {
- // find node from first to last
- SYS_DLIST_FOR_EACH_CONTAINER(&cache_list, item, node) {
- if (item->cache_off != CACHE_INVALID) {
- printk(" [%d] off=0x%08x, len=%d\n", item->hit_cnt, item->cache_off, item->cache_len);
- }
- }
- }
- }
- static const struct device *nand_sd_dev(u8_t stor_id)
- {
- if(STORAGE_ID_NAND == stor_id)
- return g_nand_dev;
- if(STORAGE_ID_SD == stor_id)
- return g_sd_dev;
- printk("sdfs dev err:%d\n", stor_id);
- return NULL;
- }
- #if 0
- static void dump(void *data, size_t len)
- {
- uint8_t *buf = data;
- size_t i, width = 8;
- for (i = 0; i < len; i++) {
- if ((i % width) == 0) {
- printk("0x%08lx\t", POINTER_TO_INT(buf + i));
- }
- printk("%02x ", buf[i]);
- if (((i + 1) % width) == 0 || i == (len - 1)) {
- printk("\n");
- }
- }
- }
- #endif
- static int nand_sd_data_read(const struct device *dev, char *buf,uint32_t adfs_addr, uint32_t size)
- {
- cache_item_t *item = nand_sd_cache_find(adfs_addr, size);
- uint32_t byte_off, sec_off, len;
- int ret;
- // printk("[sdfs] 0x%x %d\n", adfs_addr, size);
- // cache miss
- if (item == NULL) {
- item = nand_sd_cache_alloc(adfs_addr, size);
- if (item) {
- #ifdef CONFIG_SDFS_READ_BY_CACHE
- // read flash to cache
- ret = flash_read(dev, item->cache_off, sdfs_tmp_buf, item->cache_len);
- if(ret < 0)
- return -1;
- // copy to cache
- memcpy(item->cache_buf, sdfs_tmp_buf, item->cache_len);
- #else
- ret = flash_read(dev, item->cache_off, item->cache_buf, item->cache_len);
- if(ret < 0)
- return -1;
- #endif
- }
- }
- // cache copy
- if (item) {
- memcpy(buf, item->cache_buf + (adfs_addr - item->cache_off), size);
- return 0;
- }
- // large read
- byte_off = adfs_addr & 0x1ff;
- sec_off = adfs_addr >> 9;
- #ifdef CONFIG_SDFS_READ_BY_CACHE
- sec_end = (adfs_addr + size + 0x1ff) >> 9;
- while (sec_off < sec_end) {
- // read flash
- len = sec_end - sec_off;
- if (len > TBUF_SEC_LEN) {
- len = TBUF_SEC_LEN;
- }
- ret = flash_read(dev, sec_off<<9, sdfs_tmp_buf, len<<9);
- if(ret < 0)
- return -2;
- sec_off += len;
-
- // copy to buf
- len = (len << 9) - byte_off;
- if (len > size) {
- len = size;
- }
- memcpy(buf, sdfs_tmp_buf + byte_off, len);
- spi1_cache_ops(SPI_CACHE_FLUSH_ALL, buf + byte_off, len);
- buf += len;
- size -= len;
- byte_off = 0;
- }
- #else
- // read first sector
- if (byte_off > 0) {
- // read flash
- ret = flash_read(dev, sec_off<<9, sdfs_tmp_buf, 1<<9);
- if(ret < 0)
- return -1;
- sec_off += 1;
-
- // copy to buf
- len = 512 - byte_off;
- memcpy(buf, sdfs_tmp_buf + byte_off, len);
- buf += len;
- size -= len;
- }
- // read large
- if (size >= 512) {
- // read flash
- len = (size >> 9);
- ret = flash_read(dev, sec_off<<9, buf, len<<9);
- if(ret < 0)
- return -1;
- sec_off += len;
- len = (len << 9);
- buf += len;
- size -= len;
- }
- // read last sector
- if (size > 0) {
- // read flash
- ret = flash_read(dev, sec_off<<9, sdfs_tmp_buf, 1<<9);
- if(ret < 0)
- return -1;
-
- // copy to buf
- memcpy(buf, sdfs_tmp_buf, size);
- }
- #endif
- // dump cache
- nand_sd_cache_dump(0);
-
- return 0;
- }
- static struct sd_dir * nand_sd_find_dir_by_addr(const struct device *dev, const char *filename, void *buf_size_32, uint32_t adfs_addr)
- {
- int num, total, offset;
- struct sd_dir *sd_dir = buf_size_32;
- printk("read off=0x%x, file=%s\n", adfs_addr, filename);
- if(nand_sd_data_read(dev, (char *)buf_size_32, adfs_addr, sizeof(*sd_dir))){
- printk("dev=%s, read fail\n", dev->name);
- return NULL;
- }
- if(memcmp(sd_dir->fname, "sdfs.bin", 8) != 0)
- {
- printk("sdfs.bin invalid, offset=0x%x\n", adfs_addr);
- return NULL;
- }
- total = sd_dir->offset;
- for(offset = adfs_addr + sizeof(*sd_dir), num = 0; num < total; offset += 32)
- {
- nand_sd_data_read(dev, (char *)buf_size_32, offset, 32);
- //printk("%d,file=%s, size=0x%x\n", num, sd_dir->fname, sd_dir->size);
- if(strncasecmp(filename, sd_dir->fname, 12) == 0)
- {
- return sd_dir;
- }
- num++;
- }
- return NULL;
- }
- struct sd_dir * nand_sd_find_dir(u8_t stor_id, u8_t part, const char *filename, void *buf_size_32)
- {
- struct sd_dir * sd_d;
- const struct device *dev;
- const struct partition_entry *parti;
- dev = nand_sd_dev(stor_id);
- if(dev == NULL)
- return NULL;
- parti = partition_get_stf_part(stor_id, part+PARTITION_FILE_ID_SDFS_PART_BASE);
- if(parti == NULL)
- return NULL;
- k_mutex_lock(&sdfs_mutex, K_FOREVER);
- sd_d = nand_sd_find_dir_by_addr(dev, filename, buf_size_32, parti->offset);
- k_mutex_unlock(&sdfs_mutex);
- if(sd_d) {
- sd_d->offset += parti->offset;
- return sd_d;
- }
- return NULL;
- }
- int nand_sd_sd_fread(u8_t stor_id, struct sd_file *sd_file, void *buffer, int len)
- {
- const struct device *dev;
- dev = nand_sd_dev(stor_id);
- if(dev == NULL)
- return -1;
- k_mutex_lock(&sdfs_mutex, K_FOREVER);
- nand_sd_data_read(dev, (char *)buffer, sd_file->readptr, len);
- k_mutex_unlock(&sdfs_mutex);
- sd_file->readptr += len;
- return len;
- }
- static int nand_sd_fs_init(const struct device *dev)
- {
- g_sd_dev = device_get_binding("sd");
- g_nand_dev = device_get_binding("spinand");
- if (!g_sd_dev) {
- printk("sdfs cannot found device sd\n");
- }
- if (!g_nand_dev) {
- printk("sdfs cannot found device spinand\n");
- }
- nand_sd_cache_init();
- //printk("sdfs nand init\n");
- return 0;
- }
- SYS_INIT(nand_sd_fs_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
|