summaryrefslogtreecommitdiffstats
path: root/ft2232_spi.c
diff options
context:
space:
mode:
authorMichael Niewöhner <foss@mniewoehner.de>2021-09-21 20:15:32 +0200
committerNico Huber <nico.h@gmx.de>2021-10-04 10:53:03 +0000
commit7b9c74f49607dda18243138e87d71b773cec7a7b (patch)
tree27ae4513866c11f1b9e76ff9344a15427e810bcb /ft2232_spi.c
parent106f097ef66ad6c02d5efb58dd778dbece02667e (diff)
downloadflashrom-7b9c74f49607dda18243138e87d71b773cec7a7b.tar.gz
flashrom-7b9c74f49607dda18243138e87d71b773cec7a7b.tar.bz2
flashrom-7b9c74f49607dda18243138e87d71b773cec7a7b.zip
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> Reviewed-on: https://review.coreboot.org/c/flashrom/+/57810 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Nico Huber <nico.h@gmx.de>
Diffstat (limited to 'ft2232_spi.c')
-rw-r--r--ft2232_spi.c86
1 files changed, 78 insertions, 8 deletions
diff --git a/ft2232_spi.c b/ft2232_spi.c
index 110bdece2..65326f9a8 100644
--- a/ft2232_spi.c
+++ b/ft2232_spi.c
@@ -91,9 +91,10 @@ static const struct dev_entry devs_ft2232spi[] = {
* 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.
@@ -112,6 +113,7 @@ static const struct dev_entry devs_ft2232spi[] = {
*/
struct ft2232_data {
uint8_t cs_bits;
+ uint8_t aux_bits;
uint8_t pindir;
struct ftdi_context ftdic_context;
};
@@ -233,7 +235,8 @@ static int ft2232_spi_send_multicommand(const struct flashctx *flash, struct spi
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 */
@@ -255,7 +258,7 @@ static int ft2232_spi_send_multicommand(const struct flashctx *flash, struct spi
/* 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 */
@@ -325,6 +328,7 @@ static int ft2232_spi_init(void)
double mpsse_clk;
uint8_t cs_bits = 0x08;
+ uint8_t aux_bits = 0x00;
uint8_t pindir = 0x0b;
struct ftdi_context ftdic;
struct ft2232_data *spi_data;
@@ -470,8 +474,13 @@ static int ft2232_spi_init(void)
}
free(arg);
+ bool csgpiol_set = false;
arg = extract_programmer_param("csgpiol");
if (arg) {
+ csgpiol_set = true;
+ msg_pwarn("Deprecation warning: `csgpiol` is deprectated 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) {
@@ -480,8 +489,8 @@ static int ft2232_spi_init(void)
free(arg);
return -2;
}
- 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",
@@ -491,10 +500,70 @@ static int ft2232_spi_init(void)
}
cs_bits |= 1 << pin;
- pindir |= 1 << pin;
+ pindir |= 1 << pin;
}
free(arg);
+ /* gpiolX */
+ for (int 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(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));
@@ -577,7 +646,7 @@ static int ft2232_spi_init(void)
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 +659,7 @@ static int ft2232_spi_init(void)
return SPI_GENERIC_ERROR;
}
spi_data->cs_bits = cs_bits;
+ spi_data->aux_bits = aux_bits;
spi_data->pindir = pindir;
spi_data->ftdic_context = ftdic;