All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 0/6] mtd: atmel_nand: enable Nand Flash Controller (NFC) support
@ 2013-07-03  9:50 ` Josh Wu
  0 siblings, 0 replies; 34+ messages in thread
From: Josh Wu @ 2013-07-03  9:50 UTC (permalink / raw)
  To: linux-mtd, linux-arm-kernel, dedekind1
  Cc: Josh Wu, computersforpeace, plagnioj, sergei.shtylyov

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.

v4 --> v5:
 1) rebase to latest l2-mtd.git
 2) remove blank line in EOF for atmel_nand.txt
 3) add blank line for patch 2/6 for coding style.

v3 --> v4:
 1) refine the commit message for ofpart.c patch and also change the
    description in partition.txt
 2) remove len parameter for ofpart.c's change.
 3) use devm_ioremap_resource instead of devm_requrest_and_ioremap.
 4) add BIT_POS macro definition for magic number.

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         |   27 +
 .../devicetree/bindings/mtd/partition.txt          |    1 +
 drivers/mtd/nand/atmel_nand.c                      |  877 ++++++++++++++++----
 drivers/mtd/nand/atmel_nand_nfc.h                  |   98 +++
 drivers/mtd/ofpart.c                               |   13 +-
 5 files changed, 853 insertions(+), 163 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: 2
mtd_speedtest: MTD device size 62914560, eraseblock size 131072, page size 2048, count of eraseblocks 480, pages per eraseblock 64, OOB size 64
mtd_speedtest: scanning for bad eraseblocks
mtd_speedtest: scanned 480 eraseblocks, 0 are bad
mtd_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/s
mtd_speedtest: Testing erase speed
mtd_speedtest: erase speed is 167411 KiB/s
mtd_speedtest: Testing 2x multi-block erase speed
mtd_speedtest: 2x multi-block erase speed is 326808 KiB/s
mtd_speedtest: Testing 4x multi-block erase speed
  513   504 root     R     1164   0%  74% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: 4x multi-block erase speed is 301176 KiB/s
mtd_speedtest: Testing 8x multi-block erase speed
mtd_speedtest: 8x multi-block erase speed is 326808 KiB/s
mtd_speedtest: Testing 16x multi-block erase speed
mtd_speedtest: 16x multi-block erase speed is 328556 KiB/s
mtd_speedtest: Testing 32x multi-block erase speed
mtd_speedtest: 32x multi-block erase speed is 328556 KiB/s
mtd_speedtest: Testing 64x multi-block erase speed
mtd_speedtest: 64x multi-block erase speed is 325079 KiB/s
mtd_speedtest: finished
=================================================


case 2: NFC with DMA:
=================================================
mtd_speedtest: MTD device: 2
mtd_speedtest: MTD device size 62914560, eraseblock size 131072, page size 2048, count of eraseblocks 480, pages per eraseblock 64, OOB size 64
mtd_speedtest: scanning for bad eraseblocks
mtd_speedtest: scanned 480 eraseblocks, 0 are bad
top -n 130 -d 1 | grep speedtest
mtd_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/s
mtd_speedtest: Testing erase speed
  514   504 root     R     1164   0%  12% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: erase speed is 157943 KiB/s
mtd_speedtest: Testing 2x multi-block erase speed
mtd_speedtest: 2x multi-block erase speed is 308743 KiB/s
mtd_speedtest: Testing 4x multi-block erase speed
mtd_speedtest: 4x multi-block erase speed is 313469 KiB/s
mtd_speedtest: Testing 8x multi-block erase speed
mtd_speedtest: 8x multi-block erase speed is 313469 KiB/s
mtd_speedtest: Testing 16x multi-block erase speed
mtd_speedtest: 16x multi-block erase speed is 315076 KiB/s
mtd_speedtest: Testing 32x multi-block erase speed
  514   504 root     R     1164   0%  12% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: 32x multi-block erase speed is 298252 KiB/s
mtd_speedtest: Testing 64x multi-block erase speed
mtd_speedtest: 64x multi-block erase speed is 311878 KiB/s
mtd_speedtest: finished
=================================================

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH v5 0/6] mtd: atmel_nand: enable Nand Flash Controller (NFC) support
@ 2013-07-03  9:50 ` Josh Wu
  0 siblings, 0 replies; 34+ messages in thread
From: Josh Wu @ 2013-07-03  9:50 UTC (permalink / raw)
  To: linux-arm-kernel

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.

v4 --> v5:
 1) rebase to latest l2-mtd.git
 2) remove blank line in EOF for atmel_nand.txt
 3) add blank line for patch 2/6 for coding style.

v3 --> v4:
 1) refine the commit message for ofpart.c patch and also change the
    description in partition.txt
 2) remove len parameter for ofpart.c's change.
 3) use devm_ioremap_resource instead of devm_requrest_and_ioremap.
 4) add BIT_POS macro definition for magic number.

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         |   27 +
 .../devicetree/bindings/mtd/partition.txt          |    1 +
 drivers/mtd/nand/atmel_nand.c                      |  877 ++++++++++++++++----
 drivers/mtd/nand/atmel_nand_nfc.h                  |   98 +++
 drivers/mtd/ofpart.c                               |   13 +-
 5 files changed, 853 insertions(+), 163 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: 2
mtd_speedtest: MTD device size 62914560, eraseblock size 131072, page size 2048, count of eraseblocks 480, pages per eraseblock 64, OOB size 64
mtd_speedtest: scanning for bad eraseblocks
mtd_speedtest: scanned 480 eraseblocks, 0 are bad
mtd_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/s
mtd_speedtest: Testing erase speed
mtd_speedtest: erase speed is 167411 KiB/s
mtd_speedtest: Testing 2x multi-block erase speed
mtd_speedtest: 2x multi-block erase speed is 326808 KiB/s
mtd_speedtest: Testing 4x multi-block erase speed
  513   504 root     R     1164   0%  74% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: 4x multi-block erase speed is 301176 KiB/s
mtd_speedtest: Testing 8x multi-block erase speed
mtd_speedtest: 8x multi-block erase speed is 326808 KiB/s
mtd_speedtest: Testing 16x multi-block erase speed
mtd_speedtest: 16x multi-block erase speed is 328556 KiB/s
mtd_speedtest: Testing 32x multi-block erase speed
mtd_speedtest: 32x multi-block erase speed is 328556 KiB/s
mtd_speedtest: Testing 64x multi-block erase speed
mtd_speedtest: 64x multi-block erase speed is 325079 KiB/s
mtd_speedtest: finished
=================================================


case 2: NFC with DMA:
=================================================
mtd_speedtest: MTD device: 2
mtd_speedtest: MTD device size 62914560, eraseblock size 131072, page size 2048, count of eraseblocks 480, pages per eraseblock 64, OOB size 64
mtd_speedtest: scanning for bad eraseblocks
mtd_speedtest: scanned 480 eraseblocks, 0 are bad
top -n 130 -d 1 | grep speedtest
mtd_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/s
mtd_speedtest: Testing erase speed
  514   504 root     R     1164   0%  12% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: erase speed is 157943 KiB/s
mtd_speedtest: Testing 2x multi-block erase speed
mtd_speedtest: 2x multi-block erase speed is 308743 KiB/s
mtd_speedtest: Testing 4x multi-block erase speed
mtd_speedtest: 4x multi-block erase speed is 313469 KiB/s
mtd_speedtest: Testing 8x multi-block erase speed
mtd_speedtest: 8x multi-block erase speed is 313469 KiB/s
mtd_speedtest: Testing 16x multi-block erase speed
mtd_speedtest: 16x multi-block erase speed is 315076 KiB/s
mtd_speedtest: Testing 32x multi-block erase speed
  514   504 root     R     1164   0%  12% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: 32x multi-block erase speed is 298252 KiB/s
mtd_speedtest: Testing 64x multi-block erase speed
mtd_speedtest: 64x multi-block erase speed is 311878 KiB/s
mtd_speedtest: finished
=================================================

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 1/6] MTD: atmel_nand: use devm_xxx gpio kzalloc, gpio and ioremap
  2013-07-03  9:50 ` Josh Wu
@ 2013-07-03  9:50   ` Josh Wu
  -1 siblings, 0 replies; 34+ messages in thread
From: Josh Wu @ 2013-07-03  9:50 UTC (permalink / raw)
  To: linux-mtd, linux-arm-kernel, dedekind1
  Cc: Nicolas Ferre, computersforpeace, plagnioj, sergei.shtylyov, Josh Wu

From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>

this will allow to simply the error and remove path

Cc: linux-mtd@lists.infradead.org
Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
[josh.wu@atmel.com: fix checkpatch warnings and rebase to latest mtd git tree]
[josh.wu@atmel.com: replace devm_request_and_ioremap with devm_ioremap_resource]
Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
v3 --> v4:
  use devm_ioremap_resource instead of devm_request_and_ioremap.

 drivers/mtd/nand/atmel_nand.c |  182 +++++++++++++++--------------------------
 1 file changed, 66 insertions(+), 116 deletions(-)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 7e50ed8..e3cc418 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -359,43 +359,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)
@@ -1016,27 +1007,28 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
 		return 0;
 	}
 
-	host->ecc = ioremap(regs->start, resource_size(regs));
-	if (host->ecc == NULL) {
+	host->ecc = devm_ioremap_resource(&pdev->dev, regs);
+	if (IS_ERR(host->ecc)) {
 		dev_err(host->dev, "ioremap failed\n");
-		err_no = -EIO;
-		goto err_pmecc_ioremap;
+		err_no = PTR_ERR(host->ecc);
+		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_ioremap_resource(&pdev->dev, regs_pmerr);
+	if (IS_ERR(host->pmerrloc_base)) {
+		dev_err(host->dev,
+			"Can not get I/O resource for PMECC ERRLOC controller!\n");
+		err_no = PTR_ERR(host->pmerrloc_base);
+		goto err;
 	}
 
-	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;
+	regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+	host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom);
+	if (IS_ERR(host->pmecc_rom_base)) {
+		dev_err(host->dev, "Can not get I/O resource for ROM!\n");
+		err_no = PTR_ERR(host->pmecc_rom_base);
+		goto err;
 	}
 
 	/* ECC is calculated for the whole page (1 step) */
@@ -1061,7 +1053,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,
@@ -1086,7 +1078,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;
@@ -1096,15 +1088,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;
 }
 
@@ -1408,10 +1392,10 @@ static int __init atmel_hw_nand_init_params(struct platform_device *pdev,
 		return 0;
 	}
 
-	host->ecc = ioremap(regs->start, resource_size(regs));
-	if (host->ecc == NULL) {
+	host->ecc = devm_ioremap_resource(&pdev->dev, regs);
+	if (IS_ERR(host->ecc)) {
 		dev_err(host->dev, "ioremap failed\n");
-		return -EIO;
+		return PTR_ERR(host->ecc);
 	}
 
 	/* ECC is calculated for the whole page (1 step) */
@@ -1466,27 +1450,21 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 	int res;
 	struct pinctrl *pinctrl;
 
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem) {
-		printk(KERN_ERR "atmel_nand: can't get I/O resource mem\n");
-		return -ENXIO;
-	}
-
 	/* 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));
-	if (host->io_base == NULL) {
-		printk(KERN_ERR "atmel_nand: ioremap failed\n");
-		res = -EIO;
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	host->io_base = devm_ioremap_resource(&pdev->dev, mem);
+	if (IS_ERR(host->io_base)) {
+		dev_err(&pdev->dev, "atmel_nand: ioremap resource failed\n");
+		res = PTR_ERR(host->io_base);
 		goto err_nand_ioremap;
 	}
+	host->io_phys = (dma_addr_t)mem->start;
 
 	mtd = &host->mtd;
 	nand_chip = &host->nand_chip;
@@ -1494,7 +1472,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));
@@ -1513,16 +1491,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);
@@ -1530,19 +1509,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);
@@ -1550,7 +1530,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;
 		}
 	}
 
@@ -1567,7 +1547,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",
@@ -1645,26 +1626,15 @@ 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:
 	atmel_nand_disable(host);
 	if (host->dma_chan)
 		dma_release_channel(host->dma_chan);
-err_ecc_ioremap:
-	iounmap(host->io_base);
 err_nand_ioremap:
-	kfree(host);
 	return res;
 }
 
@@ -1684,31 +1654,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;
 }
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 1/6] MTD: atmel_nand: use devm_xxx gpio kzalloc, gpio and ioremap
@ 2013-07-03  9:50   ` Josh Wu
  0 siblings, 0 replies; 34+ messages in thread
From: Josh Wu @ 2013-07-03  9:50 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>

this will allow to simply the error and remove path

Cc: linux-mtd at lists.infradead.org
Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
[josh.wu at atmel.com: fix checkpatch warnings and rebase to latest mtd git tree]
[josh.wu at atmel.com: replace devm_request_and_ioremap with devm_ioremap_resource]
Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
v3 --> v4:
  use devm_ioremap_resource instead of devm_request_and_ioremap.

 drivers/mtd/nand/atmel_nand.c |  182 +++++++++++++++--------------------------
 1 file changed, 66 insertions(+), 116 deletions(-)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 7e50ed8..e3cc418 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -359,43 +359,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)
@@ -1016,27 +1007,28 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
 		return 0;
 	}
 
-	host->ecc = ioremap(regs->start, resource_size(regs));
-	if (host->ecc == NULL) {
+	host->ecc = devm_ioremap_resource(&pdev->dev, regs);
+	if (IS_ERR(host->ecc)) {
 		dev_err(host->dev, "ioremap failed\n");
-		err_no = -EIO;
-		goto err_pmecc_ioremap;
+		err_no = PTR_ERR(host->ecc);
+		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_ioremap_resource(&pdev->dev, regs_pmerr);
+	if (IS_ERR(host->pmerrloc_base)) {
+		dev_err(host->dev,
+			"Can not get I/O resource for PMECC ERRLOC controller!\n");
+		err_no = PTR_ERR(host->pmerrloc_base);
+		goto err;
 	}
 
-	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;
+	regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+	host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom);
+	if (IS_ERR(host->pmecc_rom_base)) {
+		dev_err(host->dev, "Can not get I/O resource for ROM!\n");
+		err_no = PTR_ERR(host->pmecc_rom_base);
+		goto err;
 	}
 
 	/* ECC is calculated for the whole page (1 step) */
