FreeCalypso > hg > freecalypso-tools
view loadtools/flutil.c @ 210:071544322478
CHANGES: documented newly added utilities
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 18 May 2017 23:32:31 +0000 |
parents | e7502631a0f9 |
children | 7bf0d909c87e |
line wrap: on
line source
/* * Miscellaneous utility functions for flash support */ #include <sys/types.h> #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include "flash.h" extern struct flash_bank_info flash_bank_info[2]; extern struct flash_cmdset flash_cmdset_amd; extern struct flash_cmdset flash_cmdset_intel; static int cfi_read_byte(bi, off, ret16p) struct flash_bank_info *bi; int off; uint16_t *ret16p; { return do_r16(bi->base_addr + (off << 1), ret16p); } static int cfi_read_twobyte(bi, off, retptr) struct flash_bank_info *bi; int off; uint16_t *retptr; { uint16_t lo, hi; if (cfi_read_byte(bi, off, &lo) < 0) return(-1); lo &= 0xFF; if (cfi_read_byte(bi, off + 1, &hi) < 0) return(-1); hi &= 0xFF; *retptr = (hi << 8) | lo; return(0); } flash_get_cfi(bank) { struct flash_bank_info *bi; struct flash_geom *geom; struct flash_region_desc *reg; int nr; uint16_t rdval, cmdset_id; uint32_t size_check; bi = flash_bank_info + bank; if (bi->geom) return(0); printf("Performing CFI query\n"); if (do_w16(bi->base_addr + 0xAA, 0x98)) { fprintf(stderr, "unexpected response to w16 - aborting\n"); return(-1); } /* if do_r16() returns -1, error msg has already been printed */ if (cfi_read_byte(bi, 0x10, &rdval) < 0) return(-1); if (rdval != 'Q') { noqry: fprintf(stderr, "error: no QRY response from flash\n"); amd_reset_cmd(bi); return(-1); } if (cfi_read_byte(bi, 0x11, &rdval) < 0) return(-1); if (rdval != 'R') goto noqry; if (cfi_read_byte(bi, 0x12, &rdval) < 0) return(-1); if (rdval != 'Y') goto noqry; if (cfi_read_twobyte(bi, 0x13, &cmdset_id) < 0) return(-1); if (!bi->ops) { switch (cmdset_id) { case 2: bi->ops = &flash_cmdset_amd; break; case 3: bi->ops = &flash_cmdset_intel; break; default: fprintf(stderr, "error: command set %04X unsupported\n", cmdset_id); amd_reset_cmd(bi); return(-1); } } geom = malloc(sizeof(struct flash_geom)); if (!geom) { fprintf(stderr, "unable to malloc buffer for flash bank %d CFI geometry structure\n", bank); bi->ops->reset_cmd(bi); return(-1); } /* total device size */ if (cfi_read_byte(bi, 0x27, &rdval) < 0) { free_and_immed_out: free(geom); return(-1); } if (rdval < 20 || rdval > 24) { fprintf(stderr, "error: CFI reports unreasonable device size\n"); free_and_clean_out: free(geom); bi->ops->reset_cmd(bi); return(-1); } geom->total_size = 1 << rdval; if (geom->total_size > bi->bank_desc->align_size) { fprintf(stderr, "error: CFI device size 0x%lx exceeds configured maximum 0x%lx\n", (u_long) geom->total_size, bi->bank_desc->align_size); goto free_and_clean_out; } if (cfi_read_byte(bi, 0x2C, &rdval) < 0) goto free_and_immed_out; if (rdval < 1 || rdval > CFI_MAX_REGIONS) { fprintf(stderr, "error: CFI reports unreasonable # of erase regions\n"); goto free_and_clean_out; } geom->nregions = rdval; geom->total_sectors = 0; size_check = 0; for (nr = 0; nr < geom->nregions; nr++) { reg = geom->regions + nr; if (cfi_read_twobyte(bi, 0x2D + nr*4, &rdval) < 0) goto free_and_immed_out; if (rdval > 255) { fprintf(stderr, "error: CFI reports unreasonable # of sectors in region %d\n", nr); goto free_and_clean_out; } reg->nsectors = rdval + 1; geom->total_sectors += reg->nsectors; if (cfi_read_twobyte(bi, 0x2F + nr*4, &rdval) < 0) goto free_and_immed_out; if (rdval < 0x20 || rdval > 0x400) { fprintf(stderr, "error: CFI reports unreasonable sector size in region %d\n", nr); goto free_and_clean_out; } reg->sector_size = rdval << 8; size_check += reg->sector_size * reg->nsectors; } if (bi->ops->reset_cmd(bi) < 0) { /* error msg already printed */ free(geom); return(-1); } if (size_check != geom->total_size) { fprintf(stderr, "CFI error: added size of erase regions (%lx) != reported devive size (%lx)\n", (u_long) size_check, (u_long) geom->total_size); free(geom); return(-1); } /* all checks passed */ bi->geom = geom; printf( "CFI query successful: total size %lx, %u sectors, command set style %04X\n", (u_long) geom->total_size, geom->total_sectors, cmdset_id); return(1); } get_flash_sector_table(bank) { struct flash_bank_info *bi; struct flash_geom *geom; struct flash_region_desc *reg; struct sector_info *sp; uint32_t offset; int nr, i; bi = flash_bank_info + bank; if (bi->sectors) return(0); i = flash_get_cfi(bank); if (i < 0) return(i); geom = bi->geom; sp = (struct sector_info *) malloc(sizeof(struct sector_info) * (geom->total_sectors + 1)); if (!sp) { fprintf(stderr, "unable to malloc buffer for flash bank %d sector table\n", bank); return(-1); } bi->sectors = sp; /* now fill it */ offset = 0; for (nr = 0; nr < geom->nregions; nr++) { reg = geom->regions + nr; for (i = 0; i < reg->nsectors; i++) { sp->start = offset; sp->size = reg->sector_size; sp++; offset += reg->sector_size; } } /* sanity checks */ if (sp - bi->sectors != geom->total_sectors) { fprintf(stderr, "BUG in get_flash_sector_table(): wrong # of sectors at the end\n"); abort(); } if (offset != geom->total_size) { fprintf(stderr, "BUG in get_flash_sector_table(): wrong offset at the end\n"); abort(); } /* finish */ sp->start = 0; sp->size = 0; return(0); } flashcmd_sectors(argc, argv, bank) char **argv; { struct flash_bank_info *bi; struct sector_info *sp; if (argc > 2) { fprintf(stderr, "error: too many arguments\n"); return(-1); } if (get_flash_sector_table(bank) < 0) return(-1); bi = flash_bank_info + bank; printf("%u sectors in flash bank %d:\n", bi->geom->total_sectors, bank); printf("Offset Size\n"); for (sp = bi->sectors; sp->size; sp++) printf("%08lX %lx\n", (u_long) sp->start, (u_long) sp->size); return(0); } get_flash_sector_range(bi, useroff, userlen, startp, endp) struct flash_bank_info *bi; u_long useroff, userlen; struct sector_info **startp, **endp; { struct sector_info *sp; uint32_t remlen; for (sp = bi->sectors; sp->size; sp++) if (sp->start == useroff) break; if (!sp->size) { fprintf(stderr, "error: specified offset not aligned to a flash sector boundary\n"); return(-1); } *startp = sp; for (remlen = userlen; remlen; ) { if (remlen < sp->size) { fprintf(stderr, "error: specified length not aligned to a flash sector boundary\n"); return(-1); } remlen -= sp->size; sp++; } *endp = sp; return(0); } build_flashw_hex_string(bin, strbuf, nwords, m0src) u_char *bin; char *strbuf; int nwords, m0src; { int i; u_char *dp; char *s; for (dp = bin, s = strbuf, i = 0; i < nwords; dp += 2, s += 4, i++) { if (m0src) sprintf(s, "%02X%02X", dp[0], dp[1]); else sprintf(s, "%02X%02X", dp[1], dp[0]); } *s = '\0'; } flash_id_check(bank, repeat) { struct flash_bank_info *bi; struct flash_bank_desc *bd; struct flash_idcheck *id; int stat, fail; uint16_t rdval; unsigned cnt; bi = flash_bank_info + bank; if (bi->idcheck_done && !repeat) return(0); bd = bi->bank_desc; if (!bd->idcheck_table || !bd->idcheck_num) return(0); printf("Performing flash ID check\n"); stat = do_w16(bi->base_addr + 0xAAA, 0xAA); if (stat) { bad_w16: fprintf(stderr, "unexpected response to w16 in read ID cmd sequence - aborting\n"); return(-1); } stat = do_w16(bi->base_addr + 0x554, 0x55); if (stat) goto bad_w16; stat = do_w16(bi->base_addr + 0xAAA, 0x90); if (stat) goto bad_w16; id = bd->idcheck_table; fail = 0; for (cnt = 0; cnt < bd->idcheck_num; cnt++) { stat = do_r16(bi->base_addr + id->offset, &rdval); if (stat) return(stat); /* error msg already printed */ printf("offset %02X: %04X -- ", (int)id->offset, (int)rdval); if (rdval == id->expect_val) printf("PASS\n"); else { printf("FAIL: expected %04X\n", (int)id->expect_val); fail = 1; break; } id++; } /* reset flash to read mode */ stat = do_w16(bi->base_addr + 0xAAA, 0xF0); if (stat) { fprintf(stderr, "unexpected response to w16 when resetting flash to read mode!\n"); return(-1); } if (fail) return(-1); bi->idcheck_done = 1; return(0); }