Docker-Build mit gcc-arm-none-eabi 4.9-2014q4 (statt Homebrew-Cask) verwendet, Dockerfile/tools/docker.sh dafür aus Task 13 vorgezogen. cmake/sdk.cmake schont gcc 4.9 (kennt -fcommon/-Wno-error=... nicht). Zwei zusätzliche SDK-Stubs (EarlyInit, pre_gpio_config) in src/sys/sdk_stubs.c ergänzt, siehe sdk/PATCHES.md.
578 lines
16 KiB
C
578 lines
16 KiB
C
/**
|
|
* @file wm_fls.c
|
|
*
|
|
* @brief flash Driver Module
|
|
*
|
|
* @author dave
|
|
*
|
|
* Copyright (c) 2015 Winner Microelectronics Co., Ltd.
|
|
*/
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#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;
|
|
|
|
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
|
|
* @retval TLS_FLS_STATUS_EPERM if flash driver module not beed installed
|
|
* @retval TLS_FLS_STATUS_ENODRV if the current spi flash driver not installed
|
|
* @retval TLS_FLS_STATUS_EINVAL if parameter error
|
|
*
|
|
* @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
|
|
* @retval TLS_FLS_STATUS_ENOMEM if memory allocation fail
|
|
*
|
|
* @note None
|
|
*/
|
|
int tls_spifls_write(u32 addr, u8 * buf, u32 len)
|
|
{
|
|
u8 *cache;
|
|
int err;
|
|
u32 sector_addr;
|
|
u32 sector_off;
|
|
u32 sector_remain;
|
|
u32 cntforFF;
|
|
u32 write_bytes;
|
|
u32 write_page = 0;
|
|
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;
|
|
|
|
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;
|
|
}
|
|
|
|
sector_addr = addr / drv->sector_size; //Section addr
|
|
sector_off = (addr % drv->sector_size); //Offset in section
|
|
sector_remain = drv->sector_size - sector_off;
|
|
write_bytes = len;
|
|
TLS_DBGPRT_FLASH_INFO("write to flash: sector address - %d, sector off - %x.\n", sector_addr,
|
|
sector_off);
|
|
|
|
if(write_bytes <= sector_remain)
|
|
{
|
|
sector_remain = write_bytes; //Not bigger with remain size in section
|
|
}
|
|
while (1)
|
|
{
|
|
TLS_DBGPRT_FLASH_INFO("firstly, read the sector - %d to cache.\n", sector_addr);
|
|
err = drv->read(sector_addr * drv->sector_size, cache, drv->sector_size);
|
|
if (err != TLS_FLS_STATUS_OK)
|
|
{
|
|
TLS_DBGPRT_ERR("flash read fail(sector %d)!\n", sector_addr);
|
|
break;
|
|
}
|
|
|
|
cntforFF = 0;
|
|
for(i = 0; i < sector_remain; i++)
|
|
{
|
|
if(cache[i + sector_off] == 0xFF)
|
|
{
|
|
cntforFF++;
|
|
}
|
|
cache[i + sector_off] = buf[i];
|
|
}
|
|
|
|
//If the flash address to be written is all 0xFF, then erase sector is not necessary;
|
|
if( cntforFF != sector_remain)
|
|
{
|
|
TLS_DBGPRT_FLASH_INFO("second, erase the sector - %d.\n", sector_addr);
|
|
err = drv->erase(sector_addr);
|
|
if (err != TLS_FLS_STATUS_OK)
|
|
{
|
|
TLS_DBGPRT_ERR("flash erase fail(sector %d)!\n", sector_addr);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( (cntforFF != sector_remain ) || ((sector_off == 0) && (sector_remain == drv->sector_size)))
|
|
{
|
|
for(i = 0; i < (drv->sector_size / drv->page_size); i++)
|
|
{
|
|
err = drv->page_write(sector_addr * drv->sector_size / drv->page_size + i, &cache[i * drv->page_size]);
|
|
if (err != TLS_FLS_STATUS_OK)
|
|
{
|
|
TLS_DBGPRT_ERR("flash page write fail(page %d)!\n", i);
|
|
tls_mem_free(cache);
|
|
tls_os_sem_release(spi_fls->fls_lock);
|
|
return err;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
write_page = (sector_off / drv->page_size) == 15 ? 16 : (sector_off + sector_remain) / drv->page_size + 1;
|
|
//As long as this sector is not erased in this round, we only program the changed pages instead of all of them.
|
|
for(i = (sector_off / drv->page_size); i < write_page; i++)
|
|
{
|
|
err = drv->page_write(sector_addr * drv->sector_size / drv->page_size + i, &cache[i * drv->page_size]);
|
|
if (err != TLS_FLS_STATUS_OK)
|
|
{
|
|
TLS_DBGPRT_ERR("flash page write fail(page %d)!\n", i);
|
|
tls_mem_free(cache);
|
|
tls_os_sem_release(spi_fls->fls_lock);
|
|
return err;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(write_bytes == sector_remain)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
sector_addr++;
|
|
sector_off = 0;
|
|
buf += sector_remain;
|
|
write_bytes -= sector_remain;
|
|
if(write_bytes > (drv->sector_size))
|
|
sector_remain = drv->sector_size;
|
|
else
|
|
sector_remain = write_bytes; //Next section will finish
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|