FreeCalypso > hg > freecalypso-tools
comparison loadtools/flamdsec.c @ 979:c5133c3c11b1
fc-loadtool flash: implement PL-J PPB programming functions
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 02 Dec 2023 04:21:59 +0000 |
parents | 511e2b85c115 |
children | f21798eb13cf |
comparison
equal
deleted
inserted
replaced
978:a400bb4a1620 | 979:c5133c3c11b1 |
---|---|
1 /* | 1 /* |
2 * This module is a place to implement commands that are specific to | 2 * This module is a place to implement commands and functions for |
3 * security features (OTP, sector locking) of AMD-style flash chips. | 3 * sector write-protection (locking and unlocking, checking current |
4 * lock state) on AMD-style flash chips. | |
4 */ | 5 */ |
5 | 6 |
6 #include <sys/types.h> | 7 #include <sys/types.h> |
7 #include <stdio.h> | 8 #include <stdio.h> |
8 #include <stdint.h> | 9 #include <stdint.h> |
9 #include <stdlib.h> | 10 #include <stdlib.h> |
11 #include <unistd.h> | |
10 #include "flash.h" | 12 #include "flash.h" |
11 | 13 |
12 extern struct flash_bank_info flash_bank_info[2]; | 14 extern struct flash_bank_info flash_bank_info[2]; |
13 | 15 |
14 static | 16 static |
166 if (pln_special_mode_exit(bi->base_addr) < 0) | 168 if (pln_special_mode_exit(bi->base_addr) < 0) |
167 return(-1); | 169 return(-1); |
168 } | 170 } |
169 return(0); | 171 return(0); |
170 } | 172 } |
173 | |
174 static | |
175 plj_ppb_write_op(base_addr, is_erase, retp) | |
176 uint32_t base_addr; | |
177 uint16_t *retp; | |
178 { | |
179 if (do_w16(base_addr + 0xAAA, 0xAA)) { | |
180 bad_w16: fprintf(stderr, | |
181 "unexpected response to w16 in PPB command sequence - aborting\n"); | |
182 return(-1); | |
183 } | |
184 if (do_w16(base_addr + 0x554, 0x55)) | |
185 goto bad_w16; | |
186 if (do_w16(base_addr + 0xAAA, 0x60)) | |
187 goto bad_w16; | |
188 if (do_w16(base_addr + 4, is_erase ? 0x60 : 0x68)) | |
189 goto bad_w16; | |
190 usleep(1200); /* per S29PL-J datasheet */ | |
191 if (do_w16(base_addr + 4, is_erase ? 0x40 : 0x48)) | |
192 goto bad_w16; | |
193 if (do_r16(base_addr + 4, retp) < 0) | |
194 return(-1); | |
195 return(0); | |
196 } | |
197 | |
198 plj_ppb_program_one(bi, sector_addr) | |
199 struct flash_bank_info *bi; | |
200 uint32_t sector_addr; | |
201 { | |
202 uint16_t stat; | |
203 unsigned pulsecnt; | |
204 int rc; | |
205 | |
206 for (pulsecnt = 0; pulsecnt < 25; ) { | |
207 rc = plj_ppb_write_op(bi->base_addr + sector_addr, 0, &stat); | |
208 if (rc < 0) | |
209 return(rc); | |
210 pulsecnt++; | |
211 if (!(stat & 1)) | |
212 continue; | |
213 printf("PPB 0x%X programmed with %u pulse%s\n", sector_addr, | |
214 pulsecnt, pulsecnt > 1 ? "s" : ""); | |
215 return(0); | |
216 } | |
217 printf("PPB 0x%X programming FAILED, tried %u pulses\n", sector_addr, | |
218 pulsecnt); | |
219 return(-1); | |
220 } | |
221 | |
222 plj_ppb_program_all_single(bank) | |
223 { | |
224 struct flash_bank_info *bi = flash_bank_info + bank; | |
225 struct amd_lock_info *li = bi->amd_lock; | |
226 struct lock_group_desc *grp; | |
227 uint32_t offset; | |
228 unsigned ng, nb; | |
229 int rc; | |
230 | |
231 offset = 0; | |
232 for (ng = 0; ng < li->ngroups; ng++) { | |
233 grp = li->groups + ng; | |
234 for (nb = 0; nb < grp->nblocks; nb++) { | |
235 rc = plj_ppb_program_one(bi, offset); | |
236 if (rc < 0) | |
237 return(rc); | |
238 offset += grp->block_size; | |
239 } | |
240 } | |
241 return(0); | |
242 } | |
243 | |
244 plj_ppb_program_all_dualbank(reqbank) | |
245 { | |
246 int altbank = !reqbank; | |
247 int rc; | |
248 | |
249 if (flash_detect(altbank, 0) < 0) | |
250 return(-1); | |
251 if (flash_bank_info[0].device != flash_bank_info[1].device) { | |
252 fprintf(stderr, "error: mismatch between two flash banks\n"); | |
253 return(-1); | |
254 } | |
255 printf("Programming all PPBs in flash bank 0\n"); | |
256 rc = plj_ppb_program_all_single(0); | |
257 if (rc < 0) | |
258 return(-1); | |
259 printf("Programming all PPBs in flash bank 1\n"); | |
260 rc = plj_ppb_program_all_single(1); | |
261 if (rc < 0) | |
262 return(-1); | |
263 return(0); | |
264 } | |
265 | |
266 static | |
267 plj_ppb_erase_cycle(bank) | |
268 { | |
269 struct flash_bank_info *bi = flash_bank_info + bank; | |
270 uint16_t stat; | |
271 unsigned pulsecnt; | |
272 int rc; | |
273 | |
274 printf("Performing PPB erase cycle\n"); | |
275 for (pulsecnt = 0; pulsecnt < 1000; ) { | |
276 rc = plj_ppb_write_op(bi->base_addr, 1, &stat); | |
277 if (rc < 0) | |
278 return(rc); | |
279 pulsecnt++; | |
280 if (stat & 1) | |
281 continue; | |
282 printf("PPB erase cycle succeeded after %u pulse%s\n", | |
283 pulsecnt, pulsecnt > 1 ? "s" : ""); | |
284 return(0); | |
285 } | |
286 printf("PPB erase cycle FAILED, tried %u pulses\n", pulsecnt); | |
287 return(-1); | |
288 } | |
289 | |
290 plj_ppb_erase_all_single(bank) | |
291 { | |
292 int rc; | |
293 | |
294 printf("Programming all PPBs before erase cycle\n"); | |
295 rc = plj_ppb_program_all_single(bank); | |
296 if (rc < 0) | |
297 return(-1); | |
298 return plj_ppb_erase_cycle(bank); | |
299 } | |
300 | |
301 plj_ppb_erase_all_dualbank(reqbank) | |
302 { | |
303 int rc; | |
304 | |
305 rc = plj_ppb_program_all_dualbank(reqbank); | |
306 if (rc < 0) | |
307 return(-1); | |
308 return plj_ppb_erase_cycle(reqbank); | |
309 } |