Patchwork [13/15] MTD: add few workarounds to nand system for SmartMedia/xD chips.

login
register
mail settings
Submitter Maxim Levitsky
Date Feb. 22, 2010, 6:39 p.m.
Message ID <1266863982-5258-14-git-send-email-maximlevitsky@gmail.com>
Download mbox | patch
Permalink /patch/45987/
State New
Headers show

Comments

Maxim Levitsky - Feb. 22, 2010, 6:39 p.m.
* Add an option NAND_SMARTMEDIA that can be set by nand driver
 If set, it will cause separate ID table to be used, which includes
 mask rom devices and new xD cards

* Workaround for wrong write protect status on some xD cards

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/mtd/nand/nand_base.c |   32 +++++++++++++++++++++++---------
 drivers/mtd/nand/nand_ids.c  |   39 +++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/nand.h     |   11 +++++++++++
 3 files changed, 73 insertions(+), 9 deletions(-)
Thomas Gleixner - Feb. 22, 2010, 9:25 p.m.
On Mon, 22 Feb 2010, Maxim Levitsky wrote:

> * Add an option NAND_SMARTMEDIA that can be set by nand driver
>  If set, it will cause separate ID table to be used, which includes
>  mask rom devices and new xD cards

Why that option ? We can just extend the existing ids table and be
done. No extra magic needed.
 
Thanks,

	tglx
Maxim Levitsky - Feb. 22, 2010, 9:33 p.m.
On Mon, 2010-02-22 at 22:25 +0100, Thomas Gleixner wrote: 
> On Mon, 22 Feb 2010, Maxim Levitsky wrote:
> 
> > * Add an option NAND_SMARTMEDIA that can be set by nand driver
> >  If set, it will cause separate ID table to be used, which includes
> >  mask rom devices and new xD cards
> 
> Why that option ? We can just extend the existing ids table and be
> done. No extra magic needed.
>  

Two reasons.

First of all several xD chips (I belive the Type M) have exactly same
IDs like normal nand chips. However they don't report capabilities about
pagesize, blocksize, etc.

I am confident that these cards have an internal FTL and controller, and
just 'emulate' that nand interface.

Also, my card  reports write protect, although, xD cards don't have any
'switch' to make them protected.
Even if there were readonly ROM xD cards (the odds of this are virtually
zero), these won't just expose this in WP bit.

Best regards,
Maxim Levitsky
Thomas Gleixner - Feb. 22, 2010, 9:53 p.m.
On Mon, 22 Feb 2010, Maxim Levitsky wrote:

> On Mon, 2010-02-22 at 22:25 +0100, Thomas Gleixner wrote: 
> > On Mon, 22 Feb 2010, Maxim Levitsky wrote:
> > 
> > > * Add an option NAND_SMARTMEDIA that can be set by nand driver
> > >  If set, it will cause separate ID table to be used, which includes
> > >  mask rom devices and new xD cards
> > 
> > Why that option ? We can just extend the existing ids table and be
> > done. No extra magic needed.
> >  
> 
> Two reasons.
> 
> First of all several xD chips (I belive the Type M) have exactly same
> IDs like normal nand chips. However they don't report capabilities about
> pagesize, blocksize, etc.

You mean that crap ?

+       /* xD only */
+       {"xD 512MiB 3,3V",              0xDC, 512, 512, 0x4000, XD_TYPEM},
+       {"xD 1GiB 3,3V",                0xD3, 512, 1024, 0x4000, XD_TYPEM},
+       {"xD 2GiB 3,3V",                0xD5, 512, 2048, 0x4000, XD_TYPEM},

Oh well, that's a perfect example of designed by comittee shit.
 
They abuse the 2k chips IDs and define crappy sizes just to fit the
stupid spec.

> I am confident that these cards have an internal FTL and controller, and
> just 'emulate' that nand interface.

Either that or the adapter translates the 512B commands to 2K
commands. I bet on the latter. AFAIK are xD cards just as stupid as
SmartMedia ones, i.e. bare NAND chips in a flat plastic housing with
gold contacts.

> Also, my card  reports write protect, although, xD cards don't have any
> 'switch' to make them protected.

Neither have SmartMedia Cards nor bare NAND chips. WP is a pin on the
interface which is controlled by the adapter hardware.

