improvements in ext-flash driver

This commit is contained in:
Xenofon (Fontas) Fafoutis 2018-04-04 11:08:18 +01:00
parent 1c335e9faa
commit b4b6ab1bdf
2 changed files with 105 additions and 84 deletions

View File

@ -109,13 +109,22 @@ static spi_device_t flash_spi_configuration_default = {
.spi_pha = 0,
.spi_pol = 0
};
static spi_device_t *flash_spi_configuration;
/*---------------------------------------------------------------------------*/
/**
* Get spi configuration, return default configuration if NULL
*/
static spi_device_t*
get_spi_conf(spi_device_t *conf) {
if(conf == NULL) {
return &flash_spi_configuration_default;
}
return conf;
}/*---------------------------------------------------------------------------*/
/**
* Clear external flash CSN line
*/
static bool
select_on_bus(void)
select_on_bus(spi_device_t *flash_spi_configuration)
{
if(spi_select(flash_spi_configuration) == SPI_DEV_STATUS_OK) {
return true;
@ -127,7 +136,7 @@ select_on_bus(void)
* Set external flash CSN line
*/
static void
deselect(void)
deselect(spi_device_t *flash_spi_configuration)
{
spi_deselect(flash_spi_configuration);
}
@ -137,19 +146,19 @@ deselect(void)
* \return True when successful.
*/
static bool
wait_ready(void)
wait_ready(spi_device_t *flash_spi_configuration)
{
bool ret;
const uint8_t wbuf[1] = { BLS_CODE_READ_STATUS };
if(select_on_bus() == false) {
if(select_on_bus(flash_spi_configuration) == false) {
return false;
}
ret = spi_write(flash_spi_configuration, wbuf, sizeof(wbuf));
if(ret != SPI_DEV_STATUS_OK) {
deselect();
deselect(flash_spi_configuration);
return false;
}
@ -164,7 +173,7 @@ wait_ready(void)
if(ret != SPI_DEV_STATUS_OK) {
/* Error */
deselect();
deselect(flash_spi_configuration);
return false;
}
@ -173,7 +182,7 @@ wait_ready(void)
break;
}
}
deselect();
deselect(flash_spi_configuration);
return true;
}
/*---------------------------------------------------------------------------*/
@ -185,23 +194,23 @@ wait_ready(void)
* was powered down
*/
static uint8_t
verify_part(void)
verify_part(spi_device_t *flash_spi_configuration)
{
const uint8_t wbuf[] = { BLS_CODE_MDID, 0xFF, 0xFF, 0x00 };
uint8_t rbuf[2] = { 0, 0 };
bool ret;
if(select_on_bus() == false) {
if(select_on_bus(flash_spi_configuration) == false) {
return VERIFY_PART_LOCKED;
}
if(spi_write(flash_spi_configuration, wbuf, sizeof(wbuf)) != SPI_DEV_STATUS_OK) {
deselect();
deselect(flash_spi_configuration);
return VERIFY_PART_ERROR;
}
ret = spi_read(flash_spi_configuration, rbuf, sizeof(rbuf));
deselect();
deselect(flash_spi_configuration);
if(ret != SPI_DEV_STATUS_OK) {
return VERIFY_PART_ERROR;
}
@ -219,31 +228,31 @@ verify_part(void)
* the status register is accessible.
*/
static bool
power_down(void)
power_down(spi_device_t *flash_spi_configuration)
{
uint8_t cmd;
uint8_t i;
/* First, wait for the device to be ready */
if(wait_ready() == false) {
if(wait_ready(flash_spi_configuration) == false) {
/* Entering here will leave the device in standby instead of powerdown */
return false;
}
cmd = BLS_CODE_PD;
if(select_on_bus() == false) {
if(select_on_bus(flash_spi_configuration) == false) {
return false;
}
if(spi_write_byte(flash_spi_configuration, cmd) != SPI_DEV_STATUS_OK) {
deselect();
deselect(flash_spi_configuration);
return false;
}
deselect();
deselect(flash_spi_configuration);
i = 0;
while(i < 10) {
if(verify_part() == VERIFY_PART_POWERED_DOWN) {
if(verify_part(flash_spi_configuration) == VERIFY_PART_POWERED_DOWN) {
/* Device is powered down */
return true;
}
@ -251,7 +260,7 @@ power_down(void)
}
/* Should not be required */
deselect();
deselect(flash_spi_configuration);
return false;
}
/*---------------------------------------------------------------------------*/
@ -260,23 +269,23 @@ power_down(void)
* \return True if the command was written successfully
*/
static bool
power_standby(void)
power_standby(spi_device_t *flash_spi_configuration)
{
uint8_t cmd;
bool success;
cmd = BLS_CODE_RPD;
if(select_on_bus() == false) {
if(select_on_bus(flash_spi_configuration) == false) {
return false;
}
success = (spi_write(flash_spi_configuration, &cmd, sizeof(cmd)) == SPI_DEV_STATUS_OK);
if(success) {
success = wait_ready() == true ? true : false;
success = wait_ready(flash_spi_configuration) == true ? true : false;
}
deselect();
deselect(flash_spi_configuration);
return success;
}
@ -286,17 +295,17 @@ power_standby(void)
* \return True when successful.
*/
static bool
write_enable(void)
write_enable(spi_device_t *flash_spi_configuration)
{
bool ret;
const uint8_t wbuf[] = { BLS_CODE_WRITE_ENABLE };
if(select_on_bus() == false) {
if(select_on_bus(flash_spi_configuration) == false) {
return false;
}
ret = (spi_write(flash_spi_configuration, wbuf, sizeof(wbuf)) == SPI_DEV_STATUS_OK);
deselect();
deselect(flash_spi_configuration);
if(ret == false) {
return false;
@ -305,8 +314,12 @@ write_enable(void)
}
/*---------------------------------------------------------------------------*/
bool
ext_flash_open()
ext_flash_open(spi_device_t *conf)
{
spi_device_t *flash_spi_configuration;
flash_spi_configuration = get_spi_conf(conf);
/* Check if platform has ext-flash */
if(flash_spi_configuration->pin_spi_sck == 255) {
return false;
@ -316,37 +329,51 @@ ext_flash_open()
return false;
}
/* Default output to clear chip select */
deselect();
deselect(flash_spi_configuration);
/* Put the part is standby mode */
power_standby();
power_standby(flash_spi_configuration);
return verify_part() == VERIFY_PART_OK ? true : false;
if (verify_part(flash_spi_configuration) == VERIFY_PART_OK) {
return true;
}
/* Failed to verify */
spi_release(flash_spi_configuration);
return false;
}
/*---------------------------------------------------------------------------*/
bool
ext_flash_close()
ext_flash_close(spi_device_t *conf)
{
/* Put the part in low power mode */
if(power_down() == false) {
return false;
}
bool ret;
spi_device_t *flash_spi_configuration;
flash_spi_configuration = get_spi_conf(conf);
/* Put the part in low power mode */
ret = power_down(flash_spi_configuration);
/* SPI is released no matter if power_down() succeeds or fails */
if(spi_release(flash_spi_configuration) != SPI_DEV_STATUS_OK) {
return false;
}
return true;
return ret;
}
/*---------------------------------------------------------------------------*/
bool
ext_flash_read(uint32_t offset, uint32_t length, uint8_t *buf)
ext_flash_read(spi_device_t *conf, uint32_t offset, uint32_t length, uint8_t *buf)
{
uint8_t wbuf[4];
bool ret;
spi_device_t *flash_spi_configuration;
flash_spi_configuration = get_spi_conf(conf);
/* Wait till previous erase/program operation completes */
if(wait_ready() == false) {
if(wait_ready(flash_spi_configuration) == false) {
return false;
}
@ -359,36 +386,40 @@ ext_flash_read(uint32_t offset, uint32_t length, uint8_t *buf)
wbuf[2] = (offset >> 8) & 0xff;
wbuf[3] = offset & 0xff;
if(select_on_bus() == false) {
if(select_on_bus(flash_spi_configuration) == false) {
return false;
}
if(spi_write(flash_spi_configuration, wbuf, sizeof(wbuf)) != SPI_DEV_STATUS_OK) {
/* failure */
deselect();
deselect(flash_spi_configuration);
return false;
}
ret = (spi_read(flash_spi_configuration, buf, length) == SPI_DEV_STATUS_OK);
deselect();
deselect(flash_spi_configuration);
return ret;
}
/*---------------------------------------------------------------------------*/
bool
ext_flash_write(uint32_t offset, uint32_t length, const uint8_t *buf)
ext_flash_write(spi_device_t *conf, uint32_t offset, uint32_t length, const uint8_t *buf)
{
uint8_t wbuf[4];
uint32_t ilen; /* interim length per instruction */
spi_device_t *flash_spi_configuration;
flash_spi_configuration = get_spi_conf(conf);
while(length > 0) {
/* Wait till previous erase/program operation completes */
if(wait_ready() == false) {
if(wait_ready(flash_spi_configuration) == false) {
return false;
}
if(write_enable() == false) {
if(write_enable(flash_spi_configuration) == false) {
return false;
}
@ -410,30 +441,30 @@ ext_flash_write(uint32_t offset, uint32_t length, const uint8_t *buf)
* is not imposed here since above instructions
* should be enough to delay
* as much. */
if(select_on_bus() == false) {
if(select_on_bus(flash_spi_configuration) == false) {
return false;
}
if(spi_write(flash_spi_configuration, wbuf, sizeof(wbuf)) != SPI_DEV_STATUS_OK) {
/* failure */
deselect();
deselect(flash_spi_configuration);
return false;
}
if(spi_write(flash_spi_configuration, buf, ilen) != SPI_DEV_STATUS_OK) {
/* failure */
deselect();
deselect(flash_spi_configuration);
return false;
}
buf += ilen;
deselect();
deselect(flash_spi_configuration);
}
return true;
}
/*---------------------------------------------------------------------------*/
bool
ext_flash_erase(uint32_t offset, uint32_t length)
ext_flash_erase(spi_device_t *conf, uint32_t offset, uint32_t length)
{
/*
* Note that Block erase might be more efficient when the floor map
@ -443,6 +474,10 @@ ext_flash_erase(uint32_t offset, uint32_t length)
uint8_t wbuf[4];
uint32_t i, numsectors;
uint32_t endoffset = offset + length - 1;
spi_device_t *flash_spi_configuration;
flash_spi_configuration = get_spi_conf(conf);
offset = (offset / EXT_FLASH_ERASE_SECTOR_SIZE) * EXT_FLASH_ERASE_SECTOR_SIZE;
numsectors = (endoffset - offset + EXT_FLASH_ERASE_SECTOR_SIZE - 1) / EXT_FLASH_ERASE_SECTOR_SIZE;
@ -451,11 +486,11 @@ ext_flash_erase(uint32_t offset, uint32_t length)
for(i = 0; i < numsectors; i++) {
/* Wait till previous erase/program operation completes */
if(wait_ready() == false) {
if(wait_ready(flash_spi_configuration) == false) {
return false;
}
if(write_enable() == false) {
if(write_enable(flash_spi_configuration) == false) {
return false;
}
@ -463,16 +498,16 @@ ext_flash_erase(uint32_t offset, uint32_t length)
wbuf[2] = (offset >> 8) & 0xff;
wbuf[3] = offset & 0xff;
if(select_on_bus() == false) {
if(select_on_bus(flash_spi_configuration) == false) {
return false;
}
if(spi_write(flash_spi_configuration, wbuf, sizeof(wbuf)) != SPI_DEV_STATUS_OK) {
/* failure */
deselect();
deselect(flash_spi_configuration);
return false;
}
deselect();
deselect(flash_spi_configuration);
offset += EXT_FLASH_ERASE_SECTOR_SIZE;
}
@ -481,33 +516,19 @@ ext_flash_erase(uint32_t offset, uint32_t length)
}
/*---------------------------------------------------------------------------*/
bool
ext_flash_test(void)
ext_flash_init(spi_device_t *conf)
{
flash_spi_configuration = &flash_spi_configuration_default;
if(ext_flash_open() == false) {
if(ext_flash_open(conf) == false) {
return false;
}
if(ext_flash_close() == false) {
if(ext_flash_close(conf) == false) {
return false;
}
LOG_INFO("Flash test successful\n");
LOG_INFO("Flash init successful\n");
return true;
}
/*---------------------------------------------------------------------------*/
bool
ext_flash_init(spi_device_t *conf)
{
if(conf == NULL) {
flash_spi_configuration = &flash_spi_configuration_default;
} else {
flash_spi_configuration = conf;
}
return ext_flash_test();
}
/*---------------------------------------------------------------------------*/
/** @} */

View File

@ -49,19 +49,22 @@
/*---------------------------------------------------------------------------*/
/**
* \brief Initialize storage driver.
* \param SPI bus configuration struct. NULL for default.
* \return True when successful.
*/
bool ext_flash_open(void);
bool ext_flash_open(spi_device_t *conf);
/**
* \brief Close the storage driver
* \param SPI bus configuration struct. NULL for default.
*
* This call will put the device in its lower power mode (power down).
*/
bool ext_flash_close(void);
bool ext_flash_close(spi_device_t *conf);
/**
* \brief Read storage content
* \param SPI bus configuration struct. NULL for default.
* \param offset Address to read from
* \param length Number of bytes to read
* \param buf Buffer where to store the read bytes
@ -69,10 +72,11 @@ bool ext_flash_close(void);
*
* buf must be allocated by the caller
*/
bool ext_flash_read(uint32_t offset, uint32_t length, uint8_t *buf);
bool ext_flash_read(spi_device_t *conf, uint32_t offset, uint32_t length, uint8_t *buf);
/**
* \brief Erase storage sectors corresponding to the range.
* \param SPI bus configuration struct. NULL for default.
* \param offset Address to start erasing
* \param length Number of bytes to erase
* \return True when successful.
@ -80,26 +84,22 @@ bool ext_flash_read(uint32_t offset, uint32_t length, uint8_t *buf);
* The erase operation will be sector-wise, therefore a call to this function
* will generally start the erase procedure at an address lower than offset
*/
bool ext_flash_erase(uint32_t offset, uint32_t length);
bool ext_flash_erase(spi_device_t *conf, uint32_t offset, uint32_t length);
/**
* \brief Write to storage sectors.
* \param SPI bus configuration struct. NULL for default.
* \param offset Address to write to
* \param length Number of bytes to write
* \param buf Buffer holding the bytes to be written
*
* \return True when successful.
*/
bool ext_flash_write(uint32_t offset, uint32_t length, const uint8_t *buf);
/**
* \brief Test the flash (power on self-test)
* \return True when successful.
*/
bool ext_flash_test(void);
bool ext_flash_write(spi_device_t *conf, uint32_t offset, uint32_t length, const uint8_t *buf);
/**
* \brief Initialise the external flash
* \param SPI bus configuration struct. NULL for default.
*
* This function will explicitly put the part in its lowest power mode
* (power-down).