summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/serprog-protocol.txt10
-rw-r--r--flashrom.812
-rw-r--r--serprog.c47
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 */
diff --git a/flashrom.8 b/flashrom.8
index 93df1a2..f37d5e9 100644
--- a/flashrom.8
+++ b/flashrom.8
@@ -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
diff --git a/serprog.c b/serprog.c
index 3529127..e418c3e 100644
--- a/serprog.c
+++ b/serprog.c
@@ -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;
OpenPOWER on IntegriCloud