@@ -1061,7 +1053,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,
@@ -1086,7 +1078,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;
@@ -1096,15 +1088,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;
 }
 
@@ -1408,10 +1392,10 @@ static int __init atmel_hw_nand_init_params(struct platform_device *pdev,
 		return 0;
 	}
 
-	host->ecc = ioremap(regs->start, resource_size(regs));
-	if (host->ecc == NULL) {
+	host->ecc = devm_ioremap_resource(&pdev->dev, regs);
+	if (IS_ERR(host->ecc)) {
 		dev_err(host->dev, "ioremap failed\n");
-		return -EIO;
+		return PTR_ERR(host->ecc);
 	}
 
 	/* ECC is calculated for the whole page (1 step) */
@@ -1466,27 +1450,21 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 	int res;
 	struct pinctrl *pinctrl;
 
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem) {
-		printk(KERN_ERR "atmel_nand: can't get I/O resource mem\n");
-		return -ENXIO;
-	}
-
 	/* 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));
-	if (host->io_base == NULL) {
-		printk(KERN_ERR "atmel_nand: ioremap failed\n");
-		res = -EIO;
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	host->io_base = devm_ioremap_resource(&pdev->dev, mem);
+	if (IS_ERR(host->io_base)) {
+		dev_err(&pdev->dev, "atmel_nand: ioremap resource failed\n");
+		res = PTR_ERR(host->io_base);
 		goto err_nand_ioremap;
 	}
+	host->io_phys = (dma_addr_t)mem->start;
 
 	mtd = &host->mtd;
 	nand_chip = &host->nand_chip;
@@ -1494,7 +1472,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));
@@ -1513,16 +1491,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);
@@ -1530,19 +1509,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);
@@ -1550,7 +1530,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;
 		}
 	}
 
@@ -1567,7 +1547,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",
@@ -1645,26 +1626,15 @@ 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:
 	atmel_nand_disable(host);
 	if (host->dma_chan)
 		dma_release_channel(host->dma_chan);
-err_ecc_ioremap:
-	iounmap(host->io_base);
 err_nand_ioremap:
-	kfree(host);
 	return res;
 }
 
@@ -1684,31 +1654,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;
 }
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 2/6] mtd: atmel_nand: replace pmecc enable code with one function.
  2013-07-03  9:50 ` Josh Wu
@ 2013-07-03  9:50   ` Josh Wu
  -1 siblings, 0 replies; 34+ messages in thread
From: Josh Wu @ 2013-07-03  9:50 UTC (permalink / raw)
  To: linux-mtd, linux-arm-kernel, dedekind1
  Cc: Josh Wu, computersforpeace, plagnioj, sergei.shtylyov

Signed-off-by: Josh Wu <josh.wu@atmel.com>
Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
---
v4 --> v5:
  add blank line after variable declaration.

 drivers/mtd/nand/atmel_nand.c |   41 ++++++++++++++++++++++++++---------------
 1 file changed, 26 insertions(+), 15 deletions(-)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index e3cc418..5ce13f4 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -747,6 +747,30 @@ 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)
 {
@@ -758,13 +782,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);
@@ -797,14 +815,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);
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 2/6] mtd: atmel_nand: replace pmecc enable code with one function.
@ 2013-07-03  9:50   ` Josh Wu
  0 siblings, 0 replies; 34+ messages in thread
From: Josh Wu @ 2013-07-03  9:50 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Josh Wu <josh.wu@atmel.com>
Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
---
v4 --> v5:
  add blank line after variable declaration.

 drivers/mtd/nand/atmel_nand.c |   41 ++++++++++++++++++++++++++---------------
 1 file changed, 26 insertions(+), 15 deletions(-)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index e3cc418..5ce13f4 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -747,6 +747,30 @@ 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)
 {
@@ -758,13 +782,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);
@@ -797,14 +815,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);
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 3/6] mtd: atmel_nand: add Nand Flash Controller (NFC) support
  2013-07-03  9:50 ` Josh Wu
@ 2013-07-03  9:50   ` Josh Wu
  -1 siblings, 0 replies; 34+ messages in thread
From: Josh Wu @ 2013-07-03  9:50 UTC (permalink / raw)
  To: linux-mtd, linux-arm-kernel, dedekind1
  Cc: Josh Wu, computersforpeace, plagnioj, sergei.shtylyov

Nand 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.
>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: 2
mtd_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: 2
mtd_speedtest: MTD device size 41943040, eraseblock size 131072, page size 2048, count of eraseblocks 320, pages per eraseblock 64, OOB size 64
mtd_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

Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
v4 --> v5:
  - remove blank line in EOF.

v3 --> v4:
  - remove printk and use dev_err.
  - use macro definition for the BIT_POS for bit shift instead of magical
    numbers.
  - add/remove blank line for coding style.

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                      |  411 ++++++++++++++++++--
 drivers/mtd/nand/atmel_nand_nfc.h                  |   98 +++++
 3 files changed, 501 insertions(+), 33 deletions(-)
 create mode 100644 drivers/mtd/nand/atmel_nand_nfc.h

diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
index b6eb484..5d8b7d5 100644
--- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
@@ -30,6 +30,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@40000000,0 {
@@ -78,3 +84,22 @@ nand0: nand@40000000 {
 		...
 	};
 };
+
+/* for NFC supported chips */
+nand0: nand@40000000 {
+	compatible = "atmel,at91rm9200-nand";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges;
+        ...
+        nfc@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 */
+		>;
+	};
+};
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 5ce13f4..9dcb519 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -18,6 +18,9 @@
  *  Add Programmable Multibit ECC support for various AT91 SoC
  *     © Copyright 2012 ATMEL, Hong Xu
  *
+ *  Add Nand Flash Controller support for SAMA5 SoC
+ *     © Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.com)
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
@@ -37,9 +40,11 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 
+#include <linux/delay.h>
 #include <linux/dmaengine.h>
 #include <linux/gpio.h>
 #include <linux/io.h>
+#include <linux/interrupt.h>
 #include <linux/platform_data/atmel.h>
 #include <linux/pinctrl/consumer.h>
 
@@ -56,6 +61,7 @@ module_param(on_flash_bbt, int, 0);
 	__raw_writel((value), add + ATMEL_ECC_##reg)
 
 #include "atmel_nand_ecc.h"	/* Hardware ECC registers */
+#include "atmel_nand_nfc.h"	/* Nand Flash Controller definition */
 
 /* oob layout for large page size
  * bad block info is on bytes 0 and 1
@@ -83,6 +89,17 @@ static struct nand_ecclayout atmel_oobinfo_small = {
 	},
 };
 
+struct atmel_nfc {
+	void __iomem		*base_cmd_regs;
+	void __iomem		*hsmc_regs;
+	void __iomem		*sram_bank0;
+	dma_addr_t		sram_bank0_phys;
+
+	bool			is_initialized;
+	struct completion	comp_nfc;
+};
+static struct atmel_nfc	nand_nfc;
+
 struct atmel_nand_host {
 	struct nand_chip	nand_chip;
 	struct mtd_info		mtd;
@@ -95,6 +112,8 @@ struct atmel_nand_host {
 	struct completion	comp;
 	struct dma_chan		*dma_chan;
 
+	struct atmel_nfc	*nfc;
+
 	bool			has_pmecc;
 	u8			pmecc_corr_cap;
 	u16			pmecc_sector_size;
@@ -179,6 +198,56 @@ static int atmel_nand_device_ready(struct mtd_info *mtd)
                 !!host->board.rdy_pin_active_low;
 }
 
+/* Set up for hardware ready pin and enable pin. */
+static int atmel_nand_set_enable_ready_pins(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct atmel_nand_host *host = chip->priv;
+	int res = 0;
+
+	if (gpio_is_valid(host->board.rdy_pin)) {
+		res = devm_gpio_request(host->dev,
+				host->board.rdy_pin, "nand_rdy");
+		if (res < 0) {
+			dev_err(host->dev,
+				"can't request rdy gpio %d\n",
+				host->board.rdy_pin);
+			return res;
+		}
+
+		res = gpio_direction_input(host->board.rdy_pin);
+		if (res < 0) {
+			dev_err(host->dev,
+				"can't request input direction rdy gpio %d\n",
+				host->board.rdy_pin);
+			return res;
+		}
+
+		chip->dev_ready = atmel_nand_device_ready;
+	}
+
+	if (gpio_is_valid(host->board.enable_pin)) {
+		res = devm_gpio_request(host->dev,
+				host->board.enable_pin, "nand_enable");
+		if (res < 0) {
+			dev_err(host->dev,
+				"can't request enable gpio %d\n",
+				host->board.enable_pin);
+			return res;
+		}
+
+		res = gpio_direction_output(host->board.enable_pin, 1);
+		if (res < 0) {
+			dev_err(host->dev,
+				"can't request output direction enable gpio %d\n",
+				host->board.enable_pin);
+			return res;
+		}
+	}
+
+	return res;
+}
+
 /*
  * Minimal-overhead PIO for data access.
  */
@@ -1337,6 +1406,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);
+
 	if (!(board->ecc_mode == NAND_ECC_HW) || !host->has_pmecc)
 		return 0;	/* Not using PMECC */
 
@@ -1448,6 +1520,239 @@ 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 in cmd register */
+	return acycle << NFCADDR_CMD_ACYCLE_BIT_POS;
+}
+
+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 << NFCADDR_CMD_CMD1_BIT_POS;
+
+	/* 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 << NFCADDR_CMD_CMD2_BIT_POS;
+		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 << NFCADDR_CMD_CMD1_BIT_POS;
+		}
+
+		cmd2 = NAND_CMD_READSTART << NFCADDR_CMD_CMD2_BIT_POS;
+		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.
  */
@@ -1458,7 +1763,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;
 
 	/* Allocate memory for the device structure (and zero it) */
@@ -1468,6 +1773,10 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
+	res = platform_driver_register(&atmel_nand_nfc_driver);
+	if (res)
+		dev_err(&pdev->dev, "atmel_nand: can't register NFC driver\n");
+
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	host->io_base = devm_ioremap_resource(&pdev->dev, mem);
 	if (IS_ERR(host->io_base)) {
@@ -1496,7 +1805,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)) {
@@ -1505,44 +1813,34 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 		goto err_nand_ioremap;
 	}
 
-	if (gpio_is_valid(host->board.rdy_pin)) {
-		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_nand_ioremap;
-		}
-
-		res = gpio_direction_input(host->board.rdy_pin);
-		if (res < 0) {
-			dev_err(&pdev->dev,
-				"can't request input direction rdy gpio %d\n",
-				host->board.rdy_pin);
-			goto err_nand_ioremap;
-		}
+	if (nand_nfc.is_initialized) {
+		/* NFC driver is probed and initialized */
+		host->nfc = &nand_nfc;
 
-		nand_chip->dev_ready = atmel_nand_device_ready;
-	}
+		nand_chip->select_chip = nfc_select_chip;
+		nand_chip->dev_ready = nfc_device_ready;
+		nand_chip->cmdfunc = nfc_nand_command;
 
-	if (gpio_is_valid(host->board.enable_pin)) {
-		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);
+		/* Initialize the interrupt for NFC */
+		irq = platform_get_irq(pdev, 0);
+		if (irq < 0) {
+			dev_err(host->dev, "Cannot get HSMC irq!\n");
 			goto err_nand_ioremap;
 		}
 
-		res = gpio_direction_output(host->board.enable_pin, 1);
-		if (res < 0) {
-			dev_err(&pdev->dev,
-				"can't request output direction enable gpio %d\n",
-				host->board.enable_pin);
+		res = devm_request_irq(&pdev->dev, irq, hsmc_interrupt,
+				0, "hsmc", host);
+		if (res) {
+			dev_err(&pdev->dev, "Unable to request HSMC irq %d\n",
+				irq);
 			goto err_nand_ioremap;
 		}
+	} else {
+		res = atmel_nand_set_enable_ready_pins(mtd);
+		if (res)
+			goto err_nand_ioremap;
+
+		nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
 	}
 
 	nand_chip->ecc.mode = host->board.ecc_mode;
@@ -1646,6 +1944,7 @@ err_no_card:
 	if (host->dma_chan)
 		dma_release_channel(host->dma_chan);
 err_nand_ioremap:
+	platform_driver_unregister(&atmel_nand_nfc_driver);
 	return res;
 }
 
@@ -1670,6 +1969,8 @@ static int __exit atmel_nand_remove(struct platform_device *pdev)
 	if (host->dma_chan)
 		dma_release_channel(host->dma_chan);
 
+	platform_driver_unregister(&atmel_nand_nfc_driver);
+
 	return 0;
 }
 
