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