Home | History | Annotate | Line # | Download | only in nor
cfi.c revision 1.4
      1 /*	$NetBSD: cfi.c,v 1.4 2011/07/23 06:27:40 cliff Exp $	*/
      2 /*-
      3  * Copyright (c) 2011 The NetBSD Foundation, Inc.
      4  * All rights reserved.
      5  *
      6  * This code is derived from software contributed to The NetBSD Foundation
      7  * by Cliff Neighbors.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     20  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     22  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     28  * POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "opt_flash.h"
     32 #include "opt_nor.h"
     33 #include "opt_cfi.h"
     34 
     35 #include <sys/cdefs.h>
     36 __KERNEL_RCSID(0, "$NetBSD: cfi.c,v 1.4 2011/07/23 06:27:40 cliff Exp $");
     37 
     38 #include <sys/param.h>
     39 #include <sys/systm.h>
     40 #include <sys/cdefs.h>
     41 #include <sys/device.h>
     42 #include <sys/endian.h>
     43 
     44 #include <sys/bus.h>
     45 
     46 #include <dev/nor/nor.h>
     47 #include <dev/nor/cfi.h>
     48 #include <dev/nor/cfi_0002.h>
     49 
     50 
     51 static bool cfi_chip_query(struct cfi * const);
     52 static int  cfi_scan_media(device_t self, struct nor_chip *chip);
     53 static void cfi_init(device_t);
     54 static void cfi_select(device_t, bool);
     55 static void cfi_read_1(device_t, flash_off_t, uint8_t *);
     56 static void cfi_read_2(device_t, flash_off_t, uint16_t *);
     57 static void cfi_read_4(device_t, flash_off_t, uint32_t *);
     58 static void cfi_read_buf_1(device_t, flash_off_t, uint8_t *, size_t);
     59 static void cfi_read_buf_2(device_t, flash_off_t, uint16_t *, size_t);
     60 static void cfi_read_buf_4(device_t, flash_off_t, uint32_t *, size_t);
     61 static void cfi_write_1(device_t, flash_off_t, uint8_t);
     62 static void cfi_write_2(device_t, flash_off_t, uint16_t);
     63 static void cfi_write_4(device_t, flash_off_t, uint32_t);
     64 static void cfi_write_buf_1(device_t, flash_off_t, const uint8_t *, size_t);
     65 static void cfi_write_buf_2(device_t, flash_off_t, const uint16_t *, size_t);
     66 static void cfi_write_buf_4(device_t, flash_off_t, const uint32_t *, size_t);
     67 static void cfi_jedec_id_1(struct cfi * const );
     68 static void cfi_jedec_id_2(struct cfi * const );
     69 static void cfi_jedec_id_4(struct cfi * const );
     70 static bool cfi_jedec_id(struct cfi * const);
     71 static bool cfi_emulate(struct cfi * const);
     72 static const struct cfi_jedec_tab * cfi_jedec_search(struct cfi *);
     73 static void cfi_jedec_fill(struct cfi * const,
     74 	const struct cfi_jedec_tab *);
     75 #if defined(CFI_DEBUG_JEDEC) || defined(CFI_DEBUG_QRY)
     76 static void cfi_hexdump(flash_off_t, void * const, u_int, u_int);
     77 #endif
     78 
     79 
     80 
     81 /*
     82  * NOTE these opmode tables are informed by "Table 1. CFI Query Read"
     83  * in Intel "Common Flash Interface (CFI) and Command Sets"
     84  * Application Note 646, April 2000
     85  *
     86  * The byte ordering of the signature string here varies from that table
     87  * because of discrepancy in observed behavior, for the case:
     88  *	- x16 device operating in 16-bit mode
     89  * Similar discrepancy is expected (but not verified) for the case:
     90  *	- x32 device operating in 32-bit mode
     91  * so the ordering is changed here for that case also.
     92  *
     93  * XXX down-sized, interleaved & multi-chip opmodes not yet supported
     94  */
     95 
     96 /* 1-byte access */
     97 static const struct cfi_opmodes cfi_opmodes_1[] = {
     98 	{ 0, 0, 0, 0x10,  3, "QRY", "x8 device operating in 8-bit mode" },
     99 };
    100 
    101 /* 2-byte access */
    102 static const struct cfi_opmodes cfi_opmodes_2[] = {
    103 	{ 1, 1, 0, 0x20,  6, "\0Q\0R\0Y",
    104 		"x16 device operating in 16-bit mode" },
    105 };
    106 
    107 /* 4-byte access */
    108 static const struct cfi_opmodes cfi_opmodes_4[] = {
    109 	{ 2, 2, 0, 0x40, 12, "\0\0\0Q\0\0\0R\0\0\0Y",
    110 		"x32 device operating in 32-bit mode" },
    111 };
    112 
    113 
    114 #define LOG2_64K	16
    115 #define LOG2_128K	17
    116 #define LOG2_256K	18
    117 #define LOG2_512K	19
    118 #define LOG2_1M		20
    119 #define LOG2_2M		21
    120 #define LOG2_4M		22
    121 #define LOG2_8M		23
    122 #define LOG2_16M	24
    123 #define LOG2_32M	25
    124 #define LOG2_64M	26
    125 #define LOG2_128M	27
    126 #define LOG2_256M	28
    127 #define LOG2_512M	29
    128 #define LOG2_1G		30
    129 #define LOG2_2G		31
    130 const struct cfi_jedec_tab cfi_jedec_tab[] = {
    131 	{
    132 		.jt_name = "Pm39LV512",
    133 		.jt_mid = 0x9d,
    134 		.jt_did = 0x1b,
    135 		.jt_id_pri = 0,				/* XXX */
    136 		.jt_id_alt = 0,				/* XXX */
    137 		.jt_device_size = LOG2_64K,
    138 		.jt_interface_code_desc = CFI_IFCODE_X8,
    139 		.jt_erase_blk_regions = 1,
    140 		.jt_erase_blk_info = {
    141 			{ 4096/256, (64/4)-1 },
    142 		},
    143 		.jt_write_word_time_typ = 40,
    144 		.jt_write_nbyte_time_typ = 0,
    145 		.jt_erase_blk_time_typ = 55,
    146 		.jt_erase_chip_time_typ = 55,
    147 		.jt_write_word_time_max = 1,
    148 		.jt_write_nbyte_time_max = 0,
    149 		.jt_erase_blk_time_max = 1,
    150 		.jt_erase_chip_time_max = 1,
    151 		.jt_opmode = &cfi_opmodes_1[0],
    152 	},
    153 	{
    154 		.jt_name = "Pm39LV010",
    155 		.jt_mid = 0x9d,
    156 		.jt_did = 0x1c,
    157 		.jt_id_pri = 0,				/* XXX */
    158 		.jt_id_alt = 0,				/* XXX */
    159 		.jt_device_size = LOG2_128K,
    160 		.jt_interface_code_desc = CFI_IFCODE_X8,
    161 		.jt_erase_blk_regions = 1,
    162 		.jt_erase_blk_info = {
    163 			{ 4096/256, (128/4)-1 },
    164 		},
    165 		.jt_write_word_time_typ = 40,
    166 		.jt_write_nbyte_time_typ = 0,
    167 		.jt_erase_blk_time_typ = 55,
    168 		.jt_erase_chip_time_typ = 55,
    169 		.jt_write_word_time_max = 1,
    170 		.jt_write_nbyte_time_max = 0,
    171 		.jt_erase_blk_time_max = 1,
    172 		.jt_erase_chip_time_max = 1,
    173 		.jt_opmode = &cfi_opmodes_1[0],
    174 	},
    175 };
    176 
    177 
    178 const struct nor_interface nor_interface_cfi = {
    179 	.scan_media = cfi_scan_media,
    180 	.init = cfi_init,
    181 	.select = cfi_select,
    182 	.read_1 = cfi_read_1,
    183 	.read_2 = cfi_read_2,
    184 	.read_4 = cfi_read_4,
    185 	.read_buf_1 = cfi_read_buf_1,
    186 	.read_buf_2 = cfi_read_buf_2,
    187 	.read_buf_4 = cfi_read_buf_4,
    188 	.write_1 = cfi_write_1,
    189 	.write_2 = cfi_write_2,
    190 	.write_4 = cfi_write_4,
    191 	.write_buf_1 = cfi_write_buf_1,
    192 	.write_buf_2 = cfi_write_buf_2,
    193 	.write_buf_4 = cfi_write_buf_4,
    194 	.read_page = NULL,			/* cmdset */
    195 	.program_page = NULL,			/* cmdset */
    196 	.busy = NULL,
    197 	.private = NULL,
    198 	.access_width = -1,
    199 	.part_info = NULL,
    200 	.part_num = -1,
    201 };
    202 
    203 
    204 /* only data[7..0] are used regardless of chip width */
    205 #define cfi_unpack_1(n)			((n) & 0xff)
    206 
    207 /* construct (arbitrarily big endian) uint16_t */
    208 #define cfi_unpack_2(b0, b1)						\
    209 	((cfi_unpack_1(b1) << 8) | cfi_unpack_1(b0))
    210 
    211 /* construct (arbitrarily) big endian uint32_t */
    212 #define cfi_unpack_4(b0, b1, b2, b3)					\
    213 	((cfi_unpack_1(b3) << 24) |					\
    214 	 (cfi_unpack_1(b2) << 16) |					\
    215 	 (cfi_unpack_1(b1) <<  8) |					\
    216 	 (cfi_unpack_1(b0)))
    217 
    218 #define cfi_unpack_qry(qryp, data)					\
    219     do {								\
    220 	(qryp)->qry[0] = cfi_unpack_1(data[0x10]);			\
    221 	(qryp)->qry[1] = cfi_unpack_1(data[0x11]);			\
    222 	(qryp)->qry[2] = cfi_unpack_1(data[0x12]);			\
    223 	(qryp)->id_pri = be16toh(cfi_unpack_2(data[0x13], data[0x14]));	\
    224 	(qryp)->addr_pri =						\
    225 		be16toh(cfi_unpack_2(data[0x15], data[0x16]));		\
    226 	(qryp)->id_alt = be16toh(cfi_unpack_2(data[0x17], data[0x18]));	\
    227 	(qryp)->addr_alt =						\
    228 		be16toh(cfi_unpack_2(data[0x19], data[0x1a]));		\
    229 	(qryp)->vcc_min = cfi_unpack_1(data[0x1b]);			\
    230 	(qryp)->vcc_max = cfi_unpack_1(data[0x1c]);			\
    231 	(qryp)->vpp_min = cfi_unpack_1(data[0x1d]);			\
    232 	(qryp)->vpp_max = cfi_unpack_1(data[0x1e]);			\
    233 	(qryp)->write_word_time_typ = cfi_unpack_1(data[0x1f]);		\
    234 	(qryp)->write_nbyte_time_typ = cfi_unpack_1(data[0x20]);	\
    235 	(qryp)->erase_blk_time_typ = cfi_unpack_1(data[0x21]);		\
    236 	(qryp)->erase_chip_time_typ = cfi_unpack_1(data[0x22]);		\
    237 	(qryp)->write_word_time_max = cfi_unpack_1(data[0x23]);		\
    238 	(qryp)->write_nbyte_time_max = cfi_unpack_1(data[0x24]);	\
    239 	(qryp)->erase_blk_time_max = cfi_unpack_1(data[0x25]);		\
    240 	(qryp)->erase_chip_time_max = cfi_unpack_1(data[0x26]);		\
    241 	(qryp)->device_size = cfi_unpack_1(data[0x27]);			\
    242 	(qryp)->interface_code_desc =					\
    243 		be16toh(cfi_unpack_2(data[0x28], data[0x29]));		\
    244 	(qryp)->write_nbyte_size_max = 					\
    245 		be16toh(cfi_unpack_2(data[0x2a], data[0x2b]));		\
    246 	(qryp)->erase_blk_regions = cfi_unpack_1(data[0x2c]);		\
    247 	u_int _i = 0x2d;						\
    248 	const u_int _n = (qryp)->erase_blk_regions;			\
    249 	KASSERT(_n <= 4);						\
    250 	for (u_int _r = 0; _r < _n; _r++, _i+=4) {			\
    251 		(qryp)->erase_blk_info[_r].y =				\
    252 			be32toh(cfi_unpack_2(data[_i+0], data[_i+1]));	\
    253 		(qryp)->erase_blk_info[_r].z =				\
    254 			be32toh(cfi_unpack_2(data[_i+2], data[_i+3]));	\
    255 	}								\
    256     } while (0)
    257 
    258 #define cfi_unpack_pri_0002(qryp, data)					\
    259     do {								\
    260 	(qryp)->pri.cmd_0002.pri[0] = cfi_unpack_1(data[0x00]);		\
    261 	(qryp)->pri.cmd_0002.pri[1] = cfi_unpack_1(data[0x01]);		\
    262 	(qryp)->pri.cmd_0002.pri[2] = cfi_unpack_1(data[0x02]);		\
    263 	(qryp)->pri.cmd_0002.version_maj = cfi_unpack_1(data[0x03]);	\
    264 	(qryp)->pri.cmd_0002.version_min = cfi_unpack_1(data[0x04]);	\
    265 	(qryp)->pri.cmd_0002.asupt = cfi_unpack_1(data[0x05]);		\
    266 	(qryp)->pri.cmd_0002.erase_susp = cfi_unpack_1(data[0x06]);	\
    267 	(qryp)->pri.cmd_0002.sector_prot = cfi_unpack_1(data[0x07]);	\
    268 	(qryp)->pri.cmd_0002.tmp_sector_unprot =			\
    269 		cfi_unpack_1(data[0x08]);				\
    270 	(qryp)->pri.cmd_0002.sector_prot_scheme =			\
    271 		cfi_unpack_1(data[0x09]);				\
    272 	(qryp)->pri.cmd_0002.simul_op = cfi_unpack_1(data[0x0a]);	\
    273 	(qryp)->pri.cmd_0002.burst_mode_type = cfi_unpack_1(data[0x0b]);\
    274 	(qryp)->pri.cmd_0002.page_mode_type = cfi_unpack_1(data[0x0c]);	\
    275 	(qryp)->pri.cmd_0002.acc_min = cfi_unpack_1(data[0x0d]);	\
    276 	(qryp)->pri.cmd_0002.acc_max = cfi_unpack_1(data[0x0e]);	\
    277 	(qryp)->pri.cmd_0002.wp_prot = cfi_unpack_1(data[0x0f]);	\
    278 	/* XXX 1.3 stops here */					\
    279 	(qryp)->pri.cmd_0002.prog_susp = cfi_unpack_1(data[0x10]);	\
    280 	(qryp)->pri.cmd_0002.unlock_bypass = cfi_unpack_1(data[0x11]);	\
    281 	(qryp)->pri.cmd_0002.sss_size = cfi_unpack_1(data[0x12]);	\
    282 	(qryp)->pri.cmd_0002.soft_feat = cfi_unpack_1(data[0x13]);	\
    283 	(qryp)->pri.cmd_0002.page_size = cfi_unpack_1(data[0x14]);	\
    284 	(qryp)->pri.cmd_0002.erase_susp_time_max =			\
    285 		cfi_unpack_1(data[0x15]);				\
    286 	(qryp)->pri.cmd_0002.prog_susp_time_max =			\
    287 		cfi_unpack_1(data[0x16]);				\
    288 	(qryp)->pri.cmd_0002.embhwrst_time_max =			\
    289 		cfi_unpack_1(data[0x38]);				\
    290 	(qryp)->pri.cmd_0002.hwrst_time_max =				\
    291 		cfi_unpack_1(data[0x39]);				\
    292     } while (0)
    293 
    294 #define CFI_QRY_UNPACK_COMMON(cfi, data, type, found)			\
    295     do {								\
    296 	struct cfi_query_data * const qryp = &cfi->cfi_qry_data;	\
    297 									\
    298 	memset(qryp, 0, sizeof(*qryp));					\
    299 	cfi_unpack_qry(qryp, data);					\
    300 									\
    301 	switch (qryp->id_pri) {						\
    302 	case 0x0002:							\
    303 		if ((cfi_unpack_1(data[qryp->addr_pri + 0]) == 'P') &&	\
    304 		    (cfi_unpack_1(data[qryp->addr_pri + 1]) == 'R') &&	\
    305 		    (cfi_unpack_1(data[qryp->addr_pri + 2]) == 'I')) {	\
    306 			type *pri_data = &data[qryp->addr_pri];		\
    307 			cfi_unpack_pri_0002(qryp, pri_data);		\
    308 			found = true;					\
    309 			break;						\
    310 		}							\
    311 	default:							\
    312 		printf("%s: unsupported id_pri=%#x\n",			\
    313 			__func__, qryp->id_pri);			\
    314 		break;	/* unknown command set */			\
    315 	}								\
    316     } while (0)
    317 
    318 #ifdef CFI_DEBUG_QRY
    319 # define CFI_DUMP_QRY(off, p, sz, stride)				\
    320     do {								\
    321 	printf("%s: QRY data\n", __func__);				\
    322 	cfi_hexdump(off, p, sz, stride);				\
    323     } while (0)
    324 #else
    325 # define CFI_DUMP_QRY(off, p, sz, stride)
    326 #endif
    327 
    328 #ifdef CFI_DEBUG_JEDEC
    329 # define CFI_DUMP_JEDEC(off, p, sz, stride)				\
    330     do {								\
    331 	printf("%s: JEDEC data\n", __func__);				\
    332 	cfi_hexdump(off, p, sz, stride);				\
    333     } while (0)
    334 #else
    335 # define CFI_DUMP_JEDEC(off, p, sz, stride)
    336 #endif
    337 
    338 
    339 /*
    340  * cfi_chip_query_opmode - determine operational mode based on QRY signature
    341  */
    342 static bool
    343 cfi_chip_query_opmode(struct cfi *cfi, uint8_t *data,
    344     const struct cfi_opmodes *tab, u_int nentries)
    345 {
    346 	for (u_int i=0; i < nentries; i++) {
    347 		if (memcmp(&data[tab[i].qsa], tab[i].sig, tab[i].len) == 0) {
    348 			cfi->cfi_opmode = &tab[i];
    349 			return true;
    350 		}
    351 	}
    352 	return false;
    353 }
    354 
    355 static bool
    356 cfi_chip_query_1(struct cfi * const cfi)
    357 {
    358 	uint8_t data[0x80];
    359 
    360 	bus_space_read_region_1(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
    361 		__arraycount(data));
    362 
    363 	CFI_DUMP_QRY(0, data, sizeof(data), 1);
    364 
    365 	bool found = cfi_chip_query_opmode(cfi, data, cfi_opmodes_1,
    366 		__arraycount(cfi_opmodes_1));
    367 
    368 	if (found) {
    369 		CFI_QRY_UNPACK_COMMON(cfi, data, uint8_t, found);
    370 	}
    371 
    372 	return found;
    373 }
    374 
    375 static bool
    376 cfi_chip_query_2(struct cfi * const cfi)
    377 {
    378 	uint16_t data[0x80];
    379 
    380 	bus_space_read_region_2(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
    381 		__arraycount(data));
    382 
    383 	CFI_DUMP_QRY(0, data, sizeof(data), 2);
    384 
    385 	bool found = cfi_chip_query_opmode(cfi, (uint8_t *)data,
    386 		cfi_opmodes_2, __arraycount(cfi_opmodes_2));
    387 
    388 	if (found) {
    389 		CFI_QRY_UNPACK_COMMON(cfi, data, uint16_t, found);
    390 	}
    391 
    392 	return found;
    393 }
    394 
    395 static bool
    396 cfi_chip_query_4(struct cfi * const cfi)
    397 {
    398 	uint32_t data[0x80];
    399 
    400 	bus_space_read_region_4(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
    401 		__arraycount(data));
    402 
    403 	CFI_DUMP_QRY(0, data, sizeof(data), 4);
    404 
    405 	bool found = cfi_chip_query_opmode(cfi, (uint8_t *)data,
    406 		cfi_opmodes_4, __arraycount(cfi_opmodes_4));
    407 
    408 	if (found) {
    409 		CFI_QRY_UNPACK_COMMON(cfi, data, uint32_t, found);
    410 	}
    411 
    412 	return found;
    413 }
    414 
    415 static bool
    416 cfi_chip_query_8(struct cfi * const cfi)
    417 {
    418 #ifdef NOTYET
    419 	uint64_t data[0x80];
    420 
    421 	bus_space_read_region_8(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
    422 		__arraycount(data));
    423 
    424 	CFI_DUMP_QRY(0, data, sizeof(data), 8);
    425 
    426 	bool found = cfi_chip_query_opmode(cfi, (uint8_t *)data,
    427 		cfi_opmodes_8, __arraycount(cfi_opmodes_8));
    428 
    429 	if (found) {
    430 		CFI_QRY_UNPACK_COMMON(cfi, data, uint64_t, found);
    431 	}
    432 
    433 	return found;
    434 #else
    435 	return false;
    436 #endif
    437 }
    438 
    439 /*
    440  * cfi_chip_query - detect a CFI chip
    441  *
    442  * fill in the struct cfi as we discover what's there
    443  */
    444 static bool
    445 cfi_chip_query(struct cfi * const cfi)
    446 {
    447 	bool found = false;
    448 	const bus_size_t cfi_query_offset[] = {
    449 		CFI_QUERY_MODE_ADDRESS,
    450 		CFI_QUERY_MODE_ALT_ADDRESS
    451 	};
    452 
    453 	KASSERT(cfi != NULL);
    454 	KASSERT(cfi->cfi_bst != NULL);
    455 
    456 	for (int j=0; !found && j < __arraycount(cfi_query_offset); j++) {
    457 
    458 		cfi_reset_default(cfi);
    459 		cfi_cmd(cfi, cfi_query_offset[j], CFI_QUERY_DATA);
    460 
    461 		switch(cfi->cfi_portwidth) {
    462 		case 0:
    463 			found = cfi_chip_query_1(cfi);
    464 			break;
    465 		case 1:
    466 			found = cfi_chip_query_2(cfi);
    467 			break;
    468 		case 2:
    469 			found = cfi_chip_query_4(cfi);
    470 			break;
    471 		case 3:
    472 			found = cfi_chip_query_8(cfi);
    473 			break;
    474 		default:
    475 			panic("%s: bad portwidth %d\n",
    476 				__func__, cfi->cfi_portwidth);
    477 		}
    478 	}
    479 
    480 	if (found)
    481 		cfi->cfi_emulated = false;
    482 
    483 	return found;
    484 }
    485 
    486 /*
    487  * cfi_probe - search for a CFI NOR trying various port & chip widths
    488  *
    489  * - gather CFI QRY and PRI data
    490  * - gather JEDEC ID data
    491  * - if cfi_chip_query() fails, emulate CFI using table data if possible,
    492  *   otherwise fail.
    493  *
    494  * NOTE:
    495  *   striped NOR chips design not supported yet,
    496  *   so force portwidth=chipwidth for now
    497  *   eventually permute portwidth seperately
    498  */
    499 bool
    500 cfi_probe(struct cfi * const cfi)
    501 {
    502 	bool found;
    503 
    504 	KASSERT(cfi != NULL);
    505 
    506 	for (u_int cw = 0; cw < 3; cw++) {
    507 		cfi->cfi_portwidth = 		/* XXX */
    508 		cfi->cfi_chipwidth = cw;
    509 		found = cfi_chip_query(cfi);
    510 		cfi_jedec_id(cfi);
    511 		if (! found)
    512 			found = cfi_emulate(cfi);
    513 		if (found)
    514 			break;
    515 	}
    516 
    517 	cfi_reset_default(cfi);		/* exit QRY mode */
    518 	return found;
    519 }
    520 
    521 bool
    522 cfi_identify(struct cfi * const cfi)
    523 {
    524 	const bus_space_tag_t bst = cfi->cfi_bst;
    525 	const bus_space_handle_t bsh = cfi->cfi_bsh;
    526 	bool found;
    527 
    528 	KASSERT(cfi != NULL);
    529 	KASSERT(bst != NULL);
    530 
    531 	memset(cfi, 0, sizeof(struct cfi));	/* XXX clean slate */
    532 	cfi->cfi_bst = bst;		/* restore bus space */
    533 	cfi->cfi_bsh = bsh;		/*  "       "   "    */
    534 
    535 	found = cfi_probe(cfi);
    536 
    537 	cfi_reset_default(cfi);	/* exit QRY mode */
    538 
    539 	return found;
    540 }
    541 
    542 static int
    543 cfi_scan_media(device_t self, struct nor_chip *chip)
    544 {
    545 	struct nor_softc *sc = device_private(self);
    546 	KASSERT(sc != NULL);
    547 	KASSERT(sc->sc_nor_if != NULL);
    548 	struct cfi * const cfi = (struct cfi * const)sc->sc_nor_if->private;
    549 	KASSERT(cfi != NULL);
    550 
    551 	sc->sc_nor_if->access_width = cfi->cfi_portwidth;
    552 
    553 	chip->nc_manf_id = cfi->cfi_id_data.id_mid;
    554 	chip->nc_dev_id = cfi->cfi_id_data.id_did[0]; /* XXX 3 words */
    555 	chip->nc_size = 1 << cfi->cfi_qry_data.device_size;
    556 
    557 	/* size of line for Read Buf command */
    558 	chip->nc_line_size = 1 << cfi->cfi_qry_data.pri.cmd_0002.page_size;
    559 
    560 	/*
    561 	 * size of erase block
    562 	 * XXX depends on erase region
    563 	 */
    564 	chip->nc_num_luns = 1;
    565 	chip->nc_lun_blocks = cfi->cfi_qry_data.erase_blk_info[0].y + 1;
    566 	chip->nc_block_size = cfi->cfi_qry_data.erase_blk_info[0].z * 256;
    567 
    568 	switch (cfi->cfi_qry_data.id_pri) {
    569 	case 0x0002:
    570 		cfi_0002_init(sc, cfi, chip);
    571 		break;
    572 	default:
    573 		aprint_error_dev(self, "unsupported CFI cmdset %#04x\n",
    574 			cfi->cfi_qry_data.id_pri);
    575 		return -1;
    576 	}
    577 
    578 	return 0;
    579 }
    580 
    581 void
    582 cfi_init(device_t self)
    583 {
    584 	/* nothing */
    585 }
    586 
    587 static void
    588 cfi_select(device_t self, bool select)
    589 {
    590 	/* nothing */
    591 }
    592 
    593 static void
    594 cfi_read_1(device_t self, flash_off_t offset, uint8_t *datap)
    595 {
    596 }
    597 
    598 static void
    599 cfi_read_2(device_t self, flash_off_t offset, uint16_t *datap)
    600 {
    601 }
    602 
    603 static void
    604 cfi_read_4(device_t self, flash_off_t offset, uint32_t *datap)
    605 {
    606 }
    607 
    608 static void
    609 cfi_read_buf_1(device_t self, flash_off_t offset, uint8_t *datap, size_t size)
    610 {
    611 }
    612 
    613 static void
    614 cfi_read_buf_2(device_t self, flash_off_t offset, uint16_t *datap, size_t size)
    615 {
    616 }
    617 
    618 static void
    619 cfi_read_buf_4(device_t self, flash_off_t offset, uint32_t *datap, size_t size)
    620 {
    621 }
    622 
    623 static void
    624 cfi_write_1(device_t self, flash_off_t offset, uint8_t data)
    625 {
    626 }
    627 
    628 static void
    629 cfi_write_2(device_t self, flash_off_t offset, uint16_t data)
    630 {
    631 }
    632 
    633 static void
    634 cfi_write_4(device_t self, flash_off_t offset, uint32_t data)
    635 {
    636 }
    637 
    638 static void
    639 cfi_write_buf_1(device_t self, flash_off_t offset, const uint8_t *datap,
    640     size_t size)
    641 {
    642 }
    643 
    644 static void
    645 cfi_write_buf_2(device_t self, flash_off_t offset, const uint16_t *datap,
    646     size_t size)
    647 {
    648 }
    649 
    650 static void
    651 cfi_write_buf_4(device_t self, flash_off_t offset, const uint32_t *datap,
    652     size_t size)
    653 {
    654 }
    655 
    656 void
    657 cfi_cmd(struct cfi * const cfi, bus_size_t off, uint32_t val)
    658 {
    659 	const bus_space_tag_t bst = cfi->cfi_bst;
    660 	bus_space_handle_t bsh = cfi->cfi_bsh;
    661 
    662 	off <<= cfi->cfi_portwidth;
    663 
    664 	DPRINTF(("%s: %p %x %x %x\n", __func__, bst, bsh, off, val));
    665 
    666 	switch(cfi->cfi_portwidth) {
    667 	case 0:
    668 		bus_space_write_1(bst, bsh, off, (uint8_t)val);
    669 		break;
    670 	case 1:
    671 		bus_space_write_2(bst, bsh, off, val);
    672 		break;
    673 	case 2:
    674 		bus_space_write_4(bst, bsh, off, (uint32_t)val);
    675 		break;
    676 #ifdef NOTYET
    677 	case 3:
    678 		bus_space_write_4(bst, bsh, off, (uint64_t)val);
    679 		break;
    680 #endif
    681 	default:
    682 		panic("%s: bad portwidth %d bytes\n",
    683 			__func__, 1 << cfi->cfi_portwidth);
    684 	}
    685 }
    686 
    687 /*
    688  * cfi_reset_default - when we don't know which command will work, use both
    689  */
    690 void
    691 cfi_reset_default(struct cfi * const cfi)
    692 {
    693 	cfi_cmd(cfi, CFI_ADDRESS_ANY, CFI_RESET_DATA);
    694 	cfi_cmd(cfi, CFI_ADDRESS_ANY, CFI_ALT_RESET_DATA);
    695 }
    696 
    697 /*
    698  * cfi_reset_std - use standard reset command
    699  */
    700 void
    701 cfi_reset_std(struct cfi * const cfi)
    702 {
    703 	cfi_cmd(cfi, CFI_ADDRESS_ANY, CFI_RESET_DATA);
    704 }
    705 
    706 /*
    707  * cfi_reset_alt - use "alternate" reset command
    708  */
    709 void
    710 cfi_reset_alt(struct cfi * const cfi)
    711 {
    712 	cfi_cmd(cfi, CFI_ADDRESS_ANY, CFI_ALT_RESET_DATA);
    713 }
    714 
    715 static void
    716 cfi_jedec_id_1(struct cfi * const cfi)
    717 {
    718 	struct cfi_jedec_id_data *idp = &cfi->cfi_id_data;
    719 	uint8_t data[0x10];
    720 
    721 	bus_space_read_region_1(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
    722 		__arraycount(data));
    723 
    724 	CFI_DUMP_JEDEC(0, data, sizeof(data), 1);
    725 
    726 	idp->id_mid = (uint16_t)data[0];
    727 	idp->id_did[0] = (uint16_t)data[1];
    728 	idp->id_did[1] = (uint16_t)data[0xe];
    729 	idp->id_did[2] = (uint16_t)data[0xf];
    730 	idp->id_prot_state = (uint16_t)data[2];
    731 	idp->id_indicators = (uint16_t)data[3];
    732 
    733 	/* software bits, upper and lower */
    734 	idp->id_swb_lo = data[0xc];
    735 	idp->id_swb_hi = data[0xd];
    736 
    737 }
    738 
    739 static void
    740 cfi_jedec_id_2(struct cfi * const cfi)
    741 {
    742 	struct cfi_jedec_id_data *idp = &cfi->cfi_id_data;
    743 	uint16_t data[0x10];
    744 
    745 	bus_space_read_region_2(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
    746 		__arraycount(data));
    747 
    748 	CFI_DUMP_JEDEC(0, data, sizeof(data), 1);
    749 
    750 	idp->id_mid = data[0];
    751 	idp->id_did[0] = data[1];
    752 	idp->id_did[1] = data[0xe];
    753 	idp->id_did[2] = data[0xf];
    754 	idp->id_prot_state = data[2];
    755 	idp->id_indicators = data[3];
    756 
    757 	/* software bits, upper and lower
    758 	 * - undefined on S29GL-P
    759 	 * - defined   on S29GL-S
    760 	 */
    761 	idp->id_swb_lo = data[0xc];
    762 	idp->id_swb_hi = data[0xd];
    763 
    764 }
    765 
    766 static void
    767 cfi_jedec_id_4(struct cfi * const cfi)
    768 {
    769 	struct cfi_jedec_id_data *idp = &cfi->cfi_id_data;
    770 	uint32_t data[0x10];
    771 
    772 	bus_space_read_region_4(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
    773 		__arraycount(data));
    774 
    775 	CFI_DUMP_JEDEC(0, data, sizeof(data), 1);
    776 
    777 	idp->id_mid = data[0] & 0xffff;
    778 	idp->id_did[0] = data[1] & 0xffff;
    779 	idp->id_did[1] = data[0xe] & 0xffff;
    780 	idp->id_did[2] = data[0xf] & 0xffff;
    781 	idp->id_prot_state = data[2] & 0xffff;
    782 	idp->id_indicators = data[3] & 0xffff;
    783 
    784 	/* software bits, upper and lower
    785 	 * - undefined on S29GL-P
    786 	 * - defined   on S29GL-S
    787 	 */
    788 	idp->id_swb_lo = data[0xc] & 0xffff;
    789 	idp->id_swb_hi = data[0xd] & 0xffff;
    790 
    791 }
    792 
    793 /*
    794  * cfi_jedec_id - get JEDEC ID info
    795  */
    796 static bool
    797 cfi_jedec_id(struct cfi * const cfi)
    798 {
    799 
    800 	DPRINTF(("%s\n", __func__));
    801 
    802 	cfi_cmd(cfi, 0x555, 0xaa);
    803 	cfi_cmd(cfi, 0x2aa, 0x55);
    804 	cfi_cmd(cfi, 0x555, 0x90);
    805 
    806 	switch(cfi->cfi_portwidth) {
    807 	case 0:
    808 		cfi_jedec_id_1(cfi);
    809 		break;
    810 	case 1:
    811 		cfi_jedec_id_2(cfi);
    812 		break;
    813 	case 2:
    814 		cfi_jedec_id_4(cfi);
    815 		break;
    816 #ifdef NOTYET
    817 	case 3:
    818 		cfi_jedec_id_8(cfi);
    819 		break;
    820 #endif
    821 	default:
    822 		panic("%s: bad portwidth %d bytes\n",
    823 			__func__, 1 << cfi->cfi_portwidth);
    824 	}
    825 
    826 	return true;
    827 }
    828 
    829 static bool
    830 cfi_emulate(struct cfi * const cfi)
    831 {
    832 	bool found = false;
    833 	const struct cfi_jedec_tab *jt = cfi_jedec_search(cfi);
    834 	if (jt != NULL) {
    835 		found = true;
    836 		cfi->cfi_emulated = true;
    837 		cfi_jedec_fill(cfi, jt);
    838 	}
    839 	return found;
    840 }
    841 
    842 /*
    843  * cfi_jedec_search - search cfi_jedec_tab[] for entry matching given JEDEC IDs
    844  */
    845 static const struct cfi_jedec_tab *
    846 cfi_jedec_search(struct cfi *cfi)
    847 {
    848 	struct cfi_jedec_id_data *idp = &cfi->cfi_id_data;
    849 
    850 	for (u_int i=0; i < __arraycount(cfi_jedec_tab); i++) {
    851 		const struct cfi_jedec_tab *jt = &cfi_jedec_tab[i];
    852 		if ((jt->jt_mid == idp->id_mid) &&
    853 		    (jt->jt_did == idp->id_did[0])) {
    854 			return jt;
    855 		}
    856 	}
    857 	return NULL;
    858 }
    859 
    860 /*
    861  * cfi_jedec_fill - fill in cfi with info from table entry
    862  */
    863 static void
    864 cfi_jedec_fill(struct cfi *cfi, const struct cfi_jedec_tab *jt)
    865 {
    866 	cfi->cfi_name = jt->jt_name;
    867 	cfi->cfi_opmode = jt->jt_opmode;
    868 	memset(&cfi->cfi_qry_data, 0, sizeof(struct cfi_query_data));
    869 	cfi->cfi_qry_data.id_pri = jt->jt_id_pri;
    870 	cfi->cfi_qry_data.id_alt = jt->jt_id_alt;
    871 	cfi->cfi_qry_data.interface_code_desc = jt->jt_interface_code_desc;
    872 	cfi->cfi_qry_data.write_word_time_typ = jt->jt_write_word_time_typ;
    873 	cfi->cfi_qry_data.write_nbyte_time_typ = jt->jt_write_nbyte_time_typ;
    874 	cfi->cfi_qry_data.erase_blk_time_typ = jt->jt_erase_blk_time_typ;
    875 	cfi->cfi_qry_data.erase_chip_time_typ = jt->jt_erase_chip_time_typ;
    876 	cfi->cfi_qry_data.write_word_time_max = jt->jt_write_word_time_max;
    877 	cfi->cfi_qry_data.write_nbyte_time_max = jt->jt_write_nbyte_time_max;
    878 	cfi->cfi_qry_data.erase_blk_time_max = jt->jt_erase_blk_time_max;
    879 	cfi->cfi_qry_data.erase_chip_time_max = jt->jt_erase_chip_time_max;
    880 	cfi->cfi_qry_data.device_size = jt->jt_device_size;
    881 	cfi->cfi_qry_data.interface_code_desc = jt->jt_interface_code_desc;
    882 	cfi->cfi_qry_data.write_nbyte_size_max = jt->jt_write_nbyte_size_max;
    883 	cfi->cfi_qry_data.erase_blk_regions = jt->jt_erase_blk_regions;
    884 	for (u_int i=0; i < 4; i++)
    885 		cfi->cfi_qry_data.erase_blk_info[i] = jt->jt_erase_blk_info[i];
    886 }
    887 
    888 void
    889 cfi_print(device_t self, struct cfi * const cfi)
    890 {
    891 	char pbuf[sizeof("XXXX MB")];
    892 	struct cfi_query_data * const qryp = &cfi->cfi_qry_data;
    893 
    894 	format_bytes(pbuf, sizeof(pbuf), 1 << qryp->device_size);
    895 	if (cfi->cfi_emulated) {
    896 		aprint_normal_dev(self, "%s NOR flash %s %s\n",
    897 			cfi->cfi_name, pbuf,
    898 			cfi_interface_desc_str(qryp->interface_code_desc));
    899 	} else {
    900 		aprint_normal_dev(self, "CFI NOR flash %s %s\n", pbuf,
    901 			cfi_interface_desc_str(qryp->interface_code_desc));
    902 	}
    903 #ifdef NOR_VERBOSE
    904 	aprint_normal_dev(self, "manufacturer id %#x, device id %#x %#x %#x\n",
    905 		cfi->cfi_id_data.id_mid,
    906 		cfi->cfi_id_data.id_did[0],
    907 		cfi->cfi_id_data.id_did[1],
    908 		cfi->cfi_id_data.id_did[2]);
    909 	aprint_normal_dev(self, "%s\n", cfi->cfi_opmode->str);
    910 	aprint_normal_dev(self, "sw bits lo=%#x hi=%#x\n",
    911 		cfi->cfi_id_data.id_swb_lo,
    912 		cfi->cfi_id_data.id_swb_hi);
    913 	aprint_normal_dev(self, "max multibyte write size %d\n",
    914 		1 << qryp->write_nbyte_size_max);
    915 	aprint_normal_dev(self, "%d Erase Block Region(s)\n",
    916 		qryp->erase_blk_regions);
    917 	for (u_int r=0; r < qryp->erase_blk_regions; r++) {
    918 		size_t sz = qryp->erase_blk_info[r].z * 256;
    919 		format_bytes(pbuf, sizeof(pbuf), sz);
    920 		aprint_normal("    %d: %d blocks, size %s\n", r,
    921 			qryp->erase_blk_info[r].y + 1, pbuf);
    922 	}
    923 #endif
    924 
    925 	switch (cfi->cfi_qry_data.id_pri) {
    926 	case 0x0002:
    927 		cfi_0002_print(self, cfi);
    928 		break;
    929 	}
    930 }
    931 
    932 #if defined(CFI_DEBUG_JEDEC) || defined(CFI_DEBUG_QRY)
    933 void
    934 cfi_hexdump(flash_off_t offset, void * const v, u_int count, u_int stride)
    935 {
    936 	uint8_t * const data = v;
    937 	for(int n=0; n < count; n+=16) {
    938 		int i;
    939 		printf("%08llx: ", (offset + n) / stride);
    940 		for(i=n; i < n+16; i++)
    941 			printf("%02x ", data[i]);
    942 		printf("\t");
    943 		for(i=n; i < n+16; i++) {
    944 			u_int c = (int)data[i];
    945 			if (c >= 0x20 && c < 0x7f)
    946 				printf("%c", c);
    947 			else
    948 				printf("%c", '.');
    949 		}
    950 		printf("\n");
    951 	}
    952 }
    953 #endif
    954