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 }