? sys/dev/nand/nand.c.brett
? sys/dev/nand/nand.c.good
? sys/dev/nand/nand_id.c
Index: sys/arch/arm/marvell/files.marvell
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/marvell/files.marvell,v
retrieving revision 1.7
diff -u -r1.7 files.marvell
--- sys/arch/arm/marvell/files.marvell	1 Aug 2012 10:38:41 -0000	1.7
+++ sys/arch/arm/marvell/files.marvell	30 Jan 2013 05:30:34 -0000
@@ -79,3 +79,8 @@
 device	mvsocts: sysmon_envsys
 attach	mvsocts at mvsoc
 file	arch/arm/marvell/mvsocts.c		mvsocts
+
+# NAND flash controller
+device	mvsocnand: nandbus
+attach	mvsocnand at mvsoc
+file	arch/arm/marvell/mvsocnand.c		mvsocnand
Index: sys/arch/arm/marvell/mvsoc.c
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/marvell/mvsoc.c,v
retrieving revision 1.10
diff -u -r1.10 mvsoc.c
--- sys/arch/arm/marvell/mvsoc.c	19 Oct 2012 06:14:44 -0000	1.10
+++ sys/arch/arm/marvell/mvsoc.c	30 Jan 2013 05:30:34 -0000
@@ -390,6 +390,7 @@
 
     { KIRKWOOD(88F6281),"mvsoctmr",0, MVSOC_TMR_BASE,	IRQ_DEFAULT },
     { KIRKWOOD(88F6281),"mvsocgpp",0, MVSOC_GPP_BASE,	KIRKWOOD_IRQ_GPIOLO7_0},
+    { KIRKWOOD(88F6281),"mvsocnand",0, MVSOC_NAND_READ,	IRQ_DEFAULT },
     { KIRKWOOD(88F6281),"mvsocrtc",0, KIRKWOOD_RTC_BASE,IRQ_DEFAULT },
     { KIRKWOOD(88F6281),"com",     0, MVSOC_COM0_BASE,	KIRKWOOD_IRQ_UART0INT },
     { KIRKWOOD(88F6281),"com",     1, MVSOC_COM1_BASE,	KIRKWOOD_IRQ_UART1INT },
