mtd: rawnand: omap2: convert driver to nand_scan()
Two helpers have been added to the core to do all kind of controller side configuration/initialization between the detection phase and the final NAND scan. Implement these hooks so that we can convert the driver to just use nand_scan() instead of the nand_scan_ident() + nand_scan_tail() pair. Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> Reviewed-by: Boris Brezillon <boris.brezillon@bootlin.com>
This commit is contained in:
parent
c49f3bee8c
commit
e1e6255c31
@ -144,12 +144,6 @@ static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc,
|
||||
0xac, 0x6b, 0xff, 0x99, 0x7b};
|
||||
static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10};
|
||||
|
||||
/* Shared among all NAND instances to synchronize access to the ECC Engine */
|
||||
static struct nand_controller omap_gpmc_controller = {
|
||||
.lock = __SPIN_LOCK_UNLOCKED(omap_gpmc_controller.lock),
|
||||
.wq = __WAIT_QUEUE_HEAD_INITIALIZER(omap_gpmc_controller.wq),
|
||||
};
|
||||
|
||||
struct omap_nand_info {
|
||||
struct nand_chip nand;
|
||||
struct platform_device *pdev;
|
||||
@ -1915,17 +1909,278 @@ static const struct mtd_ooblayout_ops omap_sw_ooblayout_ops = {
|
||||
.free = omap_sw_ooblayout_free,
|
||||
};
|
||||
|
||||
static int omap_nand_attach_chip(struct nand_chip *chip)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct omap_nand_info *info = mtd_to_omap(mtd);
|
||||
struct device *dev = &info->pdev->dev;
|
||||
int min_oobbytes = BADBLOCK_MARKER_LENGTH;
|
||||
int oobbytes_per_step;
|
||||
dma_cap_mask_t mask;
|
||||
int err;
|
||||
|
||||
if (chip->bbt_options & NAND_BBT_USE_FLASH)
|
||||
chip->bbt_options |= NAND_BBT_NO_OOB;
|
||||
else
|
||||
chip->options |= NAND_SKIP_BBTSCAN;
|
||||
|
||||
/* Re-populate low-level callbacks based on xfer modes */
|
||||
switch (info->xfer_type) {
|
||||
case NAND_OMAP_PREFETCH_POLLED:
|
||||
chip->read_buf = omap_read_buf_pref;
|
||||
chip->write_buf = omap_write_buf_pref;
|
||||
break;
|
||||
|
||||
case NAND_OMAP_POLLED:
|
||||
/* Use nand_base defaults for {read,write}_buf */
|
||||
break;
|
||||
|
||||
case NAND_OMAP_PREFETCH_DMA:
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
info->dma = dma_request_chan(dev, "rxtx");
|
||||
|
||||
if (IS_ERR(info->dma)) {
|
||||
dev_err(dev, "DMA engine request failed\n");
|
||||
return PTR_ERR(info->dma);
|
||||
} else {
|
||||
struct dma_slave_config cfg;
|
||||
|
||||
memset(&cfg, 0, sizeof(cfg));
|
||||
cfg.src_addr = info->phys_base;
|
||||
cfg.dst_addr = info->phys_base;
|
||||
cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
cfg.src_maxburst = 16;
|
||||
cfg.dst_maxburst = 16;
|
||||
err = dmaengine_slave_config(info->dma, &cfg);
|
||||
if (err) {
|
||||
dev_err(dev,
|
||||
"DMA engine slave config failed: %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
chip->read_buf = omap_read_buf_dma_pref;
|
||||
chip->write_buf = omap_write_buf_dma_pref;
|
||||
}
|
||||
break;
|
||||
|
||||
case NAND_OMAP_PREFETCH_IRQ:
|
||||
info->gpmc_irq_fifo = platform_get_irq(info->pdev, 0);
|
||||
if (info->gpmc_irq_fifo <= 0) {
|
||||
dev_err(dev, "Error getting fifo IRQ\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
err = devm_request_irq(dev, info->gpmc_irq_fifo,
|
||||
omap_nand_irq, IRQF_SHARED,
|
||||
"gpmc-nand-fifo", info);
|
||||
if (err) {
|
||||
dev_err(dev, "Requesting IRQ %d, error %d\n",
|
||||
info->gpmc_irq_fifo, err);
|
||||
info->gpmc_irq_fifo = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
info->gpmc_irq_count = platform_get_irq(info->pdev, 1);
|
||||
if (info->gpmc_irq_count <= 0) {
|
||||
dev_err(dev, "Error getting IRQ count\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
err = devm_request_irq(dev, info->gpmc_irq_count,
|
||||
omap_nand_irq, IRQF_SHARED,
|
||||
"gpmc-nand-count", info);
|
||||
if (err) {
|
||||
dev_err(dev, "Requesting IRQ %d, error %d\n",
|
||||
info->gpmc_irq_count, err);
|
||||
info->gpmc_irq_count = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
chip->read_buf = omap_read_buf_irq_pref;
|
||||
chip->write_buf = omap_write_buf_irq_pref;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(dev, "xfer_type %d not supported!\n", info->xfer_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!omap2_nand_ecc_check(info))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Bail out earlier to let NAND_ECC_SOFT code create its own
|
||||
* ooblayout instead of using ours.
|
||||
*/
|
||||
if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW) {
|
||||
chip->ecc.mode = NAND_ECC_SOFT;
|
||||
chip->ecc.algo = NAND_ECC_HAMMING;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Populate MTD interface based on ECC scheme */
|
||||
switch (info->ecc_opt) {
|
||||
case OMAP_ECC_HAM1_CODE_HW:
|
||||
dev_info(dev, "nand: using OMAP_ECC_HAM1_CODE_HW\n");
|
||||
chip->ecc.mode = NAND_ECC_HW;
|
||||
chip->ecc.bytes = 3;
|
||||
chip->ecc.size = 512;
|
||||
chip->ecc.strength = 1;
|
||||
chip->ecc.calculate = omap_calculate_ecc;
|
||||
chip->ecc.hwctl = omap_enable_hwecc;
|
||||
chip->ecc.correct = omap_correct_data;
|
||||
mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
|
||||
oobbytes_per_step = chip->ecc.bytes;
|
||||
|
||||
if (!(chip->options & NAND_BUSWIDTH_16))
|
||||
min_oobbytes = 1;
|
||||
|
||||
break;
|
||||
|
||||
case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
|
||||
pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n");
|
||||
chip->ecc.mode = NAND_ECC_HW;
|
||||
chip->ecc.size = 512;
|
||||
chip->ecc.bytes = 7;
|
||||
chip->ecc.strength = 4;
|
||||
chip->ecc.hwctl = omap_enable_hwecc_bch;
|
||||
chip->ecc.correct = nand_bch_correct_data;
|
||||
chip->ecc.calculate = omap_calculate_ecc_bch_sw;
|
||||
mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
|
||||
/* Reserve one byte for the OMAP marker */
|
||||
oobbytes_per_step = chip->ecc.bytes + 1;
|
||||
/* Software BCH library is used for locating errors */
|
||||
chip->ecc.priv = nand_bch_init(mtd);
|
||||
if (!chip->ecc.priv) {
|
||||
dev_err(dev, "Unable to use BCH library\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
case OMAP_ECC_BCH4_CODE_HW:
|
||||
pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n");
|
||||
chip->ecc.mode = NAND_ECC_HW;
|
||||
chip->ecc.size = 512;
|
||||
/* 14th bit is kept reserved for ROM-code compatibility */
|
||||
chip->ecc.bytes = 7 + 1;
|
||||
chip->ecc.strength = 4;
|
||||
chip->ecc.hwctl = omap_enable_hwecc_bch;
|
||||
chip->ecc.correct = omap_elm_correct_data;
|
||||
chip->ecc.read_page = omap_read_page_bch;
|
||||
chip->ecc.write_page = omap_write_page_bch;
|
||||
chip->ecc.write_subpage = omap_write_subpage_bch;
|
||||
mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
|
||||
oobbytes_per_step = chip->ecc.bytes;
|
||||
|
||||
err = elm_config(info->elm_dev, BCH4_ECC,
|
||||
mtd->writesize / chip->ecc.size,
|
||||
chip->ecc.size, chip->ecc.bytes);
|
||||
if (err < 0)
|
||||
return err;
|
||||
break;
|
||||
|
||||
case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
|
||||
pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
|
||||
chip->ecc.mode = NAND_ECC_HW;
|
||||
chip->ecc.size = 512;
|
||||
chip->ecc.bytes = 13;
|
||||
chip->ecc.strength = 8;
|
||||
chip->ecc.hwctl = omap_enable_hwecc_bch;
|
||||
chip->ecc.correct = nand_bch_correct_data;
|
||||
chip->ecc.calculate = omap_calculate_ecc_bch_sw;
|
||||
mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
|
||||
/* Reserve one byte for the OMAP marker */
|
||||
oobbytes_per_step = chip->ecc.bytes + 1;
|
||||
/* Software BCH library is used for locating errors */
|
||||
chip->ecc.priv = nand_bch_init(mtd);
|
||||
if (!chip->ecc.priv) {
|
||||
dev_err(dev, "unable to use BCH library\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
case OMAP_ECC_BCH8_CODE_HW:
|
||||
pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
|
||||
chip->ecc.mode = NAND_ECC_HW;
|
||||
chip->ecc.size = 512;
|
||||
/* 14th bit is kept reserved for ROM-code compatibility */
|
||||
chip->ecc.bytes = 13 + 1;
|
||||
chip->ecc.strength = 8;
|
||||
chip->ecc.hwctl = omap_enable_hwecc_bch;
|
||||
chip->ecc.correct = omap_elm_correct_data;
|
||||
chip->ecc.read_page = omap_read_page_bch;
|
||||
chip->ecc.write_page = omap_write_page_bch;
|
||||
chip->ecc.write_subpage = omap_write_subpage_bch;
|
||||
mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
|
||||
oobbytes_per_step = chip->ecc.bytes;
|
||||
|
||||
err = elm_config(info->elm_dev, BCH8_ECC,
|
||||
mtd->writesize / chip->ecc.size,
|
||||
chip->ecc.size, chip->ecc.bytes);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
break;
|
||||
|
||||
case OMAP_ECC_BCH16_CODE_HW:
|
||||
pr_info("Using OMAP_ECC_BCH16_CODE_HW ECC scheme\n");
|
||||
chip->ecc.mode = NAND_ECC_HW;
|
||||
chip->ecc.size = 512;
|
||||
chip->ecc.bytes = 26;
|
||||
chip->ecc.strength = 16;
|
||||
chip->ecc.hwctl = omap_enable_hwecc_bch;
|
||||
chip->ecc.correct = omap_elm_correct_data;
|
||||
chip->ecc.read_page = omap_read_page_bch;
|
||||
chip->ecc.write_page = omap_write_page_bch;
|
||||
chip->ecc.write_subpage = omap_write_subpage_bch;
|
||||
mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
|
||||
oobbytes_per_step = chip->ecc.bytes;
|
||||
|
||||
err = elm_config(info->elm_dev, BCH16_ECC,
|
||||
mtd->writesize / chip->ecc.size,
|
||||
chip->ecc.size, chip->ecc.bytes);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Invalid or unsupported ECC scheme\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check if NAND device's OOB is enough to store ECC signatures */
|
||||
min_oobbytes += (oobbytes_per_step *
|
||||
(mtd->writesize / chip->ecc.size));
|
||||
if (mtd->oobsize < min_oobbytes) {
|
||||
dev_err(dev,
|
||||
"Not enough OOB bytes: required = %d, available=%d\n",
|
||||
min_oobbytes, mtd->oobsize);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct nand_controller_ops omap_nand_controller_ops = {
|
||||
.attach_chip = omap_nand_attach_chip,
|
||||
};
|
||||
|
||||
/* Shared among all NAND instances to synchronize access to the ECC Engine */
|
||||
static struct nand_controller omap_gpmc_controller = {
|
||||
.lock = __SPIN_LOCK_UNLOCKED(omap_gpmc_controller.lock),
|
||||
.wq = __WAIT_QUEUE_HEAD_INITIALIZER(omap_gpmc_controller.wq),
|
||||
.ops = &omap_nand_controller_ops,
|
||||
};
|
||||
|
||||
static int omap_nand_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_nand_info *info;
|
||||
struct mtd_info *mtd;
|
||||
struct nand_chip *nand_chip;
|
||||
int err;
|
||||
dma_cap_mask_t mask;
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
int min_oobbytes = BADBLOCK_MARKER_LENGTH;
|
||||
int oobbytes_per_step;
|
||||
|
||||
info = devm_kzalloc(&pdev->dev, sizeof(struct omap_nand_info),
|
||||
GFP_KERNEL);
|
||||
@ -1998,266 +2253,8 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||
|
||||
/* scan NAND device connected to chip controller */
|
||||
nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
|
||||
err = nand_scan_ident(mtd, 1, NULL);
|
||||
if (err) {
|
||||
dev_err(&info->pdev->dev,
|
||||
"scan failed, may be bus-width mismatch\n");
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
if (nand_chip->bbt_options & NAND_BBT_USE_FLASH)
|
||||
nand_chip->bbt_options |= NAND_BBT_NO_OOB;
|
||||
else
|
||||
nand_chip->options |= NAND_SKIP_BBTSCAN;
|
||||
|
||||
/* re-populate low-level callbacks based on xfer modes */
|
||||
switch (info->xfer_type) {
|
||||
case NAND_OMAP_PREFETCH_POLLED:
|
||||
nand_chip->read_buf = omap_read_buf_pref;
|
||||
nand_chip->write_buf = omap_write_buf_pref;
|
||||
break;
|
||||
|
||||
case NAND_OMAP_POLLED:
|
||||
/* Use nand_base defaults for {read,write}_buf */
|
||||
break;
|
||||
|
||||
case NAND_OMAP_PREFETCH_DMA:
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
info->dma = dma_request_chan(pdev->dev.parent, "rxtx");
|
||||
|
||||
if (IS_ERR(info->dma)) {
|
||||
dev_err(&pdev->dev, "DMA engine request failed\n");
|
||||
err = PTR_ERR(info->dma);
|
||||
goto return_error;
|
||||
} else {
|
||||
struct dma_slave_config cfg;
|
||||
|
||||
memset(&cfg, 0, sizeof(cfg));
|
||||
cfg.src_addr = info->phys_base;
|
||||
cfg.dst_addr = info->phys_base;
|
||||
cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
cfg.src_maxburst = 16;
|
||||
cfg.dst_maxburst = 16;
|
||||
err = dmaengine_slave_config(info->dma, &cfg);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "DMA engine slave config failed: %d\n",
|
||||
err);
|
||||
goto return_error;
|
||||
}
|
||||
nand_chip->read_buf = omap_read_buf_dma_pref;
|
||||
nand_chip->write_buf = omap_write_buf_dma_pref;
|
||||
}
|
||||
break;
|
||||
|
||||
case NAND_OMAP_PREFETCH_IRQ:
|
||||
info->gpmc_irq_fifo = platform_get_irq(pdev, 0);
|
||||
if (info->gpmc_irq_fifo <= 0) {
|
||||
dev_err(&pdev->dev, "error getting fifo irq\n");
|
||||
err = -ENODEV;
|
||||
goto return_error;
|
||||
}
|
||||
err = devm_request_irq(&pdev->dev, info->gpmc_irq_fifo,
|
||||
omap_nand_irq, IRQF_SHARED,
|
||||
"gpmc-nand-fifo", info);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "requesting irq(%d) error:%d",
|
||||
info->gpmc_irq_fifo, err);
|
||||
info->gpmc_irq_fifo = 0;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
info->gpmc_irq_count = platform_get_irq(pdev, 1);
|
||||
if (info->gpmc_irq_count <= 0) {
|
||||
dev_err(&pdev->dev, "error getting count irq\n");
|
||||
err = -ENODEV;
|
||||
goto return_error;
|
||||
}
|
||||
err = devm_request_irq(&pdev->dev, info->gpmc_irq_count,
|
||||
omap_nand_irq, IRQF_SHARED,
|
||||
"gpmc-nand-count", info);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "requesting irq(%d) error:%d",
|
||||
info->gpmc_irq_count, err);
|
||||
info->gpmc_irq_count = 0;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
nand_chip->read_buf = omap_read_buf_irq_pref;
|
||||
nand_chip->write_buf = omap_write_buf_irq_pref;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(&pdev->dev,
|
||||
"xfer_type(%d) not supported!\n", info->xfer_type);
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
if (!omap2_nand_ecc_check(info)) {
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bail out earlier to let NAND_ECC_SOFT code create its own
|
||||
* ooblayout instead of using ours.
|
||||
*/
|
||||
if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW) {
|
||||
nand_chip->ecc.mode = NAND_ECC_SOFT;
|
||||
nand_chip->ecc.algo = NAND_ECC_HAMMING;
|
||||
goto scan_tail;
|
||||
}
|
||||
|
||||
/* populate MTD interface based on ECC scheme */
|
||||
switch (info->ecc_opt) {
|
||||
case OMAP_ECC_HAM1_CODE_HW:
|
||||
pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n");
|
||||
nand_chip->ecc.mode = NAND_ECC_HW;
|
||||
nand_chip->ecc.bytes = 3;
|
||||
nand_chip->ecc.size = 512;
|
||||
nand_chip->ecc.strength = 1;
|
||||
nand_chip->ecc.calculate = omap_calculate_ecc;
|
||||
nand_chip->ecc.hwctl = omap_enable_hwecc;
|
||||
nand_chip->ecc.correct = omap_correct_data;
|
||||
mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
|
||||
oobbytes_per_step = nand_chip->ecc.bytes;
|
||||
|
||||
if (!(nand_chip->options & NAND_BUSWIDTH_16))
|
||||
min_oobbytes = 1;
|
||||
|
||||
break;
|
||||
|
||||
case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
|
||||
pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n");
|
||||
nand_chip->ecc.mode = NAND_ECC_HW;
|
||||
nand_chip->ecc.size = 512;
|
||||
nand_chip->ecc.bytes = 7;
|
||||
nand_chip->ecc.strength = 4;
|
||||
nand_chip->ecc.hwctl = omap_enable_hwecc_bch;
|
||||
nand_chip->ecc.correct = nand_bch_correct_data;
|
||||
nand_chip->ecc.calculate = omap_calculate_ecc_bch_sw;
|
||||
mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
|
||||
/* Reserve one byte for the OMAP marker */
|
||||
oobbytes_per_step = nand_chip->ecc.bytes + 1;
|
||||
/* software bch library is used for locating errors */
|
||||
nand_chip->ecc.priv = nand_bch_init(mtd);
|
||||
if (!nand_chip->ecc.priv) {
|
||||
dev_err(&info->pdev->dev, "unable to use BCH library\n");
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
}
|
||||
break;
|
||||
|
||||
case OMAP_ECC_BCH4_CODE_HW:
|
||||
pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n");
|
||||
nand_chip->ecc.mode = NAND_ECC_HW;
|
||||
nand_chip->ecc.size = 512;
|
||||
/* 14th bit is kept reserved for ROM-code compatibility */
|
||||
nand_chip->ecc.bytes = 7 + 1;
|
||||
nand_chip->ecc.strength = 4;
|
||||
nand_chip->ecc.hwctl = omap_enable_hwecc_bch;
|
||||
nand_chip->ecc.correct = omap_elm_correct_data;
|
||||
nand_chip->ecc.read_page = omap_read_page_bch;
|
||||
nand_chip->ecc.write_page = omap_write_page_bch;
|
||||
nand_chip->ecc.write_subpage = omap_write_subpage_bch;
|
||||
mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
|
||||
oobbytes_per_step = nand_chip->ecc.bytes;
|
||||
|
||||
err = elm_config(info->elm_dev, BCH4_ECC,
|
||||
mtd->writesize / nand_chip->ecc.size,
|
||||
nand_chip->ecc.size, nand_chip->ecc.bytes);
|
||||
if (err < 0)
|
||||
goto return_error;
|
||||
break;
|
||||
|
||||
case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
|
||||
pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
|
||||
nand_chip->ecc.mode = NAND_ECC_HW;
|
||||
nand_chip->ecc.size = 512;
|
||||
nand_chip->ecc.bytes = 13;
|
||||
nand_chip->ecc.strength = 8;
|
||||
nand_chip->ecc.hwctl = omap_enable_hwecc_bch;
|
||||
nand_chip->ecc.correct = nand_bch_correct_data;
|
||||
nand_chip->ecc.calculate = omap_calculate_ecc_bch_sw;
|
||||
mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
|
||||
/* Reserve one byte for the OMAP marker */
|
||||
oobbytes_per_step = nand_chip->ecc.bytes + 1;
|
||||
/* software bch library is used for locating errors */
|
||||
nand_chip->ecc.priv = nand_bch_init(mtd);
|
||||
if (!nand_chip->ecc.priv) {
|
||||
dev_err(&info->pdev->dev, "unable to use BCH library\n");
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
}
|
||||
break;
|
||||
|
||||
case OMAP_ECC_BCH8_CODE_HW:
|
||||
pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
|
||||
nand_chip->ecc.mode = NAND_ECC_HW;
|
||||
nand_chip->ecc.size = 512;
|
||||
/* 14th bit is kept reserved for ROM-code compatibility */
|
||||
nand_chip->ecc.bytes = 13 + 1;
|
||||
nand_chip->ecc.strength = 8;
|
||||
nand_chip->ecc.hwctl = omap_enable_hwecc_bch;
|
||||
nand_chip->ecc.correct = omap_elm_correct_data;
|
||||
nand_chip->ecc.read_page = omap_read_page_bch;
|
||||
nand_chip->ecc.write_page = omap_write_page_bch;
|
||||
nand_chip->ecc.write_subpage = omap_write_subpage_bch;
|
||||
mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
|
||||
oobbytes_per_step = nand_chip->ecc.bytes;
|
||||
|
||||
err = elm_config(info->elm_dev, BCH8_ECC,
|
||||
mtd->writesize / nand_chip->ecc.size,
|
||||
nand_chip->ecc.size, nand_chip->ecc.bytes);
|
||||
if (err < 0)
|
||||
goto return_error;
|
||||
|
||||
break;
|
||||
|
||||
case OMAP_ECC_BCH16_CODE_HW:
|
||||
pr_info("using OMAP_ECC_BCH16_CODE_HW ECC scheme\n");
|
||||
nand_chip->ecc.mode = NAND_ECC_HW;
|
||||
nand_chip->ecc.size = 512;
|
||||
nand_chip->ecc.bytes = 26;
|
||||
nand_chip->ecc.strength = 16;
|
||||
nand_chip->ecc.hwctl = omap_enable_hwecc_bch;
|
||||
nand_chip->ecc.correct = omap_elm_correct_data;
|
||||
nand_chip->ecc.read_page = omap_read_page_bch;
|
||||
nand_chip->ecc.write_page = omap_write_page_bch;
|
||||
nand_chip->ecc.write_subpage = omap_write_subpage_bch;
|
||||
mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
|
||||
oobbytes_per_step = nand_chip->ecc.bytes;
|
||||
|
||||
err = elm_config(info->elm_dev, BCH16_ECC,
|
||||
mtd->writesize / nand_chip->ecc.size,
|
||||
nand_chip->ecc.size, nand_chip->ecc.bytes);
|
||||
if (err < 0)
|
||||
goto return_error;
|
||||
|
||||
break;
|
||||
default:
|
||||
dev_err(&info->pdev->dev, "invalid or unsupported ECC scheme\n");
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* check if NAND device's OOB is enough to store ECC signatures */
|
||||
min_oobbytes += (oobbytes_per_step *
|
||||
(mtd->writesize / nand_chip->ecc.size));
|
||||
if (mtd->oobsize < min_oobbytes) {
|
||||
dev_err(&info->pdev->dev,
|
||||
"not enough OOB bytes required = %d, available=%d\n",
|
||||
min_oobbytes, mtd->oobsize);
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
scan_tail:
|
||||
/* second phase scan */
|
||||
err = nand_scan_tail(mtd);
|
||||
err = nand_scan(mtd, 1);
|
||||
if (err)
|
||||
goto return_error;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user