@@ -1682,6 +1983,50 @@ static const struct of_device_id atmel_nand_dt_ids[] = {
 MODULE_DEVICE_TABLE(of, atmel_nand_dt_ids);
 #endif
 
+static int atmel_nand_nfc_probe(struct platform_device *pdev)
+{
+	struct atmel_nfc *nfc = &nand_nfc;
+	struct resource *nfc_cmd_regs, *nfc_hsmc_regs, *nfc_sram;
+
+	nfc_cmd_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	nfc->base_cmd_regs = devm_ioremap_resource(&pdev->dev, nfc_cmd_regs);
+	if (IS_ERR(nfc->base_cmd_regs))
+		return PTR_ERR(nfc->base_cmd_regs);
+
+	nfc_hsmc_regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	nfc->hsmc_regs = devm_ioremap_resource(&pdev->dev, nfc_hsmc_regs);
+	if (IS_ERR(nfc->hsmc_regs))
+		return PTR_ERR(nfc->hsmc_regs);
+
+	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))
+			dev_warn(&pdev->dev, "Fail to ioremap the NFC sram with error: %ld. So disable NFC sram.\n",
+					PTR_ERR(nfc->sram_bank0));
+		else
+			nfc->sram_bank0_phys = (dma_addr_t)nfc_sram->start;
+	}
+
+	nfc->is_initialized = true;
+	dev_info(&pdev->dev, "NFC is probed.\n");
+	return 0;
+}
+
+static struct of_device_id atmel_nand_nfc_match[] = {
+	{ .compatible = "atmel,sama5d3-nfc" },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver atmel_nand_nfc_driver = {
+	.driver = {
+		.name = "atmel_nand_nfc",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(atmel_nand_nfc_match),
+	},
+	.probe = atmel_nand_nfc_probe,
+};
+
 static struct platform_driver atmel_nand_driver = {
 	.remove		= __exit_p(atmel_nand_remove),
 	.driver		= {
diff --git a/drivers/mtd/nand/atmel_nand_nfc.h b/drivers/mtd/nand/atmel_nand_nfc.h
new file mode 100644
index 0000000..4efd117
--- /dev/null
+++ b/drivers/mtd/nand/atmel_nand_nfc.h
@@ -0,0 +1,98 @@
+/*
+ * Atmel Nand Flash Controller (NFC) - System peripherals regsters.
+ * Based on SAMA5D3 datasheet.
+ *
+ * © Copyright 2013 Atmel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef ATMEL_NAND_NFC_H
+#define ATMEL_NAND_NFC_H
+
+/*
+ * HSMC NFC registers
+ */
+#define ATMEL_HSMC_NFC_CFG	0x00		/* NFC Configuration Register */
+#define		NFC_CFG_PAGESIZE	(7 << 0)
+#define			NFC_CFG_PAGESIZE_512	(0 << 0)
+#define			NFC_CFG_PAGESIZE_1024	(1 << 0)
+#define			NFC_CFG_PAGESIZE_2048	(2 << 0)
+#define			NFC_CFG_PAGESIZE_4096	(3 << 0)
+#define			NFC_CFG_PAGESIZE_8192	(4 << 0)
+#define		NFC_CFG_WSPARE		(1 << 8)
+#define		NFC_CFG_RSPARE		(1 << 9)
+#define		NFC_CFG_NFC_DTOCYC	(0xf << 16)
+#define		NFC_CFG_NFC_DTOMUL	(0x7 << 20)
+#define		NFC_CFG_NFC_SPARESIZE	(0x7f << 24)
+#define		NFC_CFG_NFC_SPARESIZE_BIT_POS	24
+
+#define ATMEL_HSMC_NFC_CTRL	0x04		/* NFC Control Register */
+#define		NFC_CTRL_ENABLE		(1 << 0)
+#define		NFC_CTRL_DISABLE	(1 << 1)
+
+#define ATMEL_HSMC_NFC_SR	0x08		/* NFC Status Register */
+#define		NFC_SR_XFR_DONE		(1 << 16)
+#define		NFC_SR_CMD_DONE		(1 << 17)
+#define		NFC_SR_RB_EDGE		(1 << 24)
+
+#define ATMEL_HSMC_NFC_IER	0x0c
+#define ATMEL_HSMC_NFC_IDR	0x10
+#define ATMEL_HSMC_NFC_IMR	0x14
+#define ATMEL_HSMC_NFC_CYCLE0	0x18		/* NFC Address Cycle Zero */
+#define		ATMEL_HSMC_NFC_ADDR_CYCLE0	(0xff)
+
+#define ATMEL_HSMC_NFC_BANK	0x1c		/* NFC Bank Register */
+#define		ATMEL_HSMC_NFC_BANK0		(0 << 0)
+#define		ATMEL_HSMC_NFC_BANK1		(1 << 0)
+
+#define nfc_writel(addr, reg, value) \
+	writel((value), (addr) + ATMEL_HSMC_NFC_##reg)
+
+#define nfc_readl(addr, reg) \
+	readl_relaxed((addr) + ATMEL_HSMC_NFC_##reg)
+
+/*
+ * NFC Address Command definitions
+ */
+#define NFCADDR_CMD_CMD1	(0xff << 2)	/* Command for Cycle 1 */
+#define NFCADDR_CMD_CMD1_BIT_POS	2
+#define NFCADDR_CMD_CMD2	(0xff << 10)	/* Command for Cycle 2 */
+#define NFCADDR_CMD_CMD2_BIT_POS	10
+#define NFCADDR_CMD_VCMD2	(0x1 << 18)	/* Valid Cycle 2 Command */
+#define NFCADDR_CMD_ACYCLE	(0x7 << 19)	/* Number of Address required */
+#define		NFCADDR_CMD_ACYCLE_NONE		(0x0 << 19)
+#define		NFCADDR_CMD_ACYCLE_1		(0x1 << 19)
+#define		NFCADDR_CMD_ACYCLE_2		(0x2 << 19)
+#define		NFCADDR_CMD_ACYCLE_3		(0x3 << 19)
+#define		NFCADDR_CMD_ACYCLE_4		(0x4 << 19)
+#define		NFCADDR_CMD_ACYCLE_5		(0x5 << 19)
+#define NFCADDR_CMD_ACYCLE_BIT_POS	19
+#define NFCADDR_CMD_CSID	(0x7 << 22)	/* Chip Select Identifier */
+#define		NFCADDR_CMD_CSID_0		(0x0 << 22)
+#define		NFCADDR_CMD_CSID_1		(0x1 << 22)
+#define		NFCADDR_CMD_CSID_2		(0x2 << 22)
+#define		NFCADDR_CMD_CSID_3		(0x3 << 22)
+#define		NFCADDR_CMD_CSID_4		(0x4 << 22)
+#define		NFCADDR_CMD_CSID_5		(0x5 << 22)
+#define		NFCADDR_CMD_CSID_6		(0x6 << 22)
+#define		NFCADDR_CMD_CSID_7		(0x7 << 22)
+#define NFCADDR_CMD_DATAEN	(0x1 << 25)	/* Data Transfer Enable */
+#define NFCADDR_CMD_DATADIS	(0x0 << 25)	/* Data Transfer Disable */
+#define NFCADDR_CMD_NFCRD	(0x0 << 26)	/* NFC Read Enable */
+#define NFCADDR_CMD_NFCWR	(0x1 << 26)	/* NFC Write Enable */
+#define NFCADDR_CMD_NFCBUSY	(0x1 << 27)	/* NFC Busy */
+
+#define nfc_cmd_addr1234_writel(cmd, addr1234, nfc_base) \
+	writel((addr1234), (cmd) + nfc_base)
+
+#define nfc_cmd_readl(bitstatus, nfc_base) \
+	readl_relaxed((bitstatus) + nfc_base)
+
+#define NFC_TIME_OUT_MS		100
+#define	NFC_SRAM_BANK1_OFFSET	0x1200
+
+#endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 3/6] mtd: atmel_nand: add Nand Flash Controller (NFC) support
@ 2013-07-03  9:50   ` Josh Wu
  0 siblings, 0 replies; 34+ messages in thread
From: Josh Wu @ 2013-07-03  9:50 UTC (permalink / raw)
  To: linux-arm-kernel

Nand 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.
>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: 2
mtd_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: 2
mtd_speedtest: MTD device size 41943040, eraseblock size 131072, page size 2048, count of eraseblocks 320, pages per eraseblock 64, OOB size 64
mtd_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

Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
v4 --> v5:
  - remove blank line in EOF.

v3 --> v4:
  - remove printk and use dev_err.
  - use macro definition for the BIT_POS for bit shift instead of magical
    numbers.
  - add/remove blank line for coding style.

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                      |  411 ++++++++++++++++++--
 drivers/mtd/nand/atmel_nand_nfc.h                  |   98 +++++
 3 files changed, 501 insertions(+), 33 deletions(-)
 create mode 100644 drivers/mtd/nand/atmel_nand_nfc.h

diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
index b6eb484..5d8b7d5 100644
--- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
@@ -30,6 +30,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 {
@@ -78,3 +84,22 @@ 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 */
+		>;
+	};
+};
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 5ce13f4..9dcb519 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -18,6 +18,9 @@
  *  Add Programmable Multibit ECC support for various AT91 SoC
  *     ? Copyright 2012 ATMEL, Hong Xu
  *
+ *  Add Nand Flash Controller support for SAMA5 SoC
+ *     ? Copyright 2013 ATMEL, Josh Wu (josh.wu at atmel.com)
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
@@ -37,9 +40,11 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 
+#include <linux/delay.h>
 #include <linux/dmaengine.h>
 #include <linux/gpio.h>
 #include <linux/io.h>
+#include <linux/interrupt.h>
 #include <linux/platform_data/atmel.h>
 #include <linux/pinctrl/consumer.h>
 
@@ -56,6 +61,7 @@ module_param(on_flash_bbt, int, 0);
 	__raw_writel((value), add + ATMEL_ECC_##reg)
 
 #include "atmel_nand_ecc.h"	/* Hardware ECC registers */
+#include "atmel_nand_nfc.h"	/* Nand Flash Controller definition */
 
 /* oob layout for large page size
  * bad block info is on bytes 0 and 1
@@ -83,6 +89,17 @@ static struct nand_ecclayout atmel_oobinfo_small = {
 	},
 };
 
+struct atmel_nfc {
+	void __iomem		*base_cmd_regs;
+	void __iomem		*hsmc_regs;
+	void __iomem		*sram_bank0;
+	dma_addr_t		sram_bank0_phys;
+
+	bool			is_initialized;
+	struct completion	comp_nfc;
+};
+static struct atmel_nfc	nand_nfc;
+
 struct atmel_nand_host {
 	struct nand_chip	nand_chip;
 	struct mtd_info		mtd;
@@ -95,6 +112,8 @@ struct atmel_nand_host {
 	struct completion	comp;
 	struct dma_chan		*dma_chan;
 
+	struct atmel_nfc	*nfc;
+
 	bool			has_pmecc;
 	u8			pmecc_corr_cap;
 	u16			pmecc_sector_size;
@@ -179,6 +198,56 @@ static int atmel_nand_device_ready(struct mtd_info *mtd)
                 !!host->board.rdy_pin_active_low;
 }
 
+/* Set up for hardware ready pin and enable pin. */
+static int atmel_nand_set_enable_ready_pins(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct atmel_nand_host *host = chip->priv;
+	int res = 0;
+
+	if (gpio_is_valid(host->board.rdy_pin)) {
+		res = devm_gpio_request(host->dev,
+				host->board.rdy_pin, "nand_rdy");
+		if (res < 0) {
+			dev_err(host->dev,
+				"can't request rdy gpio %d\n",
+				host->board.rdy_pin);
+			return res;
+		}
+
+		res = gpio_direction_input(host->board.rdy_pin);
+		if (res < 0) {
+			dev_err(host->dev,
+				"can't request input direction rdy gpio %d\n",
+				host->board.rdy_pin);
+			return res;
+		}
+
+		chip->dev_ready = atmel_nand_device_ready;
+	}
+
+	if (gpio_is_valid(host->board.enable_pin)) {
+		res = devm_gpio_request(host->dev,
+				host->board.enable_pin, "nand_enable");
+		if (res < 0) {
+			dev_err(host->dev,
+				"can't request enable gpio %d\n",
+				host->board.enable_pin);
+			return res;
+		}
+
+		res = gpio_direction_output(host->board.enable_pin, 1);
+		if (res < 0) {
+			dev_err(host->dev,
+				"can't request output direction enable gpio %d\n",
+				host->board.enable_pin);
+			return res;
+		}
+	}
+
+	return res;
+}
+
 /*
  * Minimal-overhead PIO for data access.
  */
@@ -1337,6 +1406,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);
+
 	if (!(board->ecc_mode == NAND_ECC_HW) || !host->has_pmecc)
 		return 0;	/* Not using PMECC */
 
@@ -1448,6 +1520,239 @@ 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 in cmd register */
+	return acycle << NFCADDR_CMD_ACYCLE_BIT_POS;
+}
+
+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 << NFCADDR_CMD_CMD1_BIT_POS;
+
+	/* 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 << NFCADDR_CMD_CMD2_BIT_POS;
+		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 << NFCADDR_CMD_CMD1_BIT_POS;
+		}
+
+		cmd2 = NAND_CMD_READSTART << NFCADDR_CMD_CMD2_BIT_POS;
+		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.
  */
@@ -1458,7 +1763,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;
 
 	/* Allocate memory for the device structure (and zero it) */
@@ -1468,6 +1773,10 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
+	res = platform_driver_register(&atmel_nand_nfc_driver);
+	if (res)
+		dev_err(&pdev->dev, "atmel_nand: can't register NFC driver\n");
+
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	host->io_base = devm_ioremap_resource(&pdev->dev, mem);
 	if (IS_ERR(host->io_base)) {
@@ -1496,7 +1805,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)) {
@@ -1505,44 +1813,34 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 		goto err_nand_ioremap;
 	}
 
-	if (gpio_is_valid(host->board.rdy_pin)) {
-		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_nand_ioremap;
-		}
-
-		res = gpio_direction_input(host->board.rdy_pin);
-		if (res < 0) {
-			dev_err(&pdev->dev,
-				"can't request input direction rdy gpio %d\n",
-				host->board.rdy_pin);
-			goto err_nand_ioremap;
-		}
+	if (nand_nfc.is_initialized) {
+		/* NFC driver is probed and initialized */
+		host->nfc = &nand_nfc;
 
-		nand_chip->dev_ready = atmel_nand_device_ready;
-	}
+		nand_chip->select_chip = nfc_select_chip;
+		nand_chip->dev_ready = nfc_device_ready;
+		nand_chip->cmdfunc = nfc_nand_command;
 
-	if (gpio_is_valid(host->board.enable_pin)) {
-		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);
+		/* Initialize the interrupt for NFC */
+		irq = platform_get_irq(pdev, 0);
+		if (irq < 0) {
+			dev_err(host->dev, "Cannot get HSMC irq!\n");
 			goto err_nand_ioremap;
 		}
 
-		res = gpio_direction_output(host->board.enable_pin, 1);
-		if (res < 0) {
-			dev_err(&pdev->dev,
-				"can't request output direction enable gpio %d\n",
-				host->board.enable_pin);
+		res = devm_request_irq(&pdev->dev, irq, hsmc_interrupt,
+				0, "hsmc", host);
+		if (res) {
+			dev_err(&pdev->dev, "Unable to request HSMC irq %d\n",
+				irq);
 			goto err_nand_ioremap;
 		}
+	} else {
+		res = atmel_nand_set_enable_ready_pins(mtd);
+		if (res)
+			goto err_nand_ioremap;
+
+		nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
 	}
 
 	nand_chip->ecc.mode = host->board.ecc_mode;
@@ -1646,6 +1944,7 @@ err_no_card:
 	if (host->dma_chan)
 		dma_release_channel(host->dma_chan);
 err_nand_ioremap:
+	platform_driver_unregister(&atmel_nand_nfc_driver);
 	return res;
 }
 
@@ -1670,6 +1969,8 @@ static int __exit atmel_nand_remove(struct platform_device *pdev)
 	if (host->dma_chan)
 		dma_release_channel(host->dma_chan);
 
+	platform_driver_unregister(&atmel_nand_nfc_driver);
+
 	return 0;
 }
 
@@ -1682,6 +1983,50 @@ static const struct of_device_id atmel_nand_dt_ids[] = {
 MODULE_DEVICE_TABLE(of, atmel_nand_dt_ids);
 #endif
 
+static int atmel_nand_nfc_probe(struct platform_device *pdev)
+{
+	struct atmel_nfc *nfc = &nand_nfc;
+	struct resource *nfc_cmd_regs, *nfc_hsmc_regs, *nfc_sram;
+
+	nfc_cmd_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	nfc->base_cmd_regs = devm_ioremap_resource(&pdev->dev, nfc_cmd_regs);
+	if (IS_ERR(nfc->base_cmd_regs))
+		return PTR_ERR(nfc->base_cmd_regs);
+
+	nfc_hsmc_regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	nfc->hsmc_regs = devm_ioremap_resource(&pdev->dev, nfc_hsmc_regs);
+	if (IS_ERR(nfc->hsmc_regs))
+		return PTR_ERR(nfc->hsmc_regs);
+
+	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))
+			dev_warn(&pdev->dev, "Fail to ioremap the NFC sram with error: %ld. So disable NFC sram.\n",
+					PTR_ERR(nfc->sram_bank0));
+		else
+			nfc->sram_bank0_phys = (dma_addr_t)nfc_sram->start;
+	}
+
+	nfc->is_initialized = true;
+	dev_info(&pdev->dev, "NFC is probed.\n");
+	return 0;
+}
+
+static struct of_device_id atmel_nand_nfc_match[] = {
+	{ .compatible = "atmel,sama5d3-nfc" },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver atmel_nand_nfc_driver = {
+	.driver = {
+		.name = "atmel_nand_nfc",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(atmel_nand_nfc_match),
+	},
+	.probe = atmel_nand_nfc_probe,
+};
+
 static struct platform_driver atmel_nand_driver = {
 	.remove		= __exit_p(atmel_nand_remove),
 	.driver		= {
diff --git a/drivers/mtd/nand/atmel_nand_nfc.h b/drivers/mtd/nand/atmel_nand_nfc.h
new file mode 100644
index 0000000..4efd117
--- /dev/null
+++ b/drivers/mtd/nand/atmel_nand_nfc.h
@@ -0,0 +1,98 @@
+/*
+ * Atmel Nand Flash Controller (NFC) - System peripherals regsters.
+ * Based on SAMA5D3 datasheet.
+ *
+ * ? Copyright 2013 Atmel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef ATMEL_NAND_NFC_H
+#define ATMEL_NAND_NFC_H
+
+/*
+ * HSMC NFC registers
+ */
+#define ATMEL_HSMC_NFC_CFG	0x00		/* NFC Configuration Register */
+#define		NFC_CFG_PAGESIZE	(7 << 0)
+#define			NFC_CFG_PAGESIZE_512	(0 << 0)
+#define			NFC_CFG_PAGESIZE_1024	(1 << 0)
+#define			NFC_CFG_PAGESIZE_2048	(2 << 0)
+#define			NFC_CFG_PAGESIZE_4096	(3 << 0)
+#define			NFC_CFG_PAGESIZE_8192	(4 << 0)
+#define		NFC_CFG_WSPARE		(1 << 8)
+#define		NFC_CFG_RSPARE		(1 << 9)
+#define		NFC_CFG_NFC_DTOCYC	(0xf << 16)
+#define		NFC_CFG_NFC_DTOMUL	(0x7 << 20)
+#define		NFC_CFG_NFC_SPARESIZE	(0x7f << 24)
+#define		NFC_CFG_NFC_SPARESIZE_BIT_POS	24
+
+#define ATMEL_HSMC_NFC_CTRL	0x04		/* NFC Control Register */
+#define		NFC_CTRL_ENABLE		(1 << 0)
+#define		NFC_CTRL_DISABLE	(1 << 1)
+
+#define ATMEL_HSMC_NFC_SR	0x08		/* NFC Status Register */
+#define		NFC_SR_XFR_DONE		(1 << 16)
+#define		NFC_SR_CMD_DONE		(1 << 17)
+#define		NFC_SR_RB_EDGE		(1 << 24)
+
+#define ATMEL_HSMC_NFC_IER	0x0c
+#define ATMEL_HSMC_NFC_IDR	0x10
+#define ATMEL_HSMC_NFC_IMR	0x14
+#define ATMEL_HSMC_NFC_CYCLE0	0x18		/* NFC Address Cycle Zero */
+#define		ATMEL_HSMC_NFC_ADDR_CYCLE0	(0xff)
+
+#define ATMEL_HSMC_NFC_BANK	0x1c		/* NFC Bank Register */
+#define		ATMEL_HSMC_NFC_BANK0		(0 << 0)
+#define		ATMEL_HSMC_NFC_BANK1		(1 << 0)
+
+#define nfc_writel(addr, reg, value) \
+	writel((value), (addr) + ATMEL_HSMC_NFC_##reg)
+
+#define nfc_readl(addr, reg) \
+	readl_relaxed((addr) + ATMEL_HSMC_NFC_##reg)
+
+/*
+ * NFC Address Command definitions
+ */
+#define NFCADDR_CMD_CMD1	(0xff << 2)	/* Command for Cycle 1 */
+#define NFCADDR_CMD_CMD1_BIT_POS	2
+#define NFCADDR_CMD_CMD2	(0xff << 10)	/* Command for Cycle 2 */
+#define NFCADDR_CMD_CMD2_BIT_POS	10
+#define NFCADDR_CMD_VCMD2	(0x1 << 18)	/* Valid Cycle 2 Command */
+#define NFCADDR_CMD_ACYCLE	(0x7 << 19)	/* Number of Address required */
+#define		NFCADDR_CMD_ACYCLE_NONE		(0x0 << 19)
+#define		NFCADDR_CMD_ACYCLE_1		(0x1 << 19)
+#define		NFCADDR_CMD_ACYCLE_2		(0x2 << 19)
+#define		NFCADDR_CMD_ACYCLE_3		(0x3 << 19)
+#define		NFCADDR_CMD_ACYCLE_4		(0x4 << 19)
+#define		NFCADDR_CMD_ACYCLE_5		(0x5 << 19)
+#define NFCADDR_CMD_ACYCLE_BIT_POS	19
+#define NFCADDR_CMD_CSID	(0x7 << 22)	/* Chip Select Identifier */
+#define		NFCADDR_CMD_CSID_0		(0x0 << 22)
+#define		NFCADDR_CMD_CSID_1		(0x1 << 22)
+#define		NFCADDR_CMD_CSID_2		(0x2 << 22)
+#define		NFCADDR_CMD_CSID_3		(0x3 << 22)
+#define		NFCADDR_CMD_CSID_4		(0x4 << 22)
+#define		NFCADDR_CMD_CSID_5		(0x5 << 22)
+#define		NFCADDR_CMD_CSID_6		(0x6 << 22)
+#define		NFCADDR_CMD_CSID_7		(0x7 << 22)
+#define NFCADDR_CMD_DATAEN	(0x1 << 25)	/* Data Transfer Enable */
+#define NFCADDR_CMD_DATADIS	(0x0 << 25)	/* Data Transfer Disable */
+#define NFCADDR_CMD_NFCRD	(0x0 << 26)	/* NFC Read Enable */
+#define NFCADDR_CMD_NFCWR	(0x1 << 26)	/* NFC Write Enable */
+#define NFCADDR_CMD_NFCBUSY	(0x1 << 27)	/* NFC Busy */
+
+#define nfc_cmd_addr1234_writel(cmd, addr1234, nfc_base) \
+	writel((addr1234), (cmd) + nfc_base)
+
+#define nfc_cmd_readl(bitstatus, nfc_base) \
+	readl_relaxed((bitstatus) + nfc_base)
+
+#define NFC_TIME_OUT_MS		100
+#define	NFC_SRAM_BANK1_OFFSET	0x1200
+
+#endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 4/6] mtd: atmel_nand: enable Nand Flash Controller (NFC) read data via sram
  2013-07-03  9:50 ` Josh Wu
@ 2013-07-03  9:50   ` Josh Wu
  -1 siblings, 0 replies; 34+ messages in thread
From: Josh Wu @ 2013-07-03  9:50 UTC (permalink / raw)
  To: linux-mtd, linux-arm-kernel, dedekind1
  Cc: Josh Wu, computersforpeace, plagnioj, sergei.shtylyov

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.

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: 2
mtd_speedtest: MTD device size 41943040, eraseblock size 131072, page size 2048, count of eraseblocks 320, pages per eraseblock 64, OOB size 64
mtd_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

Signed-off-by: Josh Wu <josh.wu@atmel.com>
Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
---
v3 --> v4:
  - use BIT_POS definition not magical number.

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(-)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 9dcb519..7e14dbe 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -94,9 +94,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;
 
@@ -248,21 +252,43 @@ static int atmel_nand_set_enable_ready_pins(struct mtd_info *mtd)
 	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)
@@ -284,6 +310,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)
 {
@@ -297,6 +357,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;
@@ -313,7 +374,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;
@@ -340,6 +406,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:
@@ -851,7 +921,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);
@@ -1667,6 +1738,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);
@@ -1708,6 +1780,16 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
 			command = NAND_CMD_READ0; /* only READ0 is valid */
 			cmd1 = command << NFCADDR_CMD_CMD1_BIT_POS;
 		}
+		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 << NFCADDR_CMD_CMD2_BIT_POS;
 		vcmd2 = NFCADDR_CMD_VCMD2;
@@ -1729,6 +1811,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.
@@ -1746,12 +1832,66 @@ 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) << NFC_CFG_NFC_SPARESIZE_BIT_POS
+		& 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.
@@ -1921,6 +2061,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;
@@ -2001,11 +2150,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;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 4/6] mtd: atmel_nand: enable Nand Flash Controller (NFC) read data via sram
@ 2013-07-03  9:50   ` Josh Wu
  0 siblings, 0 replies; 34+ messages in thread
From: Josh Wu @ 2013-07-03  9:50 UTC (permalink / raw)
  To: linux-arm-kernel

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.

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: 2
mtd_speedtest: MTD device size 41943040, eraseblock size 131072, page size 2048, count of eraseblocks 320, pages per eraseblock 64, OOB size 64
mtd_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

Signed-off-by: Josh Wu <josh.wu@atmel.com>
Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
---
v3 --> v4:
  - use BIT_POS definition not magical number.

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(-)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 9dcb519..7e14dbe 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -94,9 +94,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;
 
@@ -248,21 +252,43 @@ static int atmel_nand_set_enable_ready_pins(struct mtd_info *mtd)
 	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)
@@ -284,6 +310,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)
 {
@@ -297,6 +357,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;
@@ -313,7 +374,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;
@@ -340,6 +406,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:
@@ -851,7 +921,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);
@@ -1667,6 +1738,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);
@@ -1708,6 +1780,16 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
 			command = NAND_CMD_READ0; /* only READ0 is valid */
 			cmd1 = command << NFCADDR_CMD_CMD1_BIT_POS;
 		}
+		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 << NFCADDR_CMD_CMD2_BIT_POS;
 		vcmd2 = NFCADDR_CMD_VCMD2;
@@ -1729,6 +1811,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.
@@ -1746,12 +1832,66 @@ 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) << NFC_CFG_NFC_SPARESIZE_BIT_POS
+		& 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.
@@ -1921,6 +2061,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;
@@ -2001,11 +2150,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;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 5/6] mtd: atmel_nand: enable Nand Flash Controller (NFC) write via sram
  2013-07-03  9:50 ` Josh Wu
@ 2013-07-03  9:50   ` Josh Wu
  -1 siblings, 0 replies; 34+ messages in thread
