Module Name:    src
Committed By:   phx
Date:           Sat Dec 17 19:42:41 UTC 2011

Modified Files:
        src/sys/dev/nor: cfi.c cfi.h cfi_0002.c

Log Message:
- In cfi_probe() iterate over all chip widths for every port width to find
  x8/x16 configurations, or two x8 chips forming a x16 port width.
- The offset in cfi_cmd() is now always given for 64-bit port width.
  It will be scaled down for the actual port width to avoid problems
  with 0x2aa -> 0x554 instead of 0x555.
- Added missing cfi_reset_default() in cfi_jedec_id(). The reset is
  needed, because the chip was still in CFI-Query mode.
- Removed everything dealing with cfi_opmodes. It only complicates things
  and I found no reason for keeping them. The port width and chip width
  is known, so I just introduced a new cfi_read_qry() function which reads
  a single word using bus_space_read_N() from the QRY structure, which
  can be checked for 'Q', 'R' and 'Y'. That's all we need, before
  reading and unpacking the whole QRY and PRI structures.
- Added two new fields, cfi_unlock_addr1 and cfi_unlock_addr2 to
  the cfi struct. The unlock offsets should be kept variable, depending
  on the manufacturer or command set version.

Changes have been discussed with cliff@.


To generate a diff of this commit:
cvs rdiff -u -r1.6 -r1.7 src/sys/dev/nor/cfi.c
cvs rdiff -u -r1.5 -r1.6 src/sys/dev/nor/cfi.h src/sys/dev/nor/cfi_0002.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/nor/cfi.c
diff -u src/sys/dev/nor/cfi.c:1.6 src/sys/dev/nor/cfi.c:1.7
--- src/sys/dev/nor/cfi.c:1.6	Tue Aug  2 03:37:25 2011
+++ src/sys/dev/nor/cfi.c	Sat Dec 17 19:42:41 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: cfi.c,v 1.6 2011/08/02 03:37:25 cliff Exp $	*/
+/*	$NetBSD: cfi.c,v 1.7 2011/12/17 19:42:41 phx Exp $	*/
 /*-
  * Copyright (c) 2011 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -33,7 +33,7 @@
 #include "opt_cfi.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cfi.c,v 1.6 2011/08/02 03:37:25 cliff Exp $"); 
+__KERNEL_RCSID(0, "$NetBSD: cfi.c,v 1.7 2011/12/17 19:42:41 phx Exp $"); 
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -48,7 +48,6 @@ __KERNEL_RCSID(0, "$NetBSD: cfi.c,v 1.6 
 #include <dev/nor/cfi_0002.h>
 
 
-static bool cfi_chip_query(struct cfi * const);
 static int  cfi_scan_media(device_t self, struct nor_chip *chip);
 static void cfi_init(device_t);
 static void cfi_select(device_t, bool);
@@ -64,9 +63,7 @@ static void cfi_write_4(device_t, flash_
 static void cfi_write_buf_1(device_t, flash_off_t, const uint8_t *, size_t);
 static void cfi_write_buf_2(device_t, flash_off_t, const uint16_t *, size_t);
 static void cfi_write_buf_4(device_t, flash_off_t, const uint32_t *, size_t);
-static void cfi_jedec_id_1(struct cfi * const );
-static void cfi_jedec_id_2(struct cfi * const );
-static void cfi_jedec_id_4(struct cfi * const );
+static uint8_t cfi_read_qry(struct cfi * const, bus_size_t);
 static bool cfi_jedec_id(struct cfi * const);
 static bool cfi_emulate(struct cfi * const);
 static const struct cfi_jedec_tab * cfi_jedec_search(struct cfi *);
@@ -76,59 +73,6 @@ static void cfi_jedec_fill(struct cfi * 
 static void cfi_hexdump(flash_off_t, void * const, u_int, u_int);
 #endif
 
-
-
-/*
- * NOTE these opmode tables are informed by "Table 1. CFI Query Read"
- * in Intel "Common Flash Interface (CFI) and Command Sets"
- * Application Note 646, April 2000
- *
- * Assume the byte order of the flash (and of the signature there)
- * is the same as host byte order. The Intel App. Note describes the
- * little endian variant.
- *
- * XXX down-sized, interleaved & multi-chip opmodes not yet supported
- */
-
-#if BYTE_ORDER == BIG_ENDIAN
-/* BIG ENDIAN host */
-/* 1-byte access */
-static const struct cfi_opmodes cfi_opmodes_1[] = {
-	{ 0, 0, 0, 0x10,  3, "QRY", "x8 device operating in 8-bit mode" },
-};
-
-/* 2-byte access */
-static const struct cfi_opmodes cfi_opmodes_2[] = {
-	{ 1, 1, 0, 0x20,  6, "\0Q\0R\0Y",
-		"x16 device operating in 16-bit mode" },
-};
-
-/* 4-byte access */
-static const struct cfi_opmodes cfi_opmodes_4[] = {
-	{ 2, 2, 0, 0x40, 12, "\0\0\0Q\0\0\0R\0\0\0Y",
-		"x32 device operating in 32-bit mode" },
-};
-#else
-/* LITTLE ENDIAN host */
-/* 1-byte access */
-static const struct cfi_opmodes cfi_opmodes_1[] = {
-	{ 0, 0, 0, 0x10,  3, "QRY", "x8 device operating in 8-bit mode" },
-};
-
-/* 2-byte access */
-static const struct cfi_opmodes cfi_opmodes_2[] = {
-	{ 1, 1, 0, 0x20,  6, "Q\0R\0Y\0",
-		"x16 device operating in 16-bit mode" },
-};
-
-/* 4-byte access */
-static const struct cfi_opmodes cfi_opmodes_4[] = {
-	{ 2, 2, 0, 0x40, 12, "Q\0\0\0R\0\0\0Y\0\0\0",
-		"x32 device operating in 32-bit mode" },
-};
-#endif
-
-
 #define LOG2_64K	16
 #define LOG2_128K	17
 #define LOG2_256K	18
@@ -166,7 +110,6 @@ const struct cfi_jedec_tab cfi_jedec_tab
 		.jt_write_nbyte_time_max = 0,
 		.jt_erase_blk_time_max = 1,
 		.jt_erase_chip_time_max = 1,
-		.jt_opmode = &cfi_opmodes_1[0],
 	},
 	{
 		.jt_name = "Pm39LV010",
@@ -188,7 +131,6 @@ const struct cfi_jedec_tab cfi_jedec_tab
 		.jt_write_nbyte_time_max = 0,
 		.jt_erase_blk_time_max = 1,
 		.jt_erase_chip_time_max = 1,
-		.jt_opmode = &cfi_opmodes_1[0],
 	},
 };
 
@@ -307,7 +249,7 @@ const struct nor_interface nor_interface
 		cfi_unpack_1(data[0x39]);				\
     } while (0)
 
-#define CFI_QRY_UNPACK_COMMON(cfi, data, type, found)			\
+#define CFI_QRY_UNPACK_COMMON(cfi, data, type)				\
     do {								\
 	struct cfi_query_data * const qryp = &cfi->cfi_qry_data;	\
 									\
@@ -321,13 +263,8 @@ const struct nor_interface nor_interface
 		    (cfi_unpack_1(data[qryp->addr_pri + 2]) == 'I')) {	\
 			type *pri_data = &data[qryp->addr_pri];		\
 			cfi_unpack_pri_0002(qryp, pri_data);		\
-			found = true;					\
 			break;						\
 		}							\
-	default:							\
-		printf("%s: unsupported id_pri=%#x\n",			\
-			__func__, qryp->id_pri);			\
-		break;	/* unknown command set */			\
 	}								\
     } while (0)
 
@@ -352,103 +289,49 @@ const struct nor_interface nor_interface
 #endif
 
 
