Commit af744750 authored by Christian Riesch's avatar Christian Riesch Committed by Brian Norris

mtd: cfi_cmdset_0002: Add support for writing OTP memory

This patch adds support for writing the one time programmable (OTP)
memory of Micron M29EW devices.
Signed-off-by: default avatarChristian Riesch <christian.riesch@omicron.at>
Signed-off-by: default avatarBrian Norris <computersforpeace@gmail.com>
parent feb86779
...@@ -67,6 +67,8 @@ static int cfi_amdstd_read_fact_prot_reg(struct mtd_info *, loff_t, size_t, ...@@ -67,6 +67,8 @@ static int cfi_amdstd_read_fact_prot_reg(struct mtd_info *, loff_t, size_t,
size_t *, u_char *); size_t *, u_char *);
static int cfi_amdstd_read_user_prot_reg(struct mtd_info *, loff_t, size_t, static int cfi_amdstd_read_user_prot_reg(struct mtd_info *, loff_t, size_t,
size_t *, u_char *); 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, static int cfi_amdstd_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf); size_t *retlen, const u_char *buf);
...@@ -530,6 +532,7 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) ...@@ -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->_read_fact_prot_reg = cfi_amdstd_read_fact_prot_reg;
mtd->_get_fact_prot_info = cfi_amdstd_get_fact_prot_info; mtd->_get_fact_prot_info = cfi_amdstd_get_fact_prot_info;
mtd->_get_user_prot_info = cfi_amdstd_get_user_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->flags = MTD_CAP_NORFLASH;
mtd->name = map->name; mtd->name = map->name;
mtd->writesize = 1; mtd->writesize = 1;
...@@ -1257,6 +1260,40 @@ static int cfi_amdstd_secsi_read (struct mtd_info *mtd, loff_t from, size_t len, ...@@ -1257,6 +1260,40 @@ static int cfi_amdstd_secsi_read (struct mtd_info *mtd, loff_t from, size_t len,
return ret; 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, static int cfi_amdstd_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf, size_t *retlen, u_char *buf,
otp_op_t action, int user_regs) 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, ...@@ -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); 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; struct cfi_private *cfi = map->fldrv_priv;
unsigned long timeo = jiffies + HZ; unsigned long timeo = jiffies + HZ;
...@@ -1421,7 +1468,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, ...@@ -1421,7 +1468,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
adr += chip->start; adr += chip->start;
mutex_lock(&chip->mutex); mutex_lock(&chip->mutex);
ret = get_chip(map, chip, adr, FL_WRITING); ret = get_chip(map, chip, adr, mode);
if (ret) { if (ret) {
mutex_unlock(&chip->mutex); mutex_unlock(&chip->mutex);
return ret; return ret;
...@@ -1430,6 +1477,9 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, ...@@ -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", pr_debug("MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n",
__func__, adr, datum.x[0] ); __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 * 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 * 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, ...@@ -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)); XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map));
ENABLE_VPP(map); ENABLE_VPP(map);
xip_disable(map, chip, adr); xip_disable(map, chip, adr);
retry: retry:
cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); 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(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); cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
map_write(map, datum, adr); map_write(map, datum, adr);
chip->state = FL_WRITING; chip->state = mode;
INVALIDATE_CACHE_UDELAY(map, chip, INVALIDATE_CACHE_UDELAY(map, chip,
adr, map_bankwidth(map), adr, map_bankwidth(map),
...@@ -1460,7 +1511,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, ...@@ -1460,7 +1511,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
/* See comment above for timeout value. */ /* See comment above for timeout value. */
timeo = jiffies + uWriteTimeout; timeo = jiffies + uWriteTimeout;
for (;;) { for (;;) {
if (chip->state != FL_WRITING) { if (chip->state != mode) {
/* Someone's suspended the write. Sleep */ /* Someone's suspended the write. Sleep */
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
...@@ -1500,6 +1551,8 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, ...@@ -1500,6 +1551,8 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
} }
xip_enable(map, chip, adr); xip_enable(map, chip, adr);
op_done: op_done:
if (mode == FL_OTP_WRITE)
otp_exit(map, chip, adr, map_bankwidth(map));
chip->state = FL_READY; chip->state = FL_READY;
DISABLE_VPP(map); DISABLE_VPP(map);
put_chip(map, chip, adr); 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, ...@@ -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); tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n);
ret = do_write_oneword(map, &cfi->chips[chipnum], ret = do_write_oneword(map, &cfi->chips[chipnum],
bus_ofs, tmp_buf); bus_ofs, tmp_buf, FL_WRITING);
if (ret) if (ret)
return ret; return ret;
...@@ -1579,7 +1632,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -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); datum = map_word_load(map, buf);
ret = do_write_oneword(map, &cfi->chips[chipnum], ret = do_write_oneword(map, &cfi->chips[chipnum],
ofs, datum); ofs, datum, FL_WRITING);
if (ret) if (ret)
return ret; return ret;
...@@ -1622,7 +1675,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -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); tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len);
ret = do_write_oneword(map, &cfi->chips[chipnum], ret = do_write_oneword(map, &cfi->chips[chipnum],
ofs, tmp_buf); ofs, tmp_buf, FL_WRITING);
if (ret) if (ret)
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment