📄 cfi_cmdset_0001.c
字号:
put_chip(map, chip, chip->start); spin_unlock(chip->mutex); len -= thislen; ofs = 0; chipnum++; }}static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf){ unsigned long cmd_addr; struct cfi_private *cfi = map->fldrv_priv; int ret; adr += chip->start; /* Ensure cmd read/writes are aligned. */ cmd_addr = adr & ~(map_bankwidth(map)-1); spin_lock(chip->mutex); ret = get_chip(map, chip, cmd_addr, FL_READY); if (ret) { spin_unlock(chip->mutex); return ret; } if (chip->state != FL_POINT && chip->state != FL_READY) { map_write(map, CMD(0xff), cmd_addr); chip->state = FL_READY; } map_copy_from(map, buf, adr, len); put_chip(map, chip, cmd_addr); spin_unlock(chip->mutex); return 0;}static int cfi_intelext_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf){ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; unsigned long ofs; int chipnum; int ret = 0; /* ofs: offset within the first chip that the first read should start */ chipnum = (from >> cfi->chipshift); ofs = from - (chipnum << cfi->chipshift); *retlen = 0; while (len) { unsigned long thislen; if (chipnum >= cfi->numchips) break; if ((len + ofs -1) >> cfi->chipshift) thislen = (1<<cfi->chipshift) - ofs; else thislen = len; ret = do_read_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf); if (ret) break; *retlen += thislen; len -= thislen; buf += thislen; ofs = 0; chipnum++; } return ret;}static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum, int mode){ struct cfi_private *cfi = map->fldrv_priv; map_word status, write_cmd; int ret=0; adr += chip->start; switch (mode) { case FL_WRITING: write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0x40) : CMD(0x41); break; case FL_OTP_WRITE: write_cmd = CMD(0xc0); break; default: return -EINVAL; } spin_lock(chip->mutex); ret = get_chip(map, chip, adr, mode); if (ret) { spin_unlock(chip->mutex); return ret; } XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map)); ENABLE_VPP(map); xip_disable(map, chip, adr); map_write(map, write_cmd, adr); map_write(map, datum, adr); chip->state = mode; ret = INVAL_CACHE_AND_WAIT(map, chip, adr, adr, map_bankwidth(map), chip->word_write_time, chip->word_write_time_max); if (ret) { xip_enable(map, chip, adr); printk(KERN_ERR "%s: word write error (status timeout)\n", map->name); goto out; } /* check for errors */ status = map_read(map, adr); if (map_word_bitsset(map, status, CMD(0x1a))) { unsigned long chipstatus = MERGESTATUS(status); /* reset status */ map_write(map, CMD(0x50), adr); map_write(map, CMD(0x70), adr); xip_enable(map, chip, adr); if (chipstatus & 0x02) { ret = -EROFS; } else if (chipstatus & 0x08) { printk(KERN_ERR "%s: word write error (bad VPP)\n", map->name); ret = -EIO; } else { printk(KERN_ERR "%s: word write error (status 0x%lx)\n", map->name, chipstatus); ret = -EINVAL; } goto out; } xip_enable(map, chip, adr); out: put_chip(map, chip, adr); spin_unlock(chip->mutex); return ret;}static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t len, size_t *retlen, const u_char *buf){ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; int ret = 0; int chipnum; unsigned long ofs; *retlen = 0; if (!len) return 0; chipnum = to >> cfi->chipshift; ofs = to - (chipnum << cfi->chipshift); /* If it's not bus-aligned, do the first byte write */ if (ofs & (map_bankwidth(map)-1)) { unsigned long bus_ofs = ofs & ~(map_bankwidth(map)-1); int gap = ofs - bus_ofs; int n; map_word datum; n = min_t(int, len, map_bankwidth(map)-gap); datum = map_word_ff(map); datum = map_word_load_partial(map, datum, buf, gap, n); ret = do_write_oneword(map, &cfi->chips[chipnum], bus_ofs, datum, FL_WRITING); if (ret) return ret; len -= n; ofs += n; buf += n; (*retlen) += n; if (ofs >> cfi->chipshift) { chipnum ++; ofs = 0; if (chipnum == cfi->numchips) return 0; } } while(len >= map_bankwidth(map)) { map_word datum = map_word_load(map, buf); ret = do_write_oneword(map, &cfi->chips[chipnum], ofs, datum, FL_WRITING); if (ret) return ret; ofs += map_bankwidth(map); buf += map_bankwidth(map); (*retlen) += map_bankwidth(map); len -= map_bankwidth(map); if (ofs >> cfi->chipshift) { chipnum ++; ofs = 0; if (chipnum == cfi->numchips) return 0; } } if (len & (map_bankwidth(map)-1)) { map_word datum; datum = map_word_ff(map); datum = map_word_load_partial(map, datum, buf, 0, len); ret = do_write_oneword(map, &cfi->chips[chipnum], ofs, datum, FL_WRITING); if (ret) return ret; (*retlen) += len; } return 0;}static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, unsigned long adr, const struct kvec **pvec, unsigned long *pvec_seek, int len){ struct cfi_private *cfi = map->fldrv_priv; map_word status, write_cmd, datum; unsigned long cmd_adr; int ret, wbufsize, word_gap, words; const struct kvec *vec; unsigned long vec_seek; unsigned long initial_adr; int initial_len = len; wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; adr += chip->start; initial_adr = adr; cmd_adr = adr & ~(wbufsize-1); /* Let's determine this according to the interleave only once */ write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0xe8) : CMD(0xe9); spin_lock(chip->mutex); ret = get_chip(map, chip, cmd_adr, FL_WRITING); if (ret) { spin_unlock(chip->mutex); return ret; } XIP_INVAL_CACHED_RANGE(map, initial_adr, initial_len); ENABLE_VPP(map); xip_disable(map, chip, cmd_adr); /* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set [...], the device will not accept any more Write to Buffer commands". So we must check here and reset those bits if they're set. Otherwise we're just pissing in the wind */ if (chip->state != FL_STATUS) { map_write(map, CMD(0x70), cmd_adr); chip->state = FL_STATUS; } status = map_read(map, cmd_adr); if (map_word_bitsset(map, status, CMD(0x30))) { xip_enable(map, chip, cmd_adr); printk(KERN_WARNING "SR.4 or SR.5 bits set in buffer write (status %lx). Clearing.\n", status.x[0]); xip_disable(map, chip, cmd_adr); map_write(map, CMD(0x50), cmd_adr); map_write(map, CMD(0x70), cmd_adr); } chip->state = FL_WRITING_TO_BUFFER; map_write(map, write_cmd, cmd_adr); ret = WAIT_TIMEOUT(map, chip, cmd_adr, 0, 0); if (ret) { /* Argh. Not ready for write to buffer */ map_word Xstatus = map_read(map, cmd_adr); map_write(map, CMD(0x70), cmd_adr); chip->state = FL_STATUS; status = map_read(map, cmd_adr); map_write(map, CMD(0x50), cmd_adr); map_write(map, CMD(0x70), cmd_adr); xip_enable(map, chip, cmd_adr); printk(KERN_ERR "%s: Chip not ready for buffer write. Xstatus = %lx, status = %lx\n", map->name, Xstatus.x[0], status.x[0]); goto out; } /* Figure out the number of words to write */ word_gap = (-adr & (map_bankwidth(map)-1)); words = DIV_ROUND_UP(len - word_gap, map_bankwidth(map)); if (!word_gap) { words--; } else { word_gap = map_bankwidth(map) - word_gap; adr -= word_gap; datum = map_word_ff(map); } /* Write length of data to come */ map_write(map, CMD(words), cmd_adr ); /* Write data */ vec = *pvec; vec_seek = *pvec_seek; do { int n = map_bankwidth(map) - word_gap; if (n > vec->iov_len - vec_seek) n = vec->iov_len - vec_seek; if (n > len) n = len; if (!word_gap && len < map_bankwidth(map)) datum = map_word_ff(map); datum = map_word_load_partial(map, datum, vec->iov_base + vec_seek, word_gap, n); len -= n; word_gap += n; if (!len || word_gap == map_bankwidth(map)) { map_write(map, datum, adr); adr += map_bankwidth(map); word_gap = 0; } vec_seek += n; if (vec_seek == vec->iov_len) { vec++; vec_seek = 0; } } while (len); *pvec = vec; *pvec_seek = vec_seek; /* GO GO GO */ map_write(map, CMD(0xd0), cmd_adr); chip->state = FL_WRITING; ret = INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, initial_adr, initial_len, chip->buffer_write_time, chip->buffer_write_time_max); if (ret) { map_write(map, CMD(0x70), cmd_adr); chip->state = FL_STATUS; xip_enable(map, chip, cmd_adr); printk(KERN_ERR "%s: buffer write error (status timeout)\n", map->name); goto out; } /* check for errors */ status = map_read(map, cmd_adr); if (map_word_bitsset(map, status, CMD(0x1a))) { unsigned long chipstatus = MERGESTATUS(status); /* reset status */ map_write(map, CMD(0x50), cmd_adr); map_write(map, CMD(0x70), cmd_adr); xip_enable(map, chip, cmd_adr); if (chipstatus & 0x02) { ret = -EROFS; } else if (chipstatus & 0x08) { printk(KERN_ERR "%s: buffer write error (bad VPP)\n", map->name); ret = -EIO; } else { printk(KERN_ERR "%s: buffer write error (status 0x%lx)\n", map->name, chipstatus); ret = -EINVAL; } goto out; } xip_enable(map, chip, cmd_adr); out: put_chip(map, chip, cmd_adr); spin_unlock(chip->mutex); return ret;}static int cfi_intelext_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen){ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; int ret = 0; int chipnum; unsigned long ofs, vec_seek, i; size_t len = 0; for (i = 0; i < count; i++) len += vecs[i].iov_len; *retlen = 0; if (!len) return 0; chipnum = to >> cfi->chipshift; ofs = to - (chipnum << cfi->chipshift); vec_seek = 0; do { /* We must not cross write block boundaries */ int size = wbufsize - (ofs & (wbufsize-1)); if (size > len) size = len; ret = do_write_buffer(map, &cfi->chips[chipnum], ofs, &vecs, &vec_seek, size); if (ret) return ret; ofs += size; (*retlen) += size; len -= size; if (ofs >> cfi->chipshift) { chipnum ++; ofs = 0; if (chipnum == cfi->numchips) return 0; } /* Be nice and reschedule with the chip in a usable state for other processes. */ cond_resched(); } while (len); return 0;}static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf){ struct kvec vec; vec.iov_base = (void *) buf; vec.iov_len = len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -