// SPDX-License-Identifier: GPL-2.0 /* * Common Flash Interface support: * Intel Extended Vendor Command Set (ID 0x0001) * * (C) 2000 Red Hat. * * * 10/10/2000 Nicolas Pitre <nico@fluxnic.net> * - completely revamped method functions so they are aware and * independent of the flash geometry (buswidth, interleave, etc.) * - scalability vs code size is completely set at compile-time * (see include/linux/mtd/cfi.h for selection) * - optimized write buffer method * 02/05/2002 Christopher Hoover <ch@hpl.hp.com>/<ch@murgatroid.com> * - reworked lock/unlock/erase support for var size flash * 21/03/2007 Rodolfo Giometti <giometti@linux.it> * - auto unlock sectors on resume for auto locking flash on power up
*/
/* Note this is done after the region info is endian swapped */
cfi->cfiq->EraseRegionInfo[1] =
(cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e;
};
/* Reset the Partition Configuration Register on LH28F640BF
* to a single partition (PCR = 0x000): PCR is embedded into A0-A15. */ if (is_LH28F640BF(cfi)) {
printk(KERN_INFO "Reset Partition Config. Register: 1 Partition of 4 planes\n");
map_write(map, CMD(0x60), 0);
map_write(map, CMD(0x04), 0);
/* We have set one single partition thus
* Simultaneous Operations are not allowed */
printk(KERN_INFO "cfi_cmdset_0001: Simultaneous Operations disabled\n");
extp->FeatureSupport &= ~512;
}
}
staticstruct cfi_fixup jedec_fixup_table[] = {
{ CFI_MFR_INTEL, I82802AB, fixup_use_fwh_lock },
{ CFI_MFR_INTEL, I82802AC, fixup_use_fwh_lock },
{ CFI_MFR_ST, M50LPW080, fixup_use_fwh_lock },
{ CFI_MFR_ST, M50FLW080A, fixup_use_fwh_lock },
{ CFI_MFR_ST, M50FLW080B, fixup_use_fwh_lock },
{ 0, 0, NULL }
}; staticstruct cfi_fixup fixup_table[] = { /* The CFI vendor ids and the JEDEC vendor IDs appear * to be common. It is like the devices id's are as * well. This table is to pick all cases where * we know that is the case.
*/
{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_point },
{ 0, 0, NULL }
};
if (cfi->cfi_mode == CFI_MODE_CFI) { /* * It's a real CFI chip, not one for which the probe * routine faked a CFI structure. So we read the feature * table from it.
*/
__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR; struct cfi_pri_intelext *extp;
for (i=0; i< cfi->numchips; i++) { if (cfi->cfiq->WordWriteTimeoutTyp)
cfi->chips[i].word_write_time =
1<<cfi->cfiq->WordWriteTimeoutTyp; else
cfi->chips[i].word_write_time = 50000;
if (cfi->cfiq->BufWriteTimeoutTyp)
cfi->chips[i].buffer_write_time =
1<<cfi->cfiq->BufWriteTimeoutTyp; /* No default; if it isn't specified, we won't use it */
if (cfi->cfiq->BlockEraseTimeoutTyp)
cfi->chips[i].erase_time =
1000<<cfi->cfiq->BlockEraseTimeoutTyp; else
cfi->chips[i].erase_time = 2000000;
if (offset != devsize) { /* Argh */
printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize); goto setup_err;
}
for (i=0; i<mtd->numeraseregions;i++){
printk(KERN_DEBUG "erase region %d: offset=0x%llx,size=0x%x,blocks=%d\n",
i,(unsignedlonglong)mtd->eraseregions[i].offset,
mtd->eraseregions[i].erasesize,
mtd->eraseregions[i].numblocks);
}
/* This function has the potential to distort the reality
a bit and therefore should be called last. */ if (cfi_intelext_partition_fixup(mtd, &cfi) != 0) goto setup_err;
/* * Probing of multi-partition flash chips. * * To support multiple partitions when available, we simply arrange * for each of them to have their own flchip structure even if they * are on the same physical chip. This means completely recreating * a new cfi_private structure right here which is a blatent code * layering violation, but this is still the least intrusive * arrangement at this point. This can be rearranged in the future * if someone feels motivated enough. --nico
*/ if (extp && extp->MajorVersion == '1' && extp->MinorVersion >= '3'
&& extp->FeatureSupport & (1 << 9)) { int offs = 0; struct cfi_private *newcfi; struct flchip *chip; struct flchip_shared *shared; int numregions, numparts, partshift, numvirtchips, i, j;
/* Protection Register info */ if (extp->NumProtectionFields)
offs = (extp->NumProtectionFields - 1) * sizeof(struct cfi_intelext_otpinfo);
/* Burst Read info */
offs += extp->extra[offs+1]+2;
/* Number of partition regions */
numregions = extp->extra[offs];
offs += 1;
/* skip the sizeof(partregion) field in CFI 1.4 */ if (extp->MinorVersion >= '4')
offs += 2;
/* Number of hardware partitions */
numparts = 0; for (i = 0; i < numregions; i++) { struct cfi_intelext_regioninfo *rinfo;
rinfo = (struct cfi_intelext_regioninfo *)&extp->extra[offs];
numparts += rinfo->NumIdentPartitions;
offs += sizeof(*rinfo)
+ (rinfo->NumBlockTypes - 1) * sizeof(struct cfi_intelext_blockinfo);
}
if (!numparts)
numparts = 1;
/* Programming Region info */ if (extp->MinorVersion >= '4') { struct cfi_intelext_programming_regioninfo *prinfo;
prinfo = (struct cfi_intelext_programming_regioninfo *)&extp->extra[offs];
mtd->writesize = cfi->interleave << prinfo->ProgRegShift;
mtd->flags &= ~MTD_BIT_WRITEABLE;
printk(KERN_DEBUG "%s: program region size/ctrl_valid/ctrl_inval = %d/%d/%d\n",
map->name, mtd->writesize,
cfi->interleave * prinfo->ControlValid,
cfi->interleave * prinfo->ControlInvalid);
}
/* * All functions below currently rely on all chips having * the same geometry so we'll just assume that all hardware * partitions are of the same size too.
*/
partshift = cfi->chipshift - __ffs(numparts);
if ((1 << partshift) < mtd->erasesize) {
printk( KERN_ERR "%s: bad number of hw partitions (%d)\n",
__func__, numparts); return -EINVAL;
}
/* Prevent setting state FL_SYNCING for chip in suspended state. */ if (mode == FL_SYNCING && chip->oldstate != FL_READY) goto sleep;
switch (chip->state) {
case FL_STATUS: for (;;) {
status = map_read(map, adr); if (map_word_andequal(map, status, status_OK, status_OK)) break;
/* At this point we're fine with write operations
in other partitions as they don't conflict. */ if (chip->priv && map_word_andequal(map, status, status_PWS, status_PWS)) break;
mutex_unlock(&chip->mutex);
cfi_udelay(1);
mutex_lock(&chip->mutex); /* Someone else might have been playing with it. */ return -EAGAIN;
}
fallthrough; case FL_READY: case FL_CFI_QUERY: case FL_JEDEC_QUERY: return 0;
/* Do not allow suspend iff read/write to EB address */ if ((adr & chip->in_progress_block_mask) ==
chip->in_progress_block_addr) goto sleep;
/* do not suspend small EBs, buggy Micron Chips */ if (cfi_is_micron_28F00AP30(cfi, chip) &&
(chip->in_progress_block_mask == ~(0x8000-1))) goto sleep;
/* If the flash has finished erasing, then 'erase suspend' * appears to make some (28F320) flash devices switch to * 'read' mode. Make sure that we switch to 'read status' * mode so we get the right data. --rmk
*/
map_write(map, CMD(0x70), chip->in_progress_block_addr);
chip->oldstate = FL_ERASING;
chip->state = FL_ERASE_SUSPENDING;
chip->erase_suspended = 1; for (;;) {
status = map_read(map, chip->in_progress_block_addr); if (map_word_andequal(map, status, status_OK, status_OK)) break;
if (time_after(jiffies, timeo)) { /* Urgh. Resume and pretend we weren't here.
* Make sure we're in 'read status' mode if it had finished */
put_chip(map, chip, adr);
printk(KERN_ERR "%s: Chip not ready after erase " "suspended: status = 0x%lx\n", map->name, status.x[0]); return -EIO;
}
mutex_unlock(&chip->mutex);
cfi_udelay(1);
mutex_lock(&chip->mutex); /* Nobody will touch it while it's in state FL_ERASE_SUSPENDING.
So we can just loop here. */
}
chip->state = FL_STATUS; return 0;
case FL_SHUTDOWN: /* The machine is rebooting now,so no one can get chip anymore */ return -EIO; case FL_POINT: /* Only if there's no operation suspended... */ if (mode == FL_READY && chip->oldstate == FL_READY) return 0;
fallthrough; default:
sleep:
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
mutex_unlock(&chip->mutex);
schedule();
remove_wait_queue(&chip->wq, &wait);
mutex_lock(&chip->mutex); return -EAGAIN;
}
}
staticint get_chip(struct map_info *map, struct flchip *chip, unsignedlong adr, int mode)
{ int ret;
DECLARE_WAITQUEUE(wait, current);
retry: if (chip->priv &&
(mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE
|| mode == FL_SHUTDOWN) && chip->state != FL_SYNCING) { /* * OK. We have possibility for contention on the write/erase * operations which are global to the real chip and not per * partition. So let's fight it over in the partition which * currently has authority on the operation. * * The rules are as follows: * * - any write operation must own shared->writing. * * - any erase operation must own _both_ shared->writing and * shared->erasing. * * - contention arbitration is handled in the owner's context. * * The 'shared' struct can be read and/or written only when * its lock is taken.
*/ struct flchip_shared *shared = chip->priv; struct flchip *contender;
mutex_lock(&shared->lock);
contender = shared->writing; if (contender && contender != chip) { /* * The engine to perform desired operation on this * partition is already in use by someone else. * Let's fight over it in the context of the chip * currently using it. If it is possible to suspend, * that other partition will do just that, otherwise * it'll happily send us to sleep. In any case, when * get_chip returns success we're clear to go ahead.
*/
ret = mutex_trylock(&contender->mutex);
mutex_unlock(&shared->lock); if (!ret) goto retry;
mutex_unlock(&chip->mutex);
ret = chip_ready(map, contender, contender->start, mode);
mutex_lock(&chip->mutex);
if (ret == -EAGAIN) {
mutex_unlock(&contender->mutex); goto retry;
} if (ret) {
mutex_unlock(&contender->mutex); return ret;
}
mutex_lock(&shared->lock);
/* We should not own chip if it is already
* in FL_SYNCING state. Put contender and retry. */ if (chip->state == FL_SYNCING) {
put_chip(map, contender, contender->start);
mutex_unlock(&contender->mutex); goto retry;
}
mutex_unlock(&contender->mutex);
}
/* Check if we already have suspended erase
* on this chip. Sleep. */ if (mode == FL_ERASING && shared->erasing
&& shared->erasing->oldstate == FL_ERASING) {
mutex_unlock(&shared->lock);
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
mutex_unlock(&chip->mutex);
schedule();
remove_wait_queue(&chip->wq, &wait);
mutex_lock(&chip->mutex); goto retry;
}
/* We now own it */
shared->writing = chip; if (mode == FL_ERASING)
shared->erasing = chip;
mutex_unlock(&shared->lock);
}
ret = chip_ready(map, chip, adr, mode); if (ret == -EAGAIN) goto retry;
if (chip->priv) { struct flchip_shared *shared = chip->priv;
mutex_lock(&shared->lock); if (shared->writing == chip && chip->oldstate == FL_READY) { /* We own the ability to write, but we're done */
shared->writing = shared->erasing; if (shared->writing && shared->writing != chip) { /* give back ownership to who we loaned it from */ struct flchip *loaner = shared->writing;
mutex_lock(&loaner->mutex);
mutex_unlock(&shared->lock);
mutex_unlock(&chip->mutex);
put_chip(map, loaner, loaner->start);
mutex_lock(&chip->mutex);
mutex_unlock(&loaner->mutex);
wake_up(&chip->wq); return;
}
shared->erasing = NULL;
shared->writing = NULL;
} elseif (shared->erasing == chip && shared->writing != chip) { /* * We own the ability to erase without the ability * to write, which means the erase was suspended * and some other partition is currently writing. * Don't let the switch below mess things up since * we don't have ownership to resume anything.
*/
mutex_unlock(&shared->lock);
wake_up(&chip->wq); return;
}
mutex_unlock(&shared->lock);
}
switch(chip->oldstate) { case FL_ERASING: /* What if one interleaved chip has finished and the other hasn't? The old code would leave the finished one in READY mode. That's bad, and caused -EROFS errors to be returned from do_erase_oneblock because that's the only bit it checked for at the time. As the state machine appears to explicitly allow sending the 0x70 (Read Status) command to an erasing chip and expecting it to be ignored, that's what we
do. */
map_write(map, CMD(0xd0), chip->in_progress_block_addr);
map_write(map, CMD(0x70), chip->in_progress_block_addr);
chip->oldstate = FL_READY;
chip->state = FL_ERASING; break;
case FL_XIP_WHILE_ERASING:
chip->state = chip->oldstate;
chip->oldstate = FL_READY; break;
case FL_READY: case FL_STATUS: case FL_JEDEC_QUERY: break; default:
printk(KERN_ERR "%s: put_chip() called with oldstate %d!!\n", map->name, chip->oldstate);
}
wake_up(&chip->wq);
}
#ifdef CONFIG_MTD_XIP
/* * No interrupt what so ever can be serviced while the flash isn't in array * mode. This is ensured by the xip_disable() and xip_enable() functions * enclosing any code path where the flash is known not to be in array mode. * And within a XIP disabled code path, only functions marked with __xipram * may be called and nothing else (it's a good thing to inspect generated * assembly to make sure inline functions were actually inlined and that gcc * didn't emit calls to its own support functions). Also configuring MTD CFI * support to a single buswidth and a single interleave is also recommended.
*/
staticvoid xip_disable(struct map_info *map, struct flchip *chip, unsignedlong adr)
{ /* TODO: chips with no XIP use should ignore and return */
(void) map_read(map, adr); /* ensure mmu mapping is up to date */
local_irq_disable();
}
/* * When a delay is required for the flash operation to complete, the * xip_wait_for_operation() function is polling for both the given timeout * and pending (but still masked) hardware interrupts. Whenever there is an * interrupt pending then the flash erase or write operation is suspended, * array mode restored and interrupts unmasked. Task scheduling might also * happen at that point. The CPU eventually returns from the interrupt or * the call to schedule() and the suspended flash operation is resumed for * the remaining of the delay period. * * Warning: this function _will_ fool interrupt latency tracing tools.
*/
do {
cpu_relax(); if (xip_irqpending() && cfip &&
((chip->state == FL_ERASING && (cfip->FeatureSupport&2)) ||
(chip->state == FL_WRITING && (cfip->FeatureSupport&4))) &&
(cfi_interleave_is_1(cfi) || chip->oldstate == FL_READY)) { /* * Let's suspend the erase or write operation when * supported. Note that we currently don't try to * suspend interleaved chips if there is already * another operation suspended (imagine what happens * when one chip was already done with the current * operation while another chip suspended it, then * we resume the whole thing at once). Yes, it * can happen!
*/
usec -= done;
map_write(map, CMD(0xb0), adr);
map_write(map, CMD(0x70), adr);
suspended = xip_currtime(); do { if (xip_elapsed_since(suspended) > 100000) { /* * The chip doesn't want to suspend * after waiting for 100 msecs. * This is a critical error but there * is not much we can do here.
*/ return -EIO;
}
status = map_read(map, adr);
} while (!map_word_andequal(map, status, OK, OK));
/* * We're back. However someone else might have * decided to go write to the chip if we are in * a suspended erase state. If so let's wait * until it's done.
*/
mutex_lock(&chip->mutex); while (chip->state != newstate) {
DECLARE_WAITQUEUE(wait, current);
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
mutex_unlock(&chip->mutex);
schedule();
remove_wait_queue(&chip->wq, &wait);
mutex_lock(&chip->mutex);
} /* Disallow XIP again */
local_irq_disable();
/* Resume the write or erase operation */
map_write(map, CMD(0xd0), adr);
map_write(map, CMD(0x70), adr);
chip->state = oldstate;
start = xip_currtime();
} elseif (usec >= 1000000/HZ) { /* * Try to save on CPU power when waiting delay * is at least a system timer tick period. * No need to be extremely accurate here.
*/
xip_cpu_idle();
}
status = map_read(map, adr);
done = xip_elapsed_since(start);
} while (!map_word_andequal(map, status, OK, OK)
&& done < usec);
return (done >= usec) ? -ETIME : 0;
}
/* * The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while * the flash is actively programming or erasing since we have to poll for * the operation to complete anyway. We can't do that in a generic way with * a XIP setup so do it before the actual flash operation in this case * and stub it out from INVAL_CACHE_AND_WAIT.
*/ #define XIP_INVAL_CACHED_RANGE(map, from, size) \
INVALIDATE_CACHED_RANGE(map, from, size)
/* OK Still waiting. Drop the lock, wait a while and retry. */
mutex_unlock(&chip->mutex); if (sleep_time >= 1000000/HZ) { /* * Half of the normal delay still remaining * can be performed with a sleeping delay instead * of busy waiting.
*/
msleep(sleep_time/1000);
timeo -= sleep_time;
sleep_time = 1000000/HZ;
} else {
udelay(1);
cond_resched();
timeo--;
}
mutex_lock(&chip->mutex);
}
/* We cannot point across chips that are virtually disjoint */ if (!last_end)
last_end = cfi->chips[chipnum].start; elseif (cfi->chips[chipnum].start != last_end) break;
chipnum = to >> cfi->chipshift;
ofs = to - (chipnum << cfi->chipshift);
/* If it's not bus-aligned, do the first byte write */ if (ofs & (map_bankwidth(map)-1)) { unsignedlong bus_ofs = ofs & ~(map_bankwidth(map)-1); int gap = ofs - bus_ofs; int n;
map_word datum;
n = min_t(int, len, map_bankwidth(map)-gap);
datum = map_word_ff(map);
datum = map_word_load_partial(map, datum, buf, gap, n);
ret = do_write_oneword(map, &cfi->chips[chipnum],
bus_ofs, datum, FL_WRITING); if (ret) return ret;
len -= n;
ofs += n;
buf += n;
(*retlen) += n;
if (ofs >> cfi->chipshift) {
chipnum ++;
ofs = 0; if (chipnum == cfi->numchips) return 0;
}
}
while(len >= map_bankwidth(map)) {
map_word datum = map_word_load(map, buf);
ret = do_write_oneword(map, &cfi->chips[chipnum],
ofs, datum, FL_WRITING); if (ret) return ret;
/* Sharp LH28F640BF chips need the first address for the * Page Buffer Program command. See Table 5 of
* LH28F320BF, LH28F640BF, LH28F128BF Series (Appendix FUM00701) */ if (is_LH28F640BF(cfi))
cmd_adr = adr;
/* Let's determine this according to the interleave only once */
write_cmd = (cfi->cfiq->P_ID != P_ID_INTEL_PERFORMANCE) ? CMD(0xe8) : CMD(0xe9);
mutex_lock(&chip->mutex);
ret = get_chip(map, chip, cmd_adr, FL_WRITING); if (ret) {
mutex_unlock(&chip->mutex); return ret;
}
/* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set [...], the device will not accept any more Write to Buffer commands". So we must check here and reset those bits if they're set. Otherwise
we're just pissing in the wind */ if (chip->state != FL_STATUS) {
map_write(map, CMD(0x70), cmd_adr);
chip->state = FL_STATUS;
}
status = map_read(map, cmd_adr); if (map_word_bitsset(map, status, CMD(0x30))) {
xip_enable(map, chip, cmd_adr);
printk(KERN_WARNING "SR.4 or SR.5 bits set in buffer write (status %lx). Clearing.\n", status.x[0]);
xip_disable(map, chip, cmd_adr);
map_write(map, CMD(0x50), cmd_adr);
map_write(map, CMD(0x70), cmd_adr);
}
chip->state = FL_WRITING_TO_BUFFER;
map_write(map, write_cmd, cmd_adr);
ret = WAIT_TIMEOUT(map, chip, cmd_adr, 0, 0); if (ret) { /* Argh. Not ready for write to buffer */
map_word Xstatus = map_read(map, cmd_adr);
map_write(map, CMD(0x70), cmd_adr);
chip->state = FL_STATUS;
status = map_read(map, cmd_adr);
map_write(map, CMD(0x50), cmd_adr);
map_write(map, CMD(0x70), cmd_adr);
xip_enable(map, chip, cmd_adr);
printk(KERN_ERR "%s: Chip not ready for buffer write. Xstatus = %lx, status = %lx\n",
map->name, Xstatus.x[0], status.x[0]); goto out;
}
/* Figure out the number of words to write */
word_gap = (-adr & (map_bankwidth(map)-1));
words = DIV_ROUND_UP(len - word_gap, map_bankwidth(map)); if (!word_gap) {
words--;
} else {
word_gap = map_bankwidth(map) - word_gap;
adr -= word_gap;
datum = map_word_ff(map);
}
/* Write length of data to come */
map_write(map, CMD(words), cmd_adr );
/* Write data */
vec = *pvec;
vec_seek = *pvec_seek; do { int n = map_bankwidth(map) - word_gap; if (n > vec->iov_len - vec_seek)
n = vec->iov_len - vec_seek; if (n > len)
n = len;
if (!word_gap && len < map_bankwidth(map))
datum = map_word_ff(map);
datum = map_word_load_partial(map, datum,
vec->iov_base + vec_seek,
word_gap, n);
staticvoid cfi_intelext_sync (struct mtd_info *mtd)
{ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; int i; struct flchip *chip; int ret = 0;
for (i=0; !ret && i<cfi->numchips; i++) {
chip = &cfi->chips[i];
mutex_lock(&chip->mutex);
ret = get_chip(map, chip, chip->start, FL_SYNCING);
if (!ret) {
chip->oldstate = chip->state;
chip->state = FL_SYNCING; /* No need to wake_up() on this state change - * as the whole point is that nobody can do anything * with the chip now anyway.
*/
}
mutex_unlock(&chip->mutex);
}
/* * If Instant Individual Block Locking supported then no need * to delay.
*/ /* * Unlocking may take up to 1.4 seconds on some Intel flashes. So * lets use a max of 1.5 seconds (1500ms) as timeout. * * See "Clear Block Lock-Bits Time" on page 40 in * "3 Volt Intel StrataFlash Memory" 28F128J3,28F640J3,28F320J3 manual * from February 2003
*/
mdelay = (!extp || !(extp->FeatureSupport & (1 << 5))) ? 1500 : 0;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.