changeset 983:0407d14fb854

PL-J flash PPB ops: rework for full verification of lock state
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 02 Dec 2023 08:22:00 +0000
parents 1c5b485f10ba
children cec20c461b3a
files loadtools/flamdsec.c loadtools/fldevs.c
diffstat 2 files changed, 167 insertions(+), 46 deletions(-) [+]
line wrap: on
line diff
--- a/loadtools/flamdsec.c	Sat Dec 02 06:04:37 2023 +0000
+++ b/loadtools/flamdsec.c	Sat Dec 02 08:22:00 2023 +0000
@@ -8,6 +8,8 @@
 #include <stdio.h>
 #include <stdint.h>
 #include <stdlib.h>
+#include <string.h>
+#include <strings.h>
 #include <unistd.h>
 #include "flash.h"
 
@@ -181,6 +183,52 @@
 }
 
 /*
+ * Here comes a version of the above lock-state checking code,
+ * modified for use from within ppb-program-all and ppb-erase-all
+ * functions for chips that don't do this work internally.
+ */
+
+static
+int_lock_state_check(bi, sought_state)
+	struct flash_bank_info *bi;
+{
+	struct amd_lock_info *li = bi->amd_lock;
+	struct lock_group_desc *grp;
+	uint32_t offset, part_addr;
+	uint16_t word;
+	unsigned ng, nb;
+	int lock_state;
+
+	offset = 0;
+	for (ng = 0; ng < li->ngroups; ng++) {
+		grp = li->groups + ng;
+		if (grp->part_begin) {
+			part_addr = bi->base_addr + offset;
+			if (issue_read_id(part_addr) < 0)
+				return(-1);
+		}
+		for (nb = 0; nb < grp->nblocks; nb++) {
+			if (do_r16(bi->base_addr + offset + 4, &word) < 0)
+				return(-1);
+			lock_state = word & 1;
+			if (lock_state != sought_state)
+				break;
+			offset += grp->block_size;
+		}
+		if (lock_state != sought_state) {
+			if (issue_reset_cmd(part_addr) < 0)
+				return(-1);
+			return(0);
+		}
+		if (grp->part_end) {
+			if (issue_reset_cmd(part_addr) < 0)
+				return(-1);
+		}
+	}
+	return(1);
+}
+
+/*
  * Spansion PL-J PPB write functions, referenced from lock_info structures
  * in fldevs.c device descriptions.
  */
@@ -228,14 +276,14 @@
 			pulsecnt, pulsecnt > 1 ? "s" : "");
 		return amd_reset_cmd(bi);
 	}
-	printf("PPB 0x%X programming FAILED, tried %u pulses\n", sector_addr,
-		pulsecnt);
+	fprintf(stderr, "PPB 0x%X programming FAILED, tried %u pulses\n",
+		sector_addr, pulsecnt);
 	return(-1);
 }
 
-plj_ppb_program_all_single(bank)
+plj_ppb_program_all(bi)
+	struct flash_bank_info *bi;
 {
-	struct flash_bank_info *bi = flash_bank_info + bank;
 	struct amd_lock_info *li = bi->amd_lock;
 	struct lock_group_desc *grp;
 	uint32_t offset;
@@ -252,35 +300,20 @@
 			offset += grp->block_size;
 		}
 	}
-	return(0);
-}
-
-plj_ppb_program_all_dualbank(reqbank)
-{
-	int altbank = !reqbank;
-	int rc;
-
-	if (flash_detect(altbank, 0) < 0)
-		return(-1);
-	if (flash_bank_info[0].device != flash_bank_info[1].device) {
-		fprintf(stderr, "error: mismatch between two flash banks\n");
-		return(-1);
-	}
-	printf("Programming all PPBs in flash bank 0\n");
-	rc = plj_ppb_program_all_single(0);
+	printf("Verifying PPB programming\n");
+	rc = int_lock_state_check(bi, 1);
 	if (rc < 0)
-		return(-1);
-	printf("Programming all PPBs in flash bank 1\n");
-	rc = plj_ppb_program_all_single(1);
-	if (rc < 0)
-		return(-1);
-	return(0);
+		return(rc);
+	if (rc)
+		return(0);
+	fprintf(stderr, "flash error: one or more PPBs failed to program\n");
+	return(-1);
 }
 
 static
-plj_ppb_erase_cycle(bank)
+plj_ppb_erase_cycle(bi)
+	struct flash_bank_info *bi;
 {
-	struct flash_bank_info *bi = flash_bank_info + bank;
 	uint16_t stat;
 	unsigned pulsecnt;
 	int rc;
@@ -297,29 +330,107 @@
 			pulsecnt, pulsecnt > 1 ? "s" : "");
 		return amd_reset_cmd(bi);
 	}
-	printf("PPB erase cycle FAILED, tried %u pulses\n", pulsecnt);
+	fprintf(stderr, "PPB erase cycle FAILED, tried %u pulses\n", pulsecnt);
 	return(-1);
 }
 
-plj_ppb_erase_all_single(bank)
+plj_ppb_erase_all_single(bank, raw_mode)
 {
+	struct flash_bank_info *bi = flash_bank_info + bank;
+	unsigned pulsecnt;
+	uint16_t stat;
 	int rc;
 
+	if (raw_mode)
+		return plj_ppb_erase_cycle(bi);
 	printf("Programming all PPBs before erase cycle\n");
-	rc = plj_ppb_program_all_single(bank);
+	rc = plj_ppb_program_all(bi);
 	if (rc < 0)
 		return(-1);
-	return plj_ppb_erase_cycle(bank);
+	printf("Entering PPB erase and verify loop\n");
+	for (pulsecnt = 0; ; ) {
+		if (pulsecnt >= 1000) {
+			fprintf(stderr,
+		"flash error: unable to complete PPB erase after %u pulses\n",
+				pulsecnt);
+			return(-1);
+		}
+		rc = plj_ppb_write_op(bi->base_addr, 1, &stat);
+		if (rc < 0)
+			return(rc);
+		pulsecnt++;
+		if (stat & 1)
+			continue;
+		putchar('.');
+		fflush(stdout);
+		rc = amd_reset_cmd(bi);
+		if (rc < 0)
+			return(rc);
+		rc = int_lock_state_check(bi, 0);
+		if (rc < 0)
+			return(rc);
+		if (rc)
+			break;
+	}
+	printf("\nPPB erase complete, total pulses: %u\n", pulsecnt);
+	return(0);
 }
 
-plj_ppb_erase_all_dualbank(reqbank)
+plj_ppb_erase_all_dualbank(reqbank, raw_mode)
 {
+	int altbank = !reqbank;
+	unsigned pulsecnt;
+	uint16_t stat;
 	int rc;
 
-	rc = plj_ppb_program_all_dualbank(reqbank);
+	if (flash_detect(altbank, 0) < 0)
+		return(-1);
+	if (flash_bank_info[0].device != flash_bank_info[1].device) {
+		fprintf(stderr, "error: mismatch between two flash banks\n");
+		return(-1);
+	}
+	if (raw_mode)
+		return plj_ppb_erase_cycle(flash_bank_info + reqbank);
+	printf("Programming all PPBs in flash bank 0\n");
+	rc = plj_ppb_program_all(&flash_bank_info[0]);
+	if (rc < 0)
+		return(-1);
+	printf("Programming all PPBs in flash bank 1\n");
+	rc = plj_ppb_program_all(&flash_bank_info[1]);
 	if (rc < 0)
 		return(-1);
-	return plj_ppb_erase_cycle(reqbank);
+	printf("Entering PPB erase and verify loop\n");
+	for (pulsecnt = 0; ; ) {
+		if (pulsecnt >= 1000) {
+			fprintf(stderr,
+		"flash error: unable to complete PPB erase after %u pulses\n",
+				pulsecnt);
+			return(-1);
+		}
+		rc = plj_ppb_write_op(flash_bank_info[0].base_addr, 1, &stat);
+		if (rc < 0)
+			return(rc);
+		pulsecnt++;
+		if (stat & 1)
+			continue;
+		putchar('.');
+		fflush(stdout);
+		rc = amd_reset_cmd(&flash_bank_info[0]);
+		if (rc < 0)
+			return(rc);
+		rc = int_lock_state_check(&flash_bank_info[0], 0);
+		if (rc < 0)
+			return(rc);
+		if (!rc)
+			continue;
+		rc = int_lock_state_check(&flash_bank_info[1], 0);
+		if (rc < 0)
+			return(rc);
+		if (rc)
+			break;
+	}
+	printf("\nPPB erase complete, total pulses: %u\n", pulsecnt);
+	return(0);
 }
 
 /*
@@ -390,7 +501,7 @@
 			"Operation not supported for this flash chip type\n");
 		return(-1);
 	}
-	return li->ppb_program_all(bank);
+	return li->ppb_program_all(bi);
 }
 
 flashcmd_ppb_erase_all(argc, argv, bank)
@@ -398,9 +509,20 @@
 {
 	struct flash_bank_info *bi;
 	struct amd_lock_info *li;
+	int raw_mode;
 
-	if (argc > 2) {
-		fprintf(stderr, "error: too many arguments\n");
+	switch (argc) {
+	case 2:
+		raw_mode = 0;
+		break;
+	case 3:
+		if (!strcmp(argv[2], "raw")) {
+			raw_mode = 1;
+			break;
+		}
+		/* FALL THRU */
+	default:
+		fprintf(stderr, "usage: %s %s [raw]\n", argv[0], argv[1]);
 		return(-1);
 	}
 	if (flash_detect(bank, 0) < 0)