From: Josh Wu @ 2013-07-03  9:50 UTC (permalink / raw)
  To: linux-mtd, linux-arm-kernel, dedekind1
  Cc: Josh Wu, computersforpeace, plagnioj, sergei.shtylyov

This 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: 2
mtd_speedtest: MTD device size 41943040, eraseblock size 131072, page size 2048, count of eraseblocks 320, pages per eraseblock 64, OOB size 64
mtd_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

Signed-off-by: Josh Wu <josh.wu@atmel.com>
Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
---
v3 --> v4:
  - no blank line change.

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                      |  106 +++++++++++++++++++-
 2 files changed, 103 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
index 5d8b7d5..c472883 100644
--- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
@@ -36,6 +36,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@40000000,0 {
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 7e14dbe..a784704 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -95,12 +95,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;
 
@@ -262,6 +264,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.
  */
@@ -383,7 +395,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,
@@ -955,9 +971,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)) {
@@ -1799,6 +1816,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;
@@ -1843,6 +1862,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;
@@ -1885,10 +1966,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;
 }
 
@@ -2156,6 +2247,11 @@ 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");
 		}
 	}
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 5/6] mtd: atmel_nand: enable Nand Flash Controller (NFC) write via sram
@ 2013-07-03  9:50   ` Josh Wu
  0 siblings, 0 replies; 34+ messages in thread
From: Josh Wu @ 2013-07-03  9:50 UTC (permalink / raw)
  To: linux-arm-kernel

This 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: 2
mtd_speedtest: MTD device size 41943040, eraseblock size 131072, page size 2048, count of eraseblocks 320, pages per eraseblock 64, OOB size 64
mtd_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

Signed-off-by: Josh Wu <josh.wu@atmel.com>
Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
---
v3 --> v4:
  - no blank line change.

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                      |  106 +++++++++++++++++++-
 2 files changed, 103 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
index 5d8b7d5..c472883 100644
--- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
@@ -36,6 +36,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 {
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 7e14dbe..a784704 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -95,12 +95,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;
 
@@ -262,6 +264,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.
  */
@@ -383,7 +395,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,
@@ -955,9 +971,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)) {
@@ -1799,6 +1816,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;
@@ -1843,6 +1862,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;
@@ -1885,10 +1966,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;
 }
 
@@ -2156,6 +2247,11 @@ 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");
 		}
 	}
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 6/6] mtd: ofpart: add compatible check for child nodes
  2013-07-03  9:50 ` Josh Wu