-/*
- * cfi_chip_query_opmode - determine operational mode based on QRY signature
- */
-static bool
-cfi_chip_query_opmode(struct cfi *cfi, uint8_t *data,
-    const struct cfi_opmodes *tab, u_int nentries)
-{
-	for (u_int i=0; i < nentries; i++) {
-		if (memcmp(&data[tab[i].qsa], tab[i].sig, tab[i].len) == 0) {
-			cfi->cfi_opmode = &tab[i];
-			return true;
-		}
-	}
-	return false;
-}
-
-static bool
+static void
 cfi_chip_query_1(struct cfi * const cfi)
 {
 	uint8_t data[0x80];
 
 	bus_space_read_region_1(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
-		__arraycount(data));
-
+	    __arraycount(data));
 	CFI_DUMP_QRY(0, data, sizeof(data), 1);
-
-	bool found = cfi_chip_query_opmode(cfi, data, cfi_opmodes_1,
-		__arraycount(cfi_opmodes_1));
-
-	if (found) {
-		CFI_QRY_UNPACK_COMMON(cfi, data, uint8_t, found);
-	}
-
-	return found;
+	CFI_QRY_UNPACK_COMMON(cfi, data, uint8_t);
 }
 
-static bool
+static void
 cfi_chip_query_2(struct cfi * const cfi)
 {
 	uint16_t data[0x80];
 
 	bus_space_read_region_2(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
-		__arraycount(data));
-
+	    __arraycount(data));
 	CFI_DUMP_QRY(0, data, sizeof(data), 2);
-
-	bool found = cfi_chip_query_opmode(cfi, (uint8_t *)data,
-		cfi_opmodes_2, __arraycount(cfi_opmodes_2));
-
-	if (found) {
-		CFI_QRY_UNPACK_COMMON(cfi, data, uint16_t, found);
-	}
-
-	return found;
+	CFI_QRY_UNPACK_COMMON(cfi, data, uint16_t);
 }
 
-static bool
+static void
 cfi_chip_query_4(struct cfi * const cfi)
 {
 	uint32_t data[0x80];
 
 	bus_space_read_region_4(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
-		__arraycount(data));
-
+	    __arraycount(data));
 	CFI_DUMP_QRY(0, data, sizeof(data), 4);
-
-	bool found = cfi_chip_query_opmode(cfi, (uint8_t *)data,
-		cfi_opmodes_4, __arraycount(cfi_opmodes_4));
-
-	if (found) {
-		CFI_QRY_UNPACK_COMMON(cfi, data, uint32_t, found);
-	}
-
-	return found;
+	CFI_QRY_UNPACK_COMMON(cfi, data, uint32_t);
 }
 
-static bool
+static void
 cfi_chip_query_8(struct cfi * const cfi)
 {
 #ifdef NOTYET
 	uint64_t data[0x80];
 
 	bus_space_read_region_8(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
-		__arraycount(data));
-
+	    __arraycount(data));
 	CFI_DUMP_QRY(0, data, sizeof(data), 8);
-
-	bool found = cfi_chip_query_opmode(cfi, (uint8_t *)data,
-		cfi_opmodes_8, __arraycount(cfi_opmodes_8));
-
-	if (found) {
-		CFI_QRY_UNPACK_COMMON(cfi, data, uint64_t, found);
-	}
-
-	return found;
-#else
-	return false;
+	CFI_QRY_UNPACK_COMMON(cfi, data, uint64_t);
 #endif
 }
 
