#define MAX_BANKS 8 #define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */ #define FCM_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait for FCM */
u8 __iomem *addr; /* Address of assigned FCM buffer */ unsignedint page; /* Last page written to / read from */ unsignedint read_bytes; /* Number of bytes read during command */ unsignedint column; /* Saved column from SEQIN */ unsignedint index; /* Pointer to next byte to 'read' */ unsignedint status; /* status read from LTESR after last op */ unsignedint mdr; /* UPM/FCM Data Register value */ unsignedint use_mdr; /* Non zero if the MDR is to be set */ unsignedint oob; /* Non zero if operating on OOB data */ unsignedint counter; /* counter for the initializations */ unsignedint max_bitflips; /* Saved during READ0 cmd */
};
/* These map to the positions used by the FCM hardware ECC generator */
/* * ELBC may use HW ECC, so that OOB offsets, that NAND core uses for bbt, * interfere with ECC positions, that's why we implement our own descriptors. * OOB {11, 5}, works for both SP and LP chips, with ECCM = 1 and ECCM = 0.
*/ static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
/* * Set up the FCM hardware block and page address fields, and the fcm * structure addr field to point to the correct FCM buffer in memory
*/ staticvoid set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
{ struct nand_chip *chip = mtd_to_nand(mtd); struct fsl_elbc_mtd *priv = nand_get_controller_data(chip); struct fsl_lbc_ctrl *ctrl = priv->ctrl; struct fsl_lbc_regs __iomem *lbc = ctrl->regs; struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand; int buf_num;
elbc_fcm_ctrl->page = page_addr;
if (priv->page_size) { /* * large page size chip : FPAR[PI] save the lowest 6 bits, * FBAR[BLK] save the other bits.
*/
out_be32(&lbc->fbar, page_addr >> 6);
out_be32(&lbc->fpar,
((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI) |
(oob ? FPAR_LP_MS : 0) | column);
buf_num = (page_addr & 1) << 2;
} else { /* * small page size chip : FPAR[PI] save the lowest 5 bits, * FBAR[BLK] save the other bits.
*/
out_be32(&lbc->fbar, page_addr >> 5);
out_be32(&lbc->fpar,
((page_addr << FPAR_SP_PI_SHIFT) & FPAR_SP_PI) |
(oob ? FPAR_SP_MS : 0) | column);
buf_num = page_addr & 7;
}
/* Setup the FMR[OP] to execute without write protection */
out_be32(&lbc->fmr, priv->fmr | 3); if (elbc_fcm_ctrl->use_mdr)
out_be32(&lbc->mdr, elbc_fcm_ctrl->mdr);
ctrl->irq_status = 0; /* execute special operation */
out_be32(&lbc->lsor, priv->bank);
/* wait for FCM complete flag or timeout */
wait_event_timeout(ctrl->irq_wait, ctrl->irq_status,
FCM_TIMEOUT_MSECS * HZ/1000);
elbc_fcm_ctrl->status = ctrl->irq_status; /* store mdr value in case it was needed */ if (elbc_fcm_ctrl->use_mdr)
elbc_fcm_ctrl->mdr = in_be32(&lbc->mdr);
elbc_fcm_ctrl->use_mdr = 0;
if (elbc_fcm_ctrl->status != LTESR_CC) {
dev_info(priv->dev, "command failed: fir %x fcr %x status %x mdr %x\n",
in_be32(&lbc->fir), in_be32(&lbc->fcr),
elbc_fcm_ctrl->status, elbc_fcm_ctrl->mdr); return -EIO;
}
if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST) return 0;
elbc_fcm_ctrl->max_bitflips = 0;
if (elbc_fcm_ctrl->read_bytes == mtd->writesize + mtd->oobsize) {
uint32_t lteccr = in_be32(&lbc->lteccr); /* * if command was a full page read and the ELBC * has the LTECCR register, then bits 12-15 (ppc order) of * LTECCR indicates which 512 byte sub-pages had fixed errors. * bits 28-31 are uncorrectable errors, marked elsewhere. * for small page nand only 1 bit is used. * if the ELBC doesn't have the lteccr register it reads 0 * FIXME: 4 bits can be corrected on NANDs with 2k pages, so * count the number of sub-pages with bitflips and update * ecc_stats.corrected accordingly.
*/ if (lteccr & 0x000F000F)
out_be32(&lbc->lteccr, 0x000F000F); /* clear lteccr */ if (lteccr & 0x000F0000) {
mtd->ecc_stats.corrected++;
elbc_fcm_ctrl->max_bitflips = 1;
}
}
/* clear the read buffer */
elbc_fcm_ctrl->read_bytes = 0; if (command != NAND_CMD_PAGEPROG)
elbc_fcm_ctrl->index = 0;
switch (command) { /* READ0 and READ1 read the entire buffer to use hardware ECC. */ case NAND_CMD_READ1:
column += 256;
fallthrough; case NAND_CMD_READ0:
dev_dbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:" " 0x%x, column: 0x%x.\n", page_addr, column);
/* RNDOUT moves the pointer inside the page */ case NAND_CMD_RNDOUT:
dev_dbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_RNDOUT, column: 0x%x.\n",
column);
elbc_fcm_ctrl->index = column; return;
/* READOOB reads only the OOB because no ECC is performed. */ case NAND_CMD_READOOB:
dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:" " 0x%x, column: 0x%x.\n", page_addr, column);
/* SEQIN sets up the addr buffer and all registers except the length */ case NAND_CMD_SEQIN: {
__be32 fcr;
dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, " "page_addr: 0x%x, column: 0x%x.\n",
page_addr, column);
/* PAGEPROG reuses all of the setup from SEQIN and adds the length */ case NAND_CMD_PAGEPROG: {
dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG " "writing %d bytes.\n", elbc_fcm_ctrl->index);
/* if the write did not start at 0 or is not a full page * then set the exact length, otherwise use a full page * write so the HW generates the ECC.
*/ if (elbc_fcm_ctrl->oob || elbc_fcm_ctrl->column != 0 ||
elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize)
out_be32(&lbc->fbcr,
elbc_fcm_ctrl->index - elbc_fcm_ctrl->column); else
out_be32(&lbc->fbcr, 0);
fsl_elbc_run_command(mtd); return;
}
/* CMD_STATUS must read the status byte while CEB is active */ /* Note - it does not wait for the ready line */ case NAND_CMD_STATUS:
out_be32(&lbc->fir,
(FIR_OP_CM0 << FIR_OP0_SHIFT) |
(FIR_OP_RBW << FIR_OP1_SHIFT));
out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT);
out_be32(&lbc->fbcr, 1);
set_addr(mtd, 0, 0, 0);
elbc_fcm_ctrl->read_bytes = 1;
fsl_elbc_run_command(mtd);
/* The chip always seems to report that it is * write-protected, even when it is not.
*/
setbits8(elbc_fcm_ctrl->addr, NAND_STATUS_WP); return;
/* RESET without waiting for the ready line */ case NAND_CMD_RESET:
dev_dbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n");
out_be32(&lbc->fir, FIR_OP_CM0 << FIR_OP0_SHIFT);
out_be32(&lbc->fcr, NAND_CMD_RESET << FCR_CMD0_SHIFT);
fsl_elbc_run_command(mtd); return;
if (len <= 0) {
dev_err(priv->dev, "write_buf of %d bytes", len);
elbc_fcm_ctrl->status = 0; return;
}
if ((unsignedint)len > bufsize - elbc_fcm_ctrl->index) {
dev_err(priv->dev, "write_buf beyond end of buffer " "(%d requested, %u available)\n",
len, bufsize - elbc_fcm_ctrl->index);
len = bufsize - elbc_fcm_ctrl->index;
}
memcpy_toio(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], buf, len); /* * This is workaround for the weird elbc hangs during nand write, * Scott Wood says: "...perhaps difference in how long it takes a * write to make it through the localbus compared to a write to IMMR * is causing problems, and sync isn't helping for some reason." * Reading back the last byte helps though.
*/
in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index] + len - 1);
elbc_fcm_ctrl->index += len;
}
/* * read a byte from either the FCM hardware buffer if it has any data left * otherwise issue a command to read a single byte.
*/ static u8 fsl_elbc_read_byte(struct nand_chip *chip)
{ struct fsl_elbc_mtd *priv = nand_get_controller_data(chip); struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
/* If there are still bytes in the FCM, then use the next byte. */ if (elbc_fcm_ctrl->index < elbc_fcm_ctrl->read_bytes) return in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index++]);
dev_err(priv->dev, "read_byte beyond end of buffer\n"); return ERR_BYTE;
}
/* * Read from the FCM Controller Data Buffer
*/ staticvoid fsl_elbc_read_buf(struct nand_chip *chip, u8 *buf, int len)
{ struct fsl_elbc_mtd *priv = nand_get_controller_data(chip); struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; int avail;
if (len > avail)
dev_err(priv->dev, "read_buf beyond end of buffer " "(%d requested, %d available)\n",
len, avail);
}
/* This function is called after Program and Erase Operations to * check for success or failure.
*/ staticint fsl_elbc_wait(struct nand_chip *chip)
{ struct fsl_elbc_mtd *priv = nand_get_controller_data(chip); struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
if (elbc_fcm_ctrl->status != LTESR_CC) return NAND_STATUS_FAIL;
/* The chip always seems to report that it is * write-protected, even when it is not.
*/ return (elbc_fcm_ctrl->mdr & 0xff) | NAND_STATUS_WP;
}
nand_read_page_op(chip, page, 0, buf, mtd->writesize); if (oob_required)
fsl_elbc_read_buf(chip, chip->oob_poi, mtd->oobsize);
if (fsl_elbc_wait(chip) & NAND_STATUS_FAIL)
mtd->ecc_stats.failed++;
return elbc_fcm_ctrl->max_bitflips;
}
/* ECC will be calculated automatically, and errors will be detected in * waitfunc.
*/ staticint fsl_elbc_write_page(struct nand_chip *chip, const uint8_t *buf, int oob_required, int page)
{ struct mtd_info *mtd = nand_to_mtd(chip);
/* ECC will be calculated automatically, and errors will be detected in * waitfunc.
*/ staticint fsl_elbc_write_subpage(struct nand_chip *chip, uint32_t offset,
uint32_t data_len, const uint8_t *buf, int oob_required, int page)
{ struct mtd_info *mtd = nand_to_mtd(chip);
/* * if ECC was not chosen in DT, decide whether to use HW or SW ECC from * CS Base Register
*/ if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_INVALID) { /* If CS Base Register selects full hardware ECC then use it */ if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
BR_DECC_CHK_GEN) {
chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
} else { /* otherwise fall back to default software ECC */
chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
}
}
switch (chip->ecc.engine_type) { /* if HW ECC was chosen, setup ecc and oob layout */ case NAND_ECC_ENGINE_TYPE_ON_HOST:
chip->ecc.read_page = fsl_elbc_read_page;
chip->ecc.write_page = fsl_elbc_write_page;
chip->ecc.write_subpage = fsl_elbc_write_subpage;
mtd_set_ooblayout(mtd, &fsl_elbc_ooblayout_ops);
chip->ecc.size = 512;
chip->ecc.bytes = 3;
chip->ecc.strength = 1; break;
/* if none or SW ECC was chosen, we do not need to set anything here */ case NAND_ECC_ENGINE_TYPE_NONE: case NAND_ECC_ENGINE_TYPE_SOFT: case NAND_ECC_ENGINE_TYPE_ON_DIE: break;
default: return -EINVAL;
}
/* enable/disable HW ECC checking and generating based on if HW ECC was chosen */
br = in_be32(&lbc->bank[priv->bank].br) & ~BR_DECC; if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST)
out_be32(&lbc->bank[priv->bank].br, br | BR_DECC_CHK_GEN); else
out_be32(&lbc->bank[priv->bank].br, br | BR_DECC_OFF);
/* calculate FMR Address Length field */
al = 0; if (chip->pagemask & 0xffff0000)
al++; if (chip->pagemask & 0xff000000)
al++;
if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) return dev_err_probe(&pdev->dev, -EPROBE_DEFER, "lbc_ctrl_dev missing\n");
lbc = fsl_lbc_ctrl_dev->regs;
dev = fsl_lbc_ctrl_dev->dev;
/* get, allocate and map the memory resource */
ret = of_address_to_resource(node, 0, &res); if (ret) {
dev_err(dev, "failed to get resource\n"); return ret;
}
/* find which chip select it is connected to */ for (bank = 0; bank < MAX_BANKS; bank++) if ((in_be32(&lbc->bank[bank].br) & BR_V) &&
(in_be32(&lbc->bank[bank].br) & BR_MSEL) == BR_MS_FCM &&
(in_be32(&lbc->bank[bank].br) &
in_be32(&lbc->bank[bank].or) & BR_BA)
== fsl_lbc_addr(res.start)) break;
if (bank >= MAX_BANKS) {
dev_err(dev, "address did not match any chip selects\n"); return -ENODEV;
}
priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM;
mutex_lock(&fsl_elbc_nand_mutex); if (!fsl_lbc_ctrl_dev->nand) {
elbc_fcm_ctrl = kzalloc(sizeof(*elbc_fcm_ctrl), GFP_KERNEL); if (!elbc_fcm_ctrl) {
mutex_unlock(&fsl_elbc_nand_mutex);
ret = -ENOMEM; goto err;
}
elbc_fcm_ctrl->counter++;
priv->vbase = ioremap(res.start, resource_size(&res)); if (!priv->vbase) {
dev_err(dev, "failed to map chip region\n");
ret = -ENOMEM; goto err;
}
mtd = nand_to_mtd(&priv->chip);
mtd->name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start); if (!nand_to_mtd(&priv->chip)->name) {
ret = -ENOMEM; goto err;
}
ret = fsl_elbc_chip_init(priv); if (ret) goto err;
priv->chip.controller->ops = &fsl_elbc_controller_ops;
ret = nand_scan(&priv->chip, 1); if (ret) goto err;
/* First look for RedBoot table or partitions on the command
* line, these take precedence over device tree information */
ret = mtd_device_parse_register(mtd, part_probe_types, NULL, NULL, 0); if (ret) goto cleanup_nand;
pr_info("eLBC NAND device at 0x%llx, bank %d\n",
(unsignedlonglong)res.start, priv->bank);
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.