linux-mtd.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 1/4] mtd: cfi_cmdset_0002: Add support for reading OTP
       [not found] <1367003430-24584-1-git-send-email-christian.riesch@omicron.at>
@ 2013-04-26 19:10 ` Christian Riesch
  2013-05-29  7:11   ` Artem Bityutskiy
  2013-04-26 19:10 ` [PATCH v2 2/4] mtd: cfi_cmdset_0002: Invalidate cache after entering/exiting OTP memory Christian Riesch
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 10+ messages in thread
From: Christian Riesch @ 2013-04-26 19:10 UTC (permalink / raw)
  To: linux-mtd; +Cc: Christian Riesch

The Micron M29EW has a 256 byte one time programmable (OTP) memory.
This patch adds support for reading this memory. This support will be
extended for locking and writing in subsequent patches.

Signed-off-by: Christian Riesch <christian.riesch@omicron.at>
---
 drivers/mtd/chips/cfi_cmdset_0002.c |  163 +++++++++++++++++++++++++++++++++++
 1 file changed, 163 insertions(+)

diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index fff665d..353ddfb 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -59,7 +59,15 @@ 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 *, struct otp_info *,
+					 size_t len);
+static int cfi_amdstd_get_user_prot_info(struct mtd_info *, struct otp_info *,
+					 size_t len);
 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_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
 				  size_t *retlen, const u_char *buf);
@@ -521,6 +529,10 @@ 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->flags   = MTD_CAP_NORFLASH;
 	mtd->name    = map->name;
 	mtd->writesize = 1;
@@ -1142,6 +1154,8 @@ 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);
 
 static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
 {
@@ -1224,6 +1238,155 @@ static int cfi_amdstd_secsi_read (struct mtd_info *mtd, loff_t from, size_t len,
 	return ret;
 }
 
+static int __xipram 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;
+
+		/* 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);
+			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,
+					   struct otp_info *buf, size_t len)
+{
+	size_t retlen;
+	int ret;
+
+	ret = cfi_amdstd_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 0);
+	return ret ? : retlen;
+}
+
+static int cfi_amdstd_get_user_prot_info(struct mtd_info *mtd,
+					 struct otp_info *buf, size_t len)
+{
+	size_t retlen;
+	int ret;
+
+	ret = cfi_amdstd_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 1);
+	return ret ? : retlen;
+}
+
+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 __xipram do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum)
 {
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 2/4] mtd: cfi_cmdset_0002: Invalidate cache after entering/exiting OTP memory
       [not found] <1367003430-24584-1-git-send-email-christian.riesch@omicron.at>
  2013-04-26 19:10 ` [PATCH v2 1/4] mtd: cfi_cmdset_0002: Add support for reading OTP Christian Riesch
