cfi_core.c revision 250115
1189765Sgabor/*- 2189765Sgabor * Copyright (c) 2007, Juniper Networks, Inc. 3189765Sgabor * All rights reserved. 4189765Sgabor * 5189765Sgabor * Redistribution and use in source and binary forms, with or without 6189765Sgabor * modification, are permitted provided that the following conditions 7189765Sgabor * are met: 8189765Sgabor * 1. Redistributions of source code must retain the above copyright 9189765Sgabor * notice, this list of conditions and the following disclaimer. 10189765Sgabor * 2. Redistributions in binary form must reproduce the above copyright 11189765Sgabor * notice, this list of conditions and the following disclaimer in the 12189765Sgabor * documentation and/or other materials provided with the distribution. 13189765Sgabor * 3. Neither the name of the author nor the names of any co-contributors 14189765Sgabor * may be used to endorse or promote products derived from this software 15189765Sgabor * without specific prior written permission. 16189765Sgabor * 17189765Sgabor * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18189765Sgabor * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19189765Sgabor * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20189765Sgabor * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21189765Sgabor * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22189765Sgabor * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23189765Sgabor * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 24189765Sgabor * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25189765Sgabor * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26189765Sgabor * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27189765Sgabor * SUCH DAMAGE. 28189765Sgabor */ 29189765Sgabor 30189765Sgabor#include <sys/cdefs.h> 31189765Sgabor__FBSDID("$FreeBSD: head/sys/dev/cfi/cfi_core.c 250115 2013-04-30 18:48:11Z brooks $"); 32189765Sgabor 33189765Sgabor#include "opt_cfi.h" 34189765Sgabor 35189765Sgabor#include <sys/param.h> 36189765Sgabor#include <sys/systm.h> 37189765Sgabor#include <sys/bus.h> 38189765Sgabor#include <sys/conf.h> 39189765Sgabor#include <sys/endian.h> 40189765Sgabor#include <sys/kenv.h> 41189765Sgabor#include <sys/kernel.h> 42189765Sgabor#include <sys/malloc.h> 43189765Sgabor#include <sys/module.h> 44189765Sgabor#include <sys/rman.h> 45189765Sgabor#include <sys/sysctl.h> 46189765Sgabor 47189765Sgabor#include <machine/bus.h> 48189765Sgabor 49189765Sgabor#include <dev/cfi/cfi_reg.h> 50189765Sgabor#include <dev/cfi/cfi_var.h> 51189765Sgabor 52189765Sgaborextern struct cdevsw cfi_cdevsw; 53189765Sgabor 54189765Sgaborchar cfi_driver_name[] = "cfi"; 55189765Sgabordevclass_t cfi_devclass; 56189765Sgabordevclass_t cfi_diskclass; 57189765Sgabor 58189765Sgaboruint32_t 59189765Sgaborcfi_read_raw(struct cfi_softc *sc, u_int ofs) 60189765Sgabor{ 61189765Sgabor uint32_t val; 62189765Sgabor 63189765Sgabor ofs &= ~(sc->sc_width - 1); 64189765Sgabor switch (sc->sc_width) { 65189765Sgabor case 1: 66189765Sgabor val = bus_space_read_1(sc->sc_tag, sc->sc_handle, ofs); 67189765Sgabor break; 68189765Sgabor case 2: 69189765Sgabor val = bus_space_read_2(sc->sc_tag, sc->sc_handle, ofs); 70189765Sgabor break; 71189765Sgabor case 4: 72189765Sgabor val = bus_space_read_4(sc->sc_tag, sc->sc_handle, ofs); 73189765Sgabor break; 74189765Sgabor default: 75189765Sgabor val = ~0; 76189765Sgabor break; 77189765Sgabor } 78189765Sgabor return (val); 79189765Sgabor} 80189765Sgabor 81189765Sgaboruint32_t 82189765Sgaborcfi_read(struct cfi_softc *sc, u_int ofs) 83189765Sgabor{ 84189765Sgabor uint32_t val; 85189765Sgabor uint16_t sval; 86189765Sgabor 87189765Sgabor ofs &= ~(sc->sc_width - 1); 88189765Sgabor switch (sc->sc_width) { 89189765Sgabor case 1: 90189765Sgabor val = bus_space_read_1(sc->sc_tag, sc->sc_handle, ofs); 91189765Sgabor break; 92189765Sgabor case 2: 93189765Sgabor sval = bus_space_read_2(sc->sc_tag, sc->sc_handle, ofs); 94189765Sgabor val = le16toh(sval); 95189765Sgabor break; 96189765Sgabor case 4: 97189765Sgabor val = bus_space_read_4(sc->sc_tag, sc->sc_handle, ofs); 98189765Sgabor val = le32toh(val); 99189765Sgabor break; 100189765Sgabor default: 101189765Sgabor val = ~0; 102189765Sgabor break; 103189765Sgabor } 104189765Sgabor return (val); 105189765Sgabor} 106189765Sgabor 107189765Sgaborstatic void 108189765Sgaborcfi_write(struct cfi_softc *sc, u_int ofs, u_int val) 109189765Sgabor{ 110189765Sgabor 111189765Sgabor ofs &= ~(sc->sc_width - 1); 112189765Sgabor switch (sc->sc_width) { 113189765Sgabor case 1: 114189765Sgabor bus_space_write_1(sc->sc_tag, sc->sc_handle, ofs, val); 115189765Sgabor break; 116189765Sgabor case 2: 117189765Sgabor bus_space_write_2(sc->sc_tag, sc->sc_handle, ofs, htole16(val)); 118189765Sgabor break; 119189765Sgabor case 4: 120189765Sgabor bus_space_write_4(sc->sc_tag, sc->sc_handle, ofs, htole32(val)); 121189765Sgabor break; 122189765Sgabor } 123189765Sgabor} 124189765Sgabor 125189765Sgaboruint8_t 126189765Sgaborcfi_read_qry(struct cfi_softc *sc, u_int ofs) 127189765Sgabor{ 128189765Sgabor uint8_t val; 129189765Sgabor 130189765Sgabor cfi_write(sc, CFI_QRY_CMD_ADDR * sc->sc_width, CFI_QRY_CMD_DATA); 131189765Sgabor val = cfi_read(sc, ofs * sc->sc_width); 132189765Sgabor cfi_write(sc, 0, CFI_BCS_READ_ARRAY); 133189765Sgabor return (val); 134189765Sgabor} 135189765Sgabor 136189765Sgaborstatic void 137189765Sgaborcfi_amd_write(struct cfi_softc *sc, u_int ofs, u_int addr, u_int data) 138189765Sgabor{ 139189765Sgabor 140189765Sgabor cfi_write(sc, ofs + AMD_ADDR_START, CFI_AMD_UNLOCK); 141189765Sgabor cfi_write(sc, ofs + AMD_ADDR_ACK, CFI_AMD_UNLOCK_ACK); 142189765Sgabor cfi_write(sc, ofs + addr, data); 143189765Sgabor} 144189765Sgabor 145189765Sgaborstatic char * 146189765Sgaborcfi_fmtsize(uint32_t sz) 147189765Sgabor{ 148189765Sgabor static char buf[8]; 149189765Sgabor static const char *sfx[] = { "", "K", "M", "G" }; 150189765Sgabor int sfxidx; 151189765Sgabor 152189765Sgabor sfxidx = 0; 153189765Sgabor while (sfxidx < 3 && sz > 1023) { 154189765Sgabor sz /= 1024; 155189765Sgabor sfxidx++; 156189765Sgabor } 157189765Sgabor 158189765Sgabor sprintf(buf, "%u%sB", sz, sfx[sfxidx]); 159189765Sgabor return (buf); 160189765Sgabor} 161189765Sgabor 162189765Sgaborint 163189765Sgaborcfi_probe(device_t dev) 164189765Sgabor{ 165189765Sgabor char desc[80]; 166189765Sgabor struct cfi_softc *sc; 167189765Sgabor char *vend_str; 168189765Sgabor int error; 169189765Sgabor uint16_t iface, vend; 170189765Sgabor 171189765Sgabor sc = device_get_softc(dev); 172189765Sgabor sc->sc_dev = dev; 173189765Sgabor 174189765Sgabor sc->sc_rid = 0; 175189765Sgabor sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid, 176189765Sgabor RF_ACTIVE); 177189765Sgabor if (sc->sc_res == NULL) 178189765Sgabor return (ENXIO); 179189765Sgabor 180189765Sgabor sc->sc_tag = rman_get_bustag(sc->sc_res); 181189765Sgabor sc->sc_handle = rman_get_bushandle(sc->sc_res); 182189765Sgabor 183189765Sgabor if (sc->sc_width == 0) { 184189765Sgabor sc->sc_width = 1; 185189765Sgabor while (sc->sc_width <= 4) { 186189765Sgabor if (cfi_read_qry(sc, CFI_QRY_IDENT) == 'Q') 187189765Sgabor break; 188189765Sgabor sc->sc_width <<= 1; 189189765Sgabor } 190189765Sgabor } else if (cfi_read_qry(sc, CFI_QRY_IDENT) != 'Q') { 191189765Sgabor error = ENXIO; 192189765Sgabor goto out; 193189765Sgabor } 194189765Sgabor if (sc->sc_width > 4) { 195189765Sgabor error = ENXIO; 196189765Sgabor goto out; 197189765Sgabor } 198189765Sgabor 199189765Sgabor /* We got a Q. Check if we also have the R and the Y. */ 200189765Sgabor if (cfi_read_qry(sc, CFI_QRY_IDENT + 1) != 'R' || 201189765Sgabor cfi_read_qry(sc, CFI_QRY_IDENT + 2) != 'Y') { 202189765Sgabor error = ENXIO; 203189765Sgabor goto out; 204189765Sgabor } 205189765Sgabor 206189765Sgabor /* Get the vendor and command set. */ 207189765Sgabor vend = cfi_read_qry(sc, CFI_QRY_VEND) | 208189765Sgabor (cfi_read_qry(sc, CFI_QRY_VEND + 1) << 8); 209189765Sgabor 210189765Sgabor sc->sc_cmdset = vend; 211189765Sgabor 212189765Sgabor switch (vend) { 213189765Sgabor case CFI_VEND_AMD_ECS: 214189765Sgabor case CFI_VEND_AMD_SCS: 215189765Sgabor vend_str = "AMD/Fujitsu"; 216189765Sgabor break; 217189765Sgabor case CFI_VEND_INTEL_ECS: 218189765Sgabor vend_str = "Intel/Sharp"; 219189765Sgabor break; 220189765Sgabor case CFI_VEND_INTEL_SCS: 221189765Sgabor vend_str = "Intel"; 222189765Sgabor break; 223189765Sgabor case CFI_VEND_MITSUBISHI_ECS: 224189765Sgabor case CFI_VEND_MITSUBISHI_SCS: 225189765Sgabor vend_str = "Mitsubishi"; 226189765Sgabor break; 227189765Sgabor default: 228189765Sgabor vend_str = "Unknown vendor"; 229189765Sgabor break; 230189765Sgabor } 231189765Sgabor 232189765Sgabor /* Get the device size. */ 233189765Sgabor sc->sc_size = 1U << cfi_read_qry(sc, CFI_QRY_SIZE); 234189765Sgabor 235189765Sgabor /* Sanity-check the I/F */ 236189765Sgabor iface = cfi_read_qry(sc, CFI_QRY_IFACE) | 237189765Sgabor (cfi_read_qry(sc, CFI_QRY_IFACE + 1) << 8); 238189765Sgabor 239189765Sgabor /* 240189765Sgabor * Adding 1 to iface will give us a bit-wise "switch" 241189765Sgabor * that allows us to test for the interface width by 242189765Sgabor * testing a single bit. 243189765Sgabor */ 244189765Sgabor iface++; 245189765Sgabor 246189765Sgabor error = (iface & sc->sc_width) ? 0 : EINVAL; 247189765Sgabor if (error) 248189765Sgabor goto out; 249189765Sgabor 250 snprintf(desc, sizeof(desc), "%s - %s", vend_str, 251 cfi_fmtsize(sc->sc_size)); 252 device_set_desc_copy(dev, desc); 253 254 out: 255 bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res); 256 return (error); 257} 258 259int 260cfi_attach(device_t dev) 261{ 262 struct cfi_softc *sc; 263 u_int blksz, blocks; 264 u_int r, u; 265#ifdef CFI_SUPPORT_STRATAFLASH 266 uint64_t ppr; 267 char name[KENV_MNAMELEN], value[32]; 268#endif 269 270 sc = device_get_softc(dev); 271 sc->sc_dev = dev; 272 273 sc->sc_rid = 0; 274 sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid, 275 RF_ACTIVE); 276 if (sc->sc_res == NULL) 277 return (ENXIO); 278 279 sc->sc_tag = rman_get_bustag(sc->sc_res); 280 sc->sc_handle = rman_get_bushandle(sc->sc_res); 281 282 /* Get time-out values for erase and write. */ 283 sc->sc_write_timeout = 1 << cfi_read_qry(sc, CFI_QRY_TTO_WRITE); 284 sc->sc_erase_timeout = 1 << cfi_read_qry(sc, CFI_QRY_TTO_ERASE); 285 sc->sc_write_timeout *= 1 << cfi_read_qry(sc, CFI_QRY_MTO_WRITE); 286 sc->sc_erase_timeout *= 1 << cfi_read_qry(sc, CFI_QRY_MTO_ERASE); 287 288 /* Get erase regions. */ 289 sc->sc_regions = cfi_read_qry(sc, CFI_QRY_NREGIONS); 290 sc->sc_region = malloc(sc->sc_regions * sizeof(struct cfi_region), 291 M_TEMP, M_WAITOK | M_ZERO); 292 for (r = 0; r < sc->sc_regions; r++) { 293 blocks = cfi_read_qry(sc, CFI_QRY_REGION(r)) | 294 (cfi_read_qry(sc, CFI_QRY_REGION(r) + 1) << 8); 295 sc->sc_region[r].r_blocks = blocks + 1; 296 297 blksz = cfi_read_qry(sc, CFI_QRY_REGION(r) + 2) | 298 (cfi_read_qry(sc, CFI_QRY_REGION(r) + 3) << 8); 299 sc->sc_region[r].r_blksz = (blksz == 0) ? 128 : 300 blksz * 256; 301 } 302 303 /* Reset the device to a default state. */ 304 cfi_write(sc, 0, CFI_BCS_CLEAR_STATUS); 305 306 if (bootverbose) { 307 device_printf(dev, "["); 308 for (r = 0; r < sc->sc_regions; r++) { 309 printf("%ux%s%s", sc->sc_region[r].r_blocks, 310 cfi_fmtsize(sc->sc_region[r].r_blksz), 311 (r == sc->sc_regions - 1) ? "]\n" : ","); 312 } 313 } 314 315 u = device_get_unit(dev); 316 sc->sc_nod = make_dev(&cfi_cdevsw, u, UID_ROOT, GID_WHEEL, 0600, 317 "%s%u", cfi_driver_name, u); 318 sc->sc_nod->si_drv1 = sc; 319 320#ifdef CFI_SUPPORT_STRATAFLASH 321 /* 322 * Store the Intel factory PPR in the environment. In some 323 * cases it is the most unique ID on a board. 324 */ 325 if (cfi_intel_get_factory_pr(sc, &ppr) == 0) { 326 if (snprintf(name, sizeof(name), "%s.factory_ppr", 327 device_get_nameunit(dev)) < (sizeof(name) - 1) && 328 snprintf(value, sizeof(value), "0x%016jx", ppr) < 329 (sizeof(value) - 1)) 330 (void) setenv(name, value); 331 } 332#endif 333 334 device_add_child(dev, "cfid", -1); 335 bus_generic_attach(dev); 336 337 return (0); 338} 339 340int 341cfi_detach(device_t dev) 342{ 343 struct cfi_softc *sc; 344 345 sc = device_get_softc(dev); 346 347 destroy_dev(sc->sc_nod); 348 free(sc->sc_region, M_TEMP); 349 bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res); 350 return (0); 351} 352 353static int 354cfi_wait_ready(struct cfi_softc *sc, u_int ofs, u_int timeout) 355{ 356 int done, error; 357 uint32_t st0 = 0, st = 0; 358 359 done = 0; 360 error = 0; 361 timeout *= 10; 362 while (!done && !error && timeout) { 363 DELAY(100); 364 timeout--; 365 366 switch (sc->sc_cmdset) { 367 case CFI_VEND_INTEL_ECS: 368 case CFI_VEND_INTEL_SCS: 369 st = cfi_read(sc, ofs); 370 done = (st & CFI_INTEL_STATUS_WSMS); 371 if (done) { 372 /* NB: bit 0 is reserved */ 373 st &= ~(CFI_INTEL_XSTATUS_RSVD | 374 CFI_INTEL_STATUS_WSMS | 375 CFI_INTEL_STATUS_RSVD); 376 if (st & CFI_INTEL_STATUS_DPS) 377 error = EPERM; 378 else if (st & CFI_INTEL_STATUS_PSLBS) 379 error = EIO; 380 else if (st & CFI_INTEL_STATUS_ECLBS) 381 error = ENXIO; 382 else if (st) 383 error = EACCES; 384 } 385 break; 386 case CFI_VEND_AMD_SCS: 387 case CFI_VEND_AMD_ECS: 388 st0 = cfi_read(sc, ofs); 389 st = cfi_read(sc, ofs); 390 done = ((st & 0x40) == (st0 & 0x40)) ? 1 : 0; 391 break; 392 } 393 } 394 if (!done && !error) 395 error = ETIMEDOUT; 396 if (error) 397 printf("\nerror=%d (st 0x%x st0 0x%x)\n", error, st, st0); 398 return (error); 399} 400 401int 402cfi_write_block(struct cfi_softc *sc) 403{ 404 union { 405 uint8_t *x8; 406 uint16_t *x16; 407 uint32_t *x32; 408 } ptr; 409 register_t intr; 410 int error, i; 411 412 /* Erase the block. */ 413 switch (sc->sc_cmdset) { 414 case CFI_VEND_INTEL_ECS: 415 case CFI_VEND_INTEL_SCS: 416 cfi_write(sc, sc->sc_wrofs, CFI_BCS_BLOCK_ERASE); 417 cfi_write(sc, sc->sc_wrofs, CFI_BCS_CONFIRM); 418 break; 419 case CFI_VEND_AMD_SCS: 420 case CFI_VEND_AMD_ECS: 421 cfi_amd_write(sc, sc->sc_wrofs, AMD_ADDR_START, 422 CFI_AMD_ERASE_SECTOR); 423 cfi_amd_write(sc, sc->sc_wrofs, 0, CFI_AMD_BLOCK_ERASE); 424 break; 425 default: 426 /* Better safe than sorry... */ 427 return (ENODEV); 428 } 429 error = cfi_wait_ready(sc, sc->sc_wrofs, sc->sc_erase_timeout); 430 if (error) 431 goto out; 432 433 /* Write the block. */ 434 ptr.x8 = sc->sc_wrbuf; 435 for (i = 0; i < sc->sc_wrbufsz; i += sc->sc_width) { 436 437 /* 438 * Make sure the command to start a write and the 439 * actual write happens back-to-back without any 440 * excessive delays. 441 */ 442 intr = intr_disable(); 443 444 switch (sc->sc_cmdset) { 445 case CFI_VEND_INTEL_ECS: 446 case CFI_VEND_INTEL_SCS: 447 cfi_write(sc, sc->sc_wrofs + i, CFI_BCS_PROGRAM); 448 break; 449 case CFI_VEND_AMD_SCS: 450 case CFI_VEND_AMD_ECS: 451 cfi_amd_write(sc, 0, AMD_ADDR_START, CFI_AMD_PROGRAM); 452 break; 453 } 454 switch (sc->sc_width) { 455 case 1: 456 bus_space_write_1(sc->sc_tag, sc->sc_handle, 457 sc->sc_wrofs + i, *(ptr.x8)++); 458 break; 459 case 2: 460 bus_space_write_2(sc->sc_tag, sc->sc_handle, 461 sc->sc_wrofs + i, *(ptr.x16)++); 462 break; 463 case 4: 464 bus_space_write_4(sc->sc_tag, sc->sc_handle, 465 sc->sc_wrofs + i, *(ptr.x32)++); 466 break; 467 } 468 469 intr_restore(intr); 470 471 error = cfi_wait_ready(sc, sc->sc_wrofs, sc->sc_write_timeout); 472 if (error) 473 goto out; 474 } 475 476 /* error is 0. */ 477 478 out: 479 cfi_write(sc, 0, CFI_BCS_READ_ARRAY); 480 return (error); 481} 482 483#ifdef CFI_SUPPORT_STRATAFLASH 484/* 485 * Intel StrataFlash Protection Register Support. 486 * 487 * The memory includes a 128-bit Protection Register that can be 488 * used for security. There are two 64-bit segments; one is programmed 489 * at the factory with a unique 64-bit number which is immutable. 490 * The other segment is left blank for User (OEM) programming. 491 * The User/OEM segment is One Time Programmable (OTP). It can also 492 * be locked to prevent any further writes by setting bit 0 of the 493 * Protection Lock Register (PLR). The PLR can written only once. 494 */ 495 496static uint16_t 497cfi_get16(struct cfi_softc *sc, int off) 498{ 499 uint16_t v = bus_space_read_2(sc->sc_tag, sc->sc_handle, off<<1); 500 return v; 501} 502 503#ifdef CFI_ARMEDANDDANGEROUS 504static void 505cfi_put16(struct cfi_softc *sc, int off, uint16_t v) 506{ 507 bus_space_write_2(sc->sc_tag, sc->sc_handle, off<<1, v); 508} 509#endif 510 511/* 512 * Read the factory-defined 64-bit segment of the PR. 513 */ 514int 515cfi_intel_get_factory_pr(struct cfi_softc *sc, uint64_t *id) 516{ 517 if (sc->sc_cmdset != CFI_VEND_INTEL_ECS) 518 return EOPNOTSUPP; 519 KASSERT(sc->sc_width == 2, ("sc_width %d", sc->sc_width)); 520 521 cfi_write(sc, 0, CFI_INTEL_READ_ID); 522 *id = ((uint64_t)cfi_get16(sc, CFI_INTEL_PR(0)))<<48 | 523 ((uint64_t)cfi_get16(sc, CFI_INTEL_PR(1)))<<32 | 524 ((uint64_t)cfi_get16(sc, CFI_INTEL_PR(2)))<<16 | 525 ((uint64_t)cfi_get16(sc, CFI_INTEL_PR(3))); 526 cfi_write(sc, 0, CFI_BCS_READ_ARRAY); 527 return 0; 528} 529 530/* 531 * Read the User/OEM 64-bit segment of the PR. 532 */ 533int 534cfi_intel_get_oem_pr(struct cfi_softc *sc, uint64_t *id) 535{ 536 if (sc->sc_cmdset != CFI_VEND_INTEL_ECS) 537 return EOPNOTSUPP; 538 KASSERT(sc->sc_width == 2, ("sc_width %d", sc->sc_width)); 539 540 cfi_write(sc, 0, CFI_INTEL_READ_ID); 541 *id = ((uint64_t)cfi_get16(sc, CFI_INTEL_PR(4)))<<48 | 542 ((uint64_t)cfi_get16(sc, CFI_INTEL_PR(5)))<<32 | 543 ((uint64_t)cfi_get16(sc, CFI_INTEL_PR(6)))<<16 | 544 ((uint64_t)cfi_get16(sc, CFI_INTEL_PR(7))); 545 cfi_write(sc, 0, CFI_BCS_READ_ARRAY); 546 return 0; 547} 548 549/* 550 * Write the User/OEM 64-bit segment of the PR. 551 * XXX should allow writing individual words/bytes 552 */ 553int 554cfi_intel_set_oem_pr(struct cfi_softc *sc, uint64_t id) 555{ 556#ifdef CFI_ARMEDANDDANGEROUS 557 register_t intr; 558 int i, error; 559#endif 560 561 if (sc->sc_cmdset != CFI_VEND_INTEL_ECS) 562 return EOPNOTSUPP; 563 KASSERT(sc->sc_width == 2, ("sc_width %d", sc->sc_width)); 564 565#ifdef CFI_ARMEDANDDANGEROUS 566 for (i = 7; i >= 4; i--, id >>= 16) { 567 intr = intr_disable(); 568 cfi_write(sc, 0, CFI_INTEL_PP_SETUP); 569 cfi_put16(sc, CFI_INTEL_PR(i), id&0xffff); 570 intr_restore(intr); 571 error = cfi_wait_ready(sc, CFI_BCS_READ_STATUS, 572 sc->sc_write_timeout); 573 if (error) 574 break; 575 } 576 cfi_write(sc, 0, CFI_BCS_READ_ARRAY); 577 return error; 578#else 579 device_printf(sc->sc_dev, "%s: OEM PR not set, " 580 "CFI_ARMEDANDDANGEROUS not configured\n", __func__); 581 return ENXIO; 582#endif 583} 584 585/* 586 * Read the contents of the Protection Lock Register. 587 */ 588int 589cfi_intel_get_plr(struct cfi_softc *sc, uint32_t *plr) 590{ 591 if (sc->sc_cmdset != CFI_VEND_INTEL_ECS) 592 return EOPNOTSUPP; 593 KASSERT(sc->sc_width == 2, ("sc_width %d", sc->sc_width)); 594 595 cfi_write(sc, 0, CFI_INTEL_READ_ID); 596 *plr = cfi_get16(sc, CFI_INTEL_PLR); 597 cfi_write(sc, 0, CFI_BCS_READ_ARRAY); 598 return 0; 599} 600 601/* 602 * Write the Protection Lock Register to lock down the 603 * user-settable segment of the Protection Register. 604 * NOTE: this operation is not reversible. 605 */ 606int 607cfi_intel_set_plr(struct cfi_softc *sc) 608{ 609#ifdef CFI_ARMEDANDDANGEROUS 610 register_t intr; 611 int error; 612#endif 613 if (sc->sc_cmdset != CFI_VEND_INTEL_ECS) 614 return EOPNOTSUPP; 615 KASSERT(sc->sc_width == 2, ("sc_width %d", sc->sc_width)); 616 617#ifdef CFI_ARMEDANDDANGEROUS 618 /* worthy of console msg */ 619 device_printf(sc->sc_dev, "set PLR\n"); 620 intr = intr_disable(); 621 cfi_write(sc, 0, CFI_INTEL_PP_SETUP); 622 cfi_put16(sc, CFI_INTEL_PLR, 0xFFFD); 623 intr_restore(intr); 624 error = cfi_wait_ready(sc, CFI_BCS_READ_STATUS, sc->sc_write_timeout); 625 cfi_write(sc, 0, CFI_BCS_READ_ARRAY); 626 return error; 627#else 628 device_printf(sc->sc_dev, "%s: PLR not set, " 629 "CFI_ARMEDANDDANGEROUS not configured\n", __func__); 630 return ENXIO; 631#endif 632} 633#endif /* CFI_SUPPORT_STRATAFLASH */ 634