Index: sys/arch/arm/marvell/mvsocnand.c
===================================================================
RCS file: sys/arch/arm/marvell/mvsocnand.c
diff -N sys/arch/arm/marvell/mvsocnand.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/arch/arm/marvell/mvsocnand.c	30 Jan 2013 05:30:34 -0000
@@ -0,0 +1,225 @@
+/*	$NetBSD$	*/
+/*-
+ * Copyright (c) 2012 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jeffrey C. Rizzo and Brett Slager.
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD");
+
+#include <sys/param.h>
+#include <sys/device.h>
+
+#include <arm/marvell/mvsocreg.h>
+#include <arm/marvell/mvsocvar.h>
+
+#include <dev/nand/nand.h>
+#include <dev/nand/onfi.h>
+
+static int mvsocnand_match(device_t, struct cfdata *, void *);
+static void mvsocnand_attach(device_t, device_t, void *);
+static int mvsocnand_detach(device_t, int);
+
+void mvsocnand_select(device_t, bool);
+void mvsocnand_command(device_t, uint8_t);
+void mvsocnand_address(device_t, uint8_t);
+void mvsocnand_read_1(device_t, uint8_t *);
+void mvsocnand_read_buf_1(device_t, void *, size_t);
+void mvsocnand_write_1(device_t, uint8_t);
+void mvsocnand_write_buf_1(device_t, const void *, size_t);
+
+struct mvsocnand_softc {
+	device_t sc_dev;
+	device_t sc_nanddev;
+
+	struct nand_interface sc_nand_if;
+	
+	bus_space_tag_t sc_iot;
+	bus_space_handle_t sc_ioh;
+
+	bus_addr_t	sc_cmd_reg;
+	bus_space_handle_t sc_data_ioh;
+};
+
+CFATTACH_DECL_NEW(mvsocnand, sizeof(struct mvsocnand_softc), mvsocnand_match,
+    mvsocnand_attach, mvsocnand_detach, NULL);
+
+
+static int
+mvsocnand_match(device_t parent, struct cfdata *match, void *aux)
+{
+	struct marvell_attach_args *mva = aux;
+
+	if (strcmp(mva->mva_name, match->cf_name) != 0)
+		return 0;
+
+	mva->mva_size = MVSOC_NAND_SIZE;
+	return 1;
+}
+
+static void
+mvsocnand_attach(device_t parent, device_t self, void *aux)
+{
+	struct mvsocnand_softc *sc = device_private(self);
+	struct marvell_attach_args *mva = aux;
+#define MVSOC_NAND_DATA_ADDRESS	0xd8000000
+#define MVSOC_NAND_DATA_SIZE	0x1000000
+	bus_addr_t address = MVSOC_NAND_DATA_ADDRESS;
+
+	aprint_normal(": Marvell SoC NAND controller\n");
+
+	sc->sc_dev = self;
+	sc->sc_iot = mva->mva_iot;
+
+	/* register mapping */
+	if (bus_space_subregion(mva->mva_iot, mva->mva_ioh,
+		mva->mva_offset, mva->mva_size, &sc->sc_ioh)) {
+		aprint_error_dev(self, "can't map registers\n");
+		return;
+	}
+
+	sc->sc_cmd_reg = MVSOC_NAND_CONTROL - MVSOC_NAND_READ;
+	
+	/* map data area?  XXX? riz */
+	if (bus_space_map(mva->mva_iot, address, MVSOC_NAND_DATA_SIZE, 0,
+		&sc->sc_data_ioh)) {
+		aprint_error_dev(self, "can't map data space\n");
+		return;
+	}
+	
+	nand_init_interface(&sc->sc_nand_if);
+
+	/* XXX all the MD functions should be mapped here */
+
+	sc->sc_nand_if.command = &mvsocnand_command;
+	sc->sc_nand_if.address = &mvsocnand_address;
+	sc->sc_nand_if.select = &mvsocnand_select;
+	sc->sc_nand_if.read_1 = &mvsocnand_read_1;
+	sc->sc_nand_if.read_buf_1 = &mvsocnand_read_buf_1;
+	sc->sc_nand_if.write_1 = &mvsocnand_write_1;
+	sc->sc_nand_if.write_buf_1 = &mvsocnand_write_buf_1;
+	
+#if 0
+	mvsocnand_select(self, true);
+	mvsocnand_command(self, ONFI_RESET);
+	mvsocnand_select(self, false);
+
+	mvsocnand_select(self, true);
+	mvsocnand_command(self, ONFI_READ_ID);
+	mvsocnand_address(self, 0x00);
+	for (i=0; i<8; i++)
+		mvsocnand_read_1(self, &id_data[i]);
+	mvsocnand_select(self, false);
+
+	for (i=0; i<8; i++)
+		printf("ID-%d %x ",i, id_data[i]);
+
+	mvsocnand_select(self, true);
+	mvsocnand_command(self, ONFI_READ_ID);
+	mvsocnand_address(self, 0x20);
+	mvsocnand_read_1(self, &onfi_signature[0]);
+	mvsocnand_read_1(self, &onfi_signature[1]);
+	mvsocnand_read_1(self, &onfi_signature[2]);
+	mvsocnand_read_1(self, &onfi_signature[3]);
+	mvsocnand_select(self, false);
+
+	if (onfi_signature[0] != 'O' || onfi_signature[1] != 'N' ||
+	    onfi_signature[2] != 'F' || onfi_signature[3] != 'I') {
+		aprint_normal(": Legacy NAND Flash (riz)\n");
+		printf("DATA: %x %x %x %x\n", onfi_signature[0],onfi_signature[1],onfi_signature[2],onfi_signature[3]);
+	} else
+		aprint_normal(": ONFI NAND Flash\n");
+#endif
+	
+	sc->sc_nanddev = nand_attach_mi(&sc->sc_nand_if, sc->sc_dev);
+}
+
+static int
+mvsocnand_detach(device_t device, int flags)
+{
+	/* XXX */
+	return 0;
+}
+
+void
+mvsocnand_select(device_t self, bool enable)
+{
+	struct mvsocnand_softc *sc = device_private(self);
+	uint32_t data;
+
+	data = bus_space_read_4(sc->sc_iot, sc->sc_ioh, sc->sc_cmd_reg);
+	data |= MVSOC_NAND_NFACTCENBOOT;
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, sc->sc_cmd_reg, data);
+}
+
+void
+mvsocnand_command(device_t self, uint8_t command)
+{
+	struct mvsocnand_softc *sc = device_private(self);
+
+	bus_space_write_1(sc->sc_iot, sc->sc_data_ioh, 0x01, command);
+}
+
+void
+mvsocnand_address(device_t self, uint8_t address)
+{
+	struct mvsocnand_softc *sc = device_private(self);
+
+	bus_space_write_1(sc->sc_iot, sc->sc_data_ioh, 0x02, address);
+}
+
+void
+mvsocnand_read_1(device_t self, uint8_t *data)
+{
+	struct mvsocnand_softc *sc = device_private(self);
+
+	*data = bus_space_read_1(sc->sc_iot, sc->sc_data_ioh, 0);
+}
+
+void
+mvsocnand_read_buf_1(device_t self, void *buf, size_t len)
+{
+	struct mvsocnand_softc *sc = device_private(self);
+
+	bus_space_read_multi_1(sc->sc_iot, sc->sc_data_ioh, 0, buf, len);
+}
+
+void
+mvsocnand_write_1(device_t self, uint8_t data)
+{
+	struct mvsocnand_softc *sc = device_private(self);
+
+	bus_space_write_1(sc->sc_iot, sc->sc_data_ioh, 0, data);
+}
+
+void
+mvsocnand_write_buf_1(device_t self, const void *buf, size_t len)
+{
+	struct mvsocnand_softc *sc = device_private(self);
+
+	bus_space_write_multi_1(sc->sc_iot, sc->sc_data_ioh, 0, buf, len);
+}
Index: sys/arch/arm/marvell/mvsocreg.h
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/marvell/mvsocreg.h,v
retrieving revision 1.3
diff -u -r1.3 mvsocreg.h
--- sys/arch/arm/marvell/mvsocreg.h	19 Oct 2012 06:14:44 -0000	1.3
+++ sys/arch/arm/marvell/mvsocreg.h	30 Jan 2013 05:30:34 -0000
@@ -67,6 +67,15 @@
 #define MVSOC_GPP_BASE			(MVSOC_DEVBUS_BASE + 0x0100)
 
 /*
+ * NAND Flash Registers
+ */
+#define MVSOC_NAND_READ			(MVSOC_DEVBUS_BASE + 0x418)
+#define MVSOC_NAND_WRITE		(MVSOC_DEVBUS_BASE + 0x41C)
+#define MVSOC_NAND_CONTROL		(MVSOC_DEVBUS_BASE + 0x470)
+#define MVSOC_NAND_SIZE	       	(MVSOC_NAND_CONTROL - MVSOC_NAND_READ + 4)
+#define MVSOC_NAND_NFACTCENBOOT		0x2
+
+/*
  * Two-Wire Serial Interface Registers
  */
 #define MVSOC_TWSI_BASE			(MVSOC_DEVBUS_BASE + 0x1000)
