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