Angel Pons has uploaded this change for review. ( https://review.coreboot.org/c/flashrom/+/49271 )
Change subject: [UNTESTED] bitbang_spi.c: Support changing clock polarity and phase ......................................................................
[UNTESTED] bitbang_spi.c: Support changing clock polarity and phase
Change-Id: I415a528c013f1a523e883d812b6890be39bfcc7b Signed-off-by: Angel Pons th3fanbus@gmail.com --- M bitbang_spi.c 1 file changed, 45 insertions(+), 6 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/71/49271/1
diff --git a/bitbang_spi.c b/bitbang_spi.c index 00c631f..252adab 100644 --- a/bitbang_spi.c +++ b/bitbang_spi.c @@ -21,6 +21,9 @@ #include "programmer.h" #include "spi.h"
+static int cpol = 0; /* Clock Polarity */ +static int cpha = 0; /* Clock Phase */ + /* Note that CS# is active low, so val=0 means the chip is active. */ static void bitbang_spi_set_cs(const struct bitbang_spi_master * const master, int val) { @@ -29,7 +32,7 @@
static void bitbang_spi_set_sck(const struct bitbang_spi_master * const master, int val) { - master->set_sck(val); + master->set_sck(val ^ cpol); }
static void bitbang_spi_request_bus(const struct bitbang_spi_master * const master) @@ -54,6 +57,10 @@ return master->set_sck_get_miso(sck); }
+/* + * For CPHA=0, the "in" side captures the data on (or shortly after) the leading edge of the clock cycle. + * For CPHA=1, the "in" side captures the data on (or shortly after) the trailing edge of the clock cycle. + */ static uint8_t bitbang_spi_read_byte(const struct bitbang_spi_master *master) { uint8_t ret = 0; @@ -61,25 +68,29 @@
for (i = 7; i >= 0; i--) { if (i == 0) - bitbang_spi_set_mosi_set_sck(master, 0, 0); + bitbang_spi_set_mosi_set_sck(master, 0, cpha); else bitbang_spi_set_sck(master, 0); programmer_delay(master->half_period); ret <<= 1; - ret |= bitbang_spi_set_sck_get_miso(master, 1); + ret |= bitbang_spi_set_sck_get_miso(master, !cpha); programmer_delay(master->half_period); } return ret; }
+/* + * For CPHA=0, the "out" side changes the data on the trailing edge of the preceding clock cycle. + * For CPHA=1, the "out" side changes the data on the leading edge of the current clock cycle. + */ static void bitbang_spi_write_byte(const struct bitbang_spi_master *master, uint8_t val) { int i;
for (i = 7; i >= 0; i--) { - bitbang_spi_set_mosi_set_sck(master, (val >> i) & 1, 0); + bitbang_spi_set_mosi_set_sck(master, (val >> i) & 1, cpha); programmer_delay(master->half_period); - bitbang_spi_set_sck(master, 1); + bitbang_spi_set_sck(master, !cpha); programmer_delay(master->half_period); } } @@ -98,13 +109,17 @@ */ bitbang_spi_request_bus(master); bitbang_spi_set_cs(master, 0); + if (cpha) + programmer_delay(master->half_period); + for (i = 0; i < writecnt; i++) bitbang_spi_write_byte(master, writearr[i]); for (i = 0; i < readcnt; i++) readarr[i] = bitbang_spi_read_byte(master);
bitbang_spi_set_sck(master, 0); - programmer_delay(master->half_period); + if (!cpha) + programmer_delay(master->half_period); bitbang_spi_set_cs(master, 1); programmer_delay(master->half_period); /* FIXME: Run bitbang_spi_release_bus here or in programmer init? */ @@ -132,6 +147,27 @@ } #endif
+static int parse_spi_mode(int *polarity, int *phase) +{ + char *mode = extract_programmer_param("mode"); + if (!mode) + return 0; + + if (strlen(mode)) { + char *endptr; + int v = strtol(mode, &endptr, 0); + if (mode == endptr || v > 3 || v < 0) { + msg_perr("Invalid bitbang SPI mode, valid values are 0..3\n"); + free(mode); + return -1; + } + *polarity = (v >> 1) & 1; + *phase = (v >> 0) & 1; + } + free(mode); + return 0; +} + int register_spi_bitbang_master(const struct bitbang_spi_master *master) { struct spi_master mst = spi_master_bitbang; @@ -145,6 +181,9 @@ return ERROR_FLASHROM_BUG; }
+ if (parse_spi_mode(&cpol, &cpha)) + return ERROR_FATAL; + mst.data = master; register_spi_master(&mst);