Index: sys/dev/nand/nand.c
===================================================================
RCS file: /cvsroot/src/sys/dev/nand/nand.c,v
retrieving revision 1.22
diff -u -r1.22 nand.c
--- sys/dev/nand/nand.c	3 Nov 2012 12:45:28 -0000	1.22
+++ sys/dev/nand/nand.c	30 Jan 2013 05:30:34 -0000
@@ -73,6 +73,7 @@
 
 #ifdef NAND_DEBUG
 int	nanddebug = NAND_DEBUG;
+//static void nand_chip_dump(struct nand_chip *);
 #endif
 
 struct flash_interface nand_flash_if = {
@@ -289,7 +290,7 @@
 	interface->write_buf_2 = NULL;
 	interface->write_1 = NULL;
 	interface->write_2 = NULL;
-	interface->busy = NULL;
+	interface->busy = &nand_default_busy;
 
 	/*-
 	 * most drivers dont want to change this, but some implement
@@ -354,6 +355,7 @@
 
 	nand_select(self, true);
 	nand_command(self, ONFI_RESET);
+	nand_busy(self);		/* allow time for reset */
 	nand_select(self, false);
 
 	/* check if the device implements the ONFI standard */
@@ -536,6 +538,7 @@
 	uint8_t	vendor[13], model[21];
 	int i;
 
+	/* Reminder: multibyte ONFI params as read are little endian */
 	if (nand_read_parameter_page(self, &params)) {
 		return 1;
 	}
@@ -574,6 +577,8 @@
 		chip->nc_flags |= NC_EXTENDED_PARAM;
 	}
 
+	chip->nc_read_time = le16toh(params.param_t_r);
+
 	return 0;
 }
 
