diff options
-rw-r--r-- | Documentation/serprog-protocol.txt | 10 | ||||
-rw-r--r-- | flashrom.8 | 12 | ||||
-rw-r--r-- | serprog.c | 47 |
3 files changed, 68 insertions, 1 deletions
diff --git a/Documentation/serprog-protocol.txt b/Documentation/serprog-protocol.txt index a3a4863..d8733cc 100644 --- a/Documentation/serprog-protocol.txt +++ b/Documentation/serprog-protocol.txt @@ -33,6 +33,7 @@ COMMAND Description Parameters Return Value 0x12 Set used bustype 8-bit flags (as with 0x05) ACK / NAK 0x13 Perform SPI operation 24-bit slen + 24-bit rlen ACK + rlen bytes of data / NAK + slen bytes of data +0x14 Set SPI clock frequency in Hz 32-bit requested frequency ACK + 32-bit set frequency / NAK 0x?? unimplemented command - invalid. @@ -73,6 +74,14 @@ Additional information of the above commands: Maximum slen is Q_WRNMAXLEN in case Q_BUSTYPE returns SPI only or S_BUSTYPE was used to set SPI exclusively before. Same for rlen and Q_RDNMAXLEN. This operation is immediate, meaning it doesnt use the operation buffer. + 0x14 (S_SPI_FREQ): + Set the SPI clock frequency. The 32-bit value indicates the + requested frequency in Hertz. Value 0 is reserved and should + be NAKed by the programmer. The requested frequency should be + mapped by the programmer software to a supported frequency + lower than the one requested. If there is no lower frequency + available the lowest possible should be used. The value + chosen is sent back in the reply with an ACK. About mandatory commands: The only truly mandatory commands for any device are 0x00, 0x01, 0x02 and 0x10, but one can't really do anything with these commands. @@ -107,3 +116,4 @@ This define listing should help C coders - (it's here to be the single source fo #define S_CMD_Q_RDNMAXLEN 0x11 /* Query read-n maximum length */ #define S_CMD_S_BUSTYPE 0x12 /* Set used bustype(s). */ #define S_CMD_O_SPIOP 0x13 /* Perform SPI operation. */ +#define S_CMD_S_SPI_FREQ 0x14 /* Set SPI clock frequency */ @@ -598,7 +598,17 @@ syntax and for IP, you have to use .sp .B " flashrom \-p serprog:ip=ipaddr:port" .sp -instead. More information about serprog is available in +instead. In case the device supports it, you can set the SPI clock frequency +with the optional +.B spispeed +parameter. The frequency is parsed as Hertz, unless an +.BR M ", or " k +suffix is given, then megahertz or kilohertz are used respectively. +Example that sets the frequency to 2 MHz: +.sp +.B "flashrom \-p serprog:dev=/dev/device:baud,spispeed=2M" +.sp +More information about serprog is available in .B serprog-protocol.txt in the source distribution. .SS @@ -69,6 +69,7 @@ static int serprog_shutdown(void *data); #define S_CMD_Q_RDNMAXLEN 0x11 /* Query read-n maximum length */ #define S_CMD_S_BUSTYPE 0x12 /* Set used bustype(s). */ #define S_CMD_O_SPIOP 0x13 /* Perform SPI operation. */ +#define S_CMD_S_SPI_FREQ 0x14 /* Set SPI clock frequency */ static uint16_t sp_device_serbuf_size = 16; static uint16_t sp_device_opbuf_size = 300; @@ -482,6 +483,7 @@ int serprog_init(void) /* Check for the minimum operational set of commands. */ if (serprog_buses_supported & BUS_SPI) { uint8_t bt = BUS_SPI; + char *spispeed; if (sp_check_commandavail(S_CMD_O_SPIOP) == 0) { msg_perr("Error: SPI operation not supported while the " "bustype is SPI\n"); @@ -513,6 +515,51 @@ int serprog_init(void) spi_programmer_serprog.max_data_read = v; msg_pdbg(MSGHEADER "Maximum read-n length is %d\n", v); } + spispeed = extract_programmer_param("spispeed"); + if (spispeed && strlen(spispeed)) { + uint32_t f_spi_req, f_spi; + uint8_t buf[4]; + char *f_spi_suffix; + + errno = 0; + f_spi_req = strtol(spispeed, &f_spi_suffix, 0); + if (errno != 0 || spispeed == f_spi_suffix) { + msg_perr("Error: Could not convert 'spispeed'.\n"); + return 1; + } + if (strlen(f_spi_suffix) == 1) { + if (!strcasecmp(f_spi_suffix, "M")) + f_spi_req *= 1000000; + else if (!strcasecmp(f_spi_suffix, "k")) + f_spi_req *= 1000; + else { + msg_perr("Error: Garbage following 'spispeed' value.\n"); + return 1; + } + } else if (strlen(f_spi_suffix) > 1) { + msg_perr("Error: Garbage following 'spispeed' value.\n"); + return 1; + } + + buf[0] = (f_spi_req >> (0 * 8)) & 0xFF; + buf[1] = (f_spi_req >> (1 * 8)) & 0xFF; + buf[2] = (f_spi_req >> (2 * 8)) & 0xFF; + buf[3] = (f_spi_req >> (3 * 8)) & 0xFF; + + if (sp_check_commandavail(S_CMD_S_SPI_FREQ) == 0) + msg_perr(MSGHEADER "Warning: Setting the SPI clock rate is not supported!\n"); + else if (sp_docommand(S_CMD_S_SPI_FREQ, 4, buf, 4, buf) + == 0) { + f_spi = buf[0]; + f_spi |= buf[1] << (1 * 8); + f_spi |= buf[2] << (2 * 8); + f_spi |= buf[3] << (3 * 8); + msg_pdbg(MSGHEADER "Requested to set SPI clock frequency to %u Hz. " + "It was actually set to %u Hz\n", f_spi_req, f_spi); + } else + msg_pdbg(MSGHEADER "Setting SPI clock rate to %u Hz failed!\n", f_spi_req); + } + free(spispeed); bt = serprog_buses_supported; if (sp_docommand(S_CMD_S_BUSTYPE, 1, &bt, 0, NULL)) return 1; |