spi: Use bus probing for RDID

We put 3 and 4 byte RDID into a single function. Only if we can't
read 4 bytes, we try again with 3. There are no conflicts because
the only RDID4 manufacturer ID contains the 0x7f prefix, hence it
can't match any 3-byte ID.

Change-Id: I5d35bc30255aae66da35d58431628512e50b39f0
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.sourcearcade.org/c/flashprog/+/74900
diff --git a/spi25.c b/spi25.c
index 778a822..b22c8a8 100644
--- a/spi25.c
+++ b/spi25.c
@@ -19,6 +19,7 @@
  */
 
 #include <stddef.h>
+#include <stdlib.h>
 #include <string.h>
 #include <stdbool.h>
 #include "flash.h"
@@ -29,13 +30,13 @@
 #include "spi_command.h"
 #include "spi.h"
 
-static int spi_rdid(struct flashctx *flash, unsigned char *readarr, int bytes)
+static int spi_rdid(const struct spi_master *spi, unsigned char *readarr, int bytes)
 {
 	static const unsigned char cmd[JEDEC_RDID_OUTSIZE] = { JEDEC_RDID };
 	int ret;
 	int i;
 
-	ret = spi_send_command(flash, sizeof(cmd), bytes, cmd, readarr);
+	ret = spi->command(spi, sizeof(cmd), bytes, cmd, readarr);
 	if (ret)
 		return ret;
 	msg_cspew("RDID returned");
@@ -95,63 +96,55 @@
 	return spi_send_command(flash, sizeof(cmd), 0, cmd, NULL);
 }
 
-static int probe_spi_rdid_generic(struct flashctx *flash, int bytes)
+struct found_id *probe_spi_rdid(const struct bus_probe *probe, const struct master_common *mst)
 {
-	const struct flashchip *chip = flash->chip;
+	const struct spi_master *const spi = (const struct spi_master *)mst;
 	unsigned char readarr[4];
-	uint32_t id1;
-	uint32_t id2;
+	size_t bytes;
+	int ret;
 
-	const int ret = spi_rdid(flash, readarr, bytes);
-	if (ret == SPI_INVALID_LENGTH)
-		msg_cinfo("%d byte RDID not supported on this SPI controller\n", bytes);
-	if (ret)
-		return 0;
+	for (bytes = 4; bytes >= 3; --bytes) {
+		ret = spi_rdid(spi, readarr, bytes);
+		if (ret == SPI_INVALID_LENGTH)
+			msg_cinfo("%zu byte RDID not supported on this SPI controller\n", bytes);
+		if (!ret)
+			break;
+	}
+	if (ret || flashprog_no_data(readarr, bytes))
+		return NULL;
 
 	if (!oddparity(readarr[0]))
 		msg_cdbg("RDID byte 0 parity violation. ");
 
+	struct found_id *const found = calloc(1, sizeof(*found));
+	if (!found) {
+		msg_cerr("Out of memory!\n");
+		return NULL;
+	}
+
+	struct id_info *const id = &found->info.id;
+	id->type = ID_SPI_RDID;
+
 	/* Check if this is a continuation vendor ID.
 	 * FIXME: Handle continuation device IDs.
 	 */
 	if (readarr[0] == 0x7f) {
 		if (!oddparity(readarr[1]))
 			msg_cdbg("RDID byte 1 parity violation. ");
-		id1 = (readarr[0] << 8) | readarr[1];
-		id2 = readarr[2];
+		id->manufacture = (readarr[0] << 8) | readarr[1];
+		id->model = readarr[2];
 		if (bytes > 3) {
-			id2 <<= 8;
-			id2 |= readarr[3];
+			id->model <<= 8;
+			id->model |= readarr[3];
 		}
 	} else {
-		id1 = readarr[0];
-		id2 = (readarr[1] << 8) | readarr[2];
+		id->manufacture = readarr[0];
+		id->model = (readarr[1] << 8) | readarr[2];
 	}
 
-	msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
+	msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id->id1, id->id2);
 
-	if (id1 == chip->id.manufacture && id2 == chip->id.model)
-		return 1;
-
-	/* Test if this is a pure vendor match. */
-	if (id1 == chip->id.manufacture && GENERIC_DEVICE_ID == chip->id.model)
-		return 1;
-
-	/* Test if there is any vendor ID. */
-	if (GENERIC_MANUF_ID == chip->id.manufacture && id1 != 0xff && id1 != 0x00)
-		return 1;
-
-	return 0;
-}
-
-int probe_spi_rdid(struct flashctx *flash)
-{
-	return probe_spi_rdid_generic(flash, 3);
-}
-
-int probe_spi_rdid4(struct flashctx *flash)
-{
-	return probe_spi_rdid_generic(flash, 4);
+	return found;
 }
 
 int probe_spi_rems(struct flashctx *flash)
@@ -195,7 +188,7 @@
 	/* Check if RDID is usable and does not return 0xff 0xff 0xff or
 	 * 0x00 0x00 0x00. In that case, RES is pointless.
 	 */
-	if (!spi_rdid(flash, readarr, 3) && memcmp(readarr, allff, 3) &&
+	if (!spi_rdid(flash->mst.spi, readarr, 3) && memcmp(readarr, allff, 3) &&
 	    memcmp(readarr, all00, 3)) {
 		msg_cdbg("Ignoring RES in favour of RDID.\n");
 		return 0;