@@ -628,6 +633,7 @@
 {
 	uint8_t status;
 
+	/* XXXXbds missing chip select/deselect */
 	nand_command(self, ONFI_READ_STATUS);
 	nand_busy(self);
 	nand_read_1(self, &status);
@@ -647,6 +653,8 @@
 static void
 nand_prepare_read(device_t self, flash_off_t row, flash_off_t column)
 {
+	/* chip select/deselect -- should be done by caller */
+
 	nand_command(self, ONFI_READ);
 	nand_address_column(self, row, column);
 	nand_command(self, ONFI_READ_START);
@@ -664,6 +672,7 @@
 	uint8_t *ecc;
 	int result;
 
+	/* XXXXbds missing chip select/deselect */
 	nand_prepare_read(self, offset, 0);
 
 	bs = chip->nc_ecc->necc_block_size;
@@ -749,13 +758,15 @@
 	struct nand_softc *sc = device_private(self);
 	struct nand_chip *chip = &sc->sc_chip;
 	size_t bs, cs, e, b;
+	int timeout = 1000000;	/* XXXXbds what is good here ? */
 	uint8_t status;
 	uint8_t *ecc;
 
+	/* XXXXbds missing chip select/deselect */
 	nand_command(self, ONFI_PAGE_PROGRAM);
 	nand_address_column(self, page, 0);
 
-	nand_busy(self);
+	nand_busy(self);	/* XXXX why here ? */
 
 	bs = chip->nc_ecc->necc_block_size;
 	cs = chip->nc_ecc->necc_code_size;
@@ -785,7 +796,29 @@
 
 	nand_command(self, ONFI_PAGE_PROGRAM_START);
 
-	nand_busy(self);
+//	if (sc->nand_if->busy == NULL) {
+	if (1) {
+		/*
+		 * no hardware status line -- loop checking status till
+		 * ready or timeout
+		 */
+		while (timeout) {
+			nand_command(self, ONFI_READ_STATUS);
+			delay(1);
+			nand_read_1(self, &status);
+			if (status & ONFI_STATUS_RDY)
+				break;
+			timeout--;
+		}
+		if (timeout == 0) {
+			aprint_error_dev(self,
+			    "nand_default_program_page() chip timeout!\n");
+		}
+	}
+	else {
+		nand_busy(self);
+		status = nand_get_status(self);
+	}
 
 	/* for debugging ecc */
 #if 0
@@ -800,7 +833,6 @@
 	printf("--------------\n");
 #endif
 
-	status = nand_get_status(self);
 	KASSERT(status & ONFI_STATUS_RDY);
 	if (status & ONFI_STATUS_FAIL) {
 		aprint_error_dev(self, "page program failed!\n");
@@ -817,6 +849,7 @@
 	struct nand_softc *sc = device_private(self);
 	struct nand_chip *chip = &sc->sc_chip;
 
+	/* XXXXbds missing chip select/deselect */
 	nand_prepare_read(self, page, chip->nc_page_size);
 
 	if (chip->nc_flags & NC_BUSWIDTH_16)
@@ -837,20 +870,43 @@
 {
 	struct nand_softc *sc = device_private(self);
 	struct nand_chip *chip = &sc->sc_chip;
+	int timeout = 1000000;	/* XXXXbds what is good here ? */
 	uint8_t status;
 
+	/* XXXXbds missing chip select/deselect */
 	nand_command(self, ONFI_PAGE_PROGRAM);
 	nand_address_column(self, offset, chip->nc_page_size);
-	nand_command(self, ONFI_PAGE_PROGRAM_START);
-
-	nand_busy(self);
 
 	if (chip->nc_flags & NC_BUSWIDTH_16)
 		nand_write_buf_2(self, oob, chip->nc_spare_size);
 	else
 		nand_write_buf_1(self, oob, chip->nc_spare_size);
 
-	status = nand_get_status(self);
+	nand_command(self, ONFI_PAGE_PROGRAM_START);
+
+	if (sc->nand_if->busy == NULL) {
+		/*
+		 * no hardware status line -- loop checking status till
+		 * ready or timeout
+		 */
+		while (timeout) {
+			nand_command(self, ONFI_READ_STATUS);
+			delay(1);
+			nand_read_1(self, &status);
+			if (status & ONFI_STATUS_RDY)
+				break;
+			timeout--;
+		}
+		if (timeout == 0) {
+			aprint_error_dev(self,
+			    "nand_write_oob() chip timeout!\n");
+		}
+	}
+	else {
+		nand_busy(self);
+		status = nand_get_status(self);
+	}
+
 	KASSERT(status & ONFI_STATUS_RDY);
 	if (status & ONFI_STATUS_FAIL)
 		return EIO;
@@ -987,17 +1043,44 @@
 int
 nand_erase_block(device_t self, size_t offset)
 {
+	struct nand_softc *sc = device_private(self);
+	int timeout = 1000000;	/* XXXXbds what is good here ? */
 	uint8_t status;
 
 	/* xxx calculate first page of block for address? */
 
+	/* XXXXbds missing chip select/deselect */
 	nand_command(self, ONFI_BLOCK_ERASE);
 	nand_address_row(self, offset);
 	nand_command(self, ONFI_BLOCK_ERASE_START);
 
-	nand_busy(self);
+	if (sc->nand_if->busy == NULL) {
+		/*
+		 * no hardware status line -- loop checking status till
+		 * ready or timeout
+		 */
+		while (timeout) {
+			nand_command(self, ONFI_READ_STATUS);
+			delay(1);
+			nand_read_1(self, &status);
+			if (status & ONFI_STATUS_RDY)
+				break;
+			timeout--;
+		}
+		if (timeout == 0) {
+			aprint_error_dev(self,
+			    "nand_erase_block() chip timeout!\n");
+		}
+	}
+	else {
+		nand_busy(self);
+		status = nand_get_status(self);
+	}
 
-	status = nand_get_status(self);
+	//if (!(status & ONFI_STATUS_RDY)) {
+	//	printf("AVOID PANIC - enter debugger.  status = %x\n", status);
+	//	Debugger();
+	//}
 	KASSERT(status & ONFI_STATUS_RDY);
 	if (status & ONFI_STATUS_FAIL) {
 		aprint_error_dev(self, "block erase failed!\n");
@@ -1033,6 +1116,28 @@
 	return;
 }
 
+void
+nand_default_busy(device_t self)
+{
+	struct nand_softc *sc = device_private(self);
+
+	switch (sc->sc_last_command) {
+	case ONFI_READ:
+	case ONFI_READ_START:
+		delay(sc->sc_chip.nc_read_time);
+		break;
+	case ONFI_READ_PARAMETER_PAGE:
+		/*
+		 * ONFI specifies an initial tR of 200 us for
+		 * reading the parameter page.
+		 */
+		delay(200);
+		break;
+	default:
+		break;
+	}
+}
+
 /* implementation of the block device API */
 
 int
@@ -1521,3 +1626,35 @@
 		return ENOTTY;
 	}
 }
+
+#if 0
+//#ifdef NAND_DEBUG
+static void
+nand_chip_dump(struct nand_chip *chip)
+{
+	printf("nc_ecc\t*%p\n",chip->nc_ecc);
+	printf("nc_oob_cache\t*%p\n",chip->nc_oob_cache);
+	printf("nc_page_cache\t*%p\n",chip->nc_page_cache);
+	printf("nc_ecc_cache\t*%p\n",chip->nc_ecc_cache);
+	printf("nc_size\t%" PRIu64 "\n",chip->nc_size);
+	printf("nc_page_size\t%" PRIu32 "\n",chip->nc_page_size);
+	printf("nc_block_size\t%" PRIu32 "\n",chip->nc_block_size);
+	printf("nc_spare_size\t%" PRIu32 "\n",chip->nc_spare_size);
+	printf("nc_lun_blocks\t%" PRIu32 "\n",chip->nc_lun_blocks);
+	printf("nc_flags\t0x%" PRIx32 "\n",chip->nc_flags);
+	printf("nc_quirks\t0x%" PRIx32 "\n",chip->nc_quirks);
+	printf("nc_page_shift\t0x%" PRIx32 "\n",chip->nc_page_shift);
+	printf("nc_page_mask\t0x%" PRIx32 "\n",chip->nc_page_mask);
+	printf("nc_block_shift\t0x%" PRIx32 "\n",chip->nc_block_shift);
+	printf("nc_block_mask\t0x%" PRIx32 "\n",chip->nc_block_mask);
+	printf("nc_num_luns\t%hhu\n",chip->nc_num_luns);
+	printf("nc_manf_id\t%#hhx\n",chip->nc_manf_id);
+	printf("nc_dev_id\t%#hhx\n",chip->nc_dev_id);
+	printf("nc_addr_cycles_row\t%hhu\n",chip->nc_addr_cycles_row);
+	printf("nc_addr_cycles_column\t%hhu\n",chip->nc_addr_cycles_column);
+	printf("nc_badmarker_offs\t%hhu\n",chip->nc_badmarker_offs);
+	printf("nc_isonfi\t%s\n",chip->nc_isonfi?"true":"false");
+	printf("nc_read_time\t%u\n",chip->nc_read_time);
+	printf("chip pointer:\t%p\n",chip);
+}
+#endif
Index: sys/dev/nand/nand.h
===================================================================
RCS file: /cvsroot/src/sys/dev/nand/nand.h,v
retrieving revision 1.16
diff -u -r1.16 nand.h
--- sys/dev/nand/nand.h	3 Nov 2012 12:12:48 -0000	1.16
+++ sys/dev/nand/nand.h	30 Jan 2013 05:30:34 -0000
@@ -129,6 +129,9 @@
 	uint8_t nc_addr_cycles_column;	/* column cycles for addressing */
 	uint8_t nc_badmarker_offs;	/* offset for marking bad blocks */
 	bool nc_isonfi;			/* if the device is onfi compliant */
+	uint16_t nc_read_time;		/* chip maximum read time tR (us) */
+	uint16_t nc_prog_time;		/* chip max page program time (us) */
+	uint16_t nc_block_erase_time;	/* chip max block erase time (us) */
 };
 
 struct nand_write_cache {
@@ -155,6 +158,7 @@
 	size_t sc_part_offset;
 	size_t sc_part_size;
 	kmutex_t sc_device_lock; /* serialize access to chip */
+	uint8_t sc_last_command; /* last command issued */
 	struct flash_io sc_flash_io;
 };
 
@@ -197,6 +201,17 @@
 	struct nand_interface *naa_nand_if;
 };
 
+/*
+ * default functions for driver development
+ */
+void nand_default_select(device_t, bool);
+int nand_default_ecc_compute(device_t, const uint8_t *, uint8_t *);
+int nand_default_ecc_correct(device_t, uint8_t *, const uint8_t *,
+    const uint8_t *);
+int nand_default_read_page(device_t, size_t, uint8_t *);
+int nand_default_program_page(device_t, size_t, const uint8_t *);
+void nand_default_busy(device_t);
+
 static inline void
 nand_busy(device_t device)
 {
@@ -207,9 +222,10 @@
 
 	sc->nand_if->select(sc->controller_dev, true);
 
-	if (sc->nand_if->busy != NULL) {
+	if (sc->nand_if->busy != &nand_default_busy)
 		sc->nand_if->busy(sc->controller_dev);
-	}
+	else
+		sc->nand_if->busy(device);
 
 	sc->nand_if->select(sc->controller_dev, false);
 }
@@ -245,6 +261,7 @@
 	KASSERT(sc->controller_dev != NULL);
 
 	sc->nand_if->command(sc->controller_dev, command);
+	sc->sc_last_command = command;
 }
 
 static inline void
