📄 cfi_cmdset_0001.c
字号:
return cfi_intelext_writev(mtd, &vec, 1, to, retlen);}static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk){ struct cfi_private *cfi = map->fldrv_priv; map_word status; int retries = 3; int ret; adr += chip->start; retry: spin_lock(chip->mutex); ret = get_chip(map, chip, adr, FL_ERASING); if (ret) { spin_unlock(chip->mutex); return ret; } XIP_INVAL_CACHED_RANGE(map, adr, len); ENABLE_VPP(map); xip_disable(map, chip, adr); /* Clear the status register first */ map_write(map, CMD(0x50), adr); /* Now erase */ map_write(map, CMD(0x20), adr); map_write(map, CMD(0xD0), adr); chip->state = FL_ERASING; chip->erase_suspended = 0; ret = INVAL_CACHE_AND_WAIT(map, chip, adr, adr, len, chip->erase_time, chip->erase_time_max); if (ret) { map_write(map, CMD(0x70), adr); chip->state = FL_STATUS; xip_enable(map, chip, adr); printk(KERN_ERR "%s: block erase error: (status timeout)\n", map->name); goto out; } /* We've broken this before. It doesn't hurt to be safe */ map_write(map, CMD(0x70), adr); chip->state = FL_STATUS; status = map_read(map, adr); /* check for errors */ if (map_word_bitsset(map, status, CMD(0x3a))) { unsigned long chipstatus = MERGESTATUS(status); /* Reset the error bits */ map_write(map, CMD(0x50), adr); map_write(map, CMD(0x70), adr); xip_enable(map, chip, adr); if ((chipstatus & 0x30) == 0x30) { printk(KERN_ERR "%s: block erase error: (bad command sequence, status 0x%lx)\n", map->name, chipstatus); ret = -EINVAL; } else if (chipstatus & 0x02) { /* Protection bit set */ ret = -EROFS; } else if (chipstatus & 0x8) { /* Voltage */ printk(KERN_ERR "%s: block erase error: (bad VPP)\n", map->name); ret = -EIO; } else if (chipstatus & 0x20 && retries--) { printk(KERN_DEBUG "block erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus); put_chip(map, chip, adr); spin_unlock(chip->mutex); goto retry; } else { printk(KERN_ERR "%s: block erase failed at 0x%08lx (status 0x%lx)\n", map->name, adr, chipstatus); ret = -EIO; } goto out; } xip_enable(map, chip, adr); out: put_chip(map, chip, adr); spin_unlock(chip->mutex); return ret;}static int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr){ unsigned long ofs, len; int ret; ofs = instr->addr; len = instr->len; ret = cfi_varsize_frob(mtd, do_erase_oneblock, ofs, len, NULL); if (ret) return ret; instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0;}static void cfi_intelext_sync (struct mtd_info *mtd){ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; int i; struct flchip *chip; int ret = 0; for (i=0; !ret && i<cfi->numchips; i++) { chip = &cfi->chips[i]; spin_lock(chip->mutex); ret = get_chip(map, chip, chip->start, FL_SYNCING); if (!ret) { chip->oldstate = chip->state; chip->state = FL_SYNCING; /* No need to wake_up() on this state change - * as the whole point is that nobody can do anything * with the chip now anyway. */ } spin_unlock(chip->mutex); } /* Unlock the chips again */ for (i--; i >=0; i--) { chip = &cfi->chips[i]; spin_lock(chip->mutex); if (chip->state == FL_SYNCING) { chip->state = chip->oldstate; chip->oldstate = FL_READY; wake_up(&chip->wq); } spin_unlock(chip->mutex); }}static int __xipram do_getlockstatus_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk){ struct cfi_private *cfi = map->fldrv_priv; int status, ofs_factor = cfi->interleave * cfi->device_type; adr += chip->start; xip_disable(map, chip, adr+(2*ofs_factor)); map_write(map, CMD(0x90), adr+(2*ofs_factor)); chip->state = FL_JEDEC_QUERY; status = cfi_read_query(map, adr+(2*ofs_factor)); xip_enable(map, chip, 0); return status;}#ifdef DEBUG_LOCK_BITSstatic int __xipram do_printlockstatus_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk){ printk(KERN_DEBUG "block status register for 0x%08lx is %x\n", adr, do_getlockstatus_oneblock(map, chip, adr, len, thunk)); return 0;}#endif#define DO_XXLOCK_ONEBLOCK_LOCK ((void *) 1)#define DO_XXLOCK_ONEBLOCK_UNLOCK ((void *) 2)static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk){ struct cfi_private *cfi = map->fldrv_priv; struct cfi_pri_intelext *extp = cfi->cmdset_priv; int udelay; int ret; adr += chip->start; spin_lock(chip->mutex); ret = get_chip(map, chip, adr, FL_LOCKING); if (ret) { spin_unlock(chip->mutex); return ret; } ENABLE_VPP(map); xip_disable(map, chip, adr); map_write(map, CMD(0x60), adr); if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) { map_write(map, CMD(0x01), adr); chip->state = FL_LOCKING; } else if (thunk == DO_XXLOCK_ONEBLOCK_UNLOCK) { map_write(map, CMD(0xD0), adr); chip->state = FL_UNLOCKING; } else BUG(); /* * If Instant Individual Block Locking supported then no need * to delay. */ udelay = (!extp || !(extp->FeatureSupport & (1 << 5))) ? 1000000/HZ : 0; ret = WAIT_TIMEOUT(map, chip, adr, udelay, udelay * 100); if (ret) { map_write(map, CMD(0x70), adr); chip->state = FL_STATUS; xip_enable(map, chip, adr); printk(KERN_ERR "%s: block unlock error: (status timeout)\n", map->name); goto out; } xip_enable(map, chip, adr);out: put_chip(map, chip, adr); spin_unlock(chip->mutex); return ret;}static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len){ int ret;#ifdef DEBUG_LOCK_BITS printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n", __func__, ofs, len); cfi_varsize_frob(mtd, do_printlockstatus_oneblock, ofs, len, NULL);#endif ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, ofs, len, DO_XXLOCK_ONEBLOCK_LOCK);#ifdef DEBUG_LOCK_BITS printk(KERN_DEBUG "%s: lock status after, ret=%d\n", __func__, ret); cfi_varsize_frob(mtd, do_printlockstatus_oneblock, ofs, len, NULL);#endif return ret;}static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len){ int ret;#ifdef DEBUG_LOCK_BITS printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n", __func__, ofs, len); cfi_varsize_frob(mtd, do_printlockstatus_oneblock, ofs, len, NULL);#endif ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, ofs, len, DO_XXLOCK_ONEBLOCK_UNLOCK);#ifdef DEBUG_LOCK_BITS printk(KERN_DEBUG "%s: lock status after, ret=%d\n", __func__, ret); cfi_varsize_frob(mtd, do_printlockstatus_oneblock, ofs, len, NULL);#endif return ret;}#ifdef CONFIG_MTD_OTPtypedef int (*otp_op_t)(struct map_info *map, struct flchip *chip, u_long data_offset, u_char *buf, u_int size, u_long prot_offset, u_int groupno, u_int groupsize);static int __xipramdo_otp_read(struct map_info *map, struct flchip *chip, u_long offset, u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz){ struct cfi_private *cfi = map->fldrv_priv; int ret; spin_lock(chip->mutex); ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY); if (ret) { spin_unlock(chip->mutex); return ret; } /* let's ensure we're not reading back cached data from array mode */ INVALIDATE_CACHED_RANGE(map, chip->start + offset, size); xip_disable(map, chip, chip->start); if (chip->state != FL_JEDEC_QUERY) { map_write(map, CMD(0x90), chip->start); chip->state = FL_JEDEC_QUERY; } map_copy_from(map, buf, chip->start + offset, size); xip_enable(map, chip, chip->start); /* then ensure we don't keep OTP data in the cache */ INVALIDATE_CACHED_RANGE(map, chip->start + offset, size); put_chip(map, chip, chip->start); spin_unlock(chip->mutex); return 0;}static intdo_otp_write(struct map_info *map, struct flchip *chip, u_long offset, u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz){ int ret; while (size) { unsigned long bus_ofs = offset & ~(map_bankwidth(map)-1); int gap = offset - bus_ofs; int n = min_t(int, size, map_bankwidth(map)-gap); map_word datum = map_word_ff(map); datum = map_word_load_partial(map, datum, buf, gap, n); ret = do_write_oneword(map, chip, bus_ofs, datum, FL_OTP_WRITE); if (ret) return ret; offset += n; buf += n; size -= n; } return 0;}static intdo_otp_lock(struct map_info *map, struct flchip *chip, u_long offset, u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz){ struct cfi_private *cfi = map->fldrv_priv; map_word datum; /* make sure area matches group boundaries */ if (size != grpsz) return -EXDEV; datum = map_word_ff(map); datum = map_word_clr(map, datum, CMD(1 << grpno)); return do_write_oneword(map, chip, prot, datum, FL_OTP_WRITE);}static int cfi_intelext_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, otp_op_t action, int user_regs){ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; struct cfi_pri_intelext *extp = cfi->cmdset_priv; struct flchip *chip; struct cfi_intelext_otpinfo *otp; u_long devsize, reg_prot_offset, data_offset; u_int chip_num, chip_step, field, reg_fact_size, reg_user_size; u_int groups, groupno, groupsize, reg_fact_groups, reg_user_groups; int ret; *retlen = 0; /* Check that we actually have some OTP registers */ if (!extp || !(extp->FeatureSupport & 64) || !extp->NumProtectionFields) return -ENODATA; /* we need real chips here not virtual ones */ devsize = (1 << cfi->cfiq->DevSize) * cfi->interleave; chip_step = devsize >> cfi->chipshift; chip_num = 0; /* Some chips have OTP located in the _top_ partition only. For example: Intel 28F256L18T (T means top-parameter device) */ if (cfi->mfr == MANUFACTURER_INTEL) { switch (cfi->id) { case 0x880b: case 0x880c: case 0x880d: chip_num = chip_step - 1; } } for ( ; chip_num < cfi->numchips; chip_num += chip_step) { chip = &cfi->chips[chip_num]; otp = (struct cfi_intelext_otpinfo *)&extp->extra[0]; /* first OTP region */ field = 0; reg_prot_offset = extp->ProtRegAddr; reg_fact_groups = 1; reg_fact_size = 1 << extp->FactProtRegSize; reg_user_groups = 1; reg_user_size = 1 << extp->UserProtRegSize; while (len > 0) { /* flash geometry fixup */ data_offset = reg_prot_offset + 1; data_offset *= cfi->interleave * cfi->device_type; reg_prot_offset *= cfi->interleave * cfi->device_type; reg_fact_size *= cfi->interleave; reg_user_size *= cfi->interleave; if (user_regs) { groups = reg_user_groups; groupsize = reg_user_size; /* skip over factory reg area */ groupno = reg_fact_groups; data_offset += reg_fact_groups * reg_fact_size; } else { groups = reg_fact_groups; groupsize = reg_fact_size; groupno = 0; } while (len > 0 && groups > 0) { if (!action) { /* * Special case: if action is NULL * we fill buf with otp_info records. */ struct otp_info *otpinfo; map_word lockword; len -= sizeof(struct otp_info); if (len <= 0) return -ENOSPC; ret = do_otp_read(map, chip, reg_prot_offset, (u_char *)&lockword, map_bankwidth(map), 0, 0, 0); if (ret) return ret; otpinfo = (struct otp_info *)buf; otpinfo->start = from; otpinfo->length = groupsize; otpinfo->locked = !map_word_bitsset(map, lockword, CMD(1 << groupno)); from += groupsize; buf += sizeof(*otpinfo); *retlen += sizeof(*otpinfo
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -