#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 0x10030000 // 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__ */