11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
293db446aSBoris Brezillon /* Freescale Enhanced Local Bus Controller NAND driver
393db446aSBoris Brezillon *
493db446aSBoris Brezillon * Copyright © 2006-2007, 2010 Freescale Semiconductor
593db446aSBoris Brezillon *
693db446aSBoris Brezillon * Authors: Nick Spence <nick.spence@freescale.com>,
793db446aSBoris Brezillon * Scott Wood <scottwood@freescale.com>
893db446aSBoris Brezillon * Jack Lan <jack.lan@freescale.com>
993db446aSBoris Brezillon * Roy Zang <tie-fei.zang@freescale.com>
1093db446aSBoris Brezillon */
1193db446aSBoris Brezillon
1293db446aSBoris Brezillon #include <linux/module.h>
1393db446aSBoris Brezillon #include <linux/types.h>
1493db446aSBoris Brezillon #include <linux/kernel.h>
1593db446aSBoris Brezillon #include <linux/string.h>
1693db446aSBoris Brezillon #include <linux/ioport.h>
1793db446aSBoris Brezillon #include <linux/of_address.h>
1893db446aSBoris Brezillon #include <linux/of_platform.h>
1993db446aSBoris Brezillon #include <linux/platform_device.h>
2093db446aSBoris Brezillon #include <linux/slab.h>
2193db446aSBoris Brezillon #include <linux/interrupt.h>
2293db446aSBoris Brezillon
2393db446aSBoris Brezillon #include <linux/mtd/mtd.h>
2493db446aSBoris Brezillon #include <linux/mtd/rawnand.h>
2593db446aSBoris Brezillon #include <linux/mtd/partitions.h>
2693db446aSBoris Brezillon
2793db446aSBoris Brezillon #include <asm/io.h>
2893db446aSBoris Brezillon #include <asm/fsl_lbc.h>
2993db446aSBoris Brezillon
3093db446aSBoris Brezillon #define MAX_BANKS 8
3193db446aSBoris Brezillon #define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */
3293db446aSBoris Brezillon #define FCM_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait for FCM */
3393db446aSBoris Brezillon
3493db446aSBoris Brezillon /* mtd information per set */
3593db446aSBoris Brezillon
3693db446aSBoris Brezillon struct fsl_elbc_mtd {
3793db446aSBoris Brezillon struct nand_chip chip;
3893db446aSBoris Brezillon struct fsl_lbc_ctrl *ctrl;
3993db446aSBoris Brezillon
4093db446aSBoris Brezillon struct device *dev;
4193db446aSBoris Brezillon int bank; /* Chip select bank number */
4293db446aSBoris Brezillon u8 __iomem *vbase; /* Chip select base virtual address */
4393db446aSBoris Brezillon int page_size; /* NAND page size (0=512, 1=2048) */
4493db446aSBoris Brezillon unsigned int fmr; /* FCM Flash Mode Register value */
4593db446aSBoris Brezillon };
4693db446aSBoris Brezillon
4793db446aSBoris Brezillon /* Freescale eLBC FCM controller information */
4893db446aSBoris Brezillon
4993db446aSBoris Brezillon struct fsl_elbc_fcm_ctrl {
507da45139SMiquel Raynal struct nand_controller controller;
5193db446aSBoris Brezillon struct fsl_elbc_mtd *chips[MAX_BANKS];
5293db446aSBoris Brezillon
5393db446aSBoris Brezillon u8 __iomem *addr; /* Address of assigned FCM buffer */
5493db446aSBoris Brezillon unsigned int page; /* Last page written to / read from */
5593db446aSBoris Brezillon unsigned int read_bytes; /* Number of bytes read during command */
5693db446aSBoris Brezillon unsigned int column; /* Saved column from SEQIN */
5793db446aSBoris Brezillon unsigned int index; /* Pointer to next byte to 'read' */
5893db446aSBoris Brezillon unsigned int status; /* status read from LTESR after last op */
5993db446aSBoris Brezillon unsigned int mdr; /* UPM/FCM Data Register value */
6093db446aSBoris Brezillon unsigned int use_mdr; /* Non zero if the MDR is to be set */
6193db446aSBoris Brezillon unsigned int oob; /* Non zero if operating on OOB data */
6293db446aSBoris Brezillon unsigned int counter; /* counter for the initializations */
6393db446aSBoris Brezillon unsigned int max_bitflips; /* Saved during READ0 cmd */
6493db446aSBoris Brezillon };
6593db446aSBoris Brezillon
6693db446aSBoris Brezillon /* These map to the positions used by the FCM hardware ECC generator */
6793db446aSBoris Brezillon
fsl_elbc_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * oobregion)6893db446aSBoris Brezillon static int fsl_elbc_ooblayout_ecc(struct mtd_info *mtd, int section,
6993db446aSBoris Brezillon struct mtd_oob_region *oobregion)
7093db446aSBoris Brezillon {
7193db446aSBoris Brezillon struct nand_chip *chip = mtd_to_nand(mtd);
7293db446aSBoris Brezillon struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
7393db446aSBoris Brezillon
7493db446aSBoris Brezillon if (section >= chip->ecc.steps)
7593db446aSBoris Brezillon return -ERANGE;
7693db446aSBoris Brezillon
7793db446aSBoris Brezillon oobregion->offset = (16 * section) + 6;
7893db446aSBoris Brezillon if (priv->fmr & FMR_ECCM)
7993db446aSBoris Brezillon oobregion->offset += 2;
8093db446aSBoris Brezillon
8193db446aSBoris Brezillon oobregion->length = chip->ecc.bytes;
8293db446aSBoris Brezillon
8393db446aSBoris Brezillon return 0;
8493db446aSBoris Brezillon }
8593db446aSBoris Brezillon
fsl_elbc_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * oobregion)8693db446aSBoris Brezillon static int fsl_elbc_ooblayout_free(struct mtd_info *mtd, int section,
8793db446aSBoris Brezillon struct mtd_oob_region *oobregion)
8893db446aSBoris Brezillon {
8993db446aSBoris Brezillon struct nand_chip *chip = mtd_to_nand(mtd);
9093db446aSBoris Brezillon struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
9193db446aSBoris Brezillon
9293db446aSBoris Brezillon if (section > chip->ecc.steps)
9393db446aSBoris Brezillon return -ERANGE;
9493db446aSBoris Brezillon
9593db446aSBoris Brezillon if (!section) {
9693db446aSBoris Brezillon oobregion->offset = 0;
9793db446aSBoris Brezillon if (mtd->writesize > 512)
9893db446aSBoris Brezillon oobregion->offset++;
9993db446aSBoris Brezillon oobregion->length = (priv->fmr & FMR_ECCM) ? 7 : 5;
10093db446aSBoris Brezillon } else {
10193db446aSBoris Brezillon oobregion->offset = (16 * section) -
10293db446aSBoris Brezillon ((priv->fmr & FMR_ECCM) ? 5 : 7);
10393db446aSBoris Brezillon if (section < chip->ecc.steps)
10493db446aSBoris Brezillon oobregion->length = 13;
10593db446aSBoris Brezillon else
10693db446aSBoris Brezillon oobregion->length = mtd->oobsize - oobregion->offset;
10793db446aSBoris Brezillon }
10893db446aSBoris Brezillon
10993db446aSBoris Brezillon return 0;
11093db446aSBoris Brezillon }
11193db446aSBoris Brezillon
11293db446aSBoris Brezillon static const struct mtd_ooblayout_ops fsl_elbc_ooblayout_ops = {
11393db446aSBoris Brezillon .ecc = fsl_elbc_ooblayout_ecc,
11493db446aSBoris Brezillon .free = fsl_elbc_ooblayout_free,
11593db446aSBoris Brezillon };
11693db446aSBoris Brezillon
11793db446aSBoris Brezillon /*
11893db446aSBoris Brezillon * ELBC may use HW ECC, so that OOB offsets, that NAND core uses for bbt,
11993db446aSBoris Brezillon * interfere with ECC positions, that's why we implement our own descriptors.
12093db446aSBoris Brezillon * OOB {11, 5}, works for both SP and LP chips, with ECCM = 1 and ECCM = 0.
12193db446aSBoris Brezillon */
12293db446aSBoris Brezillon static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
12393db446aSBoris Brezillon static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
12493db446aSBoris Brezillon
12593db446aSBoris Brezillon static struct nand_bbt_descr bbt_main_descr = {
12693db446aSBoris Brezillon .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
12793db446aSBoris Brezillon NAND_BBT_2BIT | NAND_BBT_VERSION,
12893db446aSBoris Brezillon .offs = 11,
12993db446aSBoris Brezillon .len = 4,
13093db446aSBoris Brezillon .veroffs = 15,
13193db446aSBoris Brezillon .maxblocks = 4,
13293db446aSBoris Brezillon .pattern = bbt_pattern,
13393db446aSBoris Brezillon };
13493db446aSBoris Brezillon
13593db446aSBoris Brezillon static struct nand_bbt_descr bbt_mirror_descr = {
13693db446aSBoris Brezillon .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
13793db446aSBoris Brezillon NAND_BBT_2BIT | NAND_BBT_VERSION,
13893db446aSBoris Brezillon .offs = 11,
13993db446aSBoris Brezillon .len = 4,
14093db446aSBoris Brezillon .veroffs = 15,
14193db446aSBoris Brezillon .maxblocks = 4,
14293db446aSBoris Brezillon .pattern = mirror_pattern,
14393db446aSBoris Brezillon };
14493db446aSBoris Brezillon
14593db446aSBoris Brezillon /*=================================*/
14693db446aSBoris Brezillon
14793db446aSBoris Brezillon /*
14893db446aSBoris Brezillon * Set up the FCM hardware block and page address fields, and the fcm
14993db446aSBoris Brezillon * structure addr field to point to the correct FCM buffer in memory
15093db446aSBoris Brezillon */
set_addr(struct mtd_info * mtd,int column,int page_addr,int oob)15193db446aSBoris Brezillon static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
15293db446aSBoris Brezillon {
15393db446aSBoris Brezillon struct nand_chip *chip = mtd_to_nand(mtd);
15493db446aSBoris Brezillon struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
15593db446aSBoris Brezillon struct fsl_lbc_ctrl *ctrl = priv->ctrl;
15693db446aSBoris Brezillon struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
15793db446aSBoris Brezillon struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
15893db446aSBoris Brezillon int buf_num;
15993db446aSBoris Brezillon
16093db446aSBoris Brezillon elbc_fcm_ctrl->page = page_addr;
16193db446aSBoris Brezillon
16293db446aSBoris Brezillon if (priv->page_size) {
16393db446aSBoris Brezillon /*
16493db446aSBoris Brezillon * large page size chip : FPAR[PI] save the lowest 6 bits,
16593db446aSBoris Brezillon * FBAR[BLK] save the other bits.
16693db446aSBoris Brezillon */
16793db446aSBoris Brezillon out_be32(&lbc->fbar, page_addr >> 6);
16893db446aSBoris Brezillon out_be32(&lbc->fpar,
16993db446aSBoris Brezillon ((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI) |
17093db446aSBoris Brezillon (oob ? FPAR_LP_MS : 0) | column);
17193db446aSBoris Brezillon buf_num = (page_addr & 1) << 2;
17293db446aSBoris Brezillon } else {
17393db446aSBoris Brezillon /*
17493db446aSBoris Brezillon * small page size chip : FPAR[PI] save the lowest 5 bits,
17593db446aSBoris Brezillon * FBAR[BLK] save the other bits.
17693db446aSBoris Brezillon */
17793db446aSBoris Brezillon out_be32(&lbc->fbar, page_addr >> 5);
17893db446aSBoris Brezillon out_be32(&lbc->fpar,
17993db446aSBoris Brezillon ((page_addr << FPAR_SP_PI_SHIFT) & FPAR_SP_PI) |
18093db446aSBoris Brezillon (oob ? FPAR_SP_MS : 0) | column);
18193db446aSBoris Brezillon buf_num = page_addr & 7;
18293db446aSBoris Brezillon }
18393db446aSBoris Brezillon
18493db446aSBoris Brezillon elbc_fcm_ctrl->addr = priv->vbase + buf_num * 1024;
18593db446aSBoris Brezillon elbc_fcm_ctrl->index = column;
18693db446aSBoris Brezillon
18793db446aSBoris Brezillon /* for OOB data point to the second half of the buffer */
18893db446aSBoris Brezillon if (oob)
18993db446aSBoris Brezillon elbc_fcm_ctrl->index += priv->page_size ? 2048 : 512;
19093db446aSBoris Brezillon
19193db446aSBoris Brezillon dev_vdbg(priv->dev, "set_addr: bank=%d, "
19293db446aSBoris Brezillon "elbc_fcm_ctrl->addr=0x%p (0x%p), "
19393db446aSBoris Brezillon "index %x, pes %d ps %d\n",
19493db446aSBoris Brezillon buf_num, elbc_fcm_ctrl->addr, priv->vbase,
19593db446aSBoris Brezillon elbc_fcm_ctrl->index,
19693db446aSBoris Brezillon chip->phys_erase_shift, chip->page_shift);
19793db446aSBoris Brezillon }
19893db446aSBoris Brezillon
19993db446aSBoris Brezillon /*
20093db446aSBoris Brezillon * execute FCM command and wait for it to complete
20193db446aSBoris Brezillon */
fsl_elbc_run_command(struct mtd_info * mtd)20293db446aSBoris Brezillon static int fsl_elbc_run_command(struct mtd_info *mtd)
20393db446aSBoris Brezillon {
20493db446aSBoris Brezillon struct nand_chip *chip = mtd_to_nand(mtd);
20593db446aSBoris Brezillon struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
20693db446aSBoris Brezillon struct fsl_lbc_ctrl *ctrl = priv->ctrl;
20793db446aSBoris Brezillon struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
20893db446aSBoris Brezillon struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
20993db446aSBoris Brezillon
21093db446aSBoris Brezillon /* Setup the FMR[OP] to execute without write protection */
21193db446aSBoris Brezillon out_be32(&lbc->fmr, priv->fmr | 3);
21293db446aSBoris Brezillon if (elbc_fcm_ctrl->use_mdr)
21393db446aSBoris Brezillon out_be32(&lbc->mdr, elbc_fcm_ctrl->mdr);
21493db446aSBoris Brezillon
21593db446aSBoris Brezillon dev_vdbg(priv->dev,
21693db446aSBoris Brezillon "fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n",
21793db446aSBoris Brezillon in_be32(&lbc->fmr), in_be32(&lbc->fir), in_be32(&lbc->fcr));
21893db446aSBoris Brezillon dev_vdbg(priv->dev,
21993db446aSBoris Brezillon "fsl_elbc_run_command: fbar=%08x fpar=%08x "
22093db446aSBoris Brezillon "fbcr=%08x bank=%d\n",
22193db446aSBoris Brezillon in_be32(&lbc->fbar), in_be32(&lbc->fpar),
22293db446aSBoris Brezillon in_be32(&lbc->fbcr), priv->bank);
22393db446aSBoris Brezillon
22493db446aSBoris Brezillon ctrl->irq_status = 0;
22593db446aSBoris Brezillon /* execute special operation */
22693db446aSBoris Brezillon out_be32(&lbc->lsor, priv->bank);
22793db446aSBoris Brezillon
22893db446aSBoris Brezillon /* wait for FCM complete flag or timeout */
22993db446aSBoris Brezillon wait_event_timeout(ctrl->irq_wait, ctrl->irq_status,
23093db446aSBoris Brezillon FCM_TIMEOUT_MSECS * HZ/1000);
23193db446aSBoris Brezillon elbc_fcm_ctrl->status = ctrl->irq_status;
23293db446aSBoris Brezillon /* store mdr value in case it was needed */
23393db446aSBoris Brezillon if (elbc_fcm_ctrl->use_mdr)
23493db446aSBoris Brezillon elbc_fcm_ctrl->mdr = in_be32(&lbc->mdr);
23593db446aSBoris Brezillon
23693db446aSBoris Brezillon elbc_fcm_ctrl->use_mdr = 0;
23793db446aSBoris Brezillon
23893db446aSBoris Brezillon if (elbc_fcm_ctrl->status != LTESR_CC) {
23993db446aSBoris Brezillon dev_info(priv->dev,
24093db446aSBoris Brezillon "command failed: fir %x fcr %x status %x mdr %x\n",
24193db446aSBoris Brezillon in_be32(&lbc->fir), in_be32(&lbc->fcr),
24293db446aSBoris Brezillon elbc_fcm_ctrl->status, elbc_fcm_ctrl->mdr);
24393db446aSBoris Brezillon return -EIO;
24493db446aSBoris Brezillon }
24593db446aSBoris Brezillon
246bace41f8SMiquel Raynal if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST)
24793db446aSBoris Brezillon return 0;
24893db446aSBoris Brezillon
24993db446aSBoris Brezillon elbc_fcm_ctrl->max_bitflips = 0;
25093db446aSBoris Brezillon
25193db446aSBoris Brezillon if (elbc_fcm_ctrl->read_bytes == mtd->writesize + mtd->oobsize) {
25293db446aSBoris Brezillon uint32_t lteccr = in_be32(&lbc->lteccr);
25393db446aSBoris Brezillon /*
25493db446aSBoris Brezillon * if command was a full page read and the ELBC
25593db446aSBoris Brezillon * has the LTECCR register, then bits 12-15 (ppc order) of
25693db446aSBoris Brezillon * LTECCR indicates which 512 byte sub-pages had fixed errors.
25793db446aSBoris Brezillon * bits 28-31 are uncorrectable errors, marked elsewhere.
25893db446aSBoris Brezillon * for small page nand only 1 bit is used.
25993db446aSBoris Brezillon * if the ELBC doesn't have the lteccr register it reads 0
26093db446aSBoris Brezillon * FIXME: 4 bits can be corrected on NANDs with 2k pages, so
26193db446aSBoris Brezillon * count the number of sub-pages with bitflips and update
26293db446aSBoris Brezillon * ecc_stats.corrected accordingly.
26393db446aSBoris Brezillon */
26493db446aSBoris Brezillon if (lteccr & 0x000F000F)
26593db446aSBoris Brezillon out_be32(&lbc->lteccr, 0x000F000F); /* clear lteccr */
26693db446aSBoris Brezillon if (lteccr & 0x000F0000) {
26793db446aSBoris Brezillon mtd->ecc_stats.corrected++;
26893db446aSBoris Brezillon elbc_fcm_ctrl->max_bitflips = 1;
26993db446aSBoris Brezillon }
27093db446aSBoris Brezillon }
27193db446aSBoris Brezillon
27293db446aSBoris Brezillon return 0;
27393db446aSBoris Brezillon }
27493db446aSBoris Brezillon
fsl_elbc_do_read(struct nand_chip * chip,int oob)27593db446aSBoris Brezillon static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
27693db446aSBoris Brezillon {
27793db446aSBoris Brezillon struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
27893db446aSBoris Brezillon struct fsl_lbc_ctrl *ctrl = priv->ctrl;
27993db446aSBoris Brezillon struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
28093db446aSBoris Brezillon
28193db446aSBoris Brezillon if (priv->page_size) {
28293db446aSBoris Brezillon out_be32(&lbc->fir,
28393db446aSBoris Brezillon (FIR_OP_CM0 << FIR_OP0_SHIFT) |
28493db446aSBoris Brezillon (FIR_OP_CA << FIR_OP1_SHIFT) |
28593db446aSBoris Brezillon (FIR_OP_PA << FIR_OP2_SHIFT) |
28693db446aSBoris Brezillon (FIR_OP_CM1 << FIR_OP3_SHIFT) |
28793db446aSBoris Brezillon (FIR_OP_RBW << FIR_OP4_SHIFT));
28893db446aSBoris Brezillon
28993db446aSBoris Brezillon out_be32(&lbc->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) |
29093db446aSBoris Brezillon (NAND_CMD_READSTART << FCR_CMD1_SHIFT));
29193db446aSBoris Brezillon } else {
29293db446aSBoris Brezillon out_be32(&lbc->fir,
29393db446aSBoris Brezillon (FIR_OP_CM0 << FIR_OP0_SHIFT) |
29493db446aSBoris Brezillon (FIR_OP_CA << FIR_OP1_SHIFT) |
29593db446aSBoris Brezillon (FIR_OP_PA << FIR_OP2_SHIFT) |
29693db446aSBoris Brezillon (FIR_OP_RBW << FIR_OP3_SHIFT));
29793db446aSBoris Brezillon
29893db446aSBoris Brezillon if (oob)
29993db446aSBoris Brezillon out_be32(&lbc->fcr, NAND_CMD_READOOB << FCR_CMD0_SHIFT);
30093db446aSBoris Brezillon else
30193db446aSBoris Brezillon out_be32(&lbc->fcr, NAND_CMD_READ0 << FCR_CMD0_SHIFT);
30293db446aSBoris Brezillon }
30393db446aSBoris Brezillon }
30493db446aSBoris Brezillon
30593db446aSBoris Brezillon /* cmdfunc send commands to the FCM */
fsl_elbc_cmdfunc(struct nand_chip * chip,unsigned int command,int column,int page_addr)3065295cf2eSBoris Brezillon static void fsl_elbc_cmdfunc(struct nand_chip *chip, unsigned int command,
30793db446aSBoris Brezillon int column, int page_addr)
30893db446aSBoris Brezillon {
3095295cf2eSBoris Brezillon struct mtd_info *mtd = nand_to_mtd(chip);
31093db446aSBoris Brezillon struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
31193db446aSBoris Brezillon struct fsl_lbc_ctrl *ctrl = priv->ctrl;
31293db446aSBoris Brezillon struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
31393db446aSBoris Brezillon struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
31493db446aSBoris Brezillon
31593db446aSBoris Brezillon elbc_fcm_ctrl->use_mdr = 0;
31693db446aSBoris Brezillon
31793db446aSBoris Brezillon /* clear the read buffer */
31893db446aSBoris Brezillon elbc_fcm_ctrl->read_bytes = 0;
31993db446aSBoris Brezillon if (command != NAND_CMD_PAGEPROG)
32093db446aSBoris Brezillon elbc_fcm_ctrl->index = 0;
32193db446aSBoris Brezillon
32293db446aSBoris Brezillon switch (command) {
32393db446aSBoris Brezillon /* READ0 and READ1 read the entire buffer to use hardware ECC. */
32493db446aSBoris Brezillon case NAND_CMD_READ1:
32593db446aSBoris Brezillon column += 256;
326025a06c1SMiquel Raynal fallthrough;
32793db446aSBoris Brezillon case NAND_CMD_READ0:
32893db446aSBoris Brezillon dev_dbg(priv->dev,
32993db446aSBoris Brezillon "fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:"
33093db446aSBoris Brezillon " 0x%x, column: 0x%x.\n", page_addr, column);
33193db446aSBoris Brezillon
33293db446aSBoris Brezillon
33393db446aSBoris Brezillon out_be32(&lbc->fbcr, 0); /* read entire page to enable ECC */
33493db446aSBoris Brezillon set_addr(mtd, 0, page_addr, 0);
33593db446aSBoris Brezillon
33693db446aSBoris Brezillon elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
33793db446aSBoris Brezillon elbc_fcm_ctrl->index += column;
33893db446aSBoris Brezillon
33993db446aSBoris Brezillon fsl_elbc_do_read(chip, 0);
34093db446aSBoris Brezillon fsl_elbc_run_command(mtd);
34193db446aSBoris Brezillon return;
34293db446aSBoris Brezillon
343070fb974SMarek Behún /* RNDOUT moves the pointer inside the page */
344070fb974SMarek Behún case NAND_CMD_RNDOUT:
345070fb974SMarek Behún dev_dbg(priv->dev,
346070fb974SMarek Behún "fsl_elbc_cmdfunc: NAND_CMD_RNDOUT, column: 0x%x.\n",
347070fb974SMarek Behún column);
348070fb974SMarek Behún
349070fb974SMarek Behún elbc_fcm_ctrl->index = column;
350070fb974SMarek Behún return;
351070fb974SMarek Behún
35293db446aSBoris Brezillon /* READOOB reads only the OOB because no ECC is performed. */
35393db446aSBoris Brezillon case NAND_CMD_READOOB:
35493db446aSBoris Brezillon dev_vdbg(priv->dev,
35593db446aSBoris Brezillon "fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:"
35693db446aSBoris Brezillon " 0x%x, column: 0x%x.\n", page_addr, column);
35793db446aSBoris Brezillon
35893db446aSBoris Brezillon out_be32(&lbc->fbcr, mtd->oobsize - column);
35993db446aSBoris Brezillon set_addr(mtd, column, page_addr, 1);
36093db446aSBoris Brezillon
36193db446aSBoris Brezillon elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
36293db446aSBoris Brezillon
36393db446aSBoris Brezillon fsl_elbc_do_read(chip, 1);
36493db446aSBoris Brezillon fsl_elbc_run_command(mtd);
36593db446aSBoris Brezillon return;
36693db446aSBoris Brezillon
36793db446aSBoris Brezillon case NAND_CMD_READID:
36893db446aSBoris Brezillon case NAND_CMD_PARAM:
36993db446aSBoris Brezillon dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD %x\n", command);
37093db446aSBoris Brezillon
37193db446aSBoris Brezillon out_be32(&lbc->fir, (FIR_OP_CM0 << FIR_OP0_SHIFT) |
37293db446aSBoris Brezillon (FIR_OP_UA << FIR_OP1_SHIFT) |
37393db446aSBoris Brezillon (FIR_OP_RBW << FIR_OP2_SHIFT));
37493db446aSBoris Brezillon out_be32(&lbc->fcr, command << FCR_CMD0_SHIFT);
37593db446aSBoris Brezillon /*
37693db446aSBoris Brezillon * although currently it's 8 bytes for READID, we always read
37793db446aSBoris Brezillon * the maximum 256 bytes(for PARAM)
37893db446aSBoris Brezillon */
37993db446aSBoris Brezillon out_be32(&lbc->fbcr, 256);
38093db446aSBoris Brezillon elbc_fcm_ctrl->read_bytes = 256;
38193db446aSBoris Brezillon elbc_fcm_ctrl->use_mdr = 1;
38293db446aSBoris Brezillon elbc_fcm_ctrl->mdr = column;
38393db446aSBoris Brezillon set_addr(mtd, 0, 0, 0);
38493db446aSBoris Brezillon fsl_elbc_run_command(mtd);
38593db446aSBoris Brezillon return;
38693db446aSBoris Brezillon
38793db446aSBoris Brezillon /* ERASE1 stores the block and page address */
38893db446aSBoris Brezillon case NAND_CMD_ERASE1:
38993db446aSBoris Brezillon dev_vdbg(priv->dev,
39093db446aSBoris Brezillon "fsl_elbc_cmdfunc: NAND_CMD_ERASE1, "
39193db446aSBoris Brezillon "page_addr: 0x%x.\n", page_addr);
39293db446aSBoris Brezillon set_addr(mtd, 0, page_addr, 0);
39393db446aSBoris Brezillon return;
39493db446aSBoris Brezillon
39593db446aSBoris Brezillon /* ERASE2 uses the block and page address from ERASE1 */
39693db446aSBoris Brezillon case NAND_CMD_ERASE2:
39793db446aSBoris Brezillon dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n");
39893db446aSBoris Brezillon
39993db446aSBoris Brezillon out_be32(&lbc->fir,
40093db446aSBoris Brezillon (FIR_OP_CM0 << FIR_OP0_SHIFT) |
40193db446aSBoris Brezillon (FIR_OP_PA << FIR_OP1_SHIFT) |
40293db446aSBoris Brezillon (FIR_OP_CM2 << FIR_OP2_SHIFT) |
40393db446aSBoris Brezillon (FIR_OP_CW1 << FIR_OP3_SHIFT) |
40493db446aSBoris Brezillon (FIR_OP_RS << FIR_OP4_SHIFT));
40593db446aSBoris Brezillon
40693db446aSBoris Brezillon out_be32(&lbc->fcr,
40793db446aSBoris Brezillon (NAND_CMD_ERASE1 << FCR_CMD0_SHIFT) |
40893db446aSBoris Brezillon (NAND_CMD_STATUS << FCR_CMD1_SHIFT) |
40993db446aSBoris Brezillon (NAND_CMD_ERASE2 << FCR_CMD2_SHIFT));
41093db446aSBoris Brezillon
41193db446aSBoris Brezillon out_be32(&lbc->fbcr, 0);
41293db446aSBoris Brezillon elbc_fcm_ctrl->read_bytes = 0;
41393db446aSBoris Brezillon elbc_fcm_ctrl->use_mdr = 1;
41493db446aSBoris Brezillon
41593db446aSBoris Brezillon fsl_elbc_run_command(mtd);
41693db446aSBoris Brezillon return;
41793db446aSBoris Brezillon
41893db446aSBoris Brezillon /* SEQIN sets up the addr buffer and all registers except the length */
41993db446aSBoris Brezillon case NAND_CMD_SEQIN: {
42093db446aSBoris Brezillon __be32 fcr;
42193db446aSBoris Brezillon dev_vdbg(priv->dev,
42293db446aSBoris Brezillon "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, "
42393db446aSBoris Brezillon "page_addr: 0x%x, column: 0x%x.\n",
42493db446aSBoris Brezillon page_addr, column);
42593db446aSBoris Brezillon
42693db446aSBoris Brezillon elbc_fcm_ctrl->column = column;
42793db446aSBoris Brezillon elbc_fcm_ctrl->use_mdr = 1;
42893db446aSBoris Brezillon
42993db446aSBoris Brezillon if (column >= mtd->writesize) {
43093db446aSBoris Brezillon /* OOB area */
43193db446aSBoris Brezillon column -= mtd->writesize;
43293db446aSBoris Brezillon elbc_fcm_ctrl->oob = 1;
43393db446aSBoris Brezillon } else {
43493db446aSBoris Brezillon WARN_ON(column != 0);
43593db446aSBoris Brezillon elbc_fcm_ctrl->oob = 0;
43693db446aSBoris Brezillon }
43793db446aSBoris Brezillon
43893db446aSBoris Brezillon fcr = (NAND_CMD_STATUS << FCR_CMD1_SHIFT) |
43993db446aSBoris Brezillon (NAND_CMD_SEQIN << FCR_CMD2_SHIFT) |
44093db446aSBoris Brezillon (NAND_CMD_PAGEPROG << FCR_CMD3_SHIFT);
44193db446aSBoris Brezillon
44293db446aSBoris Brezillon if (priv->page_size) {
44393db446aSBoris Brezillon out_be32(&lbc->fir,
44493db446aSBoris Brezillon (FIR_OP_CM2 << FIR_OP0_SHIFT) |
44593db446aSBoris Brezillon (FIR_OP_CA << FIR_OP1_SHIFT) |
44693db446aSBoris Brezillon (FIR_OP_PA << FIR_OP2_SHIFT) |
44793db446aSBoris Brezillon (FIR_OP_WB << FIR_OP3_SHIFT) |
44893db446aSBoris Brezillon (FIR_OP_CM3 << FIR_OP4_SHIFT) |
44993db446aSBoris Brezillon (FIR_OP_CW1 << FIR_OP5_SHIFT) |
45093db446aSBoris Brezillon (FIR_OP_RS << FIR_OP6_SHIFT));
45193db446aSBoris Brezillon } else {
45293db446aSBoris Brezillon out_be32(&lbc->fir,
45393db446aSBoris Brezillon (FIR_OP_CM0 << FIR_OP0_SHIFT) |
45493db446aSBoris Brezillon (FIR_OP_CM2 << FIR_OP1_SHIFT) |
45593db446aSBoris Brezillon (FIR_OP_CA << FIR_OP2_SHIFT) |
45693db446aSBoris Brezillon (FIR_OP_PA << FIR_OP3_SHIFT) |
45793db446aSBoris Brezillon (FIR_OP_WB << FIR_OP4_SHIFT) |
45893db446aSBoris Brezillon (FIR_OP_CM3 << FIR_OP5_SHIFT) |
45993db446aSBoris Brezillon (FIR_OP_CW1 << FIR_OP6_SHIFT) |
46093db446aSBoris Brezillon (FIR_OP_RS << FIR_OP7_SHIFT));
46193db446aSBoris Brezillon
46293db446aSBoris Brezillon if (elbc_fcm_ctrl->oob)
46393db446aSBoris Brezillon /* OOB area --> READOOB */
46493db446aSBoris Brezillon fcr |= NAND_CMD_READOOB << FCR_CMD0_SHIFT;
46593db446aSBoris Brezillon else
46693db446aSBoris Brezillon /* First 256 bytes --> READ0 */
46793db446aSBoris Brezillon fcr |= NAND_CMD_READ0 << FCR_CMD0_SHIFT;
46893db446aSBoris Brezillon }
46993db446aSBoris Brezillon
47093db446aSBoris Brezillon out_be32(&lbc->fcr, fcr);
47193db446aSBoris Brezillon set_addr(mtd, column, page_addr, elbc_fcm_ctrl->oob);
47293db446aSBoris Brezillon return;
47393db446aSBoris Brezillon }
47493db446aSBoris Brezillon
47593db446aSBoris Brezillon /* PAGEPROG reuses all of the setup from SEQIN and adds the length */
47693db446aSBoris Brezillon case NAND_CMD_PAGEPROG: {
47793db446aSBoris Brezillon dev_vdbg(priv->dev,
47893db446aSBoris Brezillon "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG "
47993db446aSBoris Brezillon "writing %d bytes.\n", elbc_fcm_ctrl->index);
48093db446aSBoris Brezillon
48193db446aSBoris Brezillon /* if the write did not start at 0 or is not a full page
48293db446aSBoris Brezillon * then set the exact length, otherwise use a full page
48393db446aSBoris Brezillon * write so the HW generates the ECC.
48493db446aSBoris Brezillon */
48593db446aSBoris Brezillon if (elbc_fcm_ctrl->oob || elbc_fcm_ctrl->column != 0 ||
48693db446aSBoris Brezillon elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize)
48793db446aSBoris Brezillon out_be32(&lbc->fbcr,
48893db446aSBoris Brezillon elbc_fcm_ctrl->index - elbc_fcm_ctrl->column);
48993db446aSBoris Brezillon else
49093db446aSBoris Brezillon out_be32(&lbc->fbcr, 0);
49193db446aSBoris Brezillon
49293db446aSBoris Brezillon fsl_elbc_run_command(mtd);
49393db446aSBoris Brezillon return;
49493db446aSBoris Brezillon }
49593db446aSBoris Brezillon
49693db446aSBoris Brezillon /* CMD_STATUS must read the status byte while CEB is active */
49793db446aSBoris Brezillon /* Note - it does not wait for the ready line */
49893db446aSBoris Brezillon case NAND_CMD_STATUS:
49993db446aSBoris Brezillon out_be32(&lbc->fir,
50093db446aSBoris Brezillon (FIR_OP_CM0 << FIR_OP0_SHIFT) |
50193db446aSBoris Brezillon (FIR_OP_RBW << FIR_OP1_SHIFT));
50293db446aSBoris Brezillon out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT);
50393db446aSBoris Brezillon out_be32(&lbc->fbcr, 1);
50493db446aSBoris Brezillon set_addr(mtd, 0, 0, 0);
50593db446aSBoris Brezillon elbc_fcm_ctrl->read_bytes = 1;
50693db446aSBoris Brezillon
50793db446aSBoris Brezillon fsl_elbc_run_command(mtd);
50893db446aSBoris Brezillon
50993db446aSBoris Brezillon /* The chip always seems to report that it is
51093db446aSBoris Brezillon * write-protected, even when it is not.
51193db446aSBoris Brezillon */
51293db446aSBoris Brezillon setbits8(elbc_fcm_ctrl->addr, NAND_STATUS_WP);
51393db446aSBoris Brezillon return;
51493db446aSBoris Brezillon
51593db446aSBoris Brezillon /* RESET without waiting for the ready line */
51693db446aSBoris Brezillon case NAND_CMD_RESET:
51793db446aSBoris Brezillon dev_dbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n");
51893db446aSBoris Brezillon out_be32(&lbc->fir, FIR_OP_CM0 << FIR_OP0_SHIFT);
51993db446aSBoris Brezillon out_be32(&lbc->fcr, NAND_CMD_RESET << FCR_CMD0_SHIFT);
52093db446aSBoris Brezillon fsl_elbc_run_command(mtd);
52193db446aSBoris Brezillon return;
52293db446aSBoris Brezillon
52393db446aSBoris Brezillon default:
52493db446aSBoris Brezillon dev_err(priv->dev,
52593db446aSBoris Brezillon "fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n",
52693db446aSBoris Brezillon command);
52793db446aSBoris Brezillon }
52893db446aSBoris Brezillon }
52993db446aSBoris Brezillon
fsl_elbc_select_chip(struct nand_chip * chip,int cs)530758b56f5SBoris Brezillon static void fsl_elbc_select_chip(struct nand_chip *chip, int cs)
53193db446aSBoris Brezillon {
53293db446aSBoris Brezillon /* The hardware does not seem to support multiple
53393db446aSBoris Brezillon * chips per bank.
53493db446aSBoris Brezillon */
53593db446aSBoris Brezillon }
53693db446aSBoris Brezillon
53793db446aSBoris Brezillon /*
53893db446aSBoris Brezillon * Write buf to the FCM Controller Data Buffer
53993db446aSBoris Brezillon */
fsl_elbc_write_buf(struct nand_chip * chip,const u8 * buf,int len)540c0739d85SBoris Brezillon static void fsl_elbc_write_buf(struct nand_chip *chip, const u8 *buf, int len)
54193db446aSBoris Brezillon {
542c0739d85SBoris Brezillon struct mtd_info *mtd = nand_to_mtd(chip);
54393db446aSBoris Brezillon struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
54493db446aSBoris Brezillon struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
54593db446aSBoris Brezillon unsigned int bufsize = mtd->writesize + mtd->oobsize;
54693db446aSBoris Brezillon
54793db446aSBoris Brezillon if (len <= 0) {
54893db446aSBoris Brezillon dev_err(priv->dev, "write_buf of %d bytes", len);
54993db446aSBoris Brezillon elbc_fcm_ctrl->status = 0;
55093db446aSBoris Brezillon return;
55193db446aSBoris Brezillon }
55293db446aSBoris Brezillon
55393db446aSBoris Brezillon if ((unsigned int)len > bufsize - elbc_fcm_ctrl->index) {
55493db446aSBoris Brezillon dev_err(priv->dev,
55593db446aSBoris Brezillon "write_buf beyond end of buffer "
55693db446aSBoris Brezillon "(%d requested, %u available)\n",
55793db446aSBoris Brezillon len, bufsize - elbc_fcm_ctrl->index);
55893db446aSBoris Brezillon len = bufsize - elbc_fcm_ctrl->index;
55993db446aSBoris Brezillon }
56093db446aSBoris Brezillon
56193db446aSBoris Brezillon memcpy_toio(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], buf, len);
56293db446aSBoris Brezillon /*
56393db446aSBoris Brezillon * This is workaround for the weird elbc hangs during nand write,
56493db446aSBoris Brezillon * Scott Wood says: "...perhaps difference in how long it takes a
56593db446aSBoris Brezillon * write to make it through the localbus compared to a write to IMMR
56693db446aSBoris Brezillon * is causing problems, and sync isn't helping for some reason."
56793db446aSBoris Brezillon * Reading back the last byte helps though.
56893db446aSBoris Brezillon */
56993db446aSBoris Brezillon in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index] + len - 1);
57093db446aSBoris Brezillon
57193db446aSBoris Brezillon elbc_fcm_ctrl->index += len;
57293db446aSBoris Brezillon }
57393db446aSBoris Brezillon
57493db446aSBoris Brezillon /*
57593db446aSBoris Brezillon * read a byte from either the FCM hardware buffer if it has any data left
57693db446aSBoris Brezillon * otherwise issue a command to read a single byte.
57793db446aSBoris Brezillon */
fsl_elbc_read_byte(struct nand_chip * chip)5787e534323SBoris Brezillon static u8 fsl_elbc_read_byte(struct nand_chip *chip)
57993db446aSBoris Brezillon {
58093db446aSBoris Brezillon struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
58193db446aSBoris Brezillon struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
58293db446aSBoris Brezillon
58393db446aSBoris Brezillon /* If there are still bytes in the FCM, then use the next byte. */
58493db446aSBoris Brezillon if (elbc_fcm_ctrl->index < elbc_fcm_ctrl->read_bytes)
58593db446aSBoris Brezillon return in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index++]);
58693db446aSBoris Brezillon
58793db446aSBoris Brezillon dev_err(priv->dev, "read_byte beyond end of buffer\n");
58893db446aSBoris Brezillon return ERR_BYTE;
58993db446aSBoris Brezillon }
59093db446aSBoris Brezillon
59193db446aSBoris Brezillon /*
59293db446aSBoris Brezillon * Read from the FCM Controller Data Buffer
59393db446aSBoris Brezillon */
fsl_elbc_read_buf(struct nand_chip * chip,u8 * buf,int len)5947e534323SBoris Brezillon static void fsl_elbc_read_buf(struct nand_chip *chip, u8 *buf, int len)
59593db446aSBoris Brezillon {
59693db446aSBoris Brezillon struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
59793db446aSBoris Brezillon struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
59893db446aSBoris Brezillon int avail;
59993db446aSBoris Brezillon
60093db446aSBoris Brezillon if (len < 0)
60193db446aSBoris Brezillon return;
60293db446aSBoris Brezillon
60393db446aSBoris Brezillon avail = min((unsigned int)len,
60493db446aSBoris Brezillon elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index);
60593db446aSBoris Brezillon memcpy_fromio(buf, &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], avail);
60693db446aSBoris Brezillon elbc_fcm_ctrl->index += avail;
60793db446aSBoris Brezillon
60893db446aSBoris Brezillon if (len > avail)
60993db446aSBoris Brezillon dev_err(priv->dev,
61093db446aSBoris Brezillon "read_buf beyond end of buffer "
61193db446aSBoris Brezillon "(%d requested, %d available)\n",
61293db446aSBoris Brezillon len, avail);
61393db446aSBoris Brezillon }
61493db446aSBoris Brezillon
61593db446aSBoris Brezillon /* This function is called after Program and Erase Operations to
61693db446aSBoris Brezillon * check for success or failure.
61793db446aSBoris Brezillon */
fsl_elbc_wait(struct nand_chip * chip)618f1d46942SBoris Brezillon static int fsl_elbc_wait(struct nand_chip *chip)
61993db446aSBoris Brezillon {
62093db446aSBoris Brezillon struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
62193db446aSBoris Brezillon struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
62293db446aSBoris Brezillon
62393db446aSBoris Brezillon if (elbc_fcm_ctrl->status != LTESR_CC)
62493db446aSBoris Brezillon return NAND_STATUS_FAIL;
62593db446aSBoris Brezillon
62693db446aSBoris Brezillon /* The chip always seems to report that it is
62793db446aSBoris Brezillon * write-protected, even when it is not.
62893db446aSBoris Brezillon */
62993db446aSBoris Brezillon return (elbc_fcm_ctrl->mdr & 0xff) | NAND_STATUS_WP;
63093db446aSBoris Brezillon }
63193db446aSBoris Brezillon
fsl_elbc_read_page(struct nand_chip * chip,uint8_t * buf,int oob_required,int page)632b9761687SBoris Brezillon static int fsl_elbc_read_page(struct nand_chip *chip, uint8_t *buf,
633b9761687SBoris Brezillon int oob_required, int page)
63493db446aSBoris Brezillon {
635b9761687SBoris Brezillon struct mtd_info *mtd = nand_to_mtd(chip);
63693db446aSBoris Brezillon struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
63793db446aSBoris Brezillon struct fsl_lbc_ctrl *ctrl = priv->ctrl;
63893db446aSBoris Brezillon struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
63993db446aSBoris Brezillon
64093db446aSBoris Brezillon nand_read_page_op(chip, page, 0, buf, mtd->writesize);
64193db446aSBoris Brezillon if (oob_required)
6427e534323SBoris Brezillon fsl_elbc_read_buf(chip, chip->oob_poi, mtd->oobsize);
64393db446aSBoris Brezillon
644f1d46942SBoris Brezillon if (fsl_elbc_wait(chip) & NAND_STATUS_FAIL)
64593db446aSBoris Brezillon mtd->ecc_stats.failed++;
64693db446aSBoris Brezillon
64793db446aSBoris Brezillon return elbc_fcm_ctrl->max_bitflips;
64893db446aSBoris Brezillon }
64993db446aSBoris Brezillon
65093db446aSBoris Brezillon /* ECC will be calculated automatically, and errors will be detected in
65193db446aSBoris Brezillon * waitfunc.
65293db446aSBoris Brezillon */
fsl_elbc_write_page(struct nand_chip * chip,const uint8_t * buf,int oob_required,int page)653767eb6fbSBoris Brezillon static int fsl_elbc_write_page(struct nand_chip *chip, const uint8_t *buf,
654767eb6fbSBoris Brezillon int oob_required, int page)
65593db446aSBoris Brezillon {
656767eb6fbSBoris Brezillon struct mtd_info *mtd = nand_to_mtd(chip);
657767eb6fbSBoris Brezillon
65893db446aSBoris Brezillon nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
659c0739d85SBoris Brezillon fsl_elbc_write_buf(chip, chip->oob_poi, mtd->oobsize);
66093db446aSBoris Brezillon
66193db446aSBoris Brezillon return nand_prog_page_end_op(chip);
66293db446aSBoris Brezillon }
66393db446aSBoris Brezillon
66493db446aSBoris Brezillon /* ECC will be calculated automatically, and errors will be detected in
66593db446aSBoris Brezillon * waitfunc.
66693db446aSBoris Brezillon */
fsl_elbc_write_subpage(struct nand_chip * chip,uint32_t offset,uint32_t data_len,const uint8_t * buf,int oob_required,int page)667767eb6fbSBoris Brezillon static int fsl_elbc_write_subpage(struct nand_chip *chip, uint32_t offset,
668767eb6fbSBoris Brezillon uint32_t data_len, const uint8_t *buf,
669767eb6fbSBoris Brezillon int oob_required, int page)
67093db446aSBoris Brezillon {
671767eb6fbSBoris Brezillon struct mtd_info *mtd = nand_to_mtd(chip);
672767eb6fbSBoris Brezillon
67393db446aSBoris Brezillon nand_prog_page_begin_op(chip, page, 0, NULL, 0);
674c0739d85SBoris Brezillon fsl_elbc_write_buf(chip, buf, mtd->writesize);
675c0739d85SBoris Brezillon fsl_elbc_write_buf(chip, chip->oob_poi, mtd->oobsize);
67693db446aSBoris Brezillon return nand_prog_page_end_op(chip);
67793db446aSBoris Brezillon }
67893db446aSBoris Brezillon
fsl_elbc_chip_init(struct fsl_elbc_mtd * priv)67993db446aSBoris Brezillon static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
68093db446aSBoris Brezillon {
68193db446aSBoris Brezillon struct fsl_lbc_ctrl *ctrl = priv->ctrl;
68293db446aSBoris Brezillon struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
68393db446aSBoris Brezillon struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
68493db446aSBoris Brezillon struct nand_chip *chip = &priv->chip;
68593db446aSBoris Brezillon struct mtd_info *mtd = nand_to_mtd(chip);
68693db446aSBoris Brezillon
68793db446aSBoris Brezillon dev_dbg(priv->dev, "eLBC Set Information for bank %d\n", priv->bank);
68893db446aSBoris Brezillon
68993db446aSBoris Brezillon /* Fill in fsl_elbc_mtd structure */
69093db446aSBoris Brezillon mtd->dev.parent = priv->dev;
69193db446aSBoris Brezillon nand_set_flash_node(chip, priv->dev->of_node);
69293db446aSBoris Brezillon
69393db446aSBoris Brezillon /* set timeout to maximum */
69493db446aSBoris Brezillon priv->fmr = 15 << FMR_CWTO_SHIFT;
69593db446aSBoris Brezillon if (in_be32(&lbc->bank[priv->bank].or) & OR_FCM_PGS)
69693db446aSBoris Brezillon priv->fmr |= FMR_ECCM;
69793db446aSBoris Brezillon
69893db446aSBoris Brezillon /* fill in nand_chip structure */
69993db446aSBoris Brezillon /* set up function call table */
700716bbbabSBoris Brezillon chip->legacy.read_byte = fsl_elbc_read_byte;
701716bbbabSBoris Brezillon chip->legacy.write_buf = fsl_elbc_write_buf;
702716bbbabSBoris Brezillon chip->legacy.read_buf = fsl_elbc_read_buf;
7037d6c37e9SBoris Brezillon chip->legacy.select_chip = fsl_elbc_select_chip;
704bf6065c6SBoris Brezillon chip->legacy.cmdfunc = fsl_elbc_cmdfunc;
7058395b753SBoris Brezillon chip->legacy.waitfunc = fsl_elbc_wait;
70645240367SBoris Brezillon chip->legacy.set_features = nand_get_set_features_notsupp;
70745240367SBoris Brezillon chip->legacy.get_features = nand_get_set_features_notsupp;
70893db446aSBoris Brezillon
70993db446aSBoris Brezillon chip->bbt_td = &bbt_main_descr;
71093db446aSBoris Brezillon chip->bbt_md = &bbt_mirror_descr;
71193db446aSBoris Brezillon
71293db446aSBoris Brezillon /* set up nand options */
71393db446aSBoris Brezillon chip->bbt_options = NAND_BBT_USE_FLASH;
71493db446aSBoris Brezillon
71593db446aSBoris Brezillon chip->controller = &elbc_fcm_ctrl->controller;
71693db446aSBoris Brezillon nand_set_controller_data(chip, priv);
71793db446aSBoris Brezillon
71893db446aSBoris Brezillon return 0;
71993db446aSBoris Brezillon }
72093db446aSBoris Brezillon
fsl_elbc_attach_chip(struct nand_chip * chip)7219fed3115SMarek Behún static int fsl_elbc_attach_chip(struct nand_chip *chip)
7229fed3115SMarek Behún {
7239fed3115SMarek Behún struct mtd_info *mtd = nand_to_mtd(chip);
7249fed3115SMarek Behún struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
7259fed3115SMarek Behún struct fsl_lbc_ctrl *ctrl = priv->ctrl;
7269fed3115SMarek Behún struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
7279fed3115SMarek Behún unsigned int al;
728b5626525SPali Rohár u32 br;
7299fed3115SMarek Behún
730f6424c22SMarek Behún /*
731f6424c22SMarek Behún * if ECC was not chosen in DT, decide whether to use HW or SW ECC from
732f6424c22SMarek Behún * CS Base Register
733f6424c22SMarek Behún */
734049e43b9SPali Rohár if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_INVALID) {
735f6424c22SMarek Behún /* If CS Base Register selects full hardware ECC then use it */
736f6424c22SMarek Behún if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
737f6424c22SMarek Behún BR_DECC_CHK_GEN) {
738bace41f8SMiquel Raynal chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
739f6424c22SMarek Behún } else {
740f6424c22SMarek Behún /* otherwise fall back to default software ECC */
741bace41f8SMiquel Raynal chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
742e0a564aeSMiquel Raynal chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
743f6424c22SMarek Behún }
744049e43b9SPali Rohár }
745049e43b9SPali Rohár
746049e43b9SPali Rohár switch (chip->ecc.engine_type) {
747049e43b9SPali Rohár /* if HW ECC was chosen, setup ecc and oob layout */
748049e43b9SPali Rohár case NAND_ECC_ENGINE_TYPE_ON_HOST:
749049e43b9SPali Rohár chip->ecc.read_page = fsl_elbc_read_page;
750049e43b9SPali Rohár chip->ecc.write_page = fsl_elbc_write_page;
751049e43b9SPali Rohár chip->ecc.write_subpage = fsl_elbc_write_subpage;
752049e43b9SPali Rohár mtd_set_ooblayout(mtd, &fsl_elbc_ooblayout_ops);
753049e43b9SPali Rohár chip->ecc.size = 512;
754049e43b9SPali Rohár chip->ecc.bytes = 3;
755049e43b9SPali Rohár chip->ecc.strength = 1;
756f6424c22SMarek Behún break;
757f6424c22SMarek Behún
758049e43b9SPali Rohár /* if none or SW ECC was chosen, we do not need to set anything here */
759049e43b9SPali Rohár case NAND_ECC_ENGINE_TYPE_NONE:
760bace41f8SMiquel Raynal case NAND_ECC_ENGINE_TYPE_SOFT:
761049e43b9SPali Rohár case NAND_ECC_ENGINE_TYPE_ON_DIE:
762f6424c22SMarek Behún break;
763f6424c22SMarek Behún
764f6424c22SMarek Behún default:
765f6424c22SMarek Behún return -EINVAL;
766f6424c22SMarek Behún }
767f6424c22SMarek Behún
768b5626525SPali Rohár /* enable/disable HW ECC checking and generating based on if HW ECC was chosen */
769b5626525SPali Rohár br = in_be32(&lbc->bank[priv->bank].br) & ~BR_DECC;
770b5626525SPali Rohár if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST)
771b5626525SPali Rohár out_be32(&lbc->bank[priv->bank].br, br | BR_DECC_CHK_GEN);
772b5626525SPali Rohár else
773b5626525SPali Rohár out_be32(&lbc->bank[priv->bank].br, br | BR_DECC_OFF);
774b5626525SPali Rohár
7759fed3115SMarek Behún /* calculate FMR Address Length field */
7769fed3115SMarek Behún al = 0;
7779fed3115SMarek Behún if (chip->pagemask & 0xffff0000)
7789fed3115SMarek Behún al++;
7799fed3115SMarek Behún if (chip->pagemask & 0xff000000)
7809fed3115SMarek Behún al++;
7819fed3115SMarek Behún
7829fed3115SMarek Behún priv->fmr |= al << FMR_AL_SHIFT;
7839fed3115SMarek Behún
7849fed3115SMarek Behún dev_dbg(priv->dev, "fsl_elbc_init: nand->numchips = %d\n",
7859fed3115SMarek Behún nanddev_ntargets(&chip->base));
7869fed3115SMarek Behún dev_dbg(priv->dev, "fsl_elbc_init: nand->chipsize = %lld\n",
7879fed3115SMarek Behún nanddev_target_size(&chip->base));
7889fed3115SMarek Behún dev_dbg(priv->dev, "fsl_elbc_init: nand->pagemask = %8x\n",
7899fed3115SMarek Behún chip->pagemask);
7909fed3115SMarek Behún dev_dbg(priv->dev, "fsl_elbc_init: nand->legacy.chip_delay = %d\n",
7919fed3115SMarek Behún chip->legacy.chip_delay);
7929fed3115SMarek Behún dev_dbg(priv->dev, "fsl_elbc_init: nand->badblockpos = %d\n",
7939fed3115SMarek Behún chip->badblockpos);
7949fed3115SMarek Behún dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_shift = %d\n",
7959fed3115SMarek Behún chip->chip_shift);
7969fed3115SMarek Behún dev_dbg(priv->dev, "fsl_elbc_init: nand->page_shift = %d\n",
7979fed3115SMarek Behún chip->page_shift);
7989fed3115SMarek Behún dev_dbg(priv->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n",
7999fed3115SMarek Behún chip->phys_erase_shift);
800bace41f8SMiquel Raynal dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.engine_type = %d\n",
801bace41f8SMiquel Raynal chip->ecc.engine_type);
8029fed3115SMarek Behún dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.steps = %d\n",
8039fed3115SMarek Behún chip->ecc.steps);
8049fed3115SMarek Behún dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n",
8059fed3115SMarek Behún chip->ecc.bytes);
8069fed3115SMarek Behún dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.total = %d\n",
8079fed3115SMarek Behún chip->ecc.total);
8089fed3115SMarek Behún dev_dbg(priv->dev, "fsl_elbc_init: mtd->ooblayout = %p\n",
8099fed3115SMarek Behún mtd->ooblayout);
8109fed3115SMarek Behún dev_dbg(priv->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags);
8119fed3115SMarek Behún dev_dbg(priv->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size);
8129fed3115SMarek Behún dev_dbg(priv->dev, "fsl_elbc_init: mtd->erasesize = %d\n",
8139fed3115SMarek Behún mtd->erasesize);
8149fed3115SMarek Behún dev_dbg(priv->dev, "fsl_elbc_init: mtd->writesize = %d\n",
8159fed3115SMarek Behún mtd->writesize);
8169fed3115SMarek Behún dev_dbg(priv->dev, "fsl_elbc_init: mtd->oobsize = %d\n",
8179fed3115SMarek Behún mtd->oobsize);
8189fed3115SMarek Behún
8199fed3115SMarek Behún /* adjust Option Register and ECC to match Flash page size */
8209fed3115SMarek Behún if (mtd->writesize == 512) {
8219fed3115SMarek Behún priv->page_size = 0;
8229fed3115SMarek Behún clrbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
8239fed3115SMarek Behún } else if (mtd->writesize == 2048) {
8249fed3115SMarek Behún priv->page_size = 1;
8259fed3115SMarek Behún setbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
8269fed3115SMarek Behún } else {
8279fed3115SMarek Behún dev_err(priv->dev,
8289fed3115SMarek Behún "fsl_elbc_init: page size %d is not supported\n",
8299fed3115SMarek Behún mtd->writesize);
8309fed3115SMarek Behún return -ENOTSUPP;
8319fed3115SMarek Behún }
8329fed3115SMarek Behún
8339fed3115SMarek Behún return 0;
8349fed3115SMarek Behún }
8359fed3115SMarek Behún
8369fed3115SMarek Behún static const struct nand_controller_ops fsl_elbc_controller_ops = {
8379fed3115SMarek Behún .attach_chip = fsl_elbc_attach_chip,
8389fed3115SMarek Behún };
8399fed3115SMarek Behún
fsl_elbc_chip_remove(struct fsl_elbc_mtd * priv)84093db446aSBoris Brezillon static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv)
84193db446aSBoris Brezillon {
84293db446aSBoris Brezillon struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
84393db446aSBoris Brezillon struct mtd_info *mtd = nand_to_mtd(&priv->chip);
84493db446aSBoris Brezillon
84593db446aSBoris Brezillon kfree(mtd->name);
84693db446aSBoris Brezillon
84793db446aSBoris Brezillon if (priv->vbase)
84893db446aSBoris Brezillon iounmap(priv->vbase);
84993db446aSBoris Brezillon
85093db446aSBoris Brezillon elbc_fcm_ctrl->chips[priv->bank] = NULL;
85193db446aSBoris Brezillon kfree(priv);
85293db446aSBoris Brezillon return 0;
85393db446aSBoris Brezillon }
85493db446aSBoris Brezillon
85593db446aSBoris Brezillon static DEFINE_MUTEX(fsl_elbc_nand_mutex);
85693db446aSBoris Brezillon
fsl_elbc_nand_probe(struct platform_device * pdev)85793db446aSBoris Brezillon static int fsl_elbc_nand_probe(struct platform_device *pdev)
85893db446aSBoris Brezillon {
85993db446aSBoris Brezillon struct fsl_lbc_regs __iomem *lbc;
86093db446aSBoris Brezillon struct fsl_elbc_mtd *priv;
86193db446aSBoris Brezillon struct resource res;
86293db446aSBoris Brezillon struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl;
86393db446aSBoris Brezillon static const char *part_probe_types[]
86493db446aSBoris Brezillon = { "cmdlinepart", "RedBoot", "ofpart", NULL };
86593db446aSBoris Brezillon int ret;
86693db446aSBoris Brezillon int bank;
86793db446aSBoris Brezillon struct device *dev;
86893db446aSBoris Brezillon struct device_node *node = pdev->dev.of_node;
86993db446aSBoris Brezillon struct mtd_info *mtd;
87093db446aSBoris Brezillon
87193db446aSBoris Brezillon if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
87293db446aSBoris Brezillon return -ENODEV;
87393db446aSBoris Brezillon lbc = fsl_lbc_ctrl_dev->regs;
87493db446aSBoris Brezillon dev = fsl_lbc_ctrl_dev->dev;
87593db446aSBoris Brezillon
87693db446aSBoris Brezillon /* get, allocate and map the memory resource */
87793db446aSBoris Brezillon ret = of_address_to_resource(node, 0, &res);
87893db446aSBoris Brezillon if (ret) {
87993db446aSBoris Brezillon dev_err(dev, "failed to get resource\n");
88093db446aSBoris Brezillon return ret;
88193db446aSBoris Brezillon }
88293db446aSBoris Brezillon
88393db446aSBoris Brezillon /* find which chip select it is connected to */
88493db446aSBoris Brezillon for (bank = 0; bank < MAX_BANKS; bank++)
88593db446aSBoris Brezillon if ((in_be32(&lbc->bank[bank].br) & BR_V) &&
88693db446aSBoris Brezillon (in_be32(&lbc->bank[bank].br) & BR_MSEL) == BR_MS_FCM &&
88793db446aSBoris Brezillon (in_be32(&lbc->bank[bank].br) &
88893db446aSBoris Brezillon in_be32(&lbc->bank[bank].or) & BR_BA)
88993db446aSBoris Brezillon == fsl_lbc_addr(res.start))
89093db446aSBoris Brezillon break;
89193db446aSBoris Brezillon
89293db446aSBoris Brezillon if (bank >= MAX_BANKS) {
89393db446aSBoris Brezillon dev_err(dev, "address did not match any chip selects\n");
89493db446aSBoris Brezillon return -ENODEV;
89593db446aSBoris Brezillon }
89693db446aSBoris Brezillon
89793db446aSBoris Brezillon priv = kzalloc(sizeof(*priv), GFP_KERNEL);
89893db446aSBoris Brezillon if (!priv)
89993db446aSBoris Brezillon return -ENOMEM;
90093db446aSBoris Brezillon
90193db446aSBoris Brezillon mutex_lock(&fsl_elbc_nand_mutex);
90293db446aSBoris Brezillon if (!fsl_lbc_ctrl_dev->nand) {
90393db446aSBoris Brezillon elbc_fcm_ctrl = kzalloc(sizeof(*elbc_fcm_ctrl), GFP_KERNEL);
90493db446aSBoris Brezillon if (!elbc_fcm_ctrl) {
90593db446aSBoris Brezillon mutex_unlock(&fsl_elbc_nand_mutex);
90693db446aSBoris Brezillon ret = -ENOMEM;
90793db446aSBoris Brezillon goto err;
90893db446aSBoris Brezillon }
90993db446aSBoris Brezillon elbc_fcm_ctrl->counter++;
91093db446aSBoris Brezillon
9117da45139SMiquel Raynal nand_controller_init(&elbc_fcm_ctrl->controller);
91293db446aSBoris Brezillon fsl_lbc_ctrl_dev->nand = elbc_fcm_ctrl;
91393db446aSBoris Brezillon } else {
91493db446aSBoris Brezillon elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
91593db446aSBoris Brezillon }
91693db446aSBoris Brezillon mutex_unlock(&fsl_elbc_nand_mutex);
91793db446aSBoris Brezillon
91893db446aSBoris Brezillon elbc_fcm_ctrl->chips[bank] = priv;
91993db446aSBoris Brezillon priv->bank = bank;
92093db446aSBoris Brezillon priv->ctrl = fsl_lbc_ctrl_dev;
92193db446aSBoris Brezillon priv->dev = &pdev->dev;
92293db446aSBoris Brezillon dev_set_drvdata(priv->dev, priv);
92393db446aSBoris Brezillon
92493db446aSBoris Brezillon priv->vbase = ioremap(res.start, resource_size(&res));
92593db446aSBoris Brezillon if (!priv->vbase) {
92693db446aSBoris Brezillon dev_err(dev, "failed to map chip region\n");
92793db446aSBoris Brezillon ret = -ENOMEM;
92893db446aSBoris Brezillon goto err;
92993db446aSBoris Brezillon }
93093db446aSBoris Brezillon
93193db446aSBoris Brezillon mtd = nand_to_mtd(&priv->chip);
93293db446aSBoris Brezillon mtd->name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start);
93393db446aSBoris Brezillon if (!nand_to_mtd(&priv->chip)->name) {
93493db446aSBoris Brezillon ret = -ENOMEM;
93593db446aSBoris Brezillon goto err;
93693db446aSBoris Brezillon }
93793db446aSBoris Brezillon
93893db446aSBoris Brezillon ret = fsl_elbc_chip_init(priv);
93993db446aSBoris Brezillon if (ret)
94093db446aSBoris Brezillon goto err;
94193db446aSBoris Brezillon
9425bf3e76bSMiquel Raynal priv->chip.controller->ops = &fsl_elbc_controller_ops;
94300ad378fSBoris Brezillon ret = nand_scan(&priv->chip, 1);
94493db446aSBoris Brezillon if (ret)
94593db446aSBoris Brezillon goto err;
94693db446aSBoris Brezillon
94793db446aSBoris Brezillon /* First look for RedBoot table or partitions on the command
94893db446aSBoris Brezillon * line, these take precedence over device tree information */
94939b77c58SMiquel Raynal ret = mtd_device_parse_register(mtd, part_probe_types, NULL, NULL, 0);
95039b77c58SMiquel Raynal if (ret)
95139b77c58SMiquel Raynal goto cleanup_nand;
95293db446aSBoris Brezillon
95363fa37f0SShreeya Patel pr_info("eLBC NAND device at 0x%llx, bank %d\n",
95493db446aSBoris Brezillon (unsigned long long)res.start, priv->bank);
95539b77c58SMiquel Raynal
95693db446aSBoris Brezillon return 0;
95793db446aSBoris Brezillon
95839b77c58SMiquel Raynal cleanup_nand:
95939b77c58SMiquel Raynal nand_cleanup(&priv->chip);
96093db446aSBoris Brezillon err:
96193db446aSBoris Brezillon fsl_elbc_chip_remove(priv);
96239b77c58SMiquel Raynal
96393db446aSBoris Brezillon return ret;
96493db446aSBoris Brezillon }
96593db446aSBoris Brezillon
fsl_elbc_nand_remove(struct platform_device * pdev)966*ec185b18SUwe Kleine-König static void fsl_elbc_nand_remove(struct platform_device *pdev)
96793db446aSBoris Brezillon {
96893db446aSBoris Brezillon struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
96993db446aSBoris Brezillon struct fsl_elbc_mtd *priv = dev_get_drvdata(&pdev->dev);
970128bbbf0SMiquel Raynal struct nand_chip *chip = &priv->chip;
971128bbbf0SMiquel Raynal int ret;
97293db446aSBoris Brezillon
973128bbbf0SMiquel Raynal ret = mtd_device_unregister(nand_to_mtd(chip));
974128bbbf0SMiquel Raynal WARN_ON(ret);
975128bbbf0SMiquel Raynal nand_cleanup(chip);
976128bbbf0SMiquel Raynal
97793db446aSBoris Brezillon fsl_elbc_chip_remove(priv);
97893db446aSBoris Brezillon
97993db446aSBoris Brezillon mutex_lock(&fsl_elbc_nand_mutex);
98093db446aSBoris Brezillon elbc_fcm_ctrl->counter--;
98193db446aSBoris Brezillon if (!elbc_fcm_ctrl->counter) {
98293db446aSBoris Brezillon fsl_lbc_ctrl_dev->nand = NULL;
98393db446aSBoris Brezillon kfree(elbc_fcm_ctrl);
98493db446aSBoris Brezillon }
98593db446aSBoris Brezillon mutex_unlock(&fsl_elbc_nand_mutex);
98693db446aSBoris Brezillon
98793db446aSBoris Brezillon }
98893db446aSBoris Brezillon
98993db446aSBoris Brezillon static const struct of_device_id fsl_elbc_nand_match[] = {
99093db446aSBoris Brezillon { .compatible = "fsl,elbc-fcm-nand", },
99193db446aSBoris Brezillon {}
99293db446aSBoris Brezillon };
99393db446aSBoris Brezillon MODULE_DEVICE_TABLE(of, fsl_elbc_nand_match);
99493db446aSBoris Brezillon
99593db446aSBoris Brezillon static struct platform_driver fsl_elbc_nand_driver = {
99693db446aSBoris Brezillon .driver = {
99793db446aSBoris Brezillon .name = "fsl,elbc-fcm-nand",
99893db446aSBoris Brezillon .of_match_table = fsl_elbc_nand_match,
99993db446aSBoris Brezillon },
100093db446aSBoris Brezillon .probe = fsl_elbc_nand_probe,
1001*ec185b18SUwe Kleine-König .remove_new = fsl_elbc_nand_remove,
100293db446aSBoris Brezillon };
100393db446aSBoris Brezillon
100493db446aSBoris Brezillon module_platform_driver(fsl_elbc_nand_driver);
100593db446aSBoris Brezillon
100693db446aSBoris Brezillon MODULE_LICENSE("GPL");
100793db446aSBoris Brezillon MODULE_AUTHOR("Freescale");
100893db446aSBoris Brezillon MODULE_DESCRIPTION("Freescale Enhanced Local Bus Controller MTD NAND driver");
1009