@ 2013-07-03  9:50   ` Josh Wu
  -1 siblings, 0 replies; 34+ messages in thread
From: Josh Wu @ 2013-07-03  9:50 UTC (permalink / raw)
  To: linux-mtd, linux-arm-kernel, dedekind1
  Cc: Josh Wu, computersforpeace, plagnioj, sergei.shtylyov

In case that the nand device will support some features like Nand Flash
Controller, we want to make the sub feature as a sub node of nand device.

Use such organization it is easy to enable/disable feature, also it is back
compatible and more readable.

If the sub-node has a compatible property then it is a driver not partition.

Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
v3 --> v4:
  - remove the 'len' parameter, just use NULL.
  - refine the commit message.
  - also add a NOTE in devicetree/bindings/mtd/partition.txt.

 .../devicetree/bindings/mtd/partition.txt          |    1 +
 drivers/mtd/ofpart.c                               |   13 ++++++++++++-
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/mtd/partition.txt b/Documentation/devicetree/bindings/mtd/partition.txt
index 9315ac9..8e5557d 100644
--- a/Documentation/devicetree/bindings/mtd/partition.txt
+++ b/Documentation/devicetree/bindings/mtd/partition.txt
@@ -4,6 +4,7 @@ Partitions can be represented by sub-nodes of an mtd device. This can be used
 on platforms which have strong conventions about which portions of a flash are
 used for what purposes, but which don't use an on-flash partition table such
 as RedBoot.
+NOTE: if the sub-node has a compatible string, then it is not a partition.
 
 #address-cells & #size-cells must both be present in the mtd device. There are
 two valid values for both:
diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
index 553d6d6..30fcea1 100644
--- a/drivers/mtd/ofpart.c
+++ b/drivers/mtd/ofpart.c
@@ -20,6 +20,10 @@
 #include <linux/slab.h>
 #include <linux/mtd/partitions.h>
 
+static bool node_has_compatible(struct device_node *pp)
+{
+	return of_get_property(pp, "compatible", NULL);
+}
 static int parse_ofpart_partitions(struct mtd_info *master,
 				   struct mtd_partition **pparts,
 				   struct mtd_part_parser_data *data)
@@ -40,8 +44,12 @@ 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))) {
+		if (node_has_compatible(pp))
+			continue;
+
 		nr_parts++;
+	}
 
 	if (nr_parts == 0)
 		return 0;
@@ -57,6 +65,9 @@ static int parse_ofpart_partitions(struct mtd_info *master,
 		int len;
 		int a_cells, s_cells;
 
+		if (node_has_compatible(pp))
+			continue;
+
 		reg = of_get_property(pp, "reg", &len);
 		if (!reg) {
 			nr_parts--;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 6/6] mtd: ofpart: add compatible check for child nodes
@ 2013-07-03  9:50   ` Josh Wu
  0 siblings, 0 replies; 34+ messages in thread
From: Josh Wu @ 2013-07-03  9:50 UTC (permalink / raw)
  To: linux-arm-kernel

In case that the nand device will support some features like Nand Flash
Controller, we want to make the sub feature as a sub node of nand device.

Use such organization it is easy to enable/disable feature, also it is back
compatible and more readable.

If the sub-node has a compatible property then it is a driver not partition.

Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
v3 --> v4:
  - remove the 'len' parameter, just use NULL.
  - refine the commit message.
  - also add a NOTE in devicetree/bindings/mtd/partition.txt.

 .../devicetree/bindings/mtd/partition.txt          |    1 +
 drivers/mtd/ofpart.c                               |   13 ++++++++++++-
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/mtd/partition.txt b/Documentation/devicetree/bindings/mtd/partition.txt
index 9315ac9..8e5557d 100644
--- a/Documentation/devicetree/bindings/mtd/partition.txt
+++ b/Documentation/devicetree/bindings/mtd/partition.txt
@@ -4,6 +4,7 @@ Partitions can be represented by sub-nodes of an mtd device. This can be used
 on platforms which have strong conventions about which portions of a flash are
 used for what purposes, but which don't use an on-flash partition table such
 as RedBoot.
+NOTE: if the sub-node has a compatible string, then it is not a partition.
 
 #address-cells & #size-cells must both be present in the mtd device. There are
 two valid values for both:
diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
index 553d6d6..30fcea1 100644
--- a/drivers/mtd/ofpart.c
+++ b/drivers/mtd/ofpart.c
@@ -20,6 +20,10 @@
 #include <linux/slab.h>
 #include <linux/mtd/partitions.h>
 
+static bool node_has_compatible(struct device_node *pp)
+{
+	return of_get_property(pp, "compatible", NULL);
+}
 static int parse_ofpart_partitions(struct mtd_info *master,
 				   struct mtd_partition **pparts,
 				   struct mtd_part_parser_data *data)
@@ -40,8 +44,12 @@ 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))) {
+		if (node_has_compatible(pp))
+			continue;
+
 		nr_parts++;
+	}
 
 	if (nr_parts == 0)
 		return 0;
