summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2018-06-07 14:09:10 +1000
committerDamien George <damien.p.george@gmail.com>2018-06-14 16:52:56 +1000
commit86fe73beb99686ea15787f0603ad6f10a642054c (patch)
tree68bbcba6f641518fcb4a60ac432ab62aa0968516
parentcf1509c911a1e1f983538105592575a8a520341f (diff)
drivers/memory/spiflash: Move cache buffer to user-provided config.
This patch removes the global cache variables from the SPI flash driver and now requires the user to provide the cache memory themselves, via the SPI flash configuration struct. This allows to either have a shared cache for multiple SPI flash devices (by sharing a mp_spiflash_cache_t struct), or have a single cache per device (or a mix of these options). To configure the cache use: mp_spiflash_cache_t spi_bdev_cache; const mp_spiflash_config_t spiflash_config = // any bus options .cache = &spi_bdev_cache, };
-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 {