drivers/mtd/nand/raw/fsl_elbc_nand.c

Source file repositories/reference/linux-study-clean/drivers/mtd/nand/raw/fsl_elbc_nand.c

File Facts

System
Linux kernel
Corpus path
drivers/mtd/nand/raw/fsl_elbc_nand.c
Extension
.c
Size
30289 bytes
Lines
1010
Domain
Driver Families
Bucket
drivers/mtd
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct fsl_elbc_mtd {
	struct nand_chip chip;
	struct fsl_lbc_ctrl *ctrl;

	struct device *dev;
	int bank;               /* Chip select bank number           */
	u8 __iomem *vbase;      /* Chip select base virtual address  */
	int page_size;          /* NAND page size (0=512, 1=2048)    */
	unsigned int fmr;       /* FCM Flash Mode Register value     */
};

/* Freescale eLBC FCM controller information */

struct fsl_elbc_fcm_ctrl {
	struct nand_controller controller;
	struct fsl_elbc_mtd *chips[MAX_BANKS];

	u8 __iomem *addr;        /* Address of assigned FCM buffer        */
	unsigned int page;       /* Last page written to / read from      */
	unsigned int read_bytes; /* Number of bytes read during command   */
	unsigned int column;     /* Saved column from SEQIN               */
	unsigned int index;      /* Pointer to next byte to 'read'        */
	unsigned int status;     /* status read from LTESR after last op  */
	unsigned int mdr;        /* UPM/FCM Data Register value           */
	unsigned int use_mdr;    /* Non zero if the MDR is to be set      */
	unsigned int oob;        /* Non zero if operating on OOB data     */
	unsigned int counter;	 /* counter for the initializations	  */
	unsigned int max_bitflips;  /* Saved during READ0 cmd		  */
};

/* These map to the positions used by the FCM hardware ECC generator */

static int fsl_elbc_ooblayout_ecc(struct mtd_info *mtd, int section,
				  struct mtd_oob_region *oobregion)
{
	struct nand_chip *chip = mtd_to_nand(mtd);
	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);

	if (section >= chip->ecc.steps)
		return -ERANGE;

	oobregion->offset = (16 * section) + 6;
	if (priv->fmr & FMR_ECCM)
		oobregion->offset += 2;

	oobregion->length = chip->ecc.bytes;

	return 0;
}

static int fsl_elbc_ooblayout_free(struct mtd_info *mtd, int section,
				   struct mtd_oob_region *oobregion)
{
	struct nand_chip *chip = mtd_to_nand(mtd);
	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);

	if (section > chip->ecc.steps)
		return -ERANGE;

	if (!section) {
		oobregion->offset = 0;
		if (mtd->writesize > 512)
			oobregion->offset++;
		oobregion->length = (priv->fmr & FMR_ECCM) ? 7 : 5;
	} else {
		oobregion->offset = (16 * section) -
				    ((priv->fmr & FMR_ECCM) ? 5 : 7);
		if (section < chip->ecc.steps)
			oobregion->length = 13;
		else
			oobregion->length = mtd->oobsize - oobregion->offset;
	}

	return 0;
}

static const struct mtd_ooblayout_ops fsl_elbc_ooblayout_ops = {
	.ecc = fsl_elbc_ooblayout_ecc,
	.free = fsl_elbc_ooblayout_free,
};

/*
 * 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' };

static struct nand_bbt_descr bbt_main_descr = {

Annotation

Implementation Notes