Home | History | Annotate | Line # | Download | only in nor
cfi.c revision 1.3
      1 /*	$NetBSD: cfi.c,v 1.3 2011/07/19 20:52:10 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_nor.h"
     32 #include "opt_flash.h"
     33 
     34 #include <sys/cdefs.h>
     35 __KERNEL_RCSID(0, "$NetBSD: cfi.c,v 1.3 2011/07/19 20:52:10 cliff Exp $");
     36 
     37 #include <sys/param.h>
     38 #include <sys/systm.h>
     39 #include <sys/cdefs.h>
     40 #include <sys/device.h>
     41 #include <sys/endian.h>
     42 
     43 #include <sys/bus.h>
     44 
     45 #include <dev/nor/nor.h>
     46 #include <dev/nor/cfi.h>
     47 #include <dev/nor/cfi_0002.h>
     48 
     49 
     50 static bool cfi_chip_query(struct cfi * const);
     51 static int  cfi_scan_media(device_t self, struct nor_chip *chip);
     52 static void cfi_init(device_t);
     53 static void cfi_select(device_t, bool);
     54 static void cfi_read_1(device_t, flash_off_t, uint8_t *);
     55 static void cfi_read_2(device_t, flash_off_t, uint16_t *);
     56 static void cfi_read_4(device_t, flash_off_t, uint32_t *);
     57 static void cfi_read_buf_1(device_t, flash_off_t, uint8_t *, size_t);
     58 static void cfi_read_buf_2(device_t, flash_off_t, uint16_t *, size_t);
     59 static void cfi_read_buf_4(device_t, flash_off_t, uint32_t *, size_t);
     60 static void cfi_write_1(device_t, flash_off_t, uint8_t);
     61 static void cfi_write_2(device_t, flash_off_t, uint16_t);
     62 static void cfi_write_4(device_t, flash_off_t, uint32_t);
     63 static void cfi_write_buf_1(device_t, flash_off_t, const uint8_t *, size_t);
     64 static void cfi_write_buf_2(device_t, flash_off_t, const uint16_t *, size_t);
     65 static void cfi_write_buf_4(device_t, flash_off_t, const uint32_t *, size_t);
     66 static bool cfi_jedec_id(struct cfi * const);
     67 
     68 
     69 /*
     70  * NOTE these opmode tables are informed by "Table 1. CFI Query Read"
     71  * in Intel "Common Flash Interface (CFI) and Command Sets"
     72  * Application Note 646, April 2000
     73  *
     74  * The byte ordering of the signature string here varies from that table
     75  * because of discrepancy in observed behavior, for the case:
     76  *	- x16 device operating in 16-bit mode
     77  * Similar discrepancy is expected (but not verified) for the case:
     78  *	- x32 device operating in 32-bit mode
     79  * so the ordering is changed here for that case also.
     80  *
     81  * XXX down-sized, interleaved & multi-chip opmodes not yet supported
     82  */
     83 
     84 /* 1-byte access */
     85 static const struct cfi_opmodes cfi_opmodes_1[] = {
     86 	{ 0, 0, 0, 0x10,  3, "QRY", "x8 device operating in 8-bit mode" },
     87 };
     88 
     89 /* 2-byte access */
     90 static const struct cfi_opmodes cfi_opmodes_2[] = {
     91 	{ 1, 1, 0, 0x20,  6, "\0Q\0R\0Y",
     92 		"x16 device operating in 16-bit mode" },
     93 };
     94 
     95 /* 4-byte access */
     96 static const struct cfi_opmodes cfi_opmodes_4[] = {
     97 	{ 2, 2, 0, 0x40, 12, "\0\0\0Q\0\0\0R\0\0\0Y",
     98 		"x32 device operating in 32-bit mode" },
     99 };
    100 
    101 
    102 const struct nor_interface nor_interface_cfi = {
    103 	.scan_media = cfi_scan_media,
    104 	.init = cfi_init,
    105 	.select = cfi_select,
    106 	.read_1 = cfi_read_1,
    107 	.read_2 = cfi_read_2,
    108 	.read_4 = cfi_read_4,
    109 	.read_buf_1 = cfi_read_buf_1,
    110 	.read_buf_2 = cfi_read_buf_2,
    111 	.read_buf_4 = cfi_read_buf_4,
    112 	.write_1 = cfi_write_1,
    113 	.write_2 = cfi_write_2,
    114 	.write_4 = cfi_write_4,
    115 	.write_buf_1 = cfi_write_buf_1,
    116 	.write_buf_2 = cfi_write_buf_2,
    117 	.write_buf_4 = cfi_write_buf_4,
    118 	.read_page = NULL,			/* cmdset */
    119 	.program_page = NULL,			/* cmdset */
    120 	.busy = NULL,
    121 	.private = NULL,
    122 	.access_width = -1,
    123 	.part_info = NULL,
    124 	.part_num = -1,
    125 };
    126 
    127 
    128 /* only data[7..0] are used regardless of chip width */
    129 #define cfi_unpack_1(n)			((n) & 0xff)
    130 
    131 /* construct (arbitrarily big endian) uint16_t */
    132 #define cfi_unpack_2(b0, b1)						\
    133 	((cfi_unpack_1(b1) << 8) | cfi_unpack_1(b0))
    134 
    135 /* construct (arbitrarily) big endian uint32_t */
    136 #define cfi_unpack_4(b0, b1, b2, b3)					\
    137 	((cfi_unpack_1(b3) << 24) |					\
    138 	 (cfi_unpack_1(b2) << 16) |					\
    139 	 (cfi_unpack_1(b1) <<  8) |					\
    140 	 (cfi_unpack_1(b0)))
    141 
    142 #define cfi_unpack_qry(qryp, data)					\
    143     do {								\
    144 	(qryp)->qry[0] = cfi_unpack_1(data[0x10]);			\
    145 	(qryp)->qry[1] = cfi_unpack_1(data[0x11]);			\
    146 	(qryp)->qry[2] = cfi_unpack_1(data[0x12]);			\
    147 	(qryp)->id_pri = be16toh(cfi_unpack_2(data[0x13], data[0x14]));	\
    148 	(qryp)->addr_pri =						\
    149 		be16toh(cfi_unpack_2(data[0x15], data[0x16]));		\
    150 	(qryp)->id_alt = be16toh(cfi_unpack_2(data[0x17], data[0x18]));	\
    151 	(qryp)->addr_alt =						\
    152 		be16toh(cfi_unpack_2(data[0x19], data[0x1a]));		\
    153 	(qryp)->vcc_min = cfi_unpack_1(data[0x1b]);			\
    154 	(qryp)->vcc_max = cfi_unpack_1(data[0x1c]);			\
    155 	(qryp)->vpp_min = cfi_unpack_1(data[0x1d]);			\
    156 	(qryp)->vpp_max = cfi_unpack_1(data[0x1e]);			\
    157 	(qryp)->write_word_time_typ = cfi_unpack_1(data[0x1f]);		\
    158 	(qryp)->write_nbyte_time_typ = cfi_unpack_1(data[0x20]);	\
    159 	(qryp)->erase_blk_time_typ = cfi_unpack_1(data[0x21]);		\
    160 	(qryp)->erase_chiptime_typ = cfi_unpack_1(data[0x22]);		\
    161 	(qryp)->write_word_time_max = cfi_unpack_1(data[0x23]);		\
    162 	(qryp)->write_nbyte_time_max = cfi_unpack_1(data[0x24]);	\
    163 	(qryp)->erase_blk_time_max = cfi_unpack_1(data[0x25]);		\
    164 	(qryp)->erase_chiptime_max = cfi_unpack_1(data[0x26]);		\
    165 	(qryp)->device_size = cfi_unpack_1(data[0x27]);			\
    166 	(qryp)->interface_code_desc =					\
    167 		be16toh(cfi_unpack_2(data[0x28], data[0x29]));		\
    168 	(qryp)->write_nbyte_size_max = 					\
    169 		be16toh(cfi_unpack_2(data[0x2a], data[0x2b]));		\
    170 	(qryp)->erase_blk_regions = cfi_unpack_1(data[0x2c]);		\
    171 	u_int _i = 0x2d;						\
    172 	const u_int _n = (qryp)->erase_blk_regions;			\
    173 	KASSERT(_n <= 4);						\
    174 	for (u_int _r = 0; _r < _n; _r++, _i+=4) {			\
    175 		(qryp)->erase_blk_info[_r].y =				\
    176 			be32toh(cfi_unpack_2(data[_i+0], data[_i+1]));	\
    177 		(qryp)->erase_blk_info[_r].z =				\
    178 			be32toh(cfi_unpack_2(data[_i+2], data[_i+3]));	\
    179 	}								\
    180     } while (0)
    181 
    182 #define cfi_unpack_pri_0002(qryp, data)					\
    183     do {								\
    184 	(qryp)->pri.cmd_0002.pri[0] = cfi_unpack_1(data[0x00]);		\
    185 	(qryp)->pri.cmd_0002.pri[1] = cfi_unpack_1(data[0x01]);		\
    186 	(qryp)->pri.cmd_0002.pri[2] = cfi_unpack_1(data[0x02]);		\
    187 	(qryp)->pri.cmd_0002.version_maj = cfi_unpack_1(data[0x03]);	\
    188 	(qryp)->pri.cmd_0002.version_min = cfi_unpack_1(data[0x04]);	\
    189 	(qryp)->pri.cmd_0002.asupt = cfi_unpack_1(data[0x05]);		\
    190 	(qryp)->pri.cmd_0002.erase_susp = cfi_unpack_1(data[0x06]);	\
    191 	(qryp)->pri.cmd_0002.sector_prot = cfi_unpack_1(data[0x07]);	\
    192 	(qryp)->pri.cmd_0002.tmp_sector_unprot =			\
    193 		cfi_unpack_1(data[0x08]);				\
    194 	(qryp)->pri.cmd_0002.sector_prot_scheme =			\
    195 		cfi_unpack_1(data[0x09]);				\
    196 	(qryp)->pri.cmd_0002.simul_op = cfi_unpack_1(data[0x0a]);	\
    197 	(qryp)->pri.cmd_0002.burst_mode_type = cfi_unpack_1(data[0x0b]);\
    198 	(qryp)->pri.cmd_0002.page_mode_type = cfi_unpack_1(data[0x0c]);	\
    199 	(qryp)->pri.cmd_0002.acc_min = cfi_unpack_1(data[0x0d]);	\
    200 	(qryp)->pri.cmd_0002.acc_max = cfi_unpack_1(data[0x0e]);	\
    201 	(qryp)->pri.cmd_0002.wp_prot = cfi_unpack_1(data[0x0f]);	\
    202 	/* XXX 1.3 stops here */					\
    203 	(qryp)->pri.cmd_0002.prog_susp = cfi_unpack_1(data[0x10]);	\
    204 	(qryp)->pri.cmd_0002.unlock_bypass = cfi_unpack_1(data[0x11]);	\
    205 	(qryp)->pri.cmd_0002.sss_size = cfi_unpack_1(data[0x12]);	\
    206 	(qryp)->pri.cmd_0002.soft_feat = cfi_unpack_1(data[0x13]);	\
    207 	(qryp)->pri.cmd_0002.page_size = cfi_unpack_1(data[0x14]);	\
    208 	(qryp)->pri.cmd_0002.erase_susp_time_max =			\
    209 		cfi_unpack_1(data[0x15]);				\
    210 	(qryp)->pri.cmd_0002.prog_susp_time_max =			\
    211 		cfi_unpack_1(data[0x16]);				\
    212 	(qryp)->pri.cmd_0002.embhwrst_time_max =			\
    213 		cfi_unpack_1(data[0x38]);				\
    214 	(qryp)->pri.cmd_0002.hwrst_time_max =				\
    215 		cfi_unpack_1(data[0x39]);				\
    216     } while (0)
    217 
    218 #define CFI_QRY_UNPACK_COMMON(cfi, data, type, found)			\
    219     do {								\
    220 	struct cfi_query_data * const qryp = &cfi->cfi_qry_data;	\
    221 									\
    222 	memset(qryp, 0, sizeof(*qryp));					\
    223 	cfi_unpack_qry(qryp, data);					\
    224 									\
    225 	switch (qryp->id_pri) {						\
    226 	case 0x0002:							\
    227 		if ((cfi_unpack_1(data[qryp->addr_pri + 0]) == 'P') &&	\
    228 		    (cfi_unpack_1(data[qryp->addr_pri + 1]) == 'R') &&	\
    229 		    (cfi_unpack_1(data[qryp->addr_pri + 2]) == 'I')) {	\
    230 			type *pri_data = &data[qryp->addr_pri];		\
    231 			cfi_unpack_pri_0002(qryp, pri_data);		\
    232 			found = true;					\
    233 			break;						\
    234 		}							\
    235 	default:							\
    236 		printf("%s: unsupported id_pri=%#x\n",			\
    237 			__func__, qryp->id_pri);			\
    238 		break;	/* unknown command set */			\
    239 	}								\
    240     } while (0)
    241 
    242 /*
    243  * cfi_chip_query_opmode - determine operational mode based on QRY signature
    244  */
    245 static bool
    246 cfi_chip_query_opmode(struct cfi *cfi, uint8_t *data,
    247     const struct cfi_opmodes *tab, u_int nentries)
    248 {
    249 	for (u_int i=0; i < nentries; i++) {
    250 		if (memcmp(&data[tab[i].qsa], tab[i].sig, tab[i].len) == 0) {
    251 			cfi->cfi_opmode = &tab[i];
    252 			return true;
    253 		}
    254 	}
    255 	return false;
    256 }
    257 
    258 static bool
    259 cfi_chip_query_1(struct cfi * const cfi)
    260 {
    261 	uint8_t data[0x80];
    262 
    263 	bus_space_read_region_1(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
    264 		__arraycount(data));
    265 
    266 	bool found = cfi_chip_query_opmode(cfi, data, cfi_opmodes_1,
    267 		__arraycount(cfi_opmodes_1));
    268 
    269 	if (found) {
    270 		CFI_QRY_UNPACK_COMMON(cfi, data, uint8_t, found);
    271 	}
    272 
    273 	return found;
    274 }
    275 
    276 static bool
    277 cfi_chip_query_2(struct cfi * const cfi)
    278 {
    279 	uint16_t data[0x80];
    280 
    281 	bus_space_read_region_2(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
    282 		__arraycount(data));
    283 
    284 	bool found = cfi_chip_query_opmode(cfi, (uint8_t *)data,
    285 		cfi_opmodes_2, __arraycount(cfi_opmodes_2));
    286 
    287 	if (found) {
    288 		CFI_QRY_UNPACK_COMMON(cfi, data, uint16_t, found);
    289 	}
    290 
    291 	return found;
    292 }
    293 
    294 static bool
    295 cfi_chip_query_4(struct cfi * const cfi)
    296 {
    297 	uint32_t data[0x80];
    298 
    299 	bus_space_read_region_4(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
    300 		__arraycount(data));
    301 
    302 	bool found = cfi_chip_query_opmode(cfi, (uint8_t *)data,
    303 		cfi_opmodes_4, __arraycount(cfi_opmodes_4));
    304 
    305 	if (found) {
    306 		CFI_QRY_UNPACK_COMMON(cfi, data, uint32_t, found);
    307 	}
    308 
    309 	return found;
    310 }
    311 
    312 static bool
    313 cfi_chip_query_8(struct cfi * const cfi)
    314 {
    315 #ifdef NOTYET
    316 	uint64_t data[0x80];
    317 
    318 	bus_space_read_region_8(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
    319 		__arraycount(data));
    320 
    321 	bool found = cfi_chip_query_opmode(cfi, (uint8_t *)data,
    322 		cfi_opmodes_8, __arraycount(cfi_opmodes_8));
    323 
    324 	if (found) {
    325 		CFI_QRY_UNPACK_COMMON(cfi, data, uint64_t, found);
    326 	}
    327 
    328 	return found;
    329 #else
    330 	return false;
    331 #endif
    332 }
    333 
    334 /*
    335  * cfi_chip_query - detect a CFI chip
    336  *
    337  * fill in the struct cfi as we discover what's there
    338  */
    339 static bool
    340 cfi_chip_query(struct cfi * const cfi)
    341 {
    342 	bool found = false;
    343 	const bus_size_t cfi_query_offset[] = {
    344 		CFI_QUERY_MODE_ADDRESS,
    345 		CFI_QUERY_MODE_ALT_ADDRESS
    346 	};
    347 
    348 	KASSERT(cfi != NULL);
    349 	KASSERT(cfi->cfi_bst != NULL);
    350 
    351 	for (int j=0; !found && j < __arraycount(cfi_query_offset); j++) {
    352 
    353 		cfi_reset_default(cfi);
    354 		cfi_cmd(cfi, cfi_query_offset[j], CFI_QUERY_DATA);
    355 
    356 		switch(cfi->cfi_portwidth) {
    357 		case 0:
    358 			found = cfi_chip_query_1(cfi);
    359 			break;
    360 		case 1:
    361 			found = cfi_chip_query_2(cfi);
    362 			break;
    363 		case 2:
    364 			found = cfi_chip_query_4(cfi);
    365 			break;
    366 		case 3:
    367 			found = cfi_chip_query_8(cfi);
    368 			break;
    369 		default:
    370 			panic("%s: bad portwidth %d\n",
    371 				__func__, cfi->cfi_portwidth);
    372 		}
    373 	}
    374 
    375 	return found;
    376 }
    377 
    378 /*
    379  * cfi_probe - search for a CFI NOR trying various port & chip widths
    380  *
    381  * NOTE:
    382  *   striped NOR chips design not supported yet,
    383  *   so force portwidth=chipwidth for now
    384  *   eventually permute portwidth seperately
    385  */
    386 bool
    387 cfi_probe(struct cfi * const cfi)
    388 {
    389 	bool found;
    390 
    391 	KASSERT(cfi != NULL);
    392 
    393 	for (u_int cw = 0; cw < 3; cw++) {
    394 		cfi->cfi_portwidth = 		/* XXX */
    395 		cfi->cfi_chipwidth = cw;
    396 		found = cfi_chip_query(cfi);
    397 		if (found)
    398 			goto out;
    399 	}
    400  out:
    401 	cfi_reset_default(cfi);		/* exit QRY mode */
    402 	return found;
    403 }
    404 
    405 bool
    406 cfi_identify(struct cfi * const cfi)
    407 {
    408 	const bus_space_tag_t bst = cfi->cfi_bst;
    409 	const bus_space_handle_t bsh = cfi->cfi_bsh;
    410 	bool found = true;
    411 
    412 	KASSERT(cfi != NULL);
    413 	KASSERT(bst != NULL);
    414 
    415 	memset(cfi, 0, sizeof(struct cfi));	/* XXX clean slate */
    416 	cfi->cfi_bst = bst;		/* restore bus space */
    417 	cfi->cfi_bsh = bsh;		/*  "       "   "    */
    418 
    419 	/* gather CFI PRQ and PRI data */
    420 	if (! cfi_probe(cfi)) {
    421 		aprint_debug("%s: cfi_probe failed\n", __func__);
    422 		found = false;
    423 		goto out;
    424 	}
    425 
    426 	/* gather ID data if possible */
    427 	if (! cfi_jedec_id(cfi)) {
    428 		aprint_debug("%s: cfi_jedec_id failed\n", __func__);
    429 		goto out;
    430 	}
    431 
    432  out:
    433 	cfi_reset_default(cfi);	/* exit QRY mode */
    434 
    435 	return found;
    436 }
    437 
    438 static int
    439 cfi_scan_media(device_t self, struct nor_chip *chip)
    440 {
    441 	struct nor_softc *sc = device_private(self);
    442 	KASSERT(sc != NULL);
    443 	KASSERT(sc->sc_nor_if != NULL);
    444 	struct cfi * const cfi = (struct cfi * const)sc->sc_nor_if->private;
    445 	KASSERT(cfi != NULL);
    446 
    447 	sc->sc_nor_if->access_width = cfi->cfi_portwidth;
    448 
    449 	chip->nc_manf_id = cfi->cfi_id_data.id_mid;
    450 	chip->nc_dev_id = cfi->cfi_id_data.id_did[0]; /* XXX 3 words */
    451 	chip->nc_size = 1 << cfi->cfi_qry_data.device_size;
    452 
    453 	/* size of line for Read Buf command */
    454 	chip->nc_line_size = 1 << cfi->cfi_qry_data.pri.cmd_0002.page_size;
    455 
    456 	/*
    457 	 * size of erase block
    458 	 * XXX depends on erase region
    459 	 */
    460 	chip->nc_num_luns = 1;
    461 	chip->nc_lun_blocks = cfi->cfi_qry_data.erase_blk_info[0].y + 1;
    462 	chip->nc_block_size = cfi->cfi_qry_data.erase_blk_info[0].z * 256;
    463 
    464 	switch (cfi->cfi_qry_data.id_pri) {
    465 	case 0x0002:
    466 		cfi_0002_init(sc, cfi, chip);
    467 		break;
    468 	default:
    469 		return -1;
    470 	}
    471 
    472 	return 0;
    473 }
    474 
    475 void
    476 cfi_init(device_t self)
    477 {
    478 	/* nothing */
    479 }
    480 
    481 static void
    482 cfi_select(device_t self, bool select)
    483 {
    484 	/* nothing */
    485 }
    486 
    487 static void
    488 cfi_read_1(device_t self, flash_off_t offset, uint8_t *datap)
    489 {
    490 }
    491 
    492 static void
    493 cfi_read_2(device_t self, flash_off_t offset, uint16_t *datap)
    494 {
    495 }
    496 
    497 static void
    498 cfi_read_4(device_t self, flash_off_t offset, uint32_t *datap)
    499 {
    500 }
    501 
    502 static void
    503 cfi_read_buf_1(device_t self, flash_off_t offset, uint8_t *datap, size_t size)
    504 {
    505 }
    506 
    507 static void
    508 cfi_read_buf_2(device_t self, flash_off_t offset, uint16_t *datap, size_t size)
    509 {
    510 }
    511 
    512 static void
    513 cfi_read_buf_4(device_t self, flash_off_t offset, uint32_t *datap, size_t size)
    514 {
    515 }
    516 
    517 static void
    518 cfi_write_1(device_t self, flash_off_t offset, uint8_t data)
    519 {
    520 }
    521 
    522 static void
    523 cfi_write_2(device_t self, flash_off_t offset, uint16_t data)
    524 {
    525 }
    526 
    527 static void
    528 cfi_write_4(device_t self, flash_off_t offset, uint32_t data)
    529 {
    530 }
    531 
    532 static void
    533 cfi_write_buf_1(device_t self, flash_off_t offset, const uint8_t *datap,
    534     size_t size)
    535 {
    536 }
    537 
    538 static void
    539 cfi_write_buf_2(device_t self, flash_off_t offset, const uint16_t *datap,
    540     size_t size)
    541 {
    542 }
    543 
    544 static void
    545 cfi_write_buf_4(device_t self, flash_off_t offset, const uint32_t *datap,
    546     size_t size)
    547 {
    548 }
    549 
    550 void
    551 cfi_cmd(struct cfi * const cfi, bus_size_t off, uint32_t val)
    552 {
    553 	const bus_space_tag_t bst = cfi->cfi_bst;
    554 	bus_space_handle_t bsh = cfi->cfi_bsh;
    555 
    556 	off <<= cfi->cfi_portwidth;
    557 
    558 	DPRINTF(("%s: %p %x %x %x\n", __func__, bst, bsh, off, val));
    559 
    560 	switch(cfi->cfi_portwidth) {
    561 	case 0:
    562 		bus_space_write_1(bst, bsh, off, (uint8_t)val);
    563 		break;
    564 	case 1:
    565 		bus_space_write_2(bst, bsh, off, val);
    566 		break;
    567 	case 2:
    568 		bus_space_write_4(bst, bsh, off, (uint32_t)val);
    569 		break;
    570 #ifdef NOTYET
    571 	case 3:
    572 		bus_space_write_4(bst, bsh, off, (uint64_t)val);
    573 		break;
    574 #endif
    575 	default:
    576 		panic("%s: bad portwidth %d bytes\n",
    577 			__func__, 1 << cfi->cfi_portwidth);
    578 	}
    579 }
    580 
    581 /*
    582  * cfi_reset_default - when we don't know which command will work, use both
    583  */
    584 void
    585 cfi_reset_default(struct cfi * const cfi)
    586 {
    587 	cfi_cmd(cfi, CFI_ADDRESS_ANY, CFI_RESET_DATA);
    588 	cfi_cmd(cfi, CFI_ADDRESS_ANY, CFI_ALT_RESET_DATA);
    589 }
    590 
    591 /*
    592  * cfi_reset_std - use standard reset command
    593  */
    594 void
    595 cfi_reset_std(struct cfi * const cfi)
    596 {
    597 	cfi_cmd(cfi, CFI_ADDRESS_ANY, CFI_RESET_DATA);
    598 }
    599 
    600 /*
    601  * cfi_reset_alt - use "alternate" reset command
    602  */
    603 void
    604 cfi_reset_alt(struct cfi * const cfi)
    605 {
    606 	cfi_cmd(cfi, CFI_ADDRESS_ANY, CFI_ALT_RESET_DATA);
    607 }
    608 
    609 static void
    610 cfi_jedec_id_2(struct cfi * const cfi)
    611 {
    612 	struct cfi_jedec_id_data *idp = &cfi->cfi_id_data;
    613 	uint16_t data[0x10];
    614 
    615 	bus_space_read_region_2(cfi->cfi_bst, cfi->cfi_bsh, 0, data,
    616 		__arraycount(data));
    617 
    618 	idp->id_mid = data[0];
    619 	idp->id_did[0] = data[1];
    620 	idp->id_did[1] = data[0xe];
    621 	idp->id_did[2] = data[0xf];
    622 	idp->id_prot_state = data[2];
    623 	idp->id_indicators = data[3];
    624 
    625 	/* software bits, upper and lower
    626 	 * - undefined on S29GL-P
    627 	 * - defined   on S29GL-S
    628 	 */
    629 	idp->id_swb_lo = data[0xc];
    630 	idp->id_swb_hi = data[0xd];
    631 }
    632 
    633 /*
    634  * cfi_jedec_id - get JEDEC ID info
    635  *
    636  * this should be ignored altogether for CFI chips?
    637  * JEDEC ID is superceded by CFI info except CFI is not
    638  * a true superset of the JEDEC, so some info provided
    639  * by JEDEC is not available via CFI QRY.
    640  * But the JEDEC info is unreliable:
    641  * - different chips not distinguishaable by IDs
    642  * - some fields undefined (read as 0xff) on some chips
    643  */
    644 static bool
    645 cfi_jedec_id(struct cfi * const cfi)
    646 {
    647 	DPRINTF(("%s\n", __func__));
    648 
    649 	cfi_cmd(cfi, 0x555, 0xaa);
    650 	cfi_cmd(cfi, 0x2aa, 0x55);
    651 	cfi_cmd(cfi, 0x555, 0x90);
    652 
    653 	switch(cfi->cfi_portwidth) {
    654 	case 1:
    655 		cfi_jedec_id_2(cfi);
    656 		break;
    657 #ifdef NOTYET
    658 	case 0:
    659 		cfi_jedec_id_1(cfi);
    660 		break;
    661 	case 2:
    662 		cfi_jedec_id_4(cfi);
    663 		break;
    664 	case 3:
    665 		cfi_jedec_id_8(cfi);
    666 		break;
    667 #endif
    668 	default:
    669 		panic("%s: bad portwidth %d bytes\n",
    670 			__func__, 1 << cfi->cfi_portwidth);
    671 	}
    672 
    673 	return true;
    674 }
    675 
    676 void
    677 cfi_print(device_t self, struct cfi * const cfi)
    678 {
    679 	char pbuf[sizeof("XXXX MB")];
    680 	struct cfi_query_data * const qryp = &cfi->cfi_qry_data;
    681 
    682 	format_bytes(pbuf, sizeof(pbuf), 1 << qryp->device_size);
    683 	aprint_normal_dev(self, "CFI NOR flash %s %s\n", pbuf,
    684 		cfi_interface_desc_str(qryp->interface_code_desc));
    685 #ifdef NOR_VERBOSE
    686 	aprint_normal_dev(self, "manufacturer id %#x, device id %#x %#x %#x\n",
    687 		cfi->cfi_id_data.id_mid,
    688 		cfi->cfi_id_data.id_did[0],
    689 		cfi->cfi_id_data.id_did[1],
    690 		cfi->cfi_id_data.id_did[2]);
    691 	aprint_normal_dev(self, "%s\n", cfi->cfi_opmode->str);
    692 	aprint_normal_dev(self, "sw bits lo=%#x hi=%#x\n",
    693 		cfi->cfi_id_data.id_swb_lo,
    694 		cfi->cfi_id_data.id_swb_hi);
    695 	aprint_normal_dev(self, "max multibyte write size %d\n",
    696 		1 << qryp->write_nbyte_size_max);
    697 	aprint_normal_dev(self, "%d Erase Block Region(s)\n",
    698 		qryp->erase_blk_regions);
    699 	for (u_int r=0; r < qryp->erase_blk_regions; r++) {
    700 		size_t sz = qryp->erase_blk_info[r].z * 256;
    701 		format_bytes(pbuf, sizeof(pbuf), sz);
    702 		aprint_normal("    %d: %d blocks, size %s\n", r,
    703 			qryp->erase_blk_info[r].y + 1, pbuf);
    704 	}
    705 #endif
    706 
    707 	switch (cfi->cfi_qry_data.id_pri) {
    708 	case 0x0002:
    709 		cfi_0002_print(self, cfi);
    710 		break;
    711 	}
    712 }
    713