@@ -429,6 +446,12 @@
 int nand_read_parameters_micron(device_t, struct nand_chip *);
 int nand_read_parameters_samsung(device_t, struct nand_chip *);
 
+/* match out of legacy device table */
+int nand_match_parameters_legacy(device_t, struct nand_chip *);
+
+/* match out of legacy device table */
+int nand_match_parameters_legacy(device_t, struct nand_chip *);
+
 /* debug inlines */
 
 static inline void
@@ -472,16 +495,6 @@
 void nand_read_id(device_t, uint8_t *, uint8_t *);
 int nand_read_parameter_page(device_t, struct onfi_parameter_page *);
 
-/*
- * default functions for driver development
- */
-void nand_default_select(device_t, bool);
-int nand_default_ecc_compute(device_t, const uint8_t *, uint8_t *);
-int nand_default_ecc_correct(device_t, uint8_t *, const uint8_t *,
-    const uint8_t *);
-int nand_default_read_page(device_t, size_t, uint8_t *);
-int nand_default_program_page(device_t, size_t, const uint8_t *);
-
 static inline void nand_busy(device_t);
 static inline void nand_select(device_t, bool);
 static inline void nand_command(device_t, uint8_t);
Index: sys/dev/nand/nand_samsung.c
===================================================================
RCS file: /cvsroot/src/sys/dev/nand/nand_samsung.c,v
retrieving revision 1.9
diff -u -r1.9 nand_samsung.c
--- sys/dev/nand/nand_samsung.c	3 Nov 2012 12:12:48 -0000	1.9
+++ sys/dev/nand/nand_samsung.c	30 Jan 2013 05:30:34 -0000
@@ -87,6 +87,7 @@
 		/* From the documentation */
 		chip->nc_addr_cycles_column = 2;
 		chip->nc_addr_cycles_row = 3;
+		chip->nc_read_time = 25;
 
 		switch (params2 & NAND_SAMSUNG_PAGEMASK) {
 		case 0x0:
