# HG changeset patch # User Mychaela Falconia # Date 1701490919 0 # Node ID c5133c3c11b1c4178b12f5f04744c92653ab03d6 # Parent a400bb4a1620ad446cc93c4b7eddcc71833745a6 fc-loadtool flash: implement PL-J PPB programming functions diff -r a400bb4a1620 -r c5133c3c11b1 loadtools/flamdsec.c --- a/loadtools/flamdsec.c Fri Dec 01 08:05:31 2023 +0000 +++ b/loadtools/flamdsec.c Sat Dec 02 04:21:59 2023 +0000 @@ -1,12 +1,14 @@ /* - * This module is a place to implement commands that are specific to - * security features (OTP, sector locking) of AMD-style flash chips. + * This module is a place to implement commands and functions for + * sector write-protection (locking and unlocking, checking current + * lock state) on AMD-style flash chips. */ #include #include #include #include +#include #include "flash.h" extern struct flash_bank_info flash_bank_info[2]; @@ -168,3 +170,140 @@ } return(0); } + +static +plj_ppb_write_op(base_addr, is_erase, retp) + uint32_t base_addr; + uint16_t *retp; +{ + if (do_w16(base_addr + 0xAAA, 0xAA)) { +bad_w16: fprintf(stderr, + "unexpected response to w16 in PPB command sequence - aborting\n"); + return(-1); + } + if (do_w16(base_addr + 0x554, 0x55)) + goto bad_w16; + if (do_w16(base_addr + 0xAAA, 0x60)) + goto bad_w16; + if (do_w16(base_addr + 4, is_erase ? 0x60 : 0x68)) + goto bad_w16; + usleep(1200); /* per S29PL-J datasheet */ + if (do_w16(base_addr + 4, is_erase ? 0x40 : 0x48)) + goto bad_w16; + if (do_r16(base_addr + 4, retp) < 0) + return(-1); + return(0); +} + +plj_ppb_program_one(bi, sector_addr) + struct flash_bank_info *bi; + uint32_t sector_addr; +{ + uint16_t stat; + unsigned pulsecnt; + int rc; + + for (pulsecnt = 0; pulsecnt < 25; ) { + rc = plj_ppb_write_op(bi->base_addr + sector_addr, 0, &stat); + if (rc < 0) + return(rc); + pulsecnt++; + if (!(stat & 1)) + continue; + printf("PPB 0x%X programmed with %u pulse%s\n", sector_addr, + pulsecnt, pulsecnt > 1 ? "s" : ""); + return(0); + } + printf("PPB 0x%X programming FAILED, tried %u pulses\n", sector_addr, + pulsecnt); + return(-1); +} + +plj_ppb_program_all_single(bank) +{ + struct flash_bank_info *bi = flash_bank_info + bank; + struct amd_lock_info *li = bi->amd_lock; + struct lock_group_desc *grp; + uint32_t offset; + unsigned ng, nb; + int rc; + + offset = 0; + for (ng = 0; ng < li->ngroups; ng++) { + grp = li->groups + ng; + for (nb = 0; nb < grp->nblocks; nb++) { + rc = plj_ppb_program_one(bi, offset); + if (rc < 0) + return(rc); + offset += grp->block_size; + } + } + return(0); +} + +plj_ppb_program_all_dualbank(reqbank) +{ + int altbank = !reqbank; + int rc; + + if (flash_detect(altbank, 0) < 0) + return(-1); + if (flash_bank_info[0].device != flash_bank_info[1].device) { + fprintf(stderr, "error: mismatch between two flash banks\n"); + return(-1); + } + printf("Programming all PPBs in flash bank 0\n"); + rc = plj_ppb_program_all_single(0); + if (rc < 0) + return(-1); + printf("Programming all PPBs in flash bank 1\n"); + rc = plj_ppb_program_all_single(1); + if (rc < 0) + return(-1); + return(0); +} + +static +plj_ppb_erase_cycle(bank) +{ + struct flash_bank_info *bi = flash_bank_info + bank; + uint16_t stat; + unsigned pulsecnt; + int rc; + + printf("Performing PPB erase cycle\n"); + for (pulsecnt = 0; pulsecnt < 1000; ) { + rc = plj_ppb_write_op(bi->base_addr, 1, &stat); + if (rc < 0) + return(rc); + pulsecnt++; + if (stat & 1) + continue; + printf("PPB erase cycle succeeded after %u pulse%s\n", + pulsecnt, pulsecnt > 1 ? "s" : ""); + return(0); + } + printf("PPB erase cycle FAILED, tried %u pulses\n", pulsecnt); + return(-1); +} + +plj_ppb_erase_all_single(bank) +{ + int rc; + + printf("Programming all PPBs before erase cycle\n"); + rc = plj_ppb_program_all_single(bank); + if (rc < 0) + return(-1); + return plj_ppb_erase_cycle(bank); +} + +plj_ppb_erase_all_dualbank(reqbank) +{ + int rc; + + rc = plj_ppb_program_all_dualbank(reqbank); + if (rc < 0) + return(-1); + return plj_ppb_erase_cycle(reqbank); +} diff -r a400bb4a1620 -r c5133c3c11b1 loadtools/flash.h --- a/loadtools/flash.h Fri Dec 01 08:05:31 2023 +0000 +++ b/loadtools/flash.h Sat Dec 02 04:21:59 2023 +0000 @@ -61,6 +61,9 @@ int have_status_word_7; int have_mode_lock_bits; int have_pln_lock_reg; + int (*ppb_program_one)(); + int (*ppb_program_all)(); + int (*ppb_erase_all)(); }; struct flash_device { diff -r a400bb4a1620 -r c5133c3c11b1 loadtools/fldevs.c --- a/loadtools/fldevs.c Fri Dec 01 08:05:31 2023 +0000 +++ b/loadtools/fldevs.c Sat Dec 02 04:21:59 2023 +0000 @@ -9,6 +9,12 @@ extern struct flash_cmdset flash_cmdset_intel; extern struct flash_cmdset flash_cmdset_intel_w30; +extern int plj_ppb_program_one(); +extern int plj_ppb_program_all_single(); +extern int plj_ppb_program_all_dualbank(); +extern int plj_ppb_erase_all_single(); +extern int plj_ppb_erase_all_dualbank(); + /* flash bank geometries */ static struct flash_geom geom_2M_topboot = { @@ -434,6 +440,9 @@ {0x2000, 8, 0, 0, 1}}, .have_status_word_3 = 1, .have_mode_lock_bits = 1, + .ppb_program_one = plj_ppb_program_one, + .ppb_program_all = plj_ppb_program_all_single, + .ppb_erase_all = plj_ppb_erase_all_single, }; struct flash_device flashdev_PL064J = { @@ -484,6 +493,9 @@ {0x40000, 24, 1, 1, 1}}, .have_status_word_3 = 1, .have_mode_lock_bits = 1, + .ppb_program_one = plj_ppb_program_one, + .ppb_program_all = plj_ppb_program_all_dualbank, + .ppb_erase_all = plj_ppb_erase_all_dualbank, }; static struct amd_lock_info PL129J_lock_info_1 = { @@ -494,6 +506,9 @@ {0x10000, 3, 0, 0, 0}, {0x2000, 8, 0, 0, 1}}, .have_status_word_3 = 1, + .ppb_program_one = plj_ppb_program_one, + .ppb_program_all = plj_ppb_program_all_dualbank, + .ppb_erase_all = plj_ppb_erase_all_dualbank, }; struct flash_device flashdev_PL129J = { @@ -685,6 +700,9 @@ .have_status_word_3 = 1, .have_status_word_7 = 1, .have_mode_lock_bits = 1, + .ppb_program_one = plj_ppb_program_one, + .ppb_program_all = plj_ppb_program_all_dualbank, + .ppb_erase_all = plj_ppb_erase_all_dualbank, }; static struct amd_lock_info K5L29_lock_info_1 = { @@ -696,6 +714,9 @@ {0x2000, 8, 0, 0, 1}}, .have_status_word_3 = 1, .have_status_word_7 = 1, + .ppb_program_one = plj_ppb_program_one, + .ppb_program_all = plj_ppb_program_all_dualbank, + .ppb_erase_all = plj_ppb_erase_all_dualbank, }; struct flash_device flashdev_K5L29xx_A = {