jtagspi: fix build on MacOS
[openocd.git] / src / flash / nor / sfdp.c
1 /***************************************************************************
2 * Copyright (C) 2019 by Andreas Bolsch <andreas.bolsch@mni.thm.de *
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 2 of the License, or *
6 * (at your option) any later version. *
7 * *
8 * This program is distributed in the hope that it will be useful, *
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11 * GNU General Public License for more details. *
12 * *
13 * You should have received a copy of the GNU General Public License *
14 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
15 ***************************************************************************/
16
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #include "imp.h"
22 #include "spi.h"
23 #include "sfdp.h"
24
25 #define SFDP_MAGIC 0x50444653
26 #define SFDP_ACCESS_PROT 0xFF
27 #define SFDP_BASIC_FLASH 0xFF00
28 #define SFDP_4BYTE_ADDR 0xFF84
29
30 static const char *sfdp_name = "sfdp";
31
32 struct sfdp_hdr {
33 uint32_t signature;
34 uint32_t revision;
35 };
36
37 struct sfdp_phdr {
38 uint32_t revision;
39 uint32_t ptr;
40 };
41
42 struct sfdp_basic_flash_param {
43 uint32_t fast_addr; /* 01: fast read and 3/4 address bytes */
44 uint32_t density; /* 02: memory density */
45 uint32_t fast_1x4; /* 03: 1-1-4 and 1-4-4 fast read */
46 uint32_t fast_1x2; /* 04: 1-2-2 and 1-1-2 fast read */
47 uint32_t fast_444; /* 05: 4-4-4 and 2-2-2 fast read */
48 uint32_t read_222; /* 06: 2-2-2 fast read instr and dummy */
49 uint32_t read_444; /* 07: 4-4-4 fast read instr and dummy */
50 uint32_t erase_t12; /* 08: erase types 1, 2 */
51 uint32_t erase_t34; /* 09: erase types 3, 4 */
52 uint32_t erase_time; /* 10: erase times for types 1 - 4 */
53 uint32_t chip_byte; /* 11: chip erase time, byte prog time, page prog */
54 uint32_t susp_time; /* 12: suspend and resume times */
55 uint32_t susp_instr; /* 13: suspend and resume instr */
56 uint32_t pwrd_instr; /* 14: powerdown instr */
57 uint32_t quad_req; /* 15: quad enable requirements */
58 uint32_t addr_reset; /* 16: 3-/4-byte addressing and reset */
59 uint32_t read_1x8; /* 17: 1-1-8 and 1-8-8 fast read instr and dummy */
60 uint32_t dtr_drive; /* 18: dtr modes and drive strength */
61 uint32_t octal_req; /* 19: octal enable requirements */
62 uint32_t speed_888; /* 20: speed in 8-8-8 modes */
63 };
64
65 struct sfdp_4byte_addr_param {
66 uint32_t flags; /* 01: various flags */
67 uint32_t erase_t1234; /* 02: erase commands */
68 };
69
70 /* Try to get parameters from flash via SFDP */
71 int spi_sfdp(struct flash_bank *bank, struct flash_device *dev,
72 read_sfdp_block_t read_sfdp_block)
73 {
74 struct sfdp_hdr header;
75 struct sfdp_phdr *pheaders = NULL;
76 uint32_t *ptable = NULL;
77 unsigned int j, k, nph;
78 int retval, erase_type = 0;
79
80 memset(dev, 0, sizeof(struct flash_device));
81
82 /* retrieve SFDP header */
83 memset(&header, 0, sizeof(header));
84 retval = read_sfdp_block(bank, 0x0, sizeof(header) >> 2, (uint32_t *)&header);
85 if (retval != ERROR_OK)
86 return retval;
87 LOG_DEBUG("header 0x%08" PRIx32 " 0x%08" PRIx32, header.signature, header.revision);
88 if (header.signature != SFDP_MAGIC) {
89 LOG_INFO("no SDFP found");
90 return ERROR_FLASH_BANK_NOT_PROBED;
91 }
92 if (((header.revision >> 24) & 0xFF) != SFDP_ACCESS_PROT) {
93 LOG_ERROR("access protocol 0x%02x not implemented",
94 (header.revision >> 24) & 0xFFU);
95 return ERROR_FLASH_BANK_NOT_PROBED;
96 }
97
98 /* retrieve table of parameter headers */
99 nph = ((header.revision >> 16) & 0xFF) + 1;
100 LOG_DEBUG("parameter headers: %d", nph);
101 pheaders = malloc(sizeof(struct sfdp_phdr) * nph);
102 if (!pheaders) {
103 LOG_ERROR("not enough memory");
104 return ERROR_FAIL;
105 }
106 memset(pheaders, 0, sizeof(struct sfdp_phdr) * nph);
107 retval = read_sfdp_block(bank, sizeof(header),
108 (sizeof(struct sfdp_phdr) >> 2) * nph, (uint32_t *)pheaders);
109 if (retval != ERROR_OK)
110 goto err;
111
112 for (k = 0; k < nph; k++) {
113 uint8_t words = (pheaders[k].revision >> 24) & 0xFF;
114 uint16_t id = (((pheaders[k].ptr) >> 16) & 0xFF00) | (pheaders[k].revision & 0xFF);
115 uint32_t ptr = pheaders[k].ptr & 0xFFFFFF;
116
117 LOG_DEBUG("pheader %d len=0x%02" PRIx8 " id=0x%04" PRIx16
118 " ptr=0x%06" PRIx32, k, words, id, ptr);
119
120 /* retrieve parameter table */
121 ptable = malloc(words << 2);
122 if (!ptable) {
123 LOG_ERROR("not enough memory");
124 retval = ERROR_FAIL;
125 goto err;
126 }
127 retval = read_sfdp_block(bank, ptr, words, ptable);
128 if (retval != ERROR_OK)
129 goto err;
130
131 for (j = 0; j < words; j++)
132 LOG_DEBUG("word %02d 0x%08X", j + 1, ptable[j]);
133
134 if (id == SFDP_BASIC_FLASH) {
135 struct sfdp_basic_flash_param *table = (struct sfdp_basic_flash_param *)ptable;
136 uint16_t erase;
137
138 if (words < 9) {
139 LOG_ERROR("id=0x%04" PRIx16 " invalid length %d", id, words);
140 retval = ERROR_FLASH_BANK_NOT_PROBED;
141 goto err;
142 }
143
144 LOG_DEBUG("basic flash parameter table");
145 /* dummy device name */
146 dev->name = sfdp_name;
147
148 /* default instructions */
149 dev->read_cmd = SPIFLASH_READ;
150 dev->pprog_cmd = SPIFLASH_PAGE_PROGRAM;
151 dev->chip_erase_cmd = SPIFLASH_MASS_ERASE;
152
153 /* get device size */
154 if (table->density & (1UL << 31))
155 dev->size_in_bytes = 1UL << ((table->density & ~(1UL << 31)) - 3);
156 else
157 dev->size_in_bytes = (table->density + 1) >> 3;
158
159 /* 2-2-2 read instruction, not used */
160 if (table->fast_444 & (1UL << 0))
161 dev->qread_cmd = (table->read_222 >> 24) & 0xFF;
162
163 /* 4-4-4 read instruction */
164 if (table->fast_444 & (1UL << 4))
165 dev->qread_cmd = (table->read_444 >> 24) & 0xFF;
166
167 /* find the largest erase block size and instruction */
168 erase = (table->erase_t12 >> 0) & 0xFFFF;
169 erase_type = 1;
170 if (((table->erase_t12 >> 16) & 0xFF) > (erase & 0xFF)) {
171 erase = (table->erase_t12 >> 16) & 0xFFFF;
172 erase_type = 2;
173 }
174 if (((table->erase_t34 >> 0) & 0xFF) > (erase & 0xFF)) {
175 erase = (table->erase_t34 >> 0) & 0xFFFF;
176 erase_type = 3;
177 }
178 if (((table->erase_t34 >> 16) & 0xFF) > (erase & 0xFF)) {
179 erase = (table->erase_t34 >> 16) & 0xFFFF;
180 erase_type = 4;
181 }
182 dev->erase_cmd = (erase >> 8) & 0xFF;
183 dev->sectorsize = 1UL << (erase & 0xFF);
184
185 if ((offsetof(struct sfdp_basic_flash_param, chip_byte) >> 2) < words) {
186 /* get Program Page Size, if chip_byte present, that's optional */
187 dev->pagesize = 1UL << ((table->chip_byte >> 4) & 0x0F);
188 } else {
189 /* no explicit page size specified ... */
190 if (table->fast_addr & (1UL << 2)) {
191 /* Write Granularity = 1, use 64 bytes */
192 dev->pagesize = 1UL << 6;
193 } else {
194 /* Write Granularity = 0, use 16 bytes */
195 dev->pagesize = 1UL << 4;
196 }
197 }
198
199 if (dev->size_in_bytes > (1UL << 24)) {
200 if (((table->fast_addr >> 17) & 0x3) == 0x0)
201 LOG_ERROR("device needs paging - not implemented");
202
203 /* 4-byte addresses needed if more than 16 MBytes */
204 if (((offsetof(struct sfdp_basic_flash_param, addr_reset) >> 2) < words) &&
205 (table->addr_reset & (1UL << 29))) {
206 /* dedicated 4-byte-address instructions, hopefully these ...
207 * this entry is unfortunately optional as well
208 * a subsequent 4-byte address table may overwrite this */
209 dev->read_cmd = 0x13;
210 dev->pprog_cmd = 0x12;
211 dev->erase_cmd = 0xDC;
212 if (dev->qread_cmd != 0)
213 dev->qread_cmd = 0xEC;
214 } else if (((table->fast_addr >> 17) & 0x3) == 0x1)
215 LOG_INFO("device has to be switched to 4-byte addresses");
216 }
217 } else if (id == SFDP_4BYTE_ADDR) {
218 struct sfdp_4byte_addr_param *table = (struct sfdp_4byte_addr_param *)ptable;
219
220 if (words >= (offsetof(struct sfdp_4byte_addr_param, erase_t1234)
221 + sizeof(table->erase_t1234)) >> 2) {
222 LOG_INFO("4-byte address parameter table");
223
224 /* read and page program instructions */
225 if (table->flags & (1UL << 0))
226 dev->read_cmd = 0x13;
227 if (table->flags & (1UL << 5))
228 dev->qread_cmd = 0xEC;
229 if (table->flags & (1UL << 6))
230 dev->pprog_cmd = 0x12;
231
232 /* erase instructions */
233 if ((erase_type == 1) && (table->flags & (1UL << 9)))
234 dev->erase_cmd = (table->erase_t1234 >> 0) & 0xFF;
235 else if ((erase_type == 2) && (table->flags & (1UL << 10)))
236 dev->erase_cmd = (table->erase_t1234 >> 8) & 0xFF;
237 else if ((erase_type == 3) && (table->flags & (1UL << 11)))
238 dev->erase_cmd = (table->erase_t1234 >> 16) & 0xFF;
239 else if ((erase_type == 4) && (table->flags & (1UL << 12)))
240 dev->erase_cmd = (table->erase_t1234 >> 24) & 0xFF;
241 } else
242 LOG_ERROR("parameter table id=0x%04" PRIx16 " invalid length %d", id, words);
243 } else
244 LOG_DEBUG("unimplemented parameter table id=0x%04" PRIx16, id);
245
246 free(ptable);
247 ptable = NULL;
248 }
249
250 if (erase_type != 0) {
251 LOG_INFO("valid SFDP detected");
252 retval = ERROR_OK;
253 } else {
254 LOG_ERROR("incomplete/invalid SFDP");
255 retval = ERROR_FLASH_BANK_NOT_PROBED;
256 }
257
258 err:
259 free(pheaders);
260 free(ptable);
261
262 return retval;
263 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)