FreeCalypso > hg > freecalypso-tools
diff loadtools/flashid.c @ 506:0dd2c87c1b63
fc-loadtool flash support overhaul
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Tue, 28 May 2019 05:12:47 +0000 |
parents | |
children | c942be3c7997 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/flashid.c Tue May 28 05:12:47 2019 +0000 @@ -0,0 +1,188 @@ +/* + * Flash device detection code lives here + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include "flash.h" + +extern struct flash_device flashdev_28F160C3T; +extern struct flash_device flashdev_28F320C3T; +extern struct flash_device flashdev_28F640C3T; +extern struct flash_device flashdev_28F640C3B; +extern struct flash_device flashdev_28F640W30T; +extern struct flash_device flashdev_28F640W30B; +extern struct flash_device flashdev_PL129J; +extern struct flash_device flashdev_PL129N; +extern struct flash_device flashdev_K5A32xx_T; + +extern int flash_global_config; +extern struct flash_bank_info flash_bank_info[2]; + +static +run_cfi_check(bi, table) + struct flash_bank_info *bi; + struct cfi_check *table; +{ + struct cfi_check *tp; + uint16_t rdword; + + for (tp = table; tp->offset >= 0; tp++) { + if (do_r16(bi->base_addr + (tp->offset << 1), &rdword) < 0) + return(-1); + if (rdword != tp->expect_val) + return(0); + } + return(1); +} + +static +try_device(bi, dev) + struct flash_bank_info *bi; + struct flash_device *dev; +{ + int rc; + + printf("Appears to be %s or compatible, checking CFI\n", dev->name); + if (do_w16(bi->base_addr + 0xAA, 0x98)) { + fprintf(stderr, "unexpected response to w16 - aborting\n"); + return(-1); + } + rc = run_cfi_check(bi, dev->cfi_table); + if (rc < 0) + return(rc); + if (!rc) { + fprintf(stderr, "Error: CFI mismatch, unsafe to continue\n"); + return(-1); + } + printf("Confirmed %s or compatible\n", dev->name); + bi->device = dev; + return(0); +} + +static +spansion_pl129j_or_n(bi) + struct flash_bank_info *bi; +{ + int rc; + + printf("Spansion PL129J or PL129N, 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_PL129N.cfi_table); + if (rc < 0) + return(rc); + if (rc) { + printf("Found PL129N\n"); + bi->device = &flashdev_PL129N; + return(0); + } + rc = run_cfi_check(bi, flashdev_PL129J.cfi_table); + if (rc < 0) + return(rc); + if (rc) { + printf("Found PL129J\n"); + bi->device = &flashdev_PL129J; + return(0); + } + fprintf(stderr, "Error: no matching CFI found\n"); + return(-1); +} + +static +amd_extended_id(bi) + struct flash_bank_info *bi; +{ + uint16_t ext1, ext2; + + printf("AMD-style extended ID device, reading\n"); + if (do_r16(bi->base_addr + 0x1C, &ext1) < 0) + return(-1); + if (do_r16(bi->base_addr + 0x1E, &ext2) < 0) + return(-1); + printf("Extended ID: %04X %04X\n", ext1, ext2); + if (ext1 == 0x2221 && ext2 == 0x2200) + return spansion_pl129j_or_n(bi); + fprintf(stderr, "Error: unknown device ID\n"); + return(-1); +} + +static struct idmap { + uint16_t manuf_id; + uint16_t dev_id; + int (*handler)(); + void *extra_arg; +} device_id_table[] = { + /* AMD/Spansion devices */ + {0x0001, 0x227E, amd_extended_id, 0}, + /* 28F160C3T equivalent found in a C11x phone in the wild */ + {0x0020, 0x88CE, try_device, &flashdev_28F160C3T}, + /* Intel flash chips */ + {0x0089, 0x8854, try_device, &flashdev_28F640W30T}, + {0x0089, 0x8855, try_device, &flashdev_28F640W30B}, + {0x0089, 0x8864, try_device, &flashdev_28F640W30T}, + {0x0089, 0x88C2, try_device, &flashdev_28F160C3T}, + {0x0089, 0x88C4, try_device, &flashdev_28F320C3T}, + {0x0089, 0x88CC, try_device, &flashdev_28F640C3T}, + {0x0089, 0x88CD, try_device, &flashdev_28F640C3B}, + /* Samsung flash */ + {0x00EC, 0x22A0, try_device, &flashdev_K5A32xx_T}, + /* table search terminator */ + {0, 0, 0, 0} +}; + +flash_detect(bank, repeat) +{ + struct flash_bank_info *bi; + uint16_t manuf_id, dev_id; + struct idmap *tp; + int rc; + + bi = flash_bank_info + bank; + if (bi->detect_done && !repeat) + return(0); + printf("Autodetecting flash chip type\n"); + if (do_w16(bi->base_addr + 0xAAA, 0xAA)) { +bad_w16: fprintf(stderr, + "unexpected response to w16 in read ID cmd sequence - aborting\n"); + return(-1); + } + if (do_w16(bi->base_addr + 0x554, 0x55)) + goto bad_w16; + if (do_w16(bi->base_addr + 0xAAA, 0x90)) + goto bad_w16; + if (do_r16(bi->base_addr, &manuf_id) < 0) + return(-1); + if (do_r16(bi->base_addr + 2, &dev_id) < 0) + return(-1); + printf("Basic device ID: %04X %04X\n", manuf_id, dev_id); + for (tp = device_id_table; tp->handler; tp++) + if (tp->manuf_id == manuf_id && tp->dev_id == dev_id) + break; + if (!tp->handler) { + fprintf(stderr, "Error: unknown device ID\n"); + return(-1); + } + rc = tp->handler(bi, tp->extra_arg); + if (rc < 0) + return(rc); + /* got the device, see if it is compatible with global config */ + if (bi->device->required_global_config > flash_global_config) { + fprintf(stderr, +"Error: detected flash device is not compatible with the configured mapping\n"); + return(-1); + } + /* good to go */ + if (bi->device->bank_geom[1] && bank) + bi->geom = bi->device->bank_geom[1]; + else + bi->geom = bi->device->bank_geom[0]; + bi->ops = bi->device->cmdset; + bi->detect_done = 1; + /* return device to read array mode */ + return bi->ops->reset_cmd(bi); +}