@@ -412,5 +534,5 @@
 			"Operation not supported for this flash chip type\n");
 		return(-1);
 	}
-	return li->ppb_erase_all(bank);
+	return li->ppb_erase_all(bank, raw_mode);
 }
--- a/loadtools/fldevs.c	Sat Dec 02 06:04:37 2023 +0000
+++ b/loadtools/fldevs.c	Sat Dec 02 08:22:00 2023 +0000
@@ -10,8 +10,7 @@
 extern struct flash_cmdset flash_cmdset_intel_w30;
 
 extern int plj_ppb_program_one();
-extern int plj_ppb_program_all_single();
-extern int plj_ppb_program_all_dualbank();
+extern int plj_ppb_program_all();
 extern int plj_ppb_erase_all_single();
 extern int plj_ppb_erase_all_dualbank();
 
@@ -441,7 +440,7 @@
 	.have_status_word_3	= 1,
 	.have_mode_lock_bits	= 1,
 	.ppb_program_one	= plj_ppb_program_one,
-	.ppb_program_all	= plj_ppb_program_all_single,
+	.ppb_program_all	= plj_ppb_program_all,
 	.ppb_erase_all		= plj_ppb_erase_all_single,
 };
 
@@ -494,7 +493,7 @@
 	.have_status_word_3	= 1,
 	.have_mode_lock_bits	= 1,
 	.ppb_program_one	= plj_ppb_program_one,
-	.ppb_program_all	= plj_ppb_program_all_dualbank,
+	.ppb_program_all	= plj_ppb_program_all,
 	.ppb_erase_all		= plj_ppb_erase_all_dualbank,
 };
 
@@ -507,7 +506,7 @@
 		{0x2000, 8, 0, 0, 1}},
 	.have_status_word_3	= 1,
 	.ppb_program_one	= plj_ppb_program_one,
-	.ppb_program_all	= plj_ppb_program_all_dualbank,
+	.ppb_program_all	= plj_ppb_program_all,
 	.ppb_erase_all		= plj_ppb_erase_all_dualbank,
 };
 
@@ -701,7 +700,7 @@
 	.have_status_word_7	= 1,
 	.have_mode_lock_bits	= 1,
 	.ppb_program_one	= plj_ppb_program_one,
-	.ppb_program_all	= plj_ppb_program_all_dualbank,
+	.ppb_program_all	= plj_ppb_program_all,
 	.ppb_erase_all		= plj_ppb_erase_all_dualbank,
 };
 
@@ -715,7 +714,7 @@
 	.have_status_word_3	= 1,
 	.have_status_word_7	= 1,
 	.ppb_program_one	= plj_ppb_program_one,
-	.ppb_program_all	= plj_ppb_program_all_dualbank,
+	.ppb_program_all	= plj_ppb_program_all,
 	.ppb_erase_all		= plj_ppb_erase_all_dualbank,
 };