1
2
3
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
25
26
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
81
86
87
88
89
90
91
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
116
117
118
119
120
121
122
123
124
125
126
127
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
163
167
171
172
173
174
187
188
189
190
191
192
193
194
195
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
246
247
248
249
250
251
252
/* ... */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "imp.h"
#include "spi.h"
#include "sfdp.h"
#define SFDP_ACCESS_PROT 0xFF
#define SFDP_BASIC_FLASH 0xFF00
#define SFDP_4BYTE_ADDR 0xFF84
static const char *sfdp_name = "sfdp";
struct sfdp_hdr {
uint32_t signature;
uint32_t revision;
...};
struct sfdp_phdr {
uint32_t revision;
uint32_t ptr;
...};
struct sfdp_basic_flash_param {
uint32_t fast_addr;
uint32_t density;
uint32_t fast_1x4;
uint32_t fast_1x2;
uint32_t fast_444;
uint32_t read_222;
uint32_t read_444;
uint32_t erase_t12;
uint32_t erase_t34;
uint32_t erase_time;
uint32_t chip_byte;
uint32_t susp_time;
uint32_t susp_instr;
uint32_t pwrd_instr;
uint32_t quad_req;
uint32_t addr_reset;
uint32_t read_1x8;
uint32_t dtr_drive;
uint32_t octal_req;
uint32_t speed_888;
...};
struct sfdp_4byte_addr_param {
uint32_t flags;
uint32_t erase_t1234;
...};
int spi_sfdp(struct flash_bank *bank, struct flash_device *dev,
read_sfdp_block_t read_sfdp_block)
{
struct sfdp_hdr header;
struct sfdp_phdr *pheaders = NULL;
uint32_t *ptable = NULL;
unsigned int j, k, nph;
int retval, erase_type = 0;
memset(dev, 0, sizeof(struct flash_device));
memset(&header, 0, sizeof(header));
retval = read_sfdp_block(bank, 0x0, sizeof(header) >> 2, (uint32_t *)&header);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("header 0x%08" PRIx32 " 0x%08" PRIx32, header.signature, header.revision);
if (header.signature != SFDP_MAGIC) {
LOG_INFO("no SDFP found");
return ERROR_FLASH_BANK_NOT_PROBED;
}if (header.signature != SFDP_MAGIC) { ... }
if (((header.revision >> 24) & 0xFF) != SFDP_ACCESS_PROT) {
LOG_ERROR("access protocol 0x%02x not implemented",
(header.revision >> 24) & 0xFFU);
return ERROR_FLASH_BANK_NOT_PROBED;
}if (((header.revision >> 24) & 0xFF) != SFDP_ACCESS_PROT) { ... }
nph = ((header.revision >> 16) & 0xFF) + 1;
LOG_DEBUG("parameter headers: %d", nph);
pheaders = malloc(sizeof(struct sfdp_phdr) * nph);
if (!pheaders) {
LOG_ERROR("not enough memory");
return ERROR_FAIL;
}if (!pheaders) { ... }
memset(pheaders, 0, sizeof(struct sfdp_phdr) * nph);
retval = read_sfdp_block(bank, sizeof(header),
(sizeof(struct sfdp_phdr) >> 2) * nph, (uint32_t *)pheaders);
if (retval != ERROR_OK)
goto err;
for (k = 0; k < nph; k++) {
unsigned int words = (pheaders[k].revision >> 24) & 0xFF;
uint16_t id = (((pheaders[k].ptr) >> 16) & 0xFF00) | (pheaders[k].revision & 0xFF);
uint32_t ptr = pheaders[k].ptr & 0xFFFFFF;
LOG_DEBUG("pheader %d len=0x%02" PRIx8 " id=0x%04" PRIx16
" ptr=0x%06" PRIx32, k, words, id, ptr);
ptable = malloc(words << 2);
if (!ptable) {
LOG_ERROR("not enough memory");
retval = ERROR_FAIL;
goto err;
}if (!ptable) { ... }
retval = read_sfdp_block(bank, ptr, words, ptable);
if (retval != ERROR_OK)
goto err;
for (j = 0; j < words; j++)
LOG_DEBUG("word %02d 0x%08X", j + 1, ptable[j]);
if (id == SFDP_BASIC_FLASH) {
struct sfdp_basic_flash_param *table = (struct sfdp_basic_flash_param *)ptable;
uint16_t erase;
if (words < 9) {
LOG_ERROR("id=0x%04" PRIx16 " invalid length %d", id, words);
retval = ERROR_FLASH_BANK_NOT_PROBED;
goto err;
}if (words < 9) { ... }
LOG_DEBUG("basic flash parameter table");
dev->name = sfdp_name;
dev->read_cmd = SPIFLASH_READ;
dev->pprog_cmd = SPIFLASH_PAGE_PROGRAM;
dev->chip_erase_cmd = SPIFLASH_MASS_ERASE;
if (table->density & (1UL << 31))
dev->size_in_bytes = 1UL << ((table->density & ~(1UL << 31)) - 3);
else
dev->size_in_bytes = (table->density + 1) >> 3;
if (table->fast_444 & (1UL << 0))
dev->qread_cmd = (table->read_222 >> 24) & 0xFF;
if (table->fast_444 & (1UL << 4))
dev->qread_cmd = (table->read_444 >> 24) & 0xFF;
erase = (table->erase_t12 >> 0) & 0xFFFF;
erase_type = 1;
if (((table->erase_t12 >> 16) & 0xFF) > (erase & 0xFF)) {
erase = (table->erase_t12 >> 16) & 0xFFFF;
erase_type = 2;
}if (((table->erase_t12 >> 16) & 0xFF) > (erase & 0xFF)) { ... }
if (((table->erase_t34 >> 0) & 0xFF) > (erase & 0xFF)) {
erase = (table->erase_t34 >> 0) & 0xFFFF;
erase_type = 3;
}if (((table->erase_t34 >> 0) & 0xFF) > (erase & 0xFF)) { ... }
if (((table->erase_t34 >> 16) & 0xFF) > (erase & 0xFF)) {
erase = (table->erase_t34 >> 16) & 0xFFFF;
erase_type = 4;
}if (((table->erase_t34 >> 16) & 0xFF) > (erase & 0xFF)) { ... }
dev->erase_cmd = (erase >> 8) & 0xFF;
dev->sectorsize = 1UL << (erase & 0xFF);
if ((offsetof(struct sfdp_basic_flash_param, chip_byte) >> 2) < words) {
dev->pagesize = 1UL << ((table->chip_byte >> 4) & 0x0F);
}if ((offsetof(struct sfdp_basic_flash_param, chip_byte) >> 2) < words) { ... } else {
if (table->fast_addr & (1UL << 2)) {
dev->pagesize = 1UL << 6;
}if (table->fast_addr & (1UL << 2)) { ... } else {
dev->pagesize = 1UL << 4;
}else { ... }
}else { ... }
if (dev->size_in_bytes > (1UL << 24)) {
if (((table->fast_addr >> 17) & 0x3) == 0x0)
LOG_ERROR("device needs paging - not implemented");
if (((offsetof(struct sfdp_basic_flash_param, addr_reset) >> 2) < words) &&
(table->addr_reset & (1UL << 29))) {
/* ... */
dev->read_cmd = 0x13;
dev->pprog_cmd = 0x12;
dev->erase_cmd = 0xDC;
if (dev->qread_cmd != 0)
dev->qread_cmd = 0xEC;
}if (((offsetof(struct sfdp_basic_flash_param, addr_reset) >> 2) < words) && (table->addr_reset & (1UL << 29))) { ... } else if (((table->fast_addr >> 17) & 0x3) == 0x1)
LOG_INFO("device has to be switched to 4-byte addresses");
}if (dev->size_in_bytes > (1UL << 24)) { ... }
}if (id == SFDP_BASIC_FLASH) { ... } else if (id == SFDP_4BYTE_ADDR) {
struct sfdp_4byte_addr_param *table = (struct sfdp_4byte_addr_param *)ptable;
if (words >= (offsetof(struct sfdp_4byte_addr_param, erase_t1234)
+ sizeof(table->erase_t1234)) >> 2) {
LOG_INFO("4-byte address parameter table");
if (table->flags & (1UL << 0))
dev->read_cmd = 0x13;
if (table->flags & (1UL << 5))
dev->qread_cmd = 0xEC;
if (table->flags & (1UL << 6))
dev->pprog_cmd = 0x12;
if ((erase_type == 1) && (table->flags & (1UL << 9)))
dev->erase_cmd = (table->erase_t1234 >> 0) & 0xFF;
else if ((erase_type == 2) && (table->flags & (1UL << 10)))
dev->erase_cmd = (table->erase_t1234 >> 8) & 0xFF;
else if ((erase_type == 3) && (table->flags & (1UL << 11)))
dev->erase_cmd = (table->erase_t1234 >> 16) & 0xFF;
else if ((erase_type == 4) && (table->flags & (1UL << 12)))
dev->erase_cmd = (table->erase_t1234 >> 24) & 0xFF;
}if (words >= (offsetof(struct sfdp_4byte_addr_param, erase_t1234) + sizeof(table->erase_t1234)) >> 2) { ... } else
LOG_ERROR("parameter table id=0x%04" PRIx16 " invalid length %d", id, words);
}else if (id == SFDP_4BYTE_ADDR) { ... } else
LOG_DEBUG("unimplemented parameter table id=0x%04" PRIx16, id);
free(ptable);
ptable = NULL;
}for (k = 0; k < nph; k++) { ... }
if (erase_type != 0) {
LOG_INFO("valid SFDP detected");
retval = ERROR_OK;
}if (erase_type != 0) { ... } else {
LOG_ERROR("incomplete/invalid SFDP");
retval = ERROR_FLASH_BANK_NOT_PROBED;
}else { ... }
err:
free(pheaders);
free(ptable);
return retval;
}{ ... }