/* * The IXP4xx expansion bus only allows 16-bit wide acceses * when attached to a 16-bit wide device (such as the 28F128J3A), * so we can't just memcpy_fromio(). */ static void ixp4xx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) { u8 *dest = (u8 *) to; void __iomem *src = map->virt + from; if (len <= 0) return; if (from & 1) { *dest++ = BYTE1(flash_read16(src-1)); src++; --len; } while (len >= 2) { u16 data = flash_read16(src); *dest++ = BYTE0(data); *dest++ = BYTE1(data); src += 2; len -= 2; } if (len > 0) *dest++ = BYTE0(flash_read16(src)); }
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; }
/* Internal: retrieve intel protection data */ __ramtext static int get_intel_protection(void *base_addr, uint16_t * lockp, uint8_t protp[8]) { int i; /* check args */ if (!lockp) { return -EINVAL; } if (!protp) { return -EINVAL; } /* enter read id mode */ flash_write_cmd(base_addr, CFI_CMD_READ_ID); /* get lock */ *lockp = flash_read16(base_addr, CFI_OFFSET_INTEL_PROTECTION); /* get data */ for (i = 0; i < 8; i++) { protp[i] = flash_read16(base_addr, CFI_OFFSET_INTEL_PROTECTION + 1 + i); } /* leave read id mode */ flash_write_cmd(base_addr, CFI_CMD_RESET); return 0; }
/* Internal: retrieve manufacturer and device id from id space */ __ramtext static int get_id(void *base_addr, uint16_t * manufacturer_id, uint16_t * device_id) { flash_write_cmd(base_addr, CFI_CMD_READ_ID); *manufacturer_id = flash_read16(base_addr, CFI_OFFSET_MANUFACTURER_ID); *device_id = flash_read16(base_addr, CFI_OFFSET_DEVICE_ID); flash_write_cmd(base_addr, CFI_CMD_RESET); return 0; }
static int amd_flash_write_cfibuffer(struct flash_info *info, unsigned long dest, const u8 *cp, int len) { flash_sect_t sector; int cnt; void *src = (void *)cp; void *dst = (void *)dest; cfiword_t cword; sector = find_sector (info, dest); flash_unlock_seq(info); flash_make_cmd (info, AMD_CMD_WRITE_TO_BUFFER, &cword); flash_write_word(info, cword, (void *)dest); if (bankwidth_is_1(info)) { cnt = len; flash_write_cmd(info, sector, 0, (u32)cnt - 1); while (cnt-- > 0) { flash_write8(flash_read8(src), dst); src += 1, dst += 1; } } else if (bankwidth_is_2(info)) { cnt = len >> 1; flash_write_cmd(info, sector, 0, (u32)cnt - 1); while (cnt-- > 0) { flash_write16(flash_read16(src), dst); src += 2, dst += 2; } } else if (bankwidth_is_4(info)) {
__ramtext int flash_block_erase(flash_t * flash, uint32_t block_offset) { const void *base_addr = flash->f_base; if (block_offset >= flash->f_size) { return -EINVAL; } if (flash_protected(block_offset)) { return -EPERM; } printf("Erasing block 0x%08lx...", block_offset); void *block_addr = ((uint8_t *) base_addr) + block_offset; flash_write_cmd(base_addr, CFI_CMD_CLEAR_STATUS); flash_write_cmd(block_addr, CFI_CMD_BLOCK_ERASE); flash_write_cmd(block_addr, CFI_CMD_ERASE_CONFIRM); flash_write_cmd(base_addr, CFI_CMD_READ_STATUS); uint16_t status; do { status = flash_read16(base_addr, 0); } while (!(status & CFI_STATUS_READY)); int res = 0; if (status & CFI_STATUS_ERASE_ERROR) { puts("error: "); if (status & CFI_STATUS_VPP_LOW) { puts("vpp insufficient\n"); res = -EFAULT; } else if (status & CFI_STATUS_LOCKED_ERROR) { puts("block is lock-protected\n"); res = -EPERM; } else { puts("unknown fault\n"); res = -EFAULT; } } else { puts("done\n"); } flash_write_cmd(base_addr, CFI_CMD_RESET); return res; }
/* Internal: retrieve cfi query response data */ __ramtext static int get_query(void *base_addr, struct cfi_query *query) { int res = 0; unsigned int i; flash_write_cmd(base_addr, CFI_CMD_CFI); for (i = 0; i < sizeof(struct cfi_query); i++) { uint16_t byte = flash_read16(base_addr, CFI_OFFSET_CFI_RESP + i); *(((volatile unsigned char *)query) + i) = byte; } if (query->qry[0] != 'Q' || query->qry[1] != 'R' || query->qry[2] != 'Y') { res = -ENOENT; } flash_write_cmd(base_addr, CFI_CMD_RESET); return res; }
__ramtext int flash_program(flash_t * flash, uint32_t dst, void *src, uint32_t nbytes) { const void *base_addr = flash->f_base; int res = 0; uint32_t i; /* check destination bounds */ if (dst >= flash->f_size) { return -EINVAL; } if (dst + nbytes > flash->f_size) { return -EINVAL; } /* check alignments */ if (((uint32_t) src) % 2) { return -EINVAL; } if (dst % 2) { return -EINVAL; } if (nbytes % 2) { return -EINVAL; } /* check permissions */ if (flash_protected(dst)) { return -EPERM; } /* say something */ printf("Programming %lu bytes to 0x%08lx from 0x%p...", nbytes, dst, src); /* clear status register */ flash_write_cmd(base_addr, CFI_CMD_CLEAR_STATUS); /* write the words */ puts("writing..."); for (i = 0; i < nbytes; i += 2) { uint16_t *src_addr = (uint16_t *) (src + i); uint16_t *dst_addr = (uint16_t *) (base_addr + dst + i); uint16_t data = *src_addr; flash_write_cmd(dst_addr, CFI_CMD_WRITE); flash_write_cmd(dst_addr, data); flash_write_cmd(base_addr, CFI_CMD_READ_STATUS); uint16_t status; do { status = flash_read16(base_addr, 0); } while (!(status & CFI_STATUS_READY)); if (status & CFI_STATUS_PROGRAM_ERROR) { puts("error: "); if (status & CFI_STATUS_VPP_LOW) { puts("vpp insufficient"); res = -EFAULT; } else if (status & CFI_STATUS_LOCKED_ERROR) { puts("block is lock-protected"); res = -EPERM; } else { puts("unknown fault"); res = -EFAULT; } goto err_reset; } } flash_write_cmd(base_addr, CFI_CMD_RESET); /* verify the result */ puts("verifying..."); for (i = 0; i < nbytes; i += 2) { uint16_t *src_addr = (uint16_t *) (src + i); uint16_t *dst_addr = (uint16_t *) (base_addr + dst + i); if (*src_addr != *dst_addr) { puts("error: verification failed"); res = -EFAULT; goto err; } } puts("done\n"); return res; err_reset: flash_write_cmd(base_addr, CFI_CMD_RESET); err: printf(" at offset 0x%lx\n", i); return res; }
static map_word ixp4xx_read16(struct map_info *map, unsigned long ofs) { map_word val; val.x[0] = flash_read16(map->virt + ofs); return val; }