@@ -57,6 +65,9 @@ static int parse_ofpart_partitions(struct mtd_info *master,
 		int len;
 		int a_cells, s_cells;
 
+		if (node_has_compatible(pp))
+			continue;
+
 		reg = of_get_property(pp, "reg", &len);
 		if (!reg) {
 			nr_parts--;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* Re: [PATCH 6/6] mtd: ofpart: add compatible check for child nodes
  2013-07-03  9:50   ` Josh Wu
  (?)
@ 2013-07-18  7:14     ` Brian Norris
  -1 siblings, 0 replies; 34+ messages in thread
From: Brian Norris @ 2013-07-18  7:14 UTC (permalink / raw)
  To: Josh Wu
  Cc: sergei.shtylyov, dedekind1, devicetree-discuss, linux-mtd,
	plagnioj, linux-arm-kernel

Adding device tree list, keeping patch context

On Wed, Jul 3, 2013 at 2:50 AM, Josh Wu <josh.wu@atmel.com> wrote:
> In case that the nand device will support some features like Nand Flash
> Controller, we want to make the sub feature as a sub node of nand device.
>
> Use such organization it is easy to enable/disable feature, also it is back
> compatible and more readable.
>
> If the sub-node has a compatible property then it is a driver not partition.
>
> Signed-off-by: Josh Wu <josh.wu@atmel.com>

I just came back to this patch series. I think this patch might be
deserving of a review by the device-tree mailing list. (It also
doesn't deserve to die in MTD purgatory.)

BTW, it looks good to me, so:

Acked-by: Brian Norris <computersforpeace@gmail.com>

Thanks,
Brian

> ---
> v3 --> v4:
>   - remove the 'len' parameter, just use NULL.
>   - refine the commit message.
>   - also add a NOTE in devicetree/bindings/mtd/partition.txt.
>
>  .../devicetree/bindings/mtd/partition.txt          |    1 +
>  drivers/mtd/ofpart.c                               |   13 ++++++++++++-
>  2 files changed, 13 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/mtd/partition.txt b/Documentation/devicetree/bindings/mtd/partition.txt
> index 9315ac9..8e5557d 100644
> --- a/Documentation/devicetree/bindings/mtd/partition.txt
> +++ b/Documentation/devicetree/bindings/mtd/partition.txt
> @@ -4,6 +4,7 @@ Partitions can be represented by sub-nodes of an mtd device. This can be used
>  on platforms which have strong conventions about which portions of a flash are
>  used for what purposes, but which don't use an on-flash partition table such
>  as RedBoot.
> +NOTE: if the sub-node has a compatible string, then it is not a partition.
>
>  #address-cells & #size-cells must both be present in the mtd device. There are
>  two valid values for both:
> diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
> index 553d6d6..30fcea1 100644
> --- a/drivers/mtd/ofpart.c
> +++ b/drivers/mtd/ofpart.c
> @@ -20,6 +20,10 @@
>  #include <linux/slab.h>
>  #include <linux/mtd/partitions.h>
>
> +static bool node_has_compatible(struct device_node *pp)
> +{
> +       return of_get_property(pp, "compatible", NULL);
> +}
>  static int parse_ofpart_partitions(struct mtd_info *master,
>                                    struct mtd_partition **pparts,
>                                    struct mtd_part_parser_data *data)
> @@ -40,8 +44,12 @@ 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))) {
> +               if (node_has_compatible(pp))
> +                       continue;
> +
>                 nr_parts++;
> +       }
>
>         if (nr_parts == 0)
>                 return 0;
> @@ -57,6 +65,9 @@ static int parse_ofpart_partitions(struct mtd_info *master,
>                 int len;
>                 int a_cells, s_cells;
>
> +               if (node_has_compatible(pp))
> +                       continue;
> +
>                 reg = of_get_property(pp, "reg", &len);
>                 if (!reg) {
>                         nr_parts--;
> --
> 1.7.9.5
>

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 6/6] mtd: ofpart: add compatible check for child nodes
@ 2013-07-18  7:14     ` Brian Norris
  0 siblings, 0 replies; 34+ messages in thread
From: Brian Norris @ 2013-07-18  7:14 UTC (permalink / raw)
  To: Josh Wu
  Cc: sergei.shtylyov, dedekind1, devicetree-discuss, linux-mtd,
	plagnioj, linux-arm-kernel

Adding device tree list, keeping patch context

On Wed, Jul 3, 2013 at 2:50 AM, Josh Wu <josh.wu@atmel.com> wrote:
> In case that the nand device will support some features like Nand Flash
> Controller, we want to make the sub feature as a sub node of nand device.
>
> Use such organization it is easy to enable/disable feature, also it is back
> compatible and more readable.
>
> If the sub-node has a compatible property then it is a driver not partition.
>
> Signed-off-by: Josh Wu <josh.wu@atmel.com>

I just came back to this patch series. I think this patch might be
deserving of a review by the device-tree mailing list. (It also
doesn't deserve to die in MTD purgatory.)

BTW, it looks good to me, so:

Acked-by: Brian Norris <computersforpeace@gmail.com>

Thanks,
Brian

> ---
> v3 --> v4:
>   - remove the 'len' parameter, just use NULL.
>   - refine the commit message.
>   - also add a NOTE in devicetree/bindings/mtd/partition.txt.
>
>  .../devicetree/bindings/mtd/partition.txt          |    1 +
>  drivers/mtd/ofpart.c                               |   13 ++++++++++++-
>  2 files changed, 13 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/mtd/partition.txt b/Documentation/devicetree/bindings/mtd/partition.txt
> index 9315ac9..8e5557d 100644
> --- a/Documentation/devicetree/bindings/mtd/partition.txt
> +++ b/Documentation/devicetree/bindings/mtd/partition.txt
> @@ -4,6 +4,7 @@ Partitions can be represented by sub-nodes of an mtd device. This can be used
>  on platforms which have strong conventions about which portions of a flash are
>  used for what purposes, but which don't use an on-flash partition table such
>  as RedBoot.
> +NOTE: if the sub-node has a compatible string, then it is not a partition.
>
>  #address-cells & #size-cells must both be present in the mtd device. There are
>  two valid values for both:
> diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
> index 553d6d6..30fcea1 100644
> --- a/drivers/mtd/ofpart.c
> +++ b/drivers/mtd/ofpart.c
> @@ -20,6 +20,10 @@
>  #include <linux/slab.h>
>  #include <linux/mtd/partitions.h>
>
> +static bool node_has_compatible(struct device_node *pp)
> +{
> +       return of_get_property(pp, "compatible", NULL);
> +}
>  static int parse_ofpart_partitions(struct mtd_info *master,
>                                    struct mtd_partition **pparts,
>                                    struct mtd_part_parser_data *data)
> @@ -40,8 +44,12 @@ 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))) {
> +               if (node_has_compatible(pp))
> +                       continue;
> +
>                 nr_parts++;
> +       }
>
>         if (nr_parts == 0)
>                 return 0;
> @@ -57,6 +65,9 @@ static int parse_ofpart_partitions(struct mtd_info *master,
>                 int len;
>                 int a_cells, s_cells;
>
> +               if (node_has_compatible(pp))
> +                       continue;
> +
>                 reg = of_get_property(pp, "reg", &len);
>                 if (!reg) {
>                         nr_parts--;
> --
> 1.7.9.5
>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 6/6] mtd: ofpart: add compatible check for child nodes
@ 2013-07-18  7:14     ` Brian Norris
  0 siblings, 0 replies; 34+ messages in thread
From: Brian Norris @ 2013-07-18  7:14 UTC (permalink / raw)
  To: linux-arm-kernel

Adding device tree list, keeping patch context

On Wed, Jul 3, 2013 at 2:50 AM, Josh Wu <josh.wu@atmel.com> wrote:
> In case that the nand device will support some features like Nand Flash
> Controller, we want to make the sub feature as a sub node of nand device.
>
> Use such organization it is easy to enable/disable feature, also it is back
> compatible and more readable.
>
> If the sub-node has a compatible property then it is a driver not partition.
>
> Signed-off-by: Josh Wu <josh.wu@atmel.com>

I just came back to this patch series. I think this patch might be
deserving of a review by the device-tree mailing list. (It also
doesn't deserve to die in MTD purgatory.)

BTW, it looks good to me, so:

Acked-by: Brian Norris <computersforpeace@gmail.com>

Thanks,
Brian

> ---
> v3 --> v4:
>   - remove the 'len' parameter, just use NULL.
>   - refine the commit message.
>   - also add a NOTE in devicetree/bindings/mtd/partition.txt.
>
>  .../devicetree/bindings/mtd/partition.txt          |    1 +
>  drivers/mtd/ofpart.c                               |   13 ++++++++++++-
>  2 files changed, 13 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/mtd/partition.txt b/Documentation/devicetree/bindings/mtd/partition.txt
> index 9315ac9..8e5557d 100644
> --- a/Documentation/devicetree/bindings/mtd/partition.txt
> +++ b/Documentation/devicetree/bindings/mtd/partition.txt
> @@ -4,6 +4,7 @@ Partitions can be represented by sub-nodes of an mtd device. This can be used
>  on platforms which have strong conventions about which portions of a flash are
>  used for what purposes, but which don't use an on-flash partition table such
>  as RedBoot.
> +NOTE: if the sub-node has a compatible string, then it is not a partition.
>
>  #address-cells & #size-cells must both be present in the mtd device. There are
>  two valid values for both:
> diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
> index 553d6d6..30fcea1 100644
> --- a/drivers/mtd/ofpart.c
> +++ b/drivers/mtd/ofpart.c
> @@ -20,6 +20,10 @@
>  #include <linux/slab.h>
>  #include <linux/mtd/partitions.h>
>
> +static bool node_has_compatible(struct device_node *pp)
> +{
> +       return of_get_property(pp, "compatible", NULL);
> +}
>  static int parse_ofpart_partitions(struct mtd_info *master,
>                                    struct mtd_partition **pparts,
>                                    struct mtd_part_parser_data *data)
> @@ -40,8 +44,12 @@ 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))) {
> +               if (node_has_compatible(pp))
> +                       continue;
> +
>                 nr_parts++;
> +       }
>
>         if (nr_parts == 0)
>                 return 0;
> @@ -57,6 +65,9 @@ static int parse_ofpart_partitions(struct mtd_info *master,
>                 int len;
>                 int a_cells, s_cells;
>
> +               if (node_has_compatible(pp))
> +                       continue;
> +
>                 reg = of_get_property(pp, "reg", &len);
>                 if (!reg) {
>                         nr_parts--;
> --
> 1.7.9.5
>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 6/6] mtd: ofpart: add compatible check for child nodes
  2013-07-18  7:14     ` Brian Norris
  (?)
@ 2013-07-18  8:28       ` Jean-Christophe PLAGNIOL-VILLARD
  -1 siblings, 0 replies; 34+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-07-18  8:28 UTC (permalink / raw)
  To: Brian Norris, Rob Herring
  Cc: sergei.shtylyov, dedekind1, devicetree-discuss, Josh Wu,
	linux-mtd, linux-arm-kernel

On 00:14 Thu 18 Jul     , Brian Norris wrote:
> Adding device tree list, keeping patch context
> 
> On Wed, Jul 3, 2013 at 2:50 AM, Josh Wu <josh.wu@atmel.com> wrote:
> > In case that the nand device will support some features like Nand Flash
> > Controller, we want to make the sub feature as a sub node of nand device.
> >
> > Use such organization it is easy to enable/disable feature, also it is back
> > compatible and more readable.
> >
> > If the sub-node has a compatible property then it is a driver not partition.
> >
> > Signed-off-by: Josh Wu <josh.wu@atmel.com>
> 
> I just came back to this patch series. I think this patch might be
> deserving of a review by the device-tree mailing list. (It also
> doesn't deserve to die in MTD purgatory.)
> 
> BTW, it looks good to me, so:
> 
> Acked-by: Brian Norris <computersforpeace@gmail.com>
Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>

Rob can take a look on it

Best Regards,
J.
> 
> Thanks,
> Brian
> 
> > ---
> > v3 --> v4:
> >   - remove the 'len' parameter, just use NULL.
> >   - refine the commit message.
> >   - also add a NOTE in devicetree/bindings/mtd/partition.txt.
> >
> >  .../devicetree/bindings/mtd/partition.txt          |    1 +
> >  drivers/mtd/ofpart.c                               |   13 ++++++++++++-
> >  2 files changed, 13 insertions(+), 1 deletion(-)
> >
> > diff --git a/Documentation/devicetree/bindings/mtd/partition.txt b/Documentation/devicetree/bindings/mtd/partition.txt
> > index 9315ac9..8e5557d 100644
> > --- a/Documentation/devicetree/bindings/mtd/partition.txt
> > +++ b/Documentation/devicetree/bindings/mtd/partition.txt
> > @@ -4,6 +4,7 @@ Partitions can be represented by sub-nodes of an mtd device. This can be used
> >  on platforms which have strong conventions about which portions of a flash are
> >  used for what purposes, but which don't use an on-flash partition table such
> >  as RedBoot.
> > +NOTE: if the sub-node has a compatible string, then it is not a partition.
> >
> >  #address-cells & #size-cells must both be present in the mtd device. There are
> >  two valid values for both:
> > diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
> > index 553d6d6..30fcea1 100644
> > --- a/drivers/mtd/ofpart.c
> > +++ b/drivers/mtd/ofpart.c
> > @@ -20,6 +20,10 @@
> >  #include <linux/slab.h>
> >  #include <linux/mtd/partitions.h>
> >
> > +static bool node_has_compatible(struct device_node *pp)
> > +{
> > +       return of_get_property(pp, "compatible", NULL);
> > +}
> >  static int parse_ofpart_partitions(struct mtd_info *master,
> >                                    struct mtd_partition **pparts,
> >                                    struct mtd_part_parser_data *data)
> > @@ -40,8 +44,12 @@ 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))) {
> > +               if (node_has_compatible(pp))
> > +                       continue;
> > +
> >                 nr_parts++;
> > +       }
> >
> >         if (nr_parts == 0)
> >                 return 0;
> > @@ -57,6 +65,9 @@ static int parse_ofpart_partitions(struct mtd_info *master,
> >                 int len;
> >                 int a_cells, s_cells;
> >
> > +               if (node_has_compatible(pp))
> > +                       continue;
> > +
> >                 reg = of_get_property(pp, "reg", &len);
> >                 if (!reg) {
> >                         nr_parts--;
> > --
> > 1.7.9.5
> >

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 6/6] mtd: ofpart: add compatible check for child nodes
@ 2013-07-18  8:28       ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 0 replies; 34+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-07-18  8:28 UTC (permalink / raw)
  To: Brian Norris, Rob Herring
  Cc: sergei.shtylyov, dedekind1, devicetree-discuss, Josh Wu,
	linux-mtd, linux-arm-kernel

On 00:14 Thu 18 Jul     , Brian Norris wrote:
> Adding device tree list, keeping patch context
> 
> On Wed, Jul 3, 2013 at 2:50 AM, Josh Wu <josh.wu@atmel.com> wrote:
> > In case that the nand device will support some features like Nand Flash
> > Controller, we want to make the sub feature as a sub node of nand device.
> >
> > Use such organization it is easy to enable/disable feature, also it is back
> > compatible and more readable.
> >
> > If the sub-node has a compatible property then it is a driver not partition.
> >
> > Signed-off-by: Josh Wu <josh.wu@atmel.com>
> 
> I just came back to this patch series. I think this patch might be
> deserving of a review by the device-tree mailing list. (It also
> doesn't deserve to die in MTD purgatory.)
> 
> BTW, it looks good to me, so:
> 
> Acked-by: Brian Norris <computersforpeace@gmail.com>
Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>

Rob can take a look on it

Best Regards,
J.
> 
> Thanks,
> Brian
> 
> > ---
> > v3 --> v4:
> >   - remove the 'len' parameter, just use NULL.
> >   - refine the commit message.
> >   - also add a NOTE in devicetree/bindings/mtd/partition.txt.
> >
> >  .../devicetree/bindings/mtd/partition.txt          |    1 +
> >  drivers/mtd/ofpart.c                               |   13 ++++++++++++-
> >  2 files changed, 13 insertions(+), 1 deletion(-)
> >
> > diff --git a/Documentation/devicetree/bindings/mtd/partition.txt b/Documentation/devicetree/bindings/mtd/partition.txt
> > index 9315ac9..8e5557d 100644
> > --- a/Documentation/devicetree/bindings/mtd/partition.txt
> > +++ b/Documentation/devicetree/bindings/mtd/partition.txt
> > @@ -4,6 +4,7 @@ Partitions can be represented by sub-nodes of an mtd device. This can be used
> >  on platforms which have strong conventions about which portions of a flash are
> >  used for what purposes, but which don't use an on-flash partition table such
> >  as RedBoot.
> > +NOTE: if the sub-node has a compatible string, then it is not a partition.
> >
> >  #address-cells & #size-cells must both be present in the mtd device. There are
> >  two valid values for both:
> > diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
> > index 553d6d6..30fcea1 100644
> > --- a/drivers/mtd/ofpart.c
> > +++ b/drivers/mtd/ofpart.c
> > @@ -20,6 +20,10 @@
> >  #include <linux/slab.h>
> >  #include <linux/mtd/partitions.h>
> >
> > +static bool node_has_compatible(struct device_node *pp)
> > +{
> > +       return of_get_property(pp, "compatible", NULL);
> > +}
> >  static int parse_ofpart_partitions(struct mtd_info *master,
> >                                    struct mtd_partition **pparts,
> >                                    struct mtd_part_parser_data *data)
> > @@ -40,8 +44,12 @@ 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))) {
> > +               if (node_has_compatible(pp))
> > +                       continue;
> > +
> >                 nr_parts++;
> > +       }
> >
> >         if (nr_parts == 0)
> >                 return 0;
> > @@ -57,6 +65,9 @@ static int parse_ofpart_partitions(struct mtd_info *master,
> >                 int len;
> >                 int a_cells, s_cells;
> >
> > +               if (node_has_compatible(pp))
> > +                       continue;
> > +
> >                 reg = of_get_property(pp, "reg", &len);
> >                 if (!reg) {
> >                         nr_parts--;
> > --
> > 1.7.9.5
> >

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 6/6] mtd: ofpart: add compatible check for child nodes
@ 2013-07-18  8:28       ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 0 replies; 34+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-07-18  8:28 UTC (permalink / raw)
  To: linux-arm-kernel

On 00:14 Thu 18 Jul     , Brian Norris wrote:
> Adding device tree list, keeping patch context
> 
> On Wed, Jul 3, 2013 at 2:50 AM, Josh Wu <josh.wu@atmel.com> wrote:
> > In case that the nand device will support some features like Nand Flash
> > Controller, we want to make the sub feature as a sub node of nand device.
> >
> > Use such organization it is easy to enable/disable feature, also it is back
> > compatible and more readable.
> >
> > If the sub-node has a compatible property then it is a driver not partition.
> >
> > Signed-off-by: Josh Wu <josh.wu@atmel.com>
> 
> I just came back to this patch series. I think this patch might be
> deserving of a review by the device-tree mailing list. (It also
> doesn't deserve to die in MTD purgatory.)
> 
> BTW, it looks good to me, so:
> 
> Acked-by: Brian Norris <computersforpeace@gmail.com>
Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>

Rob can take a look on it

Best Regards,
J.
> 
> Thanks,
> Brian
> 
> > ---
> > v3 --> v4:
> >   - remove the 'len' parameter, just use NULL.
> >   - refine the commit message.
> >   - also add a NOTE in devicetree/bindings/mtd/partition.txt.
> >
> >  .../devicetree/bindings/mtd/partition.txt          |    1 +
> >  drivers/mtd/ofpart.c                               |   13 ++++++++++++-
> >  2 files changed, 13 insertions(+), 1 deletion(-)
> >
> > diff --git a/Documentation/devicetree/bindings/mtd/partition.txt b/Documentation/devicetree/bindings/mtd/partition.txt
> > index 9315ac9..8e5557d 100644
> > --- a/Documentation/devicetree/bindings/mtd/partition.txt
> > +++ b/Documentation/devicetree/bindings/mtd/partition.txt
> > @@ -4,6 +4,7 @@ Partitions can be represented by sub-nodes of an mtd device. This can be used
> >  on platforms which have strong conventions about which portions of a flash are
> >  used for what purposes, but which don't use an on-flash partition table such
> >  as RedBoot.
> > +NOTE: if the sub-node has a compatible string, then it is not a partition.
> >
> >  #address-cells & #size-cells must both be present in the mtd device. There are
> >  two valid values for both:
> > diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
> > index 553d6d6..30fcea1 100644
> > --- a/drivers/mtd/ofpart.c
> > +++ b/drivers/mtd/ofpart.c
> > @@ -20,6 +20,10 @@
> >  #include <linux/slab.h>
> >  #include <linux/mtd/partitions.h>
> >
> > +static bool node_has_compatible(struct device_node *pp)
> > +{
> > +       return of_get_property(pp, "compatible", NULL);
> > +}
> >  static int parse_ofpart_partitions(struct mtd_info *master,
> >                                    struct mtd_partition **pparts,
> >                                    struct mtd_part_parser_data *data)
> > @@ -40,8 +44,12 @@ 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))) {
> > +               if (node_has_compatible(pp))
> > +                       continue;
> > +
> >                 nr_parts++;
> > +       }
> >
> >         if (nr_parts == 0)
> >                 return 0;
> > @@ -57,6 +65,9 @@ static int parse_ofpart_partitions(struct mtd_info *master,
> >                 int len;
> >                 int a_cells, s_cells;
> >
> > +               if (node_has_compatible(pp))
> > +                       continue;
> > +
> >                 reg = of_get_property(pp, "reg", &len);
> >                 if (!reg) {
> >                         nr_parts--;
> > --
> > 1.7.9.5
> >

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v5 0/6] mtd: atmel_nand: enable Nand Flash Controller (NFC) support
  2013-07-03  9:50 ` Josh Wu
@ 2013-08-05  9:55   ` Artem Bityutskiy
  -1 siblings, 0 replies; 34+ messages in thread
From: Artem Bityutskiy @ 2013-08-05  9:55 UTC (permalink / raw)
  To: Josh Wu
  Cc: plagnioj, computersforpeace, linux-mtd, sergei.shtylyov,
	linux-arm-kernel

On Wed, 2013-07-03 at 17:50 +0800, Josh Wu wrote:
> 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.

Hi,

would you please update this patch-set against the tip of the l2-mtd.git
tree, and re-send? It does not apply with many conflicts.

-- 
Best Regards,
Artem Bityutskiy

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH v5 0/6] mtd: atmel_nand: enable Nand Flash Controller (NFC) support
@ 2013-08-05  9:55   ` Artem Bityutskiy
  0 siblings, 0 replies; 34+ messages in thread
From: Artem Bityutskiy @ 2013-08-05  9:55 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 2013-07-03 at 17:50 +0800, Josh Wu wrote:
> 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.

Hi,

would you please update this patch-set against the tip of the l2-mtd.git
tree, and re-send? It does not apply with many conflicts.

-- 
Best Regards,
Artem Bityutskiy

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v5 0/6] mtd: atmel_nand: enable Nand Flash Controller (NFC) support
  2013-07-03  9:50 ` Josh Wu