@@ -460,43 +343,57 @@ cfi_chip_query_8(struct cfi * const cfi)
 static bool
 cfi_chip_query(struct cfi * const cfi)
 {
-	bool found = false;
 	const bus_size_t cfi_query_offset[] = {
-		CFI_QUERY_MODE_ADDRESS,
-		CFI_QUERY_MODE_ALT_ADDRESS
+		CFI_QUERY_MODE_ADDR,
+		CFI_QUERY_MODE_ALT_ADDR
 	};
 
 	KASSERT(cfi != NULL);
 	KASSERT(cfi->cfi_bst != NULL);
 
-	for (int j=0; !found && j < __arraycount(cfi_query_offset); j++) {
+	for (int j=0; j < __arraycount(cfi_query_offset); j++) {
 
 		cfi_reset_default(cfi);
 		cfi_cmd(cfi, cfi_query_offset[j], CFI_QUERY_DATA);
 
-		switch(cfi->cfi_portwidth) {
-		case 0:
-			found = cfi_chip_query_1(cfi);
-			break;
-		case 1:
-			found = cfi_chip_query_2(cfi);
-			break;
-		case 2:
-			found = cfi_chip_query_4(cfi);
-			break;
-		case 3:
-			found = cfi_chip_query_8(cfi);
-			break;
-		default:
-			panic("%s: bad portwidth %d\n",
-				__func__, cfi->cfi_portwidth);
+		if (cfi_read_qry(cfi, 0x10) == 'Q' &&
+		    cfi_read_qry(cfi, 0x11) == 'R' &&
+		    cfi_read_qry(cfi, 0x12) == 'Y') {
+			switch(cfi->cfi_portwidth) {
+			case 0:
+				cfi_chip_query_1(cfi);
+				break;
+			case 1:
+				cfi_chip_query_2(cfi);
+				break;
+			case 2:
+				cfi_chip_query_4(cfi);
+				break;
+			case 3:
+				cfi_chip_query_8(cfi);
+				break;
+			default:
+				panic("%s: bad portwidth %d\n",
+				    __func__, cfi->cfi_portwidth);
+			}
+
+			switch (cfi->cfi_qry_data.id_pri) {
+			case 0x0002:
+				cfi->cfi_unlock_addr1 = CFI_AMD_UNLOCK_ADDR1;
+				cfi->cfi_unlock_addr2 = CFI_AMD_UNLOCK_ADDR2;
+				break;
+			default:
+				DPRINTF(("%s: unsupported CFI cmdset %#04x\n",
+				    __func__, cfi->cfi_qry_data.id_pri));
+				return false;
+			}
+
+			cfi->cfi_emulated = false;
+			return true;
 		}
 	}
 
-	if (found)
-		cfi->cfi_emulated = false;
-
-	return found;
+	return false;
 }
 
 /*
@@ -508,9 +405,7 @@ cfi_chip_query(struct cfi * const cfi)
  *   otherwise fail.
  *
  * NOTE:
- *   striped NOR chips design not supported yet,
- *   so force portwidth=chipwidth for now
- *   eventually permute portwidth seperately
+ *   striped NOR chips design not supported yet
  */
 bool
 cfi_probe(struct cfi * const cfi)
@@ -519,17 +414,24 @@ cfi_probe(struct cfi * const cfi)
 
 	KASSERT(cfi != NULL);
 
-	for (u_int cw = 0; cw < 3; cw++) {
-		cfi->cfi_portwidth = 		/* XXX */
-		cfi->cfi_chipwidth = cw;
-		found = cfi_chip_query(cfi);
-		cfi_jedec_id(cfi);
-		if (! found)
-			found = cfi_emulate(cfi);
-		if (found)
-			break;
+	/* XXX set default unlock address for cfi_jedec_id() */
+	cfi->cfi_unlock_addr1 = CFI_AMD_UNLOCK_ADDR1;
+	cfi->cfi_unlock_addr2 = CFI_AMD_UNLOCK_ADDR2;
+
+	for (u_int pw = 0; pw < 3; pw++) {
+		for (u_int cw = 0; cw <= pw; cw++) {
+			cfi->cfi_portwidth = pw;
+			cfi->cfi_chipwidth = cw;
+			found = cfi_chip_query(cfi);
+			cfi_jedec_id(cfi);
+			if (! found)
+				found = cfi_emulate(cfi);
+			if (found)
+				goto exit_qry;
+		}
 	}
 
+    exit_qry:
 	cfi_reset_default(cfi);		/* exit QRY mode */
 	return found;
 }
@@ -539,7 +441,6 @@ cfi_identify(struct cfi * const cfi)
 {
 	const bus_space_tag_t bst = cfi->cfi_bst;
 	const bus_space_handle_t bsh = cfi->cfi_bsh;
-	bool found;
 
 	KASSERT(cfi != NULL);
 	KASSERT(bst != NULL);
@@ -548,11 +449,7 @@ cfi_identify(struct cfi * const cfi)
 	cfi->cfi_bst = bst;		/* restore bus space */
 	cfi->cfi_bsh = bsh;		/*  "       "   "    */
 
-	found = cfi_probe(cfi);
-
-	cfi_reset_default(cfi);	/* exit QRY mode */
-
-	return found;
+	return cfi_probe(cfi);
 }
 
 static int
@@ -585,10 +482,6 @@ cfi_scan_media(device_t self, struct nor
 	case 0x0002:
 		cfi_0002_init(sc, cfi, chip);
 		break;
-	default:
-		aprint_error_dev(self, "unsupported CFI cmdset %#04x\n",
-			cfi->cfi_qry_data.id_pri);
-		return -1;
 	}
 
 	return 0;
@@ -669,29 +562,48 @@ cfi_write_buf_4(device_t self, flash_off
 {
 }
 
+/*
+ * cfi_cmd - write a CFI command word.
+ *
+ * The offset 'off' is given for 64-bit port width and will be scaled
+ * down to the actual port width of the chip.
+ * The command word will be constructed out of 'val' regarding port- and
+ * chip width.
+ */
 void
 cfi_cmd(struct cfi * const cfi, bus_size_t off, uint32_t val)
 {
 	const bus_space_tag_t bst = cfi->cfi_bst;
 	bus_space_handle_t bsh = cfi->cfi_bsh;
+	uint64_t cmd;
+	int cw, pw;
 
-	off <<= cfi->cfi_portwidth;
+	off >>= 3 - cfi->cfi_portwidth;
 
-	DPRINTF(("%s: %p %x %x %x\n", __func__, bst, bsh, off, val));
+	pw = 1 << cfi->cfi_portwidth;
+	cw = 1 << cfi->cfi_chipwidth;
+	cmd = 0;
+	while (pw > 0) {
+		cmd <<= cw << 3;
+		cmd += val;
+		pw -= cw;
+	}
 
-	switch(cfi->cfi_portwidth) {
+	DPRINTF(("%s: %p %x %x %" PRIx64 "\n", __func__, bst, bsh, off, cmd));
+
+	switch (cfi->cfi_portwidth) {
 	case 0:
-		bus_space_write_1(bst, bsh, off, (uint8_t)val);
+		bus_space_write_1(bst, bsh, off, cmd);
 		break;
 	case 1:
-		bus_space_write_2(bst, bsh, off, val);
+		bus_space_write_2(bst, bsh, off, cmd);
 		break;
 	case 2:
-		bus_space_write_4(bst, bsh, off, (uint32_t)val);
+		bus_space_write_4(bst, bsh, off, cmd);
 		break;
 #ifdef NOTYET
 	case 3:
-		bus_space_write_4(bst, bsh, off, (uint64_t)val);
+		bus_space_write_8(bst, bsh, off, cmd);
 		break;
 #endif
 	default:
@@ -700,14 +612,44 @@ cfi_cmd(struct cfi * const cfi, bus_size
 	}
 }
 
+static uint8_t
+cfi_read_qry(struct cfi * const cfi, bus_size_t off)
+{
+	const bus_space_tag_t bst = cfi->cfi_bst;
+	bus_space_handle_t bsh = cfi->cfi_bsh;
+	uint8_t data;
+
+	off <<= cfi->cfi_portwidth;
+
+	switch (cfi->cfi_portwidth) {
+	case 0:
+		data = bus_space_read_1(bst, bsh, off);
+		break;
+	case 1:
+		data = bus_space_read_2(bst, bsh, off);
+		break;
+	case 2:
+		data = bus_space_read_4(bst, bsh, off);
+		break;
+	case 3:
+		data = bus_space_read_8(bst, bsh, off);
+		break;
+	default:
+		data = ~0;
+		break;
+	}
+	return data;
+}
+
 /*
  * cfi_reset_default - when we don't know which command will work, use both
  */
 void
 cfi_reset_default(struct cfi * const cfi)
 {
-	cfi_cmd(cfi, CFI_ADDRESS_ANY, CFI_RESET_DATA);
-	cfi_cmd(cfi, CFI_ADDRESS_ANY, CFI_ALT_RESET_DATA);
+
+	cfi_cmd(cfi, CFI_ADDR_ANY, CFI_RESET_DATA);
+	cfi_cmd(cfi, CFI_ADDR_ANY, CFI_ALT_RESET_DATA);
 }
 
 /*
@@ -716,7 +658,8 @@ cfi_reset_default(struct cfi * const cfi
 void
 cfi_reset_std(struct cfi * const cfi)
 {
-	cfi_cmd(cfi, CFI_ADDRESS_ANY, CFI_RESET_DATA);
+
+	cfi_cmd(cfi, CFI_ADDR_ANY, CFI_RESET_DATA);
 }
 
 /*
@@ -725,7 +668,8 @@ cfi_reset_std(struct cfi * const cfi)
 void
 cfi_reset_alt(struct cfi * const cfi)
 {
-	cfi_cmd(cfi, CFI_ADDRESS_ANY, CFI_ALT_RESET_DATA);
+
+	cfi_cmd(cfi, CFI_ADDR_ANY, CFI_ALT_RESET_DATA);
 }
 
 static void
@@ -815,9 +759,10 @@ cfi_jedec_id(struct cfi * const cfi)
 
 	DPRINTF(("%s\n", __func__));
 
-	cfi_cmd(cfi, 0x555, 0xaa);
-	cfi_cmd(cfi, 0x2aa, 0x55);
-	cfi_cmd(cfi, 0x555, 0x90);
+	cfi_reset_default(cfi);
+	cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0xaa);
+	cfi_cmd(cfi, cfi->cfi_unlock_addr2, 0x55);
+	cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0x90);
 
 	switch(cfi->cfi_portwidth) {
 	case 0:
@@ -881,7 +826,6 @@ cfi_jedec_fill(struct cfi *cfi, const st
 {
 
 	cfi->cfi_name = jt->jt_name;
-	cfi->cfi_opmode = jt->jt_opmode;
 
 	struct cfi_query_data *qryp = &cfi->cfi_qry_data;
 	memset(&qryp, 0, sizeof(*qryp));
@@ -926,7 +870,8 @@ cfi_print(device_t self, struct cfi * co
 		cfi->cfi_id_data.id_did[0],
 		cfi->cfi_id_data.id_did[1],
 		cfi->cfi_id_data.id_did[2]);
-	aprint_normal_dev(self, "%s\n", cfi->cfi_opmode->str);
+	aprint_normal_dev(self, "x%u device operating in %u-bit mode\n",
+		8 << cfi->cfi_portwidth, 8 << cfi->cfi_chipwidth);
 	aprint_normal_dev(self, "sw bits lo=%#x hi=%#x\n",
 		cfi->cfi_id_data.id_swb_lo,
 		cfi->cfi_id_data.id_swb_hi);

Index: src/sys/dev/nor/cfi.h
diff -u src/sys/dev/nor/cfi.h:1.5 src/sys/dev/nor/cfi.h:1.6
--- src/sys/dev/nor/cfi.h:1.5	Tue Aug  2 01:11:08 2011
+++ src/sys/dev/nor/cfi.h	Sat Dec 17 19:42:41 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: cfi.h,v 1.5 2011/08/02 01:11:08 cliff Exp $	*/
+/*	$NetBSD: cfi.h,v 1.6 2011/12/17 19:42:41 phx Exp $	*/
 
 #ifndef _CFI_H_
 #define _CFI_H_
@@ -120,19 +120,6 @@ struct cfi_jedec_id_data {
 	uint8_t		id_swb_hi;	/* upper software bits */
 };
 
-/*
- * table entry used to determine operating mode by QRY signature
- */
-struct cfi_opmodes {
-	uint8_t		portwidth;	/* (1<<N) bytes */
-	uint8_t		chipwidth;	/* (1<<N) bytes */
-	uint8_t		interleave;	/* (1<<N) bytes */
-	uint8_t		qsa;		/* Query Start Address (in bytes) */
-	uint8_t		len;		/* signature length */
-	const uint8_t  *sig;		/* signature */
-	const char     *str;		/* descriptive string */
-};
-
 struct cfi;	/* fwd ref */
 
 struct cfi_ops {
@@ -188,12 +175,12 @@ struct cfi {
 	uint8_t			cfi_portwidth;	/* port width, 1<<N bytes */
 	uint8_t			cfi_chipwidth;	/* chip width, 1<<N bytes */
 	bool			cfi_emulated;	/* ary data are faked */
+	bus_size_t		cfi_unlock_addr1;
+	bus_size_t		cfi_unlock_addr2;
 	struct cfi_query_data	cfi_qry_data;	/* CFI Query data */
 	struct cfi_jedec_id_data
 				cfi_id_data;	/* JEDEC ID data */
 	const char	       *cfi_name;	/* optional chip name */
-	const struct cfi_opmodes 
-			       *cfi_opmode;
 	struct cfi_ops		cfi_ops;	/* chip dependent functions */
 	u_long			cfi_yield_time;	/* thresh. for yield in wait */
 #ifdef CFI_0002_STATS
@@ -230,21 +217,20 @@ struct cfi_jedec_tab {
 	uint8_t		jt_write_nbyte_time_max;	/* typ<<N msec */
 	uint8_t		jt_erase_blk_time_max;		/* typ<<N msec */
 	uint8_t		jt_erase_chip_time_max;		/* typ<<N msec */
-	/* XXX operation mode, perhaps cannot be tabulated */
-	const struct cfi_opmodes
-		       *jt_opmode;
 };
 
 
 enum {
-	CFI_ADDRESS_ANY = 0x00,		    /* XXX "don't care" */
-
+	CFI_ADDR_ANY = 0x00*8,		    /* XXX "don't care" */
 	CFI_RESET_DATA = 0xf0,
 	CFI_ALT_RESET_DATA = 0xff,
 
-	CFI_QUERY_MODE_ADDRESS = 0x55,	    /* some devices accept anything */
-	CFI_QUERY_MODE_ALT_ADDRESS = 0x555,
+	CFI_QUERY_MODE_ADDR = 0x55*8,	    /* some devices accept anything */
+	CFI_QUERY_MODE_ALT_ADDR = 0x555*8,
 	CFI_QUERY_DATA = 0x98,
+
+	CFI_AMD_UNLOCK_ADDR1 = 0x555*8,
+	CFI_AMD_UNLOCK_ADDR2 = 0x555*4,
 };
 
 static inline void
Index: src/sys/dev/nor/cfi_0002.c
diff -u src/sys/dev/nor/cfi_0002.c:1.5 src/sys/dev/nor/cfi_0002.c:1.6
--- src/sys/dev/nor/cfi_0002.c:1.5	Wed Nov 23 21:02:28 2011
+++ src/sys/dev/nor/cfi_0002.c	Sat Dec 17 19:42:41 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: cfi_0002.c,v 1.5 2011/11/23 21:02:28 phx Exp $	*/
+/*	$NetBSD: cfi_0002.c,v 1.6 2011/12/17 19:42:41 phx Exp $	*/
 /*-
  * Copyright (c) 2011 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -31,7 +31,7 @@
 #include "opt_flash.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cfi_0002.c,v 1.5 2011/11/23 21:02:28 phx Exp $"); 
+__KERNEL_RCSID(0, "$NetBSD: cfi_0002.c,v 1.6 2011/12/17 19:42:41 phx Exp $"); 
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -291,17 +291,18 @@ cfi_0002_program_page(device_t self, fla
 
 	bus_size_t count = chip->nc_page_size >> cfi->cfi_portwidth;
 							/* #words/page */
-	bus_size_t sa = offset >> cfi->cfi_portwidth;	/* sector addr */
+	bus_size_t sa = offset << (3 - cfi->cfi_portwidth);
+							/* sector addr */
 	uint32_t wc = count - 1;			/* #words - 1 */
 
 	int error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_dflt(cfi));
 	if (error != 0)
 		return ETIMEDOUT;
 
-	cfi_cmd(cfi, 0x555, 0xaa); /* unlock 1 */
-	cfi_cmd(cfi, 0x2aa, 0x55); /* unlock 2 */
-	cfi_cmd(cfi, sa,    0x25); /* Write To Buffer */
-	cfi_cmd(cfi, sa,    wc);
+	cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0xaa);
+	cfi_cmd(cfi, cfi->cfi_unlock_addr2, 0x55);
+	cfi_cmd(cfi, sa,                    0x25); /* Write To Buffer */
+	cfi_cmd(cfi, sa,                    wc);
 
 	switch(cfi->cfi_portwidth) {
 	case 0:
@@ -320,7 +321,7 @@ cfi_0002_program_page(device_t self, fla
 		panic("%s: bad port width %d\n", __func__, cfi->cfi_portwidth);
 	};
 
-	cfi_cmd(cfi, sa,    0x29);	/*  Write Buffer Program Confirm */
+	cfi_cmd(cfi, sa, 0x29);	/*  Write Buffer Program Confirm */
 
 	error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_write_nbyte(cfi));
 
@@ -342,12 +343,12 @@ cfi_0002_erase_all(device_t self)
 	if (error != 0)
 		return ETIMEDOUT;
 
-	cfi_cmd(cfi, 0x555, 0xaa); /* unlock 1 */
-	cfi_cmd(cfi, 0x2aa, 0x55); /* unlock 2 */
-	cfi_cmd(cfi, 0x555, 0x80); /* erase start */
-	cfi_cmd(cfi, 0x555, 0xaa); /* unlock 1 */
-	cfi_cmd(cfi, 0x2aa, 0x55); /* unlock 2 */
-	cfi_cmd(cfi, 0x555, 0x10); /* erase chip */
+	cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0xaa);
+	cfi_cmd(cfi, cfi->cfi_unlock_addr2, 0x55);
+	cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0x80); /* erase start */
+	cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0xaa);
+	cfi_cmd(cfi, cfi->cfi_unlock_addr2, 0x55);
+	cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0x10); /* erase chip */
 
 	error = cfi_0002_busy_wait(cfi, 0, cfi_0002_time_erase_all(cfi));
 
@@ -365,19 +366,18 @@ cfi_0002_erase_block(device_t self, flas
 
 	CFI_0002_STATS_INC(cfi, erase_block);
 
-	/* scale sector addr by portwidth or chipwidth ?  */
-	bus_size_t sa = offset >> cfi->cfi_portwidth;
+	bus_size_t sa = offset << (3 - cfi->cfi_portwidth);
 
 	int error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_dflt(cfi));
 	if (error != 0)
 		return ETIMEDOUT;
 
-	cfi_cmd(cfi, 0x555, 0xaa); /* unlock 1 */
-	cfi_cmd(cfi, 0x2aa, 0x55); /* unlock 2 */
-	cfi_cmd(cfi, 0x555, 0x80); /* erase start */
-	cfi_cmd(cfi, 0x555, 0xaa); /* unlock 1 */
-	cfi_cmd(cfi, 0x2aa, 0x55); /* unlock 2 */
-	cfi_cmd(cfi, sa,    0x30); /* erase sector */
+	cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0xaa);
+	cfi_cmd(cfi, cfi->cfi_unlock_addr2, 0x55);
+	cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0x80); /* erase start */
+	cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0xaa);
+	cfi_cmd(cfi, cfi->cfi_unlock_addr2, 0x55);
+	cfi_cmd(cfi, sa,                    0x30); /* erase sector */
 
 	error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_erase_blk(cfi));
 
@@ -553,7 +553,7 @@ cfi_0002_busy_reg(struct cfi * const cfi
 	bus_space_handle_t bsh = cfi->cfi_bsh;
 	uint32_t r;
 
-	cfi_cmd(cfi, 0x555, 0x70);	/* Status Register Read  */
+	cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0x70); /* Status Register Read  */
 
 	switch(cfi->cfi_portwidth) {
 	case 0:

Reply via email to