summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/memory/spiflash.c69
-rw-r--r--drivers/memory/spiflash.h13
2 files changed, 48 insertions, 34 deletions
diff --git a/drivers/memory/spiflash.c b/drivers/memory/spiflash.c
index d72603f64..0cc926b79 100644
--- a/drivers/memory/spiflash.c
+++ b/drivers/memory/spiflash.c
@@ -48,12 +48,7 @@
#define WAIT_SR_TIMEOUT (1000000)
#define PAGE_SIZE (256) // maximum bytes we can write in one SPI transfer
-#define SECTOR_SIZE (4096) // size of erase sector
-
-// Note: this code is not reentrant with this shared buffer
-STATIC uint8_t buf[SECTOR_SIZE] __attribute__((aligned(4)));
-STATIC mp_spiflash_t *bufuser; // current user of buf
-STATIC uint32_t bufsec; // current sector stored in buf; 0xffffffff if invalid
+#define SECTOR_SIZE MP_SPIFLASH_ERASE_BLOCK_SIZE
STATIC void mp_spiflash_acquire_bus(mp_spiflash_t *self) {
const mp_spiflash_config_t *c = self->config;
@@ -231,15 +226,16 @@ void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *d
return;
}
mp_spiflash_acquire_bus(self);
- if (bufuser == self && bufsec != 0xffffffff) {
+ mp_spiflash_cache_t *cache = self->config->cache;
+ if (cache->user == self && cache->block != 0xffffffff) {
uint32_t bis = addr / SECTOR_SIZE;
uint32_t bie = (addr + len - 1) / SECTOR_SIZE;
- if (bis <= bufsec && bufsec <= bie) {
+ if (bis <= cache->block && cache->block <= bie) {
// Read straddles current buffer
size_t rest = 0;
- if (bis < bufsec) {
+ if (bis < cache->block) {
// Read direct from flash for first part
- rest = bufsec * SECTOR_SIZE - addr;
+ rest = cache->block * SECTOR_SIZE - addr;
mp_spiflash_read_data(self, addr, rest, dest);
len -= rest;
dest += rest;
@@ -250,7 +246,7 @@ void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *d
if (rest > len) {
rest = len;
}
- memcpy(dest, &buf[offset], rest);
+ memcpy(dest, &cache->buf[offset], rest);
len -= rest;
if (len == 0) {
mp_spiflash_release_bus(self);
@@ -273,15 +269,17 @@ STATIC void mp_spiflash_flush_internal(mp_spiflash_t *self) {
self->flags &= ~1;
+ mp_spiflash_cache_t *cache = self->config->cache;
+
// Erase sector
- int ret = mp_spiflash_erase_sector(self, bufsec * SECTOR_SIZE);
+ int ret = mp_spiflash_erase_sector(self, cache->block * SECTOR_SIZE);
if (ret != 0) {
return;
}
// Write
for (int i = 0; i < 16; i += 1) {
- int ret = mp_spiflash_write_page(self, bufsec * SECTOR_SIZE + i * PAGE_SIZE, buf + i * PAGE_SIZE);
+ int ret = mp_spiflash_write_page(self, cache->block * SECTOR_SIZE + i * PAGE_SIZE, cache->buf + i * PAGE_SIZE);
if (ret != 0) {
return;
}
@@ -302,35 +300,37 @@ STATIC int mp_spiflash_write_part(mp_spiflash_t *self, uint32_t addr, size_t len
addr = sec << 12;
// Restriction for now, so we don't need to erase multiple pages
- if (offset + len > sizeof(buf)) {
+ if (offset + len > SECTOR_SIZE) {
printf("mp_spiflash_write_part: len is too large\n");
return -MP_EIO;
}
+ mp_spiflash_cache_t *cache = self->config->cache;
+
// Acquire the sector buffer
- if (bufuser != self) {
- if (bufuser != NULL) {
- mp_spiflash_flush(bufuser);
+ if (cache->user != self) {
+ if (cache->user != NULL) {
+ mp_spiflash_flush(cache->user);
}
- bufuser = self;
- bufsec = 0xffffffff;
+ cache->user = self;
+ cache->block = 0xffffffff;
}
- if (bufsec != sec) {
+ if (cache->block != sec) {
// Read sector
#if USE_WR_DELAY
- if (bufsec != 0xffffffff) {
+ if (cache->block != 0xffffffff) {
mp_spiflash_flush_internal(self);
}
#endif
- mp_spiflash_read_data(self, addr, SECTOR_SIZE, buf);
+ mp_spiflash_read_data(self, addr, SECTOR_SIZE, cache->buf);
}
#if USE_WR_DELAY
- bufsec = sec;
+ cache->block = sec;
// Just copy to buffer
- memcpy(buf + offset, src, len);
+ memcpy(cache->buf + offset, src, len);
// And mark dirty
self->flags |= 1;
@@ -338,8 +338,8 @@ STATIC int mp_spiflash_write_part(mp_spiflash_t *self, uint32_t addr, size_t len
uint32_t dirty = 0;
for (size_t i = 0; i < len; ++i) {
- if (buf[offset + i] != src[i]) {
- if (buf[offset + i] != 0xff) {
+ if (cache->buf[offset + i] != src[i]) {
+ if (cache->buf[offset + i] != 0xff) {
// Erase sector
int ret = mp_spiflash_erase_sector(self, addr);
if (ret != 0) {
@@ -353,14 +353,14 @@ STATIC int mp_spiflash_write_part(mp_spiflash_t *self, uint32_t addr, size_t len
}
}
- bufsec = sec;
+ cache->block = sec;
// Copy new block into buffer
- memcpy(buf + offset, src, len);
+ memcpy(cache->buf + offset, src, len);
// Write sector in pages of 256 bytes
for (size_t i = 0; i < 16; ++i) {
if (dirty & (1 << i)) {
- int ret = mp_spiflash_write_page(self, addr + i * PAGE_SIZE, buf + i * PAGE_SIZE);
+ int ret = mp_spiflash_write_page(self, addr + i * PAGE_SIZE, cache->buf + i * PAGE_SIZE);
if (ret != 0) {
return ret;
}
@@ -378,16 +378,17 @@ int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint
mp_spiflash_acquire_bus(self);
- if (bufuser == self && bis <= bufsec && bie >= bufsec) {
+ mp_spiflash_cache_t *cache = self->config->cache;
+ if (cache->user == self && bis <= cache->block && bie >= cache->block) {
// Write straddles current buffer
uint32_t pre;
uint32_t offset;
- if (bufsec * SECTOR_SIZE >= addr) {
- pre = bufsec * SECTOR_SIZE - addr;
+ if (cache->block * SECTOR_SIZE >= addr) {
+ pre = cache->block * SECTOR_SIZE - addr;
offset = 0;
} else {
pre = 0;
- offset = addr - bufsec * SECTOR_SIZE;
+ offset = addr - cache->block * SECTOR_SIZE;
}
// Write buffered part first
@@ -397,7 +398,7 @@ int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint
len = len_in_buf - (SECTOR_SIZE - offset);
len_in_buf = SECTOR_SIZE - offset;
}
- memcpy(&buf[offset], &src[pre], len_in_buf);
+ memcpy(&cache->buf[offset], &src[pre], len_in_buf);
self->flags |= 1; // Mark dirty
// Write part before buffer sector
diff --git a/drivers/memory/spiflash.h b/drivers/memory/spiflash.h
index 03bad5296..66e7906cc 100644
--- a/drivers/memory/spiflash.h
+++ b/drivers/memory/spiflash.h
@@ -29,11 +29,23 @@
#include "drivers/bus/spi.h"
#include "drivers/bus/qspi.h"
+#define MP_SPIFLASH_ERASE_BLOCK_SIZE (4096) // must be a power of 2
+
enum {
MP_SPIFLASH_BUS_SPI,
MP_SPIFLASH_BUS_QSPI,
};
+struct _mp_spiflash_t;
+
+// A cache must be provided by the user in the config struct. The same cache
+// struct can be shared by multiple SPI flash instances.
+typedef struct _mp_spiflash_cache_t {
+ uint8_t buf[MP_SPIFLASH_ERASE_BLOCK_SIZE] __attribute__((aligned(4)));
+ struct _mp_spiflash_t *user; // current user of buf, for shared use
+ uint32_t block; // current block stored in buf; 0xffffffff if invalid
+} mp_spiflash_cache_t;
+
typedef struct _mp_spiflash_config_t {
uint32_t bus_kind;
union {
@@ -47,6 +59,7 @@ typedef struct _mp_spiflash_config_t {
const mp_qspi_proto_t *proto;
} u_qspi;
} bus;
+ mp_spiflash_cache_t *cache;
} mp_spiflash_config_t;
typedef struct _mp_spiflash_t {