@ 2013-04-26 19:10 ` Christian Riesch
  2013-04-26 19:10 ` [PATCH v2 3/4] mtd: cfi_cmdset_0002: Add support for writing " Christian Riesch
  2013-04-26 19:10 ` [PATCH v2 4/4] mtd: cfi_cmdset_0002: Add support for locking " Christian Riesch
  3 siblings, 0 replies; 10+ messages in thread
From: Christian Riesch @ 2013-04-26 19:10 UTC (permalink / raw)
  To: linux-mtd; +Cc: Christian Riesch

When the one time programmable (OTP) memory region is entered by
issuing the 0xaa/0x55/0x88 command, the OTP memory occupies the
addresses which are normally used by the first sector of the regular
flash memory. This patch therefore invalidates cache for this
addresses after entering/exiting OTP memory.

This patch also moves the code into separate functions.

Signed-off-by: Christian Riesch <christian.riesch@omicron.at>
---

Hi,

I am not sure if invalidating the cache here is required or not. The old code
(that supported only reading the first 8 bytes of OTP memory of some flashes
with AMD chipset) did not do it. Any comments on this?

Thank you!
Best regards, Christian

 drivers/mtd/chips/cfi_cmdset_0002.c |   44 +++++++++++++++++++++++++++--------
 1 file changed, 34 insertions(+), 10 deletions(-)

diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index 353ddfb..c9c544c 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -1157,11 +1157,42 @@ static int cfi_amdstd_read (struct mtd_info *mtd, loff_t from, size_t len, size_
 typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip,
 			loff_t adr, size_t len, u_char *buf);
 
+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)
 {
 	DECLARE_WAITQUEUE(wait, current);
 	unsigned long timeo = jiffies + HZ;
-	struct cfi_private *cfi = map->fldrv_priv;
 
  retry:
 	mutex_lock(&chip->mutex);
@@ -1183,16 +1214,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);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 3/4] mtd: cfi_cmdset_0002: Add support for writing OTP memory
       [not found] <1367003430-24584-1-git-send-email-christian.riesch@omicron.at>
  2013-04-26 19:10 ` [PATCH v2 1/4] mtd: cfi_cmdset_0002: Add support for reading OTP Christian Riesch
  2013-04-26 19:10 ` [PATCH v2 2/4] mtd: cfi_cmdset_0002: Invalidate cache after entering/exiting OTP memory Christian Riesch
@ 2013-04-26 19:10 ` Christian Riesch
  2013-04-26 19:10 ` [PATCH v2 4/4] mtd: cfi_cmdset_0002: Add support for locking " Christian Riesch
  3 siblings, 0 replies; 10+ messages in thread
From: Christian Riesch @ 2013-04-26 19:10 UTC (permalink / raw)
  To: linux-mtd; +Cc: Christian Riesch

This patch adds support for writing the one time programmable (OTP)
memory of Micron M29EW devices.

Signed-off-by: Christian Riesch <christian.riesch@omicron.at>
---
 drivers/mtd/chips/cfi_cmdset_0002.c |   60 +++++++++++++++++++++++++++++++----
 1 file changed, 53 insertions(+), 7 deletions(-)

diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index c9c544c..e939d91 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -68,6 +68,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);
@@ -533,6 +535,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;
@@ -1262,6 +1265,33 @@ 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 = 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;
+
+		adr += n;
+		buf += n;
+		len -= n;
+	}
+
+	return 0;
+}
+
 static int __xipram cfi_amdstd_otp_walk(struct mtd_info *mtd, loff_t from,
 					size_t len,
 					size_t *retlen, u_char *buf,
@@ -1412,7 +1442,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;
@@ -1433,7 +1473,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;
@@ -1442,6 +1482,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
@@ -1458,12 +1501,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),
@@ -1472,7 +1516,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);
 
@@ -1512,6 +1556,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);
@@ -1567,7 +1613,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;
 
@@ -1591,7 +1637,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;
 
@@ -1634,7 +1680,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;
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 4/4] mtd: cfi_cmdset_0002: Add support for locking OTP memory
       [not found] <1367003430-24584-1-git-send-email-christian.riesch@omicron.at>
                   ` (2 preceding siblings ...)
  2013-04-26 19:10 ` [PATCH v2 3/4] mtd: cfi_cmdset_0002: Add support for writing " Christian Riesch
@ 2013-04-26 19:10 ` Christian Riesch
  3 siblings, 0 replies; 10+ messages in thread
From: Christian Riesch @ 2013-04-26 19:10 UTC (permalink / raw)
  To: linux-mtd; +Cc: Christian Riesch

This patch adds support for the locking of the one time
programmable (OTP) memory of Micron M29EW devices.

Signed-off-by: Christian Riesch <christian.riesch@omicron.at>
---
 drivers/mtd/chips/cfi_cmdset_0002.c |   89 +++++++++++++++++++++++++++++++++--
 1 file changed, 84 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index e939d91..415e128 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -70,6 +70,7 @@ 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);
@@ -536,6 +537,7 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
 	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;
@@ -1158,7 +1160,7 @@ static int cfi_amdstd_read (struct mtd_info *mtd, loff_t from, size_t len, size_
 }
 
 typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip,
