diff --git a/.gitignore b/.gitignore index bfb8431..8404445 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.o +*.bin test/test test/test.bin tags diff --git a/src/spi_drv.h b/src/spi_drv.h new file mode 100644 index 0000000..2b357df --- /dev/null +++ b/src/spi_drv.h @@ -0,0 +1,11 @@ +#ifndef SPI_DRV_H_INCLUDED +#define SPI_DRV_H_INCLUDED +#include + +void spi_init(int polarity, int phase); +void spi_write(const char byte); +uint8_t spi_read(void); +void spi_cs_on(void); +void spi_cs_off(void); + +#endif diff --git a/src/spi_drv_stm32f4.c b/src/spi_drv_stm32f4.c new file mode 100644 index 0000000..3ba4cc3 --- /dev/null +++ b/src/spi_drv_stm32f4.c @@ -0,0 +1,98 @@ +#include +#include "spi_drv.h" +#include "system.h" + +void spi_cs_off(void) +{ + GPIOE_BSRR |= (1 << SPI_FLASH_PIN); + DMB(); + while(!(GPIOE_ODR & (1 << SPI_FLASH_PIN))) + ; +} + +void spi_cs_on(void) +{ + volatile int i; + GPIOE_BSRR |= (1 << (SPI_FLASH_PIN + 16)); + DMB(); + while(GPIOE_ODR & (1 << SPI_FLASH_PIN)) + ; +} + + +static void spi_flash_pin_setup(void) +{ + uint32_t reg; + AHB1_CLOCK_ER |= GPIOE_AHB1_CLOCK_ER; + reg = GPIOE_MODE & ~ (0x03 << (SPI_FLASH_PIN * 2)); + GPIOE_MODE = reg | (1 << (SPI_FLASH_PIN * 2)); + + reg = GPIOE_PUPD & (0x03 << (SPI_FLASH_PIN * 2)); + GPIOE_PUPD = reg | (0x01 << (SPI_FLASH_PIN * 2)); + + reg = GPIOE_OSPD & ~(0x03 << (SPI_FLASH_PIN * 2)); + GPIOE_OSPD |= (0x03 << (SPI_FLASH_PIN * 2)); + +} + +static void spi1_pins_setup(void) +{ + uint32_t reg; + AHB1_CLOCK_ER |= GPIOB_AHB1_CLOCK_ER; + /* Set mode = AF */ + reg = GPIOB_MODE & ~ (0x03 << (SPI1_CLOCK_PIN * 2)); + GPIOB_MODE = reg | (2 << (SPI1_CLOCK_PIN * 2)); + reg = GPIOB_MODE & ~ (0x03 << (SPI1_MOSI_PIN * 2)); + GPIOB_MODE = reg | (2 << (SPI1_MOSI_PIN * 2)); + reg = GPIOB_MODE & ~ (0x03 << (SPI1_MISO_PIN * 2)); + GPIOB_MODE = reg | (2 << (SPI1_MISO_PIN * 2)); + + /* Alternate function: use low pins (5,6,7) */ + reg = GPIOB_AFL & ~(0xf << ((SPI1_CLOCK_PIN) * 4)); + GPIOB_AFL = reg | (SPI1_PIN_AF << ((SPI1_CLOCK_PIN) * 4)); + reg = GPIOB_AFL & ~(0xf << ((SPI1_MOSI_PIN) * 4)); + GPIOB_AFL = reg | (SPI1_PIN_AF << ((SPI1_MOSI_PIN) * 4)); + reg = GPIOB_AFL & ~(0xf << ((SPI1_MISO_PIN) * 4)); + GPIOB_AFL = reg | (SPI1_PIN_AF << ((SPI1_MISO_PIN) * 4)); + +} + +static void spi1_reset(void) +{ + APB2_CLOCK_RST |= SPI1_APB2_CLOCK_ER_VAL; + APB2_CLOCK_RST &= ~SPI1_APB2_CLOCK_ER_VAL; +} + +uint8_t spi_read(void) +{ + volatile uint32_t reg; + do { + reg = SPI1_SR; + } while(!(reg & SPI_SR_RX_NOTEMPTY)); + return (uint8_t)SPI1_DR; +} + +void spi_write(const char byte) +{ + int i; + volatile uint32_t reg; + do { + reg = SPI1_SR; + } while ((reg & SPI_SR_TX_EMPTY) == 0); + SPI1_DR = byte; + do { + reg = SPI1_SR; + } while ((reg & SPI_SR_TX_EMPTY) == 0); +} + + +void spi_init(int polarity, int phase) +{ + spi1_pins_setup(); + spi_flash_pin_setup(); + APB2_CLOCK_ER |= SPI1_APB2_CLOCK_ER_VAL; + spi1_reset(); + SPI1_CR1 = SPI_CR1_MASTER | (5 << 3) | (polarity << 1) | (phase << 0); + SPI1_CR2 |= SPI_CR2_SSOE; + SPI1_CR1 |= SPI_CR1_SPI_EN; +} diff --git a/src/spi_flash.c b/src/spi_flash.c new file mode 100644 index 0000000..cb2d094 --- /dev/null +++ b/src/spi_flash.c @@ -0,0 +1,247 @@ +#include "system.h" +#include "spi_drv.h" + +#define SPI_FLASH_SECTOR_SIZE (4096) +#define SPI_FLASH_PAGE_SIZE (256) + +#define MDID 0x90 +#define RDSR 0x05 +#define WRSR 0x01 +# define ST_BUSY (1 << 0) +# define ST_WEL (1 << 1) +# define ST_BP0 (1 << 2) +# define ST_BP1 (1 << 3) +# define ST_BP2 (1 << 4) +# define ST_BP3 (1 << 5) +# define ST_AAI (1 << 6) +# define ST_BRO (1 << 7) +#define WREN 0x06 +#define WRDI 0x04 +#define SECTOR_ERASE 0x20 +#define BYTE_READ 0x03 +#define BYTE_WRITE 0x02 +#define AUTOINC 0xAD +#define EWSR 0x50 +#define EBSY 0x70 +#define DBSY 0x80 + + +static enum write_mode { + WB_WRITEPAGE = 0x00, + SST_AAI = 0x01 +} chip_write_mode = WB_WRITEPAGE; + +static void write_address(uint32_t address) +{ + spi_write((address & 0xFF00) >> 8); + spi_read(); + spi_write((address & 0xFF0000) >> 16); + spi_read(); + spi_write((address & 0xFF000000) >> 24); + spi_read(); +} + +static uint8_t read_status(void) +{ + uint8_t status; + int i; + spi_cs_on(); + spi_write(RDSR); + spi_read(); + spi_write(0xFF); + status = spi_read(); + spi_cs_off(); + return status; +} + +static void spi_cmd(uint8_t cmd) +{ + spi_cs_on(); + spi_write(cmd); + spi_read(); + spi_cs_off(); +} + +static inline void flash_aai_enable(void) +{ + spi_cmd(EBSY); +} + +static inline void flash_aai_disable(void) +{ + spi_cmd(DBSY); +} + +static void flash_write_enable(void) +{ + uint8_t status; + do { + spi_cmd(WREN); + status = read_status(); + } while ((status & ST_WEL) == 0); +} + +static void flash_write_disable(void) +{ + uint8_t status; + spi_cmd(WRDI); +} +static void wait_busy(void) +{ + uint8_t status; + do { + status = read_status(); + } while(status & ST_BUSY); +} + +static int spi_flash_write_page(uint32_t address, const void *data, int len) +{ + const uint8_t *buf = data; + int j = 0; + while (len > 0) { + wait_busy(); + flash_write_enable(); + spi_cs_on(); + spi_write(BYTE_WRITE); + spi_read(); + write_address(address); + do { + spi_write(buf[j++]); + address++; + spi_read(); + len--; + } while ((address % SPI_FLASH_PAGE_SIZE) != 0); + spi_cs_off(); + } + wait_busy(); + return j; +} + +static int spi_flash_write_aai(uint32_t address, const void *data, int len) +{ + const uint8_t *buf = data; + int j = 0; + int cont = 0; + wait_busy(); + if (len < 1) + return -1; + while (len > 0) { + if ((address & 0x01) || (len < 2)) { + flash_write_enable(); + spi_cs_on(); + spi_write(BYTE_WRITE); + spi_read(); + write_address(address); + spi_write(buf[j++]); + spi_read(); + spi_cs_off(); + len--; + address++; + } else { + if (!cont) { + flash_aai_enable(); + flash_write_enable(); + } + spi_cs_on(); + spi_write(AUTOINC); + spi_read(); + if (!cont) { + /* First AAI transaction, send address. */ + write_address(address); + cont = 1; + } + spi_write(buf[j++]); + spi_read(); + spi_write(buf[j++]); + spi_read(); + spi_cs_off(); + len -= 2; + address += 2; + read_status(); + } + } + if (cont) { + flash_write_disable(); + flash_aai_disable(); + } + wait_busy(); + return j; +} + +/* --- */ + +uint16_t spi_flash_probe(void) +{ + uint8_t manuf, product, b0; + int i; + wait_busy(); + spi_cs_on(); + spi_write(MDID); + b0 = spi_read(); + + write_address(0); + spi_write(0xFF); + manuf = spi_read(); + spi_write(0xFF); + product = spi_read(); + spi_cs_off(); + if (manuf == 0xBF) + chip_write_mode = SST_AAI; + if (manuf == 0xEF) + chip_write_mode = WB_WRITEPAGE; + +#ifndef READONLY + spi_cmd(EWSR); + spi_cs_on(); + spi_write(WRSR); + spi_read(); + spi_write(0x00); + spi_read(); + spi_cs_off(); +#endif + return (uint16_t)(manuf << 8 | product); +} + + +void spi_flash_sector_erase(uint32_t address) +{ + uint8_t status; + address &= (~(SPI_FLASH_SECTOR_SIZE - 1)); + + wait_busy(); + flash_write_enable(); + spi_cs_on(); + spi_write(SECTOR_ERASE); + spi_read(); + write_address(address); + spi_cs_off(); + wait_busy(); +} + +int spi_flash_read(uint32_t address, void *data, int len) +{ + uint8_t *buf = data; + int i = 0; + wait_busy(); + spi_cs_on(); + spi_write(BYTE_READ); + spi_read(); + write_address(address); + while (len > 0) { + spi_write(0xFF); + buf[i++] = spi_read(); + len--; + } + spi_cs_off(); + return i; +} + +int spi_flash_write(uint32_t address, const void *data, int len) +{ + if (chip_write_mode == SST_AAI) + return spi_flash_write_aai(address, data, len); + if (chip_write_mode == WB_WRITEPAGE) + return spi_flash_write_page(address, data, len); + return -1; +} + diff --git a/src/spi_flash.h b/src/spi_flash.h new file mode 100644 index 0000000..f2fd001 --- /dev/null +++ b/src/spi_flash.h @@ -0,0 +1,9 @@ +#ifndef SPI_FLASH_DRI_H +#define SPI_FLASH_DRI_H +#include +uint16_t spi_flash_probe(void); + +void spi_flash_sector_erase(uint32_t address); +int spi_flash_read(uint32_t address, void *data, int len); +int spi_flash_write(uint32_t address, const void *data, int len); +#endif diff --git a/src/usecfs.c b/src/usecfs.c index cf9b67a..b6fac5d 100644 --- a/src/usecfs.c +++ b/src/usecfs.c @@ -87,7 +87,7 @@ static void cache_commit(void) } } #endif - block_write(blockdev, cache, cached_block, 0, BLOCK_SIZE); + block_write(blockdev, cache, cached_block); cached_block = NO_BLOCK; } @@ -97,7 +97,7 @@ static void cache_load(uint32_t blk) return; if (cached_block != NO_BLOCK) cache_commit(); - if (block_read(blockdev, cache, blk, 0, BLOCK_SIZE) == BLOCK_SIZE) { + if (block_read(blockdev, cache, blk) == BLOCK_SIZE) { cached_block = blk; #ifdef CRYPTO if (!is_block_empty()) { diff --git a/src/usecfs_dev.h b/src/usecfs_dev.h index 7a35f14..2d80b21 100644 --- a/src/usecfs_dev.h +++ b/src/usecfs_dev.h @@ -6,8 +6,8 @@ #endif void *block_open(void *args); -int block_read(void *dev, void *_buf, uint32_t lba, int offset, int count); -int block_write(void *dev, const void *_buf, uint32_t lba, int offset, int count); +int block_read(void *dev, void *_buf, uint32_t lba); +int block_write(void *dev, const void *_buf, uint32_t lba); void block_close(void *dev); #endif diff --git a/src/usecfs_dev_spi.c b/src/usecfs_dev_spi.c new file mode 100644 index 0000000..fbd8a10 --- /dev/null +++ b/src/usecfs_dev_spi.c @@ -0,0 +1,36 @@ +#include +#include "usecfs_dev.h" +#include "spi_flash.h" + +static uint32_t part_base = 0xFFFFFFFF; +static uint32_t part_size = 0; + +void *block_open(void *args_ptr) +{ + uint32_t *args = (uint32_t *)args_ptr; + part_base = args[0]; + part_size = args[1]; + return &part_base; +} + +int block_read(void *dev, void *_buf, uint32_t lba) +{ + if (part_size == 0) + return -1; + return spi_flash_read(part_base + (lba * BLOCK_SIZE), _buf, BLOCK_SIZE); +} + +int block_write(void *dev, const void *_buf, uint32_t lba) +{ + if (part_size == 0) + return -1; + spi_flash_sector_erase(part_base + lba * BLOCK_SIZE); + return spi_flash_write(part_base + lba * BLOCK_SIZE, _buf, BLOCK_SIZE); +} + +void block_close(void *dev) +{ + (void)dev; + part_base = 0xFFFFFFFF; + part_size = 0; +} diff --git a/src/usecfs_dev_test.c b/src/usecfs_dev_test.c index 0696555..7851018 100644 --- a/src/usecfs_dev_test.c +++ b/src/usecfs_dev_test.c @@ -21,19 +21,20 @@ void *block_open(void *args) return &fd; } -int block_read(void *dev, void *_buf, uint32_t lba, int offset, int count) +int block_read(void *dev, void *_buf, uint32_t lba) { (void)dev; - lseek(fd, lba * BLOCK_SIZE + offset, SEEK_SET); - read(fd, _buf, count); + lseek(fd, lba * BLOCK_SIZE, SEEK_SET); + return read(fd, _buf, BLOCK_SIZE); } -int block_write(void *dev, const void *_buf, uint32_t lba, int offset, int count) +int block_write(void *dev, const void *_buf, uint32_t lba) { (void)dev; - lseek(fd, lba * BLOCK_SIZE + offset, SEEK_SET); - write(fd, _buf, count); + lseek(fd, lba * BLOCK_SIZE, SEEK_SET); + return write(fd, _buf, BLOCK_SIZE); } + void block_close(void *dev) { (void)dev; diff --git a/test/Makefile b/test/Makefile index 453172a..89fec2e 100644 --- a/test/Makefile +++ b/test/Makefile @@ -6,4 +6,4 @@ test: main.o ../src/usecfs.o ../src/usecfs_dev_test.o gcc -o $@ $^ -lwolfssl clean: - rm main.o ../src/usecfs.o ../src/usecfs_dev_test.o test + @rm -f main.o ../src/*.o