Home | History | Annotate | Line # | Download | only in vr
flash_vrip.c revision 1.1
      1 /* $NetBSD: flash_vrip.c,v 1.1 2003/05/01 07:02:03 igy Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2002 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Naoto Shimazaki of YOKOGAWA Electric Corporation.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 /*
     40  * Flash Memory Driver
     41  */
     42 
     43 #include <sys/param.h>
     44 #include <sys/conf.h>
     45 #include <sys/device.h>
     46 #include <sys/kernel.h>
     47 #include <sys/malloc.h>
     48 #include <sys/proc.h>
     49 #include <sys/systm.h>
     50 
     51 #include <machine/bus.h>
     52 
     53 #include <hpcmips/vr/vripif.h>
     54 #include <hpcmips/vr/cfireg.h>
     55 #include <hpcmips/vr/flashreg.h>
     56 #include <hpcmips/vr/flashvar.h>
     57 
     58 #ifdef FLASH_DEBUG
     59 int	flash_debug = 0;
     60 #define DPRINTF(x)	if (flash_debug) printf x
     61 #else
     62 #define DPRINTF(x)
     63 #endif
     64 
     65 static int flash_probe(struct device *, struct cfdata *, void *);
     66 static void flash_attach(struct device *, struct device *, void *);
     67 
     68 const static struct flashops * find_command_set(u_int8_t cmdset0,
     69 						u_int8_t cmdset1);
     70 static int i28f128_probe(bus_space_tag_t, bus_space_handle_t);
     71 static int mbm29160_probe(bus_space_tag_t, bus_space_handle_t);
     72 static int is_block_same(struct flash_softc *, bus_size_t, const void *);
     73 static int probe_cfi(bus_space_tag_t iot, bus_space_handle_t ioh);
     74 
     75 static int intel_erase(struct flash_softc *, bus_size_t);
     76 static int intel_write(struct flash_softc *, bus_size_t);
     77 static int amd_erase(struct flash_softc *, bus_size_t);
     78 static int amd_write(struct flash_softc *, bus_size_t);
     79 
     80 extern struct cfdriver flash_cd;
     81 
     82 CFATTACH_DECL(flash_vrip, sizeof(struct flash_softc),
     83 	      flash_probe, flash_attach, NULL, NULL);
     84 
     85 dev_type_open(flashopen);
     86 dev_type_close(flashclose);
     87 dev_type_read(flashread);
     88 dev_type_write(flashwrite);
     89 
     90 const struct cdevsw flash_cdevsw = {
     91 	flashopen, flashclose, flashread, flashwrite, noioctl,
     92 	nostop, notty, nopoll, nommap, nokqfilter,
     93 };
     94 
     95 static const struct flash_command_set {
     96 	u_int8_t	fc_set0;
     97 	u_int8_t	fc_set1;
     98 	struct flashops	fc_ops;
     99 } flash_cmd[] = {
    100 	{
    101 		.fc_set0	= CFI_COMMSET_INTEL0,
    102 		.fc_set1	= CFI_COMMSET_INTEL1,
    103 		.fc_ops		= {
    104 			.fo_name	= "Intel",
    105 			.fo_erase	= intel_erase,
    106 			.fo_write	= intel_write,
    107 		}
    108 	},
    109 	{
    110 		.fc_set0	= CFI_COMMSET_AMDFJITU0,
    111 		.fc_set1	= CFI_COMMSET_AMDFJITU1,
    112 		.fc_ops		= {
    113 			.fo_name	= "AMD/Fujitsu",
    114 			.fo_erase	= amd_erase,
    115 			.fo_write	= amd_write,
    116 		}
    117 	},
    118 	{
    119 		.fc_set0	= 0,
    120 		.fc_set1	= 0,
    121 		.fc_ops		= {
    122 			.fo_name	= NULL,
    123 			.fo_erase	= NULL,
    124 			.fo_write	= NULL,
    125 		}
    126 	}
    127 };
    128 
    129 
    130 const static struct flashops *
    131 find_command_set(u_int8_t cmdset0, u_int8_t cmdset1)
    132 {
    133 	const struct flash_command_set	*fc;
    134 
    135 	for (fc = flash_cmd; fc->fc_ops.fo_name; fc++) {
    136 		if (cmdset0 == fc->fc_set0 && cmdset1 == fc->fc_set1)
    137 			return &fc->fc_ops;
    138 	}
    139 	return NULL;
    140 }
    141 
    142 static int
    143 probe_cfi(bus_space_tag_t iot, bus_space_handle_t ioh)
    144 {
    145 	const u_int8_t	*idstr = CFI_QUERY_ID_STR;
    146 	int		i;
    147 	u_int8_t	cmdset0;
    148 	u_int8_t	cmdset1;
    149 
    150 	/* start Common Flash Interface Query */
    151 	bus_space_write_2(iot, ioh, CFI_QUERY_OFFSET, CFI_READ_CFI_QUERY);
    152 
    153 	/* read CFI Query ID string */
    154 	i = CFI_QUERY_ID_STR_REG << 1;
    155 	do {
    156 		if (bus_space_read_2(iot, ioh, i) != *idstr) {
    157 			bus_space_write_2(iot, ioh, 0, FLASH_RESET);
    158 			return 1;
    159 		}
    160 		i += 2;
    161 		idstr++;
    162 	} while (*idstr);
    163 
    164 	cmdset0 = bus_space_read_2(iot, ioh, CFI_PRIM_COMM_REG0 << 1);
    165 	cmdset1 = bus_space_read_2(iot, ioh, CFI_PRIM_COMM_REG1 << 1);
    166 
    167 	/* switch flash to read mode */
    168 	bus_space_write_2(iot, ioh, 0, FLASH_RESET);
    169 
    170 	if (!find_command_set(cmdset0, cmdset1))
    171 		return 1;
    172 
    173 	return 0;
    174 }
    175 
    176 static int
    177 flash_probe(struct device *parent, struct cfdata *match, void *aux)
    178 {
    179 	struct vrip_attach_args	*va = aux;
    180 	bus_space_handle_t	ioh;
    181 
    182 	if (bus_space_map(va->va_iot, va->va_addr, va->va_size, 0, &ioh))
    183 		return 0;
    184 	if (!probe_cfi(va->va_iot, ioh)) {
    185 		DPRINTF("CFI ID str and command set recognized\n");
    186 		goto detect;
    187 	}
    188 	if (!i28f128_probe(va->va_iot, ioh)) {
    189 		DPRINTF("28F128 detected\n");
    190 		goto detect;
    191 	}
    192 	if (!mbm29160_probe(va->va_iot, ioh)) {
    193 		DPRINTF("29LV160 detected\n");
    194 		goto detect;
    195 	}
    196 	return 0;
    197 
    198 detect:
    199 	bus_space_unmap(va->va_iot, ioh, va->va_size);
    200 	return 1;
    201 }
    202 
    203 static void
    204 flash_attach(struct device *parent, struct device *self, void *aux)
    205 {
    206 	struct flash_softc	*sc = (void *) self;
    207 	struct vrip_attach_args	*va = aux;
    208 	int			i;
    209 	int			fence;
    210 	bus_space_tag_t		iot = va->va_iot;
    211 	bus_space_handle_t	ioh;
    212 	size_t			block_size;
    213 
    214 	if (bus_space_map(iot, va->va_addr, va->va_size, 0, &ioh)) {
    215 		printf(": can't map i/o space\n");
    216                 return;
    217   	}
    218 
    219 	sc->sc_iot = iot;
    220 	sc->sc_ioh = ioh;
    221 	sc->sc_size = va->va_size;
    222 	sc->sc_status = 0;
    223 
    224 	/*
    225 	 * Read entire CFI structure
    226 	 */
    227 	bus_space_write_2(iot, ioh, CFI_QUERY_OFFSET, CFI_READ_CFI_QUERY);
    228 	for (i = 0; i < CFI_TOTAL_SIZE; i++) {
    229 		sc->sc_cfi_raw[i] = bus_space_read_2(iot, ioh, i << 1);
    230 	}
    231 	bus_space_write_2(iot, ioh, 0, FLASH_RESET);
    232 
    233 	sc->sc_ops = find_command_set(sc->sc_cfi_raw[CFI_PRIM_COMM_REG0],
    234 				      sc->sc_cfi_raw[CFI_PRIM_COMM_REG1]);
    235 	if (sc->sc_ops) {
    236 		printf(": using %s command set", sc->sc_ops->fo_name);
    237 	} else {
    238 		printf("opps sc->sc_ops is NULL\n");
    239 	}
    240 
    241 	/*
    242 	 * determine size of the largest block
    243 	 */
    244 	sc->sc_block_size = 0;
    245 	i = CFI_EBLK1_INFO_REG;
    246 	fence = sc->sc_cfi_raw[CFI_NUM_ERASE_BLK_REG] * CFI_EBLK_INFO_SIZE
    247 		+ i;
    248 	for (; i < fence; i += CFI_EBLK_INFO_SIZE) {
    249 		if (sc->sc_cfi_raw[i + CFI_EBLK_INFO_NSECT0] == 0
    250 		    && sc->sc_cfi_raw[i + CFI_EBLK_INFO_NSECT1] == 0)
    251 			continue;
    252 		block_size
    253 			= (sc->sc_cfi_raw[i + CFI_EBLK_INFO_SECSIZE0] << 8)
    254 			+ (sc->sc_cfi_raw[i + CFI_EBLK_INFO_SECSIZE1] << 16);
    255 		if (sc->sc_block_size < block_size)
    256 			sc->sc_block_size = block_size;
    257 	}
    258 
    259 	if ((sc->sc_buf = malloc(sc->sc_block_size, M_DEVBUF, M_NOWAIT))
    260 	    == NULL) {
    261 		printf(": can't alloc buffer space\n");
    262 		return;
    263 	}
    264 
    265 	sc->sc_write_buffer_size
    266 		= 1 << (sc->sc_cfi_raw[CFI_MAX_WBUF_SIZE_REG0]
    267 			+ (sc->sc_cfi_raw[CFI_MAX_WBUF_SIZE_REG1] << 8));
    268 	sc->sc_typ_word_prog_timo
    269 		= 1 << sc->sc_cfi_raw[CFI_TYP_WORD_PROG_REG];
    270 	sc->sc_max_word_prog_timo
    271 		= 1 << sc->sc_cfi_raw[CFI_MAX_WORD_PROG_REG];
    272 	sc->sc_typ_buffer_write_timo
    273 		= 1 << sc->sc_cfi_raw[CFI_TYP_BUF_WRITE_REG];
    274 	sc->sc_max_buffer_write_timo
    275 		= 1 << sc->sc_cfi_raw[CFI_MAX_BUF_WRITE_REG];
    276 	sc->sc_typ_block_erase_timo
    277 		= 1 << sc->sc_cfi_raw[CFI_TYP_BLOCK_ERASE_REG];
    278 	sc->sc_max_block_erase_timo
    279 		= 1 << sc->sc_cfi_raw[CFI_MAX_BLOCK_ERASE_REG];
    280 
    281 	printf("\n");
    282 
    283 #ifdef FLASH_DEBUG
    284 	printf("read_cfi: extract cfi\n");
    285 	printf("max block size: %dbyte\n", sc->sc_block_size);
    286 	printf("write buffer size: %dbyte\n", sc->sc_write_buffer_size);
    287 	printf("typical word program timeout: %dusec\n",
    288 	       sc->sc_typ_word_prog_timo);
    289 	printf("maximam word program timeout: %dusec (%d time of typ)\n",
    290 	       sc->sc_typ_word_prog_timo * sc->sc_max_word_prog_timo,
    291 	       sc->sc_max_word_prog_timo);
    292 	printf("typical buffer write timeout: %dusec\n",
    293 	       sc->sc_typ_buffer_write_timo);
    294 	printf("maximam buffer write timeout: %dusec (%d time of typ)\n",
    295 	       sc->sc_typ_buffer_write_timo * sc->sc_max_buffer_write_timo,
    296 	       sc->sc_max_buffer_write_timo);
    297 	printf("typical block erase timeout: %dmsec\n",
    298 	       sc->sc_typ_block_erase_timo);
    299 	printf("maximam block erase timeout: %dmsec (%d time of typ)\n",
    300 	       sc->sc_typ_block_erase_timo * sc->sc_max_block_erase_timo,
    301 	       sc->sc_max_block_erase_timo);
    302 
    303 	printf("read_cfi: dump cfi\n");
    304 	for (i = 0; i < CFI_TOTAL_SIZE;) {
    305 		int	j;
    306 		for (j = 0; j < 16; j++) {
    307 			printf("%02x ", sc->sc_cfi_raw[i++]);
    308 		}
    309 		printf("\n");
    310 	}
    311 #endif
    312 }
    313 
    314 int
    315 flashopen(dev_t dev, int flag, int mode, struct proc *p)
    316 {
    317 	struct flash_softc	*sc;
    318 
    319 	if ((sc = device_lookup(&flash_cd, minor(dev))) == NULL)
    320 		return ENXIO;
    321 	if (sc->sc_status & FLASH_ST_BUSY)
    322 		return EBUSY;
    323 	sc->sc_status |= FLASH_ST_BUSY;
    324 	return 0;
    325 }
    326 
    327 int
    328 flashclose(dev_t dev, int flag, int mode, struct proc *p)
    329 {
    330 	struct flash_softc	*sc;
    331 
    332 	sc = device_lookup(&flash_cd, minor(dev));
    333 	sc->sc_status &= ~FLASH_ST_BUSY;
    334 	return 0;
    335 }
    336 
    337 int
    338 flashread(dev_t dev, struct uio *uio, int flag)
    339 {
    340 	struct flash_softc	*sc;
    341 	bus_space_tag_t		iot;
    342 	bus_space_handle_t	ioh;
    343 	bus_size_t		off;
    344 	int			total;
    345 	int			count;
    346 	int			error;
    347 
    348 	sc = device_lookup(&flash_cd, minor(dev));
    349 	iot = sc->sc_iot;
    350 	ioh = sc->sc_ioh;
    351 
    352 	off = uio->uio_offset;
    353 	total = min(sc->sc_size - off, uio->uio_resid);
    354 
    355 	while (total > 0) {
    356 		count = min(sc->sc_block_size, uio->uio_resid);
    357 		bus_space_read_region_1(iot, ioh, off, sc->sc_buf, count);
    358 		if ((error = uiomove(sc->sc_buf, count, uio)) != 0)
    359 			return error;
    360 		off += count;
    361 		total -= count;
    362 	}
    363 	return 0;
    364 }
    365 
    366 
    367 int
    368 flashwrite(dev_t dev, struct uio *uio, int flag)
    369 {
    370 	struct flash_softc	*sc;
    371 	bus_space_tag_t		iot;
    372 	bus_space_handle_t	ioh;
    373 	bus_size_t		off;
    374 	int			stat;
    375 	int			error;
    376 
    377 	sc = device_lookup(&flash_cd, minor(dev));
    378 
    379 	if (sc->sc_size < uio->uio_offset + uio->uio_resid)
    380 		return ENOSPC;
    381 	if (uio->uio_offset % sc->sc_block_size)
    382 		return EINVAL;
    383 	if (uio->uio_resid % sc->sc_block_size)
    384 		return EINVAL;
    385 
    386 	iot = sc->sc_iot;
    387 	ioh = sc->sc_ioh;
    388 
    389 	for (off = uio->uio_offset;
    390 	     uio->uio_resid > 0;
    391 	     off += sc->sc_block_size) {
    392 		if ((error = uiomove(sc->sc_buf, sc->sc_block_size, uio)) != 0)
    393 			return error;
    394 		if (is_block_same(sc, off, sc->sc_buf))
    395 			continue;
    396 		if ((stat = flash_block_erase(sc, off)) != 0) {
    397 			printf("block erase failed status = 0x%x\n", stat);
    398 			return EIO;
    399 		}
    400 		if ((stat = flash_block_write(sc, off)) != 0) {
    401 			printf("block write failed status = 0x%x\n", stat);
    402 			return EIO;
    403 		}
    404 	}
    405 	return 0;
    406 }
    407 
    408 /*
    409  * XXX
    410  * this function is too much specific for the device.
    411  */
    412 static int
    413 i28f128_probe(bus_space_tag_t iot, bus_space_handle_t ioh)
    414 {
    415 	static const u_int8_t	vendor_code[] = {
    416 		0x89,	/* manufacturer code: 	intel */
    417 		0x18,	/* device code:		28F128 */
    418 	};
    419 
    420 	static const u_int8_t	idstr[] = {
    421 		'Q', 'R', 'Y',
    422 		0x01, 0x00,
    423 		0x31, 0x00,
    424 		0xff
    425 	};
    426 
    427 	int	i;
    428 
    429 	/* start Common Flash Interface Query */
    430 	bus_space_write_2(iot, ioh, 0, CFI_READ_CFI_QUERY);
    431 	/* read CFI Query ID string */
    432 	for (i = 0; idstr[i] != 0xff; i++) {
    433 		if (bus_space_read_2(iot, ioh, (0x10 + i) << 1) != idstr[i])
    434 			return 1;
    435 	}
    436 
    437 	/* read manufacturer code and device code */
    438 	if (bus_space_read_2(iot, ioh, 0x00) != vendor_code[0])
    439 		return 1;
    440 	if (bus_space_read_2(iot, ioh, 0x02) != vendor_code[1])
    441 		return 1;
    442 
    443 	bus_space_write_2(iot, ioh, 0, I28F128_RESET);
    444 	return 0;
    445 }
    446 
    447 /*
    448  * XXX
    449  * this function is too much specific for the device.
    450  */
    451 static int
    452 mbm29160_probe(bus_space_tag_t iot, bus_space_handle_t ioh)
    453 {
    454 	static const u_int16_t	vendor_code[] = {
    455 		0x0004,	/* manufacturer code: 	intel */
    456 		0x2249,	/* device code:		29LV160BE */
    457 	};
    458 
    459 	static const u_int8_t	idstr[] = {
    460 		'Q', 'R', 'Y',
    461 		0x02, 0x00,
    462 		0x40, 0x00,
    463 		0xff
    464 	};
    465 
    466 	int	i;
    467 
    468 	/* start Common Flash Interface Query */
    469 	bus_space_write_2(iot, ioh, 0xaa, CFI_READ_CFI_QUERY);
    470 	/* read CFI Query ID string */
    471 	for (i = 0; idstr[i] != 0xff; i++) {
    472 		if (bus_space_read_2(iot, ioh, (0x10 + i) << 1) != idstr[i])
    473 			return 1;
    474 	}
    475 
    476 	bus_space_write_2(iot, ioh, 0, 0xff);
    477 
    478 	/* read manufacturer code and device code */
    479 	bus_space_write_2(iot, ioh, 0x555 << 1, 0xaa);
    480 	bus_space_write_2(iot, ioh, 0x2aa << 1, 0x55);
    481 	bus_space_write_2(iot, ioh, 0x555 << 1, 0x90);
    482 	if (bus_space_read_2(iot, ioh, 0x00) != vendor_code[0])
    483 		return 1;
    484 	if (bus_space_read_2(iot, ioh, 0x02) != vendor_code[1])
    485 		return 1;
    486 
    487 	bus_space_write_2(iot, ioh, 0, 0xff);
    488 	return 0;
    489 }
    490 
    491 static int
    492 is_block_same(struct flash_softc *sc, bus_size_t offset, const void *bufp)
    493 {
    494 	bus_space_tag_t		iot = sc->sc_iot;
    495 	bus_space_handle_t	ioh = sc->sc_ioh;
    496 	const u_int8_t		*p = bufp;
    497 	int			count = sc->sc_block_size;
    498 
    499 	while (count-- > 0) {
    500 		if (bus_space_read_1(iot, ioh, offset++) != *p++)
    501 			return 0;
    502 	}
    503 	return 1;
    504 }
    505 
    506 static int
    507 intel_erase(struct flash_softc *sc, bus_size_t offset)
    508 {
    509 	bus_space_tag_t		iot = sc->sc_iot;
    510 	bus_space_handle_t	ioh = sc->sc_ioh;
    511 	int			status;
    512 	int			i;
    513 
    514 	bus_space_write_2(iot, ioh, offset, I28F128_BLK_ERASE_1ST);
    515 	bus_space_write_2(iot, ioh, offset, I28F128_BLK_ERASE_2ND);
    516 
    517 	for (i = sc->sc_max_block_erase_timo; i > 0; i--) {
    518 		tsleep(sc, PRIBIO, "blockerase",
    519 		       1 + (sc->sc_typ_block_erase_timo * hz) / 1000);
    520 		if ((status = bus_space_read_2(iot, ioh, offset))
    521 		    & I28F128_S_READY)
    522 			break;
    523 	}
    524 
    525 	bus_space_write_2(iot, ioh, offset, I28F128_CLEAR_STATUS);
    526 	bus_space_write_2(iot, ioh, offset, I28F128_RESET);
    527 
    528 	return status & (I28F128_S_ERASE_SUSPEND
    529 			 | I28F128_S_COMSEQ_ERROR
    530 			 | I28F128_S_ERASE_ERROR
    531 			 | I28F128_S_BLOCK_LOCKED);
    532 }
    533 
    534 static int
    535 intel_write(struct flash_softc *sc, bus_size_t offset)
    536 {
    537 	bus_space_tag_t		iot = sc->sc_iot;
    538 	bus_space_handle_t	ioh = sc->sc_ioh;
    539 	int			wbuf_size;
    540 	int			timo;
    541 	int			status;
    542 	bus_size_t		fence;
    543 	int			i;
    544 	const u_int16_t		*p;
    545 
    546 	/* wbuf_size = size in u_int16_t */
    547 	wbuf_size = sc->sc_write_buffer_size >> 1;
    548 
    549 	p = (u_int16_t *) sc->sc_buf;
    550 	fence = offset + sc->sc_block_size;
    551 	do {
    552 		for (timo = sc->sc_max_buffer_write_timo; timo > 0; timo--) {
    553 			bus_space_write_2(iot, ioh, offset,
    554 					  I28F128_WRITE_BUFFER);
    555 			status = bus_space_read_2(iot, ioh, offset);
    556 			if (status & I28F128_XS_BUF_AVAIL)
    557 				break;
    558 			DELAY(sc->sc_typ_buffer_write_timo);
    559 		}
    560 		if (timo == 0) {
    561 			status |= FLASH_TIMEOUT;
    562 			goto errout;
    563 		}
    564 
    565 		bus_space_write_2(iot, ioh, offset, wbuf_size - 1);
    566 
    567 		for (i = wbuf_size; i > 0; i--, p++, offset += 2)
    568 			bus_space_write_2(iot, ioh, offset, *p);
    569 
    570 		bus_space_write_2(iot, ioh, offset, I28F128_WBUF_CONFIRM);
    571 
    572 		do {
    573 			bus_space_write_2(iot, ioh, offset,
    574 					  I28F128_READ_STATUS);
    575 			status = bus_space_read_2(iot, ioh, offset);
    576 		} while (!(status & I28F128_S_READY));
    577 
    578 	} while (offset < fence);
    579 
    580 	bus_space_write_2(iot, ioh, offset, I28F128_CLEAR_STATUS);
    581 	bus_space_write_2(iot, ioh, offset, I28F128_RESET);
    582 
    583 	return 0;
    584 
    585 errout:
    586 	bus_space_write_2(iot, ioh, offset, I28F128_CLEAR_STATUS);
    587 	bus_space_write_2(iot, ioh, offset, I28F128_RESET);
    588 
    589 	status &= (FLASH_TIMEOUT
    590 		   | I28F128_S_PROG_ERROR
    591 		   | I28F128_S_COMSEQ_ERROR
    592 		   | I28F128_S_LOW_VOLTAGE
    593 		   | I28F128_S_PROG_SUSPEND
    594 		   | I28F128_S_BLOCK_LOCKED);
    595 	return status;
    596 }
    597 
    598 static int
    599 amd_erase_sector(struct flash_softc *sc, bus_size_t offset)
    600 {
    601 	bus_space_tag_t		iot = sc->sc_iot;
    602 	bus_space_handle_t	ioh = sc->sc_ioh;
    603 	int			i;
    604 
    605 	DPRINTF(("amd_erase_sector offset = %08lx\n", offset));
    606 
    607 	bus_space_write_2(iot, ioh,
    608 			  MBM29LV160_COMM_ADDR0, MBM29LV160_COMM_CMD0);
    609 	bus_space_write_2(iot, ioh,
    610 			  MBM29LV160_COMM_ADDR1, MBM29LV160_COMM_CMD1);
    611 	bus_space_write_2(iot, ioh,
    612 			  MBM29LV160_COMM_ADDR2, MBM29LV160_ESECT_CMD2);
    613 	bus_space_write_2(iot, ioh,
    614 			  MBM29LV160_COMM_ADDR3, MBM29LV160_ESECT_CMD3);
    615 	bus_space_write_2(iot, ioh,
    616 			  MBM29LV160_COMM_ADDR4, MBM29LV160_ESECT_CMD4);
    617 	bus_space_write_2(iot, ioh, offset, MBM29LV160_ESECT_CMD5);
    618 
    619 	for (i = sc->sc_max_block_erase_timo; i > 0; i--) {
    620 		tsleep(sc, PRIBIO, "blockerase",
    621 		       1 + (sc->sc_typ_block_erase_timo * hz) / 1000);
    622 		if (bus_space_read_2(iot, ioh, offset) == 0xffff)
    623 			return 0;
    624 	}
    625 
    626 	return FLASH_TIMEOUT;
    627 }
    628 
    629 static int
    630 amd_erase(struct flash_softc *sc, bus_size_t offset)
    631 {
    632 	static const struct mbm29lv_subsect {
    633 		u_int16_t	devcode;
    634 		u_int32_t	subsect_mask;
    635 		u_int32_t	subsect_addr;
    636 	} subsect[] = {
    637 		{
    638 			MBM29LV160TE_DEVCODE,
    639 			MBM29LV160_SUBSECT_MASK,
    640 			MBM29LV160TE_SUBSECT_ADDR
    641 		},
    642 		{
    643 			MBM29LV160BE_DEVCODE,
    644 			MBM29LV160_SUBSECT_MASK,
    645 			MBM29LV160BE_SUBSECT_ADDR
    646 		},
    647 		{ 0, 0, 0 }
    648 	};
    649 
    650 	bus_space_tag_t			iot = sc->sc_iot;
    651 	bus_space_handle_t		ioh = sc->sc_ioh;
    652 	u_int16_t			devcode;
    653 	const struct mbm29lv_subsect	*ss;
    654 	bus_size_t			fence;
    655 	int				step;
    656 	int				status;
    657 
    658 	bus_space_write_2(iot, ioh,
    659 			  MBM29LV160_COMM_ADDR0, MBM29LV160_COMM_CMD0);
    660 	bus_space_write_2(iot, ioh,
    661 			  MBM29LV160_COMM_ADDR1, MBM29LV160_COMM_CMD1);
    662 	bus_space_write_2(iot, ioh,
    663 			  MBM29LV160_COMM_ADDR2, MBM29LV160_SIGN_CMD2);
    664 	devcode = bus_space_read_2(iot, ioh, MBM29LV160_DEVCODE_REG);
    665 
    666 	for (ss = subsect; ss->devcode; ss++) {
    667 		if (ss->devcode == devcode)
    668 			break;
    669 	}
    670 	if (ss->devcode == 0) {
    671 		printf("flash: amd_erase(): unknown device code %04x\n",
    672 		       devcode);
    673 		return -1;
    674 	}
    675 
    676 	DPRINTF(("flash: amd_erase(): devcode = %04x subsect = %08x\n",
    677 		 devcode, ss->subsect_addr));
    678 
    679 	fence = offset + sc->sc_block_size;
    680 	step = (offset & ss->subsect_mask) == ss->subsect_addr
    681 		? MBM29LV160_SUBSECT_SIZE : MBM29LV160_SECT_SIZE;
    682 	do {
    683 		if ((status = amd_erase_sector(sc, offset)) != 0)
    684 			return status;
    685 		offset += step;
    686 	} while (offset < fence);
    687 
    688 	return 0;
    689 }
    690 
    691 static int
    692 amd_write(struct flash_softc *sc, bus_size_t offset)
    693 {
    694 	bus_space_tag_t		iot = sc->sc_iot;
    695 	bus_space_handle_t	ioh = sc->sc_ioh;
    696 	int			timo;
    697 	bus_size_t		fence;
    698 	const u_int16_t		*p;
    699 
    700 	p = (u_int16_t *) sc->sc_buf;
    701 	fence = offset + sc->sc_block_size;
    702 	do {
    703 		bus_space_write_2(iot, ioh,
    704 				  MBM29LV160_COMM_ADDR0,
    705 				  MBM29LV160_COMM_CMD0);
    706 		bus_space_write_2(iot, ioh,
    707 				  MBM29LV160_COMM_ADDR1,
    708 				  MBM29LV160_COMM_CMD1);
    709 		bus_space_write_2(iot, ioh,
    710 				  MBM29LV160_COMM_ADDR2,
    711 				  MBM29LV160_PROG_CMD2);
    712 		bus_space_write_2(iot, ioh, offset, *p);
    713 
    714 		for (timo = sc->sc_max_word_prog_timo; timo > 0; timo--) {
    715 			if (bus_space_read_2(iot, ioh, offset) == *p)
    716 				break;
    717 			DELAY(sc->sc_typ_word_prog_timo);
    718 		}
    719 		if (timo == 0)
    720 			return FLASH_TIMEOUT;
    721 
    722 		p++;
    723 		offset += 2;
    724 	} while (offset < fence);
    725 
    726 	return 0;
    727 }
    728