void cfi_read(int unit, int addr, int size, char *buf) { struct cfi *cfi = &cfid[unit]; cfi_wait_ready(cfi); cfi_send_command(cfi, CMD_READ, &addr, buf, size, 0); cfi_wait_ready(cfi); }
/* * Write the Protection Lock Register to lock down the * user-settable segment of the Protection Register. * NOTE: this operation is not reversible. */ int cfi_intel_set_plr(struct cfi_softc *sc) { #ifdef CFI_ARMEDANDDANGEROUS register_t intr; int error; #endif if (sc->sc_cmdset != CFI_VEND_INTEL_ECS) return EOPNOTSUPP; KASSERT(sc->sc_width == 2, ("sc_width %d", sc->sc_width)); #ifdef CFI_ARMEDANDDANGEROUS /* worthy of console msg */ device_printf(sc->sc_dev, "set PLR\n"); intr = intr_disable(); cfi_write(sc, 0, CFI_INTEL_PP_SETUP); cfi_put16(sc, CFI_INTEL_PLR, 0xFFFD); intr_restore(intr); error = cfi_wait_ready(sc, CFI_BCS_READ_STATUS, sc->sc_write_timeout); cfi_write(sc, 0, CFI_BCS_READ_ARRAY); return error; #else device_printf(sc->sc_dev, "%s: PLR not set, " "CFI_ARMEDANDDANGEROUS not configured\n", __func__); return ENXIO; #endif }
/* * Write the User/OEM 64-bit segment of the PR. * XXX should allow writing individual words/bytes */ int cfi_intel_set_oem_pr(struct cfi_softc *sc, uint64_t id) { #ifdef CFI_ARMEDANDDANGEROUS register_t intr; int i, error; #endif if (sc->sc_cmdset != CFI_VEND_INTEL_ECS) return EOPNOTSUPP; KASSERT(sc->sc_width == 2, ("sc_width %d", sc->sc_width)); #ifdef CFI_ARMEDANDDANGEROUS for (i = 7; i >= 4; i--, id >>= 16) { intr = intr_disable(); cfi_write(sc, 0, CFI_INTEL_PP_SETUP); cfi_put16(sc, CFI_INTEL_PR(i), id&0xffff); intr_restore(intr); error = cfi_wait_ready(sc, CFI_BCS_READ_STATUS, sc->sc_write_timeout); if (error) break; } cfi_write(sc, 0, CFI_BCS_READ_ARRAY); return error; #else device_printf(sc->sc_dev, "%s: OEM PR not set, " "CFI_ARMEDANDDANGEROUS not configured\n", __func__); return ENXIO; #endif }
int cfi_write(int unit, int addr, int size, char *buf) { struct cfi *cfi = &cfid[unit]; enable_write(cfi); cfi_send_command(cfi, CMD_PP, &addr, buf, size, 1); cfi_wait_ready(cfi); return 0; }
static int enable_write(struct cfi *cfi) { cfi_wait_ready(cfi); cfi_send_command(cfi, CMD_WREN, NULL, NULL, 0, 0); // Wait for write enable latch while (!(cfi_read_reg(cfi, CMD_RDSR1) & SR1_WEL_MASK)); return 0; }
void cfi_erase(int unit, int addr, int size) { struct cfi *cfi = &cfid[unit]; int i, block; // Get the block number block = (addr - cfi->pagesiz) / cfi->sectsiz; if (block == 255) { for(i=0;i < 16;i++) { enable_write(cfi); cfi_send_command(cfi, CMD_P4E, &addr, NULL, 0, 1); addr += cfi->sectsiz / 16; } } else { enable_write(cfi); cfi_send_command(cfi, CMD_SE, &addr, NULL, 0, 1); } cfi_wait_ready(cfi); }
int cfi_write_block(struct cfi_softc *sc) { union { uint8_t *x8; uint16_t *x16; uint32_t *x32; } ptr; register_t intr; int error, i; /* Erase the block. */ switch (sc->sc_cmdset) { case CFI_VEND_INTEL_ECS: case CFI_VEND_INTEL_SCS: cfi_write(sc, sc->sc_wrofs, CFI_BCS_BLOCK_ERASE); cfi_write(sc, sc->sc_wrofs, CFI_BCS_CONFIRM); break; case CFI_VEND_AMD_SCS: case CFI_VEND_AMD_ECS: cfi_amd_write(sc, sc->sc_wrofs, AMD_ADDR_START, CFI_AMD_ERASE_SECTOR); cfi_amd_write(sc, sc->sc_wrofs, 0, CFI_AMD_BLOCK_ERASE); break; default: /* Better safe than sorry... */ return (ENODEV); } error = cfi_wait_ready(sc, sc->sc_wrofs, sc->sc_erase_timeout); if (error) goto out; /* Write the block. */ ptr.x8 = sc->sc_wrbuf; for (i = 0; i < sc->sc_wrbufsz; i += sc->sc_width) { /* * Make sure the command to start a write and the * actual write happens back-to-back without any * excessive delays. */ intr = intr_disable(); switch (sc->sc_cmdset) { case CFI_VEND_INTEL_ECS: case CFI_VEND_INTEL_SCS: cfi_write(sc, sc->sc_wrofs + i, CFI_BCS_PROGRAM); break; case CFI_VEND_AMD_SCS: case CFI_VEND_AMD_ECS: cfi_amd_write(sc, 0, AMD_ADDR_START, CFI_AMD_PROGRAM); break; } switch (sc->sc_width) { case 1: bus_space_write_1(sc->sc_tag, sc->sc_handle, sc->sc_wrofs + i, *(ptr.x8)++); break; case 2: bus_space_write_2(sc->sc_tag, sc->sc_handle, sc->sc_wrofs + i, *(ptr.x16)++); break; case 4: bus_space_write_4(sc->sc_tag, sc->sc_handle, sc->sc_wrofs + i, *(ptr.x32)++); break; } intr_restore(intr); error = cfi_wait_ready(sc, sc->sc_wrofs, sc->sc_write_timeout); if (error) goto out; } /* error is 0. */ out: cfi_write(sc, 0, CFI_BCS_READ_ARRAY); return (error); }