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.
308 lines
6.9 KiB
C
308 lines
6.9 KiB
C
/**
|
|
* @file wm_fls_gd25qxx.c
|
|
*
|
|
* @brief gd25qxx flash Driver Module
|
|
*
|
|
* @author dave
|
|
*
|
|
* Copyright (c) 2015 Winner Microelectronics Co., Ltd.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "wm_type_def.h"
|
|
#include "wm_flash.h"
|
|
#include "wm_hostspi.h"
|
|
#include "wm_fls_gd25qxx.h"
|
|
#include "wm_debug.h"
|
|
#include "wm_gpio.h"
|
|
|
|
static int tls_spifls_drv_read(u32 addr, u8 * buf, u32 len);
|
|
static int tls_spifls_drv_fast_read(u32 addr, u8 * buf, u32 len);
|
|
static int tls_spifls_drv_page_write(u32 page, u8 * buf);
|
|
static int tls_spifls_drv_erase(u32 sector);
|
|
static int tls_spifls_drv_chip_erase(void);
|
|
static int tls_spifls_drv_probe(u32 id);
|
|
static void tls_spifls_drv_remove(void);
|
|
|
|
static struct tls_fls_drv exspi_fls = {
|
|
.drv_list = {NULL, NULL},
|
|
.clock = SPI_SCLK,
|
|
.mode = TLS_SPI_MODE_0,
|
|
.cs_active = TLS_SPI_CS_LOW,
|
|
.flags = 0,
|
|
.read = tls_spifls_drv_read,
|
|
.fast_read = tls_spifls_drv_fast_read,
|
|
.page_write = tls_spifls_drv_page_write,
|
|
.erase = tls_spifls_drv_erase,
|
|
.chip_erase = tls_spifls_drv_chip_erase,
|
|
.probe = tls_spifls_drv_probe,
|
|
.remove = tls_spifls_drv_remove
|
|
};
|
|
|
|
static struct tls_fls_drv *exspifls_drv = NULL;
|
|
|
|
|
|
static unsigned int swap32(unsigned int v)
|
|
{
|
|
return ((v & 0xff) << 24) | ((v & 0xff00) << 8) |
|
|
((v & 0xff0000) >> 8) | (v >> 24);
|
|
}
|
|
|
|
static int tls_spifls_drv_write_enable(void)
|
|
{
|
|
u8 cmd;
|
|
int err;
|
|
|
|
cmd = EXSPIFLASH_WRITE_ENABLE;
|
|
|
|
err = tls_spi_write((const u8 *) &cmd, 1);
|
|
if (err != TLS_SPI_STATUS_OK)
|
|
{
|
|
return TLS_FLS_STATUS_EIO;
|
|
}
|
|
|
|
return TLS_FLS_STATUS_OK;
|
|
}
|
|
|
|
static int tls_spifls_drv_wait_write_enable(void)
|
|
{
|
|
u8 cmd;
|
|
u8 sr;
|
|
int err;
|
|
|
|
cmd = EXSPIFLASH_READ_SR1;
|
|
sr = 0;
|
|
do
|
|
{
|
|
err = tls_spi_read_with_cmd((const u8 *) &cmd, 1, &sr, 1);
|
|
if (err != TLS_SPI_STATUS_OK)
|
|
{
|
|
return TLS_FLS_STATUS_EIO;
|
|
}
|
|
|
|
if (sr & FLASH_STATUS_WEL)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while (1);
|
|
|
|
return TLS_FLS_STATUS_OK;
|
|
}
|
|
|
|
static int tls_spifls_drv_wait_flash_ready(void)
|
|
{
|
|
u8 cmd;
|
|
u8 sr;
|
|
int err;
|
|
|
|
cmd = EXSPIFLASH_READ_SR1;
|
|
sr = 0;
|
|
do
|
|
{
|
|
err = tls_spi_read_with_cmd((const u8 *) &cmd, 1, &sr, 1);
|
|
if (err != TLS_SPI_STATUS_OK)
|
|
{
|
|
return TLS_FLS_STATUS_EIO;
|
|
}
|
|
|
|
if ((sr & FLASH_STATUS_BUSY) == 0x00)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while (1);
|
|
|
|
return TLS_FLS_STATUS_OK;
|
|
}
|
|
|
|
static int tls_spifls_drv_read(u32 addr, u8 * buf, u32 len)
|
|
{
|
|
u32 cmd;
|
|
int err;
|
|
|
|
cmd = 0;
|
|
cmd |= EXSPIFLASH_DATA_READ;
|
|
cmd |= swap32(addr) & 0xffffff00;
|
|
err = tls_spi_read_with_cmd((const u8 *) &cmd, 4, buf, len);
|
|
if (err != TLS_SPI_STATUS_OK)
|
|
{
|
|
return TLS_FLS_STATUS_EIO;
|
|
}
|
|
|
|
return TLS_FLS_STATUS_OK;
|
|
}
|
|
|
|
static int tls_spifls_drv_fast_read(u32 addr, u8 * buf, u32 len)
|
|
{
|
|
return TLS_FLS_STATUS_ENOSUPPORT;
|
|
}
|
|
|
|
static int tls_spifls_drv_page_write(u32 page, u8 * buf)
|
|
{
|
|
u32 cmd;
|
|
int err;
|
|
|
|
err = tls_spifls_drv_write_enable();
|
|
if (err != TLS_SPI_STATUS_OK)
|
|
{
|
|
return TLS_FLS_STATUS_EIO;
|
|
}
|
|
|
|
err = tls_spifls_drv_wait_write_enable();
|
|
if (err != TLS_SPI_STATUS_OK)
|
|
{
|
|
return TLS_FLS_STATUS_EIO;
|
|
}
|
|
|
|
cmd = 0;
|
|
cmd |= EXSPIFLASH_PAGE_PROGRAM;
|
|
cmd |= swap32(page * exspifls_drv->page_size) & 0xffffff00;
|
|
err = tls_spi_write_with_cmd((const u8 *) &cmd, 4, (const u8 *) buf,
|
|
exspifls_drv->page_size);
|
|
if (err != TLS_SPI_STATUS_OK)
|
|
{
|
|
return TLS_FLS_STATUS_EIO;
|
|
}
|
|
|
|
err = tls_spifls_drv_wait_flash_ready();
|
|
if (err != TLS_SPI_STATUS_OK)
|
|
{
|
|
return TLS_FLS_STATUS_EIO;
|
|
}
|
|
|
|
return TLS_FLS_STATUS_OK;
|
|
}
|
|
|
|
static int tls_spifls_drv_erase(u32 sector)
|
|
{
|
|
u32 cmd;
|
|
int err;
|
|
|
|
err = tls_spifls_drv_write_enable();
|
|
if (err != TLS_SPI_STATUS_OK)
|
|
{
|
|
return TLS_FLS_STATUS_EIO;
|
|
}
|
|
err = tls_spifls_drv_wait_write_enable();
|
|
if (err != TLS_SPI_STATUS_OK)
|
|
{
|
|
return TLS_FLS_STATUS_EIO;
|
|
}
|
|
cmd = 0;
|
|
cmd |= EXSPIFLASH_SECTOR_ERASE;
|
|
cmd |= swap32(sector * exspifls_drv->sector_size) & 0xffffff00;
|
|
err = tls_spi_write((const u8 *) &cmd, 4);
|
|
if (err != TLS_SPI_STATUS_OK)
|
|
{
|
|
return TLS_FLS_STATUS_EIO;
|
|
}
|
|
tls_os_time_delay(6);
|
|
err = tls_spifls_drv_wait_flash_ready();
|
|
if (err != TLS_SPI_STATUS_OK)
|
|
{
|
|
return TLS_FLS_STATUS_EIO;
|
|
}
|
|
return TLS_FLS_STATUS_OK;
|
|
}
|
|
|
|
static int tls_spifls_drv_chip_erase(void)
|
|
{
|
|
u8 cmd;
|
|
int err;
|
|
|
|
err = tls_spifls_drv_write_enable();
|
|
if (err != TLS_SPI_STATUS_OK)
|
|
{
|
|
return TLS_FLS_STATUS_EIO;
|
|
}
|
|
|
|
err = tls_spifls_drv_wait_write_enable();
|
|
if (err != TLS_SPI_STATUS_OK)
|
|
{
|
|
return TLS_FLS_STATUS_EIO;
|
|
}
|
|
|
|
cmd = EXSPIFLASH_CHIP_ERASE;
|
|
err = tls_spi_write((const u8 *) &cmd, 1);
|
|
if (err != TLS_SPI_STATUS_OK)
|
|
{
|
|
return TLS_FLS_STATUS_EIO;
|
|
}
|
|
|
|
err = tls_spifls_drv_wait_flash_ready();
|
|
if (err != TLS_SPI_STATUS_OK)
|
|
{
|
|
return TLS_FLS_STATUS_EIO;
|
|
}
|
|
|
|
return TLS_FLS_STATUS_OK;
|
|
}
|
|
|
|
static int tls_spifls_drv_probe(u32 id)
|
|
{
|
|
// int i = 0;
|
|
|
|
|
|
if (!id)
|
|
{
|
|
return TLS_FLS_STATUS_EINVAL;
|
|
}
|
|
|
|
exspi_fls.id = id;
|
|
if ((id>>16)&0xFF)
|
|
{
|
|
exspi_fls.total_size = 1 << (id>>16);
|
|
}else{
|
|
exspi_fls.total_size = FLASH_TOTAL_SIZE; /*1MByte*/
|
|
}
|
|
|
|
exspi_fls.page_size = PAGE_SIZE;
|
|
exspi_fls.program_size = PROGRAM_SIZE;
|
|
exspi_fls.sector_size = SECTOR_SIZE;
|
|
|
|
|
|
exspifls_drv = &exspi_fls;
|
|
return TLS_FLS_STATUS_OK;
|
|
}
|
|
|
|
static void tls_spifls_drv_remove(void)
|
|
{
|
|
exspifls_drv = NULL;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief This function is used to install gd25qxx driver.
|
|
*
|
|
* @param[in] None
|
|
*
|
|
* @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_EEXIST if driver is already existed
|
|
*
|
|
* @note None
|
|
*/
|
|
int tls_spifls_drv_install(void)
|
|
{
|
|
int err;
|
|
extern int tls_spifls_probe(void);
|
|
extern int tls_spifls_drv_register(struct tls_fls_drv *fls_drv);
|
|
|
|
|
|
err = tls_spifls_drv_register((struct tls_fls_drv *) &exspi_fls);
|
|
if (err == TLS_FLS_STATUS_EEXIST)
|
|
{
|
|
return err;
|
|
}
|
|
TLS_DBGPRT_INFO("register the spi flash driver - %d.\n", err);
|
|
|
|
err = tls_spifls_probe();
|
|
TLS_DBGPRT_INFO("probe spi flash - %d.\n", err);
|
|
|
|
return err;
|
|
}
|