# HG changeset patch # User Mychaela Falconia # Date 1701413001 0 # Node ID ff4ce8d5ece4f81ff6125ee555105d581bc7f622 # Parent 343552c6c6216583e9f8ea060da2a5b0f63eb4b7 fc-loadtool flash: definitions for AMD sector lock architecture diff -r 343552c6c621 -r ff4ce8d5ece4 loadtools/flash.h --- a/loadtools/flash.h Tue Nov 28 19:08:53 2023 +0000 +++ b/loadtools/flash.h Fri Dec 01 06:43:21 2023 +0000 @@ -36,12 +36,40 @@ uint8_t expect_val; }; +/* + * In order to examine non-volatile sector lock state of AMD-style flash + * chips, we need to know how their sectors are grouped for the purpose + * of locking: aggregation of sectors into groups that can only be locked + * or unlocked as a unit, and also grouping into independent-read partitions + * where each partition needs its own Autoselect sequence. + */ + +struct lock_group_desc { + uint32_t block_size; + unsigned nblocks; + int is_group; + int part_begin; + int part_end; +}; + +#define MAX_AMD_LOCK_GROUPS 8 + +struct amd_lock_info { + unsigned ngroups; + struct lock_group_desc groups[MAX_AMD_LOCK_GROUPS]; + int have_status_word_3; + int have_status_word_7; + int have_mode_lock_bits; + int have_pln_lock_reg; +}; + struct flash_device { char *name; struct cfi_check *cfi_table; int required_global_config; struct flash_geom *bank_geom[2]; struct flash_cmdset *cmdset; + struct amd_lock_info *lock_info[2]; }; /* the following structures describe flash banks as accessible to us */ @@ -70,6 +98,7 @@ struct flash_device *device; struct flash_geom *geom; struct flash_cmdset *ops; + struct amd_lock_info *amd_lock; struct sector_info *sectors; int detect_done; }; diff -r 343552c6c621 -r ff4ce8d5ece4 loadtools/flashid.c --- a/loadtools/flashid.c Tue Nov 28 19:08:53 2023 +0000 +++ b/loadtools/flashid.c Fri Dec 01 06:43:21 2023 +0000 @@ -21,6 +21,7 @@ extern struct flash_device flashdev_Am29DL640G; extern struct flash_device flashdev_PL032J; +extern struct flash_device flashdev_PL064J; extern struct flash_device flashdev_PL129J; extern struct flash_device flashdev_PL129N; extern struct flash_device flashdev_K5A32xx_T; @@ -133,6 +134,37 @@ } static +spansion_pl064j_or_oldamd(bi) + struct flash_bank_info *bi; +{ + int rc; + + printf("Am29DL640G or PL064J, looking at CFI\n"); + if (do_w16(bi->base_addr + 0xAA, 0x98)) { + fprintf(stderr, "unexpected response to w16 - aborting\n"); + return(-1); + } + rc = run_cfi_check(bi, flashdev_PL064J.cfi_table); + if (rc < 0) + return(rc); + if (rc) { + printf("Found PL064J\n"); + bi->device = &flashdev_PL064J; + return(0); + } + rc = run_cfi_check(bi, flashdev_Am29DL640G.cfi_table); + if (rc < 0) + return(rc); + if (rc) { + printf("Found Am29DL640G\n"); + bi->device = &flashdev_Am29DL640G; + return(0); + } + fprintf(stderr, "Error: no matching CFI found\n"); + return(-1); +} + +static amd_extended_id(bi) struct flash_bank_info *bi; { @@ -147,7 +179,7 @@ if (ext1 == 0x2221 && ext2 == 0x2200) return spansion_pl129j_or_n(bi); if (ext1 == 0x2202 && ext2 == 0x2201) - return try_device(bi, &flashdev_Am29DL640G); + return spansion_pl064j_or_oldamd(bi); if (ext1 == 0x220A && ext2 == 0x2201) return try_device(bi, &flashdev_PL032J); fprintf(stderr, "Error: unknown device ID\n"); @@ -251,10 +283,13 @@ return(-1); } /* good to go */ - if (bi->device->bank_geom[1] && bank) + if (bi->device->bank_geom[1] && bank) { bi->geom = bi->device->bank_geom[1]; - else + bi->amd_lock = bi->device->lock_info[1]; + } else { bi->geom = bi->device->bank_geom[0]; + bi->amd_lock = bi->device->lock_info[0]; + } bi->ops = bi->device->cmdset; bi->detect_done = 1; /* return device to read array mode */ diff -r 343552c6c621 -r ff4ce8d5ece4 loadtools/fldevs.c --- a/loadtools/fldevs.c Tue Nov 28 19:08:53 2023 +0000 +++ b/loadtools/fldevs.c Fri Dec 01 06:43:21 2023 +0000 @@ -316,15 +316,31 @@ {0x42, 'I'}, {0x43, '1'}, {0x44, '3'}, + {0x49, 0x04}, {-1, 0} }; +static struct amd_lock_info Am29DL640G_lock_info = { + .ngroups = 8, + .groups = { + {0x2000, 8, 0, 1, 0}, + {0x10000, 3, 0, 0, 0}, + {0x40000, 3, 1, 0, 1}, + {0x40000, 12, 1, 1, 1}, + {0x40000, 12, 1, 1, 1}, + {0x40000, 3, 1, 1, 0}, + {0x10000, 3, 0, 0, 0}, + {0x2000, 8, 0, 0, 1}}, + .have_status_word_3 = 1, +}; + struct flash_device flashdev_Am29DL640G = { .name = "Am29DL640G", .cfi_table = Am29DL640G_cfi, .required_global_config = FLASH_GLOBAL_CFG_SINGLE_8M, .bank_geom = {&geom_8M_bothends, 0}, .cmdset = &flash_cmdset_amd, + .lock_info = {&Am29DL640G_lock_info, 0}, }; /* Spansion S71PL-J and S71PL-N flash */ @@ -367,7 +383,67 @@ .cmdset = &flash_cmdset_amd, }; -/* S29PL064J/S71PL064J is identical to Am29DL640G covered above */ +/* + * For our purposes, S29PL064J/S71PL064J differs from Am29DL640G only + * in terms of lock status retrieval and manipulation: the older chip + * lacks persistent/password mode lock bits and in-system lock/unlock + * operations. We distinguish them by one byte in CFI. + */ + +static struct cfi_check spansion_PL064J_cfi[] = { + {0x10, 'Q'}, + {0x11, 'R'}, + {0x12, 'Y'}, + {0x13, 0x02}, + {0x14, 0x00}, + {0x15, 0x40}, + {0x16, 0x00}, + {0x27, 0x17}, + {0x2C, 0x03}, + {0x2D, 0x07}, + {0x2E, 0x00}, + {0x2F, 0x20}, + {0x30, 0x00}, + {0x31, 0x7D}, + {0x32, 0x00}, + {0x33, 0x00}, + {0x34, 0x01}, + {0x35, 0x07}, + {0x36, 0x00}, + {0x37, 0x20}, + {0x38, 0x00}, + {0x40, 'P'}, + {0x41, 'R'}, + {0x42, 'I'}, + {0x43, '1'}, + {0x44, '3'}, + {0x49, 0x07}, + {-1, 0} +}; + +static struct amd_lock_info PL064J_lock_info = { + .ngroups = 8, + .groups = { + {0x2000, 8, 0, 1, 0}, + {0x10000, 3, 0, 0, 0}, + {0x40000, 3, 1, 0, 1}, + {0x40000, 12, 1, 1, 1}, + {0x40000, 12, 1, 1, 1}, + {0x40000, 3, 1, 1, 0}, + {0x10000, 3, 0, 0, 0}, + {0x2000, 8, 0, 0, 1}}, + .have_status_word_3 = 1, + .have_mode_lock_bits = 1, +}; + +struct flash_device flashdev_PL064J = { + .name = "Spansion S29PL064J", + .cfi_table = spansion_PL064J_cfi, + .required_global_config = FLASH_GLOBAL_CFG_SINGLE_8M, + .bank_geom = {&geom_8M_bothends, 0}, + .cmdset = &flash_cmdset_amd, + .lock_info = {&PL064J_lock_info, 0}, +}; static struct cfi_check spansion_PL129J_cfi[] = { {0x10, 'Q'}, @@ -399,12 +475,35 @@ {-1, 0} }; +static struct amd_lock_info PL129J_lock_info_0 = { + .ngroups = 4, + .groups = { + {0x2000, 8, 0, 1, 0}, + {0x10000, 3, 0, 0, 0}, + {0x40000, 7, 1, 0, 1}, + {0x40000, 24, 1, 1, 1}}, + .have_status_word_3 = 1, + .have_mode_lock_bits = 1, +}; + +static struct amd_lock_info PL129J_lock_info_1 = { + .ngroups = 4, + .groups = { + {0x40000, 24, 1, 1, 1}, + {0x40000, 7, 1, 1, 0}, + {0x10000, 3, 0, 0, 0}, + {0x2000, 8, 0, 0, 1}}, + .have_status_word_3 = 1, + .have_mode_lock_bits = 1, +}; + struct flash_device flashdev_PL129J = { .name = "Spansion S29PL129J", .cfi_table = spansion_PL129J_cfi, .required_global_config = FLASH_GLOBAL_CFG_DUAL_8M, .bank_geom = {&geom_8M_bottomboot, &geom_8M_topboot}, .cmdset = &flash_cmdset_amd, + .lock_info = {&PL129J_lock_info_0, &PL129J_lock_info_1}, }; static struct cfi_check spansion_PL129N_cfi[] = { @@ -437,6 +536,26 @@ {-1, 0} }; +static struct amd_lock_info PL129N_lock_info_0 = { + .ngroups = 3, + .groups = { + {0x10000, 4, 0, 1, 0}, + {0x40000, 7, 1, 0, 1}, + {0x40000, 24, 1, 1, 1}}, + .have_status_word_3 = 1, + .have_pln_lock_reg = 1, +}; + +static struct amd_lock_info PL129N_lock_info_1 = { + .ngroups = 3, + .groups = { + {0x40000, 24, 1, 1, 1}, + {0x40000, 7, 1, 1, 0}, + {0x10000, 4, 0, 0, 1}}, + .have_status_word_3 = 1, + .have_pln_lock_reg = 1, +}; + struct flash_device flashdev_PL129N = { .name = "Spansion S29PL129N", .cfi_table = spansion_PL129N_cfi, @@ -444,6 +563,7 @@ .bank_geom = {&geom_8M_bottomboot_big, &geom_8M_topboot_big}, .cmdset = &flash_cmdset_amd, + .lock_info = {&PL129N_lock_info_0, &PL129N_lock_info_1}, }; /* Samsung K5A32xxCTM introduced onto the scene by Openmoko */ @@ -557,10 +677,35 @@ {-1, 0} }; +static struct amd_lock_info K5L29_lock_info_0 = { + .ngroups = 4, + .groups = { + {0x2000, 8, 0, 1, 0}, + {0x10000, 3, 0, 0, 0}, + {0x40000, 7, 1, 0, 1}, + {0x40000, 24, 1, 1, 1}}, + .have_status_word_3 = 1, + .have_status_word_7 = 1, + .have_mode_lock_bits = 1, +}; + +static struct amd_lock_info K5L29_lock_info_1 = { + .ngroups = 4, + .groups = { + {0x40000, 24, 1, 1, 1}, + {0x40000, 7, 1, 1, 0}, + {0x10000, 3, 0, 0, 0}, + {0x2000, 8, 0, 0, 1}}, + .have_status_word_3 = 1, + .have_status_word_7 = 1, + .have_mode_lock_bits = 1, +}; + struct flash_device flashdev_K5L29xx_A = { .name = "Samsung K5L29xx_A", .cfi_table = samsung_PL129J_equiv_cfi, .required_global_config = FLASH_GLOBAL_CFG_DUAL_8M, .bank_geom = {&geom_8M_bottomboot, &geom_8M_topboot}, .cmdset = &flash_cmdset_amd, + .lock_info = {&K5L29_lock_info_0, &K5L29_lock_info_1}, };