diff options
Diffstat (limited to 'drivers/mtd/nand/bf5xx_nand.c')
| -rw-r--r-- | drivers/mtd/nand/bf5xx_nand.c | 93 | 
1 files changed, 71 insertions, 22 deletions
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index e87a5729732..9af2a2cc115 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -91,6 +91,41 @@ static const unsigned short bfin_nfc_pin_req[] =  	 P_NAND_ALE,  	 0}; +#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC +static uint8_t bbt_pattern[] = { 0xff }; + +static struct nand_bbt_descr bootrom_bbt = { +	.options = 0, +	.offs = 63, +	.len = 1, +	.pattern = bbt_pattern, +}; + +static struct nand_ecclayout bootrom_ecclayout = { +	.eccbytes = 24, +	.eccpos = { +		0x8 * 0, 0x8 * 0 + 1, 0x8 * 0 + 2, +		0x8 * 1, 0x8 * 1 + 1, 0x8 * 1 + 2, +		0x8 * 2, 0x8 * 2 + 1, 0x8 * 2 + 2, +		0x8 * 3, 0x8 * 3 + 1, 0x8 * 3 + 2, +		0x8 * 4, 0x8 * 4 + 1, 0x8 * 4 + 2, +		0x8 * 5, 0x8 * 5 + 1, 0x8 * 5 + 2, +		0x8 * 6, 0x8 * 6 + 1, 0x8 * 6 + 2, +		0x8 * 7, 0x8 * 7 + 1, 0x8 * 7 + 2 +	}, +	.oobfree = { +		{ 0x8 * 0 + 3, 5 }, +		{ 0x8 * 1 + 3, 5 }, +		{ 0x8 * 2 + 3, 5 }, +		{ 0x8 * 3 + 3, 5 }, +		{ 0x8 * 4 + 3, 5 }, +		{ 0x8 * 5 + 3, 5 }, +		{ 0x8 * 6 + 3, 5 }, +		{ 0x8 * 7 + 3, 5 }, +	} +}; +#endif +  /*   * Data structures for bf5xx nand flash controller driver   */ @@ -273,7 +308,7 @@ static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat,  		dat += 256;  		read_ecc += 8;  		calc_ecc += 8; -		ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc); +		ret |= bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);  	}  	return ret; @@ -298,7 +333,7 @@ static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd,  	ecc0 = bfin_read_NFC_ECC0();  	ecc1 = bfin_read_NFC_ECC1(); -	code[0] = (ecc0 & 0x3FF) | ((ecc1 & 0x3FF) << 11); +	code[0] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11);  	dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]); @@ -310,7 +345,7 @@ static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd,  	if (page_size == 512) {  		ecc0 = bfin_read_NFC_ECC2();  		ecc1 = bfin_read_NFC_ECC3(); -		code[1] = (ecc0 & 0x3FF) | ((ecc1 & 0x3FF) << 11); +		code[1] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11);  		/* second 3 bytes in ecc_code for second 256  		 * bytes of 512 page size @@ -514,7 +549,6 @@ static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd,  /*   * System initialization functions   */ -  static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info)  {  	int ret; @@ -547,6 +581,13 @@ static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info)  	return 0;  } +static void bf5xx_nand_dma_remove(struct bf5xx_nand_info *info) +{ +	/* Free NFC DMA channel */ +	if (hardware_ecc) +		free_dma(CH_NFC); +} +  /*   * BF5XX NFC hardware initialization   *  - pin mux setup @@ -605,7 +646,7 @@ static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info)  #endif  } -static int bf5xx_nand_remove(struct platform_device *pdev) +static int __devexit bf5xx_nand_remove(struct platform_device *pdev)  {  	struct bf5xx_nand_info *info = to_nand_info(pdev);  	struct mtd_info *mtd = NULL; @@ -623,6 +664,7 @@ static int bf5xx_nand_remove(struct platform_device *pdev)  	}  	peripheral_free_list(bfin_nfc_pin_req); +	bf5xx_nand_dma_remove(info);  	/* free the common resources */  	kfree(info); @@ -638,7 +680,7 @@ static int bf5xx_nand_remove(struct platform_device *pdev)   * it can allocate all necessary resources then calls the   * nand layer to look for devices   */ -static int bf5xx_nand_probe(struct platform_device *pdev) +static int __devinit bf5xx_nand_probe(struct platform_device *pdev)  {  	struct bf5xx_nand_platform *plat = to_nand_plat(pdev);  	struct bf5xx_nand_info *info = NULL; @@ -648,22 +690,21 @@ static int bf5xx_nand_probe(struct platform_device *pdev)  	dev_dbg(&pdev->dev, "(%p)\n", pdev); -	if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) { -		printk(KERN_ERR DRV_NAME -		": Requesting Peripherals failed\n"); -		return -EFAULT; -	} -  	if (!plat) {  		dev_err(&pdev->dev, "no platform specific information\n"); -		goto exit_error; +		return -EINVAL; +	} + +	if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) { +		dev_err(&pdev->dev, "requesting Peripherals failed\n"); +		return -EFAULT;  	}  	info = kzalloc(sizeof(*info), GFP_KERNEL);  	if (info == NULL) {  		dev_err(&pdev->dev, "no memory for flash info\n");  		err = -ENOMEM; -		goto exit_error; +		goto out_err_kzalloc;  	}  	platform_set_drvdata(pdev, info); @@ -707,11 +748,16 @@ static int bf5xx_nand_probe(struct platform_device *pdev)  	/* initialise the hardware */  	err = bf5xx_nand_hw_init(info); -	if (err != 0) -		goto exit_error; +	if (err) +		goto out_err_hw_init;  	/* setup hardware ECC data struct */  	if (hardware_ecc) { +#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC +		chip->badblock_pattern = &bootrom_bbt; +		chip->ecc.layout = &bootrom_ecclayout; +#endif +  		if (plat->page_size == NFC_PG_SIZE_256) {  			chip->ecc.bytes = 3;  			chip->ecc.size = 256; @@ -733,7 +779,7 @@ static int bf5xx_nand_probe(struct platform_device *pdev)  	/* scan hardware nand chip and setup mtd info data struct */  	if (nand_scan(mtd, 1)) {  		err = -ENXIO; -		goto exit_error; +		goto out_err_nand_scan;  	}  	/* add NAND partition */ @@ -742,11 +788,14 @@ static int bf5xx_nand_probe(struct platform_device *pdev)  	dev_dbg(&pdev->dev, "initialised ok\n");  	return 0; -exit_error: -	bf5xx_nand_remove(pdev); +out_err_nand_scan: +	bf5xx_nand_dma_remove(info); +out_err_hw_init: +	platform_set_drvdata(pdev, NULL); +	kfree(info); +out_err_kzalloc: +	peripheral_free_list(bfin_nfc_pin_req); -	if (err == 0) -		err = -EINVAL;  	return err;  } @@ -775,7 +824,7 @@ static int bf5xx_nand_resume(struct platform_device *dev)  /* driver device registration */  static struct platform_driver bf5xx_nand_driver = {  	.probe		= bf5xx_nand_probe, -	.remove		= bf5xx_nand_remove, +	.remove		= __devexit_p(bf5xx_nand_remove),  	.suspend	= bf5xx_nand_suspend,  	.resume		= bf5xx_nand_resume,  	.driver		= {  |