mtd: atmel_nand: enable Nand Flash Controller (NFC) support
Subsystems (5)
v3 cover mtd: atmel_nand: enable Nand Flash Controller (NFC) support
This patch series enable NFC support for SAMA5 soc. It can send command, address cycles automaticly. Also when enable NFC sram, NFC will transfer data to sram. Which can save lots of cpu time.
The mtd speed test results (non-NFC vs NFC), run in sama5d3x-ek with DMA enable, is in the end of this patch.
v2 --> v3:
1) Change the dts usage for NFC. Now use a NFC child node of atmel nand to enable NFC driver. In this way the atmel nand driver will include a NFC driver, which will be probed if dts has NFC node.
2) can enable/disable NFC write by sram in dts.
3) merged J.C's patch(use devm_xxx to simple the code) in this series.
4) remove unused NFC register definitions. Change the definition names.
5) trival fix accroding to J.C's suggestion.
6) modify the ofpart.c for child node check. If the child node has compatible property then this node is a device not a partition.
v1 --> v2:
1) rebase it with latest l2-mtd git tree:
- remove useless nand commands (NAND_CMD_DEPLETE1, NAND_CMD_STATUS_ERRORx).
- adopt to the new nand write function's parameters. Add error message when handle subpage write via nfc sram.
2) rewrite pmecc_enable function. Now I use exist NAND_ECC_READ/WRITE const instead of using a new enum definition.
Jean-Christophe PLAGNIOL-VILLARD (1):
MTD: atmel_nand: use devm_xxx gpio kzalloc, gpio and ioremap
Josh Wu (5):
mtd: atmel_nand: replace pmecc enable code with one function.
mtd: atmel_nand: add Nand Flash Controller (NFC) support
mtd: atmel_nand: enable Nand Flash Controller (NFC) read data via
sram
mtd: atmel_nand: enable Nand Flash Controller (NFC) write via sram
mtd: ofpart: add compatible check for child nodes
.../devicetree/bindings/mtd/atmel-nand.txt | 28 + drivers/mtd/nand/atmel_nand.c | 840 ++++++++++++++++---- drivers/mtd/nand/atmel_nand_nfc.h | 94 +++ drivers/mtd/ofpart.c | 14 +- 4 files changed, 832 insertions(+), 144 deletions(-) create mode 100644 drivers/mtd/nand/atmel_nand_nfc.h
mtd_speedtest is run in 60M partition with DMA enabled for two cases:
1. Using NFC and sram read/write with DMA enabled.
2. Using Non-NFC with DMA enabled.
Summary of the two test results:
1. With NFC and sram read/write enabled, the write speed will become %10 slower
and the cpu load also is reduce a lot (50% -> 20%):
Non-NFC NFC
Page write Speed: 5536KiB : 46% ~ 64% --> 4989KiB : 13% ~ 22%
2 Page write speed: 5567KiB : 52% ~ 69% --> 5043KiB : 10% ~ 20%2. With NFC and sram read/write enabled, the read speed is almost same and the
cpu load is reduced (30% -> 15%):
Non-NFC NFC
Page read Speed: 9361KiB : %24 ~ 46% --> 9340KiB : 13% ~ 19%
2 Page read Speed: 9361KiB : %21 ~ 57% --> 9426KiB : 8% ~ 15%Following is the detail test log:
case 1: Non-NFC with DMA:
=================================================mtd_speedtest: MTD device: 2mtd_speedtest: MTD device size 62914560, eraseblock size 131072, page size 2048, count of eraseblocks 480, pages per eraseblock 64, OOB size 64mtd_speedtest: scanning for bad eraseblocksmtd_speedtest: scanned 480 eraseblocks, 0 are badmtd_speedtest: testing eraseblock write speed
top -n 130 -d 1 | grep speedtest
513 504 root R 1164 0% 62% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root D 1164 0% 53% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 57% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 58% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 53% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 60% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 55% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 55% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 59% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 57% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 62% insmod /root/mtd_test/mtd_speedtest.ko mtd_speedtest: eraseblock write speed is 5594 KiB/s mtd_speedtest: testing eraseblock read speed 513 504 root R 1164 0% 27% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 14% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 5% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 1% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 2% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 1% insmod /root/mtd_test/mtd_speedtest.ko mtd_speedtest: eraseblock read speed is 9442 KiB/s mtd_speedtest: testing page write speed 513 504 root R 1164 0% 46% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 64% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 57% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 64% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 56% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 59% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 59% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 56% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 59% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 62% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 60% insmod /root/mtd_test/mtd_speedtest.ko mtd_speedtest: page write speed is 5536 KiB/s mtd_speedtest: testing page read speed 513 504 root R 1164 0% 46% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 24% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 30% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 30% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 26% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 25% insmod /root/mtd_test/mtd_speedtest.ko mtd_speedtest: page read speed is 9361 KiB/s 513 504 root R 1164 0% 24% insmod /root/mtd_test/mtd_speedtest.ko mtd_speedtest: testing 2 page write speed 513 504 root R 1164 0% 69% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 56% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 57% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 61% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 55% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 61% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 55% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 52% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 55% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 58% insmod /root/mtd_test/mtd_speedtest.ko mtd_speedtest: 2 page write speed is 5567 KiB/s mtd_speedtest: testing 2 page read speed 513 504 root D 1164 0% 57% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 26% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 21% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 23% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 24% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 25% insmod /root/mtd_test/mtd_speedtest.ko 513 504 root R 1164 0% 23% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: 2 page read speed is 9361 KiB/smtd_speedtest: Testing erase speedmtd_speedtest: erase speed is 167411 KiB/smtd_speedtest: Testing 2x multi-block erase speedmtd_speedtest: 2x multi-block erase speed is 326808 KiB/smtd_speedtest: Testing 4x multi-block erase speed
513 504 root R 1164 0% 74% insmod /root/mtd_test/mtd_speedtest.komtd_speedtest: 4x multi-block erase speed is 301176 KiB/smtd_speedtest: Testing 8x multi-block erase speedmtd_speedtest: 8x multi-block erase speed is 326808 KiB/smtd_speedtest: Testing 16x multi-block erase speedmtd_speedtest: 16x multi-block erase speed is 328556 KiB/smtd_speedtest: Testing 32x multi-block erase speedmtd_speedtest: 32x multi-block erase speed is 328556 KiB/smtd_speedtest: Testing 64x multi-block erase speedmtd_speedtest: 64x multi-block erase speed is 325079 KiB/smtd_speedtest: finished
=================================================
case 2: NFC with DMA:
=================================================mtd_speedtest: MTD device: 2mtd_speedtest: MTD device size 62914560, eraseblock size 131072, page size 2048, count of eraseblocks 480, pages per eraseblock 64, OOB size 64mtd_speedtest: scanning for bad eraseblocksmtd_speedtest: scanned 480 eraseblocks, 0 are bad
top -n 130 -d 1 | grep speedtestmtd_speedtest: testing eraseblock write speed
514 504 root R 1164 0% 8% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 12% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 10% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 13% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root D 1164 0% 15% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root D 1164 0% 14% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 11% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 9% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 15% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 11% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 15% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 12% insmod /root/mtd_test/mtd_speedtest.ko mtd_speedtest: eraseblock write speed is 5105 KiB/s mtd_speedtest: testing eraseblock read speed 514 504 root R 1164 0% 14% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 20% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 17% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 8% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 6% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 15% insmod /root/mtd_test/mtd_speedtest.ko mtd_speedtest: eraseblock read speed is 9512 KiB/s 514 504 root R 1164 0% 6% insmod /root/mtd_test/mtd_speedtest.ko mtd_speedtest: testing page write speed 514 504 root R 1164 0% 17% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 20% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 13% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 12% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 14% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 17% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 11% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 22% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 17% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 14% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 17% insmod /root/mtd_test/mtd_speedtest.ko mtd_speedtest: page write speed is 4989 KiB/s mtd_speedtest: testing page read speed 514 504 root R 1164 0% 16% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 13% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 17% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 16% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 18% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 19% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 16% insmod /root/mtd_test/mtd_speedtest.ko mtd_speedtest: page read speed is 9340 KiB/s mtd_speedtest: testing 2 page write speed 514 504 root R 1164 0% 20% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 10% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 14% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 16% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 15% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 12% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 16% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 18% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 15% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 16% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 17% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 13% insmod /root/mtd_test/mtd_speedtest.ko mtd_speedtest: 2 page write speed is 5043 KiB/s mtd_speedtest: testing 2 page read speed 514 504 root R 1164 0% 8% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 9% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 14% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 12% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 12% insmod /root/mtd_test/mtd_speedtest.ko 514 504 root R 1164 0% 15% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: 2 page read speed is 9426 KiB/smtd_speedtest: Testing erase speed
514 504 root R 1164 0% 12% insmod /root/mtd_test/mtd_speedtest.komtd_speedtest: erase speed is 157943 KiB/smtd_speedtest: Testing 2x multi-block erase speedmtd_speedtest: 2x multi-block erase speed is 308743 KiB/smtd_speedtest: Testing 4x multi-block erase speedmtd_speedtest: 4x multi-block erase speed is 313469 KiB/smtd_speedtest: Testing 8x multi-block erase speedmtd_speedtest: 8x multi-block erase speed is 313469 KiB/smtd_speedtest: Testing 16x multi-block erase speedmtd_speedtest: 16x multi-block erase speed is 315076 KiB/smtd_speedtest: Testing 32x multi-block erase speed
514 504 root R 1164 0% 12% insmod /root/mtd_test/mtd_speedtest.komtd_speedtest: 32x multi-block erase speed is 298252 KiB/smtd_speedtest: Testing 64x multi-block erase speedmtd_speedtest: 64x multi-block erase speed is 311878 KiB/smtd_speedtest: finished
=================================================
Signature · 1 line
1.7.9.5
PATCH v3 1/6 MTD: atmel_nand: use devm_xxx gpio kzalloc, gpio and ioremap
From: Jean-Christophe PLAGNIOL-VILLARD <[email protected]>
this will allow to simply the error and remove path
--- drivers/mtd/nand/atmel_nand.c | 148 ++++++++++++++--------------------------- 1 file changed, 51 insertions(+), 97 deletions(-)
drivers/mtd/nand/atmel_nand.c +51 -97
@@ -366,43 +366,34 @@ static void __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host) table_size * sizeof(int16_t); } -static void pmecc_data_free (struct atmel_nand_host *host) -{ -kfree (host->pmecc_partial_syn); -kfree (host->pmecc_si); -kfree (host->pmecc_lmu); -kfree (host->pmecc_smu); -kfree (host->pmecc_mu); -kfree (host->pmecc_dmu); -kfree (host->pmecc_delta); -} -static int pmecc_data_alloc (struct atmel_nand_host *host) {const int cap = host->pmecc_corr_cap; +int size; + + size = (2 * cap +1 ) *sizeof (int16_t ); + host->pmecc_partial_syn =devm_kzalloc (host->dev, size,GFP_KERNEL ); + host->pmecc_si =devm_kzalloc (host->dev, size,GFP_KERNEL ); + host->pmecc_lmu =devm_kzalloc (host->dev, + (cap +1 ) *sizeof (int16_t ),GFP_KERNEL ); + host->pmecc_smu =devm_kzalloc (host->dev, + (cap +2 ) * size,GFP_KERNEL ); + + size = (cap +1 ) *sizeof (int ); + host->pmecc_mu =devm_kzalloc (host->dev, size,GFP_KERNEL ); + host->pmecc_dmu =devm_kzalloc (host->dev, size,GFP_KERNEL ); + host->pmecc_delta =devm_kzalloc (host->dev, size,GFP_KERNEL ); + +if (!host->pmecc_partial_syn || + !host->pmecc_si || + !host->pmecc_lmu || + !host->pmecc_smu || + !host->pmecc_mu || + !host->pmecc_dmu || + !host->pmecc_delta) +return -ENOMEM ; - host->pmecc_partial_syn =kzalloc ((2 * cap +1 ) *sizeof (int16_t ), -GFP_KERNEL ); - host->pmecc_si =kzalloc ((2 * cap +1 ) *sizeof (int16_t ),GFP_KERNEL ); - host->pmecc_lmu =kzalloc ((cap +1 ) *sizeof (int16_t ),GFP_KERNEL ); - host->pmecc_smu =kzalloc ((cap +2 ) * (2 * cap +1 ) *sizeof (int16_t ), -GFP_KERNEL ); - host->pmecc_mu =kzalloc ((cap +1 ) *sizeof (int ),GFP_KERNEL ); - host->pmecc_dmu =kzalloc ((cap +1 ) *sizeof (int ),GFP_KERNEL ); - host->pmecc_delta =kzalloc ((cap +1 ) *sizeof (int ),GFP_KERNEL ); - -if (host->pmecc_partial_syn && - host->pmecc_si && - host->pmecc_lmu && - host->pmecc_smu && - host->pmecc_mu && - host->pmecc_dmu && - host->pmecc_delta) -return 0 ; - -/* error happened */ -pmecc_data_free (host); -return -ENOMEM ; +return 0 ; }static void pmecc_gen_syndrome (struct mtd_info *mtd,int sector)
@@ -1023,27 +1014,27 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,return 0 ; } - host->ecc =ioremap (regs->start,resource_size (regs)); + host->ecc =devm_request_and_ioremap (&pdev->dev, regs);if (host->ecc ==NULL ) {dev_err (host->dev,"ioremap failed\n" ); err_no = -EIO ; - goto err_pmecc_ioremap; + goto err; } regs_pmerr =platform_get_resource (pdev,IORESOURCE_MEM ,2 ); regs_rom =platform_get_resource (pdev,IORESOURCE_MEM ,3 );if (regs_pmerr && regs_rom) { - host->pmerrloc_base =ioremap (regs_pmerr->start, -resource_size (regs_pmerr)); - host->pmecc_rom_base =ioremap (regs_rom->start, -resource_size (regs_rom)); + host->pmerrloc_base =devm_request_and_ioremap (&pdev->dev, + regs_pmerr); + host->pmecc_rom_base =devm_request_and_ioremap (&pdev->dev, + regs_rom); }if (!host->pmerrloc_base || !host->pmecc_rom_base) {dev_err (host->dev,"Can not get I/O resource for PMECC ERRLOC controller or ROM!\n" ); err_no = -EIO ; - goto err_pmloc_ioremap; + goto err; }/* ECC is calculated for the whole page (1 step) */
@@ -1068,7 +1059,7 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,if (nand_chip->ecc.bytes > mtd->oobsize -2 ) {dev_err (host->dev,"No room for ECC bytes\n" ); err_no = -EINVAL ; - goto err_no_ecc_room; + goto err; } pmecc_config_ecc_layout(&atmel_pmecc_oobinfo, mtd->oobsize,
@@ -1093,7 +1084,7 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,if (err_no) {dev_err (host->dev,"Cannot allocate memory for PMECC computation!\n" ); - goto err_pmecc_data_alloc; + goto err; } nand_chip->ecc.read_page = atmel_nand_pmecc_read_page;
@@ -1103,15 +1094,7 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,return 0 ; -err_pmecc_data_alloc: -err_no_ecc_room: -err_pmloc_ioremap: -iounmap (host->ecc); -if (host->pmerrloc_base) -iounmap (host->pmerrloc_base); -if (host->pmecc_rom_base) -iounmap (host->pmecc_rom_base); -err_pmecc_ioremap: +err:return err_no; }
@@ -1414,7 +1397,7 @@ static int __init atmel_hw_nand_init_params(struct platform_device *pdev,return 0 ; } - host->ecc =ioremap (regs->start,resource_size (regs)); + host->ecc =devm_request_and_ioremap (&pdev->dev, regs);if (host->ecc ==NULL ) {dev_err (host->dev,"ioremap failed\n" );return -EIO ;
@@ -1479,20 +1462,19 @@ static int __init atmel_nand_probe(struct platform_device *pdev) }/* Allocate memory for the device structure (and zero it) */ - host =kzalloc (sizeof (struct atmel_nand_host ),GFP_KERNEL ); + host =devm_kzalloc (&pdev->dev,sizeof (*host),GFP_KERNEL );if (!host) {printk (KERN_ERR "atmel_nand: failed to allocate device structure.\n" );return -ENOMEM ; } - host->io_phys = (dma_addr_t )mem->start; - - host->io_base =ioremap (mem->start,resource_size (mem)); + host->io_base =devm_request_and_ioremap (&pdev->dev, mem);if (host->io_base ==NULL ) {printk (KERN_ERR "atmel_nand: ioremap failed\n" ); res = -EIO ; goto err_nand_ioremap; } + host->io_phys = (dma_addr_t )mem->start; mtd = &host->mtd; nand_chip = &host->nand_chip;
@@ -1500,7 +1482,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)if (pdev->dev.of_node) { res =atmel_of_init_port (host, pdev->dev.of_node);if (res) - goto err_ecc_ioremap; + goto err_nand_ioremap; }else {memcpy (&host->board, pdev->dev.platform_data,sizeof (struct atmel_nand_data ));
@@ -1519,16 +1501,17 @@ static int __init atmel_nand_probe(struct platform_device *pdev)if (IS_ERR (pinctrl)) {dev_err (host->dev,"Failed to request pinctrl\n" ); res =PTR_ERR (pinctrl); - goto err_ecc_ioremap; + goto err_nand_ioremap; }if (gpio_is_valid (host->board.rdy_pin)) { - res =gpio_request (host->board.rdy_pin,"nand_rdy" ); + res =devm_gpio_request (&pdev->dev, + host->board.rdy_pin,"nand_rdy" );if (res <0 ) {dev_err (&pdev->dev,"can't request rdy gpio %d\n" , host->board.rdy_pin); - goto err_ecc_ioremap; + goto err_nand_ioremap; } res =gpio_direction_input (host->board.rdy_pin);
@@ -1536,19 +1519,20 @@ static int __init atmel_nand_probe(struct platform_device *pdev)dev_err (&pdev->dev,"can't request input direction rdy gpio %d\n" , host->board.rdy_pin); - goto err_ecc_ioremap; + goto err_nand_ioremap; } nand_chip->dev_ready = atmel_nand_device_ready; }if (gpio_is_valid (host->board.enable_pin)) { - res =gpio_request (host->board.enable_pin,"nand_enable" ); + res =devm_gpio_request (&pdev->dev, + host->board.enable_pin,"nand_enable" );if (res <0 ) {dev_err (&pdev->dev,"can't request enable gpio %d\n" , host->board.enable_pin); - goto err_ecc_ioremap; + goto err_nand_ioremap; } res =gpio_direction_output (host->board.enable_pin,1 );
@@ -1556,7 +1540,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)dev_err (&pdev->dev,"can't request output direction enable gpio %d\n" , host->board.enable_pin); - goto err_ecc_ioremap; + goto err_nand_ioremap; } }
@@ -1573,7 +1557,8 @@ static int __init atmel_nand_probe(struct platform_device *pdev)atmel_nand_enable (host);if (gpio_is_valid (host->board.det_pin)) { - res =gpio_request (host->board.det_pin,"nand_det" ); + res =devm_gpio_request (&pdev->dev, + host->board.det_pin,"nand_det" );if (res <0 ) { dev_err(&pdev->dev, "can't request det gpio %d\n",
@@ -1651,16 +1636,8 @@ static int __init atmel_nand_probe(struct platform_device *pdev)return res; err_scan_tail: -if (host->has_pmecc && host->nand_chip.ecc.mode ==NAND_ECC_HW ) { +if (host->has_pmecc && host->nand_chip.ecc.mode ==NAND_ECC_HW )pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_DISABLE ); -pmecc_data_free (host); - } -if (host->ecc) -iounmap (host->ecc); -if (host->pmerrloc_base) -iounmap (host->pmerrloc_base); -if (host->pmecc_rom_base) -iounmap (host->pmecc_rom_base); err_hw_ecc: err_scan_ident: err_no_card:
@@ -1668,10 +1645,7 @@ err_no_card:platform_set_drvdata (pdev,NULL );if (host->dma_chan)dma_release_channel (host->dma_chan); -err_ecc_ioremap: -iounmap (host->io_base); err_nand_ioremap: -kfree (host);return res; }
@@ -1691,31 +1665,11 @@ static int __exit atmel_nand_remove(struct platform_device *pdev)pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_DISABLE );pmerrloc_writel (host->pmerrloc_base,ELDIS ,PMERRLOC_DISABLE ); -pmecc_data_free (host); } -if (gpio_is_valid (host->board.det_pin)) -gpio_free (host->board.det_pin); - -if (gpio_is_valid (host->board.enable_pin)) -gpio_free (host->board.enable_pin); - -if (gpio_is_valid (host->board.rdy_pin)) -gpio_free (host->board.rdy_pin); - -if (host->ecc) -iounmap (host->ecc); -if (host->pmecc_rom_base) -iounmap (host->pmecc_rom_base); -if (host->pmerrloc_base) -iounmap (host->pmerrloc_base); -if (host->dma_chan)dma_release_channel (host->dma_chan); -iounmap (host->io_base); -kfree (host); -return 0 ; }
Signature · 1 line
1.7.9.5
PATCH v3 2/6 mtd: atmel_nand: replace pmecc enable code with one function.
In reply to Josh Wu--- drivers/mtd/nand/atmel_nand.c | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-)
drivers/mtd/nand/atmel_nand.c +25 -15
@@ -754,6 +754,29 @@ normal_check:return total_err; } +static void pmecc_enable (struct atmel_nand_host *host,int ecc_op) +{ +u32 val; +pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_RST ); +pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_DISABLE ); + val =pmecc_readl_relaxed (host->ecc,CFG ); + +if (ecc_op !=NAND_ECC_READ && ecc_op !=NAND_ECC_WRITE ) { +dev_err (host->dev,"atmel_nand: wrong pmecc operation type!" ); +return ; + } + +if (ecc_op ==NAND_ECC_READ ) +pmecc_writel (host->ecc,CFG , (val & ~PMECC_CFG_WRITE_OP ) + |PMECC_CFG_AUTO_ENABLE ); +else +pmecc_writel (host->ecc,CFG , (val |PMECC_CFG_WRITE_OP ) + & ~PMECC_CFG_AUTO_ENABLE ); + +pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_ENABLE ); +pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_DATA ); +} +static int atmel_nand_pmecc_read_page (struct mtd_info *mtd,struct nand_chip *chip,uint8_t *buf,int oob_required,int page) {
@@ -765,13 +788,7 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,unsigned long end_time;int bitflips =0 ; -pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_RST ); -pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_DISABLE ); -pmecc_writel (host->ecc,CFG , (pmecc_readl_relaxed (host->ecc,CFG ) - & ~PMECC_CFG_WRITE_OP ) |PMECC_CFG_AUTO_ENABLE ); - -pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_ENABLE ); -pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_DATA ); +pmecc_enable (host,NAND_ECC_READ ); chip->read_buf (mtd, buf, eccsize); chip->read_buf (mtd, oob, mtd->oobsize);
@@ -804,14 +821,7 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,int i, j;unsigned long end_time; -pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_RST ); -pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_DISABLE ); - -pmecc_writel (host->ecc,CFG , (pmecc_readl_relaxed (host->ecc,CFG ) | -PMECC_CFG_WRITE_OP ) & ~PMECC_CFG_AUTO_ENABLE ); - -pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_ENABLE ); -pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_DATA ); +pmecc_enable (host,NAND_ECC_WRITE ); chip->write_buf (mtd, (u8 *)buf, mtd->writesize);
Signature · 1 line
1.7.9.5
PATCH 2/6 mtd: atmel_nand: replace pmecc enable code with one function.
Quoted 1 line · Josh Wu
Signed-off-by Josh Wu <[email protected]>
Best Regards,
J.
Quoted 72 lines
--- drivers/mtd/nand/atmel_nand.c | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-)drivers/mtd/nand/atmel_nand.c +25
-15@@ -754,6 +754,29 @@ normal_check:return total_err; } +static void pmecc_enable (struct atmel_nand_host *host,int ecc_op) +{ +u32 val; +pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_RST ); +pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_DISABLE ); + val =pmecc_readl_relaxed (host->ecc,CFG ); + +if (ecc_op !=NAND_ECC_READ && ecc_op !=NAND_ECC_WRITE ) { +dev_err (host->dev,"atmel_nand: wrong pmecc operation type!" ); +return ; + } + +if (ecc_op ==NAND_ECC_READ ) +pmecc_writel (host->ecc,CFG , (val & ~PMECC_CFG_WRITE_OP ) + |PMECC_CFG_AUTO_ENABLE ); +else +pmecc_writel (host->ecc,CFG , (val |PMECC_CFG_WRITE_OP ) + & ~PMECC_CFG_AUTO_ENABLE ); + +pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_ENABLE ); +pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_DATA ); +} +static int atmel_nand_pmecc_read_page (struct mtd_info *mtd,struct nand_chip *chip,uint8_t *buf,int oob_required,int page) {@@ -765,13 +788,7 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,unsigned long end_time;int bitflips =0 ; -pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_RST ); -pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_DISABLE ); -pmecc_writel (host->ecc,CFG , (pmecc_readl_relaxed (host->ecc,CFG ) - & ~PMECC_CFG_WRITE_OP ) |PMECC_CFG_AUTO_ENABLE ); - -pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_ENABLE ); -pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_DATA ); +pmecc_enable (host,NAND_ECC_READ ); chip->read_buf (mtd, buf, eccsize); chip->read_buf (mtd, oob, mtd->oobsize);@@ -804,14 +821,7 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,int i, j;unsigned long end_time; -pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_RST ); -pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_DISABLE ); - -pmecc_writel (host->ecc,CFG , (pmecc_readl_relaxed (host->ecc,CFG ) | -PMECC_CFG_WRITE_OP ) & ~PMECC_CFG_AUTO_ENABLE ); - -pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_ENABLE ); -pmecc_writel (host->ecc,CTRL ,PMECC_CTRL_DATA ); +pmecc_enable (host,NAND_ECC_WRITE ); chip->write_buf (mtd, (u8 *)buf, mtd->writesize);Signature · 1 line
1.7.9.5
PATCH v3 3/6 mtd: atmel_nand: add Nand Flash Controller (NFC) support
In reply to Josh WuNand Flash Controller (NFC) can handle automatic transfers, sending the commands and address cycles to the NAND Flash.
To use NFC in this driver, user needs to add NFC child node in nand flash driver. The NFC child node includes NFC's compatible string and regiters of the address and size of NFC command registers, NFC registers (embedded in HSMC) and NFC SRAM.
Also user need to set up the HSMC irq, which use to check whether nfc command is finish or not.
This driver has been tested on SAMA5D3X-EK board with JFFS2, YAFFS, UBIFS and mtd-utils.
I put the part of the mtd_speedtest result here for your information.
Quoted 1 line
From the
mtd_speedtest, we can see the NFC will reduce the %50 of cpu load
when writing nand flash. No change when reading.
In the meantime, the speed will be slow about %8.
- commands use to test:
#insmod /mnt/mtd_speedtest.ko dev=2 &
#top -n 30 -d 1 | grep speedtest
- test result:
Before the patch:
=================================================mtd_speedtest: MTD device: 2mtd_speedtest: MTD device size 41943040, eraseblock size 131072, page size 2048, count of eraseblocks 320, pages per eraseblock 64, OOB size 64
515 495 root R 1164 0% 93% insmod /mnt/mtd_speedtest.ko dev=2 515 495 root R 1164 0% 98% insmod /mnt/mtd_speedtest.ko dev=2 515 495 root R 1164 0% 99% insmod /mnt/mtd_speedtest.ko dev=2 mtd_speedtest: eraseblock write speed is 5768 KiB/s mtd_speedtest: testing eraseblock read speed 515 495 root R 1164 0% 92% insmod /mnt/mtd_speedtest.ko dev=2 515 495 root R 1164 0% 91% insmod /mnt/mtd_speedtest.ko dev=2 515 495 root R 1164 0% 94% insmod /mnt/mtd_speedtest.ko dev=2 mtd_speedtest: eraseblock read speed is 5932 KiB/s mtd_speedtest: testing page write speed 515 495 root R 1164 0% 94% insmod /mnt/mtd_speedtest.ko dev=2 515 495 root R 1164 0% 98% insmod /mnt/mtd_speedtest.ko dev=2 515 495 root R 1164 0% 98% insmod /mnt/mtd_speedtest.ko dev=2 mtd_speedtest: page write speed is 5770 KiB/s mtd_speedtest: testing page read speed 515 495 root R 1164 0% 91% insmod /mnt/mtd_speedtest.ko dev=2 515 495 root R 1164 0% 89% insmod /mnt/mtd_speedtest.ko dev=2 515 495 root R 1164 0% 91% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: page read speed is 5910 KiB/s
After the patch:
=================================================mtd_speedtest: MTD device: 2mtd_speedtest: MTD device size 41943040, eraseblock size 131072, page size 2048, count of eraseblocks 320, pages per eraseblock 64, OOB size 64mtd_speedtest: testing eraseblock write speed
509 495 root D 1164 0% 49% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root D 1164 0% 50% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root D 1164 0% 47% insmod /mnt/mtd_speedtest.ko dev=2 mtd_speedtest: eraseblock write speed is 5370 KiB/s mtd_speedtest: testing eraseblock read speed 509 495 root R 1164 0% 92% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root R 1164 0% 91% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root R 1164 0% 95% insmod /mnt/mtd_speedtest.ko dev=2 mtd_speedtest: eraseblock read speed is 5715 KiB/s mtd_speedtest: testing page write speed 509 495 root D 1164 0% 48% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root D 1164 0% 47% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root D 1164 0% 50% insmod /mnt/mtd_speedtest.ko dev=2 mtd_speedtest: page write speed is 5224 KiB/s mtd_speedtest: testing page read speed 509 495 root R 1164 0% 89% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root R 1164 0% 94% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root R 1164 0% 93% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: page read speed is 5641 KiB/s
---
v2 --> v3:
- Add a NFC child node of atmel nand to enable NFC.
- So add a NFC driver which use to initialize the NFC reg resources.
- remove unused NFC register definitions.
- modify NFC register definition names.
.../devicetree/bindings/mtd/atmel-nand.txt | 26 ++ drivers/mtd/nand/atmel_nand.c | 410 ++++++++++++++++++-- drivers/mtd/nand/atmel_nand_nfc.h | 94 +++++ 3 files changed, 497 insertions(+), 33 deletions(-) create mode 100644 drivers/mtd/nand/atmel_nand_nfc.h
Documentation/devicetree/bindings/mtd/atmel-nand.txt +26 -0
@@ -29,6 +29,12 @@ Optional properties: sector size 1024. - nand-bus-width : 8 or 16 bus width if not present 8 - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false +- Nand Flash Controller(NFC) is a slave driver under Atmel nand flash + - Required properties: + - compatible : "atmel,sama5d3-nfc". + - reg : should specify the address and size used for NFC command registers, + NFC registers and NFC Sram. NFC Sram address and size can be absent + if don't want to use it. Examples: nand0: nand at 40000000,0 {
@@ -77,3 +83,23 @@ nand0: nand at 40000000 { ... }; }; + +/* for NFC supported chips */ +nand0: nand at 40000000 { + compatible = "atmel,at91rm9200-nand"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + ... + nfc at 70000000 { + compatible = "atmel,sama5d3-nfc"; + #address-cells = <1>; + #size-cells = <1>; + reg = < + 0x70000000 0x10000000 /* NFC Command Registers */ + 0xffffc000 0x00000070 /* NFC HSMC regs */ + 0x00200000 0x00100000 /* NFC SRAM banks */ + >; + }; +}; +
drivers/mtd/nand/atmel_nand.c +377 -33
510 lines not on this page · raw message
drivers/mtd/nand/atmel_nand_nfc.h new file +94 -0
94 lines not on this page · raw message
Signature · 1 line
1.7.9.5
PATCH 3/6 mtd: atmel_nand: add Nand Flash Controller (NFC) support
drivers/mtd/nand/atmel_nand.c static int atmel_of_init_port(struct atmel_nand_host *host, · line 1413
Quoted 10 lines
drivers/mtd/nand/atmel_nand.c +3
-0+/* * Minimal-overhead PIO for data access. */ @@ -1341,6 +1409,9 @@ static int atmel_of_init_port(struct atmel_nand_host *host, host->has_pmecc =of_property_read_bool (np,"atmel,has-pmecc" ); +/* load the nfc driver if there is */ +of_platform_populate (np,NULL ,NULL , host->dev);
what is this?????
Quoted 253 lines
drivers/mtd/nand/atmel_nand.c +234
-1+if (!(board->ecc_mode ==NAND_ECC_HW ) || !host->has_pmecc)return 0 ;/* Not using PMECC */ @@ -1452,6 +1523,238 @@ static int __init atmel_hw_nand_init_params(struct platform_device *pdev,return 0 ; } +/* SMC interrupt service routine */ +static irqreturn_t hsmc_interrupt (int irq,void *dev_id) +{ +struct atmel_nand_host *host = dev_id; +u32 status, mask, pending; +irqreturn_t ret =IRQ_HANDLED ; + + status =nfc_readl (host->nfc->hsmc_regs,SR ); + mask =nfc_readl (host->nfc->hsmc_regs,IMR ); + pending = status & mask; + +if (pending &NFC_SR_XFR_DONE ) { +complete (&host->nfc->comp_nfc); +nfc_writel (host->nfc->hsmc_regs,IDR ,NFC_SR_XFR_DONE ); + }else if (pending &NFC_SR_RB_EDGE ) { +complete (&host->nfc->comp_nfc); +nfc_writel (host->nfc->hsmc_regs,IDR ,NFC_SR_RB_EDGE ); + }else if (pending &NFC_SR_CMD_DONE ) { +complete (&host->nfc->comp_nfc); +nfc_writel (host->nfc->hsmc_regs,IDR ,NFC_SR_CMD_DONE ); + }else { + ret =IRQ_NONE ; + } + +return ret; +} + +/* NFC(Nand Flash Controller) related functions */ +static int nfc_wait_interrupt (struct atmel_nand_host *host,u32 flag) +{ +unsigned long timeout; +init_completion (&host->nfc->comp_nfc); + +/* Enable interrupt that need to wait for */ +nfc_writel (host->nfc->hsmc_regs,IER , flag); + + timeout =wait_for_completion_timeout (&host->nfc->comp_nfc, +msecs_to_jiffies (NFC_TIME_OUT_MS )); +if (timeout) +return 0 ; + +/* Time out to wait for the interrupt */ +dev_err (host->dev,"Time out to wait for interrupt: 0x%08x\n" , flag); +return -ETIMEDOUT ; +} + +static int nfc_send_command (struct atmel_nand_host *host, +unsigned int cmd,unsigned int addr,unsigned char cycle0) +{ +unsigned long timeout; +dev_dbg (host->dev, +"nfc_cmd: 0x%08x, addr1234: 0x%08x, cycle0: 0x%02x\n" , + cmd, addr, cycle0); + + timeout = jiffies +msecs_to_jiffies (NFC_TIME_OUT_MS ); +while (nfc_cmd_readl (NFCADDR_CMD_NFCBUSY , host->nfc->base_cmd_regs) + &NFCADDR_CMD_NFCBUSY ) { +if (time_after (jiffies, timeout)) { +dev_err (host->dev, +"Time out to wait CMD_NFCBUSY ready!\n" ); +return -ETIMEDOUT ; + } + } +nfc_writel (host->nfc->hsmc_regs,CYCLE0 , cycle0); +nfc_cmd_addr1234_writel (cmd, addr, host->nfc->base_cmd_regs); +return nfc_wait_interrupt (host,NFC_SR_CMD_DONE ); +} + +static int nfc_device_ready (struct mtd_info *mtd) +{ +struct nand_chip *nand_chip = mtd->priv; +struct atmel_nand_host *host = nand_chip->priv; +if (!nfc_wait_interrupt (host,NFC_SR_RB_EDGE )) +return 1 ; +return 0 ; +} + +static void nfc_select_chip (struct mtd_info *mtd,int chip) +{ +struct nand_chip *nand_chip = mtd->priv; +struct atmel_nand_host *host = nand_chip->priv; + +if (chip ==-1 ) +nfc_writel (host->nfc->hsmc_regs,CTRL ,NFC_CTRL_DISABLE ); +else +nfc_writel (host->nfc->hsmc_regs,CTRL ,NFC_CTRL_ENABLE ); +} + +static int nfc_make_addr (struct mtd_info *mtd,int column,int page_addr, +unsigned int *addr1234,unsigned int *cycle0) +{ +struct nand_chip *chip = mtd->priv; + +int acycle =0 ; +unsigned char addr_bytes[8 ]; +int index =0 , bit_shift; + +BUG_ON (addr1234 ==NULL || cycle0 ==NULL ); + + *cycle0 =0 ; + *addr1234 =0 ; + +if (column !=-1 ) { +if (chip->options &NAND_BUSWIDTH_16 ) + column >>=1 ; + addr_bytes[acycle++] = column &0xff ; +if (mtd->writesize >512 ) + addr_bytes[acycle++] = (column >>8 ) &0xff ; + } + +if (page_addr !=-1 ) { + addr_bytes[acycle++] = page_addr &0xff ; + addr_bytes[acycle++] = (page_addr >>8 ) &0xff ; +if (chip->chipsize > (128 <<20 )) + addr_bytes[acycle++] = (page_addr >>16 ) &0xff ; + } + +if (acycle >4 ) + *cycle0 = addr_bytes[index++]; + +for (bit_shift =0 ; index < acycle; bit_shift +=8 ) + *addr1234 += addr_bytes[index++] << bit_shift; + +return acycle <<19 ;/* return acycle in cmd register */ +} + +static void nfc_nand_command (struct mtd_info *mtd,unsigned int command, +int column,int page_addr) +{ +struct nand_chip *chip = mtd->priv; +struct atmel_nand_host *host = chip->priv; +unsigned long timeout; +unsigned int nfc_addr_cmd =0 ; + +unsigned int cmd1 = command <<2 ; + +/* Set default settings: no cmd2, no addr cycle. read from nand */ +unsigned int cmd2 =0 ; +unsigned int vcmd2 =0 ; +int acycle =NFCADDR_CMD_ACYCLE_NONE ; +int csid =NFCADDR_CMD_CSID_3 ; +int dataen =NFCADDR_CMD_DATADIS ; +int nfcwr =NFCADDR_CMD_NFCRD ; +unsigned int addr1234 =0 ; +unsigned int cycle0 =0 ; +bool do_addr = true; + +dev_dbg (host->dev,"%s: cmd = 0x%02x, col = 0x%08x, page = 0x%08x\n" , + __func__, command, column, page_addr); + +switch (command) { +case NAND_CMD_RESET : + nfc_addr_cmd = cmd1 | acycle | csid | dataen | nfcwr; +nfc_send_command (host, nfc_addr_cmd, addr1234, cycle0); +udelay (chip->chip_delay); + +nfc_nand_command (mtd,NAND_CMD_STATUS ,-1 ,-1 ); + timeout = jiffies +msecs_to_jiffies (NFC_TIME_OUT_MS ); +while (!(chip->read_byte (mtd) &NAND_STATUS_READY )) { +if (time_after (jiffies, timeout)) { +dev_err (host->dev, +"Time out to wait status ready!\n" ); +break ; + } + } +return ; +case NAND_CMD_STATUS : + do_addr = false; +break ; +case NAND_CMD_PARAM : +case NAND_CMD_READID : + do_addr = false; + acycle =NFCADDR_CMD_ACYCLE_1 ; +if (column !=-1 ) + addr1234 = column; +break ; +case NAND_CMD_RNDOUT : + cmd2 =NAND_CMD_RNDOUTSTART <<10 ; + vcmd2 =NFCADDR_CMD_VCMD2 ; +break ; +case NAND_CMD_READ0 : +case NAND_CMD_READOOB : +if (command ==NAND_CMD_READOOB ) { + column += mtd->writesize; + command =NAND_CMD_READ0 ;/* only READ0 is valid */ + cmd1 = command <<2 ; + } + + cmd2 =NAND_CMD_READSTART <<10 ; + vcmd2 =NFCADDR_CMD_VCMD2 ; +break ; +/* For prgramming command, the cmd need set to write enable */ +case NAND_CMD_PAGEPROG : +case NAND_CMD_SEQIN : +case NAND_CMD_RNDIN : + nfcwr =NFCADDR_CMD_NFCWR ; +break ; +default : +break ; + } + +if (do_addr) + acycle =nfc_make_addr (mtd, column, page_addr, &addr1234, + &cycle0); + + nfc_addr_cmd = cmd1 | cmd2 | vcmd2 | acycle | csid | dataen | nfcwr; +nfc_send_command (host, nfc_addr_cmd, addr1234, cycle0); + +/* +* Program and erase have their own busy handlers status, sequential +* in, and deplete1 need no delay. +*/ +switch (command) { +case NAND_CMD_CACHEDPROG : +case NAND_CMD_PAGEPROG : +case NAND_CMD_ERASE1 : +case NAND_CMD_ERASE2 : +case NAND_CMD_RNDIN : +case NAND_CMD_STATUS : +case NAND_CMD_RNDOUT : +case NAND_CMD_SEQIN : +case NAND_CMD_READID : +return ; + +case NAND_CMD_READ0 : +/* fall through */ +default : +nfc_wait_interrupt (host,NFC_SR_RB_EDGE ); + } +} + +static struct platform_driver atmel_nand_nfc_driver;/* * Probe for the NAND device. */ @@ -1462,7 +1765,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)struct nand_chip *nand_chip;struct resource *mem;struct mtd_part_parser_data ppdata = {}; -int res; +int res, irq;struct pinctrl *pinctrl; mem =platform_get_resource (pdev,IORESOURCE_MEM ,0 );
drivers/mtd/nand/atmel_nand.c static int __init atmel_nand_probe(struct platform_device *pdev) · line 1787
Quoted 7 lines
drivers/mtd/nand/atmel_nand.c +4
-0@@ -1478,6 +1781,10 @@ static int __init atmel_nand_probe(struct platform_device *pdev)return -ENOMEM ; } + res =platform_driver_register (&atmel_nand_nfc_driver); +if (res) +printk (KERN_ERR "atmel_nand: can't register NFC driver\n" ); +
and this????
Quoted 12 lines
drivers/mtd/nand/atmel_nand.c +0
-1host->io_base =devm_request_and_ioremap (&pdev->dev, mem);if (host->io_base ==NULL ) {printk (KERN_ERR "atmel_nand: ioremap failed\n" );@@ -1505,7 +1812,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev)/* Set address of NAND IO lines */ nand_chip->IO_ADDR_R = host->io_base; nand_chip->IO_ADDR_W = host->io_base; - nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl; pinctrl =devm_pinctrl_get_select_default (&pdev->dev);if (IS_ERR (pinctrl)) {
drivers/mtd/nand/atmel_nand.c static int __init atmel_nand_probe(struct platform_device *pdev) · line 1822
Quoted 3 lines
drivers/mtd/nand/atmel_nand.c +0
-0@@ -1514,44 +1820,34 @@ static int __init atmel_nand_probe(struct platform_device *pdev) goto err_nand_ioremap; }
Best Regards,
J.
PATCH v3 3/6 mtd: atmel_nand: add Nand Flash Controller (NFC) support
Hi, Jean-Christophe PLAGNIOL-VILLARD
Quoted 11 lines · Jean-Christophe PLAGNIOL-VILLARD
drivers/mtd/nand/atmel_nand.c static int atmel_of_init_port(struct atmel_nand_host *host, · line 1413
Quoted 10 lines
drivers/mtd/nand/atmel_nand.c +3
-0+/* * Minimal-overhead PIO for data access. */ @@ -1341,6 +1409,9 @@ static int atmel_of_init_port(struct atmel_nand_host *host, host->has_pmecc =of_property_read_bool (np,"atmel,has-pmecc" ); +/* load the nfc driver if there is */ +of_platform_populate (np,NULL ,NULL , host->dev);what is this?????
Here I call of_platform_populate() to make sure the NFC driver's probe function is called.
In this version, in the dts file, the NFC device node is as sub-node of Atmel NAND device like:
nand0: nand at 40000000 {
compatible = "atmel,at91rm9200-nand";
#address-cells = <1>;
#size-cells = <1>;
ranges;
...
nfc at 70000000 {
compatible = "atmel,sama5d3-nfc";
reg = <
...
>;
};So when NAND driver is probed, It will populate its sub-node (i.e NFC device node). And this make
sure after the function (atmel_of_init_port) is called and the NFC driver's probe function is already
called and NFC resources should be initialized.
Quoted 258 lines
Quoted 258 lines
drivers/mtd/nand/atmel_nand.c +234
-1+if (!(board->ecc_mode ==NAND_ECC_HW ) || !host->has_pmecc)return 0 ;/* Not using PMECC */ @@ -1452,6 +1523,238 @@ static int __init atmel_hw_nand_init_params(struct platform_device *pdev,return 0 ; } +/* SMC interrupt service routine */ +static irqreturn_t hsmc_interrupt (int irq,void *dev_id) +{ +struct atmel_nand_host *host = dev_id; +u32 status, mask, pending; +irqreturn_t ret =IRQ_HANDLED ; + + status =nfc_readl (host->nfc->hsmc_regs,SR ); + mask =nfc_readl (host->nfc->hsmc_regs,IMR ); + pending = status & mask; + +if (pending &NFC_SR_XFR_DONE ) { +complete (&host->nfc->comp_nfc); +nfc_writel (host->nfc->hsmc_regs,IDR ,NFC_SR_XFR_DONE ); + }else if (pending &NFC_SR_RB_EDGE ) { +complete (&host->nfc->comp_nfc); +nfc_writel (host->nfc->hsmc_regs,IDR ,NFC_SR_RB_EDGE ); + }else if (pending &NFC_SR_CMD_DONE ) { +complete (&host->nfc->comp_nfc); +nfc_writel (host->nfc->hsmc_regs,IDR ,NFC_SR_CMD_DONE ); + }else { + ret =IRQ_NONE ; + } + +return ret; +} + +/* NFC(Nand Flash Controller) related functions */ +static int nfc_wait_interrupt (struct atmel_nand_host *host,u32 flag) +{ +unsigned long timeout; +init_completion (&host->nfc->comp_nfc); + +/* Enable interrupt that need to wait for */ +nfc_writel (host->nfc->hsmc_regs,IER , flag); + + timeout =wait_for_completion_timeout (&host->nfc->comp_nfc, +msecs_to_jiffies (NFC_TIME_OUT_MS )); +if (timeout) +return 0 ; + +/* Time out to wait for the interrupt */ +dev_err (host->dev,"Time out to wait for interrupt: 0x%08x\n" , flag); +return -ETIMEDOUT ; +} + +static int nfc_send_command (struct atmel_nand_host *host, +unsigned int cmd,unsigned int addr,unsigned char cycle0) +{ +unsigned long timeout; +dev_dbg (host->dev, +"nfc_cmd: 0x%08x, addr1234: 0x%08x, cycle0: 0x%02x\n" , + cmd, addr, cycle0); + + timeout = jiffies +msecs_to_jiffies (NFC_TIME_OUT_MS ); +while (nfc_cmd_readl (NFCADDR_CMD_NFCBUSY , host->nfc->base_cmd_regs) + &NFCADDR_CMD_NFCBUSY ) { +if (time_after (jiffies, timeout)) { +dev_err (host->dev, +"Time out to wait CMD_NFCBUSY ready!\n" ); +return -ETIMEDOUT ; + } + } +nfc_writel (host->nfc->hsmc_regs,CYCLE0 , cycle0); +nfc_cmd_addr1234_writel (cmd, addr, host->nfc->base_cmd_regs); +return nfc_wait_interrupt (host,NFC_SR_CMD_DONE ); +} + +static int nfc_device_ready (struct mtd_info *mtd) +{ +struct nand_chip *nand_chip = mtd->priv; +struct atmel_nand_host *host = nand_chip->priv; +if (!nfc_wait_interrupt (host,NFC_SR_RB_EDGE )) +return 1 ; +return 0 ; +} + +static void nfc_select_chip (struct mtd_info *mtd,int chip) +{ +struct nand_chip *nand_chip = mtd->priv; +struct atmel_nand_host *host = nand_chip->priv; + +if (chip ==-1 ) +nfc_writel (host->nfc->hsmc_regs,CTRL ,NFC_CTRL_DISABLE ); +else +nfc_writel (host->nfc->hsmc_regs,CTRL ,NFC_CTRL_ENABLE ); +} + +static int nfc_make_addr (struct mtd_info *mtd,int column,int page_addr, +unsigned int *addr1234,unsigned int *cycle0) +{ +struct nand_chip *chip = mtd->priv; + +int acycle =0 ; +unsigned char addr_bytes[8 ]; +int index =0 , bit_shift; + +BUG_ON (addr1234 ==NULL || cycle0 ==NULL ); + + *cycle0 =0 ; + *addr1234 =0 ; + +if (column !=-1 ) { +if (chip->options &NAND_BUSWIDTH_16 ) + column >>=1 ; + addr_bytes[acycle++] = column &0xff ; +if (mtd->writesize >512 ) + addr_bytes[acycle++] = (column >>8 ) &0xff ; + } + +if (page_addr !=-1 ) { + addr_bytes[acycle++] = page_addr &0xff ; + addr_bytes[acycle++] = (page_addr >>8 ) &0xff ; +if (chip->chipsize > (128 <<20 )) + addr_bytes[acycle++] = (page_addr >>16 ) &0xff ; + } + +if (acycle >4 ) + *cycle0 = addr_bytes[index++]; + +for (bit_shift =0 ; index < acycle; bit_shift +=8 ) + *addr1234 += addr_bytes[index++] << bit_shift; + +return acycle <<19 ;/* return acycle in cmd register */ +} + +static void nfc_nand_command (struct mtd_info *mtd,unsigned int command, +int column,int page_addr) +{ +struct nand_chip *chip = mtd->priv; +struct atmel_nand_host *host = chip->priv; +unsigned long timeout; +unsigned int nfc_addr_cmd =0 ; + +unsigned int cmd1 = command <<2 ; + +/* Set default settings: no cmd2, no addr cycle. read from nand */ +unsigned int cmd2 =0 ; +unsigned int vcmd2 =0 ; +int acycle =NFCADDR_CMD_ACYCLE_NONE ; +int csid =NFCADDR_CMD_CSID_3 ; +int dataen =NFCADDR_CMD_DATADIS ; +int nfcwr =NFCADDR_CMD_NFCRD ; +unsigned int addr1234 =0 ; +unsigned int cycle0 =0 ; +bool do_addr = true; + +dev_dbg (host->dev,"%s: cmd = 0x%02x, col = 0x%08x, page = 0x%08x\n" , + __func__, command, column, page_addr); + +switch (command) { +case NAND_CMD_RESET : + nfc_addr_cmd = cmd1 | acycle | csid | dataen | nfcwr; +nfc_send_command (host, nfc_addr_cmd, addr1234, cycle0); +udelay (chip->chip_delay); + +nfc_nand_command (mtd,NAND_CMD_STATUS ,-1 ,-1 ); + timeout = jiffies +msecs_to_jiffies (NFC_TIME_OUT_MS ); +while (!(chip->read_byte (mtd) &NAND_STATUS_READY )) { +if (time_after (jiffies, timeout)) { +dev_err (host->dev, +"Time out to wait status ready!\n" ); +break ; + } + } +return ; +case NAND_CMD_STATUS : + do_addr = false; +break ; +case NAND_CMD_PARAM : +case NAND_CMD_READID : + do_addr = false; + acycle =NFCADDR_CMD_ACYCLE_1 ; +if (column !=-1 ) + addr1234 = column; +break ; +case NAND_CMD_RNDOUT : + cmd2 =NAND_CMD_RNDOUTSTART <<10 ; + vcmd2 =NFCADDR_CMD_VCMD2 ; +break ; +case NAND_CMD_READ0 : +case NAND_CMD_READOOB : +if (command ==NAND_CMD_READOOB ) { + column += mtd->writesize; + command =NAND_CMD_READ0 ;/* only READ0 is valid */ + cmd1 = command <<2 ; + } + + cmd2 =NAND_CMD_READSTART <<10 ; + vcmd2 =NFCADDR_CMD_VCMD2 ; +break ; +/* For prgramming command, the cmd need set to write enable */ +case NAND_CMD_PAGEPROG : +case NAND_CMD_SEQIN : +case NAND_CMD_RNDIN : + nfcwr =NFCADDR_CMD_NFCWR ; +break ; +default : +break ; + } + +if (do_addr) + acycle =nfc_make_addr (mtd, column, page_addr, &addr1234, + &cycle0); + + nfc_addr_cmd = cmd1 | cmd2 | vcmd2 | acycle | csid | dataen | nfcwr; +nfc_send_command (host, nfc_addr_cmd, addr1234, cycle0); + +/* +* Program and erase have their own busy handlers status, sequential +* in, and deplete1 need no delay. +*/ +switch (command) { +case NAND_CMD_CACHEDPROG : +case NAND_CMD_PAGEPROG : +case NAND_CMD_ERASE1 : +case NAND_CMD_ERASE2 : +case NAND_CMD_RNDIN : +case NAND_CMD_STATUS : +case NAND_CMD_RNDOUT : +case NAND_CMD_SEQIN : +case NAND_CMD_READID : +return ; + +case NAND_CMD_READ0 : +/* fall through */ +default : +nfc_wait_interrupt (host,NFC_SR_RB_EDGE ); + } +} + +static struct platform_driver atmel_nand_nfc_driver;/* * Probe for the NAND device. */ @@ -1462,7 +1765,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)struct nand_chip *nand_chip;struct resource *mem;struct mtd_part_parser_data ppdata = {}; -int res; +int res, irq;struct pinctrl *pinctrl; mem =platform_get_resource (pdev,IORESOURCE_MEM ,0 );@@ -1478,6 +1781,10 @@ static int __init atmel_nand_probe(struct platform_device *pdev)return -ENOMEM ; }
Quoted 5 lines
drivers/mtd/nand/atmel_nand.c static int __init atmel_nand_probe(struct platform_device *pdev) · line 1787
Quoted 4 lines
drivers/mtd/nand/atmel_nand.c +4
-0+ res =platform_driver_register (&atmel_nand_nfc_driver); +if (res) +printk (KERN_ERR "atmel_nand: can't register NFC driver\n" ); +and this????
Did you mean the printk()?
Sorry, I forgot to replace the printk() function, I willuse dev_err() in next version.
Best Regards,
Josh Wu
Quoted 17 lines
Quoted 12 lines
drivers/mtd/nand/atmel_nand.c +0
-1host->io_base =devm_request_and_ioremap (&pdev->dev, mem);if (host->io_base ==NULL ) {printk (KERN_ERR "atmel_nand: ioremap failed\n" );@@ -1505,7 +1812,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev)/* Set address of NAND IO lines */ nand_chip->IO_ADDR_R = host->io_base; nand_chip->IO_ADDR_W = host->io_base; - nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl; pinctrl =devm_pinctrl_get_select_default (&pdev->dev);if (IS_ERR (pinctrl)) {drivers/mtd/nand/atmel_nand.c static int __init atmel_nand_probe(struct platform_device *pdev) · line 1822
Quoted 3 lines
drivers/mtd/nand/atmel_nand.c +0
-0@@ -1514,44 +1820,34 @@ static int __init atmel_nand_probe(struct platform_device *pdev) goto err_nand_ioremap; }Best Regards,
J.
PATCH v3 4/6 mtd: atmel_nand: enable Nand Flash Controller (NFC) read data via sram
In reply to Josh WuNFC has embedded sram which can use to transfer data. This patch enable reading nand flash via NFC SRAM. It will minimize the CPU overhead.
This driver has been tested on SAMA5D3X-EK with JFFS2, YAFFS2, UBIFS and mtd-utils.
Here puts the part of mtd_speedtest (read test) result as following:
Compare with non-NFC mtd_speedtest result, reading will reduce %45 cpu load with increase %80 speed.
- commands use to test:
# insmod /mnt/mtd_speedtest.ko dev=2 & # top -n 30 -d 1 | grep speedtest
- test result:
=================================================mtd_speedtest: MTD device: 2mtd_speedtest: MTD device size 41943040, eraseblock size 131072, page size 2048, count of eraseblocks 320, pages per eraseblock 64, OOB size 64mtd_speedtest: testing eraseblock read speed
509 495 root D 1164 0% 28% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root D 1164 0% 25% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root D 1164 0% 26% insmod /mnt/mtd_speedtest.ko dev=2 mtd_speedtest: eraseblock read speed is 9403 KiB/s mtd_speedtest: testing page read speed 509 495 root R 1164 0% 31% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root D 1164 0% 57% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root D 1164 0% 53% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root D 1164 0% 71% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: page read speed is 9258 KiB/s
---
v2 --> v3:
- if NFC sram address and size is specified then enable NFC sram read. Otherwise disable NFC sram read.
drivers/mtd/nand/atmel_nand.c | 163 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 157 insertions(+), 6 deletions(-)
drivers/mtd/nand/atmel_nand.c +157 -6
@@ -96,9 +96,13 @@ struct atmel_nfc {void __iomem *hsmc_regs;void __iomem *sram_bank0;dma_addr_t sram_bank0_phys; +bool use_nfc_sram;bool is_initialized;struct completion comp_nfc; + +/* Point to the sram bank which include readed data via NFC */ +void __iomem *data_in_sram; };static struct atmel_nfc nand_nfc;
@@ -251,24 +255,47 @@ static int atmel_nand_set_enable_ready_pins(struct mtd_info *mtd)return res; } } +return res; } +static void memcpy32_fromio (void *trg,const void __iomem *src,size_t size) +{ +int i; +u32 *t = trg; +const __iomem u32 *s = src; + +for (i =0 ; i < (size >>2 ); i++) + *t++ =readl_relaxed (s++); +} +/* * Minimal-overhead PIO for data access. */ static void atmel_read_buf8 (struct mtd_info *mtd,u8 *buf,int len) {struct nand_chip *nand_chip = mtd->priv; +struct atmel_nand_host *host = nand_chip->priv; -__raw_readsb (nand_chip->IO_ADDR_R, buf, len); +if (host->nfc && host->nfc->use_nfc_sram && host->nfc->data_in_sram) { +memcpy32_fromio (buf, host->nfc->data_in_sram, len); + host->nfc->data_in_sram += len; + }else { +__raw_readsb (nand_chip->IO_ADDR_R, buf, len); + } }static void atmel_read_buf16 (struct mtd_info *mtd,u8 *buf,int len) {struct nand_chip *nand_chip = mtd->priv; +struct atmel_nand_host *host = nand_chip->priv; -__raw_readsw (nand_chip->IO_ADDR_R, buf, len /2 ); +if (host->nfc && host->nfc->use_nfc_sram && host->nfc->data_in_sram) { +memcpy32_fromio (buf, host->nfc->data_in_sram, len); + host->nfc->data_in_sram += len; + }else { +__raw_readsw (nand_chip->IO_ADDR_R, buf, len /2 ); + } }static void atmel_write_buf8 (struct mtd_info *mtd,const u8 *buf,int len)
@@ -290,6 +317,40 @@ static void dma_complete_func(void *completion)complete (completion); } +static int nfc_set_sram_bank (struct atmel_nand_host *host,unsigned int bank) +{ +/* NFC only has two banks. Must be 0 or 1 */ +if (bank >1 ) +return -EINVAL ; + +if (bank) { +/* Only for a 2k-page or lower flash, NFC can handle 2 banks */ +if (host->mtd.writesize >2048 ) +return -EINVAL ; +nfc_writel (host->nfc->hsmc_regs,BANK ,ATMEL_HSMC_NFC_BANK1 ); + }else { +nfc_writel (host->nfc->hsmc_regs,BANK ,ATMEL_HSMC_NFC_BANK0 ); + } + +return 0 ; +} + +static uint nfc_get_sram_off (struct atmel_nand_host *host) +{ +if (nfc_readl (host->nfc->hsmc_regs,BANK ) &ATMEL_HSMC_NFC_BANK1 ) +return NFC_SRAM_BANK1_OFFSET ; +else +return 0 ; +} + +static dma_addr_t nfc_sram_phys (struct atmel_nand_host *host) +{ +if (nfc_readl (host->nfc->hsmc_regs,BANK ) &ATMEL_HSMC_NFC_BANK1 ) +return host->nfc->sram_bank0_phys +NFC_SRAM_BANK1_OFFSET ; +else +return host->nfc->sram_bank0_phys; +} +static int atmel_nand_dma_op (struct mtd_info *mtd,void *buf,int len,int is_read) {
@@ -303,6 +364,7 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,void *p = buf;int err = -EIO ;enum dma_data_direction dir = is_read ?DMA_FROM_DEVICE :DMA_TO_DEVICE ; +struct atmel_nfc *nfc = host->nfc;if (buf >= high_memory) goto err_buf;
@@ -319,7 +381,12 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len, }if (is_read) { - dma_src_addr = host->io_phys; +if (nfc && nfc->data_in_sram) + dma_src_addr =nfc_sram_phys (host) + (nfc->data_in_sram + - (nfc->sram_bank0 +nfc_get_sram_off (host))); +else + dma_src_addr = host->io_phys; + dma_dst_addr = phys_addr; }else { dma_src_addr = phys_addr;
@@ -346,6 +413,10 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,dma_async_issue_pending (host->dma_chan);wait_for_completion (&host->comp); +if (is_read && nfc && nfc->data_in_sram) +/* After read data from SRAM, need to increase the position */ + nfc->data_in_sram += len; + err =0 ; err_dma:
@@ -856,7 +927,8 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,unsigned long end_time;int bitflips =0 ; -pmecc_enable (host,NAND_ECC_READ ); +if (!host->nfc || !host->nfc->use_nfc_sram) +pmecc_enable (host,NAND_ECC_READ ); chip->read_buf (mtd, buf, eccsize); chip->read_buf (mtd, oob, mtd->oobsize);
@@ -1669,6 +1741,7 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,unsigned int addr1234 =0 ;unsigned int cycle0 =0 ;bool do_addr = true; + host->nfc->data_in_sram =NULL ;dev_dbg (host->dev,"%s: cmd = 0x%02x, col = 0x%08x, page = 0x%08x\n" , __func__, command, column, page_addr);
@@ -1710,6 +1783,16 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command, command =NAND_CMD_READ0 ;/* only READ0 is valid */ cmd1 = command <<2 ; } +if (host->nfc->use_nfc_sram) { +/* Enable Data transfer to sram */ + dataen =NFCADDR_CMD_DATAEN ; + +/* Need enable PMECC now, since NFC will transfer +* data in bus after sending nfc read command. +*/ +if (chip->ecc.mode ==NAND_ECC_HW && host->has_pmecc) +pmecc_enable (host,NAND_ECC_READ ); + } cmd2 =NAND_CMD_READSTART <<10 ; vcmd2 =NFCADDR_CMD_VCMD2 ;
@@ -1731,6 +1814,10 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command, nfc_addr_cmd = cmd1 | cmd2 | vcmd2 | acycle | csid | dataen | nfcwr;nfc_send_command (host, nfc_addr_cmd, addr1234, cycle0); +if (dataen ==NFCADDR_CMD_DATAEN ) +if (nfc_wait_interrupt (host,NFC_SR_XFR_DONE )) +dev_err (host->dev,"something wrong, No XFR_DONE interrupt comes.\n" ); +/* * Program and erase have their own busy handlers status, sequential * in, and deplete1 need no delay.
@@ -1748,12 +1835,65 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,return ;case NAND_CMD_READ0 : +if (dataen ==NFCADDR_CMD_DATAEN ) { + host->nfc->data_in_sram = host->nfc->sram_bank0 + +nfc_get_sram_off (host); +return ; + }/* fall through */ default :nfc_wait_interrupt (host,NFC_SR_RB_EDGE ); } } +static int nfc_sram_init (struct mtd_info *mtd) +{ +struct nand_chip *chip = mtd->priv; +struct atmel_nand_host *host = chip->priv; +int res =0 ; + +/* Initialize the NFC CFG register */ +unsigned int cfg_nfc =0 ; + +/* set page size and oob layout */ +switch (mtd->writesize) { +case 512 : + cfg_nfc =NFC_CFG_PAGESIZE_512 ; +break ; +case 1024 : + cfg_nfc =NFC_CFG_PAGESIZE_1024 ; +break ; +case 2048 : + cfg_nfc =NFC_CFG_PAGESIZE_2048 ; +break ; +case 4096 : + cfg_nfc =NFC_CFG_PAGESIZE_4096 ; +break ; +case 8192 : + cfg_nfc =NFC_CFG_PAGESIZE_8192 ; +break ; +default : +dev_err (host->dev,"Unsupported page size for NFC.\n" ); + res = -ENXIO ; +return res; + } + +/* oob bytes size = (NFCSPARESIZE + 1) * 4 +* Max support spare size is 512 bytes. */ + cfg_nfc |= (((mtd->oobsize /4 ) -1 ) <<24 &NFC_CFG_NFC_SPARESIZE ); +/* default set a max timeout */ + cfg_nfc |=NFC_CFG_RSPARE | +NFC_CFG_NFC_DTOCYC |NFC_CFG_NFC_DTOMUL ; + +nfc_writel (host->nfc->hsmc_regs,CFG , cfg_nfc); + +nfc_set_sram_bank (host,0 ); + +dev_info (host->dev,"Using NFC Sram read\n" ); + +return 0 ; +} +static struct platform_driver atmel_nand_nfc_driver;/* * Probe for the NAND device.
@@ -1928,6 +2068,15 @@ static int __init atmel_nand_probe(struct platform_device *pdev) goto err_hw_ecc; } +/* initialize the nfc configuration register */ +if (host->nfc && host->nfc->use_nfc_sram) { + res =nfc_sram_init (mtd); +if (res) { + host->nfc->use_nfc_sram = false; +dev_err (host->dev,"Disable use nfc sram for data transfer.\n" ); + } + } +/* second phase scan */ if (nand_scan_tail (mtd)) { res = -ENXIO ;
@@ -2009,11 +2158,13 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) nfc_sram =platform_get_resource (pdev,IORESOURCE_MEM ,2 );if (nfc_sram) { nfc->sram_bank0 =devm_ioremap_resource (&pdev->dev, nfc_sram); -if (IS_ERR (nfc->sram_bank0)) +if (IS_ERR (nfc->sram_bank0)) {dev_warn (&pdev->dev,"Fail to ioremap the NFC sram with error: %ld. So disable NFC sram.\n" ,PTR_ERR (nfc->sram_bank0)); -else + }else { + nfc->use_nfc_sram = true; nfc->sram_bank0_phys = (dma_addr_t )nfc_sram->start; + } } nfc->is_initialized = true;
Signature · 1 line
1.7.9.5
PATCH 4/6 mtd: atmel_nand: enable Nand Flash Controller (NFC) read data via sram
Quoted 6 lines · Josh Wu
NFC has embedded sram which can use to transfer data. This patch enable reading nand flash via NFC SRAM. It will minimize the CPU overhead.
This driver has been tested on SAMA5D3X-EK with JFFS2, YAFFS2, UBIFS and mtd-utils.
Quoted 8 lines
Here puts the part of
mtd_speedtest(read test) result as following:
Compare with non-NFCmtd_speedtestresult, reading will reduce %45 cpu load with increase %80 speed.- commands use to test:
# insmod /mnt/mtd_speedtest.ko dev=2 & # top -n 30 -d 1 | grep speedtest
Best Regards,
J.
Quoted 314 lines
- test result:
=================================================mtd_speedtest: MTD device: 2mtd_speedtest: MTD device size 41943040, eraseblock size 131072, page size 2048, count of eraseblocks 320, pages per eraseblock 64, OOB size 64mtd_speedtest: testing eraseblock read speed509 495 root D 1164 0% 28% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root D 1164 0% 25% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root D 1164 0% 26% insmod /mnt/mtd_speedtest.ko dev=2 mtd_speedtest: eraseblock read speed is 9403 KiB/s mtd_speedtest: testing page read speed 509 495 root R 1164 0% 31% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root D 1164 0% 57% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root D 1164 0% 53% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root D 1164 0% 71% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: page read speed is 9258 KiB/sSigned-off-by Josh Wu <[email protected]>---
v2 --> v3:
- if NFC sram address and size is specified then enable NFC sram read. Otherwise disable NFC sram read.drivers/mtd/nand/atmel_nand.c | 163 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 157 insertions(+), 6 deletions(-)drivers/mtd/nand/atmel_nand.c +157
-6@@ -96,9 +96,13 @@ struct atmel_nfc {void __iomem *hsmc_regs;void __iomem *sram_bank0;dma_addr_t sram_bank0_phys; +bool use_nfc_sram;bool is_initialized;struct completion comp_nfc; + +/* Point to the sram bank which include readed data via NFC */ +void __iomem *data_in_sram; };static struct atmel_nfc nand_nfc;@@ -251,24 +255,47 @@ static int atmel_nand_set_enable_ready_pins(struct mtd_info *mtd)return res; } } +return res; } +static void memcpy32_fromio (void *trg,const void __iomem *src,size_t size) +{ +int i; +u32 *t = trg; +const __iomem u32 *s = src; + +for (i =0 ; i < (size >>2 ); i++) + *t++ =readl_relaxed (s++); +} +/* * Minimal-overhead PIO for data access. */ static void atmel_read_buf8 (struct mtd_info *mtd,u8 *buf,int len) {struct nand_chip *nand_chip = mtd->priv; +struct atmel_nand_host *host = nand_chip->priv; -__raw_readsb (nand_chip->IO_ADDR_R, buf, len); +if (host->nfc && host->nfc->use_nfc_sram && host->nfc->data_in_sram) { +memcpy32_fromio (buf, host->nfc->data_in_sram, len); + host->nfc->data_in_sram += len; + }else { +__raw_readsb (nand_chip->IO_ADDR_R, buf, len); + } }static void atmel_read_buf16 (struct mtd_info *mtd,u8 *buf,int len) {struct nand_chip *nand_chip = mtd->priv; +struct atmel_nand_host *host = nand_chip->priv; -__raw_readsw (nand_chip->IO_ADDR_R, buf, len /2 ); +if (host->nfc && host->nfc->use_nfc_sram && host->nfc->data_in_sram) { +memcpy32_fromio (buf, host->nfc->data_in_sram, len); + host->nfc->data_in_sram += len; + }else { +__raw_readsw (nand_chip->IO_ADDR_R, buf, len /2 ); + } }static void atmel_write_buf8 (struct mtd_info *mtd,const u8 *buf,int len)@@ -290,6 +317,40 @@ static void dma_complete_func(void *completion)complete (completion); } +static int nfc_set_sram_bank (struct atmel_nand_host *host,unsigned int bank) +{ +/* NFC only has two banks. Must be 0 or 1 */ +if (bank >1 ) +return -EINVAL ; + +if (bank) { +/* Only for a 2k-page or lower flash, NFC can handle 2 banks */ +if (host->mtd.writesize >2048 ) +return -EINVAL ; +nfc_writel (host->nfc->hsmc_regs,BANK ,ATMEL_HSMC_NFC_BANK1 ); + }else { +nfc_writel (host->nfc->hsmc_regs,BANK ,ATMEL_HSMC_NFC_BANK0 ); + } + +return 0 ; +} + +static uint nfc_get_sram_off (struct atmel_nand_host *host) +{ +if (nfc_readl (host->nfc->hsmc_regs,BANK ) &ATMEL_HSMC_NFC_BANK1 ) +return NFC_SRAM_BANK1_OFFSET ; +else +return 0 ; +} + +static dma_addr_t nfc_sram_phys (struct atmel_nand_host *host) +{ +if (nfc_readl (host->nfc->hsmc_regs,BANK ) &ATMEL_HSMC_NFC_BANK1 ) +return host->nfc->sram_bank0_phys +NFC_SRAM_BANK1_OFFSET ; +else +return host->nfc->sram_bank0_phys; +} +static int atmel_nand_dma_op (struct mtd_info *mtd,void *buf,int len,int is_read) {@@ -303,6 +364,7 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,void *p = buf;int err = -EIO ;enum dma_data_direction dir = is_read ?DMA_FROM_DEVICE :DMA_TO_DEVICE ; +struct atmel_nfc *nfc = host->nfc;if (buf >= high_memory) goto err_buf;@@ -319,7 +381,12 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len, }if (is_read) { - dma_src_addr = host->io_phys; +if (nfc && nfc->data_in_sram) + dma_src_addr =nfc_sram_phys (host) + (nfc->data_in_sram + - (nfc->sram_bank0 +nfc_get_sram_off (host))); +else + dma_src_addr = host->io_phys; + dma_dst_addr = phys_addr; }else { dma_src_addr = phys_addr;@@ -346,6 +413,10 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,dma_async_issue_pending (host->dma_chan);wait_for_completion (&host->comp); +if (is_read && nfc && nfc->data_in_sram) +/* After read data from SRAM, need to increase the position */ + nfc->data_in_sram += len; + err =0 ; err_dma:@@ -856,7 +927,8 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,unsigned long end_time;int bitflips =0 ; -pmecc_enable (host,NAND_ECC_READ ); +if (!host->nfc || !host->nfc->use_nfc_sram) +pmecc_enable (host,NAND_ECC_READ ); chip->read_buf (mtd, buf, eccsize); chip->read_buf (mtd, oob, mtd->oobsize);@@ -1669,6 +1741,7 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,unsigned int addr1234 =0 ;unsigned int cycle0 =0 ;bool do_addr = true; + host->nfc->data_in_sram =NULL ;dev_dbg (host->dev,"%s: cmd = 0x%02x, col = 0x%08x, page = 0x%08x\n" , __func__, command, column, page_addr);@@ -1710,6 +1783,16 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command, command =NAND_CMD_READ0 ;/* only READ0 is valid */ cmd1 = command <<2 ; } +if (host->nfc->use_nfc_sram) { +/* Enable Data transfer to sram */ + dataen =NFCADDR_CMD_DATAEN ; + +/* Need enable PMECC now, since NFC will transfer +* data in bus after sending nfc read command. +*/ +if (chip->ecc.mode ==NAND_ECC_HW && host->has_pmecc) +pmecc_enable (host,NAND_ECC_READ ); + } cmd2 =NAND_CMD_READSTART <<10 ; vcmd2 =NFCADDR_CMD_VCMD2 ;@@ -1731,6 +1814,10 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command, nfc_addr_cmd = cmd1 | cmd2 | vcmd2 | acycle | csid | dataen | nfcwr;nfc_send_command (host, nfc_addr_cmd, addr1234, cycle0); +if (dataen ==NFCADDR_CMD_DATAEN ) +if (nfc_wait_interrupt (host,NFC_SR_XFR_DONE )) +dev_err (host->dev,"something wrong, No XFR_DONE interrupt comes.\n" ); +/* * Program and erase have their own busy handlers status, sequential * in, and deplete1 need no delay. @@ -1748,12 +1835,65 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,return ;case NAND_CMD_READ0 : +if (dataen ==NFCADDR_CMD_DATAEN ) { + host->nfc->data_in_sram = host->nfc->sram_bank0 + +nfc_get_sram_off (host); +return ; + }/* fall through */ default :nfc_wait_interrupt (host,NFC_SR_RB_EDGE ); } } +static int nfc_sram_init (struct mtd_info *mtd) +{ +struct nand_chip *chip = mtd->priv; +struct atmel_nand_host *host = chip->priv; +int res =0 ; + +/* Initialize the NFC CFG register */ +unsigned int cfg_nfc =0 ; + +/* set page size and oob layout */ +switch (mtd->writesize) { +case 512 : + cfg_nfc =NFC_CFG_PAGESIZE_512 ; +break ; +case 1024 : + cfg_nfc =NFC_CFG_PAGESIZE_1024 ; +break ; +case 2048 : + cfg_nfc =NFC_CFG_PAGESIZE_2048 ; +break ; +case 4096 : + cfg_nfc =NFC_CFG_PAGESIZE_4096 ; +break ; +case 8192 : + cfg_nfc =NFC_CFG_PAGESIZE_8192 ; +break ; +default : +dev_err (host->dev,"Unsupported page size for NFC.\n" ); + res = -ENXIO ; +return res; + } + +/* oob bytes size = (NFCSPARESIZE + 1) * 4 +* Max support spare size is 512 bytes. */ + cfg_nfc |= (((mtd->oobsize /4 ) -1 ) <<24 &NFC_CFG_NFC_SPARESIZE ); +/* default set a max timeout */ + cfg_nfc |=NFC_CFG_RSPARE | +NFC_CFG_NFC_DTOCYC |NFC_CFG_NFC_DTOMUL ; + +nfc_writel (host->nfc->hsmc_regs,CFG , cfg_nfc); + +nfc_set_sram_bank (host,0 ); + +dev_info (host->dev,"Using NFC Sram read\n" ); + +return 0 ; +} +static struct platform_driver atmel_nand_nfc_driver;/* * Probe for the NAND device. @@ -1928,6 +2068,15 @@ static int __init atmel_nand_probe(struct platform_device *pdev) goto err_hw_ecc; } +/* initialize the nfc configuration register */ +if (host->nfc && host->nfc->use_nfc_sram) { + res =nfc_sram_init (mtd); +if (res) { + host->nfc->use_nfc_sram = false; +dev_err (host->dev,"Disable use nfc sram for data transfer.\n" ); + } + } +/* second phase scan */ if (nand_scan_tail (mtd)) { res = -ENXIO ;@@ -2009,11 +2158,13 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) nfc_sram =platform_get_resource (pdev,IORESOURCE_MEM ,2 );if (nfc_sram) { nfc->sram_bank0 =devm_ioremap_resource (&pdev->dev, nfc_sram); -if (IS_ERR (nfc->sram_bank0)) +if (IS_ERR (nfc->sram_bank0)) {dev_warn (&pdev->dev,"Fail to ioremap the NFC sram with error: %ld. So disable NFC sram.\n" ,PTR_ERR (nfc->sram_bank0)); -else + }else { + nfc->use_nfc_sram = true; nfc->sram_bank0_phys = (dma_addr_t )nfc_sram->start; + } } nfc->is_initialized = true;Signature · 1 line
1.7.9.5
PATCH v3 5/6 mtd: atmel_nand: enable Nand Flash Controller (NFC) write via sram
In reply to Josh WuThis patch enable writing nand flash via NFC SRAM. It will minimize the CPU overhead. The SRAM write only support ECC_NONE and ECC_HW with PMECC.
To enable this NFC write by SRAM feature, you can add a string in dts under NFC driver node.
This driver has been tested on SAMA5D3X-EK with JFFS2, YAFFS2, UBIFS and mtd-utils.
Here is part of mtd_speedtest (writing test) result, compare with non-NFC writing, it reduces %65 cpu load with loss %12 speed.
- commands use to test:
# insmod /mnt/mtd_speedtest.ko dev=2 & # top -n 30 -d 1 | grep speedtest
- test result:
=================================================mtd_speedtest: MTD device: 2mtd_speedtest: MTD device size 41943040, eraseblock size 131072, page size 2048, count of eraseblocks 320, pages per eraseblock 64, OOB size 64mtd_speedtest: testing eraseblock write speed
509 495 root D 1164 0% 7% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root D 1164 0% 8% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root R 1164 0% 5% insmod /mnt/mtd_speedtest.ko dev=2 mtd_speedtest: eraseblock write speed is 5194 KiB/s mtd_speedtest: testing page write speed 509 495 root D 1164 0% 32% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root D 1164 0% 27% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root D 1164 0% 25% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root D 1164 0% 30% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: page write speed is 5024 KiB/s
---
v2 --> v3:
- use a property of NFC node to enable/disable NFC write via sram.
.../devicetree/bindings/mtd/atmel-nand.txt | 2 + drivers/mtd/nand/atmel_nand.c | 107 ++++++++++++++++++-- 2 files changed, 103 insertions(+), 6 deletions(-)
Documentation/devicetree/bindings/mtd/atmel-nand.txt +2 -0
@@ -35,6 +35,8 @@ Optional properties: - reg : should specify the address and size used for NFC command registers, NFC registers and NFC Sram. NFC Sram address and size can be absent if don't want to use it. + - Optional properties: + - atmel,write-by-sram: boolean to enable NFC write by sram. Examples: nand0: nand at 40000000,0 {
drivers/mtd/nand/atmel_nand.c +101 -6
168 lines not on this page · raw message
Signature · 1 line
1.7.9.5
PATCH 5/6 mtd: atmel_nand: enable Nand Flash Controller (NFC) write via sram
Quoted 30 lines · Josh Wu
This patch enable writing nand flash via NFC SRAM. It will minimize the CPU overhead. The SRAM write only support
ECC_NONEandECC_HWwith PMECC.To enable this NFC write by SRAM feature, you can add a string in dts under NFC driver node.
This driver has been tested on SAMA5D3X-EK with JFFS2, YAFFS2, UBIFS and mtd-utils.
Here is part of
mtd_speedtest(writing test) result, compare with non-NFC writing, it reduces %65 cpu load with loss %12 speed.- commands use to test:
# insmod /mnt/mtd_speedtest.ko dev=2 & # top -n 30 -d 1 | grep speedtest- test result:
=================================================mtd_speedtest: MTD device: 2mtd_speedtest: MTD device size 41943040, eraseblock size 131072, page size 2048, count of eraseblocks 320, pages per eraseblock 64, OOB size 64mtd_speedtest: testing eraseblock write speed509 495 root D 1164 0% 7% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root D 1164 0% 8% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root R 1164 0% 5% insmod /mnt/mtd_speedtest.ko dev=2 mtd_speedtest: eraseblock write speed is 5194 KiB/s mtd_speedtest: testing page write speed 509 495 root D 1164 0% 32% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root D 1164 0% 27% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root D 1164 0% 25% insmod /mnt/mtd_speedtest.ko dev=2 509 495 root D 1164 0% 30% insmod /mnt/mtd_speedtest.ko dev=2
Quoted 3 lines
mtd_speedtest: page write speed is 5024 KiB/sSigned-off-by Josh Wu <[email protected]>
Best Regards,
J.
Quoted 204 lines
---
v2 --> v3:
- use a property of NFC node to enable/disable NFC write via sram..../devicetree/bindings/mtd/atmel-nand.txt | 2 + drivers/mtd/nand/atmel_nand.c | 107 ++++++++++++++++++-- 2 files changed, 103 insertions(+), 6 deletions(-)Documentation/devicetree/bindings/mtd/atmel-nand.txt +2
-0@@ -35,6 +35,8 @@ Optional properties: - reg : should specify the address and size used for NFC command registers, NFC registers and NFC Sram. NFC Sram address and size can be absent if don't want to use it. + - Optional properties: + - atmel,write-by-sram: boolean to enable NFC write by sram. Examples: nand0: nand at 40000000,0 {drivers/mtd/nand/atmel_nand.c +101
-6@@ -97,12 +97,14 @@ struct atmel_nfc {void __iomem *sram_bank0;dma_addr_t sram_bank0_phys;bool use_nfc_sram; +bool write_by_sram;bool is_initialized;struct completion comp_nfc;/* Point to the sram bank which include readed data via NFC */ void __iomem *data_in_sram; +bool will_write_sram; };static struct atmel_nfc nand_nfc;@@ -269,6 +271,16 @@ static void memcpy32_fromio(void *trg, const void __iomem *src, size_t size) *t++ =readl_relaxed (s++); } +static void memcpy32_toio (void __iomem *trg,const void *src,int size) +{ +int i; +u32 __iomem *t = trg; +const u32 *s = src; + +for (i =0 ; i < (size >>2 ); i++) +writel_relaxed (*s++, t++); +} +/* * Minimal-overhead PIO for data access. */ @@ -390,7 +402,11 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len, dma_dst_addr = phys_addr; }else { dma_src_addr = phys_addr; - dma_dst_addr = host->io_phys; + +if (nfc && nfc->write_by_sram) + dma_dst_addr =nfc_sram_phys (host); +else + dma_dst_addr = host->io_phys; } tx = dma_dev->device_prep_dma_memcpy(host->dma_chan, dma_dst_addr,@@ -961,9 +977,10 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,int i, j;unsigned long end_time; -pmecc_enable (host,NAND_ECC_WRITE ); - - chip->write_buf (mtd, (u8 *)buf, mtd->writesize); +if (!host->nfc || !host->nfc->write_by_sram) { +pmecc_enable (host,NAND_ECC_WRITE ); + chip->write_buf (mtd, (u8 *)buf, mtd->writesize); + } end_time = jiffies +msecs_to_jiffies (PMECC_MAX_TIMEOUT_MS );while ((pmecc_readl_relaxed (host->ecc,SR ) &PMECC_SR_BUSY )) {@@ -1802,6 +1819,8 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,case NAND_CMD_SEQIN :case NAND_CMD_RNDIN : nfcwr =NFCADDR_CMD_NFCWR ; +if (host->nfc->will_write_sram && command ==NAND_CMD_SEQIN ) + dataen =NFCADDR_CMD_DATAEN ;break ;default :break ;@@ -1846,6 +1865,68 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command, } } +static int nfc_sram_write_page (struct mtd_info *mtd,struct nand_chip *chip, +uint32_t offset,int data_len,const uint8_t *buf, +int oob_required,int page,int cached,int raw) +{ +int cfg, len; +int status =0 ; +struct atmel_nand_host *host = chip->priv; +void __iomem *sram = host->nfc->sram_bank0 +nfc_get_sram_off (host); + +/* Subpage write is not supported */ +if (offset || (data_len < mtd->writesize)) +return -EINVAL ; + + cfg =nfc_readl (host->nfc->hsmc_regs,CFG ); + len = mtd->writesize; + +if (unlikely (raw)) { + len += mtd->oobsize; +nfc_writel (host->nfc->hsmc_regs,CFG , cfg |NFC_CFG_WSPARE ); + }else +nfc_writel (host->nfc->hsmc_regs,CFG , cfg & ~NFC_CFG_WSPARE ); + +/* Copy page data to sram that will write to nand via NFC */ +if (use_dma) { +if (atmel_nand_dma_op (mtd, (void *)buf, len,0 ) !=0 ) +/* Fall back to use cpu copy */ +memcpy32_toio (sram, buf, len); + }else { +memcpy32_toio (sram, buf, len); + } + +if (chip->ecc.mode ==NAND_ECC_HW && host->has_pmecc) +/* +* When use NFC sram, need set up PMECC before send +* NAND_CMD_SEQIN command. Since when the nand command +* is sent, nfc will do transfer from sram and nand. +*/ +pmecc_enable (host,NAND_ECC_WRITE ); + + host->nfc->will_write_sram = true; + chip->cmdfunc (mtd,NAND_CMD_SEQIN ,0x00 , page); + host->nfc->will_write_sram = false; + +if (likely (!raw)) +/* Need to write ecc into oob */ + status = chip->ecc.write_page (mtd, chip, buf, oob_required); + +if (status <0 ) +return status; + + chip->cmdfunc (mtd,NAND_CMD_PAGEPROG ,-1 ,-1 ); + status = chip->waitfunc (mtd, chip); + +if ((status &NAND_STATUS_FAIL ) && (chip->errstat)) + status = chip->errstat (mtd, chip,FL_WRITING , status, page); + +if (status &NAND_STATUS_FAIL ) +return -EIO ; + +return 0 ; +} +static int nfc_sram_init (struct mtd_info *mtd) {struct nand_chip *chip = mtd->priv;@@ -1887,10 +1968,20 @@ static int nfc_sram_init(struct mtd_info *mtd)nfc_writel (host->nfc->hsmc_regs,CFG , cfg_nfc); + host->nfc->will_write_sram = false;nfc_set_sram_bank (host,0 ); -dev_info (host->dev,"Using NFC Sram read\n" ); +/* Use Write page with NFC SRAM only for PMECC or ECC NONE. */ +if (host->nfc->write_by_sram) { +if ((chip->ecc.mode ==NAND_ECC_HW && host->has_pmecc) || + chip->ecc.mode ==NAND_ECC_NONE ) + chip->write_page = nfc_sram_write_page; +else + host->nfc->write_by_sram = false; + } +dev_info (host->dev,"Using NFC Sram read %s\n" , + host->nfc->write_by_sram ?"and write" :"" );return 0 ; }@@ -2164,11 +2255,15 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) }else { nfc->use_nfc_sram = true; nfc->sram_bank0_phys = (dma_addr_t )nfc_sram->start; + +if (pdev->dev.of_node) + nfc->write_by_sram =of_property_read_bool ( + pdev->dev.of_node, +"atmel,write-by-sram" ); } } nfc->is_initialized = true; -dev_info (&pdev->dev,"NFC is probed.\n" );return 0 ; }Signature · 1 line
1.7.9.5
PATCH v3 6/6 mtd: ofpart: add compatible check for child nodes
In reply to Josh WuIf the child node has compatible property then it is a driver not partition.
--- drivers/mtd/ofpart.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
drivers/mtd/ofpart.c +13 -1
@@ -20,6 +20,10 @@#include <linux/slab.h> #include <linux/mtd/partitions.h> +static bool node_has_compatible (struct device_node *pp,int *len) +{ +return of_get_property (pp,"compatible" , len); +}static int parse_ofpart_partitions (struct mtd_info *master,struct mtd_partition **pparts,struct mtd_part_parser_data *data)
@@ -40,8 +44,13 @@ static int parse_ofpart_partitions(struct mtd_info *master,/* First count the subnodes */ pp =NULL ; nr_parts =0 ; -while ((pp =of_get_next_child (node, pp))) +while ((pp =of_get_next_child (node, pp))) { +int len; +if (node_has_compatible (pp, &len)) +continue ; + nr_parts++; + }if (nr_parts ==0 )return 0 ;
@@ -57,6 +66,9 @@ static int parse_ofpart_partitions(struct mtd_info *master,int len;int a_cells, s_cells; +if (node_has_compatible (pp, &len)) +continue ; + reg =of_get_property (pp,"reg" , &len);if (!reg) { nr_parts--;
Signature · 1 line
1.7.9.5
PATCH 6/6 mtd: ofpart: add compatible check for child nodes
hello.
Quoted 12 lines · Josh Wu
If the child node has compatible property then it is a driver not partition.
Signed-off-by Josh Wu <[email protected]>--- drivers/mtd/ofpart.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)drivers/mtd/ofpart.c +0
-0
[...]
drivers/mtd/ofpart.c static int parse_ofpart_partitions(struct mtd_info *master, · line 47
Quoted 6 lines
drivers/mtd/ofpart.c +1
-1@@ -40,8 +44,13 @@ static int parse_ofpart_partitions(struct mtd_info *master,/* First count the subnodes */ pp =NULL ; nr_parts =0 ; -while ((pp =of_get_next_child (node, pp))) +while ((pp =of_get_next_child (node, pp))) {
Assignment in *while*? Is scripts/checkpatch.pl happy about that?
drivers/mtd/ofpart.c static int parse_ofpart_partitions(struct mtd_info *master, · line 48
Quoted 1 line
drivers/mtd/ofpart.c +1
-0+int len;
Empty line wouldn't hurt here, after declaration.
drivers/mtd/ofpart.c static int parse_ofpart_partitions(struct mtd_info *master, · line 56
Quoted 8 lines
drivers/mtd/ofpart.c +4
-0+if (node_has_compatible (pp, &len)) +continue ; + nr_parts++; + }if (nr_parts ==0 )return 0 ;
WBR, Sergei
PATCH v3 6/6 mtd: ofpart: add compatible check for child nodes
Hi, Sergei
Quoted 18 lines · Sergei Shtylyov
hello.
Quoted 13 lines · Josh Wu
If the child node has compatible property then it is a driver not partition.
Signed-off-by Josh Wu <[email protected]>--- drivers/mtd/ofpart.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)drivers/mtd/ofpart.c +0
-0[...]
Quoted 9 lines
drivers/mtd/ofpart.c static int parse_ofpart_partitions(struct mtd_info · line 48
Quoted 7 lines
drivers/mtd/ofpart.c +1
-1@@ -40,8 +44,13 @@ static int parse_ofpart_partitions(struct mtd_info *master,/* First count the subnodes */ pp =NULL ; nr_parts =0 ; -while ((pp =of_get_next_child (node, pp))) +while ((pp =of_get_next_child (node, pp))) {Assignment in *while*? Is
scripts/checkpatch.plhappy about that?
yes, checkpatch.pl has no complain ;-)
Quoted 4 lines
drivers/mtd/ofpart.c static int parse_ofpart_partitions(struct mtd_info *master, · line 48
Quoted 2 lines
drivers/mtd/ofpart.c +1
-0+int len;Empty line wouldn't hurt here, after declaration.
Ok, as Brian said, I will no need to use a 'int len' here. So I will remove those declaration.
Quoted 7 lines
Quoted 7 lines
drivers/mtd/ofpart.c +4
-0+if (node_has_compatible (pp, &len)) +continue ; + nr_parts++; + }
Quoted 5 lines
Quoted 2 lines
drivers/mtd/ofpart.c +0
-0if (nr_parts ==0 )return 0;WBR, Sergei
Thanks.
Best Regards,
Josh Wu
PATCH 6/6 mtd: ofpart: add compatible check for child nodes
Hello.
Quoted 24 lines · Josh Wu
Quoted 14 lines
Quoted 13 lines
If the child node has compatible property then it is a driver not partition.
Signed-off-by Josh Wu <[email protected]>--- drivers/mtd/ofpart.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)drivers/mtd/ofpart.c +0
-0[...]
Quoted 9 lines
drivers/mtd/ofpart.c static int parse_ofpart_partitions(struct mtd_info · line 48
Quoted 7 lines
drivers/mtd/ofpart.c +1
-1@@ -40,8 +44,13 @@ static int parse_ofpart_partitions(struct mtd_info *master,/* First count the subnodes */ pp =NULL ; nr_parts =0 ; -while ((pp =of_get_next_child (node, pp))) +while ((pp =of_get_next_child (node, pp))) {Assignment in *while*? Is
scripts/checkpatch.plhappy about that?
Quoted 1 line
yes, checkpatch.pl has no complain ;-)
It seems checkpatch.pl only complains about *if*. Not very consistent...
WBR, Sergei
PATCH 6/6 mtd: ofpart: add compatible check for child nodes
In reply to Josh WuHi Josh,
Quoted 12 lines · Josh Wu
If the child node has compatible property then it is a driver not partition.
Signed-off-by Josh Wu <[email protected]>--- drivers/mtd/ofpart.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)drivers/mtd/ofpart.c +0
-0
drivers/mtd/ofpart.c line 26
Quoted 7 lines
drivers/mtd/ofpart.c +4
-0@@ -20,6 +20,10 @@#include <linux/slab.h> #include <linux/mtd/partitions.h> +static bool node_has_compatible (struct device_node *pp,int *len) +{ +return of_get_property (pp,"compatible" , len); +}
The way the interface is named, it seems like a user only would ever need the bool return value, not the implicit 'len' return value. So I would write it like this:
static bool node_has_compatible(struct device_node *pp)
{
return of_get_property(pp, "compatible", NULL);
}drivers/mtd/ofpart.c static int parse_ofpart_partitions(struct mtd_info *master, · line 49
Quoted 11 lines
drivers/mtd/ofpart.c +3
-1static int parse_ofpart_partitions (struct mtd_info *master,struct mtd_partition **pparts,struct mtd_part_parser_data *data)@@ -40,8 +44,13 @@ static int parse_ofpart_partitions(struct mtd_info *master,/* First count the subnodes */ pp =NULL ; nr_parts =0 ; -while ((pp =of_get_next_child (node, pp))) +while ((pp =of_get_next_child (node, pp))) { +int len; +if (node_has_compatible (pp, &len))
Then this would just be:
if (node_has_compatible(pp))
...
etc. (rest snipped)
On a more important question, why does a NAND device node have sub-nodes that are not partitions? And if such devices exist, wouldn't it be more foolproof to establish a "compatible" property for ofpart partitions? Of course, we'd still have to retain backward-compatibility and allow partitions without a "compatible" prop. But this question probably should be addressed in the commit log and documented in Documentation/devicetree/bindings/mtd/partition.txt ; either specifying that all sub-nodes without a compatible property must be partitions, or else some other explanation.
Brian
PATCH v3 6/6 mtd: ofpart: add compatible check for child nodes
Hi, Brian
Quoted 26 lines · Brian Norris
Hi Josh,
Quoted 12 lines · Josh Wu
If the child node has compatible property then it is a driver not partition.
Signed-off-by Josh Wu <[email protected]>--- drivers/mtd/ofpart.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)drivers/mtd/ofpart.c +0
-0drivers/mtd/ofpart.c line 26
Quoted 7 lines
drivers/mtd/ofpart.c +4
-0@@ -20,6 +20,10 @@#include <linux/slab.h> #include <linux/mtd/partitions.h> +static bool node_has_compatible (struct device_node *pp,int *len) +{ +return of_get_property (pp,"compatible" , len); +}The way the interface is named, it seems like a user only would ever need the bool return value, not the implicit 'len' return value. So I would write it like this:
Quoted 4 lines
static bool
node_has_compatible(struct device_node *pp){ return of_get_property(pp, "compatible", NULL); }
yes, this is exactly is what I want. I didn't check the *len can be NULL or not. thanks.
Quoted 14 lines
drivers/mtd/ofpart.c static int parse_ofpart_partitions(struct mtd_info *master, · line 49
Quoted 12 lines
drivers/mtd/ofpart.c +3
-1static int parse_ofpart_partitions (struct mtd_info *master,struct mtd_partition **pparts,struct mtd_part_parser_data *data)@@ -40,8 +44,13 @@ static int parse_ofpart_partitions(struct mtd_info *master,/* First count the subnodes */ pp =NULL ; nr_parts =0 ; -while ((pp =of_get_next_child (node, pp))) +while ((pp =of_get_next_child (node, pp))) { +int len; +if (node_has_compatible (pp, &len))Then this would just be:
Quoted 8 lines
if (
node_has_compatible(pp))
...
etc. (rest snipped)On a more important question, why does a NAND device node have sub-nodes that are not partitions? And if such devices exist, wouldn't it be more foolproof to establish a "compatible" property for ofpart partitions?
In my case, we have a Atmel NAND flash driver/device which is work for all series of SAM9/SAMA5D3 chip.
And since in the new chip SAMA5D3 which has a NAND Flash Controller support.
So to enable NAND flash controller, I should either write a compatible driver like atmel,sama5-nand, which is
just old device property plus NFC regs and NFC properties, that became too big. Or add a NFC sub-node for the NFC support.
IMHO, to make the NFC device as a sub-node is the simplest way to make nand driver is back-compatible and easy to enable/disable NFC feature. Since all NFC related property are grouped it is more readable.
But to implement this, I need to add this patch, otherwise this NFC sub node will be recognized as a partition.
Quoted 6 lines
Of course, we'd still have to retain
backward-compatibility and allow partitions without a "compatible" prop. But this question probably should be addressed in the commit log and documented inDocumentation/devicetree/bindings/mtd/partition.txt; either specifying that all sub-nodes without a compatible property must be partitions, or else some other explanation.
yes, sure. I will add an explanation in commit log and Documentation/devicetree/bindings/mtd/partition.txt in next version.
Quoted 2 lines
Brian
Best Regards,
Josh Wu