> Even if there were readonly ROM xD cards (the odds of this are virtually
> zero), these won't just expose this in WP bit.

Hmm, I wonder whether that horror has the WP bit inverted.

Thanks,

	tglx
Maxim Levitsky - Feb. 22, 2010, 10:12 p.m.
On Mon, 2010-02-22 at 22:53 +0100, Thomas Gleixner wrote: 
> On Mon, 22 Feb 2010, Maxim Levitsky wrote:
> 
> > On Mon, 2010-02-22 at 22:25 +0100, Thomas Gleixner wrote: 
> > > On Mon, 22 Feb 2010, Maxim Levitsky wrote:
> > > 
> > > > * Add an option NAND_SMARTMEDIA that can be set by nand driver
> > > >  If set, it will cause separate ID table to be used, which includes
> > > >  mask rom devices and new xD cards
> > > 
> > > Why that option ? We can just extend the existing ids table and be
> > > done. No extra magic needed.
> > >  
> > 
> > Two reasons.
> > 
> > First of all several xD chips (I belive the Type M) have exactly same
> > IDs like normal nand chips. However they don't report capabilities about
> > pagesize, blocksize, etc.

Sure, I didn't meant the #WP line. Sure it is set by the controller.
I mean WP bit in status report.

Best regards,
Maxim Levitsky

Patch

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index ba29a29..fd9b00d 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -434,9 +434,18 @@  static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
 static int nand_check_wp(struct mtd_info *mtd)
 {
 	struct nand_chip *chip = mtd->priv;
+	int wp;
+
+	/* broken xD cards report WP despite beeing writable */
+	if (chip->options & NAND_BROKEN_XD)
+		return 0;
+
 	/* Check the WP bit */
 	chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
-	return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
+	wp = (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
+
+
+	return wp;
 }
 
 /**
@@ -2769,7 +2778,7 @@  static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
 						  int busw, int *maf_id)
 {
 	struct nand_flash_dev *type = NULL;
-	int i, dev_id, maf_idx;
+	int dev_id, maf_idx;
 	int tmp_id, tmp_manf;
 
 	/* Select the device */
@@ -2809,14 +2818,18 @@  static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
 	}
 
 	/* Lookup the flash id */
-	for (i = 0; nand_flash_ids[i].name != NULL; i++) {
-		if (dev_id == nand_flash_ids[i].id) {
-			type =  &nand_flash_ids[i];
+#ifdef CONFIG_MTD_NAND_SMARTMEDIA
+	if (chip->options & NAND_SMARTMEDIA)
+		type = nand_smartmedia_flash_ids;
+	else
+#endif
+		type = nand_flash_ids;
+
+	for (; type->name != NULL; type++)
+		if (dev_id == type->id)
 			break;
-		}
-	}
 
-	if (!type)
+	if (!type->name)
 		return ERR_PTR(-ENODEV);
 
 	if (!mtd->name)
@@ -3174,7 +3187,8 @@  int nand_scan_tail(struct mtd_info *mtd)
 
 	/* Fill in remaining MTD driver data */
 	mtd->type = MTD_NANDFLASH;
-	mtd->flags = MTD_CAP_NANDFLASH;
+	mtd->flags = chip->options & NAND_ROM ? MTD_CAP_ROM :
+							MTD_CAP_NANDFLASH;
 	mtd->erase = nand_erase;
 	mtd->point = NULL;
 	mtd->unpoint = NULL;
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index 69ee2c9..f9e72d5 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -127,6 +127,45 @@  struct nand_flash_dev nand_flash_ids[] = {
 	{NULL,}
 };
 
