Xiang Wang has uploaded this change for review. ( https://review.coreboot.org/c/flashrom/+/49255 )
Change subject: bitbang-spi.c: support clock polarity and phase ......................................................................
bitbang-spi.c: support clock polarity and phase
Change-Id: I04c1dfe132d756119229b27c3cd611d1be1abc8d Signed-off-by: Xiang Wang merle@hardenedlinux.org --- M bitbang_spi.c 1 file changed, 71 insertions(+), 41 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/55/49255/1
diff --git a/bitbang_spi.c b/bitbang_spi.c index c402119..9003d81 100644 --- a/bitbang_spi.c +++ b/bitbang_spi.c @@ -2,6 +2,7 @@ * This file is part of the flashrom project. * * Copyright (C) 2009, 2010 Carl-Daniel Hailfinger + * Copyright (C) 2021 HardenedLinux * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,6 +22,26 @@ #include "programmer.h" #include "spi.h"
+/* + * SPI has four modes + * + * These four modes are determined by two factors. + * These two factors are cpol(clock polarity) and cpha(clock phase). + * + * cpol determines the sck level, when the bus is idle. + * + * There are two sck changes in a cycle. + * If the data transmission occurs in the first sck change then cpha=0, otherwise cpha=1. + * + * Mode = 0 -> cpol = 0, cpha = 0 + * Mode = 1 -> cpol = 0, cpha = 1 + * Mode = 2 -> cpol = 1, cpha = 0 + * Mode = 3 -> cpol = 1, cpha = 1 + */ + +static int cpol; /* Clock Polarity */ +static int cpha; /* 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) { @@ -44,56 +65,47 @@ master->release_bus(); }
-static void bitbang_spi_set_sck_set_mosi(const struct bitbang_spi_master * const master, int sck, int mosi) +static void bitbang_spi_set_mosi(const struct bitbang_spi_master * const master, int mosi) { - if (master->set_sck_set_mosi) { - master->set_sck_set_mosi(sck, mosi); - return; - } - - master->set_sck(sck); master->set_mosi(mosi); }
-static int bitbang_spi_set_sck_get_miso(const struct bitbang_spi_master * const master, int sck) +static int bitbang_spi_get_miso(const struct bitbang_spi_master * const master) { - if (master->set_sck_get_miso) - return master->set_sck_get_miso(sck); - - master->set_sck(sck); return master->get_miso(); }
-static uint8_t bitbang_spi_read_byte(const struct bitbang_spi_master *master) +static uint8_t bitbang_spi_xfer(const struct bitbang_spi_master * const master, uint8_t val) { uint8_t ret = 0; - int i; + for (int i = 0; i < 8; i++) { + if (cpha == 0) { + bitbang_spi_set_mosi(master, (val & 0x80)==0x80); + val = val << 1; + programmer_delay(master->half_period); + } + bitbang_spi_set_sck(master, !cpol); + if (cpha == 0) { + ret = ret << 1; + ret |= bitbang_spi_get_miso(master); + programmer_delay(master->half_period); + }
- for (i = 7; i >= 0; i--) { - if (i == 0) - bitbang_spi_set_sck_set_mosi(master, 0, 0); - else - bitbang_spi_set_sck(master, 0); - programmer_delay(master->half_period); - ret <<= 1; - ret |= bitbang_spi_set_sck_get_miso(master, 1); - programmer_delay(master->half_period); + if (cpha == 1) { + bitbang_spi_set_mosi(master, (val & 0x80)==0x80); + val = val << 1; + programmer_delay(master->half_period); + } + bitbang_spi_set_sck(master, cpol); + if (cpha == 1) { + ret = ret << 1; + ret |= bitbang_spi_get_miso(master); + programmer_delay(master->half_period); + } } return ret; }
-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_sck_set_mosi(master, 0, (val >> i) & 1); - programmer_delay(master->half_period); - bitbang_spi_set_sck(master, 1); - programmer_delay(master->half_period); - } -} - static int bitbang_spi_send_command(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, @@ -107,13 +119,15 @@ * programmer to use its own SPI engine for native accesses. */ bitbang_spi_request_bus(master); + programmer_delay(master->half_period); bitbang_spi_set_cs(master, 0); - 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); + programmer_delay(master->half_period);
- bitbang_spi_set_sck(master, 0); + for (i = 0; i < writecnt; i++) + bitbang_spi_xfer(master, writearr[i]); + for (i = 0; i < readcnt; i++) + readarr[i] = bitbang_spi_xfer(master, 0); + programmer_delay(master->half_period); bitbang_spi_set_cs(master, 1); programmer_delay(master->half_period); @@ -155,13 +169,29 @@ return ERROR_FLASHROM_BUG; }
+ char *mode = extract_programmer_param("mode"); + if (mode) { + if (strlen(mode)) { + char *endptr; + int v = strtol(mode, &endptr, 0); + if (mode == endptr || v > 3 || v < 0) { + msg_perr("bitbang spi only work with mode 0-3\n"); + free(mode); + return ERROR_FLASHROM_BUG; + } + cpol = (v >> 1) & 1; + cpha = (v >> 0) & 1; + } + free(mode); + } + mst.data = master; register_spi_master(&mst);
/* Only mess with the bus if we're sure nobody else uses it. */ bitbang_spi_request_bus(master); bitbang_spi_set_cs(master, 1); - bitbang_spi_set_sck_set_mosi(master, 0, 0); + bitbang_spi_set_sck(master, cpol); /* FIXME: Release SPI bus here and request it again for each command or * don't release it now and only release it on programmer shutdown? */