Merge pull request #1677 from mntmn/master
bios/spiflash: fix write/ erase, add write from sdcard and range erase
This commit is contained in:
commit
34ec22f8ab
|
@ -8,23 +8,26 @@
|
||||||
#include "../command.h"
|
#include "../command.h"
|
||||||
#include "../helpers.h"
|
#include "../helpers.h"
|
||||||
|
|
||||||
|
#include <libbase/progress.h>
|
||||||
|
#include <liblitespi/spiflash.h>
|
||||||
|
#include <libfatfs/ff.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Command "flash_write"
|
* Command "flash_write"
|
||||||
*
|
*
|
||||||
* Write data from a memory buffer to SPI flash
|
* Write data from a memory buffer to SPI flash
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#if (defined CSR_SPIFLASH_BASE && defined SPIFLASH_PAGE_SIZE)
|
#if (defined CSR_SPIFLASH_CORE_MASTER_CS_ADDR)
|
||||||
static void flash_write_handler(int nb_params, char **params)
|
static void flash_write_handler(int nb_params, char **params)
|
||||||
{
|
{
|
||||||
char *c;
|
char *c;
|
||||||
unsigned int addr;
|
unsigned int addr;
|
||||||
unsigned int value;
|
unsigned int mem_addr;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
if (nb_params < 2) {
|
if (nb_params < 2) {
|
||||||
printf("flash_write <offset> <value> [count]");
|
printf("flash_write <offset> <mem_addr> [count (bytes)]");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,9 +37,9 @@ static void flash_write_handler(int nb_params, char **params)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
value = strtoul(params[1], &c, 0);
|
mem_addr = strtoul(params[1], &c, 0);
|
||||||
if (*c != 0) {
|
if (*c != 0) {
|
||||||
printf("Incorrect value");
|
printf("Incorrect mem_addr");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,26 +53,92 @@ static void flash_write_handler(int nb_params, char **params)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < count; i++)
|
spiflash_write_stream(addr, (unsigned char *)mem_addr, count);
|
||||||
write_to_flash(addr + i * 4, (unsigned char *)&value, 4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
define_command(flash_write, flash_write_handler, "Write to flash", SPIFLASH_CMDS);
|
define_command(flash_write, flash_write_handler, "Write to flash", SPIFLASH_CMDS);
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
static void flash_from_sdcard_handler(int nb_params, char **params)
|
||||||
* Command "flash_erase"
|
|
||||||
*
|
|
||||||
* Flash erase
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#if (defined CSR_SPIFLASH_BASE && defined SPIFLASH_PAGE_SIZE)
|
|
||||||
static void flash_erase_handler(int nb_params, char **params)
|
|
||||||
{
|
{
|
||||||
erase_flash();
|
FRESULT fr;
|
||||||
printf("Flash erased\n");
|
FATFS fs;
|
||||||
|
FIL file;
|
||||||
|
uint32_t br;
|
||||||
|
uint32_t offset;
|
||||||
|
unsigned long length;
|
||||||
|
uint8_t buf[512];
|
||||||
|
|
||||||
|
if (nb_params < 1) {
|
||||||
|
printf("flash_from_sdcard <filename>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* filename = params[0];
|
||||||
|
|
||||||
|
fr = f_mount(&fs, "", 1);
|
||||||
|
if (fr != FR_OK)
|
||||||
|
return;
|
||||||
|
fr = f_open(&file, filename, FA_READ);
|
||||||
|
if (fr != FR_OK) {
|
||||||
|
printf("%s file not found.\n", filename);
|
||||||
|
f_mount(0, "", 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
length = f_size(&file);
|
||||||
|
printf("Copying %s to SPI flash (%ld bytes)...\n", filename, length);
|
||||||
|
init_progression_bar(length);
|
||||||
|
offset = 0;
|
||||||
|
for (;;) {
|
||||||
|
fr = f_read(&file, (void*) buf, 512, (UINT *)&br);
|
||||||
|
if (fr != FR_OK) {
|
||||||
|
printf("file read error.\n");
|
||||||
|
f_close(&file);
|
||||||
|
f_mount(0, "", 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (br == 0) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
spiflash_write_stream(offset, buf, br);
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += br;
|
||||||
|
show_progress(offset);
|
||||||
|
}
|
||||||
|
show_progress(offset);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
f_close(&file);
|
||||||
|
f_mount(0, "", 0);
|
||||||
|
}
|
||||||
|
define_command(flash_from_sdcard, flash_from_sdcard_handler, "Write file from SD card to flash", SPIFLASH_CMDS);
|
||||||
|
|
||||||
|
static void flash_erase_range_handler(int nb_params, char **params)
|
||||||
|
{
|
||||||
|
char *c;
|
||||||
|
uint32_t addr;
|
||||||
|
uint32_t count;
|
||||||
|
|
||||||
|
if (nb_params < 2) {
|
||||||
|
printf("flash_erase <offset> <count (bytes)>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr = strtoul(params[0], &c, 0);
|
||||||
|
if (*c != 0) {
|
||||||
|
printf("Incorrect offset");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = strtoul(params[1], &c, 0);
|
||||||
|
if (*c != 0) {
|
||||||
|
printf("Incorrect count");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
spiflash_erase_range(addr, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
define_command(flash_erase, flash_erase_handler, "Erase whole flash", SPIFLASH_CMDS);
|
define_command(flash_erase_range, flash_erase_range_handler, "Erase flash range", SPIFLASH_CMDS);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,149 @@ static void spiflash_master_write(uint32_t val, size_t len, size_t width, uint32
|
||||||
spiflash_core_master_cs_write(0);
|
spiflash_core_master_cs_write(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static volatile uint8_t w_buf[SPI_FLASH_BLOCK_SIZE + 4];
|
||||||
|
static volatile uint8_t r_buf[SPI_FLASH_BLOCK_SIZE + 4];
|
||||||
|
|
||||||
|
static uint32_t transfer_byte(uint8_t b)
|
||||||
|
{
|
||||||
|
/* wait for tx ready */
|
||||||
|
while (!spiflash_core_master_status_tx_ready_read());
|
||||||
|
|
||||||
|
spiflash_core_master_rxtx_write((uint32_t)b);
|
||||||
|
|
||||||
|
/* wait for rx ready */
|
||||||
|
while (!spiflash_core_master_status_rx_ready_read());
|
||||||
|
|
||||||
|
return spiflash_core_master_rxtx_read();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void transfer_cmd(uint8_t *bs, uint8_t *resp, int len)
|
||||||
|
{
|
||||||
|
spiflash_core_master_phyconfig_len_write(8);
|
||||||
|
spiflash_core_master_phyconfig_width_write(1);
|
||||||
|
spiflash_core_master_phyconfig_mask_write(1);
|
||||||
|
spiflash_core_master_cs_write(1);
|
||||||
|
|
||||||
|
flush_cpu_dcache();
|
||||||
|
for (int i=0; i < len; i++) {
|
||||||
|
resp[i] = transfer_byte(bs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
spiflash_core_master_cs_write(0);
|
||||||
|
flush_cpu_dcache();
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t spiflash_read_status_register(void)
|
||||||
|
{
|
||||||
|
volatile uint8_t buf[4];
|
||||||
|
w_buf[0] = 0x05;
|
||||||
|
w_buf[1] = 0x00;
|
||||||
|
transfer_cmd(w_buf, buf, 4);
|
||||||
|
|
||||||
|
#if SPIFLASH_DEBUG
|
||||||
|
printf("[SR: %02x %02x %02x %02x]", buf[0], buf[1], buf[2], buf[3]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* FIXME normally the status should be in buf[1],
|
||||||
|
but we have to read it a few more times to be
|
||||||
|
stable for unknown reasons */
|
||||||
|
return buf[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spiflash_write_enable(void)
|
||||||
|
{
|
||||||
|
uint8_t buf[1];
|
||||||
|
w_buf[0] = 0x06;
|
||||||
|
transfer_cmd(w_buf, buf, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void page_program(uint32_t addr, uint8_t *data, int len)
|
||||||
|
{
|
||||||
|
w_buf[0] = 0x02;
|
||||||
|
w_buf[1] = addr>>16;
|
||||||
|
w_buf[2] = addr>>8;
|
||||||
|
w_buf[3] = addr>>0;
|
||||||
|
memcpy(w_buf+4, data, len);
|
||||||
|
transfer_cmd(w_buf, r_buf, len+4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spiflash_sector_erase(uint32_t addr)
|
||||||
|
{
|
||||||
|
w_buf[0] = 0xd8;
|
||||||
|
w_buf[1] = addr>>16;
|
||||||
|
w_buf[2] = addr>>8;
|
||||||
|
w_buf[3] = addr>>0;
|
||||||
|
transfer_cmd(w_buf, r_buf, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* erase page size in bytes, check flash datasheet */
|
||||||
|
#define SPI_FLASH_ERASE_SIZE (64*1024)
|
||||||
|
|
||||||
|
#define min(x, y) (((x) < (y)) ? (x) : (y))
|
||||||
|
|
||||||
|
void spiflash_erase_range(uint32_t addr, uint32_t len)
|
||||||
|
{
|
||||||
|
uint32_t i = 0;
|
||||||
|
uint32_t j = 0;
|
||||||
|
for (i=0; i<len; i+=SPI_FLASH_ERASE_SIZE) {
|
||||||
|
printf("Erase SPI Flash @0x%08lx", ((uint32_t)addr+i));
|
||||||
|
spiflash_write_enable();
|
||||||
|
spiflash_sector_erase(addr+i);
|
||||||
|
|
||||||
|
while (spiflash_read_status_register() & 1) {
|
||||||
|
printf(".");
|
||||||
|
cdelay(CONFIG_CLOCK_FREQUENCY/25);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
/* check if region was really erased */
|
||||||
|
for (j = 0; j < SPI_FLASH_ERASE_SIZE; j++) {
|
||||||
|
uint8_t* peek = (((uint8_t*)SPIFLASH_BASE)+addr+i+j);
|
||||||
|
if (*peek != 0xff) {
|
||||||
|
printf("Error: location 0x%08lx not erased (%0x2x)\n", addr+i+j, *peek);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int spiflash_write_stream(uint32_t addr, uint8_t *stream, uint32_t len)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
uint32_t w_len = min(len, SPI_FLASH_BLOCK_SIZE);
|
||||||
|
uint32_t offset = 0;
|
||||||
|
uint32_t j = 0;
|
||||||
|
|
||||||
|
#if SPIFLASH_DEBUG
|
||||||
|
printf("Write SPI Flash @0x%08lx", ((uint32_t)addr));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while(w_len) {
|
||||||
|
spiflash_write_enable();
|
||||||
|
page_program(addr+offset, stream+offset, w_len);
|
||||||
|
|
||||||
|
while(spiflash_read_status_register() & 1) {
|
||||||
|
#if SPIFLASH_DEBUG
|
||||||
|
printf(".");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 0; j < w_len; j++) {
|
||||||
|
uint8_t* peek = (((uint8_t*)SPIFLASH_BASE)+addr+offset+j);
|
||||||
|
if (*peek != stream[offset+j]) {
|
||||||
|
printf("Error: verify failed at 0x%08lx (0x%02x should be 0x%02x)\n", (uint32_t)peek, *peek, stream[offset+j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += w_len;
|
||||||
|
w_len = min(len-offset, SPI_FLASH_BLOCK_SIZE);
|
||||||
|
res = offset;
|
||||||
|
}
|
||||||
|
#if SPIFLASH_DEBUG
|
||||||
|
printf("\n");
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void spiflash_memspeed(void) {
|
void spiflash_memspeed(void) {
|
||||||
|
|
|
@ -12,6 +12,8 @@ int spiflash_freq_init(void);
|
||||||
void spiflash_dummy_bits_setup(unsigned int dummy_bits);
|
void spiflash_dummy_bits_setup(unsigned int dummy_bits);
|
||||||
void spiflash_memspeed(void);
|
void spiflash_memspeed(void);
|
||||||
void spiflash_init(void);
|
void spiflash_init(void);
|
||||||
|
int spiflash_write_stream(uint32_t addr, uint8_t *stream, uint32_t len);
|
||||||
|
void spiflash_erase_range(uint32_t addr, uint32_t len);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue