1 /*- 2 * Copyright (c) 2007, Juniper Networks, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the author nor the names of any co-contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/bus.h> 36 #include <sys/conf.h> 37 #include <sys/kernel.h> 38 #include <sys/malloc.h> 39 #include <sys/module.h> 40 #include <sys/rman.h> 41 #include <sys/sysctl.h> 42 43 #include <machine/bus.h> 44 45 #include <dev/cfi/cfi_reg.h> 46 #include <dev/cfi/cfi_var.h> 47 48 extern struct cdevsw cfi_cdevsw; 49 50 char cfi_driver_name[] = "cfi"; 51 devclass_t cfi_devclass; 52 53 uint32_t 54 cfi_read(struct cfi_softc *sc, u_int ofs) 55 { 56 uint32_t val; 57 58 ofs &= ~(sc->sc_width - 1); 59 switch (sc->sc_width) { 60 case 1: 61 val = bus_space_read_1(sc->sc_tag, sc->sc_handle, ofs); 62 break; 63 case 2: 64 val = bus_space_read_2(sc->sc_tag, sc->sc_handle, ofs); 65 break; 66 case 4: 67 val = bus_space_read_4(sc->sc_tag, sc->sc_handle, ofs); 68 break; 69 default: 70 val = ~0; 71 break; 72 } 73 74 return (val); 75 } 76 77 static void 78 cfi_write(struct cfi_softc *sc, u_int ofs, u_int val) 79 { 80 81 ofs &= ~(sc->sc_width - 1); 82 switch (sc->sc_width) { 83 case 1: 84 bus_space_write_1(sc->sc_tag, sc->sc_handle, ofs, val); 85 break; 86 case 2: 87 bus_space_write_2(sc->sc_tag, sc->sc_handle, ofs, val); 88 break; 89 case 4: 90 bus_space_write_4(sc->sc_tag, sc->sc_handle, ofs, val); 91 break; 92 } 93 } 94 95 uint8_t 96 cfi_read_qry(struct cfi_softc *sc, u_int ofs) 97 { 98 uint8_t val; 99 100 cfi_write(sc, CFI_QRY_CMD_ADDR * sc->sc_width, CFI_QRY_CMD_DATA); 101 val = cfi_read(sc, ofs * sc->sc_width); 102 cfi_write(sc, 0, CFI_BCS_READ_ARRAY); 103 return (val); 104 } 105 106 static void 107 cfi_amd_write(struct cfi_softc *sc, u_int ofs, u_int addr, u_int data) 108 { 109 110 cfi_write(sc, ofs + AMD_ADDR_START, CFI_AMD_UNLOCK); 111 cfi_write(sc, ofs + AMD_ADDR_ACK, CFI_AMD_UNLOCK_ACK); 112 cfi_write(sc, ofs + addr, data); 113 } 114 115 static char * 116 cfi_fmtsize(uint32_t sz) 117 { 118 static char buf[8]; 119 static const char *sfx[] = { "", "K", "M", "G" }; 120 int sfxidx; 121 122 sfxidx = 0; 123 while (sfxidx < 3 && sz > 1023) { 124 sz /= 1024; 125 sfxidx++; 126 } 127 128 sprintf(buf, "%u%sB", sz, sfx[sfxidx]); 129 return (buf); 130 } 131 132 int 133 cfi_probe(device_t dev) 134 { 135 char desc[80]; 136 struct cfi_softc *sc; 137 char *vend_str; 138 int error; 139 uint16_t iface, vend; 140 141 sc = device_get_softc(dev); 142 sc->sc_dev = dev; 143 144 sc->sc_rid = 0; 145 sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid, 146 RF_ACTIVE); 147 if (sc->sc_res == NULL) 148 return (ENXIO); 149 150 sc->sc_tag = rman_get_bustag(sc->sc_res); 151 sc->sc_handle = rman_get_bushandle(sc->sc_res); 152 153 sc->sc_width = 1; 154 while (sc->sc_width <= 4) { 155 if (cfi_read_qry(sc, CFI_QRY_IDENT) == 'Q') 156 break; 157 sc->sc_width <<= 1; 158 } 159 if (sc->sc_width > 4) { 160 error = ENXIO; 161 goto out; 162 } 163 164 /* We got a Q. Check if we also have the R and the Y. */ 165 if (cfi_read_qry(sc, CFI_QRY_IDENT + 1) != 'R' || 166 cfi_read_qry(sc, CFI_QRY_IDENT + 2) != 'Y') { 167 error = ENXIO; 168 goto out; 169 } 170 171 /* Get the vendor and command set. */ 172 vend = cfi_read_qry(sc, CFI_QRY_VEND) | 173 (cfi_read_qry(sc, CFI_QRY_VEND + 1) << 8); 174 175 sc->sc_cmdset = vend; 176 177 switch (vend) { 178 case CFI_VEND_AMD_ECS: 179 case CFI_VEND_AMD_SCS: 180 vend_str = "AMD/Fujitsu"; 181 break; 182 case CFI_VEND_INTEL_ECS: 183 vend_str = "Intel/Sharp"; 184 break; 185 case CFI_VEND_INTEL_SCS: 186 vend_str = "Intel"; 187 break; 188 case CFI_VEND_MITSUBISHI_ECS: 189 case CFI_VEND_MITSUBISHI_SCS: 190 vend_str = "Mitsubishi"; 191 break; 192 default: 193 vend_str = "Unknown vendor"; 194 break; 195 } 196 197 /* Get the device size. */ 198 sc->sc_size = 1U << cfi_read_qry(sc, CFI_QRY_SIZE); 199 200 /* Sanity-check the I/F */ 201 iface = cfi_read_qry(sc, CFI_QRY_IFACE) | 202 (cfi_read_qry(sc, CFI_QRY_IFACE + 1) << 8); 203 204 /* 205 * Adding 1 to iface will give us a bit-wise "switch" 206 * that allows us to test for the interface width by 207 * testing a single bit. 208 */ 209 iface++; 210 211 error = (iface & sc->sc_width) ? 0 : EINVAL; 212 if (error) 213 goto out; 214 215 snprintf(desc, sizeof(desc), "%s - %s", vend_str, 216 cfi_fmtsize(sc->sc_size)); 217 device_set_desc_copy(dev, desc); 218 219 out: 220 bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res); 221 return (error); 222 } 223 224 int 225 cfi_attach(device_t dev) 226 { 227 struct cfi_softc *sc; 228 u_int blksz, blocks; 229 u_int r, u; 230 231 sc = device_get_softc(dev); 232 sc->sc_dev = dev; 233 234 sc->sc_rid = 0; 235 sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid, 236 RF_ACTIVE); 237 if (sc->sc_res == NULL) 238 return (ENXIO); 239 240 sc->sc_tag = rman_get_bustag(sc->sc_res); 241 sc->sc_handle = rman_get_bushandle(sc->sc_res); 242 243 /* Get time-out values for erase and write. */ 244 sc->sc_write_timeout = 1 << cfi_read_qry(sc, CFI_QRY_TTO_WRITE); 245 sc->sc_erase_timeout = 1 << cfi_read_qry(sc, CFI_QRY_TTO_ERASE); 246 sc->sc_write_timeout *= 1 << cfi_read_qry(sc, CFI_QRY_MTO_WRITE); 247 sc->sc_erase_timeout *= 1 << cfi_read_qry(sc, CFI_QRY_MTO_ERASE); 248 249 /* Get erase regions. */ 250 sc->sc_regions = cfi_read_qry(sc, CFI_QRY_NREGIONS); 251 sc->sc_region = malloc(sc->sc_regions * sizeof(struct cfi_region), 252 M_TEMP, M_WAITOK | M_ZERO); 253 for (r = 0; r < sc->sc_regions; r++) { 254 blocks = cfi_read_qry(sc, CFI_QRY_REGION(r)) | 255 (cfi_read_qry(sc, CFI_QRY_REGION(r) + 1) << 8); 256 sc->sc_region[r].r_blocks = blocks + 1; 257 258 blksz = cfi_read_qry(sc, CFI_QRY_REGION(r) + 2) | 259 (cfi_read_qry(sc, CFI_QRY_REGION(r) + 3) << 8); 260 sc->sc_region[r].r_blksz = (blksz == 0) ? 128 : 261 blksz * 256; 262 } 263 264 /* Reset the device to a default state. */ 265 cfi_write(sc, 0, CFI_BCS_CLEAR_STATUS); 266 267 if (bootverbose) { 268 device_printf(dev, "["); 269 for (r = 0; r < sc->sc_regions; r++) { 270 printf("%ux%s%s", sc->sc_region[r].r_blocks, 271 cfi_fmtsize(sc->sc_region[r].r_blksz), 272 (r == sc->sc_regions - 1) ? "]\n" : ","); 273 } 274 } 275 276 u = device_get_unit(dev); 277 sc->sc_nod = make_dev(&cfi_cdevsw, u, UID_ROOT, GID_WHEEL, 0600, 278 "%s%u", cfi_driver_name, u); 279 sc->sc_nod->si_drv1 = sc; 280 281 return (0); 282 } 283 284 int 285 cfi_detach(device_t dev) 286 { 287 struct cfi_softc *sc; 288 289 sc = device_get_softc(dev); 290 291 destroy_dev(sc->sc_nod); 292 free(sc->sc_region, M_TEMP); 293 bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res); 294 return (0); 295 } 296 297 static int 298 cfi_wait_ready(struct cfi_softc *sc, u_int timeout) 299 { 300 int done, error; 301 uint32_t st0, st; 302 303 done = 0; 304 error = 0; 305 timeout *= 10; 306 while (!done && !error && timeout) { 307 DELAY(100); 308 timeout--; 309 310 switch (sc->sc_cmdset) { 311 case CFI_VEND_INTEL_ECS: 312 case CFI_VEND_INTEL_SCS: 313 st = cfi_read(sc, sc->sc_wrofs); 314 done = (st & 0x80); 315 if (done) { 316 if (st & 0x02) 317 error = EPERM; 318 else if (st & 0x10) 319 error = EIO; 320 else if (st & 0x20) 321 error = ENXIO; 322 } 323 break; 324 case CFI_VEND_AMD_SCS: 325 case CFI_VEND_AMD_ECS: 326 st0 = cfi_read(sc, sc->sc_wrofs); 327 st = cfi_read(sc, sc->sc_wrofs); 328 done = ((st & 0x40) == (st0 & 0x40)) ? 1 : 0; 329 break; 330 } 331 } 332 if (!done && !error) 333 error = ETIMEDOUT; 334 if (error) 335 printf("\nerror=%d\n", error); 336 return (error); 337 } 338 339 int 340 cfi_write_block(struct cfi_softc *sc) 341 { 342 union { 343 uint8_t *x8; 344 uint16_t *x16; 345 uint32_t *x32; 346 } ptr; 347 register_t intr; 348 int error, i; 349 350 /* Erase the block. */ 351 switch (sc->sc_cmdset) { 352 case CFI_VEND_INTEL_ECS: 353 case CFI_VEND_INTEL_SCS: 354 cfi_write(sc, sc->sc_wrofs, CFI_BCS_BLOCK_ERASE); 355 cfi_write(sc, sc->sc_wrofs, CFI_BCS_CONFIRM); 356 break; 357 case CFI_VEND_AMD_SCS: 358 case CFI_VEND_AMD_ECS: 359 cfi_amd_write(sc, sc->sc_wrofs, AMD_ADDR_START, 360 CFI_AMD_ERASE_SECTOR); 361 cfi_amd_write(sc, sc->sc_wrofs, 0, CFI_AMD_BLOCK_ERASE); 362 break; 363 default: 364 /* Better safe than sorry... */ 365 return (ENODEV); 366 } 367 error = cfi_wait_ready(sc, sc->sc_erase_timeout); 368 if (error) 369 goto out; 370 371 /* Write the block. */ 372 ptr.x8 = sc->sc_wrbuf; 373 for (i = 0; i < sc->sc_wrbufsz; i += sc->sc_width) { 374 375 /* 376 * Make sure the command to start a write and the 377 * actual write happens back-to-back without any 378 * excessive delays. 379 */ 380 intr = intr_disable(); 381 382 switch (sc->sc_cmdset) { 383 case CFI_VEND_INTEL_ECS: 384 case CFI_VEND_INTEL_SCS: 385 cfi_write(sc, sc->sc_wrofs + i, CFI_BCS_PROGRAM); 386 break; 387 case CFI_VEND_AMD_SCS: 388 case CFI_VEND_AMD_ECS: 389 cfi_amd_write(sc, 0, AMD_ADDR_START, CFI_AMD_PROGRAM); 390 break; 391 } 392 switch (sc->sc_width) { 393 case 1: 394 bus_space_write_1(sc->sc_tag, sc->sc_handle, 395 sc->sc_wrofs + i, *(ptr.x8)++); 396 break; 397 case 2: 398 bus_space_write_2(sc->sc_tag, sc->sc_handle, 399 sc->sc_wrofs + i, *(ptr.x16)++); 400 break; 401 case 4: 402 bus_space_write_4(sc->sc_tag, sc->sc_handle, 403 sc->sc_wrofs + i, *(ptr.x32)++); 404 break; 405 } 406 407 intr_restore(intr); 408 409 error = cfi_wait_ready(sc, sc->sc_write_timeout); 410 if (error) 411 goto out; 412 } 413 414 /* error is 0. */ 415 416 out: 417 cfi_write(sc, 0, CFI_BCS_READ_ARRAY); 418 return (error); 419 } 420