|
@@ -67,6 +67,8 @@ 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_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|
|
size_t *retlen, const u_char *buf);
|
|
@@ -530,6 +532,7 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
|
|
|
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->flags = MTD_CAP_NORFLASH;
|
|
|
mtd->name = map->name;
|
|
|
mtd->writesize = 1;
|
|
@@ -1257,6 +1260,40 @@ 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)
|
|
|
+{
|
|
|
+ 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 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)
|
|
@@ -1400,7 +1437,17 @@ static int cfi_amdstd_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
|
|
|
buf, do_read_secsi_onechip, 1);
|
|
|
}
|
|
|
|
|
|
-static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum)
|
|
|
+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 __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;
|
|
@@ -1421,7 +1468,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;
|
|
@@ -1430,6 +1477,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
|
|
@@ -1446,12 +1496,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),
|
|
@@ -1460,7 +1511,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);
|
|
|
|
|
@@ -1500,6 +1551,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);
|
|
@@ -1555,7 +1608,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;
|
|
|
|
|
@@ -1579,7 +1632,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;
|
|
|
|
|
@@ -1622,7 +1675,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;
|
|
|
|