From 09fe20efda03c43bce2d97f37944a10786c46bf3 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 28 Nov 2018 13:19:51 -0500 Subject: [PATCH] fomu-flash: first full commit Signed-off-by: Your Name --- .gitignore | 2 +- Makefile | 10 +- fomu-flash.c | 334 +++++++++++++++++++++++++++++++++++++++++++ fpga.c | 112 +++++++++++++++ fpga.h | 78 +++++++++++ bbflash.c => spi.c | 343 +++++++++++++-------------------------------- spi.h | 69 +++++++++ 7 files changed, 697 insertions(+), 251 deletions(-) create mode 100644 fomu-flash.c create mode 100644 fpga.c create mode 100644 fpga.h rename bbflash.c => spi.c (62%) create mode 100644 spi.h diff --git a/.gitignore b/.gitignore index a097b40..021bac1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ .obj *.swp *.swo -bbflash +fomu-flash diff --git a/Makefile b/Makefile index a41189a..48c8a10 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -PACKAGE = $(notdir $(realpath .)) +PACKAGE = fomu-flash ADD_CFLAGS = ADD_LFLAGS = @@ -21,11 +21,9 @@ endif DBG_CFLAGS = -ggdb -g -DDEBUG -Wall DBG_LFLAGS = -ggdb -g -Wall CFLAGS = $(ADD_CFLAGS) \ - -Wall -Wextra \ - -ffunction-sections -fdata-sections -fno-common \ - -fomit-frame-pointer -Os \ - -DGIT_VERSION=u\"$(GIT_VERSION)\" -std=gnu11 -CXXFLAGS = $(CFLAGS) -std=c++11 + -Wall -Wextra -O2 \ + -DGIT_VERSION=u\"$(GIT_VERSION)\" +CXXFLAGS = $(CFLAGS) LFLAGS = $(ADD_LFLAGS) $(CFLAGS) \ OBJ_DIR = .obj diff --git a/fomu-flash.c b/fomu-flash.c new file mode 100644 index 0000000..98ed565 --- /dev/null +++ b/fomu-flash.c @@ -0,0 +1,334 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rpi.h" +#include "spi.h" +#include "fpga.h" + +#define S_MOSI 10 +#define S_MISO 9 +#define S_CLK 11 +#define S_CE0 8 +#define S_HOLD 25 +#define S_WP 24 +#define S_D0 S_MOSI +#define S_D1 S_MISO +#define S_D2 S_WP +#define S_D3 S_HOLD +#define F_RESET 27 +#define F_DONE 17 + +static inline int isprint(int c) +{ + return c > 32 && c < 127; +} + +int print_hex_offset(FILE *stream, + const void *block, int count, int offset, uint32_t start) +{ + + int byte; + const uint8_t *b = block; + + count += offset; + b -= offset; + for ( ; offset < count; offset += 16) { + fprintf(stream, "%08x", start + offset); + + for (byte = 0; byte < 16; byte++) { + if (byte == 8) + fprintf(stream, " "); + fprintf(stream, " "); + if (offset + byte < count) + fprintf(stream, "%02x", b[offset + byte] & 0xff); + else + fprintf(stream, " "); + } + + fprintf(stream, " |"); + for (byte = 0; byte < 16 && byte + offset < count; byte++) + fprintf(stream, "%c", isprint(b[offset + byte]) ? b[offset + byte] : '.'); + fprintf(stream, "|\r\n"); + } + return 0; +} + +int print_hex(const void *block, int count, uint32_t start) +{ + FILE *stream = stdout; + return print_hex_offset(stream, block, count, 0, start); +} + +enum op { + OP_SPI_READ, + OP_SPI_WRITE, + OP_SPI_VERIFY, + OP_SPI_PEEK, + OP_FPGA_BOOT, + OP_FPGA_RESET, + OP_UNKNOWN, +}; + +int print_help(FILE *stream, const char *progname) { + fprintf(stream, "Fomu Raspberry Pi Flash Utilities\n"); + fprintf(stream, "Usage:\n"); + fprintf(stream, " %s [-h] [-r] [-p] [-f bin] [-w bin] [-v bin] [-s out] [-2 pin] [-3 pin]\n", progname); + fprintf(stream, "Flags:\n"); + fprintf(stream, " -h This help page\n"); + fprintf(stream, " -r Reset the FPGA and have it boot from SPI\n"); + fprintf(stream, " -p Peek at the first 256 bytes of SPI flash\n"); + fprintf(stream, " -f bin Load this binary directly into the FPGA\n"); + fprintf(stream, " -w bin Write this binary into the SPI flash chip\n"); + fprintf(stream, " -v bin Verify the SPI flash contains this data\n"); + fprintf(stream, " -s out Save the SPI flash contents to this file\n"); + fprintf(stream, " -2 pin Use this pin number as QSPI IO2\n"); + fprintf(stream, " -3 pin Use this pin number as QSPI IO3\n"); + return 0; +} + +int main(int argc, char **argv) { + int opt; + int fd; + char *op_filename = NULL; + struct ff_spi *spi; + struct ff_fpga *fpga; + enum op op = OP_UNKNOWN; + + spi = spiAlloc(); + fpga = fpgaAlloc(); + + spiSetPin(spi, SP_CLK, S_CLK); + spiSetPin(spi, SP_D0, S_D0); + spiSetPin(spi, SP_D1, S_D1); + spiSetPin(spi, SP_D2, S_D2); + spiSetPin(spi, SP_D3, S_D3); + spiSetPin(spi, SP_MISO, S_MISO); + spiSetPin(spi, SP_MOSI, S_MOSI); + spiSetPin(spi, SP_HOLD, S_HOLD); + spiSetPin(spi, SP_WP, S_WP); + spiSetPin(spi, SP_CS, S_CE0); + + fpgaSetPin(fpga, FP_RESET, F_RESET); + fpgaSetPin(fpga, FP_DONE, F_DONE); + fpgaSetPin(fpga, FP_CS, S_CE0); + + if (gpioInitialise() < 0) { + fprintf(stderr, "Unable to initialize GPIO\n"); + return 1; + } + + while ((opt = getopt(argc, argv, "hprf:w:s:2:3:v:")) != -1) { + switch (opt) { + case '2': + spiSetPin(spi, SP_D2, strtoul(optarg, NULL, 0)); + break; + + case '3': + spiSetPin(spi, SP_D3, strtoul(optarg, NULL, 0)); + break; + + case 'r': + op = OP_FPGA_RESET; + break; + + case 'p': + op = OP_SPI_PEEK; + break; + + case 'f': + op = OP_FPGA_BOOT; + if (op_filename) + free(op_filename); + op_filename = strdup(optarg); + break; + + case 'w': + op = OP_SPI_WRITE; + if (op_filename) + free(op_filename); + op_filename = strdup(optarg); + break; + + case 'v': + op = OP_SPI_VERIFY; + if (op_filename) + free(op_filename); + op_filename = strdup(optarg); + break; + + case 's': + op = OP_SPI_READ; + if (op_filename) + free(op_filename); + op_filename = strdup(optarg); + break; + + default: + print_help(stdout, argv[0]); + return 1; + } + } + + if (op == OP_UNKNOWN) { + print_help(stdout, argv[0]); + return 1; + } + + spiInit(spi); + fpgaInit(fpga); + + switch (op) { + case OP_SPI_READ: { + spiSetType(spi, ST_QPI); + fpgaReset(fpga); + fd = open(op_filename, O_WRONLY | O_CREAT | O_TRUNC, 0777); + if (fd == -1) { + perror("unable to open output file"); + break; + } + uint8_t *bfr = malloc(16777216); + spiRead(spi, 0, bfr, 16777216); + if (write(fd, bfr, 16777216) != 16777216) { + perror("unable to write SPI flash image"); + break; + } + close(fd); + free(bfr); + break; + } + + case OP_SPI_WRITE: { + spiSetType(spi, ST_QPI); + fpgaReset(fpga); + fd = open(op_filename, O_RDONLY); + if (fd == -1) { + perror("unable to open input file"); + break; + } + struct stat stat; + if (fstat(fd, &stat) == -1) { + perror("unable to get bitstream file size"); + break; + } + + uint8_t *bfr = malloc(stat.st_size); + if (!bfr) { + perror("unable to alloc memory for buffer"); + break; + } + if (read(fd, bfr, stat.st_size) != stat.st_size) { + perror("unable to read from file"); + free(bfr); + break; + } + close(fd); + spiWrite(spi, 0, bfr, stat.st_size); + break; + } + + case OP_SPI_VERIFY: { + + spiSetType(spi, ST_QPI); + fpgaReset(fpga); + fd = open(op_filename, O_RDONLY); + if (fd == -1) { + perror("unable to open input file"); + break; + } + struct stat stat; + if (fstat(fd, &stat) == -1) { + perror("unable to get bitstream file size"); + break; + } + + uint8_t *file_src = malloc(stat.st_size); + uint8_t *spi_src = malloc(stat.st_size); + if (!file_src) { + perror("unable to alloc memory for buffer"); + break; + } + if (read(fd, file_src, stat.st_size) != stat.st_size) { + perror("unable to read from file"); + free(file_src); + break; + } + close(fd); + + spiRead(spi, 0, spi_src, stat.st_size); + + int offset; + for (offset = 0; offset < stat.st_size; offset++) { + if (file_src[offset] != spi_src[offset]) + printf("%9d: file: %02x spi: %02x\n", +offset, file_src[offset], spi_src[offset]); + } + break; + } + + case OP_SPI_PEEK: { + fpgaReset(fpga); + spiSetType(spi, ST_QPI); + uint8_t page0[256]; + spiRead(spi, 0, page0, sizeof(page0)); + print_hex(page0, sizeof(page0), 0); + break; + } + + case OP_FPGA_BOOT: { + spiHold(spi); + spiSwapTxRx(spi); + fpgaResetSlave(fpga); + + fprintf(stderr, "FPGA Done? %d\n", fpgaDone(fpga)); + + int fd = open(op_filename, O_RDONLY); + if (fd == -1) { + perror("unable to open fpga bitstream"); + break; + } + + spiBegin(spi); + + uint8_t bfr[32768]; + int count; + while ((count = read(fd, bfr, sizeof(bfr))) > 0) { + int i; + for (i = 0; i < count; i++) + spiTx(spi, bfr[i]); + } + if (count < 0) { + perror("unable to read from fpga bitstream file"); + break; + } + close(fd); + for (count = 0; count < 500; count++) + spiTx(spi, 0xff); + fprintf(stderr, "FPGA Done? %d\n", fpgaDone(fpga)); + spiEnd(spi); + + spiSwapTxRx(spi); + spiUnhold(spi); + break; + } + + case OP_FPGA_RESET: + printf("resetting fpga\n"); + fpgaResetMaster(fpga); + break; + + default: + fprintf(stderr, "error: unknown operation\n"); + break; + } + + fpgaFree(&fpga); + spiFree(&spi); + + return 0; +} diff --git a/fpga.c b/fpga.c new file mode 100644 index 0000000..88b112c --- /dev/null +++ b/fpga.c @@ -0,0 +1,112 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rpi.h" +#include "fpga.h" + +struct ff_fpga { + struct { + int reset; + int done; + int cs; + } pins; +}; + +int fpgaDone(struct ff_fpga *fpga) { + return gpioRead(fpga->pins.done); +} + +int fpgaResetSlave(struct ff_fpga *fpga) { + // Put the FPGA into reset + gpioSetMode(fpga->pins.reset, PI_OUTPUT); + gpioWrite(fpga->pins.reset, 0); + + // Set the CS pin to a GPIO, which will let us control it + gpioSetMode(fpga->pins.cs, PI_OUTPUT); + + // Set CS to 0, which will put the FPGA into slave mode + gpioWrite(fpga->pins.cs, 0); + + usleep(10000); // XXX figure out correct sleep length here + + // Bring the FPGA out of reset + gpioWrite(fpga->pins.reset, 1); + + usleep(1200); // 13.2.SPI Slave Configuration Process + + // Release the CS pin + gpioWrite(fpga->pins.cs, 1); + + return 0; +} + +int fpgaResetMaster(struct ff_fpga *fpga) { + + // Put the FPGA into reset + gpioSetMode(fpga->pins.reset, PI_OUTPUT); + gpioWrite(fpga->pins.reset, 0); + + // Set the CS pin to a GPIO, which will let us control it + gpioSetMode(fpga->pins.cs, PI_OUTPUT); + + // Set CS to 1, which will put the FPGA into "self boot" mode + gpioWrite(fpga->pins.cs, 1); + + usleep(10000); // XXX figure out correct sleep length here + + // Bring the FPGA out of reset + gpioWrite(fpga->pins.reset, 1); + + usleep(1200); // 13.2.SPI Slave Configuration Process + + return 0; +} + +int fpgaReset(struct ff_fpga *fpga) { + // Put the FPGA into reset + gpioSetMode(fpga->pins.reset, PI_OUTPUT); + gpioWrite(fpga->pins.reset, 0); + return 0; +} + +int fpgaInit(struct ff_fpga *fpga) { + // Put the FPGA into reset + gpioSetMode(fpga->pins.reset, PI_OUTPUT); + gpioWrite(fpga->pins.reset, 0); + + // Also monitor the C_DONE pin + gpioSetMode(fpga->pins.done, PI_INPUT); + + return 0; +} + +struct ff_fpga *fpgaAlloc(void) { + struct ff_fpga *fpga = (struct ff_fpga *)malloc(sizeof(struct ff_fpga)); + memset(fpga, 0, sizeof(*fpga)); + return fpga; +} + +void fpgaSetPin(struct ff_fpga *fpga, enum fpga_pin pin, int val) { + switch (pin) { + case FP_RESET: fpga->pins.reset = val; break; + case FP_DONE: fpga->pins.done = val; break; + case FP_CS: fpga->pins.cs = val; break; + default: fprintf(stderr, "unrecognized pin: %d\n", pin); break; + } +} + +void fpgaFree(struct ff_fpga **fpga) { + if (!fpga) + return; + if (!*fpga) + return; + + free(*fpga); + *fpga = NULL; +} diff --git a/fpga.h b/fpga.h new file mode 100644 index 0000000..6536d34 --- /dev/null +++ b/fpga.h @@ -0,0 +1,78 @@ +#ifndef BB_FPGA_H_ +#define BB_FPGA_H_ + +#include + +struct ff_fpga; + +enum fpga_pin { + FP_RESET, + FP_DONE, + FP_CS, +}; + +#if 0 +enum spi_state { + SS_UNCONFIGURED = 0, + SS_SINGLE, + SS_DUAL_RX, + SS_DUAL_TX, + SS_QUAD_RX, + SS_QUAD_TX, + SS_HARDWARE, +}; + +enum spi_type { + ST_UNCONFIGURED, + ST_SINGLE, + ST_DUAL, + ST_QUAD, + ST_QPI, +}; + +enum spi_pin { + SP_MOSI, + SP_MISO, + SP_HOLD, + SP_WP, + SP_CS, + SP_CLK, + SP_D0, + SP_D1, + SP_D2, + SP_D3, +}; + +struct ff_spi; + +void spiPause(struct ff_spi *spi); +void spiBegin(struct ff_spi *spi); +void spiEnd(struct ff_spi *spi); + +//void spiSingleTx(struct ff_spi *spi, uint8_t out); +//uint8_t spiSingleRx(struct ff_spi *spi); +//void spiDualTx(struct ff_spi *spi, uint8_t out); +//void spiQuadTx(struct ff_spi *spi, uint8_t out); +void spiCommand(struct ff_spi *spi, uint8_t cmd); +//uint8_t spiDualRx(struct ff_spi *spi); +//uint8_t spiQuadRx(struct ff_spi *spi); +int spiTx(struct ff_spi *spi, uint8_t word); +uint8_t spiRx(struct ff_spi *spi); +uint8_t spiReadSr(struct ff_spi *spi, int sr); +void spiWriteSr(struct ff_spi *spi, int sr, uint8_t val); +int spiSetType(struct ff_spi *spi, enum spi_type type); +int spiRead(struct ff_spi *spi, uint32_t addr, uint8_t *data, unsigned int count); +//int spi_wait_for_not_busy(struct ff_spi *spi); +int spiWrite(struct ff_spi *spi, uint32_t addr, const uint8_t *data, unsigned int count); +#endif +int fpgaResetSlave(struct ff_fpga *fpga); +int fpgaResetMaster(struct ff_fpga *fpga); +int fpgaReset(struct ff_fpga *fpga); +int fpgaInit(struct ff_fpga *fpga); +int fpgaDone(struct ff_fpga *fpga); + +struct ff_fpga *fpgaAlloc(void); +void fpgaSetPin(struct ff_fpga *fpga, enum fpga_pin pin, int val); +void fpgaFree(struct ff_fpga **fpga); + +#endif /* BB_FPGA_H_ */ diff --git a/bbflash.c b/spi.c similarity index 62% rename from bbflash.c rename to spi.c index bd95889..9e0fbd2 100644 --- a/bbflash.c +++ b/spi.c @@ -5,44 +5,15 @@ #include #include #include +#include #include "rpi.h" +#include "spi.h" -#define S_MOSI 10 -#define S_MISO 9 -#define S_CLK 11 -#define S_CE0 8 -#define S_HOLD 25 -#define S_WP 24 -#define S_D0 S_MOSI -#define S_D1 S_MISO -#define S_D2 S_WP -#define S_D3 S_HOLD -#define F_RESET 27 -#define F_DONE 17 - -enum spi_state { - SS_UNCONFIGURED = 0, - SS_SINGLE, - SS_DUAL_RX, - SS_DUAL_TX, - SS_QUAD_RX, - SS_QUAD_TX, - SS_HARDWARE, -}; - -enum spi_type { - ST_UNCONFIGURED, - ST_SINGLE, - ST_DUAL, - ST_QUAD, - ST_QPI, -}; - -struct bb_spi { +struct ff_spi { enum spi_state state; enum spi_type type; - int qpi; + enum spi_type desired_type; struct { int clk; @@ -58,7 +29,7 @@ struct bb_spi { } pins; }; -static void spi_set_state(struct bb_spi *spi, enum spi_state state) { +static void spi_set_state(struct ff_spi *spi, enum spi_state state) { if (spi->state == state) return; @@ -125,22 +96,23 @@ static void spi_set_state(struct bb_spi *spi, enum spi_state state) { spi->state = state; } -static void spi_pause(void) { +void spiPause(struct ff_spi *spi) { + (void)spi; // usleep(1); return; } -static void spiBegin(struct bb_spi *spi) { +void spiBegin(struct ff_spi *spi) { spi_set_state(spi, SS_SINGLE); gpioWrite(spi->pins.cs, 0); } -static void spiEnd(struct bb_spi *spi) { +void spiEnd(struct ff_spi *spi) { (void)spi; gpioWrite(spi->pins.cs, 1); } -static uint8_t spiXfer(struct bb_spi *spi, uint8_t out) { +static uint8_t spiXfer(struct ff_spi *spi, uint8_t out) { int bit; uint8_t in = 0; for (bit = 7; bit >= 0; bit--) { @@ -151,25 +123,25 @@ static uint8_t spiXfer(struct bb_spi *spi, uint8_t out) { gpioWrite(spi->pins.mosi, 0); } gpioWrite(spi->pins.clk, 1); - spi_pause(); + spiPause(spi); in |= ((!!gpioRead(spi->pins.miso)) << bit); gpioWrite(spi->pins.clk, 0); - spi_pause(); + spiPause(spi); } return in; } -static void spiSingleTx(struct bb_spi *spi, uint8_t out) { +static void spiSingleTx(struct ff_spi *spi, uint8_t out) { spi_set_state(spi, SS_SINGLE); spiXfer(spi, out); } -static uint8_t spiSingleRx(struct bb_spi *spi) { +static uint8_t spiSingleRx(struct ff_spi *spi) { spi_set_state(spi, SS_SINGLE); return spiXfer(spi, 0xff); } -static void spiDualTx(struct bb_spi *spi, uint8_t out) { +static void spiDualTx(struct ff_spi *spi, uint8_t out) { int bit; spi_set_state(spi, SS_DUAL_TX); for (bit = 7; bit >= 0; bit -= 2) { @@ -187,13 +159,13 @@ static void spiDualTx(struct bb_spi *spi, uint8_t out) { gpioWrite(spi->pins.d1, 0); } gpioWrite(spi->pins.clk, 1); - spi_pause(); + spiPause(spi); gpioWrite(spi->pins.clk, 0); - spi_pause(); + spiPause(spi); } } -static void spiQuadTx(struct bb_spi *spi, uint8_t out) { +static void spiQuadTx(struct ff_spi *spi, uint8_t out) { int bit; spi_set_state(spi, SS_QUAD_TX); for (bit = 7; bit >= 0; bit -= 4) { @@ -225,54 +197,54 @@ static void spiQuadTx(struct bb_spi *spi, uint8_t out) { gpioWrite(spi->pins.d3, 0); } gpioWrite(spi->pins.clk, 1); - spi_pause(); + spiPause(spi); gpioWrite(spi->pins.clk, 0); - spi_pause(); + spiPause(spi); } } -void spiCommand(struct bb_spi *spi, uint8_t cmd) { - if (spi->qpi) +void spiCommand(struct ff_spi *spi, uint8_t cmd) { + if (spi->type == ST_QPI) spiQuadTx(spi, cmd); else spiSingleTx(spi, cmd); } -static uint8_t spiDualRx(struct bb_spi *spi) { +static uint8_t spiDualRx(struct ff_spi *spi) { int bit; uint8_t in = 0; spi_set_state(spi, SS_QUAD_RX); for (bit = 7; bit >= 0; bit -= 2) { gpioWrite(spi->pins.clk, 1); - spi_pause(); + spiPause(spi); in |= ((!!gpioRead(spi->pins.d0)) << (bit - 1)); in |= ((!!gpioRead(spi->pins.d1)) << (bit - 0)); gpioWrite(spi->pins.clk, 0); - spi_pause(); + spiPause(spi); } return in; } -static uint8_t spiQuadRx(struct bb_spi *spi) { +static uint8_t spiQuadRx(struct ff_spi *spi) { int bit; uint8_t in = 0; spi_set_state(spi, SS_QUAD_RX); for (bit = 7; bit >= 0; bit -= 4) { gpioWrite(spi->pins.clk, 1); - spi_pause(); + spiPause(spi); in |= ((!!gpioRead(spi->pins.d0)) << (bit - 3)); in |= ((!!gpioRead(spi->pins.d1)) << (bit - 2)); in |= ((!!gpioRead(spi->pins.d2)) << (bit - 1)); in |= ((!!gpioRead(spi->pins.d3)) << (bit - 0)); gpioWrite(spi->pins.clk, 0); - spi_pause(); + spiPause(spi); } return in; } -int spiTx(struct bb_spi *spi, uint8_t word) { +int spiTx(struct ff_spi *spi, uint8_t word) { switch (spi->type) { case ST_SINGLE: spiSingleTx(spi, word); @@ -290,7 +262,7 @@ int spiTx(struct bb_spi *spi, uint8_t word) { return 0; } -uint8_t spiRx(struct bb_spi *spi) { +uint8_t spiRx(struct ff_spi *spi) { switch (spi->type) { case ST_SINGLE: return spiSingleRx(spi); @@ -304,7 +276,7 @@ uint8_t spiRx(struct bb_spi *spi) { } } -uint8_t spiReadSr(struct bb_spi *spi, int sr) { +uint8_t spiReadSr(struct ff_spi *spi, int sr) { uint8_t val = 0xff; switch (sr) { @@ -337,7 +309,7 @@ uint8_t spiReadSr(struct bb_spi *spi, int sr) { return val; } -void spiWriteSr(struct bb_spi *spi, int sr, uint8_t val) { +void spiWriteSr(struct ff_spi *spi, int sr, uint8_t val) { switch (sr) { case 1: spiBegin(spi); @@ -378,7 +350,7 @@ void spiWriteSr(struct bb_spi *spi, int sr, uint8_t val) { } } -int spiSetType(struct bb_spi *spi, enum spi_type type) { +int spiSetType(struct ff_spi *spi, enum spi_type type) { if (spi->type == type) return 0; @@ -390,7 +362,6 @@ int spiSetType(struct bb_spi *spi, enum spi_type type) { spiBegin(spi); spiCommand(spi, 0xff); // Exit QPI Mode spiEnd(spi); - spi->qpi = 0; } spi->type = type; spi_set_state(spi, SS_SINGLE); @@ -401,7 +372,6 @@ int spiSetType(struct bb_spi *spi, enum spi_type type) { spiBegin(spi); spiCommand(spi, 0xff); // Exit QPI Mode spiEnd(spi); - spi->qpi = 0; } spi->type = type; spi_set_state(spi, SS_DUAL_TX); @@ -412,7 +382,6 @@ int spiSetType(struct bb_spi *spi, enum spi_type type) { spiBegin(spi); spiCommand(spi, 0xff); // Exit QPI Mode spiEnd(spi); - spi->qpi = 0; } // Enable QE bit @@ -429,7 +398,6 @@ int spiSetType(struct bb_spi *spi, enum spi_type type) { spiBegin(spi); spiCommand(spi, 0x38); // Enter QPI Mode spiEnd(spi); - spi->qpi = 1; spi->type = type; spi_set_state(spi, SS_QUAD_TX); break; @@ -441,7 +409,7 @@ int spiSetType(struct bb_spi *spi, enum spi_type type) { return 0; } -int spiRead(struct bb_spi *spi, uint32_t addr, uint8_t *data, unsigned int count) { +int spiRead(struct ff_spi *spi, uint32_t addr, uint8_t *data, unsigned int count) { unsigned int i; @@ -473,7 +441,7 @@ int spiRead(struct bb_spi *spi, uint32_t addr, uint8_t *data, unsigned int count return 0; } -int spi_wait_for_not_busy(struct bb_spi *spi) { +static int spi_wait_for_not_busy(struct ff_spi *spi) { uint8_t sr1; sr1 = spiReadSr(spi, 1); @@ -483,7 +451,16 @@ int spi_wait_for_not_busy(struct bb_spi *spi) { return 0; } -int spiWrite(struct bb_spi *spi, uint32_t addr, const uint8_t *data, unsigned int count) { +void spiSwapTxRx(struct ff_spi *spi) { + int tmp = spi->pins.mosi; + spi->pins.mosi = spi->pins.miso; + spi->pins.miso = tmp; + spiSetType(spi, ST_SINGLE); + spi->state = SS_UNCONFIGURED; + spi_set_state(spi, SS_SINGLE); +} + +int spiWrite(struct ff_spi *spi, uint32_t addr, const uint8_t *data, unsigned int count) { unsigned int i; @@ -546,43 +523,30 @@ int spiWrite(struct bb_spi *spi, uint32_t addr, const uint8_t *data, unsigned in return 0; } -uint8_t spiReset(struct bb_spi *spi) { +uint8_t spiReset(struct ff_spi *spi) { // XXX You should check the "Ready" bit before doing this! + // Shift to QPI mode, then back to Single mode, to ensure + // we're actually in Single mode. + spiSetType(spi, ST_QPI); spiSetType(spi, ST_SINGLE); spiBegin(spi); - spiSingleTx(spi, 0x66); // "Enable Reset" command + spiCommand(spi, 0x66); // "Enable Reset" command spiEnd(spi); spiBegin(spi); - spiSingleTx(spi, 0x99); // "Reset Device" command + spiCommand(spi, 0x99); // "Reset Device" command spiEnd(spi); usleep(30); return 0; } -void fpgaSlaveMode(struct bb_spi *spi) { - - // Set the CS pin to a GPIO, which will let us control it - gpioSetMode(spi->pins.cs, PI_OUTPUT); - - // Set CS to 0, which will put the FPGA into slave mode - gpioWrite(spi->pins.cs, 0); - - usleep(10000); // XXX figure out correct sleep length here - - // Bring the FPGA out of reset - gpioWrite(F_RESET, 1); - - usleep(1200); // 13.2.SPI Slave Configuration Process -} - -int spiInit(struct bb_spi *spi) { +int spiInit(struct ff_spi *spi) { spi->state = SS_UNCONFIGURED; spi->type = ST_UNCONFIGURED; - spi->qpi = 0; + // Reset the SPI flash, which will return it to SPI mode even // if it's in QPI mode. @@ -590,163 +554,54 @@ int spiInit(struct bb_spi *spi) { spiSetType(spi, ST_SINGLE); - return 0; -} - - -static inline int isprint(int c) -{ - return c > 32 && c < 127; -} - -int print_hex_offset(FILE *stream, - const void *block, int count, int offset, uint32_t start) -{ - - int byte; - const uint8_t *b = block; - - count += offset; - b -= offset; - for ( ; offset < count; offset += 16) { - fprintf(stream, "%08x", start + offset); - - for (byte = 0; byte < 16; byte++) { - if (byte == 8) - fprintf(stream, " "); - fprintf(stream, " "); - if (offset + byte < count) - fprintf(stream, "%02x", b[offset + byte] & 0xff); - else - fprintf(stream, " "); - } - - fprintf(stream, " |"); - for (byte = 0; byte < 16 && byte + offset < count; byte++) - fprintf(stream, "%c", isprint(b[offset + byte]) ? b[offset + byte] : '.'); - fprintf(stream, "|\r\n"); - } - return 0; -} - -int print_hex(const void *block, int count, uint32_t start) -{ - FILE *stream = stdout; - return print_hex_offset(stream, block, count, 0, start); -} - -int main(int argc, char *argv[]) -{ - int result; - struct bb_spi spi; - - if (gpioInitialise() < 0) { - fprintf(stderr, "Unable to initialize GPIO\n"); - return 1; - } - - /* The dance to put the FPGA into programming mode: - * 1) Put it into reset (set C_RESET to 0) - * 2) Drive CS to 0 - * 3) Bring it out of reset - * 4) Let CS go back to 1 - * 5) Set HOLD/ on the SPI flash by setting pin 25 to 0 - * To program the FPGA - */ - - spi.pins.clk = S_CLK; - spi.pins.d0 = S_D0; - spi.pins.d1 = S_D1; - spi.pins.d2 = S_D2; - spi.pins.d3 = S_D3; - spi.pins.miso = S_MISO; - spi.pins.mosi = S_MOSI; - spi.pins.hold = S_HOLD; - spi.pins.wp = S_WP; - spi.pins.cs = S_CE0; - // Have the SPI flash pay attention to us - gpioWrite(spi.pins.hold, 1); - + gpioWrite(spi->pins.hold, 1); // Disable WP - gpioWrite(spi.pins.wp, 1); - - // Put the FPGA into reset - gpioSetMode(F_RESET, PI_OUTPUT); - gpioWrite(F_RESET, 0); - - // Also monitor the C_DONE pin - gpioSetMode(F_DONE, PI_INPUT); - - // Restart the FPGA in slave mode - //fpgaSlaveMode(); - - result = gpioRead(F_DONE); - fprintf(stderr, "Reset before running: %d\n", result); - - spiInit(&spi); - - spiSetType(&spi, ST_QPI); - - // Assert CS - spiBegin(&spi); - - int i; - fprintf(stderr, "Write:"); - spiCommand(&spi, 0x90); - spiTx(&spi, 0x00); // A23-16 - spiTx(&spi, 0x00); // A15-8 - spiRx(&spi); // Dummy0 - spiRx(&spi); // Dummy1 - fprintf(stderr, "\nRead:"); - for (i=0; i<16; i++) { - fprintf(stderr, " 0x%02x", spiRx(&spi)); - } - fprintf(stderr, "\n"); - spiEnd(&spi); - - - uint8_t data[383316]; - { - memset(data, 0xaa, sizeof(data)); - int fd = open("/tmp/image-gateware+bios+micropython.bin", O_RDONLY); - if (read(fd, data, sizeof(data)) != sizeof(data)) { - perror("uanble to read"); - return 1; - } - spiWrite(&spi, 0, data, sizeof(data)); - } - - { - uint8_t page0[256]; - spiRead(&spi, 0, page0, sizeof(page0)); - print_hex(page0, sizeof(page0), 0); - } - { - uint8_t check_data[sizeof(data)]; - spiRead(&spi, 0, check_data, sizeof(check_data)); - size_t j; - for (j=0; jpins.wp, 1); return 0; } + +struct ff_spi *spiAlloc(void) { + struct ff_spi *spi = (struct ff_spi *)malloc(sizeof(struct ff_spi)); + memset(spi, 0, sizeof(*spi)); + return spi; +} + +void spiSetPin(struct ff_spi *spi, enum spi_pin pin, int val) { + switch (pin) { + case SP_MOSI: spi->pins.mosi = val; break; + case SP_MISO: spi->pins.miso = val; break; + case SP_HOLD: spi->pins.hold = val; break; + case SP_WP: spi->pins.wp = val; break; + case SP_CS: spi->pins.cs = val; break; + case SP_CLK: spi->pins.clk = val; break; + case SP_D0: spi->pins.d0 = val; break; + case SP_D1: spi->pins.d1 = val; break; + case SP_D2: spi->pins.d2 = val; break; + case SP_D3: spi->pins.d3 = val; break; + default: fprintf(stderr, "unrecognized pin: %d\n", pin); break; + } +} + +void spiHold(struct ff_spi *spi) { + spiBegin(spi); + spiCommand(spi, 0xb9); + spiEnd(spi); +} +void spiUnhold(struct ff_spi *spi) { + spiBegin(spi); + spiCommand(spi, 0xab); + spiEnd(spi); +} + +void spiFree(struct ff_spi **spi) { + if (!spi) + return; + if (!*spi) + return; + + spi_set_state(*spi, SS_HARDWARE); + free(*spi); + *spi = NULL; +} diff --git a/spi.h b/spi.h new file mode 100644 index 0000000..52c5f37 --- /dev/null +++ b/spi.h @@ -0,0 +1,69 @@ +#ifndef BB_SPI_H_ +#define BB_SPI_H_ + +#include + +enum spi_state { + SS_UNCONFIGURED = 0, + SS_SINGLE, + SS_DUAL_RX, + SS_DUAL_TX, + SS_QUAD_RX, + SS_QUAD_TX, + SS_HARDWARE, +}; + +enum spi_type { + ST_UNCONFIGURED, + ST_SINGLE, + ST_DUAL, + ST_QUAD, + ST_QPI, +}; + +enum spi_pin { + SP_MOSI, + SP_MISO, + SP_HOLD, + SP_WP, + SP_CS, + SP_CLK, + SP_D0, + SP_D1, + SP_D2, + SP_D3, +}; + +struct ff_spi; + +void spiPause(struct ff_spi *spi); +void spiBegin(struct ff_spi *spi); +void spiEnd(struct ff_spi *spi); + +//void spiSingleTx(struct ff_spi *spi, uint8_t out); +//uint8_t spiSingleRx(struct ff_spi *spi); +//void spiDualTx(struct ff_spi *spi, uint8_t out); +//void spiQuadTx(struct ff_spi *spi, uint8_t out); +void spiCommand(struct ff_spi *spi, uint8_t cmd); +//uint8_t spiDualRx(struct ff_spi *spi); +//uint8_t spiQuadRx(struct ff_spi *spi); +int spiTx(struct ff_spi *spi, uint8_t word); +uint8_t spiRx(struct ff_spi *spi); +uint8_t spiReadSr(struct ff_spi *spi, int sr); +void spiWriteSr(struct ff_spi *spi, int sr, uint8_t val); +int spiSetType(struct ff_spi *spi, enum spi_type type); +int spiRead(struct ff_spi *spi, uint32_t addr, uint8_t *data, unsigned int count); +//int spi_wait_for_not_busy(struct ff_spi *spi); +int spiWrite(struct ff_spi *spi, uint32_t addr, const uint8_t *data, unsigned int count); +uint8_t spiReset(struct ff_spi *spi); +int spiInit(struct ff_spi *spi); + +void spiHold(struct ff_spi *spi); +void spiUnhold(struct ff_spi *spi); +void spiSwapTxRx(struct ff_spi *spi); + +struct ff_spi *spiAlloc(void); +void spiSetPin(struct ff_spi *spi, enum spi_pin pin, int val); +void spiFree(struct ff_spi **spi); + +#endif /* BB_SPI_H_ */