FreeCalypso > hg > freecalypso-tools
view loadtools/flashops.c @ 558:a59a7f838fce
CHANGES: better explain that the newly added Am29DL640G flash
support also covers S29PL064J and S71PL064J
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Wed, 29 Jan 2020 08:03:19 +0000 |
parents | 0dd2c87c1b63 |
children | 77a0001d8849 |
line wrap: on
line source
/* * This module implements those flash operations which are dependent * on the AMD vs. Intel command set style. */ #include <sys/types.h> #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <time.h> #include "flash.h" /* common stub functions */ static noop() { return(0); } static amd_invalid() { fprintf(stderr, "This operation is not applicable to AMD-style flash\n"); return(-1); } /* AMD flash functions */ amd_reset_cmd(bi) struct flash_bank_info *bi; { if (do_w16(bi->base_addr + 0xAAA, 0xF0)) { fprintf(stderr, "unexpected response to w16 when resetting flash to read mode!\n"); return(-1); } return(0); } amd_sector_erase(bi, sp) struct flash_bank_info *bi; struct sector_info *sp; { int stat; uint16_t flstat; time_t start_time, curtime; stat = do_w16(bi->base_addr + sp->start + 0xAAA, 0xAA); if (stat) { bad_w16: fprintf(stderr, "unexpected response to w16 in erase cmd sequence - aborting\n"); return(-1); } stat = do_w16(bi->base_addr + sp->start + 0x554, 0x55); if (stat) goto bad_w16; stat = do_w16(bi->base_addr + sp->start + 0xAAA, 0x80); if (stat) goto bad_w16; stat = do_w16(bi->base_addr + sp->start + 0xAAA, 0xAA); if (stat) goto bad_w16; stat = do_w16(bi->base_addr + sp->start + 0x554, 0x55); if (stat) goto bad_w16; stat = do_w16(bi->base_addr + sp->start + 0xAAA, 0x30); if (stat) goto bad_w16; start_time = time(0); for (;;) { stat = do_r16(bi->base_addr + sp->start, &flstat); if (stat) return(stat); /* error msg already printed */ if (flstat == 0xFFFF) return(0); curtime = time(0); if (curtime >= start_time + 20) { fprintf(stderr, "erase timeout, aborting\n"); return(-1); } } } struct flash_cmdset flash_cmdset_amd = { .cmdset_name = "AMD", .reset_cmd = amd_reset_cmd, .status_cmd = amd_invalid, .unlock_sector = amd_invalid, .erase_sector = amd_sector_erase, .prep_for_program = noop, .loadagent_setbase_cmd = "AMFB", .loadagent_program_cmd = "AMFW", .needs_unlock = 0, }; /* Intel flash functions */ intel_reset_cmd(bi) struct flash_bank_info *bi; { if (do_w16(bi->base_addr, 0xFF)) { fprintf(stderr, "unexpected response to w16 when resetting flash to read mode!\n"); return(-1); } return(0); } intel_w30_reset_cmd(bi) struct flash_bank_info *bi; { uint32_t part; for (part = 0; part < bi->geom->total_size; part += 0x80000) { if (do_w16(bi->base_addr + part, 0xFF)) { fprintf(stderr, "unexpected response to w16 when resetting flash to read mode!\n"); return(-1); } } return(0); } intel_status_cmd(bi) struct flash_bank_info *bi; { int stat; uint16_t sr; /* issue Read SR command */ stat = do_w16(bi->base_addr, 0x70); if (stat) { fprintf(stderr, "unexpected response to w16 for Read SR command\n"); return(-1); } stat = do_r16(bi->base_addr, &sr); if (stat) return(stat); /* error msg already printed */ sr &= 0xFF; printf("Status Register: %02X\n", sr); return(0); } intel_w30_status_cmd(bi) struct flash_bank_info *bi; { uint32_t part; int stat; uint16_t sr; for (part = 0; part < bi->geom->total_size; part += 0x80000) { /* issue Read SR command */ stat = do_w16(bi->base_addr + part, 0x70); if (stat) { fprintf(stderr, "unexpected response to w16 for Read SR command\n"); return(-1); } stat = do_r16(bi->base_addr + part, &sr); if (stat) return(stat); /* error msg already printed */ sr &= 0xFF; printf("Status Register for partition %08lX: %02X\n", (u_long) part, sr); } return(0); } intel_sector_unlock(bi, sp) struct flash_bank_info *bi; struct sector_info *sp; { int stat; stat = do_w16(bi->base_addr + sp->start, 0x60); if (stat) { bad_w16: fprintf(stderr, "unexpected response to w16 in block unlock cmd sequence - aborting\n"); return(-1); } stat = do_w16(bi->base_addr + sp->start, 0xD0); if (stat) goto bad_w16; return(0); } intel_sector_erase(bi, sp) struct flash_bank_info *bi; struct sector_info *sp; { int stat; uint16_t flstat; time_t start_time, curtime; stat = intel_sector_unlock(bi, sp); if (stat) return(stat); /* error msg already printed */ /* clear SR */ stat = do_w16(bi->base_addr + sp->start, 0x50); if (stat) { bad_w16: fprintf(stderr, "unexpected response to w16 in erase cmd sequence - aborting\n"); return(-1); } /* send the actual block erase command */ stat = do_w16(bi->base_addr + sp->start, 0x20); if (stat) goto bad_w16; stat = do_w16(bi->base_addr + sp->start, 0xD0); if (stat) goto bad_w16; /* wait for completion */ start_time = time(0); for (;;) { stat = do_r16(bi->base_addr + sp->start, &flstat); if (stat) return(stat); /* error msg already printed */ if (flstat & 0x80) break; curtime = time(0); if (curtime >= start_time + 20) { fprintf(stderr, "erase timeout, aborting\n"); return(-1); } } if (flstat & 0x20) { fprintf(stderr, "block erase failed!\n"); return(-1); } else return(0); } intel_clear_sr(bi) struct flash_bank_info *bi; { printf("Clearing Intel flash SR\n"); if (do_w16(bi->base_addr, 0x50)) { fprintf(stderr, "unexpected response to w16 for Clear SR command\n"); return(-1); } return(0); } intel_w30_clear_sr(bi) struct flash_bank_info *bi; { uint32_t part; printf("Clearing Intel flash SR\n"); for (part = 0; part < bi->geom->total_size; part += 0x80000) { if (do_w16(bi->base_addr + part, 0x50)) { fprintf(stderr, "unexpected response to w16 for Clear SR command\n"); return(-1); } } return(0); } struct flash_cmdset flash_cmdset_intel = { .cmdset_name = "Intel", .reset_cmd = intel_reset_cmd, .status_cmd = intel_status_cmd, .unlock_sector = intel_sector_unlock, .erase_sector = intel_sector_erase, .prep_for_program = intel_clear_sr, .loadagent_setbase_cmd = "INFB", .loadagent_program_cmd = "INFW", .needs_unlock = 1, }; struct flash_cmdset flash_cmdset_intel_w30 = { .cmdset_name = "Intel", .reset_cmd = intel_w30_reset_cmd, .status_cmd = intel_w30_status_cmd, .unlock_sector = intel_sector_unlock, .erase_sector = intel_sector_erase, .prep_for_program = intel_w30_clear_sr, .loadagent_setbase_cmd = "INFB", .loadagent_program_cmd = "INFW", .needs_unlock = 1, };