Add SPI flash support (#546)
* Add SPI flash configs, IOBinders, CI tests, and docs * Add writable SPI flash support * bump * Fix CI * Fix CI * Update docs/Generators/TestChipIP.rst Co-authored-by: Chick Markley <chick@qrhino.com> * Maybe actually fix CI * Fix broken merge * Fix the tutorial patch * bump tcip to master * fix GPIO naming bug Co-authored-by: Chick Markley <chick@qrhino.com>
This commit is contained in:
174
tests/spiflash.h
Normal file
174
tests/spiflash.h
Normal file
@@ -0,0 +1,174 @@
|
||||
#ifndef __SPIFLASH_H__
|
||||
#define __SPIFLASH_H__
|
||||
|
||||
// These are configuration-dependent, but for the unit test we'll use the example config
|
||||
#define SPIFLASH_BASE_MEM 0x20000000
|
||||
#define SPIFLASH_BASE_MEM_SIZE 0x10000000
|
||||
|
||||
#define SPIFLASH_BASE_CTRL 0x10040000
|
||||
// Only defining the registers we use; there are more
|
||||
// Software control
|
||||
#define SPIFLASH_OFFS_CSMODE 0x18
|
||||
#define SPIFLASH_OFFS_FMT 0x40
|
||||
#define SPIFLASH_OFFS_TXDATA 0x48
|
||||
#define SPIFLASH_OFFS_RXDATA 0x4c
|
||||
// Hardware state machine control
|
||||
#define SPIFLASH_OFFS_FLASH_EN 0x60
|
||||
#define SPIFLASH_OFFS_FFMT 0x64
|
||||
|
||||
// chip select modes
|
||||
#define CSMODE_AUTO 0
|
||||
#define CSMODE_HOLD 2
|
||||
#define CSMODE_OFF 3
|
||||
|
||||
// SPI flash protocol settings
|
||||
#define SPIFLASH_PROTO_SINGLE 0
|
||||
#define SPIFLASH_PROTO_DUAL 1
|
||||
#define SPIFLASH_PROTO_QUAD 2
|
||||
|
||||
// SPI flash IO settings
|
||||
#define SPIFLASH_IODIR_RX 0
|
||||
#define SPIFLASH_IODIR_TX 1
|
||||
|
||||
// SPI flash endianness settings
|
||||
#define SPIFLASH_ENDIAN_MSB 0
|
||||
#define SPIFLASH_ENDIAN_LSB 1
|
||||
|
||||
static uint8_t test_data[] = {0x13,0x37,0x00,0xff,0xaa,0x55,0xfa,0xce,0x0f,0xf0,0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef};
|
||||
static uint8_t test_len = 16;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct {
|
||||
unsigned int proto : 2;
|
||||
unsigned int endian : 1;
|
||||
unsigned int iodir : 1;
|
||||
unsigned int : 12;
|
||||
unsigned int len : 4;
|
||||
unsigned int : 12;
|
||||
} fields;
|
||||
uint32_t bits;
|
||||
} spi_fmt;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct {
|
||||
unsigned int cmd_en : 1;
|
||||
unsigned int addr_len : 3;
|
||||
unsigned int pad_cnt : 4;
|
||||
unsigned int cmd_proto : 2;
|
||||
unsigned int addr_proto : 2;
|
||||
unsigned int data_proto : 2;
|
||||
unsigned int : 2;
|
||||
unsigned int cmd_code : 8;
|
||||
unsigned int pad_code : 8;
|
||||
} fields;
|
||||
uint32_t bits;
|
||||
} spiflash_ffmt;
|
||||
|
||||
// send something to the SPI TX
|
||||
void spi_data_write(uint8_t data)
|
||||
{
|
||||
while (reg_read32(SPIFLASH_BASE_CTRL + SPIFLASH_OFFS_TXDATA) >= 0x80000000);
|
||||
reg_write32(SPIFLASH_BASE_CTRL + SPIFLASH_OFFS_TXDATA, (uint32_t)data);
|
||||
}
|
||||
|
||||
// configure the hardware flash controller
|
||||
void configure_spiflash(spiflash_ffmt data)
|
||||
{
|
||||
reg_write32(SPIFLASH_BASE_CTRL + SPIFLASH_OFFS_FLASH_EN, 0);
|
||||
reg_write32(SPIFLASH_BASE_CTRL + SPIFLASH_OFFS_FFMT, data.bits);
|
||||
reg_write32(SPIFLASH_BASE_CTRL + SPIFLASH_OFFS_FLASH_EN, 1);
|
||||
}
|
||||
|
||||
// write some data to the flash using software (there is no hardware write controller)
|
||||
void write_spiflash(uint8_t *data, uint32_t len, uint32_t addr, uint8_t cmd, uint8_t abytes, uint8_t aproto, uint8_t dproto)
|
||||
{
|
||||
|
||||
spi_fmt fmt;
|
||||
fmt.fields.proto = SPIFLASH_PROTO_SINGLE;
|
||||
fmt.fields.endian = SPIFLASH_ENDIAN_MSB;
|
||||
fmt.fields.iodir = SPIFLASH_IODIR_TX;
|
||||
fmt.fields.len = 8;
|
||||
|
||||
uint32_t i;
|
||||
|
||||
// Need to be out of flash mode
|
||||
reg_write32(SPIFLASH_BASE_CTRL + SPIFLASH_OFFS_FLASH_EN, 0);
|
||||
|
||||
reg_write32(SPIFLASH_BASE_CTRL + SPIFLASH_OFFS_FMT, fmt.bits);
|
||||
reg_write32(SPIFLASH_BASE_CTRL + SPIFLASH_OFFS_CSMODE, CSMODE_HOLD);
|
||||
|
||||
spi_data_write(cmd);
|
||||
|
||||
// need to wait a bit to flush the tx queue before changing fmt
|
||||
for(i = 0; i < 0x100; i++) asm volatile ("nop");
|
||||
|
||||
fmt.fields.proto = aproto;
|
||||
reg_write32(SPIFLASH_BASE_CTRL + SPIFLASH_OFFS_FMT, fmt.bits);
|
||||
|
||||
for (i = abytes; i > 0; i--)
|
||||
{
|
||||
spi_data_write((uint8_t)(addr >> (i*8-8)));
|
||||
}
|
||||
|
||||
// need to wait a bit to flush the tx queue before changing fmt
|
||||
for(i = 0; i < 0x100; i++) asm volatile ("nop");
|
||||
|
||||
fmt.fields.proto = dproto;
|
||||
reg_write32(SPIFLASH_BASE_CTRL + SPIFLASH_OFFS_FMT, fmt.bits);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
spi_data_write(data[i]);
|
||||
}
|
||||
|
||||
// need to wait a bit to flush the tx queue before deasserting CS
|
||||
for(i = 0; i < 0x100; i++) asm volatile ("nop");
|
||||
|
||||
reg_write32(SPIFLASH_BASE_CTRL + SPIFLASH_OFFS_CSMODE, CSMODE_OFF);
|
||||
|
||||
// go back into flash read mode
|
||||
reg_write32(SPIFLASH_BASE_CTRL + SPIFLASH_OFFS_FLASH_EN, 1);
|
||||
|
||||
}
|
||||
|
||||
// test that a large chunk of memory contains (0xdeadbeef - address) or 0
|
||||
int test_spiflash(uint32_t start, uint32_t size, uint8_t zero)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = start; i < (start + size); i += 4)
|
||||
{
|
||||
uint32_t data = reg_read32(SPIFLASH_BASE_MEM + i);
|
||||
uint32_t check = 0;
|
||||
if (!zero) check = 0xdeadbeef - i;
|
||||
if(data != check)
|
||||
{
|
||||
printf("Error reading address 0x%08x from SPI flash. Got 0x%08x, expected 0x%08x.\n", i, data, check);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// this is a variant of test_spiflash that only tests a small array of values
|
||||
int check_write(uint8_t *check, uint32_t len, uint32_t addr)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < len; i += 4)
|
||||
{
|
||||
uint32_t data = reg_read32(SPIFLASH_BASE_MEM + addr + i);
|
||||
uint32_t check32 = ((uint32_t *)check)[i/4];
|
||||
if(check32 != data)
|
||||
{
|
||||
printf("Error reading address 0x%08x from SPI flash. Got 0x%02x, expected 0x%02x.\n", i + addr, data, check32);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __SPIFLASH_H__ */
|
||||
Reference in New Issue
Block a user