@ 2013-08-05  9:56   ` Artem Bityutskiy
  -1 siblings, 0 replies; 34+ messages in thread
From: Artem Bityutskiy @ 2013-08-05  9:56 UTC (permalink / raw)
  To: Josh Wu
  Cc: plagnioj, computersforpeace, linux-mtd, sergei.shtylyov,
	linux-arm-kernel

On Wed, 2013-07-03 at 17:50 +0800, Josh Wu wrote:
> 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.

Please, also all all the acks to the patches.

-- 
Best Regards,
Artem Bityutskiy

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH v5 0/6] mtd: atmel_nand: enable Nand Flash Controller (NFC) support
@ 2013-08-05  9:56   ` Artem Bityutskiy
  0 siblings, 0 replies; 34+ messages in thread
From: Artem Bityutskiy @ 2013-08-05  9:56 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 2013-07-03 at 17:50 +0800, Josh Wu wrote:
> 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.

Please, also all all the acks to the patches.

-- 
Best Regards,
Artem Bityutskiy

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v5 0/6] mtd: atmel_nand: enable Nand Flash Controller (NFC) support
  2013-08-05  9:56   ` Artem Bityutskiy
@ 2013-08-05 11:28     ` Josh Wu
  -1 siblings, 0 replies; 34+ messages in thread
From: Josh Wu @ 2013-08-05 11:28 UTC (permalink / raw)
  To: dedekind1
  Cc: plagnioj, computersforpeace, linux-mtd, sergei.shtylyov,
	linux-arm-kernel

Dear Artem

On 8/5/2013 5:56 PM, Artem Bityutskiy wrote:
> On Wed, 2013-07-03 at 17:50 +0800, Josh Wu wrote:
>> 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.
> Please, also all all the acks to the patches.
>

I already sent out the v6 for this NFC patch series. Which is rebased on 
the top of l2-mtd.git and add the Acks in patch. Thanks for the remind.

Best Regards,
Josh Wu

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH v5 0/6] mtd: atmel_nand: enable Nand Flash Controller (NFC) support
@ 2013-08-05 11:28     ` Josh Wu
  0 siblings, 0 replies; 34+ messages in thread
From: Josh Wu @ 2013-08-05 11:28 UTC (permalink / raw)
  To: linux-arm-kernel

Dear Artem

On 8/5/2013 5:56 PM, Artem Bityutskiy wrote:
> On Wed, 2013-07-03 at 17:50 +0800, Josh Wu wrote:
>> 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.
> Please, also all all the acks to the patches.
>

I already sent out the v6 for this NFC patch series. Which is rebased on 
the top of l2-mtd.git and add the Acks in patch. Thanks for the remind.

Best Regards,
Josh Wu

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 1/6] MTD: atmel_nand: use devm_xxx gpio kzalloc, gpio and ioremap
  2013-08-05 11:14   ` Josh Wu
@ 2013-08-05 13:04     ` Artem Bityutskiy
  -1 siblings, 0 replies; 34+ messages in thread
From: Artem Bityutskiy @ 2013-08-05 13:04 UTC (permalink / raw)
  To: Josh Wu
  Cc: sergei.shtylyov, nicolas.ferre, linux-mtd, computersforpeace,
	plagnioj, linux-arm-kernel

On Mon, 2013-08-05 at 19:14 +0800, Josh Wu wrote:
> From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
> 
> this will allow to simply the error and remove path
> 
> Cc: linux-mtd@lists.infradead.org
> Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
> Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
> [josh.wu@atmel.com: fix checkpatch warnings and rebase to latest mtd git tree]
> [josh.wu@atmel.com: replace devm_request_and_ioremap with devm_ioremap_resource]
> Signed-off-by: Josh Wu <josh.wu@atmel.com>

Pushed to l2-mtd.git. I did not review it much, though, so extra eyes
would not hurt. But it generally looks good.

-- 
Best Regards,
Artem Bityutskiy

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 1/6] MTD: atmel_nand: use devm_xxx gpio kzalloc, gpio and ioremap
@ 2013-08-05 13:04     ` Artem Bityutskiy
  0 siblings, 0 replies; 34+ messages in thread
From: Artem Bityutskiy @ 2013-08-05 13:04 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 2013-08-05 at 19:14 +0800, Josh Wu wrote:
> From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
> 
> this will allow to simply the error and remove path
> 
> Cc: linux-mtd at lists.infradead.org
> Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
> Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
> [josh.wu at atmel.com: fix checkpatch warnings and rebase to latest mtd git tree]
> [josh.wu at atmel.com: replace devm_request_and_ioremap with devm_ioremap_resource]
> Signed-off-by: Josh Wu <josh.wu@atmel.com>

Pushed to l2-mtd.git. I did not review it much, though, so extra eyes
would not hurt. But it generally looks good.

-- 
Best Regards,
Artem Bityutskiy

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 1/6] MTD: atmel_nand: use devm_xxx gpio kzalloc, gpio and ioremap
  2013-08-05 11:14 [PATCH v6 " Josh Wu
@ 2013-08-05 11:14   ` Josh Wu
  0 siblings, 0 replies; 34+ messages in thread
From: Josh Wu @ 2013-08-05 11:14 UTC (permalink / raw)
  To: linux-mtd, linux-arm-kernel, dedekind1
  Cc: nicolas.ferre, computersforpeace, plagnioj, sergei.shtylyov, Josh Wu

From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>

this will allow to simply the error and remove path

Cc: linux-mtd@lists.infradead.org
Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
[josh.wu@atmel.com: fix checkpatch warnings and rebase to latest mtd git tree]
[josh.wu@atmel.com: replace devm_request_and_ioremap with devm_ioremap_resource]
Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
v5 --> v6:
  rebase on top of l2-mtd.git.

v3 --> v4:
  use devm_ioremap_resource instead of devm_request_and_ioremap.

 drivers/mtd/nand/atmel_nand.c |  180 +++++++++++++++--------------------------
 1 file changed, 65 insertions(+), 115 deletions(-)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index a43adce..3d7db95 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -358,43 +358,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)
@@ -1015,27 +1006,28 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
 		return 0;
 	}
 
-	host->ecc = ioremap(regs->start, resource_size(regs));
-	if (host->ecc == NULL) {
+	host->ecc = devm_ioremap_resource(&pdev->dev, regs);
+	if (IS_ERR(host->ecc)) {
 		dev_err(host->dev, "ioremap failed\n");
-		err_no = -EIO;
-		goto err_pmecc_ioremap;
+		err_no = PTR_ERR(host->ecc);
+		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_ioremap_resource(&pdev->dev, regs_pmerr);
+	if (IS_ERR(host->pmerrloc_base)) {
+		dev_err(host->dev,
+			"Can not get I/O resource for PMECC ERRLOC controller!\n");
+		err_no = PTR_ERR(host->pmerrloc_base);
+		goto err;
 	}
 
-	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;
+	regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+	host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom);
+	if (IS_ERR(host->pmecc_rom_base)) {
+		dev_err(host->dev, "Can not get I/O resource for ROM!\n");
+		err_no = PTR_ERR(host->pmecc_rom_base);
+		goto err;
 	}
 
 	/* ECC is calculated for the whole page (1 step) */
@@ -1060,7 +1052,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,
@@ -1085,7 +1077,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;
@@ -1095,15 +1087,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;
 }
 
@@ -1407,10 +1391,10 @@ static int __init atmel_hw_nand_init_params(struct platform_device *pdev,
 		return 0;
 	}
 
-	host->ecc = ioremap(regs->start, resource_size(regs));
-	if (host->ecc == NULL) {
+	host->ecc = devm_ioremap_resource(&pdev->dev, regs);
+	if (IS_ERR(host->ecc)) {
 		dev_err(host->dev, "ioremap failed\n");
-		return -EIO;
+		return PTR_ERR(host->ecc);
 	}
 
 	/* ECC is calculated for the whole page (1 step) */
@@ -1464,27 +1448,21 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 	struct mtd_part_parser_data ppdata = {};
 	int res;
 
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem) {
-		printk(KERN_ERR "atmel_nand: can't get I/O resource mem\n");
-		return -ENXIO;
-	}
-
 	/* 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));
-	if (host->io_base == NULL) {
-		printk(KERN_ERR "atmel_nand: ioremap failed\n");
-		res = -EIO;
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	host->io_base = devm_ioremap_resource(&pdev->dev, mem);
+	if (IS_ERR(host->io_base)) {
+		dev_err(&pdev->dev, "atmel_nand: ioremap resource failed\n");
+		res = PTR_ERR(host->io_base);
 		goto err_nand_ioremap;
 	}
+	host->io_phys = (dma_addr_t)mem->start;
 
 	mtd = &host->mtd;
 	nand_chip = &host->nand_chip;
@@ -1492,7 +1470,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));
@@ -1508,12 +1486,13 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 	nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
 
 	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);
@@ -1521,19 +1500,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);
@@ -1541,7 +1521,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;
 		}
 	}
 
@@ -1558,7 +1538,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",
@@ -1636,26 +1617,15 @@ 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:
 	atmel_nand_disable(host);
 	if (host->dma_chan)
 		dma_release_channel(host->dma_chan);
-err_ecc_ioremap:
-	iounmap(host->io_base);
 err_nand_ioremap:
-	kfree(host);
 	return res;
 }
 
@@ -1675,31 +1645,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;
 }
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 1/6] MTD: atmel_nand: use devm_xxx gpio kzalloc, gpio and ioremap
@ 2013-08-05 11:14   ` Josh Wu
  0 siblings, 0 replies; 34+ messages in thread
From: Josh Wu @ 2013-08-05 11:14 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>

this will allow to simply the error and remove path

Cc: linux-mtd at lists.infradead.org
Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
[josh.wu at atmel.com: fix checkpatch warnings and rebase to latest mtd git tree]
[josh.wu at atmel.com: replace devm_request_and_ioremap with devm_ioremap_resource]
Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
v5 --> v6:
  rebase on top of l2-mtd.git.

v3 --> v4:
  use devm_ioremap_resource instead of devm_request_and_ioremap.

 drivers/mtd/nand/atmel_nand.c |  180 +++++++++++++++--------------------------
 1 file changed, 65 insertions(+), 115 deletions(-)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index a43adce..3d7db95 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -358,43 +358,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)
@@ -1015,27 +1006,28 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
 		return 0;
 	}
 
-	host->ecc = ioremap(regs->start, resource_size(regs));
-	if (host->ecc == NULL) {
+	host->ecc = devm_ioremap_resource(&pdev->dev, regs);
+	if (IS_ERR(host->ecc)) {
 		dev_err(host->dev, "ioremap failed\n");
-		err_no = -EIO;
-		goto err_pmecc_ioremap;
+		err_no = PTR_ERR(host->ecc);
+		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_ioremap_resource(&pdev->dev, regs_pmerr);
+	if (IS_ERR(host->pmerrloc_base)) {
+		dev_err(host->dev,
+			"Can not get I/O resource for PMECC ERRLOC controller!\n");
+		err_no = PTR_ERR(host->pmerrloc_base);
+		goto err;
 	}
 
-	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;
+	regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+	host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom);
+	if (IS_ERR(host->pmecc_rom_base)) {
+		dev_err(host->dev, "Can not get I/O resource for ROM!\n");
+		err_no = PTR_ERR(host->pmecc_rom_base);
+		goto err;
 	}
 
 	/* ECC is calculated for the whole page (1 step) */
@@ -1060,7 +1052,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,
@@ -1085,7 +1077,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;
@@ -1095,15 +1087,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;
 }
 
@@ -1407,10 +1391,10 @@ static int __init atmel_hw_nand_init_params(struct platform_device *pdev,
 		return 0;
 	}
 
