Skip to contentSkip to conversation

mtdchar : writing image with oob and NOP=1

DISCUSSION Matthieu CASTET 2 participants 3 messages Aug 2, 2010 – Aug 24, 2010 Memory technology devices (MTD)

lore
Share & tools
lore
#0 lore raw

Hi,

We need to write our bootloader with a special ecc (use by cpu rom).

For that we use MTD_MODE_RAW, write and MEMWRITEOOB. This work fine, but from my understanding this will do a first page program with oob set to 0xff and then program again oob.

But some recent nand support only 1 program per page (NOP=1). How can we program nand with NOP=1 with a custom ecc ?

From what I see in mtdchar either datbuf is set (and oobbuf is null) or oobbuf is set (and datbuf is null).

So this mean we need to add an ioctl to do that ?

Matthieu

#1 lore raw
Quoted 6 lines · Matthieu CASTET

Hi,

We need to write our bootloader with a special ecc (use by cpu rom).

For that we use MTD_MODE_RAW, write and MEMWRITEOOB. This work fine, but from my understanding this will do a first page program with oob set to 0xff and then program again oob.

Quoted 8 lines

But some recent nand support only 1 program per page (NOP=1). How can we program nand with NOP=1 with a custom ecc ?

From what I see in mtdchar either datbuf is set (and oobbuf is null) or
oobbuf is set (and datbuf is null).

So this mean we need to add an ioctl to do that ?

For info here what we did for our 2.6.27 kernel.

Matthieu

drivers/mtd/mtdchar.c +78 -0
index e00d424..7621449 100644
@@ -547,6 +547,84 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
 		break;
 
 	}
+	case MEMWRITEPAGE:
+	{
+		struct mtd_page_buf buf;
+		struct mtd_oob_ops ops;
+		struct mtd_page_buf __user *user_buf = argp;
+	        uint32_t retlen;
+
+		if(!(file->f_mode & 2))
+			return -EPERM;
+
+		if (copy_from_user(&buf, argp, sizeof(struct mtd_page_buf)))
+			return -EFAULT;
+
+		if (buf.length != mtd->writesize || buf.oob_length != mtd->oobsize)
+			return -EINVAL;
+
+		if (!mtd->write_oob)
+			return -EOPNOTSUPP;
+
+		ret = access_ok(VERIFY_READ, buf.ptr,
+					buf.length) ? 0 : EFAULT;
+		if (ret)
+			return ret;
+
+		ret = access_ok(VERIFY_READ, buf.oob_ptr,
+					buf.oob_length) ? 0 : EFAULT;
+		if (ret)
+			return ret;
+
+		ops.ooblen = mtd->oobsize;
+		ops.ooboffs = 0;
+		ops.len = mtd->writesize;
+		ops.mode = MTD_OOB_RAW;
+
+		if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs))
+			return -EINVAL;
+
+		ops.datbuf = kmalloc(buf.length, GFP_KERNEL);
+		if (!ops.datbuf)
+			return -ENOMEM;
+
+		if (copy_from_user(ops.datbuf, buf.ptr, buf.length)) {
+			kfree(ops.datbuf);
+			return -EFAULT;
+		}
+
+		ops.oobbuf = kmalloc(buf.oob_length, GFP_KERNEL);
+		if (!ops.oobbuf) {
+			kfree(ops.datbuf);
+			return -ENOMEM;
+		}
+
+		if (copy_from_user(ops.oobbuf, buf.oob_ptr, buf.oob_length)) {
+			kfree(ops.datbuf);
+			kfree(ops.oobbuf);
+			return -EFAULT;
+		}
+
+		ret = mtd->write_oob(mtd, buf.start, &ops);
+
+		if (!ret) {
+			retlen = ops.retlen;
+			if (copy_to_user(&user_buf->length, &retlen, sizeof(buf.length)))
+				ret = -EFAULT;
+		}
+
+		if (!ret) {
+			retlen = ops.oobretlen;
+			if (copy_to_user(&user_buf->oob_length, &retlen, sizeof(buf.oob_length)))
+				ret = -EFAULT;
+		}
+
+
+		kfree(ops.datbuf);
+		kfree(ops.oobbuf);
+		break;
+
+	}
 
 	case MEMREADOOB:
 	{
include/mtd/mtd-abi.h +8 -0
index c6c61cd..3d9e3bc 100644
@@ -16,6 +16,13 @@ struct mtd_oob_buf {
 	unsigned char __user *ptr;
 };
 
+struct mtd_page_buf {
+	uint32_t start;
+	uint32_t length;
+	unsigned char __user *ptr;
+	uint32_t oob_length;
+	unsigned char __user *oob_ptr;
+};
 #define MTD_ABSENT		0
 #define MTD_RAM			1
 #define MTD_ROM			2
@@ -93,6 +100,7 @@ struct otp_info {
 #define ECCGETLAYOUT		_IOR('M', 17, struct nand_ecclayout)
 #define ECCGETSTATS		_IOR('M', 18, struct mtd_ecc_stats)
 #define MTDFILEMODE		_IO('M', 19)
+#define MEMWRITEPAGE		_IOWR('M', 30, struct mtd_page_buf)
 
 /*
  * Obsolete legacy interface. Keep it in order not to break userspace
#2 lore raw
In reply to Matthieu CASTET
Quoted 8 lines · Matthieu CASTET

Hi,

We need to write our bootloader with a special ecc (use by cpu rom).

For that we use MTD_MODE_RAW, write and MEMWRITEOOB. This work fine, but from my understanding this will do a first page program with oob set to 0xff and then program again oob.

Quoted 7 lines

But some recent nand support only 1 program per page (NOP=1). How can we program nand with NOP=1 with a custom ecc ?

From what I see in mtdchar either datbuf is set (and oobbuf is null) or
oobbuf is set (and datbuf is null).

So this mean we need to add an ioctl to do that ?

Certainly not ioctl. MEMWRITEOOB should handle this and hide from users, I think.

Signature · 2 lines
Best Regards,
Artem Bityutskiy (Артём Битюцкий)