ft2232_spi: reintroduce generic GPIOL control
This reintroduces a reworked version of the GPIOL pin control first
introduced in commit 3207844 (CB:49637), which was reverted in commit
6518cf3 (CB:55692) due to breakage.
This change introduces a new argument `gpiolX` to allow use of the four
GPIOL pins either as generic gpios or as additional CS# signal(s). `X`
specifies the GPIOL pin (0-3) to be set to one of [HLC] with the
following meaning:
* H - set the pin as output high
* L - set the pin as output low
* C - use the pin as additional CS# signal
The third value, `C`, aims to replace the parameter `csgpiol`, that is
now marked as deprecated and can be removed at some point in the future.
`gpiol` and `csgpiol` are mutually exclusive and use of both results in
an error.
Multiple pins may be set by specifying the parameter multiple times.
Documentation was updated/added accordingly.
Test: All pin levels/modes have been verified to behave correctly with a
logic analyzer.
Change-Id: I3989f0f9596c090de52dca67183b1363dae59d3a
Signed-off-by: Alan Green <avg@google.com>
Signed-off-by: Michael Niewöhner <foss@mniewoehner.de>
Original-Reviewed-on: https://review.coreboot.org/c/flashrom/+/57810
Original-Reviewed-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.coreboot.org/c/flashrom-stable/+/71431
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Nico Huber <nico.h@gmx.de>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
diff --git a/ft2232_spi.c b/ft2232_spi.c
index fadd3a4..1106a0e 100644
--- a/ft2232_spi.c
+++ b/ft2232_spi.c
@@ -93,9 +93,10 @@
* to high and will be toggled during SPI transactions. All other
* output pins will be kept low all the time. For some programmers,
* some reserved GPIOL* pins are used as outputs. Free GPIOL* pins
- * are configured as inputs, while it's possible to use one of them
- * as additional CS# signal through the parameter `csgpiol`. On exit,
- * all pins will be reconfigured as inputs.
+ * are configured as inputs, while it's possible to use them either
+ * as generic gpios or as additional CS# signal(s) through the
+ * parameter(s) `gpiolX`. On exit, all pins will be reconfigured
+ * as inputs.
*
* The pin offsets are as follows:
* TCK/SK is bit 0.
@@ -114,6 +115,7 @@
*/
struct ft2232_data {
uint8_t cs_bits;
+ uint8_t aux_bits;
uint8_t pindir;
struct ftdi_context ftdi_context;
};
@@ -231,7 +233,8 @@
msg_pspew("Assert CS#\n");
buf[i++] = SET_BITS_LOW;
- buf[i++] = 0; /* assert CS# pins, all other output pins stay low */
+ /* assert CS# pins, keep aux_bits, all other output pins stay low */
+ buf[i++] = spi_data->aux_bits;
buf[i++] = spi_data->pindir;
/* WREN, OP(PROGRAM, ERASE), ADDR, DATA */
@@ -253,7 +256,7 @@
/* Add final de-assert CS# */
msg_pspew("De-assert CS#\n");
buf[i++] = SET_BITS_LOW;
- buf[i++] = spi_data->cs_bits;
+ buf[i++] = spi_data->cs_bits | spi_data->aux_bits;
buf[i++] = spi_data->pindir;
/* continue if there is no read-cmd and further cmds exist */
@@ -320,6 +323,7 @@
char *arg, *arg2;
double mpsse_clk;
uint8_t cs_bits = 0x08;
+ uint8_t aux_bits = 0x00;
uint8_t pindir = 0x0b;
struct ft2232_data *const spi_data = calloc(1, sizeof(*spi_data));
@@ -472,8 +476,13 @@
}
free(arg);
+ bool csgpiol_set = false;
arg = extract_programmer_param("csgpiol");
if (arg) {
+ csgpiol_set = true;
+ msg_pwarn("Deprecation warning: `csgpiol` is deprecated and will be removed "
+ "in the future.\nUse `gpiolX=C` instead.\n");
+
char *endptr;
unsigned int temp = strtoul(arg, &endptr, 10);
if (*endptr || endptr == arg || temp > 3) {
@@ -483,8 +492,8 @@
ret = -2;
goto init_err;
}
- unsigned int pin = temp + 4;
+ unsigned int pin = temp + 4;
if (rsv_bits & 1 << pin) {
msg_perr("Error: Invalid GPIOL specified: \"%s\".\n"
"The pin is reserved on this programmer.\n",
@@ -494,10 +503,71 @@
}
cs_bits |= 1 << pin;
- pindir |= 1 << pin;
+ pindir |= 1 << pin;
}
free(arg);
+ /* gpiolX */
+ int pin;
+ for (pin = 0; pin < 4; pin++) {
+ char gpiol_param[7];
+ snprintf(gpiol_param, sizeof(gpiol_param), "gpiol%d", pin);
+ arg = extract_programmer_param(gpiol_param);
+
+ if (!arg)
+ continue;
+
+ if (csgpiol_set) {
+ msg_perr("Error: `csgpiol` and `gpiolX` are mutually exclusive.\n"
+ "Since `csgpiol` is deprecated and will be removed in the "
+ "future, use of `gpiolX=C` is recommended.\n");
+ free(arg);
+ return -2;
+ }
+
+ uint8_t bit = 1 << (pin + 4);
+ if (rsv_bits & bit) {
+ msg_perr("Error: Invalid GPIOL specified: \"gpiol%d=%s\".\n"
+ "Pin GPIOL%i is reserved on this programmer.\n",
+ pin, arg, pin);
+ free(arg);
+ return -2;
+ }
+
+ if (strlen(arg) != 1)
+ goto format_error;
+
+ switch (toupper((unsigned char)arg[0])) {
+ case 'H':
+ aux_bits |= bit;
+ pindir |= bit;
+ break;
+ case 'L':
+ pindir |= bit;
+ break;
+ case 'C':
+ cs_bits |= bit;
+ pindir |= bit;
+ break;
+ default:
+ goto format_error;
+ }
+
+ free(arg);
+ continue;
+
+format_error:
+ msg_perr("Error: Invalid GPIOL specified: \"gpiol%d=%s\".\n"
+ "Valid values are H, L and C.\n"
+ " H - Set GPIOL output high\n"
+ " L - Set GPIOL output low\n"
+ " C - Use GPIOL as additional CS# output\n",
+ pin, arg);
+
+ free(arg);
+ return -2;
+ }
+
msg_pdbg("Using device type %s %s ",
get_ft2232_vendorname(ft2232_vid, ft2232_type),
get_ft2232_devicename(ft2232_vid, ft2232_type));
@@ -582,7 +652,7 @@
msg_pdbg("Set data bits\n");
buf[0] = SET_BITS_LOW;
- buf[1] = cs_bits;
+ buf[1] = cs_bits | aux_bits;
buf[2] = pindir;
if (send_buf(ftdic, buf, 3)) {
ret = -8;
@@ -590,6 +660,7 @@
}
spi_data->cs_bits = cs_bits;
+ spi_data->aux_bits = aux_bits;
spi_data->pindir = pindir;
spi_master_ft2232.data = spi_data;