-	host->ecc = ioremap(regs->start, resource_size(regs));
-	if (host->ecc == NULL) {
+	host->ecc = devm_ioremap_resource(&pdev->dev, regs);
+	if (IS_ERR(host->ecc)) {
 		dev_err(host->dev, "ioremap failed\n");
-		return -EIO;
+		return PTR_ERR(host->ecc);
 	}
 
 	/* ECC is calculated for the whole page (1 step) */
@@ -1464,27 +1448,21 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 	struct mtd_part_parser_data ppdata = {};
 	int res;
 
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem) {
-		printk(KERN_ERR "atmel_nand: can't get I/O resource mem\n");
-		return -ENXIO;
-	}
-
 	/* 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));
-	if (host->io_base == NULL) {
-		printk(KERN_ERR "atmel_nand: ioremap failed\n");
-		res = -EIO;
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	host->io_base = devm_ioremap_resource(&pdev->dev, mem);
+	if (IS_ERR(host->io_base)) {
+		dev_err(&pdev->dev, "atmel_nand: ioremap resource failed\n");
+		res = PTR_ERR(host->io_base);
 		goto err_nand_ioremap;
 	}
+	host->io_phys = (dma_addr_t)mem->start;
 
 	mtd = &host->mtd;
 	nand_chip = &host->nand_chip;
@@ -1492,7 +1470,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));
@@ -1508,12 +1486,13 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 	nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
 
 	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);
@@ -1521,19 +1500,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);
@@ -1541,7 +1521,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;
 		}
 	}
 
@@ -1558,7 +1538,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",
@@ -1636,26 +1617,15 @@ 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:
 	atmel_nand_disable(host);
 	if (host->dma_chan)
 		dma_release_channel(host->dma_chan);
-err_ecc_ioremap:
-	iounmap(host->io_base);
 err_nand_ioremap:
-	kfree(host);
 	return res;
 }
 
@@ -1675,31 +1645,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;
 }
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 1/6] MTD: atmel_nand: use devm_xxx gpio kzalloc, gpio and ioremap
  2013-06-19  6:23 [PATCH v4 0/6] mtd: atmel_nand: enable Nand Flash Controller (NFC) support Josh Wu
@ 2013-06-19  6:23   ` Josh Wu
  0 siblings, 0 replies; 34+ messages in thread
From: Josh Wu @ 2013-06-19  6:23 UTC (permalink / raw)
  To: linux-mtd, linux-arm-kernel, dedekind1
  Cc: nicolas.ferre, computersforpeace, plagnioj, sergei.shtylyov, Josh Wu

From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>

this will allow to simply the error and remove path

Cc: linux-mtd@lists.infradead.org
Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
[josh.wu@atmel.com: fix checkpatch warnings and rebase to latest mtd git tree]
[josh.wu@atmel.com: replace devm_request_and_ioremap with devm_ioremap_resource]
Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
v3 --> v4:
  use devm_ioremap_resource instead of devm_request_and_ioremap.

 drivers/mtd/nand/atmel_nand.c |  182 +++++++++++++++--------------------------
 1 file changed, 66 insertions(+), 116 deletions(-)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 2d23d29..d39f364 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -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,28 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
 		return 0;
 	}
 
-	host->ecc = ioremap(regs->start, resource_size(regs));
-	if (host->ecc == NULL) {
+	host->ecc = devm_ioremap_resource(&pdev->dev, regs);
+	if (IS_ERR(host->ecc)) {
 		dev_err(host->dev, "ioremap failed\n");
-		err_no = -EIO;
-		goto err_pmecc_ioremap;
+		err_no = PTR_ERR(host->ecc);
+		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_ioremap_resource(&pdev->dev, regs_pmerr);
+	if (IS_ERR(host->pmerrloc_base)) {
+		dev_err(host->dev,
+			"Can not get I/O resource for PMECC ERRLOC controller!\n");
+		err_no = PTR_ERR(host->pmerrloc_base);
+		goto err;
 	}
 
-	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;
+	regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+	host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom);
+	if (IS_ERR(host->pmecc_rom_base)) {
+		dev_err(host->dev, "Can not get I/O resource for ROM!\n");
+		err_no = PTR_ERR(host->pmecc_rom_base);
+		goto err;
 	}
 
 	/* ECC is calculated for the whole page (1 step) */
@@ -1068,7 +1060,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 +1085,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 +1095,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,10 +1398,10 @@ static int __init atmel_hw_nand_init_params(struct platform_device *pdev,
 		return 0;
 	}
 
-	host->ecc = ioremap(regs->start, resource_size(regs));
-	if (host->ecc == NULL) {
+	host->ecc = devm_ioremap_resource(&pdev->dev, regs);
+	if (IS_ERR(host->ecc)) {
 		dev_err(host->dev, "ioremap failed\n");
-		return -EIO;
+		return PTR_ERR(host->ecc);
 	}
 
 	/* ECC is calculated for the whole page (1 step) */
@@ -1472,27 +1456,21 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 	int res;
 	struct pinctrl *pinctrl;
 
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem) {
-		printk(KERN_ERR "atmel_nand: can't get I/O resource mem\n");
-		return -ENXIO;
-	}
-
 	/* 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));
-	if (host->io_base == NULL) {
-		printk(KERN_ERR "atmel_nand: ioremap failed\n");
-		res = -EIO;
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	host->io_base = devm_ioremap_resource(&pdev->dev, mem);
+	if (IS_ERR(host->io_base)) {
+		dev_err(&pdev->dev, "atmel_nand: ioremap resource failed\n");
+		res = PTR_ERR(host->io_base);
 		goto err_nand_ioremap;
 	}
+	host->io_phys = (dma_addr_t)mem->start;
 
 	mtd = &host->mtd;
 	nand_chip = &host->nand_chip;
@@ -1500,7 +1478,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 +1497,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 +1515,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 +1536,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 +1553,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 +1632,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 +1641,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 +1661,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;
 }
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 1/6] MTD: atmel_nand: use devm_xxx gpio kzalloc, gpio and ioremap
@ 2013-06-19  6:23   ` Josh Wu
  0 siblings, 0 replies; 34+ messages in thread
From: Josh Wu @ 2013-06-19  6:23 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>

this will allow to simply the error and remove path

Cc: linux-mtd at lists.infradead.org
Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
[josh.wu at atmel.com: fix checkpatch warnings and rebase to latest mtd git tree]
[josh.wu at atmel.com: replace devm_request_and_ioremap with devm_ioremap_resource]
Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
v3 --> v4:
  use devm_ioremap_resource instead of devm_request_and_ioremap.

 drivers/mtd/nand/atmel_nand.c |  182 +++++++++++++++--------------------------
 1 file changed, 66 insertions(+), 116 deletions(-)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 2d23d29..d39f364 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -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,28 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
 		return 0;
 	}
 
-	host->ecc = ioremap(regs->start, resource_size(regs));
-	if (host->ecc == NULL) {
+	host->ecc = devm_ioremap_resource(&pdev->dev, regs);
+	if (IS_ERR(host->ecc)) {
 		dev_err(host->dev, "ioremap failed\n");
-		err_no = -EIO;
-		goto err_pmecc_ioremap;
+		err_no = PTR_ERR(host->ecc);
+		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_ioremap_resource(&pdev->dev, regs_pmerr);
+	if (IS_ERR(host->pmerrloc_base)) {
+		dev_err(host->dev,
+			"Can not get I/O resource for PMECC ERRLOC controller!\n");
+		err_no = PTR_ERR(host->pmerrloc_base);
+		goto err;
 	}
 
-	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;
+	regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+	host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom);
+	if (IS_ERR(host->pmecc_rom_base)) {
+		dev_err(host->dev, "Can not get I/O resource for ROM!\n");
+		err_no = PTR_ERR(host->pmecc_rom_base);
+		goto err;
 	}
 
 	/* ECC is calculated for the whole page (1 step) */
@@ -1068,7 +1060,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 +1085,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 +1095,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,10 +1398,10 @@ static int __init atmel_hw_nand_init_params(struct platform_device *pdev,
 		return 0;
 	}
 
-	host->ecc = ioremap(regs->start, resource_size(regs));
-	if (host->ecc == NULL) {
+	host->ecc = devm_ioremap_resource(&pdev->dev, regs);
+	if (IS_ERR(host->ecc)) {
 		dev_err(host->dev, "ioremap failed\n");
-		return -EIO;
+		return PTR_ERR(host->ecc);
 	}
 
 	/* ECC is calculated for the whole page (1 step) */
@@ -1472,27 +1456,21 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 	int res;
 	struct pinctrl *pinctrl;
 
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem) {
-		printk(KERN_ERR "atmel_nand: can't get I/O resource mem\n");
-		return -ENXIO;
-	}
-
 	/* 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));
-	if (host->io_base == NULL) {
-		printk(KERN_ERR "atmel_nand: ioremap failed\n");
-		res = -EIO;
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	host->io_base = devm_ioremap_resource(&pdev->dev, mem);
+	if (IS_ERR(host->io_base)) {
+		dev_err(&pdev->dev, "atmel_nand: ioremap resource failed\n");
+		res = PTR_ERR(host->io_base);
 		goto err_nand_ioremap;
 	}
+	host->io_phys = (dma_addr_t)mem->start;
 
 	mtd = &host->mtd;
 	nand_chip = &host->nand_chip;
@@ -1500,7 +1478,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 +1497,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 +1515,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 +1536,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 +1553,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 +1632,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 +1641,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 +1661,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;
 }
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 1/6] MTD: atmel_nand: use devm_xxx gpio kzalloc, gpio and ioremap
  2013-06-10 10:26 [PATCH v3 0/6] mtd: atmel_nand: enable Nand Flash Controller (NFC) support Josh Wu
@ 2013-06-10 10:26   ` Josh Wu
  0 siblings, 0 replies; 34+ messages in thread
From: Josh Wu @ 2013-06-10 10:26 UTC (permalink / raw)
  To: linux-mtd, linux-arm-kernel, dedekind1; +Cc: nicolas.ferre, plagnioj, Josh Wu

From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>

this will allow to simply the error and remove path

Cc: linux-mtd@lists.infradead.org
Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
[josh.wu@atmel.com: fix checkpatch warnings and rebase to latest mtd git tree]
Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
 drivers/mtd/nand/atmel_nand.c |  148 ++++++++++++++---------------------------
 1 file changed, 51 insertions(+), 97 deletions(-)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 2d23d29..c7a4016 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -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;
 }
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 1/6] MTD: atmel_nand: use devm_xxx gpio kzalloc, gpio and ioremap
@ 2013-06-10 10:26   ` Josh Wu
  0 siblings, 0 replies; 34+ messages in thread
From: Josh Wu @ 2013-06-10 10:26 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>

this will allow to simply the error and remove path

Cc: linux-mtd at lists.infradead.org
Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
[josh.wu at atmel.com: fix checkpatch warnings and rebase to latest mtd git tree]
Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
 drivers/mtd/nand/atmel_nand.c |  148 ++++++++++++++---------------------------
 1 file changed, 51 insertions(+), 97 deletions(-)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 2d23d29..c7a4016 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -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;
 }
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2013-08-05 13:04 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-07-03  9:50 [PATCH v5 0/6] mtd: atmel_nand: enable Nand Flash Controller (NFC) support Josh Wu
2013-07-03  9:50 ` Josh Wu
2013-07-03  9:50 ` [PATCH 1/6] MTD: atmel_nand: use devm_xxx gpio kzalloc, gpio and ioremap Josh Wu
2013-07-03  9:50   ` Josh Wu
2013-07-03  9:50 ` [PATCH 2/6] mtd: atmel_nand: replace pmecc enable code with one function Josh Wu
2013-07-03  9:50   ` Josh Wu
2013-07-03  9:50 ` [PATCH 3/6] mtd: atmel_nand: add Nand Flash Controller (NFC) support Josh Wu
2013-07-03  9:50   ` Josh Wu
2013-07-03  9:50 ` [PATCH 4/6] mtd: atmel_nand: enable Nand Flash Controller (NFC) read data via sram Josh Wu
2013-07-03  9:50   ` Josh Wu
2013-07-03  9:50 ` [PATCH 5/6] mtd: atmel_nand: enable Nand Flash Controller (NFC) write " Josh Wu
2013-07-03  9:50   ` Josh Wu
2013-07-03  9:50 ` [PATCH 6/6] mtd: ofpart: add compatible check for child nodes Josh Wu
2013-07-03  9:50   ` Josh Wu
2013-07-18  7:14   ` Brian Norris
2013-07-18  7:14     ` Brian Norris
2013-07-18  7:14     ` Brian Norris
2013-07-18  8:28     ` Jean-Christophe PLAGNIOL-VILLARD
2013-07-18  8:28       ` Jean-Christophe PLAGNIOL-VILLARD
2013-07-18  8:28       ` Jean-Christophe PLAGNIOL-VILLARD
2013-08-05  9:55 ` [PATCH v5 0/6] mtd: atmel_nand: enable Nand Flash Controller (NFC) support Artem Bityutskiy
2013-08-05  9:55   ` Artem Bityutskiy
2013-08-05  9:56 ` Artem Bityutskiy
2013-08-05  9:56   ` Artem Bityutskiy
2013-08-05 11:28   ` Josh Wu
2013-08-05 11:28     ` Josh Wu
  -- strict thread matches above, loose matches on Subject: below --
2013-08-05 11:14 [PATCH v6 " Josh Wu
2013-08-05 11:14 ` [PATCH 1/6] MTD: atmel_nand: use devm_xxx gpio kzalloc, gpio and ioremap Josh Wu
2013-08-05 11:14   ` Josh Wu
2013-08-05 13:04   ` Artem Bityutskiy
2013-08-05 13:04     ` Artem Bityutskiy
2013-06-19  6:23 [PATCH v4 0/6] mtd: atmel_nand: enable Nand Flash Controller (NFC) support Josh Wu
2013-06-19  6:23 ` [PATCH 1/6] MTD: atmel_nand: use devm_xxx gpio kzalloc, gpio and ioremap Josh Wu
2013-06-19  6:23   ` Josh Wu
2013-06-10 10:26 [PATCH v3 0/6] mtd: atmel_nand: enable Nand Flash Controller (NFC) support Josh Wu
2013-06-10 10:26 ` [PATCH 1/6] MTD: atmel_nand: use devm_xxx gpio kzalloc, gpio and ioremap Josh Wu
2013-06-10 10:26   ` Josh Wu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.