dediprog: Implement multi-i/o reads

This implements i/o-mode switches and opcode handling for multi-i/o
reads with protocol versions 2 and 3. The mode switching is done by
a simple command  that takes an enum just as our internal `io_mode`
as argument.

The opcode handling differs between protocol versions. For protocol
v2, we keep the current behavior for single-i/o operations and only
set the matching opcode. Tests with an SF600Plus-G2 have shown that
the programmer automatically chooses the address length  and number
of dummy cycles. It is unknown, however,  if it chooses these para-
meters based on the opcode or the configured i/o mode. For dual-out
reads,  it seems to choose the wrong number of dummy cycles. Hence,
we mask the respective support bit for the v2 case.

For protocol v3,  a new `read mode' was discovered in traces of the
Dediprog Windows application.  It allows to explicitly specify  the
opcode, the address length, and the number of dummy cycles. We call
this READ_MODE_CONFIGURABLE. As this is the only way to make use of
the additional command bytes of the v3 protocol, we can assume that
this mode always works with v3.

For partial reads, i.e. not multiples of 512B blocks,  that have to
go through dediprog_spi_send_command(),  we temporarily disable the
chosen `.spi_fast_read` function. This is necessary, because multi-
io is not supported on this path.

We enable dual i/o by default for protocol v3 devices. This should
work out of the box with many compatible flash chips. The command-
line logic is a little convoluted this way,  but can be refactored
once protocol v2 devices are tested.

Change-Id: Ib07b1b61eccc19c7ead9f64c980b37feabfa70a8
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.sourcearcade.org/c/flashprog/+/114
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
diff --git a/include/spi_command.h b/include/spi_command.h
index b0daeee..3af0cd0 100644
--- a/include/spi_command.h
+++ b/include/spi_command.h
@@ -77,6 +77,15 @@
 	uint8_t dummy_len;	/* dummy bytes (including optional mode byte) */
 };
 
+const struct spi_read_op *get_spi_read_op(const struct flashctx *);
+
+static inline unsigned int spi_dummy_cycles(const struct spi_read_op *const op)
+{
+	return op->dummy_len * 8
+		/ (op->io_mode == SINGLE_IO_1_1_1 ? 1
+			: (op->io_mode <= DUAL_IO_1_2_2 ? 2 : 4));
+}
+
 struct spi_command {
 	enum io_mode io_mode;
 	size_t opcode_len;	/* bytes to write in opcode i/o phase */