static int flash_toggle(struct flash_info *info, flash_sect_t sect, unsigned int offset, u8 cmd) { void *addr; cfiword_t cword; int retval; addr = flash_make_addr (info, sect, offset); flash_make_cmd (info, cmd, &cword); if (bankwidth_is_1(info)) { retval = flash_read8(addr) != flash_read8(addr); } else if (bankwidth_is_2(info)) { retval = flash_read16(addr) != flash_read16(addr); } else if (bankwidth_is_4(info)) { retval = flash_read32(addr) != flash_read32(addr); } else if (bankwidth_is_8(info)) { retval = ( (flash_read32( addr ) != flash_read32( addr )) || (flash_read32(addr+4) != flash_read32(addr+4)) ); } else { retval = 0; } return retval; }
/*----------------------------------------------------------------------- * read a short word by swapping for ppc format. */ ushort flash_read_ushort(flash_info_t * info, int sect, uchar offset) { uchar *addr; addr = flash_make_addr(info, sect, offset); return ((addr[(2 * info->portwidth) - 1] << 8) | addr[info->portwidth - 1]); }
static uint8_t flash_read_uint8_t(flash_info_t * info, uint32_t offset) { uint8_t *cp; cp = flash_make_addr(info, 0, offset); #if defined(__LITTLE_ENDIAN) return (cp[0]); #else return (cp[info->portwidth - 1]); #endif }
/*----------------------------------------------------------------------- * read a long word by picking the least significant byte of each maiximum * port size word. Swap for ppc format. */ ulong flash_read_long(flash_info_t * info, int sect, uchar offset) { uchar *addr; addr = flash_make_addr(info, sect, offset); return ((addr[(2 * info->portwidth) - 1] << 24) | (addr[(info->portwidth) - 1] << 16) | (addr[(4 * info->portwidth) - 1] << 8) | addr[(3 * info->portwidth) - 1]); }
/*----------------------------------------------------------------------- */ static int flash_write_cfiword(flash_info_t * info, ulong dest, cfiword_t cword) { cfiptr_t ctladdr; cfiptr_t cptr; int flag; ctladdr.cp = flash_make_addr(info, 0, 0); cptr.cp = (uchar *) dest; /* Check if Flash is (sufficiently) erased */ switch (info->portwidth) { case FLASH_CFI_8BIT: flag = ((cptr.cp[0] & cword.c) == cword.c); break; case FLASH_CFI_16BIT: flag = ((cptr.wp[0] & cword.w) == cword.w); break; case FLASH_CFI_32BIT: flag = ((cptr.lp[0] & cword.l) == cword.l); break; default: return 2; } if (!flag) return 2; /* Disable interrupts which might cause a timeout here */ flag = disable_interrupts(); flash_write_cmd(info, 0, 0, FLASH_CMD_CLEAR_STATUS); flash_write_cmd(info, 0, 0, FLASH_CMD_WRITE); switch (info->portwidth) { case FLASH_CFI_8BIT: cptr.cp[0] = cword.c; break; case FLASH_CFI_16BIT: cptr.wp[0] = cword.w; break; case FLASH_CFI_32BIT: cptr.lp[0] = cword.l; break; } /* re-enable interrupts if necessary */ if (flag) enable_interrupts(); return flash_full_status_check(info, 0, info->write_tout, "write"); }
static int32_t flash_detect_cfi(flash_info_t * info) { cfiptr_t cptr1, cptr2, cptr3; for (info->portwidth = FLASH_CFI_8BIT; info->portwidth <= FLASH_CFI_16BIT; info->portwidth <<= 1) { for (info->chipwidth = FLASH_CFI_BY8; info->chipwidth <= info->portwidth; info->chipwidth <<= 1) { cptr1.cp = flash_make_addr(info, 0, FLASH_OFFSET_CFI_RESP); cptr2.cp = flash_make_addr(info, 0, FLASH_OFFSET_CFI_RESP + 1); cptr3.cp = flash_make_addr(info, 0, FLASH_OFFSET_CFI_RESP + 2); flash_write_cmd(info, 0, FLASH_OFFSET_CFI, FLASH_CMD_CFI); if (flash_isequal(info, cptr1, 'Q') && flash_isequal(info, cptr2, 'R') && flash_isequal(info, cptr3, 'Y')) { info->interface = flash_read_uint16_t(info, 0, FLASH_OFFSET_INTERFACE); return 1; } } } printf("Error: CFI flah not found\n"); return 0; }
static uint16_t flash_read_uint16_t(flash_info_t * info, int32_t sect, uint32_t offset) { uint8_t *addr; uint16_t retval; addr = flash_make_addr(info, sect, offset); #if defined(__LITTLE_ENDIAN) retval = ((addr[(info->portwidth)] << 8) | addr[0]); #else retval = (uint16_t) ((addr[(2 * info->portwidth) - 1] << 8) | addr[info->portwidth - 1]); #endif return retval; }
static void flash_write_cmd(flash_info_t * info, int32_t sect, uint32_t offset, uint8_t cmd) { cfiptr_t addr; cfiword_t cword; addr.cp = flash_make_addr(info, sect, offset); flash_make_cmd(info, cmd, &cword); switch (info->portwidth) { case FLASH_CFI_8BIT: *addr.cp = cword.c; break; case FLASH_CFI_16BIT: *addr.wp = cword.w; break; } }
static uint32_t flash_read_long(flash_info_t * info, int32_t sect, uint32_t offset) { uint8_t *addr; uint32_t retval; addr = flash_make_addr(info, sect, offset); #if defined(__LITTLE_ENDIAN) retval = (addr[0] << 16) | (addr[(info->portwidth)] << 24) | (addr[(2 * info->portwidth)]) | (addr[(3 * info->portwidth)] << 8); #else retval = (uint32_t) (addr[(2 * info->portwidth) - 1] << 24) | (addr[(info->portwidth) - 1] << 16) | (addr[(4 * info->portwidth) - 1] << 8) | addr[(3 * info->portwidth) - 1]; #endif return retval; }
static int flash_toggle (struct flash_info *info, flash_sect_t sect, uint offset, uchar cmd) { cfiptr_t cptr; cfiword_t cword; int retval; cptr.cp = flash_make_addr (info, sect, offset); flash_make_cmd (info, cmd, &cword); if (bankwidth_is_1(info)) { retval = ((cptr.cp[0] & cword.c) != (cptr.cp[0] & cword.c)); } else if (bankwidth_is_2(info)) { retval = ((cptr.wp[0] & cword.w) != (cptr.wp[0] & cword.w)); } else if (bankwidth_is_4(info)) { retval = ((cptr.lp[0] & cword.l) != (cptr.lp[0] & cword.l)); } else if (bankwidth_is_8(info)) { retval = ((cptr.llp[0] & cword.ll) != (cptr.llp[0] & cword.ll)); } else retval = 0; return retval; }
/*----------------------------------------------------------------------- */ static int flash_isset(flash_info_t * info, int sect, uchar offset, uchar cmd) { cfiptr_t cptr; cfiword_t cword; int retval; cptr.cp = flash_make_addr(info, sect, offset); flash_make_cmd(info, cmd, &cword); switch (info->portwidth) { case FLASH_CFI_8BIT: retval = ((cptr.cp[0] & cword.c) == cword.c); break; case FLASH_CFI_16BIT: retval = ((cptr.wp[0] & cword.w) == cword.w); break; case FLASH_CFI_32BIT: retval = ((cptr.lp[0] & cword.l) == cword.l); break; default: retval = 0; break; } return retval; }
static uint32_t flash_get_size(uint32_t base, int32_t banknum) { flash_info_t *info = &flash_info[banknum]; int32_t i, j; int32_t sect_cnt; uint32_t sector; uint32_t tmp; int32_t size_ratio; uint8_t num_erase_regions; int32_t erase_region_size; int32_t erase_region_count; cfiptr_t cptr; info->start[0] = base; if (flash_detect_cfi(info)) { info->vendor = flash_read_uint16_t(info, 0, FLASH_OFFSET_PRIMARY_VENDOR); switch (info->vendor) { case CFI_CMDSET_INTEL_STANDARD: case CFI_CMDSET_INTEL_EXTENDED: default: info->cmd_reset = FLASH_CMD_RESET; break; case CFI_CMDSET_AMD_STANDARD: case CFI_CMDSET_AMD_EXTENDED: info->cmd_reset = AMD_CMD_RESET; break; } size_ratio = info->portwidth / info->chipwidth; if ((info->interface == FLASH_CFI_X8X16) && (info->chipwidth == FLASH_CFI_BY8)) { size_ratio >>= 1; } num_erase_regions = flash_read_uint8_t(info, FLASH_OFFSET_NUM_ERASE_REGIONS); sect_cnt = 0; sector = base; for (i = 0; i < num_erase_regions; i++) { if (i > NUM_ERASE_REGIONS) { printf("%d erase regions found, only %d used\n", num_erase_regions, NUM_ERASE_REGIONS); break; } tmp = flash_read_long(info, 0, FLASH_OFFSET_ERASE_REGIONS + i * 4); erase_region_size = (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128; tmp >>= 16; erase_region_count = (tmp & 0xffff) + 1; for (j = 0; j < erase_region_count; j++) { info->start[sect_cnt] = sector; sector += (erase_region_size * size_ratio); switch (info->vendor) { case CFI_CMDSET_INTEL_EXTENDED: case CFI_CMDSET_INTEL_STANDARD: cptr.cp = flash_make_addr(info, sect_cnt, FLASH_OFFSET_PROTECT); info->protect[sect_cnt] = flash_isset(info, cptr, FLASH_STATUS_PROTECT); break; default: info->protect[sect_cnt] = 0; /* default: not protected */ } sect_cnt++; } } info->sector_count = sect_cnt; /* multiply the size by the number of chips */ info->size = (1 << flash_read_uint8_t(info, FLASH_OFFSET_SIZE)) * size_ratio; info->buffer_size = (1 << flash_read_uint16_t(info, 0, FLASH_OFFSET_BUFFER_SIZE)); tmp = 1 << flash_read_uint8_t(info, FLASH_OFFSET_ETOUT); info->erase_blk_tout = (tmp * (1 << flash_read_uint8_t(info, FLASH_OFFSET_EMAX_TOUT))); info->erase_chip_tout = info->erase_blk_tout * info->sector_count; tmp = 1 << flash_read_uint8_t(info, FLASH_OFFSET_WBTOUT); info->buffer_write_tout = (tmp * (1 << flash_read_uint8_t(info, FLASH_OFFSET_WBMAX_TOUT))); tmp = 1 << flash_read_uint8_t(info, FLASH_OFFSET_WTOUT); info->write_tout = (tmp * (1 << flash_read_uint8_t(info, FLASH_OFFSET_WMAX_TOUT))) / 1000; info->flash_id = FLASH_MAN_CFI; if ((info->interface == FLASH_CFI_X8X16) && (info->chipwidth == FLASH_CFI_BY8)) { info->portwidth >>= 1; }
/*----------------------------------------------------------------------- * read a character at a port width address */ inline uchar flash_read_uchar(flash_info_t * info, uchar offset) { uchar *cp; cp = flash_make_addr(info, 0, offset); return (cp[info->portwidth - 1]); }