+#ifdef CONFIG_MTD_NAND_SMARTMEDIA
+struct nand_flash_dev nand_smartmedia_flash_ids[] = {
+
+	/* SmartMedia */
+	{"SmartMedia 1MiB 5V",		0x6e, 256, 1, 0x1000, 0},
+	{"SmartMedia 1MiB 3,3V",	0xe8, 256, 1, 0x1000, 0},
+	{"SmartMedia 1MiB 3,3V",	0xec, 256, 1, 0x1000, 0},
+	{"SmartMedia 2MiB 3,3V",	0xea, 256, 2, 0x1000, 0},
+	{"SmartMedia 2MiB 5V",		0x64, 256, 2, 0x1000, 0},
+	{"SmartMedia 2MiB 3,3V ROM",	0x5d, 512, 2, 0x2000, NAND_ROM},
+	{"SmartMedia 4MiB 3,3V",	0xe3, 512, 4, 0x2000, 0},
+	{"SmartMedia 4MiB 3,3/5V",	0xe5, 512, 4, 0x2000, 0},
+	{"SmartMedia 4MiB 5V",		0x6b, 512, 4, 0x2000, 0},
+	{"SmartMedia 4MiB 3,3V ROM",	0xd5, 512, 4, 0x2000, NAND_ROM},
+	{"SmartMedia 8MiB 3,3V",	0xe6, 512, 8, 0x2000, 0},
+	{"SmartMedia 8MiB 3,3V ROM",	0xd6, 512, 8, 0x2000, NAND_ROM},
+
+#define XD_TYPEM	(NAND_NO_AUTOINCR | NAND_BROKEN_XD)
+	/* xD / SmartMedia */
+	{"SmartMedia/xD 16MiB 3,3V",	0x73, 512, 16, 0x4000, 0},
+	{"SmartMedia 16MiB 3,3V ROM",	0x57, 512, 16, 0x4000, NAND_ROM},
+	{"SmartMedia/xD 32MiB 3,3V",	0x75, 512, 32, 0x4000, 0},
+	{"SmartMedia 32MiB 3,3V ROM",	0x58, 512, 32, 0x4000, NAND_ROM},
+	{"SmartMedia/xD 64MiB 3,3V",	0x76, 512, 64, 0x4000, 0},
+	{"SmartMedia 64MiB 3,3V ROM",	0xd9, 512, 64, 0x4000, NAND_ROM},
+	{"SmartMedia/xD 128MiB 3,3V",	0x79, 512, 128, 0x4000, 0},
+	{"SmartMedia 128MiB 3,3V ROM",	0xda, 512, 128, 0x4000, NAND_ROM},
+	{"SmartMedia/xD 256MiB 3,3V",	0x71, 512, 256, 0x4000, XD_TYPEM},
+	{"SmartMedia 256MiB 3,3V ROM",	0x5b, 512, 256, 0x4000, NAND_ROM},
+
+	/* xD only */
+	{"xD 512MiB 3,3V",		0xDC, 512, 512, 0x4000, XD_TYPEM},
+	{"xD 1GiB 3,3V",		0xD3, 512, 1024, 0x4000, XD_TYPEM},
+	{"xD 2GiB 3,3V",		0xD5, 512, 2048, 0x4000, XD_TYPEM},
+	{NULL,}
+};
+EXPORT_SYMBOL(nand_smartmedia_flash_ids);
+#endif
+
 /*
 *	Manufacturer ID list
 */
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index f2d4a1a..7291725 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -180,6 +180,12 @@  typedef enum {
 /* Chip does not allow subpage writes */
 #define NAND_NO_SUBPAGE_WRITE	0x00000200
 
+/* Device is one of 'new' xD cards that expose fake nand command set */
+#define NAND_BROKEN_XD		0x00000400
+
+/* Device behaves just like nand, but is readonly */
+#define NAND_ROM		0x00000800
+
 /* Options valid for Samsung large page devices */
 #define NAND_SAMSUNG_LP_OPTIONS \
 	(NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK)
@@ -205,9 +211,13 @@  typedef enum {
 /* This option is defined if the board driver allocates its own buffers
    (e.g. because it needs them DMA-coherent */
 #define NAND_OWN_BUFFERS	0x00040000
+
 /* Chip may not exist, so silence any errors in scan */
 #define NAND_SCAN_SILENT_NODEV	0x00080000
 
+/* controller supports only xD/SmartMedia cards*/
+#define NAND_SMARTMEDIA		0x00100000
+
 /* Options set by nand scan */
 /* Nand scan has allocated controller struct */
 #define NAND_CONTROLLER_ALLOC	0x80000000
@@ -469,6 +479,7 @@  struct nand_manufacturers {
 };
 
 extern struct nand_flash_dev nand_flash_ids[];
+extern struct nand_flash_dev nand_smartmedia_flash_ids[];
 extern struct nand_manufacturers nand_manuf_ids[];
 
 extern int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd);