1 1.12 thorpej /* $NetBSD: athflash.c,v 1.12 2021/01/04 17:42:29 thorpej Exp $ */ 2 1.1 gdamore 3 1.1 gdamore /* 4 1.1 gdamore * Copyright (c) 2006 Urbana-Champaign Independent Media Center. 5 1.1 gdamore * Copyright (c) 2006 Garrett D'Amore. 6 1.1 gdamore * All rights reserved. 7 1.1 gdamore * 8 1.1 gdamore * Portions of this code were written by Garrett D'Amore for the 9 1.1 gdamore * Champaign-Urbana Community Wireless Network Project. 10 1.1 gdamore * 11 1.1 gdamore * Redistribution and use in source and binary forms, with or 12 1.1 gdamore * without modification, are permitted provided that the following 13 1.1 gdamore * conditions are met: 14 1.1 gdamore * 1. Redistributions of source code must retain the above copyright 15 1.1 gdamore * notice, this list of conditions and the following disclaimer. 16 1.1 gdamore * 2. Redistributions in binary form must reproduce the above 17 1.1 gdamore * copyright notice, this list of conditions and the following 18 1.1 gdamore * disclaimer in the documentation and/or other materials provided 19 1.1 gdamore * with the distribution. 20 1.1 gdamore * 3. All advertising materials mentioning features or use of this 21 1.1 gdamore * software must display the following acknowledgements: 22 1.1 gdamore * This product includes software developed by the Urbana-Champaign 23 1.1 gdamore * Independent Media Center. 24 1.1 gdamore * This product includes software developed by Garrett D'Amore. 25 1.1 gdamore * 4. Urbana-Champaign Independent Media Center's name and Garrett 26 1.1 gdamore * D'Amore's name may not be used to endorse or promote products 27 1.1 gdamore * derived from this software without specific prior written permission. 28 1.1 gdamore * 29 1.1 gdamore * THIS SOFTWARE IS PROVIDED BY THE URBANA-CHAMPAIGN INDEPENDENT 30 1.1 gdamore * MEDIA CENTER AND GARRETT D'AMORE ``AS IS'' AND ANY EXPRESS OR 31 1.1 gdamore * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 32 1.1 gdamore * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 1.1 gdamore * ARE DISCLAIMED. IN NO EVENT SHALL THE URBANA-CHAMPAIGN INDEPENDENT 34 1.1 gdamore * MEDIA CENTER OR GARRETT D'AMORE BE LIABLE FOR ANY DIRECT, INDIRECT, 35 1.1 gdamore * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 36 1.1 gdamore * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 37 1.1 gdamore * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 38 1.1 gdamore * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 1.1 gdamore * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 40 1.1 gdamore * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 41 1.1 gdamore * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 1.1 gdamore */ 43 1.1 gdamore /* 44 1.1 gdamore * Copyright (c) 2002 The NetBSD Foundation, Inc. 45 1.1 gdamore * All rights reserved. 46 1.1 gdamore * 47 1.1 gdamore * This code is derived from software contributed to The NetBSD Foundation 48 1.1 gdamore * by Naoto Shimazaki of YOKOGAWA Electric Corporation. 49 1.1 gdamore * 50 1.1 gdamore * Redistribution and use in source and binary forms, with or without 51 1.1 gdamore * modification, are permitted provided that the following conditions 52 1.1 gdamore * are met: 53 1.1 gdamore * 1. Redistributions of source code must retain the above copyright 54 1.1 gdamore * notice, this list of conditions and the following disclaimer. 55 1.1 gdamore * 2. Redistributions in binary form must reproduce the above copyright 56 1.1 gdamore * notice, this list of conditions and the following disclaimer in the 57 1.1 gdamore * documentation and/or other materials provided with the distribution. 58 1.1 gdamore * 59 1.1 gdamore * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 60 1.1 gdamore * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 61 1.1 gdamore * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 62 1.1 gdamore * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 63 1.1 gdamore * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 64 1.1 gdamore * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 65 1.1 gdamore * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 66 1.1 gdamore * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 67 1.1 gdamore * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 68 1.1 gdamore * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 69 1.1 gdamore * POSSIBILITY OF SUCH DAMAGE. 70 1.1 gdamore */ 71 1.1 gdamore 72 1.1 gdamore /* 73 1.1 gdamore * Flash Memory Driver 74 1.1 gdamore * 75 1.1 gdamore * XXX This primitive flash driver does *not* support boot sectored devices, 76 1.1 gdamore * XXX and only supports a fairly limited set of devices, that we are likely to 77 1.1 gdamore * XXX to find in an AP30. 78 1.1 gdamore * XXX 79 1.1 gdamore * XXX We also are only supporting flash widths of 16 _for the moment_, and 80 1.1 gdamore * XXX we are only supporting flash devices that use the AMD command sets. 81 1.1 gdamore * XXX All this should be reviewed and improved to be much more generic. 82 1.1 gdamore */ 83 1.1 gdamore 84 1.1 gdamore #include <sys/cdefs.h> 85 1.12 thorpej __KERNEL_RCSID(0, "$NetBSD: athflash.c,v 1.12 2021/01/04 17:42:29 thorpej Exp $"); 86 1.1 gdamore 87 1.1 gdamore #include <sys/param.h> 88 1.1 gdamore #include <sys/conf.h> 89 1.1 gdamore #include <sys/device.h> 90 1.1 gdamore #include <sys/kernel.h> 91 1.12 thorpej #include <sys/kmem.h> 92 1.1 gdamore #include <sys/proc.h> 93 1.1 gdamore #include <sys/systm.h> 94 1.1 gdamore 95 1.4 dyoung #include <sys/bus.h> 96 1.1 gdamore 97 1.1 gdamore #include <mips/atheros/include/arbusvar.h> 98 1.1 gdamore 99 1.1 gdamore #ifdef FLASH_DEBUG 100 1.1 gdamore int flash_debug = 0; 101 1.1 gdamore #define DPRINTF(x) if (flash_debug) printf x 102 1.1 gdamore #else 103 1.1 gdamore #define DPRINTF(x) 104 1.1 gdamore #endif 105 1.1 gdamore 106 1.1 gdamore struct flash_softc { 107 1.1 gdamore bus_space_tag_t sc_iot; 108 1.1 gdamore bus_space_handle_t sc_ioh; 109 1.1 gdamore size_t sc_size; 110 1.1 gdamore size_t sc_sector_size; 111 1.1 gdamore int sc_status; 112 1.1 gdamore u_int8_t *sc_buf; 113 1.1 gdamore }; 114 1.1 gdamore 115 1.1 gdamore #define FLASH_ST_BUSY 0x1 116 1.1 gdamore 117 1.6 chs static int flash_probe(device_t, cfdata_t, void *); 118 1.6 chs static void flash_attach(device_t, device_t, void *); 119 1.1 gdamore 120 1.1 gdamore static int is_block_same(struct flash_softc *, bus_size_t, const void *); 121 1.1 gdamore static int toggle_bit_wait(struct flash_softc *, bus_size_t, int, int, int); 122 1.1 gdamore 123 1.1 gdamore static int flash_sector_erase(struct flash_softc *, bus_size_t); 124 1.1 gdamore static int flash_sector_write(struct flash_softc *, bus_size_t); 125 1.1 gdamore 126 1.1 gdamore extern struct cfdriver athflash_cd; 127 1.1 gdamore 128 1.6 chs CFATTACH_DECL_NEW(athflash, sizeof(struct flash_softc), 129 1.1 gdamore flash_probe, flash_attach, NULL, NULL); 130 1.1 gdamore 131 1.1 gdamore dev_type_open(flashopen); 132 1.1 gdamore dev_type_close(flashclose); 133 1.1 gdamore dev_type_read(flashread); 134 1.1 gdamore dev_type_write(flashwrite); 135 1.1 gdamore 136 1.1 gdamore const struct cdevsw athflash_cdevsw = { 137 1.7 dholland .d_open = flashopen, 138 1.7 dholland .d_close = flashclose, 139 1.7 dholland .d_read = flashread, 140 1.7 dholland .d_write = flashwrite, 141 1.7 dholland .d_ioctl = noioctl, 142 1.7 dholland .d_stop = nostop, 143 1.7 dholland .d_tty = notty, 144 1.7 dholland .d_poll = nopoll, 145 1.7 dholland .d_mmap = nommap, 146 1.7 dholland .d_kqfilter = nokqfilter, 147 1.8 dholland .d_discard = nodiscard, 148 1.7 dholland .d_flag = 0 149 1.1 gdamore }; 150 1.1 gdamore 151 1.1 gdamore static struct { 152 1.1 gdamore uint16_t vendor_id; 153 1.1 gdamore uint16_t device_id; 154 1.1 gdamore const char *name; 155 1.1 gdamore int sector_size; 156 1.1 gdamore int flash_size; 157 1.1 gdamore } flash_ids[] = { 158 1.1 gdamore { 0x00bf, 0x2780, "SST 39VF400", 0x01000, 0x080000 }, /* 512KB */ 159 1.1 gdamore { 0x00bf, 0x2782, "SST 39VF160", 0x01000, 0x200000 }, /* 2MB */ 160 1.1 gdamore { 0xffff, 0xffff, NULL, 0, 0 } /* end list */ 161 1.1 gdamore }; 162 1.1 gdamore 163 1.1 gdamore static int 164 1.6 chs flash_probe(device_t parent, cfdata_t cf, void *aux) 165 1.1 gdamore { 166 1.1 gdamore struct arbus_attach_args *aa = aux; 167 1.1 gdamore bus_space_handle_t ioh; 168 1.1 gdamore int rv = 0, i; 169 1.1 gdamore uint16_t venid, devid; 170 1.1 gdamore 171 1.1 gdamore if (strcmp(aa->aa_name, cf->cf_name) != 0) 172 1.1 gdamore return 0; 173 1.1 gdamore 174 1.1 gdamore DPRINTF(("trying to map address %x\n", (unsigned)aa->aa_addr)); 175 1.1 gdamore if (bus_space_map(aa->aa_bst, aa->aa_addr, aa->aa_size, 0, &ioh)) 176 1.1 gdamore return 0; 177 1.1 gdamore 178 1.1 gdamore /* issue JEDEC query */ 179 1.1 gdamore DPRINTF(("issuing JEDEC query\n")); 180 1.1 gdamore bus_space_write_2(aa->aa_bst, ioh, (0x5555 << 1), 0xAAAA); 181 1.1 gdamore bus_space_write_2(aa->aa_bst, ioh, (0x2AAA << 1), 0x5555); 182 1.1 gdamore bus_space_write_2(aa->aa_bst, ioh, (0x5555 << 1), 0x9090); 183 1.1 gdamore 184 1.1 gdamore delay(100); 185 1.1 gdamore venid = bus_space_read_2(aa->aa_bst, ioh, 0); 186 1.1 gdamore devid = bus_space_read_2(aa->aa_bst, ioh, 2); 187 1.1 gdamore 188 1.1 gdamore /* issue software exit */ 189 1.1 gdamore bus_space_write_2(aa->aa_bst, ioh, 0x0, 0xF0F0); 190 1.1 gdamore 191 1.1 gdamore for (i = 0; flash_ids[i].name != NULL; i++) { 192 1.1 gdamore if ((venid == flash_ids[i].vendor_id) && 193 1.1 gdamore (devid == flash_ids[i].device_id)) { 194 1.1 gdamore rv = 1; 195 1.1 gdamore break; 196 1.1 gdamore } 197 1.1 gdamore } 198 1.1 gdamore 199 1.1 gdamore bus_space_unmap(aa->aa_bst, ioh, aa->aa_size); 200 1.1 gdamore return rv; 201 1.1 gdamore } 202 1.1 gdamore 203 1.1 gdamore static void 204 1.6 chs flash_attach(device_t parent, device_t self, void *aux) 205 1.1 gdamore { 206 1.5 dyoung char nbuf[32]; 207 1.6 chs struct flash_softc *sc = device_private(self); 208 1.1 gdamore struct arbus_attach_args *aa = aux; 209 1.1 gdamore int i; 210 1.1 gdamore bus_space_tag_t iot = aa->aa_bst; 211 1.1 gdamore bus_space_handle_t ioh; 212 1.1 gdamore uint16_t venid, devid; 213 1.1 gdamore 214 1.1 gdamore if (bus_space_map(iot, aa->aa_addr, aa->aa_size, 0, &ioh)) { 215 1.1 gdamore printf(": can't map i/o space\n"); 216 1.1 gdamore return; 217 1.1 gdamore } 218 1.1 gdamore 219 1.1 gdamore sc->sc_iot = iot; 220 1.1 gdamore sc->sc_ioh = ioh; 221 1.1 gdamore sc->sc_status = 0; 222 1.1 gdamore 223 1.1 gdamore /* issue JEDEC query */ 224 1.1 gdamore bus_space_write_2(aa->aa_bst, ioh, (0x5555 << 1), 0xAAAA); 225 1.1 gdamore bus_space_write_2(aa->aa_bst, ioh, (0x2AAA << 1), 0x5555); 226 1.1 gdamore bus_space_write_2(aa->aa_bst, ioh, (0x5555 << 1), 0x9090); 227 1.1 gdamore 228 1.1 gdamore delay(100); 229 1.1 gdamore venid = bus_space_read_2(aa->aa_bst, ioh, 0); 230 1.1 gdamore devid = bus_space_read_2(aa->aa_bst, ioh, 2); 231 1.1 gdamore 232 1.1 gdamore /* issue software exit */ 233 1.1 gdamore bus_space_write_2(aa->aa_bst, ioh, 0x0, 0xF0F0); 234 1.1 gdamore 235 1.1 gdamore for (i = 0; flash_ids[i].name != NULL; i++) { 236 1.1 gdamore if ((venid == flash_ids[i].vendor_id) && 237 1.1 gdamore (devid == flash_ids[i].device_id)) { 238 1.1 gdamore break; 239 1.1 gdamore } 240 1.1 gdamore } 241 1.1 gdamore 242 1.1 gdamore KASSERT(flash_ids[i].name != NULL); 243 1.5 dyoung printf(": %s", flash_ids[i].name); 244 1.5 dyoung if (humanize_number(nbuf, sizeof(nbuf), flash_ids[i].flash_size, "B", 245 1.5 dyoung 1024) > 0) 246 1.5 dyoung printf(" (%s)", nbuf); 247 1.1 gdamore 248 1.1 gdamore /* 249 1.1 gdamore * determine size of the largest block 250 1.1 gdamore */ 251 1.1 gdamore sc->sc_size = flash_ids[i].flash_size; 252 1.1 gdamore sc->sc_sector_size = flash_ids[i].sector_size; 253 1.5 dyoung 254 1.12 thorpej sc->sc_buf = kmem_alloc(sc->sc_sector_size, KM_SLEEP); 255 1.1 gdamore 256 1.1 gdamore printf("\n"); 257 1.1 gdamore } 258 1.1 gdamore 259 1.1 gdamore int 260 1.1 gdamore flashopen(dev_t dev, int flag, int mode, struct lwp *l) 261 1.1 gdamore { 262 1.1 gdamore struct flash_softc *sc; 263 1.1 gdamore 264 1.3 cegger sc = device_lookup_private(&athflash_cd, minor(dev)); 265 1.3 cegger if (sc == NULL) 266 1.1 gdamore return ENXIO; 267 1.1 gdamore if (sc->sc_status & FLASH_ST_BUSY) 268 1.1 gdamore return EBUSY; 269 1.1 gdamore sc->sc_status |= FLASH_ST_BUSY; 270 1.1 gdamore return 0; 271 1.1 gdamore } 272 1.1 gdamore 273 1.1 gdamore int 274 1.1 gdamore flashclose(dev_t dev, int flag, int mode, struct lwp *l) 275 1.1 gdamore { 276 1.1 gdamore struct flash_softc *sc; 277 1.1 gdamore 278 1.3 cegger sc = device_lookup_private(&athflash_cd, minor(dev)); 279 1.1 gdamore sc->sc_status &= ~FLASH_ST_BUSY; 280 1.1 gdamore return 0; 281 1.1 gdamore } 282 1.1 gdamore 283 1.1 gdamore int 284 1.1 gdamore flashread(dev_t dev, struct uio *uio, int flag) 285 1.1 gdamore { 286 1.1 gdamore struct flash_softc *sc; 287 1.1 gdamore bus_space_tag_t iot; 288 1.1 gdamore bus_space_handle_t ioh; 289 1.1 gdamore bus_size_t off; 290 1.1 gdamore int total; 291 1.1 gdamore int count; 292 1.1 gdamore int error; 293 1.1 gdamore 294 1.3 cegger sc = device_lookup_private(&athflash_cd, minor(dev)); 295 1.1 gdamore iot = sc->sc_iot; 296 1.1 gdamore ioh = sc->sc_ioh; 297 1.1 gdamore 298 1.1 gdamore off = uio->uio_offset; 299 1.10 riastrad total = uimin(sc->sc_size - off, uio->uio_resid); 300 1.1 gdamore 301 1.1 gdamore while (total > 0) { 302 1.10 riastrad count = uimin(sc->sc_sector_size, uio->uio_resid); 303 1.1 gdamore bus_space_read_region_1(iot, ioh, off, sc->sc_buf, count); 304 1.1 gdamore if ((error = uiomove(sc->sc_buf, count, uio)) != 0) 305 1.1 gdamore return error; 306 1.1 gdamore off += count; 307 1.1 gdamore total -= count; 308 1.1 gdamore } 309 1.1 gdamore return 0; 310 1.1 gdamore } 311 1.1 gdamore 312 1.1 gdamore 313 1.1 gdamore int 314 1.1 gdamore flashwrite(dev_t dev, struct uio *uio, int flag) 315 1.1 gdamore { 316 1.1 gdamore struct flash_softc *sc; 317 1.1 gdamore bus_size_t off; 318 1.1 gdamore int stat; 319 1.1 gdamore int error; 320 1.1 gdamore 321 1.3 cegger sc = device_lookup_private(&athflash_cd, minor(dev)); 322 1.1 gdamore 323 1.1 gdamore if (sc->sc_size < uio->uio_offset + uio->uio_resid) 324 1.1 gdamore return ENOSPC; 325 1.1 gdamore if (uio->uio_offset % sc->sc_sector_size) 326 1.1 gdamore return EINVAL; 327 1.1 gdamore if (uio->uio_resid % sc->sc_sector_size) 328 1.1 gdamore return EINVAL; 329 1.1 gdamore 330 1.1 gdamore for (off = uio->uio_offset; 331 1.1 gdamore uio->uio_resid > 0; 332 1.1 gdamore off += sc->sc_sector_size) { 333 1.1 gdamore error = uiomove(sc->sc_buf, sc->sc_sector_size, uio); 334 1.1 gdamore if (error != 0) 335 1.1 gdamore return error; 336 1.1 gdamore if (is_block_same(sc, off, sc->sc_buf)) 337 1.1 gdamore continue; 338 1.1 gdamore if ((stat = flash_sector_erase(sc, off)) != 0) { 339 1.1 gdamore printf("sector erase failed status = 0x%x\n", stat); 340 1.1 gdamore return EIO; 341 1.1 gdamore } 342 1.1 gdamore if ((stat = flash_sector_write(sc, off)) != 0) { 343 1.1 gdamore printf("sector write failed status = 0x%x\n", stat); 344 1.1 gdamore return EIO; 345 1.1 gdamore } 346 1.1 gdamore } 347 1.1 gdamore return 0; 348 1.1 gdamore } 349 1.1 gdamore 350 1.1 gdamore static int 351 1.1 gdamore is_block_same(struct flash_softc *sc, bus_size_t offset, const void *bufp) 352 1.1 gdamore { 353 1.1 gdamore bus_space_tag_t iot = sc->sc_iot; 354 1.1 gdamore bus_space_handle_t ioh = sc->sc_ioh; 355 1.1 gdamore const u_int8_t *p = bufp; 356 1.1 gdamore int count = sc->sc_sector_size; 357 1.1 gdamore 358 1.1 gdamore while (count-- > 0) { 359 1.1 gdamore if (bus_space_read_1(iot, ioh, offset++) != *p++) 360 1.1 gdamore return 0; 361 1.1 gdamore } 362 1.1 gdamore return 1; 363 1.1 gdamore } 364 1.1 gdamore 365 1.1 gdamore static int 366 1.1 gdamore toggle_bit_wait(struct flash_softc *sc, bus_size_t offset, 367 1.1 gdamore int typtmo, int maxtmo, int spin) 368 1.1 gdamore { 369 1.1 gdamore bus_space_tag_t iot = sc->sc_iot; 370 1.1 gdamore bus_space_handle_t ioh = sc->sc_ioh; 371 1.1 gdamore uint8_t d1, d2; 372 1.1 gdamore 373 1.1 gdamore while (maxtmo > 0) { 374 1.1 gdamore 375 1.1 gdamore if (spin) { 376 1.1 gdamore DELAY(typtmo); 377 1.1 gdamore } else { 378 1.1 gdamore tsleep(sc, PRIBIO, "blockerase", 379 1.1 gdamore (typtmo / hz) + 1); 380 1.1 gdamore } 381 1.1 gdamore 382 1.1 gdamore d1 = bus_space_read_1(iot, ioh, offset); 383 1.1 gdamore d2 = bus_space_read_2(iot, ioh, offset); 384 1.1 gdamore 385 1.1 gdamore /* watch for the toggle bit to stop toggling */ 386 1.1 gdamore if ((d1 & 0x40) == (d2 & 0x40)) { 387 1.1 gdamore return 0; 388 1.1 gdamore } 389 1.1 gdamore 390 1.1 gdamore maxtmo -= typtmo; 391 1.1 gdamore } 392 1.1 gdamore return (ETIMEDOUT); 393 1.1 gdamore } 394 1.1 gdamore 395 1.1 gdamore static int 396 1.1 gdamore flash_sector_erase(struct flash_softc *sc, bus_size_t offset) 397 1.1 gdamore { 398 1.1 gdamore bus_space_tag_t iot = sc->sc_iot; 399 1.1 gdamore bus_space_handle_t ioh = sc->sc_ioh; 400 1.1 gdamore 401 1.1 gdamore DPRINTF(("flash_sector_erase offset = %08lx\n", offset)); 402 1.1 gdamore 403 1.1 gdamore bus_space_write_2(iot, ioh, (0x5555 << 1), 0xAAAA); 404 1.1 gdamore bus_space_write_2(iot, ioh, (0x2AAA << 1), 0x5555); 405 1.1 gdamore bus_space_write_2(iot, ioh, (0x5555 << 1), 0x8080); 406 1.1 gdamore bus_space_write_2(iot, ioh, (0x5555 << 1), 0xAAAA); 407 1.1 gdamore bus_space_write_2(iot, ioh, (0x2AAA << 1), 0x5555); 408 1.1 gdamore 409 1.1 gdamore bus_space_write_2(iot, ioh, offset, 0x3030); 410 1.1 gdamore 411 1.1 gdamore /* 412 1.1 gdamore * NB: with CFI, we could get more meaningful timeout data for 413 1.1 gdamore * now we just assign reasonable values - 10 msec typical, and 414 1.1 gdamore * up to 60 secs to erase the whole sector. 415 1.1 gdamore */ 416 1.1 gdamore 417 1.1 gdamore return toggle_bit_wait(sc, offset, 10000, 60000000, 0); 418 1.1 gdamore } 419 1.1 gdamore 420 1.1 gdamore static int 421 1.1 gdamore flash_sector_write(struct flash_softc *sc, bus_size_t offset) 422 1.1 gdamore { 423 1.1 gdamore bus_space_tag_t iot = sc->sc_iot; 424 1.1 gdamore bus_space_handle_t ioh = sc->sc_ioh; 425 1.1 gdamore bus_size_t fence; 426 1.1 gdamore const u_int16_t *p; 427 1.1 gdamore 428 1.1 gdamore p = (u_int16_t *) sc->sc_buf; 429 1.1 gdamore fence = offset + sc->sc_sector_size; 430 1.1 gdamore do { 431 1.1 gdamore bus_space_write_2(iot, ioh, (0x5555 << 1), 0xAAAA); 432 1.1 gdamore bus_space_write_2(iot, ioh, (0x2AAA << 1), 0x5555); 433 1.1 gdamore bus_space_write_2(iot, ioh, (0xAAAA << 1), 0xA0A0); 434 1.1 gdamore 435 1.1 gdamore bus_space_write_2(iot, ioh, offset, *p); 436 1.1 gdamore 437 1.1 gdamore /* wait up to 1 msec, in 10 usec increments, no sleeping */ 438 1.1 gdamore if (toggle_bit_wait(sc, offset, 10, 1000, 1) != 0) 439 1.1 gdamore return ETIMEDOUT; 440 1.1 gdamore p++; 441 1.1 gdamore offset += 2; 442 1.1 gdamore } while (offset < fence); 443 1.1 gdamore 444 1.1 gdamore return 0; 445 1.1 gdamore } 446