-			loff_t adr, size_t len, u_char *buf);
+			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)
@@ -1192,7 +1194,10 @@ static inline void otp_exit(struct map_info *map, struct flchip *chip,
 	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;
@@ -1251,7 +1256,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;
 
@@ -1270,7 +1276,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
 				     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 len, u_char *buf, size_t grouplen)
 {
 	int ret;
 	while (len) {
@@ -1292,6 +1298,70 @@ static int do_otp_write(struct map_info *map, struct flchip *chip, loff_t adr,
 	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 __xipram cfi_amdstd_otp_walk(struct mtd_info *mtd, loff_t from,
 					size_t len,
 					size_t *retlen, u_char *buf,
@@ -1391,7 +1461,8 @@ static int __xipram cfi_amdstd_otp_walk(struct mtd_info *mtd, loff_t from,
 		} else if ((from < otpsize) && (len > 0)) {
 			size_t size;
 			size = (len < otpsize - from) ? len : otpsize - from;
-			ret = action(map, chip, otpoffset + from, size, buf);
+			ret = action(map, chip, otpoffset + from, size, buf,
+				     otpsize);
 			if (ret < 0)
 				return ret;
 
@@ -1450,6 +1521,14 @@ static int cfi_amdstd_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
 				   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)
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 1/4] mtd: cfi_cmdset_0002: Add support for reading OTP
  2013-04-26 19:10 ` [PATCH v2 1/4] mtd: cfi_cmdset_0002: Add support for reading OTP Christian Riesch
@ 2013-05-29  7:11   ` Artem Bityutskiy
  2013-05-29 12:54     ` Christian Riesch
  0 siblings, 1 reply; 10+ messages in thread
From: Artem Bityutskiy @ 2013-05-29  7:11 UTC (permalink / raw)
  To: Christian Riesch; +Cc: linux-mtd

On Fri, 2013-04-26 at 21:10 +0200, Christian Riesch wrote:
> +static int cfi_amdstd_get_fact_prot_info(struct mtd_info *mtd,
> +                                          struct otp_info *buf,
> size_t len)
> +{
> +       size_t retlen;
> +       int ret;
> +
> +       ret = cfi_amdstd_otp_walk(mtd, 0, len, &retlen, (u_char *)buf,
> NULL, 0);
> +       return ret ? : retlen;
> +}

Hmm, I thought we would return 0 in case of success and a negative error
code in case of error. Returning retlen looks wrong.

-- 
Best Regards,
Artem Bityutskiy

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 1/4] mtd: cfi_cmdset_0002: Add support for reading OTP
  2013-05-29  7:11   ` Artem Bityutskiy
@ 2013-05-29 12:54     ` Christian Riesch
  2013-05-29 13:53       ` Artem Bityutskiy
  0 siblings, 1 reply; 10+ messages in thread
From: Christian Riesch @ 2013-05-29 12:54 UTC (permalink / raw)
  To: dedekind1; +Cc: linux-mtd

Artem,
Thank you very much for your comments!

On 2013-05-29 09:11, Artem Bityutskiy wrote:
> On Fri, 2013-04-26 at 21:10 +0200, Christian Riesch wrote:
>> +static int cfi_amdstd_get_fact_prot_info(struct mtd_info *mtd,
>> +                                          struct otp_info *buf,
>> size_t len)
>> +{
>> +       size_t retlen;
>> +       int ret;
>> +
>> +       ret = cfi_amdstd_otp_walk(mtd, 0, len, &retlen, (u_char *)buf,
>> NULL, 0);
>> +       return ret ? : retlen;
>> +}
>
> Hmm, I thought we would return 0 in case of success and a negative error
> code in case of error. Returning retlen looks wrong.
>

I don't think so. Somehow the caller of this function should be told how 
many bytes have been written into buf, there is no other way to return 
the data length than the return value. Anyway, I just stole this code 
from cfi_cmdset_0001.c (function cfi_intelext_get_fact_prot_info), it is 
done in the same way there.

Christian

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 1/4] mtd: cfi_cmdset_0002: Add support for reading OTP
  2013-05-29 12:54     ` Christian Riesch
@ 2013-05-29 13:53       ` Artem Bityutskiy
  2013-05-29 14:36         ` Christian Riesch
  0 siblings, 1 reply; 10+ messages in thread
From: Artem Bityutskiy @ 2013-05-29 13:53 UTC (permalink / raw)
  To: Christian Riesch; +Cc: linux-mtd

On Wed, 2013-05-29 at 14:54 +0200, Christian Riesch wrote:
> Artem,
> Thank you very much for your comments!
> 
> On 2013-05-29 09:11, Artem Bityutskiy wrote:
> > On Fri, 2013-04-26 at 21:10 +0200, Christian Riesch wrote:
> >> +static int cfi_amdstd_get_fact_prot_info(struct mtd_info *mtd,
> >> +                                          struct otp_info *buf,
> >> size_t len)
> >> +{
> >> +       size_t retlen;
> >> +       int ret;
> >> +
> >> +       ret = cfi_amdstd_otp_walk(mtd, 0, len, &retlen, (u_char *)buf,
> >> NULL, 0);
> >> +       return ret ? : retlen;
> >> +}
> >
> > Hmm, I thought we would return 0 in case of success and a negative error
> > code in case of error. Returning retlen looks wrong.
> >
> 
> I don't think so. Somehow the caller of this function should be told how 
> many bytes have been written into buf, there is no other way to return 
> the data length than the return value. Anyway, I just stole this code 
> from cfi_cmdset_0001.c (function cfi_intelext_get_fact_prot_info), it is 
> done in the same way there.

But retlen is where you return the amount of bytes you actually wrote.
The return code is either 0 or a negative error code number. This is
what we do in mtd_write() and I'd expect the OTP functions to be
consistent.

-- 
Best Regards,
Artem Bityutskiy

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 1/4] mtd: cfi_cmdset_0002: Add support for reading OTP
  2013-05-29 13:53       ` Artem Bityutskiy
@ 2013-05-29 14:36         ` Christian Riesch
  2013-06-03  9:40           ` Artem Bityutskiy
  0 siblings, 1 reply; 10+ messages in thread
From: Christian Riesch @ 2013-05-29 14:36 UTC (permalink / raw)
  To: dedekind1; +Cc: linux-mtd

On 2013-05-29 15:53, Artem Bityutskiy wrote:
> On Wed, 2013-05-29 at 14:54 +0200, Christian Riesch wrote:
>> Artem,
>> Thank you very much for your comments!
>>
>> On 2013-05-29 09:11, Artem Bityutskiy wrote:
>>> On Fri, 2013-04-26 at 21:10 +0200, Christian Riesch wrote:
>>>> +static int cfi_amdstd_get_fact_prot_info(struct mtd_info *mtd,
>>>> +                                          struct otp_info *buf,
>>>> size_t len)
>>>> +{
>>>> +       size_t retlen;
>>>> +       int ret;
>>>> +
>>>> +       ret = cfi_amdstd_otp_walk(mtd, 0, len, &retlen, (u_char *)buf,
>>>> NULL, 0);
>>>> +       return ret ? : retlen;
>>>> +}
>>>
>>> Hmm, I thought we would return 0 in case of success and a negative error
>>> code in case of error. Returning retlen looks wrong.
>>>
>>
>> I don't think so. Somehow the caller of this function should be told how
>> many bytes have been written into buf, there is no other way to return
>> the data length than the return value. Anyway, I just stole this code
>> from cfi_cmdset_0001.c (function cfi_intelext_get_fact_prot_info), it is
>> done in the same way there.
>
> But retlen is where you return the amount of bytes you actually wrote.
> The return code is either 0 or a negative error code number. This is
> what we do in mtd_write() and I'd expect the OTP functions to be
> consistent.

Unlike mtd_write, mtd->_get_fact_prot_info (which is a pointer to 
cfi_amdstd_get_fact_prot_info here) does not have a retlen parameter. Do 
you suggest to change this?

Regards, Christian

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 1/4] mtd: cfi_cmdset_0002: Add support for reading OTP
  2013-05-29 14:36         ` Christian Riesch
@ 2013-06-03  9:40           ` Artem Bityutskiy
  2013-06-04 11:30             ` Christian Riesch
  0 siblings, 1 reply; 10+ messages in thread
From: Artem Bityutskiy @ 2013-06-03  9:40 UTC (permalink / raw)
  To: Christian Riesch; +Cc: linux-mtd

On Wed, 2013-05-29 at 16:36 +0200, Christian Riesch wrote:
> > But retlen is where you return the amount of bytes you actually
> wrote.
> > The return code is either 0 or a negative error code number. This is
> > what we do in mtd_write() and I'd expect the OTP functions to be
> > consistent.
> 
> Unlike mtd_write, mtd->_get_fact_prot_info (which is a pointer to 
> cfi_amdstd_get_fact_prot_info here) does not have a retlen parameter.
> Do 
> you suggest to change this?

Yes, I would suggest this.

-- 
Best Regards,
Artem Bityutskiy

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 1/4] mtd: cfi_cmdset_0002: Add support for reading OTP
  2013-06-03  9:40           ` Artem Bityutskiy
@ 2013-06-04 11:30             ` Christian Riesch
  0 siblings, 0 replies; 10+ messages in thread
From: Christian Riesch @ 2013-06-04 11:30 UTC (permalink / raw)
  To: dedekind1; +Cc: linux-mtd

On 2013-06-03 11:40, Artem Bityutskiy wrote:
> On Wed, 2013-05-29 at 16:36 +0200, Christian Riesch wrote:
>>> But retlen is where you return the amount of bytes you actually
>> wrote.
>>> The return code is either 0 or a negative error code number. This is
>>> what we do in mtd_write() and I'd expect the OTP functions to be
>>> consistent.
>>
>> Unlike mtd_write, mtd->_get_fact_prot_info (which is a pointer to
>> cfi_amdstd_get_fact_prot_info here) does not have a retlen parameter.
>> Do
>> you suggest to change this?
>
> Yes, I would suggest this.
>

Ok, I will prepare a patch for this.
Thanks, Christian

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2013-06-04 11:31 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <1367003430-24584-1-git-send-email-christian.riesch@omicron.at>
2013-04-26 19:10 ` [PATCH v2 1/4] mtd: cfi_cmdset_0002: Add support for reading OTP Christian Riesch
2013-05-29  7:11   ` Artem Bityutskiy
2013-05-29 12:54     ` Christian Riesch
2013-05-29 13:53       ` Artem Bityutskiy
2013-05-29 14:36         ` Christian Riesch
2013-06-03  9:40           ` Artem Bityutskiy
2013-06-04 11:30             ` Christian Riesch
2013-04-26 19:10 ` [PATCH v2 2/4] mtd: cfi_cmdset_0002: Invalidate cache after entering/exiting OTP memory Christian Riesch
2013-04-26 19:10 ` [PATCH v2 3/4] mtd: cfi_cmdset_0002: Add support for writing " Christian Riesch
2013-04-26 19:10 ` [PATCH v2 4/4] mtd: cfi_cmdset_0002: Add support for locking " Christian Riesch

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).