Exemplo n.º 1
0
static uint32_t mxs_nand_mark_bit_offset(struct mtd_info *mtd)
{
	uint32_t ecc_strength;
	ecc_strength = mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize);
	return mxs_nand_get_mark_offset(mtd->writesize, ecc_strength) & 0x7;
}
Exemplo n.º 2
0
/*
 * Nominally, the purpose of this function is to look for or create the bad
 * block table. In fact, since the we call this function at the very end of
 * the initialization process started by nand_scan(), and we don't have a
 * more formal mechanism, we "hook" this function to continue init process.
 *
 * At this point, the physical NAND Flash chips have been identified and
 * counted, so we know the physical geometry. This enables us to make some
 * important configuration decisions.
 *
 * The return value of this function propogates directly back to this driver's
 * call to nand_scan(). Anything other than zero will cause this driver to
 * tear everything down and declare failure.
 */
static int mxs_nand_scan_bbt(struct mtd_info *mtd)
{
	struct nand_chip *nand = mtd->priv;
	struct mxs_nand_info *nand_info = nand->priv;
	uint32_t tmp;

	/* Configure BCH and set NFC geometry */
	if (readl(&bch_regs->hw_bch_ctrl_reg) &
		(BCH_CTRL_SFTRST | BCH_CTRL_CLKGATE))
		/* When booting from NAND the BCH engine will already
		 * be operational and obviously does not like being reset here.
		 * There will be occasional read errors upon boot when this
		 * reset is done.
		 */
		mxs_reset_block(&bch_regs->hw_bch_ctrl_reg);
	readl(&bch_regs->hw_bch_ctrl_reg);

	debug("mtd->writesize=%d\n", mtd->writesize);
	debug("mtd->oobsize=%d\n", mtd->oobsize);
	debug("ecc_strength=%d\n", mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize));

	/* Configure layout 0 */
	tmp = (mxs_nand_ecc_chunk_cnt(mtd) - 1)
		<< BCH_FLASHLAYOUT0_NBLOCKS_OFFSET;
	tmp |= MXS_NAND_METADATA_SIZE << BCH_FLASHLAYOUT0_META_SIZE_OFFSET;
	tmp |= (mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize) >> 1)
		<< BCH_FLASHLAYOUT0_ECC0_OFFSET;
	tmp |= MXS_NAND_CHUNK_DATA_CHUNK_SIZE;
	writel(tmp, &bch_regs->hw_bch_flash0layout0);

	tmp = (mtd->writesize + mtd->oobsize)
		<< BCH_FLASHLAYOUT1_PAGE_SIZE_OFFSET;
	tmp |= (mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize) >> 1)
		<< BCH_FLASHLAYOUT1_ECCN_OFFSET;
	tmp |= MXS_NAND_CHUNK_DATA_CHUNK_SIZE;
	writel(tmp, &bch_regs->hw_bch_flash0layout1);

	/* Set *all* chip selects to use layout 0 */
	writel(0, &bch_regs->hw_bch_layoutselect);

	/* Enable BCH complete interrupt */
	writel(BCH_CTRL_COMPLETE_IRQ_EN, &bch_regs->hw_bch_ctrl_set);

	/* Hook some operations at the MTD level. */
	if (mtd->read_oob != mxs_nand_hook_read_oob) {
		nand_info->hooked_read_oob = mtd->read_oob;
		mtd->read_oob = mxs_nand_hook_read_oob;
	}

	if (mtd->write_oob != mxs_nand_hook_write_oob) {
		nand_info->hooked_write_oob = mtd->write_oob;
		mtd->write_oob = mxs_nand_hook_write_oob;
	}

	if (mtd->block_markbad != mxs_nand_hook_block_markbad) {
		nand_info->hooked_block_markbad = mtd->block_markbad;
		mtd->block_markbad = mxs_nand_hook_block_markbad;
	}

	/* We use the reference implementation for bad block management. */
	return nand_default_bbt(mtd);
}