Module Name:    src
Committed By:   ahoka
Date:           Wed Mar  9 10:05:08 UTC 2011

Modified Files:
        src/sys/dev/nand: files.nand nand.c nand.h
Added Files:
        src/sys/dev/nand: nand_micron.c

Log Message:
Add support for legacy devices not supporting the ONFI READ_PARAMETER_PAGE
command with example usage for Micron chips


To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 src/sys/dev/nand/files.nand
cvs rdiff -u -r1.2 -r1.3 src/sys/dev/nand/nand.c src/sys/dev/nand/nand.h
cvs rdiff -u -r0 -r1.1 src/sys/dev/nand/nand_micron.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/nand/files.nand
diff -u src/sys/dev/nand/files.nand:1.1 src/sys/dev/nand/files.nand:1.2
--- src/sys/dev/nand/files.nand:1.1	Sat Feb 26 18:07:31 2011
+++ src/sys/dev/nand/files.nand	Wed Mar  9 10:05:08 2011
@@ -1,4 +1,4 @@
-# $NetBSD: files.nand,v 1.1 2011/02/26 18:07:31 ahoka Exp $
+# $NetBSD: files.nand,v 1.2 2011/03/09 10:05:08 ahoka Exp $
 
 define	nandbus	{ }
 
@@ -9,6 +9,7 @@
 file	dev/nand/hamming.c	nand
 file	dev/nand/nand_bbt.c	nand
 file	dev/nand/nand_crc.c	nand
+file	dev/nand/nand_micron.c	nand
 
 defpseudodev	nandemulator: nandbus
 file	dev/nand/nandemulator.c	nandemulator

Index: src/sys/dev/nand/nand.c
diff -u src/sys/dev/nand/nand.c:1.2 src/sys/dev/nand/nand.c:1.3
--- src/sys/dev/nand/nand.c:1.2	Wed Mar  9 07:49:15 2011
+++ src/sys/dev/nand/nand.c	Wed Mar  9 10:05:08 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: nand.c,v 1.2 2011/03/09 07:49:15 ahoka Exp $	*/
+/*	$NetBSD: nand.c,v 1.3 2011/03/09 10:05:08 ahoka Exp $	*/
 
 /*-
  * Copyright (c) 2010 Department of Software Engineering,
@@ -34,7 +34,7 @@
 /* Common driver for NAND chips implementing the ONFI 2.2 specification */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nand.c,v 1.2 2011/03/09 07:49:15 ahoka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nand.c,v 1.3 2011/03/09 10:05:08 ahoka Exp $");
 
 #include "locators.h"
 
@@ -117,8 +117,10 @@
 		aprint_error("NAND chip is write protected!\n");
 		return;
 	}
-	if (nand_scan_media(self, chip))
+	
+	if (nand_scan_media(self, chip)) {
 		return;
+	}
 
 	/* allocate cache */
 	chip->nc_oob_cache = kmem_alloc(chip->nc_spare_size, KM_SLEEP);
@@ -281,6 +283,19 @@
 }
 #endif
 
+static int
+nand_read_legacy_parameters(device_t self, struct nand_chip *chip)
+{
+	switch (chip->nc_manf_id) {
+	case NAND_MFR_MICRON:
+		return nand_read_parameters_micron(self, chip);
+	default:
+		return 1;
+	}
+	
+	return 0;
+}
+
 /**
  * scan media to determine the chip's properties
  * this function resets the device
@@ -296,6 +311,7 @@
 	nand_command(self, ONFI_RESET);
 	nand_select(self, false);
 
+	/* check if the device implements the ONFI standard */
 	nand_select(self, true);
 	nand_command(self, ONFI_READ_ID);
 	nand_address(self, 0x20);
@@ -307,24 +323,48 @@
 
 	if (onfi_signature[0] != 'O' || onfi_signature[1] != 'N' ||
 	    onfi_signature[2] != 'F' || onfi_signature[3] != 'I') {
-		aprint_error_dev(self,
-		    "device does not support the ONFI specification\n");
+		chip->nc_isonfi = false;
+		
+		aprint_normal(": Legacy NAND Flash\n");
+		
+		nand_readid(self, chip);
 
-		return 1;
-	}
+		if (nand_read_legacy_parameters(self, chip)) {
+			aprint_error_dev(self,
+			    "can't read device parameters for legacy chip\n");
+			return 1;
+		}
+	} else {
+		chip->nc_isonfi = true;
 
-	nand_readid(self, chip);
+		aprint_normal(": ONFI NAND Flash\n");
 
-	aprint_normal(": NAND Flash\n");
+		nand_readid(self, chip);
+		nand_read_parameter_page(self, chip);
+	}
 
