|
@@ -58,7 +58,18 @@ static void cfi_amdstd_sync (struct mtd_info *);
|
|
|
static int cfi_amdstd_suspend (struct mtd_info *);
|
|
|
static void cfi_amdstd_resume (struct mtd_info *);
|
|
|
static int cfi_amdstd_reboot(struct notifier_block *, unsigned long, void *);
|
|
|
+static int cfi_amdstd_get_fact_prot_info(struct mtd_info *, size_t,
|
|
|
+ size_t *, struct otp_info *);
|
|
|
+static int cfi_amdstd_get_user_prot_info(struct mtd_info *, size_t,
|
|
|
+ size_t *, struct otp_info *);
|
|
|
static int cfi_amdstd_secsi_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
|
|
|
+static int cfi_amdstd_read_fact_prot_reg(struct mtd_info *, loff_t, size_t,
|
|
|
+ size_t *, u_char *);
|
|
|
+static int cfi_amdstd_read_user_prot_reg(struct mtd_info *, loff_t, size_t,
|
|
|
+ size_t *, u_char *);
|
|
|
+static int cfi_amdstd_write_user_prot_reg(struct mtd_info *, loff_t, size_t,
|
|
|
+ size_t *, u_char *);
|
|
|
+static int cfi_amdstd_lock_user_prot_reg(struct mtd_info *, loff_t, size_t);
|
|
|
|
|
|
static int cfi_amdstd_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|
|
size_t *retlen, const u_char *buf);
|
|
@@ -518,6 +529,12 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
|
|
|
mtd->_sync = cfi_amdstd_sync;
|
|
|
mtd->_suspend = cfi_amdstd_suspend;
|
|
|
mtd->_resume = cfi_amdstd_resume;
|
|
|
+ mtd->_read_user_prot_reg = cfi_amdstd_read_user_prot_reg;
|
|
|
+ mtd->_read_fact_prot_reg = cfi_amdstd_read_fact_prot_reg;
|
|
|
+ mtd->_get_fact_prot_info = cfi_amdstd_get_fact_prot_info;
|
|
|
+ mtd->_get_user_prot_info = cfi_amdstd_get_user_prot_info;
|
|
|
+ mtd->_write_user_prot_reg = cfi_amdstd_write_user_prot_reg;
|
|
|
+ mtd->_lock_user_prot_reg = cfi_amdstd_lock_user_prot_reg;
|
|
|
mtd->flags = MTD_CAP_NORFLASH;
|
|
|
mtd->name = map->name;
|
|
|
mtd->writesize = 1;
|
|
@@ -628,6 +645,23 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
|
|
|
cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
|
|
|
cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp;
|
|
|
cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp;
|
|
|
+ /*
|
|
|
+ * First calculate the timeout max according to timeout field
|
|
|
+ * of struct cfi_ident that probed from chip's CFI aera, if
|
|
|
+ * available. Specify a minimum of 2000us, in case the CFI data
|
|
|
+ * is wrong.
|
|
|
+ */
|
|
|
+ if (cfi->cfiq->BufWriteTimeoutTyp &&
|
|
|
+ cfi->cfiq->BufWriteTimeoutMax)
|
|
|
+ cfi->chips[i].buffer_write_time_max =
|
|
|
+ 1 << (cfi->cfiq->BufWriteTimeoutTyp +
|
|
|
+ cfi->cfiq->BufWriteTimeoutMax);
|
|
|
+ else
|
|
|
+ cfi->chips[i].buffer_write_time_max = 0;
|
|
|
+
|
|
|
+ cfi->chips[i].buffer_write_time_max =
|
|
|
+ max(cfi->chips[i].buffer_write_time_max, 2000);
|
|
|
+
|
|
|
cfi->chips[i].ref_point_counter = 0;
|
|
|
init_waitqueue_head(&(cfi->chips[i].wq));
|
|
|
}
|
|
@@ -1137,12 +1171,48 @@ static int cfi_amdstd_read (struct mtd_info *mtd, loff_t from, size_t len, size_
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip,
|
|
|
+ loff_t adr, size_t len, u_char *buf, size_t grouplen);
|
|
|
+
|
|
|
+static inline void otp_enter(struct map_info *map, struct flchip *chip,
|
|
|
+ loff_t adr, size_t len)
|
|
|
+{
|
|
|
+ struct cfi_private *cfi = map->fldrv_priv;
|
|
|
+
|
|
|
+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,
|
|
|
+ cfi->device_type, NULL);
|
|
|
+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi,
|
|
|
+ cfi->device_type, NULL);
|
|
|
+ cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi,
|
|
|
+ cfi->device_type, NULL);
|
|
|
+
|
|
|
+ INVALIDATE_CACHED_RANGE(map, chip->start + adr, len);
|
|
|
+}
|
|
|
+
|
|
|
+static inline void otp_exit(struct map_info *map, struct flchip *chip,
|
|
|
+ loff_t adr, size_t len)
|
|
|
+{
|
|
|
+ struct cfi_private *cfi = map->fldrv_priv;
|
|
|
+
|
|
|
+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,
|
|
|
+ cfi->device_type, NULL);
|
|
|
+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi,
|
|
|
+ cfi->device_type, NULL);
|
|
|
+ cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi,
|
|
|
+ cfi->device_type, NULL);
|
|
|
+ cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi,
|
|
|
+ cfi->device_type, NULL);
|
|
|
+
|
|
|
+ INVALIDATE_CACHED_RANGE(map, chip->start + adr, len);
|
|
|
+}
|
|
|
|
|
|
-static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
|
|
|
+static inline int do_read_secsi_onechip(struct map_info *map,
|
|
|
+ struct flchip *chip, loff_t adr,
|
|
|
+ size_t len, u_char *buf,
|
|
|
+ size_t grouplen)
|
|
|
{
|
|
|
DECLARE_WAITQUEUE(wait, current);
|
|
|
unsigned long timeo = jiffies + HZ;
|
|
|
- struct cfi_private *cfi = map->fldrv_priv;
|
|
|
|
|
|
retry:
|
|
|
mutex_lock(&chip->mutex);
|
|
@@ -1164,16 +1234,9 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi
|
|
|
|
|
|
chip->state = FL_READY;
|
|
|
|
|
|
- cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
|
|
|
- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
|
|
|
- cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
|
|
|
-
|
|
|
+ otp_enter(map, chip, adr, len);
|
|
|
map_copy_from(map, buf, adr, len);
|
|
|
-
|
|
|
- cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
|
|
|
- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
|
|
|
- cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
|
|
|
- cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
|
|
|
+ otp_exit(map, chip, adr, len);
|
|
|
|
|
|
wake_up(&chip->wq);
|
|
|
mutex_unlock(&chip->mutex);
|
|
@@ -1205,7 +1268,8 @@ static int cfi_amdstd_secsi_read (struct mtd_info *mtd, loff_t from, size_t len,
|
|
|
else
|
|
|
thislen = len;
|
|
|
|
|
|
- ret = do_read_secsi_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
|
|
|
+ ret = do_read_secsi_onechip(map, &cfi->chips[chipnum], ofs,
|
|
|
+ thislen, buf, 0);
|
|
|
if (ret)
|
|
|
break;
|
|
|
|
|
@@ -1219,8 +1283,267 @@ static int cfi_amdstd_secsi_read (struct mtd_info *mtd, loff_t from, size_t len,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
|
|
|
+ unsigned long adr, map_word datum,
|
|
|
+ int mode);
|
|
|
+
|
|
|
+static int do_otp_write(struct map_info *map, struct flchip *chip, loff_t adr,
|
|
|
+ size_t len, u_char *buf, size_t grouplen)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ while (len) {
|
|
|
+ unsigned long bus_ofs = adr & ~(map_bankwidth(map)-1);
|
|
|
+ int gap = adr - bus_ofs;
|
|
|
+ int n = min_t(int, len, map_bankwidth(map) - gap);
|
|
|
+ map_word datum;
|
|
|
+
|
|
|
+ if (n != map_bankwidth(map)) {
|
|
|
+ /* partial write of a word, load old contents */
|
|
|
+ otp_enter(map, chip, bus_ofs, map_bankwidth(map));
|
|
|
+ datum = map_read(map, bus_ofs);
|
|
|
+ otp_exit(map, chip, bus_ofs, map_bankwidth(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;
|
|
|
+
|
|
|
+ adr += n;
|
|
|
+ buf += n;
|
|
|
+ len -= n;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int do_otp_lock(struct map_info *map, struct flchip *chip, loff_t adr,
|
|
|
+ size_t len, u_char *buf, size_t grouplen)
|
|
|
+{
|
|
|
+ struct cfi_private *cfi = map->fldrv_priv;
|
|
|
+ uint8_t lockreg;
|
|
|
+ unsigned long timeo;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ /* make sure area matches group boundaries */
|
|
|
+ if ((adr != 0) || (len != grouplen))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ mutex_lock(&chip->mutex);
|
|
|
+ ret = get_chip(map, chip, chip->start, FL_LOCKING);
|
|
|
+ if (ret) {
|
|
|
+ mutex_unlock(&chip->mutex);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ chip->state = FL_LOCKING;
|
|
|
+
|
|
|
+ /* Enter lock register command */
|
|
|
+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,
|
|
|
+ cfi->device_type, NULL);
|
|
|
+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi,
|
|
|
+ cfi->device_type, NULL);
|
|
|
+ cfi_send_gen_cmd(0x40, cfi->addr_unlock1, chip->start, map, cfi,
|
|
|
+ cfi->device_type, NULL);
|
|
|
+
|
|
|
+ /* read lock register */
|
|
|
+ lockreg = cfi_read_query(map, 0);
|
|
|
+
|
|
|
+ /* set bit 0 to protect extended memory block */
|
|
|
+ lockreg &= ~0x01;
|
|
|
+
|
|
|
+ /* set bit 0 to protect extended memory block */
|
|
|
+ /* write lock register */
|
|
|
+ map_write(map, CMD(0xA0), chip->start);
|
|
|
+ map_write(map, CMD(lockreg), chip->start);
|
|
|
+
|
|
|
+ /* wait for chip to become ready */
|
|
|
+ timeo = jiffies + msecs_to_jiffies(2);
|
|
|
+ for (;;) {
|
|
|
+ if (chip_ready(map, adr))
|
|
|
+ break;
|
|
|
+
|
|
|
+ if (time_after(jiffies, timeo)) {
|
|
|
+ pr_err("Waiting for chip to be ready timed out.\n");
|
|
|
+ ret = -EIO;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ UDELAY(map, chip, 0, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* exit protection commands */
|
|
|
+ map_write(map, CMD(0x90), chip->start);
|
|
|
+ map_write(map, CMD(0x00), chip->start);
|
|
|
+
|
|
|
+ chip->state = FL_READY;
|
|
|
+ put_chip(map, chip, chip->start);
|
|
|
+ mutex_unlock(&chip->mutex);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int cfi_amdstd_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;
|
|
|
+ int ofs_factor = cfi->interleave * cfi->device_type;
|
|
|
+ unsigned long base;
|
|
|
+ int chipnum;
|
|
|
+ struct flchip *chip;
|
|
|
+ uint8_t otp, lockreg;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ size_t user_size, factory_size, otpsize;
|
|
|
+ loff_t user_offset, factory_offset, otpoffset;
|
|
|
+ int user_locked = 0, otplocked;
|
|
|
+
|
|
|
+ *retlen = 0;
|
|
|
+
|
|
|
+ for (chipnum = 0; chipnum < cfi->numchips; chipnum++) {
|
|
|
+ chip = &cfi->chips[chipnum];
|
|
|
+ factory_size = 0;
|
|
|
+ user_size = 0;
|
|
|
|
|
|
-static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum)
|
|
|
+ /* Micron M29EW family */
|
|
|
+ if (is_m29ew(cfi)) {
|
|
|
+ base = chip->start;
|
|
|
+
|
|
|
+ /* check whether secsi area is factory locked
|
|
|
+ or user lockable */
|
|
|
+ mutex_lock(&chip->mutex);
|
|
|
+ ret = get_chip(map, chip, base, FL_CFI_QUERY);
|
|
|
+ if (ret) {
|
|
|
+ mutex_unlock(&chip->mutex);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ cfi_qry_mode_on(base, map, cfi);
|
|
|
+ otp = cfi_read_query(map, base + 0x3 * ofs_factor);
|
|
|
+ cfi_qry_mode_off(base, map, cfi);
|
|
|
+ put_chip(map, chip, base);
|
|
|
+ mutex_unlock(&chip->mutex);
|
|
|
+
|
|
|
+ if (otp & 0x80) {
|
|
|
+ /* factory locked */
|
|
|
+ factory_offset = 0;
|
|
|
+ factory_size = 0x100;
|
|
|
+ } else {
|
|
|
+ /* customer lockable */
|
|
|
+ user_offset = 0;
|
|
|
+ user_size = 0x100;
|
|
|
+
|
|
|
+ mutex_lock(&chip->mutex);
|
|
|
+ ret = get_chip(map, chip, base, FL_LOCKING);
|
|
|
+
|
|
|
+ /* Enter lock register command */
|
|
|
+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1,
|
|
|
+ chip->start, map, cfi,
|
|
|
+ cfi->device_type, NULL);
|
|
|
+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2,
|
|
|
+ chip->start, map, cfi,
|
|
|
+ cfi->device_type, NULL);
|
|
|
+ cfi_send_gen_cmd(0x40, cfi->addr_unlock1,
|
|
|
+ chip->start, map, cfi,
|
|
|
+ cfi->device_type, NULL);
|
|
|
+ /* read lock register */
|
|
|
+ lockreg = cfi_read_query(map, 0);
|
|
|
+ /* exit protection commands */
|
|
|
+ map_write(map, CMD(0x90), chip->start);
|
|
|
+ map_write(map, CMD(0x00), chip->start);
|
|
|
+ put_chip(map, chip, chip->start);
|
|
|
+ mutex_unlock(&chip->mutex);
|
|
|
+
|
|
|
+ user_locked = ((lockreg & 0x01) == 0x00);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ otpsize = user_regs ? user_size : factory_size;
|
|
|
+ if (!otpsize)
|
|
|
+ continue;
|
|
|
+ otpoffset = user_regs ? user_offset : factory_offset;
|
|
|
+ otplocked = user_regs ? user_locked : 1;
|
|
|
+
|
|
|
+ if (!action) {
|
|
|
+ /* return otpinfo */
|
|
|
+ struct otp_info *otpinfo;
|
|
|
+ len -= sizeof(*otpinfo);
|
|
|
+ if (len <= 0)
|
|
|
+ return -ENOSPC;
|
|
|
+ otpinfo = (struct otp_info *)buf;
|
|
|
+ otpinfo->start = from;
|
|
|
+ otpinfo->length = otpsize;
|
|
|
+ otpinfo->locked = otplocked;
|
|
|
+ buf += sizeof(*otpinfo);
|
|
|
+ *retlen += sizeof(*otpinfo);
|
|
|
+ from += otpsize;
|
|
|
+ } else if ((from < otpsize) && (len > 0)) {
|
|
|
+ size_t size;
|
|
|
+ size = (len < otpsize - from) ? len : otpsize - from;
|
|
|
+ ret = action(map, chip, otpoffset + from, size, buf,
|
|
|
+ otpsize);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ buf += size;
|
|
|
+ len -= size;
|
|
|
+ *retlen += size;
|
|
|
+ from = 0;
|
|
|
+ } else {
|
|
|
+ from -= otpsize;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int cfi_amdstd_get_fact_prot_info(struct mtd_info *mtd, size_t len,
|
|
|
+ size_t *retlen, struct otp_info *buf)
|
|
|
+{
|
|
|
+ return cfi_amdstd_otp_walk(mtd, 0, len, retlen, (u_char *)buf,
|
|
|
+ NULL, 0);
|
|
|
+}
|
|
|
+
|
|
|
+static int cfi_amdstd_get_user_prot_info(struct mtd_info *mtd, size_t len,
|
|
|
+ size_t *retlen, struct otp_info *buf)
|
|
|
+{
|
|
|
+ return cfi_amdstd_otp_walk(mtd, 0, len, retlen, (u_char *)buf,
|
|
|
+ NULL, 1);
|
|
|
+}
|
|
|
+
|
|
|
+static int cfi_amdstd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
|
|
|
+ size_t len, size_t *retlen,
|
|
|
+ u_char *buf)
|
|
|
+{
|
|
|
+ return cfi_amdstd_otp_walk(mtd, from, len, retlen,
|
|
|
+ buf, do_read_secsi_onechip, 0);
|
|
|
+}
|
|
|
+
|
|
|
+static int cfi_amdstd_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
|
|
|
+ size_t len, size_t *retlen,
|
|
|
+ u_char *buf)
|
|
|
+{
|
|
|
+ return cfi_amdstd_otp_walk(mtd, from, len, retlen,
|
|
|
+ buf, do_read_secsi_onechip, 1);
|
|
|
+}
|
|
|
+
|
|
|
+static int cfi_amdstd_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
|
|
|
+ size_t len, size_t *retlen,
|
|
|
+ u_char *buf)
|
|
|
+{
|
|
|
+ return cfi_amdstd_otp_walk(mtd, from, len, retlen, buf,
|
|
|
+ do_otp_write, 1);
|
|
|
+}
|
|
|
+
|
|
|
+static int cfi_amdstd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
|
|
|
+ size_t len)
|
|
|
+{
|
|
|
+ size_t retlen;
|
|
|
+ return cfi_amdstd_otp_walk(mtd, from, len, &retlen, NULL,
|
|
|
+ do_otp_lock, 1);
|
|
|
+}
|
|
|
+
|
|
|
+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;
|
|
|
unsigned long timeo = jiffies + HZ;
|
|
@@ -1241,7 +1564,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
|
|
|
adr += chip->start;
|
|
|
|
|
|
mutex_lock(&chip->mutex);
|
|
|
- ret = get_chip(map, chip, adr, FL_WRITING);
|
|
|
+ ret = get_chip(map, chip, adr, mode);
|
|
|
if (ret) {
|
|
|
mutex_unlock(&chip->mutex);
|
|
|
return ret;
|
|
@@ -1250,6 +1573,9 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
|
|
|
pr_debug("MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n",
|
|
|
__func__, adr, datum.x[0] );
|
|
|
|
|
|
+ if (mode == FL_OTP_WRITE)
|
|
|
+ otp_enter(map, chip, adr, map_bankwidth(map));
|
|
|
+
|
|
|
/*
|
|
|
* Check for a NOP for the case when the datum to write is already
|
|
|
* present - it saves time and works around buggy chips that corrupt
|
|
@@ -1266,12 +1592,13 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
|
|
|
XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map));
|
|
|
ENABLE_VPP(map);
|
|
|
xip_disable(map, chip, adr);
|
|
|
+
|
|
|
retry:
|
|
|
cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
|
|
|
cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
|
|
|
cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
|
|
|
map_write(map, datum, adr);
|
|
|
- chip->state = FL_WRITING;
|
|
|
+ chip->state = mode;
|
|
|
|
|
|
INVALIDATE_CACHE_UDELAY(map, chip,
|
|
|
adr, map_bankwidth(map),
|
|
@@ -1280,7 +1607,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
|
|
|
/* See comment above for timeout value. */
|
|
|
timeo = jiffies + uWriteTimeout;
|
|
|
for (;;) {
|
|
|
- if (chip->state != FL_WRITING) {
|
|
|
+ if (chip->state != mode) {
|
|
|
/* Someone's suspended the write. Sleep */
|
|
|
DECLARE_WAITQUEUE(wait, current);
|
|
|
|
|
@@ -1320,6 +1647,8 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
|
|
|
}
|
|
|
xip_enable(map, chip, adr);
|
|
|
op_done:
|
|
|
+ if (mode == FL_OTP_WRITE)
|
|
|
+ otp_exit(map, chip, adr, map_bankwidth(map));
|
|
|
chip->state = FL_READY;
|
|
|
DISABLE_VPP(map);
|
|
|
put_chip(map, chip, adr);
|
|
@@ -1375,7 +1704,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
|
|
|
tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n);
|
|
|
|
|
|
ret = do_write_oneword(map, &cfi->chips[chipnum],
|
|
|
- bus_ofs, tmp_buf);
|
|
|
+ bus_ofs, tmp_buf, FL_WRITING);
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|
|
@@ -1399,7 +1728,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
|
|
|
datum = map_word_load(map, buf);
|
|
|
|
|
|
ret = do_write_oneword(map, &cfi->chips[chipnum],
|
|
|
- ofs, datum);
|
|
|
+ ofs, datum, FL_WRITING);
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|
|
@@ -1442,7 +1771,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
|
|
|
tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len);
|
|
|
|
|
|
ret = do_write_oneword(map, &cfi->chips[chipnum],
|
|
|
- ofs, tmp_buf);
|
|
|
+ ofs, tmp_buf, FL_WRITING);
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|
|
@@ -1462,8 +1791,12 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
|
|
|
{
|
|
|
struct cfi_private *cfi = map->fldrv_priv;
|
|
|
unsigned long timeo = jiffies + HZ;
|
|
|
- /* see comments in do_write_oneword() regarding uWriteTimeo. */
|
|
|
- unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
|
|
|
+ /*
|
|
|
+ * Timeout is calculated according to CFI data, if available.
|
|
|
+ * See more comments in cfi_cmdset_0002().
|
|
|
+ */
|
|
|
+ unsigned long uWriteTimeout =
|
|
|
+ usecs_to_jiffies(chip->buffer_write_time_max);
|
|
|
int ret = -EIO;
|
|
|
unsigned long cmd_adr;
|
|
|
int z, words;
|