/** * @file wm_fls.c * * @brief flash Driver Module * * @author dave * * Copyright (c) 2015 Winner Microelectronics Co., Ltd. */ #include #include #include #include "list.h" #include "wm_hostspi.h" #include "wm_flash.h" #include "wm_dbg.h" #include "wm_mem.h" #include "wm_fls_gd25qxx.h" static struct tls_fls *spi_fls = NULL; static int tls_spifls_read_id(u32 * id) { u32 cmd; int err; cmd = FLS_CMD_READ_DEV_ID; *id = 0; err = tls_spi_read_with_cmd((const u8 *) &cmd, 4, (u8 *) id, 3); if (err != TLS_SPI_STATUS_OK) { TLS_DBGPRT_ERR("flash read ID fail(%d)!\n", err); return TLS_FLS_STATUS_EIO; } TLS_DBGPRT_FLASH_INFO("flash ID - 0x%x.\n", *id); return TLS_FLS_STATUS_OK; } /** * @brief This function is used to read data from the flash. * * @param[in] addr is byte offset addr for read from the flash. * @param[in] buf is user for data buffer of flash read * @param[in] len is byte length for read. * * @retval TLS_FLS_STATUS_OK if read sucsess * @retval TLS_FLS_STATUS_EIO if read fail * * @note None */ int tls_spifls_read(u32 addr, u8 * buf, u32 len) { int err; u32 read_bytes; struct tls_fls_drv *drv; if (spi_fls == NULL) { TLS_DBGPRT_ERR("flash driver module not beed installed!\n"); return TLS_FLS_STATUS_EPERM; } if (spi_fls->current_drv == NULL) { TLS_DBGPRT_ERR("the current spi flash driver not installed!\n"); return TLS_FLS_STATUS_ENODRV; } if ((addr >= spi_fls->current_drv->total_size) || (len == 0) || (buf == NULL)) { return TLS_FLS_STATUS_EINVAL; } tls_os_sem_acquire(spi_fls->fls_lock, 0); drv = spi_fls->current_drv; read_bytes = ((addr + len) > drv->total_size) ? (drv->total_size - addr) : len; err = TLS_FLS_STATUS_OK; err = drv->read(addr, buf, read_bytes); tls_os_sem_release(spi_fls->fls_lock); return err; } int tls_spifls_fast_read(u32 addr, u8 * buf, u32 len) { int err; u32 read_bytes; struct tls_fls_drv *drv; if (spi_fls == NULL) { TLS_DBGPRT_ERR("flash driver module not beed installed!\n"); return TLS_FLS_STATUS_EPERM; } if (spi_fls->current_drv == NULL) { TLS_DBGPRT_ERR("the current spi flash driver not installed!\n"); return TLS_FLS_STATUS_ENODRV; } if ((addr >= spi_fls->current_drv->total_size) || (len == 0) || (buf == NULL)) { return TLS_FLS_STATUS_EINVAL; } if ((spi_fls->current_drv->flags & TLS_FLS_FLAG_FAST_READ) != TLS_FLS_FLAG_FAST_READ) { return TLS_FLS_STATUS_ENOSUPPORT; } drv = spi_fls->current_drv; read_bytes = ((addr + len) > drv->total_size) ? (drv->total_size - addr) : len; err = TLS_FLS_STATUS_OK; err = drv->fast_read(addr, buf, read_bytes); return err; } int tls_spifls_page_write(u32 page, u8 * buf, u32 page_cnt) { int err; u32 write_pages; u32 i; struct tls_fls_drv *drv; if (spi_fls == NULL) { TLS_DBGPRT_ERR("flash driver module not beed installed!\n"); return TLS_FLS_STATUS_EPERM; } if (spi_fls->current_drv == NULL) { TLS_DBGPRT_ERR("the current spi flash driver not installed!\n"); return TLS_FLS_STATUS_ENODRV; } if ((page >= (spi_fls->current_drv->total_size / spi_fls->current_drv->page_size)) || (page_cnt == 0) || (buf == NULL)) { return TLS_FLS_STATUS_EINVAL; } drv = spi_fls->current_drv; write_pages = ((page + page_cnt) > (drv->total_size / drv->page_size)) ? ((drv->total_size / drv->page_size) -page) : page_cnt; err = TLS_FLS_STATUS_OK; for (i = 0; i < write_pages; i++) { err = drv->page_write(page + i, buf + i * drv->page_size); if (err != TLS_FLS_STATUS_OK) { TLS_DBGPRT_ERR("flash page write fail(page %d)!\n", (page + i)); break; } } return err; } /** * @brief This function is used to write data to the flash. * * @param[in] addr is byte offset addr for write to the flash * @param[in] buf is the data buffer want to write to flash * @param[in] len is the byte length want to write * * @retval TLS_FLS_STATUS_OK if write flash success * @retval TLS_FLS_STATUS_EPERM if flash struct point is null * @retval TLS_FLS_STATUS_ENODRV if flash driver is not installed * @retval TLS_FLS_STATUS_EINVAL if argument is invalid * @retval TLS_FLS_STATUS_EIO if io error * * @note None */ int tls_spifls_write(u32 addr, u8 * buf, u32 len) { u8 *cache; int err; u32 sector_addr; u32 sector_num; u32 write_bytes; u32 i; struct tls_fls_drv *drv; if (spi_fls == NULL) { TLS_DBGPRT_ERR("flash driver module not beed installed!\n"); return TLS_FLS_STATUS_EPERM; } if (spi_fls->current_drv == NULL) { TLS_DBGPRT_ERR("the current spi flash driver not installed!\n"); return TLS_FLS_STATUS_ENODRV; } if ((addr >= spi_fls->current_drv->total_size) || (len == 0) || (buf == NULL)) { return TLS_FLS_STATUS_EINVAL; } tls_os_sem_acquire(spi_fls->fls_lock, 0); drv = spi_fls->current_drv; write_bytes = ((addr + len) > drv->total_size) ? (drv->total_size - addr) : len; sector_addr = addr / drv->sector_size; sector_num = (addr + write_bytes - 1) / drv->sector_size - sector_addr + 1; TLS_DBGPRT_FLASH_INFO ("write to flash: sector address - %d, sectors - %d.\n", sector_addr, sector_num); err = TLS_FLS_STATUS_OK; cache = tls_mem_alloc(drv->sector_size); if (cache == NULL) { tls_os_sem_release(spi_fls->fls_lock); TLS_DBGPRT_ERR("allocate sector cache memory(%dB) fail!\n", drv->sector_size); return TLS_FLS_STATUS_ENOMEM; } for (i = 0; i < sector_num; i++) { TLS_DBGPRT_FLASH_INFO("firstly, read the sector - %d to cache.\n", sector_addr + i); err = drv->read((sector_addr + i) * drv->sector_size, cache, drv->sector_size); if (err != TLS_FLS_STATUS_OK) { tls_os_sem_release(spi_fls->fls_lock); TLS_DBGPRT_ERR("flash read fail(sector %d)!\n", (sector_addr + i)); break; } if (1 == sector_num){/*flash write only in one sector*/ MEMCPY(cache + (addr%drv->sector_size), buf, write_bytes); buf += write_bytes; write_bytes = 0; }else{/*flash write through some sectors*/ if (0 == i) { MEMCPY(cache+(addr%drv->sector_size), buf, drv->sector_size - (addr%drv->sector_size)); buf += drv->sector_size - (addr%drv->sector_size); write_bytes -= drv->sector_size - (addr%drv->sector_size); } else if (i == (sector_num - 1)) { MEMCPY(cache, buf, write_bytes); buf += write_bytes; write_bytes = 0; } else { MEMCPY(cache, buf, drv->sector_size); buf += drv->sector_size; write_bytes -= drv->sector_size; } } TLS_DBGPRT_FLASH_INFO("second, erase the sector - %d.\n", sector_addr + i); err = drv->erase(sector_addr + i); if (err != TLS_FLS_STATUS_OK) { tls_os_sem_release(spi_fls->fls_lock); TLS_DBGPRT_ERR("flash erase fail(sector %d)!\n", (sector_addr + i)); break; } TLS_DBGPRT_FLASH_INFO ("finnaly, write the data in cache to the sector - %d.\n", sector_addr + i); err = tls_spifls_page_write((sector_addr +i) * (drv->sector_size / drv->page_size), cache, drv->sector_size / drv->page_size); if (err != TLS_FLS_STATUS_OK) { tls_os_sem_release(spi_fls->fls_lock); TLS_DBGPRT_ERR("flash write fail(sector %d)!\n", (sector_addr + i)); break; } } tls_mem_free(cache); tls_os_sem_release(spi_fls->fls_lock); return err; } int tls_spifls_erase(u32 sector) { int err; struct tls_fls_drv *drv; if (spi_fls == NULL) { TLS_DBGPRT_ERR("flash driver module not beed installed!\n"); return TLS_FLS_STATUS_EPERM; } if (spi_fls->current_drv == NULL) { TLS_DBGPRT_ERR("the current spi flash driver not installed!\n"); return TLS_FLS_STATUS_ENODRV; } if (sector >= (spi_fls->current_drv->total_size / spi_fls->current_drv->sector_size)) { TLS_DBGPRT_ERR("the sector to be erase overflow!\n"); return TLS_FLS_STATUS_EINVAL; } tls_os_sem_acquire(spi_fls->fls_lock, 0); drv = spi_fls->current_drv; err = TLS_FLS_STATUS_OK; err = drv->erase(sector); tls_os_sem_release(spi_fls->fls_lock); return err; } int tls_spifls_chip_erase(void) { int err; struct tls_fls_drv *drv; if (spi_fls == NULL) { TLS_DBGPRT_ERR("flash driver module not beed installed!\n"); return TLS_FLS_STATUS_EPERM; } if (spi_fls->current_drv == NULL) { TLS_DBGPRT_ERR("the current spi flash driver not installed!\n"); return TLS_FLS_STATUS_ENODRV; } drv = spi_fls->current_drv; err = TLS_FLS_STATUS_OK; err = drv->chip_erase(); return err; } int tls_spifls_get_param(u8 type, void *param) { int err; struct tls_fls_drv *drv; if (spi_fls == NULL) { TLS_DBGPRT_ERR("flash driver module not beed installed!\n"); return TLS_FLS_STATUS_EPERM; } if (spi_fls->current_drv == NULL) { TLS_DBGPRT_ERR("the current spi flash driver not installed!\n"); return TLS_FLS_STATUS_ENODRV; } if (param == NULL) { return TLS_FLS_STATUS_EINVAL; } tls_os_sem_acquire(spi_fls->fls_lock, 0); drv = spi_fls->current_drv; err = TLS_FLS_STATUS_OK; switch (type) { case TLS_FLS_PARAM_TYPE_ID: *((u32 *) param) = drv->id; break; case TLS_FLS_PARAM_TYPE_SIZE: *((u32 *) param) = drv->total_size; break; case TLS_FLS_PARAM_TYPE_PAGE_SIZE: *((u32 *) param) = drv->page_size; break; case TLS_FLS_PARAM_TYPE_PROG_SIZE: *((u32 *) param) = drv->program_size; break; case TLS_FLS_PARAM_TYPE_SECTOR_SIZE: *((u32 *) param) = drv->sector_size; break; default: TLS_DBGPRT_WARNING("invalid parameter ID!\n"); err = TLS_FLS_STATUS_EINVAL; break; } tls_os_sem_release(spi_fls->fls_lock); return err; } int tls_spifls_drv_register(struct tls_fls_drv *fls_drv) { u32 cpu_sr; struct tls_fls_drv *drv; if (fls_drv == NULL) { TLS_DBGPRT_ERR("flash driver module not beed installed!\n"); return TLS_FLS_STATUS_EINVAL; } dl_list_for_each(drv, &spi_fls->fls_drvs, struct tls_fls_drv, drv_list) { if (drv->id == fls_drv->id) { TLS_DBGPRT_WARNING ("corresponding spi flash driver has registered!\n"); return TLS_FLS_STATUS_EEXIST; } } cpu_sr = tls_os_set_critical(); dl_list_add_tail((struct dl_list *) &spi_fls->fls_drvs, (struct dl_list *) &fls_drv->drv_list); tls_os_release_critical(cpu_sr); TLS_DBGPRT_FLASH_INFO("the spi flash driver is registered successfully!\n"); return TLS_FLS_STATUS_OK; } int tls_spifls_drv_unregister(struct tls_fls_drv *fls_drv) { TLS_DBGPRT_WARNING ("unregister spi flash driver operation is not supported!\n"); return TLS_FLS_STATUS_EPERM; } int tls_spifls_probe(void) { int err; u32 id; struct tls_fls_drv *drv; if (spi_fls == NULL) { TLS_DBGPRT_ERR("flash driver module not beed installed!\n"); return TLS_FLS_STATUS_EPERM; } if (spi_fls->current_drv != NULL) { TLS_DBGPRT_ERR("the current spi flash has fount the matched driver!\n"); return TLS_FLS_STATUS_EBUSY; } TLS_DBGPRT_FLASH_INFO("try to read the current spi flash ID.\n"); err = tls_spifls_read_id(&id); if (err != TLS_FLS_STATUS_OK) { return err; } TLS_DBGPRT_FLASH_INFO("current spi flash ID - 0x%x.\n", id); dl_list_for_each(drv, &spi_fls->fls_drvs, struct tls_fls_drv, drv_list) { err = drv->probe(id); if (err != TLS_FLS_STATUS_OK) { return err; } tls_spi_setup(drv->mode, drv->cs_active, drv->clock); TLS_DBGPRT_FLASH_INFO("matched the spi flash driver.\n"); spi_fls->current_drv = drv; break; } if (spi_fls->current_drv == NULL) { TLS_DBGPRT_WARNING("not found the matched spi flash driver!\n"); return TLS_FLS_STATUS_ENODRV; } return TLS_FLS_STATUS_OK; } int tls_spifls_init(void) { struct tls_fls *fls; int err; if (spi_fls != NULL) { TLS_DBGPRT_ERR("flash driver module has been installed!\n"); return TLS_FLS_STATUS_EBUSY; } fls = (struct tls_fls *) tls_mem_alloc(sizeof(struct tls_fls)); if (fls == NULL) { TLS_DBGPRT_ERR("allocate @spi_fls fail!\n"); return TLS_FLS_STATUS_ENOMEM; } memset(fls, 0, sizeof(*fls)); dl_list_init((struct dl_list *) &fls->fls_drvs); err = tls_os_sem_create(&fls->fls_lock, 1); if (err != TLS_OS_SUCCESS) { tls_mem_free(fls); TLS_DBGPRT_ERR("create semaphore @fls_lock fail!\n"); return TLS_FLS_STATUS_ENOMEM; } spi_fls = fls; tls_spifls_drv_install(); return TLS_FLS_STATUS_OK; } int tls_spifls_exit(void) { TLS_DBGPRT_FLASH_INFO("Not support flash driver module uninstalled!\n"); return TLS_FLS_STATUS_EPERM; }