Skip to content

Commit d20937f

Browse files
chmoussetjianjunjiang
authored andcommitted
[enh] added verify and auto-retry to write operation
1 parent 8dfc8c5 commit d20937f

1 file changed

Lines changed: 95 additions & 4 deletions

File tree

spinor.c

Lines changed: 95 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ struct spinor_info_t {
77
uint32_t blksz;
88
uint32_t read_granularity;
99
uint32_t write_granularity;
10+
uint32_t write_pagesz;
1011
uint8_t address_length;
1112
uint8_t opcode_read;
1213
uint8_t opcode_write;
@@ -70,10 +71,11 @@ struct sfdp_t {
7071
};
7172

7273
static const struct spinor_info_t spinor_infos[] = {
73-
{ "W25X40", 0xef3013, 512 * 1024, 4096, 1, 256, 3, OPCODE_READ, OPCODE_PROG, OPCODE_WREN, OPCODE_E4K, 0, OPCODE_E64K, 0 },
74-
{ "W25Q128JVEIQ", 0xefc018, 16 * 1024 * 1024, 4096, 1, 256, 3, OPCODE_READ, OPCODE_PROG, OPCODE_WREN, OPCODE_E4K, OPCODE_E32K, OPCODE_E64K, 0 },
75-
{ "W25Q256JVEIQ", 0xef4019, 32 * 1024 * 1024, 4096, 1, 256, 4, OPCODE_READ, OPCODE_PROG, OPCODE_WREN, OPCODE_E4K, OPCODE_E32K, OPCODE_E64K, 0 },
76-
{ "GD25D10B", 0xc84011, 128 * 1024, 4096, 1, 256, 3, OPCODE_READ, OPCODE_PROG, OPCODE_WREN, OPCODE_E4K, OPCODE_E32K, OPCODE_E64K, 0 },
74+
{ "W25X40", 0xef3013, 512 * 1024, 4096, 1, 256, 256, 3, OPCODE_READ, OPCODE_PROG, OPCODE_WREN, OPCODE_E4K, 0, OPCODE_E64K, 0 },
75+
{ "SST25VF016B", 0xbf2541, 2 * 1024 * 1024, 4096, 1, 1, 1, 3, OPCODE_READ, OPCODE_PROG, OPCODE_WREN, OPCODE_E4K, OPCODE_E32K, OPCODE_E64K, 0 },
76+
{ "W25Q128JVEIQ", 0xefc018, 16 * 1024 * 1024, 4096, 1, 256, 256, 3, OPCODE_READ, OPCODE_PROG, OPCODE_WREN, OPCODE_E4K, OPCODE_E32K, OPCODE_E64K, 0 },
77+
{ "W25Q256JVEIQ", 0xef4019, 32 * 1024 * 1024, 4096, 1, 256, 256, 4, OPCODE_READ, OPCODE_PROG, OPCODE_WREN, OPCODE_E4K, OPCODE_E32K, OPCODE_E64K, 0 },
78+
{ "GD25D10B", 0xc84011, 128 * 1024, 4096, 1, 256, 256, 3, OPCODE_READ, OPCODE_PROG, OPCODE_WREN, OPCODE_E4K, OPCODE_E32K, OPCODE_E64K, 0 },
7779
};
7880

7981
static inline int spinor_read_sfdp(struct xfel_ctx_t * ctx, uint32_t swapbuf, uint32_t swaplen, uint32_t cmdlen, struct sfdp_t * sfdp)
@@ -255,6 +257,7 @@ static inline int spinor_info(struct xfel_ctx_t * ctx, struct spinor_pdata_t * p
255257
pdat->info.opcode_write_enable = OPCODE_WREN;
256258
pdat->info.read_granularity = 1;
257259
pdat->info.opcode_read = OPCODE_READ;
260+
pdat->info.write_pagesz = 256;
258261
if((sfdp.bt.major == 1) && (sfdp.bt.minor < 5))
259262
{
260263
/* Basic flash parameter table 1th dword */
@@ -269,6 +272,7 @@ static inline int spinor_info(struct xfel_ctx_t * ctx, struct spinor_pdata_t * p
269272
/* Basic flash parameter table 11th dword */
270273
v = (sfdp.bt.table[43] << 24) | (sfdp.bt.table[42] << 16) | (sfdp.bt.table[41] << 8) | (sfdp.bt.table[40] << 0);
271274
pdat->info.write_granularity = 1 << ((v >> 4) & 0xf);
275+
pdat->info.write_pagesz = pdat->info.write_granularity;
272276
}
273277
pdat->info.opcode_write = OPCODE_PROG;
274278
return 1;
@@ -730,6 +734,8 @@ static void spinor_helper_write(struct xfel_ctx_t * ctx, struct spinor_pdata_t *
730734
granularity = (count < 0x40000000) ? count : 0x40000000;
731735
else
732736
granularity = pdat->info.write_granularity;
737+
if(pdat->info.write_pagesz > 0)
738+
granularity = granularity > (int32_t)pdat->info.write_pagesz ? (int32_t)pdat->info.write_pagesz : granularity;
733739
granularity = granularity > (pdat->swaplen - 5) ? (pdat->swaplen - 5) : granularity;
734740

735741
switch(pdat->info.address_length)
@@ -927,9 +933,20 @@ int spinor_write(struct xfel_ctx_t * ctx, uint64_t addr, void * buf, uint64_t le
927933
uint64_t base, n;
928934
int64_t cnt;
929935
uint32_t esize, emask;
936+
uint64_t waddr, wlen;
937+
uint8_t * wbuf;
938+
uint8_t * vbuf;
939+
uint8_t * expbuf;
940+
uint64_t vbase, vcnt;
941+
uint64_t start, end;
942+
uint32_t i;
943+
int attempt;
930944

931945
if(spinor_helper_init(ctx, &pdat))
932946
{
947+
waddr = addr;
948+
wlen = len;
949+
wbuf = buf;
933950
if(pdat.info.opcode_erase_4k != 0)
934951
esize = 4096;
935952
else if(pdat.info.opcode_erase_32k != 0)
@@ -955,6 +972,16 @@ int spinor_write(struct xfel_ctx_t * ctx, uint64_t addr, void * buf, uint64_t le
955972
}
956973
base = addr;
957974
cnt = len;
975+
vbuf = malloc(esize);
976+
expbuf = malloc(esize);
977+
if(!vbuf || !expbuf)
978+
{
979+
if(vbuf)
980+
free(vbuf);
981+
if(expbuf)
982+
free(expbuf);
983+
return 0;
984+
}
958985
progress_start(&p, cnt);
959986
while(cnt > 0)
960987
{
@@ -966,6 +993,70 @@ int spinor_write(struct xfel_ctx_t * ctx, uint64_t addr, void * buf, uint64_t le
966993
progress_update(&p, n);
967994
}
968995
progress_stop(&p);
996+
vbase = waddr & ~emask;
997+
vcnt = (waddr & emask) + wlen;
998+
vcnt = (vcnt + ((vcnt & emask) ? esize : 0)) & ~emask;
999+
while(vcnt > 0)
1000+
{
1001+
memset(expbuf, 0xff, esize);
1002+
start = vbase > waddr ? vbase : waddr;
1003+
end = (vbase + esize) < (waddr + wlen) ? (vbase + esize) : (waddr + wlen);
1004+
if(start < end)
1005+
memcpy(expbuf + (start - vbase), wbuf + (start - waddr), end - start);
1006+
for(attempt = 0; attempt < 3; attempt++)
1007+
{
1008+
int need_erase = 0;
1009+
int need_prog = 0;
1010+
spinor_helper_read(ctx, &pdat, vbase, vbuf, esize);
1011+
for(i = 0; i < esize; i++)
1012+
{
1013+
uint8_t exp = expbuf[i];
1014+
uint8_t got = vbuf[i];
1015+
if((exp & ~got) != 0)
1016+
need_erase = 1;
1017+
if((~exp & got) != 0)
1018+
need_prog = 1;
1019+
if(need_erase && need_prog)
1020+
break;
1021+
}
1022+
if(!need_erase && !need_prog)
1023+
break;
1024+
printf("spinor: verify mismatch at 0x%llx (attempt %d), %s%s\r\n",
1025+
(unsigned long long)vbase, attempt + 1,
1026+
need_erase ? "need-erase" : "",
1027+
need_prog ? (need_erase ? "+need-prog" : "need-prog") : "");
1028+
if(need_erase)
1029+
{
1030+
uint64_t off;
1031+
spinor_helper_erase(ctx, &pdat, vbase, esize);
1032+
for(off = 0; off < esize; off += n)
1033+
{
1034+
n = (esize - off) > 65536 ? 65536 : (esize - off);
1035+
spinor_helper_write(ctx, &pdat, vbase + off, expbuf + off, n);
1036+
}
1037+
}
1038+
else if(need_prog)
1039+
{
1040+
for(i = 0; i < esize; i++)
1041+
{
1042+
if(vbuf[i] != expbuf[i])
1043+
spinor_helper_write(ctx, &pdat, vbase + i, expbuf + i, 1);
1044+
}
1045+
}
1046+
}
1047+
if(attempt == 3)
1048+
{
1049+
printf("spinor: verify failed at 0x%llx after retries\r\n",
1050+
(unsigned long long)vbase);
1051+
free(vbuf);
1052+
free(expbuf);
1053+
return 0;
1054+
}
1055+
vbase += esize;
1056+
vcnt -= esize;
1057+
}
1058+
free(vbuf);
1059+
free(expbuf);
9691060
return 1;
9701061
}
9711062
return 0;

0 commit comments

Comments
 (0)