-	aprint_debug_dev(self,
+#ifdef NAND_VERBOSE
+	aprint_normal_dev(self,
 	    "manufacturer id: 0x%.2x (%s), device id: 0x%.2x\n",
 	    chip->nc_manf_id,
 	    nand_midtoname(chip->nc_manf_id),
 	    chip->nc_dev_id);
+#endif
 
-	nand_read_parameter_page(self, chip);
+	aprint_normal_dev(self,
+	   "page size: %u bytes, spare size: %u bytes, block size: %u bytes\n",
+	    chip->nc_page_size, chip->nc_spare_size, chip->nc_block_size);
+
+	aprint_normal_dev(self,
+	    "LUN size: %u blocks, LUNs: %u, total storage size: %u MB\n",
+	    chip->nc_lun_blocks, chip->nc_num_luns,
+	    chip->nc_size / 1024 / 1024);
 
+#ifdef NAND_VERBOSE
+	aprint_normal_dev(self, "column cycles: %d, row cycles: %d\n",
+	    chip->nc_addr_cycles_column, chip->nc_addr_cycles_row);
+#endif
+		
 	ecc = chip->nc_ecc = &sc->nand_if->ecc;
 
 	/*
@@ -388,12 +428,13 @@
 	nand_select(self, true);
 	nand_command(self, ONFI_READ_ID);
 	nand_address(self, 0x00);
+	
 	nand_read_byte(self, &chip->nc_manf_id);
 	nand_read_byte(self, &chip->nc_dev_id);
+	
 	nand_select(self, false);
 }
 
-/* read the parameter page. TODO: check CRC! */
 static void
 nand_read_parameter_page(device_t self, struct nand_chip *chip)
 {
@@ -435,20 +476,10 @@
 
 	aprint_normal_dev(self, "vendor: %s, model: %s\n", vendor, model);
 
-	aprint_normal_dev(self,
-	   "page size: %u bytes, spare size: %u bytes, block size: %u bytes\n",
-	    params.param_pagesize, params.param_sparesize,
-	    params.param_blocksize * params.param_pagesize);
-
-	aprint_normal_dev(self,
-	    "LUN size: %u blocks, LUNs: %u, total storage size: %u MB\n",
-	    params.param_lunsize, params.param_numluns,
-	    params.param_blocksize * params.param_pagesize *
-	    params.param_lunsize * params.param_numluns / 1024 / 1024);
-
 	/* XXX TODO multiple LUNs */
-	if (__predict_false(params.param_numluns != 1))
+	if (__predict_false(params.param_numluns != 1)) {
 		panic("more than one LUNs are not supported yet!\n");
+	}
 
 	chip->nc_size = params.param_pagesize * params.param_blocksize *
 	    params.param_lunsize * params.param_numluns;
@@ -457,17 +488,14 @@
 	chip->nc_block_pages = params.param_blocksize;
 	chip->nc_block_size = params.param_blocksize * params.param_pagesize;
 	chip->nc_spare_size = params.param_sparesize;
+	chip->nc_lun_blocks = params.param_lunsize;
+	chip->nc_num_luns = params.param_numluns;
 
 	/* the lower 4 bits contain the row address cycles */
 	chip->nc_addr_cycles_row = params.param_addr_cycles & 0x07;
 	/* the upper 4 bits contain the column address cycles */
 	chip->nc_addr_cycles_column = (params.param_addr_cycles & ~0x07) >> 4;
 
-#ifdef NAND_VERBOSE
-	aprint_normal_dev(self, "column cycles: %d, row cycles: %d\n",
-	    chip->nc_addr_cycles_column, chip->nc_addr_cycles_row);
-#endif
-
 	if (params.param_features & ONFI_FEATURE_16BIT)
 		chip->nc_flags |= NC_BUSWIDTH_16;
 
Index: src/sys/dev/nand/nand.h
diff -u src/sys/dev/nand/nand.h:1.2 src/sys/dev/nand/nand.h:1.3
--- src/sys/dev/nand/nand.h:1.2	Sat Mar  5 06:28:29 2011
+++ src/sys/dev/nand/nand.h	Wed Mar  9 10:05:08 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: nand.h,v 1.2 2011/03/05 06:28:29 jruoho Exp $	*/
+/*	$NetBSD: nand.h,v 1.3 2011/03/09 10:05:08 ahoka Exp $	*/
 
 /*-
  * Copyright (c) 2010 Department of Software Engineering,
@@ -64,7 +64,7 @@
 void nand_markbad(device_t, size_t);
 
 int nand_read_page(device_t, size_t, uint8_t *);
-int nand_read_oob(device_t self, size_t page, void *oob);
+int nand_read_oob(device_t, size_t, void *);
 
 /*
  * default functions for driver development
@@ -154,6 +154,7 @@
  *	      about the NAND chip.
  */
 struct nand_chip {
+	struct nand_ecc *nc_ecc; 	/* ecc information */
 	uint8_t	*nc_oob_cache;		/* buffer for oob cache */
 	uint8_t *nc_page_cache;		/* buffer for page cache */
 	uint8_t *nc_ecc_cache;
@@ -162,19 +163,20 @@
 	size_t nc_block_pages;		/* block size in pages */
 	size_t nc_block_size;		/* block size in bytes */
 	size_t nc_spare_size;		/* spare (oob) size in bytes */
+	uint32_t nc_lun_blocks;		/* LUN size in blocks */
 	uint32_t nc_flags;		/* bitfield flags */
 	uint32_t nc_quirks;		/* bitfield quirks */
 	unsigned int nc_page_shift;	/* page shift for page alignment */
 	unsigned int nc_page_mask;	/* page mask for page alignment */
 	unsigned int nc_block_shift;	/* write shift */
 	unsigned int nc_block_mask;	/* write mask */
+	uint8_t nc_num_luns;		/* number of LUNs */
 	uint8_t nc_manf_id;		/* manufacturer id */
 	uint8_t nc_dev_id;		/* device id  */
 	uint8_t nc_addr_cycles_row;	/* row cycles for addressing */
 	uint8_t nc_addr_cycles_column;	/* column cycles for addressing */
 	uint8_t nc_badmarker_offs;	/* offset for marking bad blocks */
-	
-	struct nand_ecc *nc_ecc;
+	bool nc_isonfi;			/* if the device is onfi compliant */
 };
 
 struct nand_write_cache {
@@ -450,6 +452,13 @@
 
 extern const struct nand_manufacturer nand_mfrs[];
 
+/*
+ * Manufacturer specific parameter functions
+ */
+int nand_read_parameters_micron(device_t, struct nand_chip *);
+
+/* debug inlines */
+
 static inline void
 nand_dump_data(const char *name, void *data, size_t len)
 {

Added files:

Index: src/sys/dev/nand/nand_micron.c
diff -u /dev/null src/sys/dev/nand/nand_micron.c:1.1
--- /dev/null	Wed Mar  9 10:05:08 2011
+++ src/sys/dev/nand/nand_micron.c	Wed Mar  9 10:05:08 2011
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2011 Department of Software Engineering,
+ *		      University of Szeged, Hungary
+ * Copyright (c) 2011 Adam Hoka <[email protected]>
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by the Department of Software Engineering, University of Szeged, Hungary
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Device specific functions for legacy Micron NAND chips
+ *
+ * Currently supported:
+ * MT29F2G08AACWP, MT29F4G08BACWP, MT29F8G08FACWP
+ */
+
+#include "nand.h"
+#include "onfi.h"
+
+int
+nand_read_parameters_micron(device_t self, struct nand_chip *chip)
+{
+	uint8_t byte;
+
+	KASSERT(chip->nc_manf_id == NAND_MFR_MICRON);
+
+	nand_select(self, true);
+	nand_command(self, ONFI_READ_ID);
+	nand_address(self, 0x00);
+
+	switch (chip->nc_manf_id) {
+		/* three dummy reads */
+		nand_read_byte(self, &byte); /* vendor */
+		nand_read_byte(self, &byte); /* device */
+		nand_read_byte(self, &byte); /* unused */
+
+		/* this is the interesting one */
+		nand_read_byte(self, &byte);
+		/* TODO actually get info */
+		nand_select(self, false);
+		return 1;
+		
+		break;
+	default:
+		nand_select(self, false);
+		return 1;
+	}
+	
+	chip->nc_num_luns = 1;
+	chip->nc_lun_blocks = chip->nc_size / chip->nc_block_size;
+
+	nand_select(self, false);
+
+	return 0;
+}

Reply via email to