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

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)