All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/36] OMAP: GPMC: Restructure and move OMAP GPMC driver out of mach-omap2
@ 2014-06-11  8:56 ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Hi,

This is a complete functional set to get the gpmc driver out of mach-omap2
and into drivers/memory. The DT binding remains the same except for the
following minor changes
- compatible property is required for NAND & OneNAND nodes
- Second register space and interrupts properties are required for
  NAND controller node
- ti,onenand-sync-rw property added for OneNAND node.

The series does the following changes
- Move GPMC IRQ and NAND register handling to NAND driver.
  The entire GPMC register space is made available to the NAND driver.
- Clean up NAND device tree handling. Don't rely on legacy platform device
  i.e. don't call gpmc_nand_init()
- Add 2 public APIs omap_gpmc_retime() and omap_gpmc_get_clk_period()
  omap_gpmc_retime() allows to reconfigure the GPMC settings and timings
  for the specified Chip select region.
  omap_gpmc_get_clk_period() allows to query the GPMC_CLK (external clock)
  period, to perform timing calculations.
  Both functions will be needed by the OneNAND driver since it calculates
  device timings on the fly and needs to change from Asynchronous mode
  to Synchronous mode.
- Setup OneNAND in Asynchronous mode by default and move Synchronous
  setting code into OneNAND driver.
- Clean up OneNAND device tree handling. Don't rely on legacy platform device
  i.e. don't call gpmc_onenand_init()
- Introduce gpmc_generic_init() that should be used by board files to specify
  GPMC chip select setting/timing and platform device within that Chip Select.
- Stop using all gpmc*() that are meant to be private to GPMC driver.
- Move GPMC driver into drivers/memory

Tested on:

- beagleboard C4: NAND
- Nokia N900: OneNAND

Changelog:

[1] RFC patch - https://lkml.org/lkml/2014/5/21/218

cheers,
-roger

---
Roger Quadros (36):
  ARM: OMAP3: hwmod: Fix gpmc memory resource space
  ARM: dts: OMAP2+: Fix GPMC register space size
  ARM: OMAP2+: gpmc: Add platform data
  ARM: OMAP2+: gpmc: Add gpmc timings and settings to platform data
  mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
  mtd: nand: omap: Move gpmc_update_nand_reg to nand driver
  mtd: nand: omap: Move NAND write protect code from GPMC to NAND driver
  mtd: nand: omap: Copy platform data parameters to omap_nand_info data
  mtd: nand: omap: Clean up device tree support
  ARM: dts: OMAP2+: Fix NAND device nodes
  mtd: nand: omap: Update DT binding documentation
  ARM: dts: omap3-beagle: Add NAND device
  ARM: OMAP2+: gpmc.c: sanity check bank-width DT property
  ARM: OMAP2+: gpmc: Allow drivers to reconfigure GPMC settings &
    timings
  ARM: OMAP2+: gpmc: Allow drivers to query GPMC_CLK period
  mtd: onenand: omap: Remove regulator management code
  ARM: OMAP2+: gpmc-onenand: Use Async settings/timings by default
  ARM: OMAP2+: gpmc-onenand: Move Synchronous setting code to drivers/
  mtd: onenand: omap: Use devres managed resources
  mtd: onenand: omap: Clean up device tree support
  ARM: dts: OMAP2+: Fix OneNAND device nodes
  ARM: OMAP2+: gmpc: add gpmc_generic_init()
  ARM: OMAP2+: gpmc: use platform data to configure CS space and
    poplulate device
  ARM: OMAP2+: gpmc: add NAND specific setup
  ARM: OMAP2+: gpmc: Support multiple Chip Selects per device
  ARM: OMAP2+: gpmc-smc91x: Get rid of retime() from
    omap_smc91x_platform_data
  ARM: OMAP2+: usb-tusb6010: Use omap_gpmc_retime()
  ARM: OMAP2+: nand: Update gpmc_nand_init() to use generic_gpmc_init()
  ARM: OMAP2+: gpmc-smc91x: Use gpmc_generic_init()
  ARM: OMAP2+: gpmc-smsc911x: Use gpmc_generic_init()
  ARM: OMAP2: usb-tusb6010: Use gpmc_generic_init()
  ARM: OMAP2+: onenand: Use gpmc_generic_init()
  ARM: OMAP2+: board-flash: Use gpmc_generic_init() for NOR
  ARM: OMAP2+: gpmc: Make externally unused functions/defines private
  ARM: OMAP2+: gpmc: move GPMC driver into drivers/memory
  ARM: OMAP2+: defconfig: Enable TI GPMC driver

 .../devicetree/bindings/mtd/gpmc-nand.txt          |   16 +-
 .../devicetree/bindings/mtd/gpmc-onenand.txt       |    4 +
 arch/arm/boot/dts/am335x-evm.dts                   |    8 +-
 arch/arm/boot/dts/am335x-igep0033.dtsi             |    8 +-
 arch/arm/boot/dts/am33xx.dtsi                      |    2 +-
 arch/arm/boot/dts/am4372.dtsi                      |    2 +-
 arch/arm/boot/dts/am43x-epos-evm.dts               |    8 +-
 arch/arm/boot/dts/omap2420-n8x0-common.dtsi        |    5 +-
 arch/arm/boot/dts/omap2420.dtsi                    |    2 +-
 arch/arm/boot/dts/omap2430.dtsi                    |    2 +-
 arch/arm/boot/dts/omap3-beagle.dts                 |   53 +
 arch/arm/boot/dts/omap3-devkit8000.dts             |    9 +-
 arch/arm/boot/dts/omap3-evm-37xx.dts               |   10 +-
 arch/arm/boot/dts/omap3-igep0020.dts               |   10 +-
 arch/arm/boot/dts/omap3-igep0030.dts               |    8 +-
 arch/arm/boot/dts/omap3-ldp.dts                    |   10 +-
 arch/arm/boot/dts/omap3-lilly-a83x.dtsi            |   10 +-
 arch/arm/boot/dts/omap3-lilly-dbb056.dts           |    7 +-
 arch/arm/boot/dts/omap3-n900.dts                   |    6 +-
 arch/arm/boot/dts/omap3-n950-n9.dtsi               |    6 +-
 arch/arm/boot/dts/omap3.dtsi                       |    2 +-
 arch/arm/boot/dts/omap3430-sdp.dts                 |   14 +-
 arch/arm/boot/dts/omap4.dtsi                       |    2 +-
 arch/arm/boot/dts/omap5.dtsi                       |    2 +-
 arch/arm/configs/omap2plus_defconfig               |    2 +
 arch/arm/mach-omap2/Makefile                       |    2 +-
 arch/arm/mach-omap2/board-3430sdp.c                |    8 +-
 arch/arm/mach-omap2/board-flash.c                  |   28 +-
 arch/arm/mach-omap2/gpmc-nand.c                    |   66 +-
 arch/arm/mach-omap2/gpmc-onenand.c                 |  351 +---
 arch/arm/mach-omap2/gpmc-smc91x.c                  |   91 +-
 arch/arm/mach-omap2/gpmc-smc91x.h                  |    1 -
 arch/arm/mach-omap2/gpmc-smsc911x.c                |   76 +-
 arch/arm/mach-omap2/gpmc.c                         | 1872 --------------------
 arch/arm/mach-omap2/gpmc.h                         |  221 +--
 arch/arm/mach-omap2/gpmc_legacy.c                  |  296 ++++
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c         |    2 +-
 arch/arm/mach-omap2/usb-tusb6010.c                 |  172 +-
 drivers/memory/Kconfig                             |   10 +
 drivers/memory/Makefile                            |    1 +
 drivers/memory/ti-gpmc.c                           | 1829 +++++++++++++++++++
 drivers/mtd/nand/Kconfig                           |    2 +-
 drivers/mtd/nand/omap2.c                           |  364 +++-
 drivers/mtd/onenand/Kconfig                        |    6 +-
 drivers/mtd/onenand/omap2.c                        |  456 +++--
 include/linux/platform_data/gpmc-omap.h            |  189 ++
 include/linux/platform_data/mtd-nand-omap2.h       |   10 +-
 include/linux/platform_data/mtd-onenand-omap2.h    |    7 +-
 48 files changed, 3361 insertions(+), 2907 deletions(-)
 delete mode 100644 arch/arm/mach-omap2/gpmc.c
 create mode 100644 arch/arm/mach-omap2/gpmc_legacy.c
 create mode 100644 drivers/memory/ti-gpmc.c
 create mode 100644 include/linux/platform_data/gpmc-omap.h

-- 
1.8.3.2


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

* [PATCH 00/36] OMAP: GPMC: Restructure and move OMAP GPMC driver out of mach-omap2
@ 2014-06-11  8:56 ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Hi,

This is a complete functional set to get the gpmc driver out of mach-omap2
and into drivers/memory. The DT binding remains the same except for the
following minor changes
- compatible property is required for NAND & OneNAND nodes
- Second register space and interrupts properties are required for
  NAND controller node
- ti,onenand-sync-rw property added for OneNAND node.

The series does the following changes
- Move GPMC IRQ and NAND register handling to NAND driver.
  The entire GPMC register space is made available to the NAND driver.
- Clean up NAND device tree handling. Don't rely on legacy platform device
  i.e. don't call gpmc_nand_init()
- Add 2 public APIs omap_gpmc_retime() and omap_gpmc_get_clk_period()
  omap_gpmc_retime() allows to reconfigure the GPMC settings and timings
  for the specified Chip select region.
  omap_gpmc_get_clk_period() allows to query the GPMC_CLK (external clock)
  period, to perform timing calculations.
  Both functions will be needed by the OneNAND driver since it calculates
  device timings on the fly and needs to change from Asynchronous mode
  to Synchronous mode.
- Setup OneNAND in Asynchronous mode by default and move Synchronous
  setting code into OneNAND driver.
- Clean up OneNAND device tree handling. Don't rely on legacy platform device
  i.e. don't call gpmc_onenand_init()
- Introduce gpmc_generic_init() that should be used by board files to specify
  GPMC chip select setting/timing and platform device within that Chip Select.
- Stop using all gpmc*() that are meant to be private to GPMC driver.
- Move GPMC driver into drivers/memory

Tested on:

- beagleboard C4: NAND
- Nokia N900: OneNAND

Changelog:

[1] RFC patch - https://lkml.org/lkml/2014/5/21/218

cheers,
-roger

---
Roger Quadros (36):
  ARM: OMAP3: hwmod: Fix gpmc memory resource space
  ARM: dts: OMAP2+: Fix GPMC register space size
  ARM: OMAP2+: gpmc: Add platform data
  ARM: OMAP2+: gpmc: Add gpmc timings and settings to platform data
  mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
  mtd: nand: omap: Move gpmc_update_nand_reg to nand driver
  mtd: nand: omap: Move NAND write protect code from GPMC to NAND driver
  mtd: nand: omap: Copy platform data parameters to omap_nand_info data
  mtd: nand: omap: Clean up device tree support
  ARM: dts: OMAP2+: Fix NAND device nodes
  mtd: nand: omap: Update DT binding documentation
  ARM: dts: omap3-beagle: Add NAND device
  ARM: OMAP2+: gpmc.c: sanity check bank-width DT property
  ARM: OMAP2+: gpmc: Allow drivers to reconfigure GPMC settings &
    timings
  ARM: OMAP2+: gpmc: Allow drivers to query GPMC_CLK period
  mtd: onenand: omap: Remove regulator management code
  ARM: OMAP2+: gpmc-onenand: Use Async settings/timings by default
  ARM: OMAP2+: gpmc-onenand: Move Synchronous setting code to drivers/
  mtd: onenand: omap: Use devres managed resources
  mtd: onenand: omap: Clean up device tree support
  ARM: dts: OMAP2+: Fix OneNAND device nodes
  ARM: OMAP2+: gmpc: add gpmc_generic_init()
  ARM: OMAP2+: gpmc: use platform data to configure CS space and
    poplulate device
  ARM: OMAP2+: gpmc: add NAND specific setup
  ARM: OMAP2+: gpmc: Support multiple Chip Selects per device
  ARM: OMAP2+: gpmc-smc91x: Get rid of retime() from
    omap_smc91x_platform_data
  ARM: OMAP2+: usb-tusb6010: Use omap_gpmc_retime()
  ARM: OMAP2+: nand: Update gpmc_nand_init() to use generic_gpmc_init()
  ARM: OMAP2+: gpmc-smc91x: Use gpmc_generic_init()
  ARM: OMAP2+: gpmc-smsc911x: Use gpmc_generic_init()
  ARM: OMAP2: usb-tusb6010: Use gpmc_generic_init()
  ARM: OMAP2+: onenand: Use gpmc_generic_init()
  ARM: OMAP2+: board-flash: Use gpmc_generic_init() for NOR
  ARM: OMAP2+: gpmc: Make externally unused functions/defines private
  ARM: OMAP2+: gpmc: move GPMC driver into drivers/memory
  ARM: OMAP2+: defconfig: Enable TI GPMC driver

 .../devicetree/bindings/mtd/gpmc-nand.txt          |   16 +-
 .../devicetree/bindings/mtd/gpmc-onenand.txt       |    4 +
 arch/arm/boot/dts/am335x-evm.dts                   |    8 +-
 arch/arm/boot/dts/am335x-igep0033.dtsi             |    8 +-
 arch/arm/boot/dts/am33xx.dtsi                      |    2 +-
 arch/arm/boot/dts/am4372.dtsi                      |    2 +-
 arch/arm/boot/dts/am43x-epos-evm.dts               |    8 +-
 arch/arm/boot/dts/omap2420-n8x0-common.dtsi        |    5 +-
 arch/arm/boot/dts/omap2420.dtsi                    |    2 +-
 arch/arm/boot/dts/omap2430.dtsi                    |    2 +-
 arch/arm/boot/dts/omap3-beagle.dts                 |   53 +
 arch/arm/boot/dts/omap3-devkit8000.dts             |    9 +-
 arch/arm/boot/dts/omap3-evm-37xx.dts               |   10 +-
 arch/arm/boot/dts/omap3-igep0020.dts               |   10 +-
 arch/arm/boot/dts/omap3-igep0030.dts               |    8 +-
 arch/arm/boot/dts/omap3-ldp.dts                    |   10 +-
 arch/arm/boot/dts/omap3-lilly-a83x.dtsi            |   10 +-
 arch/arm/boot/dts/omap3-lilly-dbb056.dts           |    7 +-
 arch/arm/boot/dts/omap3-n900.dts                   |    6 +-
 arch/arm/boot/dts/omap3-n950-n9.dtsi               |    6 +-
 arch/arm/boot/dts/omap3.dtsi                       |    2 +-
 arch/arm/boot/dts/omap3430-sdp.dts                 |   14 +-
 arch/arm/boot/dts/omap4.dtsi                       |    2 +-
 arch/arm/boot/dts/omap5.dtsi                       |    2 +-
 arch/arm/configs/omap2plus_defconfig               |    2 +
 arch/arm/mach-omap2/Makefile                       |    2 +-
 arch/arm/mach-omap2/board-3430sdp.c                |    8 +-
 arch/arm/mach-omap2/board-flash.c                  |   28 +-
 arch/arm/mach-omap2/gpmc-nand.c                    |   66 +-
 arch/arm/mach-omap2/gpmc-onenand.c                 |  351 +---
 arch/arm/mach-omap2/gpmc-smc91x.c                  |   91 +-
 arch/arm/mach-omap2/gpmc-smc91x.h                  |    1 -
 arch/arm/mach-omap2/gpmc-smsc911x.c                |   76 +-
 arch/arm/mach-omap2/gpmc.c                         | 1872 --------------------
 arch/arm/mach-omap2/gpmc.h                         |  221 +--
 arch/arm/mach-omap2/gpmc_legacy.c                  |  296 ++++
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c         |    2 +-
 arch/arm/mach-omap2/usb-tusb6010.c                 |  172 +-
 drivers/memory/Kconfig                             |   10 +
 drivers/memory/Makefile                            |    1 +
 drivers/memory/ti-gpmc.c                           | 1829 +++++++++++++++++++
 drivers/mtd/nand/Kconfig                           |    2 +-
 drivers/mtd/nand/omap2.c                           |  364 +++-
 drivers/mtd/onenand/Kconfig                        |    6 +-
 drivers/mtd/onenand/omap2.c                        |  456 +++--
 include/linux/platform_data/gpmc-omap.h            |  189 ++
 include/linux/platform_data/mtd-nand-omap2.h       |   10 +-
 include/linux/platform_data/mtd-onenand-omap2.h    |    7 +-
 48 files changed, 3361 insertions(+), 2907 deletions(-)
 delete mode 100644 arch/arm/mach-omap2/gpmc.c
 create mode 100644 arch/arm/mach-omap2/gpmc_legacy.c
 create mode 100644 drivers/memory/ti-gpmc.c
 create mode 100644 include/linux/platform_data/gpmc-omap.h

-- 
1.8.3.2


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

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

* [PATCH 00/36] OMAP: GPMC: Restructure and move OMAP GPMC driver out of mach-omap2
@ 2014-06-11  8:56 ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Hi,

This is a complete functional set to get the gpmc driver out of mach-omap2
and into drivers/memory. The DT binding remains the same except for the
following minor changes
- compatible property is required for NAND & OneNAND nodes
- Second register space and interrupts properties are required for
  NAND controller node
- ti,onenand-sync-rw property added for OneNAND node.

The series does the following changes
- Move GPMC IRQ and NAND register handling to NAND driver.
  The entire GPMC register space is made available to the NAND driver.
- Clean up NAND device tree handling. Don't rely on legacy platform device
  i.e. don't call gpmc_nand_init()
- Add 2 public APIs omap_gpmc_retime() and omap_gpmc_get_clk_period()
  omap_gpmc_retime() allows to reconfigure the GPMC settings and timings
  for the specified Chip select region.
  omap_gpmc_get_clk_period() allows to query the GPMC_CLK (external clock)
  period, to perform timing calculations.
  Both functions will be needed by the OneNAND driver since it calculates
  device timings on the fly and needs to change from Asynchronous mode
  to Synchronous mode.
- Setup OneNAND in Asynchronous mode by default and move Synchronous
  setting code into OneNAND driver.
- Clean up OneNAND device tree handling. Don't rely on legacy platform device
  i.e. don't call gpmc_onenand_init()
- Introduce gpmc_generic_init() that should be used by board files to specify
  GPMC chip select setting/timing and platform device within that Chip Select.
- Stop using all gpmc*() that are meant to be private to GPMC driver.
- Move GPMC driver into drivers/memory

Tested on:

- beagleboard C4: NAND
- Nokia N900: OneNAND

Changelog:

[1] RFC patch - https://lkml.org/lkml/2014/5/21/218

cheers,
-roger

---
Roger Quadros (36):
  ARM: OMAP3: hwmod: Fix gpmc memory resource space
  ARM: dts: OMAP2+: Fix GPMC register space size
  ARM: OMAP2+: gpmc: Add platform data
  ARM: OMAP2+: gpmc: Add gpmc timings and settings to platform data
  mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
  mtd: nand: omap: Move gpmc_update_nand_reg to nand driver
  mtd: nand: omap: Move NAND write protect code from GPMC to NAND driver
  mtd: nand: omap: Copy platform data parameters to omap_nand_info data
  mtd: nand: omap: Clean up device tree support
  ARM: dts: OMAP2+: Fix NAND device nodes
  mtd: nand: omap: Update DT binding documentation
  ARM: dts: omap3-beagle: Add NAND device
  ARM: OMAP2+: gpmc.c: sanity check bank-width DT property
  ARM: OMAP2+: gpmc: Allow drivers to reconfigure GPMC settings &
    timings
  ARM: OMAP2+: gpmc: Allow drivers to query GPMC_CLK period
  mtd: onenand: omap: Remove regulator management code
  ARM: OMAP2+: gpmc-onenand: Use Async settings/timings by default
  ARM: OMAP2+: gpmc-onenand: Move Synchronous setting code to drivers/
  mtd: onenand: omap: Use devres managed resources
  mtd: onenand: omap: Clean up device tree support
  ARM: dts: OMAP2+: Fix OneNAND device nodes
  ARM: OMAP2+: gmpc: add gpmc_generic_init()
  ARM: OMAP2+: gpmc: use platform data to configure CS space and
    poplulate device
  ARM: OMAP2+: gpmc: add NAND specific setup
  ARM: OMAP2+: gpmc: Support multiple Chip Selects per device
  ARM: OMAP2+: gpmc-smc91x: Get rid of retime() from
    omap_smc91x_platform_data
  ARM: OMAP2+: usb-tusb6010: Use omap_gpmc_retime()
  ARM: OMAP2+: nand: Update gpmc_nand_init() to use generic_gpmc_init()
  ARM: OMAP2+: gpmc-smc91x: Use gpmc_generic_init()
  ARM: OMAP2+: gpmc-smsc911x: Use gpmc_generic_init()
  ARM: OMAP2: usb-tusb6010: Use gpmc_generic_init()
  ARM: OMAP2+: onenand: Use gpmc_generic_init()
  ARM: OMAP2+: board-flash: Use gpmc_generic_init() for NOR
  ARM: OMAP2+: gpmc: Make externally unused functions/defines private
  ARM: OMAP2+: gpmc: move GPMC driver into drivers/memory
  ARM: OMAP2+: defconfig: Enable TI GPMC driver

 .../devicetree/bindings/mtd/gpmc-nand.txt          |   16 +-
 .../devicetree/bindings/mtd/gpmc-onenand.txt       |    4 +
 arch/arm/boot/dts/am335x-evm.dts                   |    8 +-
 arch/arm/boot/dts/am335x-igep0033.dtsi             |    8 +-
 arch/arm/boot/dts/am33xx.dtsi                      |    2 +-
 arch/arm/boot/dts/am4372.dtsi                      |    2 +-
 arch/arm/boot/dts/am43x-epos-evm.dts               |    8 +-
 arch/arm/boot/dts/omap2420-n8x0-common.dtsi        |    5 +-
 arch/arm/boot/dts/omap2420.dtsi                    |    2 +-
 arch/arm/boot/dts/omap2430.dtsi                    |    2 +-
 arch/arm/boot/dts/omap3-beagle.dts                 |   53 +
 arch/arm/boot/dts/omap3-devkit8000.dts             |    9 +-
 arch/arm/boot/dts/omap3-evm-37xx.dts               |   10 +-
 arch/arm/boot/dts/omap3-igep0020.dts               |   10 +-
 arch/arm/boot/dts/omap3-igep0030.dts               |    8 +-
 arch/arm/boot/dts/omap3-ldp.dts                    |   10 +-
 arch/arm/boot/dts/omap3-lilly-a83x.dtsi            |   10 +-
 arch/arm/boot/dts/omap3-lilly-dbb056.dts           |    7 +-
 arch/arm/boot/dts/omap3-n900.dts                   |    6 +-
 arch/arm/boot/dts/omap3-n950-n9.dtsi               |    6 +-
 arch/arm/boot/dts/omap3.dtsi                       |    2 +-
 arch/arm/boot/dts/omap3430-sdp.dts                 |   14 +-
 arch/arm/boot/dts/omap4.dtsi                       |    2 +-
 arch/arm/boot/dts/omap5.dtsi                       |    2 +-
 arch/arm/configs/omap2plus_defconfig               |    2 +
 arch/arm/mach-omap2/Makefile                       |    2 +-
 arch/arm/mach-omap2/board-3430sdp.c                |    8 +-
 arch/arm/mach-omap2/board-flash.c                  |   28 +-
 arch/arm/mach-omap2/gpmc-nand.c                    |   66 +-
 arch/arm/mach-omap2/gpmc-onenand.c                 |  351 +---
 arch/arm/mach-omap2/gpmc-smc91x.c                  |   91 +-
 arch/arm/mach-omap2/gpmc-smc91x.h                  |    1 -
 arch/arm/mach-omap2/gpmc-smsc911x.c                |   76 +-
 arch/arm/mach-omap2/gpmc.c                         | 1872 --------------------
 arch/arm/mach-omap2/gpmc.h                         |  221 +--
 arch/arm/mach-omap2/gpmc_legacy.c                  |  296 ++++
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c         |    2 +-
 arch/arm/mach-omap2/usb-tusb6010.c                 |  172 +-
 drivers/memory/Kconfig                             |   10 +
 drivers/memory/Makefile                            |    1 +
 drivers/memory/ti-gpmc.c                           | 1829 +++++++++++++++++++
 drivers/mtd/nand/Kconfig                           |    2 +-
 drivers/mtd/nand/omap2.c                           |  364 +++-
 drivers/mtd/onenand/Kconfig                        |    6 +-
 drivers/mtd/onenand/omap2.c                        |  456 +++--
 include/linux/platform_data/gpmc-omap.h            |  189 ++
 include/linux/platform_data/mtd-nand-omap2.h       |   10 +-
 include/linux/platform_data/mtd-onenand-omap2.h    |    7 +-
 48 files changed, 3361 insertions(+), 2907 deletions(-)
 delete mode 100644 arch/arm/mach-omap2/gpmc.c
 create mode 100644 arch/arm/mach-omap2/gpmc_legacy.c
 create mode 100644 drivers/memory/ti-gpmc.c
 create mode 100644 include/linux/platform_data/gpmc-omap.h

-- 
1.8.3.2

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

* [PATCH 01/36] ARM: OMAP3: hwmod: Fix gpmc memory resource space
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 71ac7d5..f2848a8 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -3426,7 +3426,7 @@ static struct omap_hwmod_addr_space omap3xxx_counter_32k_addrs[] = {
 static struct omap_hwmod_addr_space omap3xxx_gpmc_addrs[] = {
 	{
 		.pa_start	= 0x6e000000,
-		.pa_end		= 0x6e000fff,
+		.pa_end		= 0x6e0002d4,
 		.flags		= ADDR_TYPE_RT
 	},
 	{ }
-- 
1.8.3.2


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

* [PATCH 01/36] ARM: OMAP3: hwmod: Fix gpmc memory resource space
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 71ac7d5..f2848a8 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -3426,7 +3426,7 @@ static struct omap_hwmod_addr_space omap3xxx_counter_32k_addrs[] = {
 static struct omap_hwmod_addr_space omap3xxx_gpmc_addrs[] = {
 	{
 		.pa_start	= 0x6e000000,
-		.pa_end		= 0x6e000fff,
+		.pa_end		= 0x6e0002d4,
 		.flags		= ADDR_TYPE_RT
 	},
 	{ }
-- 
1.8.3.2


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

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

* [PATCH 01/36] ARM: OMAP3: hwmod: Fix gpmc memory resource space
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 71ac7d5..f2848a8 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -3426,7 +3426,7 @@ static struct omap_hwmod_addr_space omap3xxx_counter_32k_addrs[] = {
 static struct omap_hwmod_addr_space omap3xxx_gpmc_addrs[] = {
 	{
 		.pa_start	= 0x6e000000,
-		.pa_end		= 0x6e000fff,
+		.pa_end		= 0x6e0002d4,
 		.flags		= ADDR_TYPE_RT
 	},
 	{ }
-- 
1.8.3.2

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

* [PATCH 02/36] ARM: dts: OMAP2+: Fix GPMC register space size
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Use actual register space size from Reference Manual.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/boot/dts/am33xx.dtsi   | 2 +-
 arch/arm/boot/dts/am4372.dtsi   | 2 +-
 arch/arm/boot/dts/omap2420.dtsi | 2 +-
 arch/arm/boot/dts/omap2430.dtsi | 2 +-
 arch/arm/boot/dts/omap3.dtsi    | 2 +-
 arch/arm/boot/dts/omap4.dtsi    | 2 +-
 arch/arm/boot/dts/omap5.dtsi    | 2 +-
 7 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
index 7ad75b4..27f0b25 100644
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -767,7 +767,7 @@
 			compatible = "ti,am3352-gpmc";
 			ti,hwmods = "gpmc";
 			ti,no-idle-on-init;
-			reg = <0x50000000 0x2000>;
+			reg = <0x50000000 0x36c>;
 			interrupts = <100>;
 			gpmc,num-cs = <7>;
 			gpmc,num-waitpins = <2>;
diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi
index d1f8707..0014d5d 100644
--- a/arch/arm/boot/dts/am4372.dtsi
+++ b/arch/arm/boot/dts/am4372.dtsi
@@ -727,7 +727,7 @@
 			ti,hwmods = "gpmc";
 			clocks = <&l3s_gclk>;
 			clock-names = "fck";
-			reg = <0x50000000 0x2000>;
+			reg = <0x50000000 0x36c>;
 			interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
 			gpmc,num-cs = <7>;
 			gpmc,num-waitpins = <2>;
diff --git a/arch/arm/boot/dts/omap2420.dtsi b/arch/arm/boot/dts/omap2420.dtsi
index 2d99798..d0f5953 100644
--- a/arch/arm/boot/dts/omap2420.dtsi
+++ b/arch/arm/boot/dts/omap2420.dtsi
@@ -79,7 +79,7 @@
 
 		gpmc: gpmc@6800a000 {
 			compatible = "ti,omap2420-gpmc";
-			reg = <0x6800a000 0x1000>;
+			reg = <0x6800a000 0x23c>;
 			#address-cells = <2>;
 			#size-cells = <1>;
 			interrupts = <20>;
diff --git a/arch/arm/boot/dts/omap2430.dtsi b/arch/arm/boot/dts/omap2430.dtsi
index 42d2c61..94f81e8 100644
--- a/arch/arm/boot/dts/omap2430.dtsi
+++ b/arch/arm/boot/dts/omap2430.dtsi
@@ -106,7 +106,7 @@
 
 		gpmc: gpmc@6e000000 {
 			compatible = "ti,omap2430-gpmc";
-			reg = <0x6e000000 0x1000>;
+			reg = <0x6e000000 0x23c>;
 			#address-cells = <2>;
 			#size-cells = <1>;
 			interrupts = <20>;
diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi
index 4231191..fc7a3e3 100644
--- a/arch/arm/boot/dts/omap3.dtsi
+++ b/arch/arm/boot/dts/omap3.dtsi
@@ -687,7 +687,7 @@
 		gpmc: gpmc@6e000000 {
 			compatible = "ti,omap3430-gpmc";
 			ti,hwmods = "gpmc";
-			reg = <0x6e000000 0x02d0>;
+			reg = <0x6e000000 0x02d4>;
 			interrupts = <20>;
 			gpmc,num-cs = <8>;
 			gpmc,num-waitpins = <4>;
diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi
index 649b5cd..469c699 100644
--- a/arch/arm/boot/dts/omap4.dtsi
+++ b/arch/arm/boot/dts/omap4.dtsi
@@ -288,7 +288,7 @@
 
 		gpmc: gpmc@50000000 {
 			compatible = "ti,omap4430-gpmc";
-			reg = <0x50000000 0x1000>;
+			reg = <0x50000000 0x37c>;
 			#address-cells = <2>;
 			#size-cells = <1>;
 			interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi
index 36b4312..187c93f 100644
--- a/arch/arm/boot/dts/omap5.dtsi
+++ b/arch/arm/boot/dts/omap5.dtsi
@@ -317,7 +317,7 @@
 
 		gpmc: gpmc@50000000 {
 			compatible = "ti,omap4430-gpmc";
-			reg = <0x50000000 0x1000>;
+			reg = <0x50000000 0x37c>;
 			#address-cells = <2>;
 			#size-cells = <1>;
 			interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
-- 
1.8.3.2


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

* [PATCH 02/36] ARM: dts: OMAP2+: Fix GPMC register space size
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Use actual register space size from Reference Manual.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/boot/dts/am33xx.dtsi   | 2 +-
 arch/arm/boot/dts/am4372.dtsi   | 2 +-
 arch/arm/boot/dts/omap2420.dtsi | 2 +-
 arch/arm/boot/dts/omap2430.dtsi | 2 +-
 arch/arm/boot/dts/omap3.dtsi    | 2 +-
 arch/arm/boot/dts/omap4.dtsi    | 2 +-
 arch/arm/boot/dts/omap5.dtsi    | 2 +-
 7 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
index 7ad75b4..27f0b25 100644
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -767,7 +767,7 @@
 			compatible = "ti,am3352-gpmc";
 			ti,hwmods = "gpmc";
 			ti,no-idle-on-init;
-			reg = <0x50000000 0x2000>;
+			reg = <0x50000000 0x36c>;
 			interrupts = <100>;
 			gpmc,num-cs = <7>;
 			gpmc,num-waitpins = <2>;
diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi
index d1f8707..0014d5d 100644
--- a/arch/arm/boot/dts/am4372.dtsi
+++ b/arch/arm/boot/dts/am4372.dtsi
@@ -727,7 +727,7 @@
 			ti,hwmods = "gpmc";
 			clocks = <&l3s_gclk>;
 			clock-names = "fck";
-			reg = <0x50000000 0x2000>;
+			reg = <0x50000000 0x36c>;
 			interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
 			gpmc,num-cs = <7>;
 			gpmc,num-waitpins = <2>;
diff --git a/arch/arm/boot/dts/omap2420.dtsi b/arch/arm/boot/dts/omap2420.dtsi
index 2d99798..d0f5953 100644
--- a/arch/arm/boot/dts/omap2420.dtsi
+++ b/arch/arm/boot/dts/omap2420.dtsi
@@ -79,7 +79,7 @@
 
 		gpmc: gpmc@6800a000 {
 			compatible = "ti,omap2420-gpmc";
-			reg = <0x6800a000 0x1000>;
+			reg = <0x6800a000 0x23c>;
 			#address-cells = <2>;
 			#size-cells = <1>;
 			interrupts = <20>;
diff --git a/arch/arm/boot/dts/omap2430.dtsi b/arch/arm/boot/dts/omap2430.dtsi
index 42d2c61..94f81e8 100644
--- a/arch/arm/boot/dts/omap2430.dtsi
+++ b/arch/arm/boot/dts/omap2430.dtsi
@@ -106,7 +106,7 @@
 
 		gpmc: gpmc@6e000000 {
 			compatible = "ti,omap2430-gpmc";
-			reg = <0x6e000000 0x1000>;
+			reg = <0x6e000000 0x23c>;
 			#address-cells = <2>;
 			#size-cells = <1>;
 			interrupts = <20>;
diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi
index 4231191..fc7a3e3 100644
--- a/arch/arm/boot/dts/omap3.dtsi
+++ b/arch/arm/boot/dts/omap3.dtsi
@@ -687,7 +687,7 @@
 		gpmc: gpmc@6e000000 {
 			compatible = "ti,omap3430-gpmc";
 			ti,hwmods = "gpmc";
-			reg = <0x6e000000 0x02d0>;
+			reg = <0x6e000000 0x02d4>;
 			interrupts = <20>;
 			gpmc,num-cs = <8>;
 			gpmc,num-waitpins = <4>;
diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi
index 649b5cd..469c699 100644
--- a/arch/arm/boot/dts/omap4.dtsi
+++ b/arch/arm/boot/dts/omap4.dtsi
@@ -288,7 +288,7 @@
 
 		gpmc: gpmc@50000000 {
 			compatible = "ti,omap4430-gpmc";
-			reg = <0x50000000 0x1000>;
+			reg = <0x50000000 0x37c>;
 			#address-cells = <2>;
 			#size-cells = <1>;
 			interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi
index 36b4312..187c93f 100644
--- a/arch/arm/boot/dts/omap5.dtsi
+++ b/arch/arm/boot/dts/omap5.dtsi
@@ -317,7 +317,7 @@
 
 		gpmc: gpmc@50000000 {
 			compatible = "ti,omap4430-gpmc";
-			reg = <0x50000000 0x1000>;
+			reg = <0x50000000 0x37c>;
 			#address-cells = <2>;
 			#size-cells = <1>;
 			interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
-- 
1.8.3.2

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

* [PATCH 02/36] ARM: dts: OMAP2+: Fix GPMC register space size
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Use actual register space size from Reference Manual.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/boot/dts/am33xx.dtsi   | 2 +-
 arch/arm/boot/dts/am4372.dtsi   | 2 +-
 arch/arm/boot/dts/omap2420.dtsi | 2 +-
 arch/arm/boot/dts/omap2430.dtsi | 2 +-
 arch/arm/boot/dts/omap3.dtsi    | 2 +-
 arch/arm/boot/dts/omap4.dtsi    | 2 +-
 arch/arm/boot/dts/omap5.dtsi    | 2 +-
 7 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
index 7ad75b4..27f0b25 100644
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -767,7 +767,7 @@
 			compatible = "ti,am3352-gpmc";
 			ti,hwmods = "gpmc";
 			ti,no-idle-on-init;
-			reg = <0x50000000 0x2000>;
+			reg = <0x50000000 0x36c>;
 			interrupts = <100>;
 			gpmc,num-cs = <7>;
 			gpmc,num-waitpins = <2>;
diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi
index d1f8707..0014d5d 100644
--- a/arch/arm/boot/dts/am4372.dtsi
+++ b/arch/arm/boot/dts/am4372.dtsi
@@ -727,7 +727,7 @@
 			ti,hwmods = "gpmc";
 			clocks = <&l3s_gclk>;
 			clock-names = "fck";
-			reg = <0x50000000 0x2000>;
+			reg = <0x50000000 0x36c>;
 			interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
 			gpmc,num-cs = <7>;
 			gpmc,num-waitpins = <2>;
diff --git a/arch/arm/boot/dts/omap2420.dtsi b/arch/arm/boot/dts/omap2420.dtsi
index 2d99798..d0f5953 100644
--- a/arch/arm/boot/dts/omap2420.dtsi
+++ b/arch/arm/boot/dts/omap2420.dtsi
@@ -79,7 +79,7 @@
 
 		gpmc: gpmc@6800a000 {
 			compatible = "ti,omap2420-gpmc";
-			reg = <0x6800a000 0x1000>;
+			reg = <0x6800a000 0x23c>;
 			#address-cells = <2>;
 			#size-cells = <1>;
 			interrupts = <20>;
diff --git a/arch/arm/boot/dts/omap2430.dtsi b/arch/arm/boot/dts/omap2430.dtsi
index 42d2c61..94f81e8 100644
--- a/arch/arm/boot/dts/omap2430.dtsi
+++ b/arch/arm/boot/dts/omap2430.dtsi
@@ -106,7 +106,7 @@
 
 		gpmc: gpmc@6e000000 {
 			compatible = "ti,omap2430-gpmc";
-			reg = <0x6e000000 0x1000>;
+			reg = <0x6e000000 0x23c>;
 			#address-cells = <2>;
 			#size-cells = <1>;
 			interrupts = <20>;
diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi
index 4231191..fc7a3e3 100644
--- a/arch/arm/boot/dts/omap3.dtsi
+++ b/arch/arm/boot/dts/omap3.dtsi
@@ -687,7 +687,7 @@
 		gpmc: gpmc@6e000000 {
 			compatible = "ti,omap3430-gpmc";
 			ti,hwmods = "gpmc";
-			reg = <0x6e000000 0x02d0>;
+			reg = <0x6e000000 0x02d4>;
 			interrupts = <20>;
 			gpmc,num-cs = <8>;
 			gpmc,num-waitpins = <4>;
diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi
index 649b5cd..469c699 100644
--- a/arch/arm/boot/dts/omap4.dtsi
+++ b/arch/arm/boot/dts/omap4.dtsi
@@ -288,7 +288,7 @@
 
 		gpmc: gpmc@50000000 {
 			compatible = "ti,omap4430-gpmc";
-			reg = <0x50000000 0x1000>;
+			reg = <0x50000000 0x37c>;
 			#address-cells = <2>;
 			#size-cells = <1>;
 			interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi
index 36b4312..187c93f 100644
--- a/arch/arm/boot/dts/omap5.dtsi
+++ b/arch/arm/boot/dts/omap5.dtsi
@@ -317,7 +317,7 @@
 
 		gpmc: gpmc@50000000 {
 			compatible = "ti,omap4430-gpmc";
-			reg = <0x50000000 0x1000>;
+			reg = <0x50000000 0x37c>;
 			#address-cells = <2>;
 			#size-cells = <1>;
 			interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
-- 
1.8.3.2

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

* [PATCH 03/36] ARM: OMAP2+: gpmc: Add platform data
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Add a platform data structure for GPMC. It contains all the necessary
platform information that needs to be passed from platform init code
to GPMC driver.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.h              |  4 +---
 include/linux/platform_data/gpmc-omap.h | 30 ++++++++++++++++++++++++++++++
 2 files changed, 31 insertions(+), 3 deletions(-)
 create mode 100644 include/linux/platform_data/gpmc-omap.h

diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h
index 707f6d5..c476712 100644
--- a/arch/arm/mach-omap2/gpmc.h
+++ b/arch/arm/mach-omap2/gpmc.h
@@ -12,9 +12,7 @@
 #define __OMAP2_GPMC_H
 
 #include <linux/platform_data/mtd-nand-omap2.h>
-
-/* Maximum Number of Chip Selects */
-#define GPMC_CS_NUM		8
+#include <linux/platform_data/gpmc-omap.h>
 
 #define GPMC_CS_CONFIG1		0x00
 #define GPMC_CS_CONFIG2		0x04
diff --git a/include/linux/platform_data/gpmc-omap.h b/include/linux/platform_data/gpmc-omap.h
new file mode 100644
index 0000000..d32d9de
--- /dev/null
+++ b/include/linux/platform_data/gpmc-omap.h
@@ -0,0 +1,30 @@
+/*
+ * OMAP GPMC Platform data
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc. - http://www.ti.com
+ *	Roger Quadros <rogerq@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#ifndef _GPMC_OMAP_H_
+#define _GPMC_OMAP_H_
+
+/* Maximum Number of Chip Selects */
+#define GPMC_CS_NUM		8
+
+/* Data for each chip select */
+struct gpmc_omap_cs_data {
+	bool valid;			/* data is valid */
+	bool is_nand;			/* device within this CS is NAND */
+	struct platform_device *pdev;	/* device within this CS region */
+	unsigned pdata_size;
+};
+
+struct gpmc_omap_platform_data {
+	struct gpmc_omap_cs_data cs[GPMC_CS_NUM];
+};
+
+#endif /* _GPMC_OMAP_H */
-- 
1.8.3.2


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

* [PATCH 03/36] ARM: OMAP2+: gpmc: Add platform data
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Add a platform data structure for GPMC. It contains all the necessary
platform information that needs to be passed from platform init code
to GPMC driver.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.h              |  4 +---
 include/linux/platform_data/gpmc-omap.h | 30 ++++++++++++++++++++++++++++++
 2 files changed, 31 insertions(+), 3 deletions(-)
 create mode 100644 include/linux/platform_data/gpmc-omap.h

diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h
index 707f6d5..c476712 100644
--- a/arch/arm/mach-omap2/gpmc.h
+++ b/arch/arm/mach-omap2/gpmc.h
@@ -12,9 +12,7 @@
 #define __OMAP2_GPMC_H
 
 #include <linux/platform_data/mtd-nand-omap2.h>
-
-/* Maximum Number of Chip Selects */
-#define GPMC_CS_NUM		8
+#include <linux/platform_data/gpmc-omap.h>
 
 #define GPMC_CS_CONFIG1		0x00
 #define GPMC_CS_CONFIG2		0x04
diff --git a/include/linux/platform_data/gpmc-omap.h b/include/linux/platform_data/gpmc-omap.h
new file mode 100644
index 0000000..d32d9de
--- /dev/null
+++ b/include/linux/platform_data/gpmc-omap.h
@@ -0,0 +1,30 @@
+/*
+ * OMAP GPMC Platform data
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc. - http://www.ti.com
+ *	Roger Quadros <rogerq@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#ifndef _GPMC_OMAP_H_
+#define _GPMC_OMAP_H_
+
+/* Maximum Number of Chip Selects */
+#define GPMC_CS_NUM		8
+
+/* Data for each chip select */
+struct gpmc_omap_cs_data {
+	bool valid;			/* data is valid */
+	bool is_nand;			/* device within this CS is NAND */
+	struct platform_device *pdev;	/* device within this CS region */
+	unsigned pdata_size;
+};
+
+struct gpmc_omap_platform_data {
+	struct gpmc_omap_cs_data cs[GPMC_CS_NUM];
+};
+
+#endif /* _GPMC_OMAP_H */
-- 
1.8.3.2


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

* [PATCH 03/36] ARM: OMAP2+: gpmc: Add platform data
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Add a platform data structure for GPMC. It contains all the necessary
platform information that needs to be passed from platform init code
to GPMC driver.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.h              |  4 +---
 include/linux/platform_data/gpmc-omap.h | 30 ++++++++++++++++++++++++++++++
 2 files changed, 31 insertions(+), 3 deletions(-)
 create mode 100644 include/linux/platform_data/gpmc-omap.h

diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h
index 707f6d5..c476712 100644
--- a/arch/arm/mach-omap2/gpmc.h
+++ b/arch/arm/mach-omap2/gpmc.h
@@ -12,9 +12,7 @@
 #define __OMAP2_GPMC_H
 
 #include <linux/platform_data/mtd-nand-omap2.h>
-
-/* Maximum Number of Chip Selects */
-#define GPMC_CS_NUM		8
+#include <linux/platform_data/gpmc-omap.h>
 
 #define GPMC_CS_CONFIG1		0x00
 #define GPMC_CS_CONFIG2		0x04
diff --git a/include/linux/platform_data/gpmc-omap.h b/include/linux/platform_data/gpmc-omap.h
new file mode 100644
index 0000000..d32d9de
--- /dev/null
+++ b/include/linux/platform_data/gpmc-omap.h
@@ -0,0 +1,30 @@
+/*
+ * OMAP GPMC Platform data
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc. - http://www.ti.com
+ *	Roger Quadros <rogerq@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#ifndef _GPMC_OMAP_H_
+#define _GPMC_OMAP_H_
+
+/* Maximum Number of Chip Selects */
+#define GPMC_CS_NUM		8
+
+/* Data for each chip select */
+struct gpmc_omap_cs_data {
+	bool valid;			/* data is valid */
+	bool is_nand;			/* device within this CS is NAND */
+	struct platform_device *pdev;	/* device within this CS region */
+	unsigned pdata_size;
+};
+
+struct gpmc_omap_platform_data {
+	struct gpmc_omap_cs_data cs[GPMC_CS_NUM];
+};
+
+#endif /* _GPMC_OMAP_H */
-- 
1.8.3.2

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

* [PATCH 04/36] ARM: OMAP2+: gpmc: Add gpmc timings and settings to platform data
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Add device_timings, gpmc_timings and gpmc_setting to
gpmc platform data.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.h              | 134 ------------------------------
 include/linux/platform_data/gpmc-omap.h | 139 ++++++++++++++++++++++++++++++++
 2 files changed, 139 insertions(+), 134 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h
index c476712..13554e7 100644
--- a/arch/arm/mach-omap2/gpmc.h
+++ b/arch/arm/mach-omap2/gpmc.h
@@ -71,140 +71,6 @@
 #define GPMC_IRQ_FIFOEVENTENABLE	0x01
 #define GPMC_IRQ_COUNT_EVENT		0x02
 
-#define GPMC_BURST_4			4	/* 4 word burst */
-#define GPMC_BURST_8			8	/* 8 word burst */
-#define GPMC_BURST_16			16	/* 16 word burst */
-#define GPMC_DEVWIDTH_8BIT		1	/* 8-bit device width */
-#define GPMC_DEVWIDTH_16BIT		2	/* 16-bit device width */
-#define GPMC_MUX_AAD			1	/* Addr-Addr-Data multiplex */
-#define GPMC_MUX_AD			2	/* Addr-Data multiplex */
-
-/* bool type time settings */
-struct gpmc_bool_timings {
-	bool cycle2cyclediffcsen;
-	bool cycle2cyclesamecsen;
-	bool we_extra_delay;
-	bool oe_extra_delay;
-	bool adv_extra_delay;
-	bool cs_extra_delay;
-	bool time_para_granularity;
-};
-
-/*
- * Note that all values in this struct are in nanoseconds except sync_clk
- * (which is in picoseconds), while the register values are in gpmc_fck cycles.
- */
-struct gpmc_timings {
-	/* Minimum clock period for synchronous mode (in picoseconds) */
-	u32 sync_clk;
-
-	/* Chip-select signal timings corresponding to GPMC_CS_CONFIG2 */
-	u32 cs_on;		/* Assertion time */
-	u32 cs_rd_off;		/* Read deassertion time */
-	u32 cs_wr_off;		/* Write deassertion time */
-
-	/* ADV signal timings corresponding to GPMC_CONFIG3 */
-	u32 adv_on;		/* Assertion time */
-	u32 adv_rd_off;		/* Read deassertion time */
-	u32 adv_wr_off;		/* Write deassertion time */
-
-	/* WE signals timings corresponding to GPMC_CONFIG4 */
-	u32 we_on;		/* WE assertion time */
-	u32 we_off;		/* WE deassertion time */
-
-	/* OE signals timings corresponding to GPMC_CONFIG4 */
-	u32 oe_on;		/* OE assertion time */
-	u32 oe_off;		/* OE deassertion time */
-
-	/* Access time and cycle time timings corresponding to GPMC_CONFIG5 */
-	u32 page_burst_access;	/* Multiple access word delay */
-	u32 access;		/* Start-cycle to first data valid delay */
-	u32 rd_cycle;		/* Total read cycle time */
-	u32 wr_cycle;		/* Total write cycle time */
-
-	u32 bus_turnaround;
-	u32 cycle2cycle_delay;
-
-	u32 wait_monitoring;
-	u32 clk_activation;
-
-	/* The following are only on OMAP3430 */
-	u32 wr_access;		/* WRACCESSTIME */
-	u32 wr_data_mux_bus;	/* WRDATAONADMUXBUS */
-
-	struct gpmc_bool_timings bool_timings;
-};
-
-/* Device timings in picoseconds */
-struct gpmc_device_timings {
-	u32 t_ceasu;	/* address setup to CS valid */
-	u32 t_avdasu;	/* address setup to ADV valid */
-	/* XXX: try to combine t_avdp_r & t_avdp_w. Issue is
-	 * of tusb using these timings even for sync whilst
-	 * ideally for adv_rd/(wr)_off it should have considered
-	 * t_avdh instead. This indirectly necessitates r/w
-	 * variations of t_avdp as it is possible to have one
-	 * sync & other async
-	 */
-	u32 t_avdp_r;	/* ADV low time (what about t_cer ?) */
-	u32 t_avdp_w;
-	u32 t_aavdh;	/* address hold time */
-	u32 t_oeasu;	/* address setup to OE valid */
-	u32 t_aa;	/* access time from ADV assertion */
-	u32 t_iaa;	/* initial access time */
-	u32 t_oe;	/* access time from OE assertion */
-	u32 t_ce;	/* access time from CS asertion */
-	u32 t_rd_cycle;	/* read cycle time */
-	u32 t_cez_r;	/* read CS deassertion to high Z */
-	u32 t_cez_w;	/* write CS deassertion to high Z */
-	u32 t_oez;	/* OE deassertion to high Z */
-	u32 t_weasu;	/* address setup to WE valid */
-	u32 t_wpl;	/* write assertion time */
-	u32 t_wph;	/* write deassertion time */
-	u32 t_wr_cycle;	/* write cycle time */
-
-	u32 clk;
-	u32 t_bacc;	/* burst access valid clock to output delay */
-	u32 t_ces;	/* CS setup time to clk */
-	u32 t_avds;	/* ADV setup time to clk */
-	u32 t_avdh;	/* ADV hold time from clk */
-	u32 t_ach;	/* address hold time from clk */
-	u32 t_rdyo;	/* clk to ready valid */
-
-	u32 t_ce_rdyz;	/* XXX: description ?, or use t_cez instead */
-	u32 t_ce_avd;	/* CS on to ADV on delay */
-
-	/* XXX: check the possibility of combining
-	 * cyc_aavhd_oe & cyc_aavdh_we
-	 */
-	u8 cyc_aavdh_oe;/* read address hold time in cycles */
-	u8 cyc_aavdh_we;/* write address hold time in cycles */
-	u8 cyc_oe;	/* access time from OE assertion in cycles */
-	u8 cyc_wpl;	/* write deassertion time in cycles */
-	u32 cyc_iaa;	/* initial access time in cycles */
-
-	/* extra delays */
-	bool ce_xdelay;
-	bool avd_xdelay;
-	bool oe_xdelay;
-	bool we_xdelay;
-};
-
-struct gpmc_settings {
-	bool burst_wrap;	/* enables wrap bursting */
-	bool burst_read;	/* enables read page/burst mode */
-	bool burst_write;	/* enables write page/burst mode */
-	bool device_nand;	/* device is NAND */
-	bool sync_read;		/* enables synchronous reads */
-	bool sync_write;	/* enables synchronous writes */
-	bool wait_on_read;	/* monitor wait on reads */
-	bool wait_on_write;	/* monitor wait on writes */
-	u32 burst_len;		/* page/burst length */
-	u32 device_width;	/* device bus width (8 or 16 bit) */
-	u32 mux_add_data;	/* multiplex address & data */
-	u32 wait_pin;		/* wait-pin to be used */
-};
-
 extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
 			     struct gpmc_settings *gpmc_s,
 			     struct gpmc_device_timings *dev_t);
diff --git a/include/linux/platform_data/gpmc-omap.h b/include/linux/platform_data/gpmc-omap.h
index d32d9de..e861112 100644
--- a/include/linux/platform_data/gpmc-omap.h
+++ b/include/linux/platform_data/gpmc-omap.h
@@ -15,10 +15,149 @@
 /* Maximum Number of Chip Selects */
 #define GPMC_CS_NUM		8
 
+/* bool type time settings */
+struct gpmc_bool_timings {
+	bool cycle2cyclediffcsen;
+	bool cycle2cyclesamecsen;
+	bool we_extra_delay;
+	bool oe_extra_delay;
+	bool adv_extra_delay;
+	bool cs_extra_delay;
+	bool time_para_granularity;
+};
+
+/*
+ * Note that all values in this struct are in nanoseconds except sync_clk
+ * (which is in picoseconds), while the register values are in gpmc_fck cycles.
+ */
+struct gpmc_timings {
+	/* Minimum clock period for synchronous mode (in picoseconds) */
+	u32 sync_clk;
+
+	/* Chip-select signal timings corresponding to GPMC_CS_CONFIG2 */
+	u32 cs_on;		/* Assertion time */
+	u32 cs_rd_off;		/* Read deassertion time */
+	u32 cs_wr_off;		/* Write deassertion time */
+
+	/* ADV signal timings corresponding to GPMC_CONFIG3 */
+	u32 adv_on;		/* Assertion time */
+	u32 adv_rd_off;		/* Read deassertion time */
+	u32 adv_wr_off;		/* Write deassertion time */
+
+	/* WE signals timings corresponding to GPMC_CONFIG4 */
+	u32 we_on;		/* WE assertion time */
+	u32 we_off;		/* WE deassertion time */
+
+	/* OE signals timings corresponding to GPMC_CONFIG4 */
+	u32 oe_on;		/* OE assertion time */
+	u32 oe_off;		/* OE deassertion time */
+
+	/* Access time and cycle time timings corresponding to GPMC_CONFIG5 */
+	u32 page_burst_access;	/* Multiple access word delay */
+	u32 access;		/* Start-cycle to first data valid delay */
+	u32 rd_cycle;		/* Total read cycle time */
+	u32 wr_cycle;		/* Total write cycle time */
+
+	u32 bus_turnaround;
+	u32 cycle2cycle_delay;
+
+	u32 wait_monitoring;
+	u32 clk_activation;
+
+	/* The following are only on OMAP3430 */
+	u32 wr_access;		/* WRACCESSTIME */
+	u32 wr_data_mux_bus;	/* WRDATAONADMUXBUS */
+
+	struct gpmc_bool_timings bool_timings;
+};
+
+
+/* Device timings in picoseconds */
+struct gpmc_device_timings {
+	u32 t_ceasu;	/* address setup to CS valid */
+	u32 t_avdasu;	/* address setup to ADV valid */
+	/* XXX: try to combine t_avdp_r & t_avdp_w. Issue is
+	 * of tusb using these timings even for sync whilst
+	 * ideally for adv_rd/(wr)_off it should have considered
+	 * t_avdh instead. This indirectly necessitates r/w
+	 * variations of t_avdp as it is possible to have one
+	 * sync & other async
+	 */
+	u32 t_avdp_r;	/* ADV low time (what about t_cer ?) */
+	u32 t_avdp_w;
+	u32 t_aavdh;	/* address hold time */
+	u32 t_oeasu;	/* address setup to OE valid */
+	u32 t_aa;	/* access time from ADV assertion */
+	u32 t_iaa;	/* initial access time */
+	u32 t_oe;	/* access time from OE assertion */
+	u32 t_ce;	/* access time from CS asertion */
+	u32 t_rd_cycle;	/* read cycle time */
+	u32 t_cez_r;	/* read CS deassertion to high Z */
+	u32 t_cez_w;	/* write CS deassertion to high Z */
+	u32 t_oez;	/* OE deassertion to high Z */
+	u32 t_weasu;	/* address setup to WE valid */
+	u32 t_wpl;	/* write assertion time */
+	u32 t_wph;	/* write deassertion time */
+	u32 t_wr_cycle;	/* write cycle time */
+
+	u32 clk;
+	u32 t_bacc;	/* burst access valid clock to output delay */
+	u32 t_ces;	/* CS setup time to clk */
+	u32 t_avds;	/* ADV setup time to clk */
+	u32 t_avdh;	/* ADV hold time from clk */
+	u32 t_ach;	/* address hold time from clk */
+	u32 t_rdyo;	/* clk to ready valid */
+
+	u32 t_ce_rdyz;	/* XXX: description ?, or use t_cez instead */
+	u32 t_ce_avd;	/* CS on to ADV on delay */
+
+	/* XXX: check the possibility of combining
+	 * cyc_aavhd_oe & cyc_aavdh_we
+	 */
+	u8 cyc_aavdh_oe;/* read address hold time in cycles */
+	u8 cyc_aavdh_we;/* write address hold time in cycles */
+	u8 cyc_oe;	/* access time from OE assertion in cycles */
+	u8 cyc_wpl;	/* write deassertion time in cycles */
+	u32 cyc_iaa;	/* initial access time in cycles */
+
+	/* extra delays */
+	bool ce_xdelay;
+	bool avd_xdelay;
+	bool oe_xdelay;
+	bool we_xdelay;
+};
+
+#define GPMC_BURST_4			4	/* 4 word burst */
+#define GPMC_BURST_8			8	/* 8 word burst */
+#define GPMC_BURST_16			16	/* 16 word burst */
+#define GPMC_DEVWIDTH_8BIT		1	/* 8-bit device width */
+#define GPMC_DEVWIDTH_16BIT		2	/* 16-bit device width */
+#define GPMC_MUX_AAD			1	/* Addr-Addr-Data multiplex */
+#define GPMC_MUX_AD			2	/* Addr-Data multiplex */
+
+struct gpmc_settings {
+	bool burst_wrap;	/* enables wrap bursting */
+	bool burst_read;	/* enables read page/burst mode */
+	bool burst_write;	/* enables write page/burst mode */
+	bool device_nand;	/* device is NAND */
+	bool sync_read;		/* enables synchronous reads */
+	bool sync_write;	/* enables synchronous writes */
+	bool wait_on_read;	/* monitor wait on reads */
+	bool wait_on_write;	/* monitor wait on writes */
+	u32 burst_len;		/* page/burst length */
+	u32 device_width;	/* device bus width (8 or 16 bit) */
+	u32 mux_add_data;	/* multiplex address & data */
+	u32 wait_pin;		/* wait-pin to be used */
+};
+
+
 /* Data for each chip select */
 struct gpmc_omap_cs_data {
 	bool valid;			/* data is valid */
 	bool is_nand;			/* device within this CS is NAND */
+	struct gpmc_settings *settings;
+	struct gpmc_device_timings *device_timings;
+	struct gpmc_timings *gpmc_timings;
 	struct platform_device *pdev;	/* device within this CS region */
 	unsigned pdata_size;
 };
-- 
1.8.3.2


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

* [PATCH 04/36] ARM: OMAP2+: gpmc: Add gpmc timings and settings to platform data
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Add device_timings, gpmc_timings and gpmc_setting to
gpmc platform data.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.h              | 134 ------------------------------
 include/linux/platform_data/gpmc-omap.h | 139 ++++++++++++++++++++++++++++++++
 2 files changed, 139 insertions(+), 134 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h
index c476712..13554e7 100644
--- a/arch/arm/mach-omap2/gpmc.h
+++ b/arch/arm/mach-omap2/gpmc.h
@@ -71,140 +71,6 @@
 #define GPMC_IRQ_FIFOEVENTENABLE	0x01
 #define GPMC_IRQ_COUNT_EVENT		0x02
 
-#define GPMC_BURST_4			4	/* 4 word burst */
-#define GPMC_BURST_8			8	/* 8 word burst */
-#define GPMC_BURST_16			16	/* 16 word burst */
-#define GPMC_DEVWIDTH_8BIT		1	/* 8-bit device width */
-#define GPMC_DEVWIDTH_16BIT		2	/* 16-bit device width */
-#define GPMC_MUX_AAD			1	/* Addr-Addr-Data multiplex */
-#define GPMC_MUX_AD			2	/* Addr-Data multiplex */
-
-/* bool type time settings */
-struct gpmc_bool_timings {
-	bool cycle2cyclediffcsen;
-	bool cycle2cyclesamecsen;
-	bool we_extra_delay;
-	bool oe_extra_delay;
-	bool adv_extra_delay;
-	bool cs_extra_delay;
-	bool time_para_granularity;
-};
-
-/*
- * Note that all values in this struct are in nanoseconds except sync_clk
- * (which is in picoseconds), while the register values are in gpmc_fck cycles.
- */
-struct gpmc_timings {
-	/* Minimum clock period for synchronous mode (in picoseconds) */
-	u32 sync_clk;
-
-	/* Chip-select signal timings corresponding to GPMC_CS_CONFIG2 */
-	u32 cs_on;		/* Assertion time */
-	u32 cs_rd_off;		/* Read deassertion time */
-	u32 cs_wr_off;		/* Write deassertion time */
-
-	/* ADV signal timings corresponding to GPMC_CONFIG3 */
-	u32 adv_on;		/* Assertion time */
-	u32 adv_rd_off;		/* Read deassertion time */
-	u32 adv_wr_off;		/* Write deassertion time */
-
-	/* WE signals timings corresponding to GPMC_CONFIG4 */
-	u32 we_on;		/* WE assertion time */
-	u32 we_off;		/* WE deassertion time */
-
-	/* OE signals timings corresponding to GPMC_CONFIG4 */
-	u32 oe_on;		/* OE assertion time */
-	u32 oe_off;		/* OE deassertion time */
-
-	/* Access time and cycle time timings corresponding to GPMC_CONFIG5 */
-	u32 page_burst_access;	/* Multiple access word delay */
-	u32 access;		/* Start-cycle to first data valid delay */
-	u32 rd_cycle;		/* Total read cycle time */
-	u32 wr_cycle;		/* Total write cycle time */
-
-	u32 bus_turnaround;
-	u32 cycle2cycle_delay;
-
-	u32 wait_monitoring;
-	u32 clk_activation;
-
-	/* The following are only on OMAP3430 */
-	u32 wr_access;		/* WRACCESSTIME */
-	u32 wr_data_mux_bus;	/* WRDATAONADMUXBUS */
-
-	struct gpmc_bool_timings bool_timings;
-};
-
-/* Device timings in picoseconds */
-struct gpmc_device_timings {
-	u32 t_ceasu;	/* address setup to CS valid */
-	u32 t_avdasu;	/* address setup to ADV valid */
-	/* XXX: try to combine t_avdp_r & t_avdp_w. Issue is
-	 * of tusb using these timings even for sync whilst
-	 * ideally for adv_rd/(wr)_off it should have considered
-	 * t_avdh instead. This indirectly necessitates r/w
-	 * variations of t_avdp as it is possible to have one
-	 * sync & other async
-	 */
-	u32 t_avdp_r;	/* ADV low time (what about t_cer ?) */
-	u32 t_avdp_w;
-	u32 t_aavdh;	/* address hold time */
-	u32 t_oeasu;	/* address setup to OE valid */
-	u32 t_aa;	/* access time from ADV assertion */
-	u32 t_iaa;	/* initial access time */
-	u32 t_oe;	/* access time from OE assertion */
-	u32 t_ce;	/* access time from CS asertion */
-	u32 t_rd_cycle;	/* read cycle time */
-	u32 t_cez_r;	/* read CS deassertion to high Z */
-	u32 t_cez_w;	/* write CS deassertion to high Z */
-	u32 t_oez;	/* OE deassertion to high Z */
-	u32 t_weasu;	/* address setup to WE valid */
-	u32 t_wpl;	/* write assertion time */
-	u32 t_wph;	/* write deassertion time */
-	u32 t_wr_cycle;	/* write cycle time */
-
-	u32 clk;
-	u32 t_bacc;	/* burst access valid clock to output delay */
-	u32 t_ces;	/* CS setup time to clk */
-	u32 t_avds;	/* ADV setup time to clk */
-	u32 t_avdh;	/* ADV hold time from clk */
-	u32 t_ach;	/* address hold time from clk */
-	u32 t_rdyo;	/* clk to ready valid */
-
-	u32 t_ce_rdyz;	/* XXX: description ?, or use t_cez instead */
-	u32 t_ce_avd;	/* CS on to ADV on delay */
-
-	/* XXX: check the possibility of combining
-	 * cyc_aavhd_oe & cyc_aavdh_we
-	 */
-	u8 cyc_aavdh_oe;/* read address hold time in cycles */
-	u8 cyc_aavdh_we;/* write address hold time in cycles */
-	u8 cyc_oe;	/* access time from OE assertion in cycles */
-	u8 cyc_wpl;	/* write deassertion time in cycles */
-	u32 cyc_iaa;	/* initial access time in cycles */
-
-	/* extra delays */
-	bool ce_xdelay;
-	bool avd_xdelay;
-	bool oe_xdelay;
-	bool we_xdelay;
-};
-
-struct gpmc_settings {
-	bool burst_wrap;	/* enables wrap bursting */
-	bool burst_read;	/* enables read page/burst mode */
-	bool burst_write;	/* enables write page/burst mode */
-	bool device_nand;	/* device is NAND */
-	bool sync_read;		/* enables synchronous reads */
-	bool sync_write;	/* enables synchronous writes */
-	bool wait_on_read;	/* monitor wait on reads */
-	bool wait_on_write;	/* monitor wait on writes */
-	u32 burst_len;		/* page/burst length */
-	u32 device_width;	/* device bus width (8 or 16 bit) */
-	u32 mux_add_data;	/* multiplex address & data */
-	u32 wait_pin;		/* wait-pin to be used */
-};
-
 extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
 			     struct gpmc_settings *gpmc_s,
 			     struct gpmc_device_timings *dev_t);
diff --git a/include/linux/platform_data/gpmc-omap.h b/include/linux/platform_data/gpmc-omap.h
index d32d9de..e861112 100644
--- a/include/linux/platform_data/gpmc-omap.h
+++ b/include/linux/platform_data/gpmc-omap.h
@@ -15,10 +15,149 @@
 /* Maximum Number of Chip Selects */
 #define GPMC_CS_NUM		8
 
+/* bool type time settings */
+struct gpmc_bool_timings {
+	bool cycle2cyclediffcsen;
+	bool cycle2cyclesamecsen;
+	bool we_extra_delay;
+	bool oe_extra_delay;
+	bool adv_extra_delay;
+	bool cs_extra_delay;
+	bool time_para_granularity;
+};
+
+/*
+ * Note that all values in this struct are in nanoseconds except sync_clk
+ * (which is in picoseconds), while the register values are in gpmc_fck cycles.
+ */
+struct gpmc_timings {
+	/* Minimum clock period for synchronous mode (in picoseconds) */
+	u32 sync_clk;
+
+	/* Chip-select signal timings corresponding to GPMC_CS_CONFIG2 */
+	u32 cs_on;		/* Assertion time */
+	u32 cs_rd_off;		/* Read deassertion time */
+	u32 cs_wr_off;		/* Write deassertion time */
+
+	/* ADV signal timings corresponding to GPMC_CONFIG3 */
+	u32 adv_on;		/* Assertion time */
+	u32 adv_rd_off;		/* Read deassertion time */
+	u32 adv_wr_off;		/* Write deassertion time */
+
+	/* WE signals timings corresponding to GPMC_CONFIG4 */
+	u32 we_on;		/* WE assertion time */
+	u32 we_off;		/* WE deassertion time */
+
+	/* OE signals timings corresponding to GPMC_CONFIG4 */
+	u32 oe_on;		/* OE assertion time */
+	u32 oe_off;		/* OE deassertion time */
+
+	/* Access time and cycle time timings corresponding to GPMC_CONFIG5 */
+	u32 page_burst_access;	/* Multiple access word delay */
+	u32 access;		/* Start-cycle to first data valid delay */
+	u32 rd_cycle;		/* Total read cycle time */
+	u32 wr_cycle;		/* Total write cycle time */
+
+	u32 bus_turnaround;
+	u32 cycle2cycle_delay;
+
+	u32 wait_monitoring;
+	u32 clk_activation;
+
+	/* The following are only on OMAP3430 */
+	u32 wr_access;		/* WRACCESSTIME */
+	u32 wr_data_mux_bus;	/* WRDATAONADMUXBUS */
+
+	struct gpmc_bool_timings bool_timings;
+};
+
+
+/* Device timings in picoseconds */
+struct gpmc_device_timings {
+	u32 t_ceasu;	/* address setup to CS valid */
+	u32 t_avdasu;	/* address setup to ADV valid */
+	/* XXX: try to combine t_avdp_r & t_avdp_w. Issue is
+	 * of tusb using these timings even for sync whilst
+	 * ideally for adv_rd/(wr)_off it should have considered
+	 * t_avdh instead. This indirectly necessitates r/w
+	 * variations of t_avdp as it is possible to have one
+	 * sync & other async
+	 */
+	u32 t_avdp_r;	/* ADV low time (what about t_cer ?) */
+	u32 t_avdp_w;
+	u32 t_aavdh;	/* address hold time */
+	u32 t_oeasu;	/* address setup to OE valid */
+	u32 t_aa;	/* access time from ADV assertion */
+	u32 t_iaa;	/* initial access time */
+	u32 t_oe;	/* access time from OE assertion */
+	u32 t_ce;	/* access time from CS asertion */
+	u32 t_rd_cycle;	/* read cycle time */
+	u32 t_cez_r;	/* read CS deassertion to high Z */
+	u32 t_cez_w;	/* write CS deassertion to high Z */
+	u32 t_oez;	/* OE deassertion to high Z */
+	u32 t_weasu;	/* address setup to WE valid */
+	u32 t_wpl;	/* write assertion time */
+	u32 t_wph;	/* write deassertion time */
+	u32 t_wr_cycle;	/* write cycle time */
+
+	u32 clk;
+	u32 t_bacc;	/* burst access valid clock to output delay */
+	u32 t_ces;	/* CS setup time to clk */
+	u32 t_avds;	/* ADV setup time to clk */
+	u32 t_avdh;	/* ADV hold time from clk */
+	u32 t_ach;	/* address hold time from clk */
+	u32 t_rdyo;	/* clk to ready valid */
+
+	u32 t_ce_rdyz;	/* XXX: description ?, or use t_cez instead */
+	u32 t_ce_avd;	/* CS on to ADV on delay */
+
+	/* XXX: check the possibility of combining
+	 * cyc_aavhd_oe & cyc_aavdh_we
+	 */
+	u8 cyc_aavdh_oe;/* read address hold time in cycles */
+	u8 cyc_aavdh_we;/* write address hold time in cycles */
+	u8 cyc_oe;	/* access time from OE assertion in cycles */
+	u8 cyc_wpl;	/* write deassertion time in cycles */
+	u32 cyc_iaa;	/* initial access time in cycles */
+
+	/* extra delays */
+	bool ce_xdelay;
+	bool avd_xdelay;
+	bool oe_xdelay;
+	bool we_xdelay;
+};
+
+#define GPMC_BURST_4			4	/* 4 word burst */
+#define GPMC_BURST_8			8	/* 8 word burst */
+#define GPMC_BURST_16			16	/* 16 word burst */
+#define GPMC_DEVWIDTH_8BIT		1	/* 8-bit device width */
+#define GPMC_DEVWIDTH_16BIT		2	/* 16-bit device width */
+#define GPMC_MUX_AAD			1	/* Addr-Addr-Data multiplex */
+#define GPMC_MUX_AD			2	/* Addr-Data multiplex */
+
+struct gpmc_settings {
+	bool burst_wrap;	/* enables wrap bursting */
+	bool burst_read;	/* enables read page/burst mode */
+	bool burst_write;	/* enables write page/burst mode */
+	bool device_nand;	/* device is NAND */
+	bool sync_read;		/* enables synchronous reads */
+	bool sync_write;	/* enables synchronous writes */
+	bool wait_on_read;	/* monitor wait on reads */
+	bool wait_on_write;	/* monitor wait on writes */
+	u32 burst_len;		/* page/burst length */
+	u32 device_width;	/* device bus width (8 or 16 bit) */
+	u32 mux_add_data;	/* multiplex address & data */
+	u32 wait_pin;		/* wait-pin to be used */
+};
+
+
 /* Data for each chip select */
 struct gpmc_omap_cs_data {
 	bool valid;			/* data is valid */
 	bool is_nand;			/* device within this CS is NAND */
+	struct gpmc_settings *settings;
+	struct gpmc_device_timings *device_timings;
+	struct gpmc_timings *gpmc_timings;
 	struct platform_device *pdev;	/* device within this CS region */
 	unsigned pdata_size;
 };
-- 
1.8.3.2

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

* [PATCH 04/36] ARM: OMAP2+: gpmc: Add gpmc timings and settings to platform data
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Add device_timings, gpmc_timings and gpmc_setting to
gpmc platform data.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.h              | 134 ------------------------------
 include/linux/platform_data/gpmc-omap.h | 139 ++++++++++++++++++++++++++++++++
 2 files changed, 139 insertions(+), 134 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h
index c476712..13554e7 100644
--- a/arch/arm/mach-omap2/gpmc.h
+++ b/arch/arm/mach-omap2/gpmc.h
@@ -71,140 +71,6 @@
 #define GPMC_IRQ_FIFOEVENTENABLE	0x01
 #define GPMC_IRQ_COUNT_EVENT		0x02
 
-#define GPMC_BURST_4			4	/* 4 word burst */
-#define GPMC_BURST_8			8	/* 8 word burst */
-#define GPMC_BURST_16			16	/* 16 word burst */
-#define GPMC_DEVWIDTH_8BIT		1	/* 8-bit device width */
-#define GPMC_DEVWIDTH_16BIT		2	/* 16-bit device width */
-#define GPMC_MUX_AAD			1	/* Addr-Addr-Data multiplex */
-#define GPMC_MUX_AD			2	/* Addr-Data multiplex */
-
-/* bool type time settings */
-struct gpmc_bool_timings {
-	bool cycle2cyclediffcsen;
-	bool cycle2cyclesamecsen;
-	bool we_extra_delay;
-	bool oe_extra_delay;
-	bool adv_extra_delay;
-	bool cs_extra_delay;
-	bool time_para_granularity;
-};
-
-/*
- * Note that all values in this struct are in nanoseconds except sync_clk
- * (which is in picoseconds), while the register values are in gpmc_fck cycles.
- */
-struct gpmc_timings {
-	/* Minimum clock period for synchronous mode (in picoseconds) */
-	u32 sync_clk;
-
-	/* Chip-select signal timings corresponding to GPMC_CS_CONFIG2 */
-	u32 cs_on;		/* Assertion time */
-	u32 cs_rd_off;		/* Read deassertion time */
-	u32 cs_wr_off;		/* Write deassertion time */
-
-	/* ADV signal timings corresponding to GPMC_CONFIG3 */
-	u32 adv_on;		/* Assertion time */
-	u32 adv_rd_off;		/* Read deassertion time */
-	u32 adv_wr_off;		/* Write deassertion time */
-
-	/* WE signals timings corresponding to GPMC_CONFIG4 */
-	u32 we_on;		/* WE assertion time */
-	u32 we_off;		/* WE deassertion time */
-
-	/* OE signals timings corresponding to GPMC_CONFIG4 */
-	u32 oe_on;		/* OE assertion time */
-	u32 oe_off;		/* OE deassertion time */
-
-	/* Access time and cycle time timings corresponding to GPMC_CONFIG5 */
-	u32 page_burst_access;	/* Multiple access word delay */
-	u32 access;		/* Start-cycle to first data valid delay */
-	u32 rd_cycle;		/* Total read cycle time */
-	u32 wr_cycle;		/* Total write cycle time */
-
-	u32 bus_turnaround;
-	u32 cycle2cycle_delay;
-
-	u32 wait_monitoring;
-	u32 clk_activation;
-
-	/* The following are only on OMAP3430 */
-	u32 wr_access;		/* WRACCESSTIME */
-	u32 wr_data_mux_bus;	/* WRDATAONADMUXBUS */
-
-	struct gpmc_bool_timings bool_timings;
-};
-
-/* Device timings in picoseconds */
-struct gpmc_device_timings {
-	u32 t_ceasu;	/* address setup to CS valid */
-	u32 t_avdasu;	/* address setup to ADV valid */
-	/* XXX: try to combine t_avdp_r & t_avdp_w. Issue is
-	 * of tusb using these timings even for sync whilst
-	 * ideally for adv_rd/(wr)_off it should have considered
-	 * t_avdh instead. This indirectly necessitates r/w
-	 * variations of t_avdp as it is possible to have one
-	 * sync & other async
-	 */
-	u32 t_avdp_r;	/* ADV low time (what about t_cer ?) */
-	u32 t_avdp_w;
-	u32 t_aavdh;	/* address hold time */
-	u32 t_oeasu;	/* address setup to OE valid */
-	u32 t_aa;	/* access time from ADV assertion */
-	u32 t_iaa;	/* initial access time */
-	u32 t_oe;	/* access time from OE assertion */
-	u32 t_ce;	/* access time from CS asertion */
-	u32 t_rd_cycle;	/* read cycle time */
-	u32 t_cez_r;	/* read CS deassertion to high Z */
-	u32 t_cez_w;	/* write CS deassertion to high Z */
-	u32 t_oez;	/* OE deassertion to high Z */
-	u32 t_weasu;	/* address setup to WE valid */
-	u32 t_wpl;	/* write assertion time */
-	u32 t_wph;	/* write deassertion time */
-	u32 t_wr_cycle;	/* write cycle time */
-
-	u32 clk;
-	u32 t_bacc;	/* burst access valid clock to output delay */
-	u32 t_ces;	/* CS setup time to clk */
-	u32 t_avds;	/* ADV setup time to clk */
-	u32 t_avdh;	/* ADV hold time from clk */
-	u32 t_ach;	/* address hold time from clk */
-	u32 t_rdyo;	/* clk to ready valid */
-
-	u32 t_ce_rdyz;	/* XXX: description ?, or use t_cez instead */
-	u32 t_ce_avd;	/* CS on to ADV on delay */
-
-	/* XXX: check the possibility of combining
-	 * cyc_aavhd_oe & cyc_aavdh_we
-	 */
-	u8 cyc_aavdh_oe;/* read address hold time in cycles */
-	u8 cyc_aavdh_we;/* write address hold time in cycles */
-	u8 cyc_oe;	/* access time from OE assertion in cycles */
-	u8 cyc_wpl;	/* write deassertion time in cycles */
-	u32 cyc_iaa;	/* initial access time in cycles */
-
-	/* extra delays */
-	bool ce_xdelay;
-	bool avd_xdelay;
-	bool oe_xdelay;
-	bool we_xdelay;
-};
-
-struct gpmc_settings {
-	bool burst_wrap;	/* enables wrap bursting */
-	bool burst_read;	/* enables read page/burst mode */
-	bool burst_write;	/* enables write page/burst mode */
-	bool device_nand;	/* device is NAND */
-	bool sync_read;		/* enables synchronous reads */
-	bool sync_write;	/* enables synchronous writes */
-	bool wait_on_read;	/* monitor wait on reads */
-	bool wait_on_write;	/* monitor wait on writes */
-	u32 burst_len;		/* page/burst length */
-	u32 device_width;	/* device bus width (8 or 16 bit) */
-	u32 mux_add_data;	/* multiplex address & data */
-	u32 wait_pin;		/* wait-pin to be used */
-};
-
 extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
 			     struct gpmc_settings *gpmc_s,
 			     struct gpmc_device_timings *dev_t);
diff --git a/include/linux/platform_data/gpmc-omap.h b/include/linux/platform_data/gpmc-omap.h
index d32d9de..e861112 100644
--- a/include/linux/platform_data/gpmc-omap.h
+++ b/include/linux/platform_data/gpmc-omap.h
@@ -15,10 +15,149 @@
 /* Maximum Number of Chip Selects */
 #define GPMC_CS_NUM		8
 
+/* bool type time settings */
+struct gpmc_bool_timings {
+	bool cycle2cyclediffcsen;
+	bool cycle2cyclesamecsen;
+	bool we_extra_delay;
+	bool oe_extra_delay;
+	bool adv_extra_delay;
+	bool cs_extra_delay;
+	bool time_para_granularity;
+};
+
+/*
+ * Note that all values in this struct are in nanoseconds except sync_clk
+ * (which is in picoseconds), while the register values are in gpmc_fck cycles.
+ */
+struct gpmc_timings {
+	/* Minimum clock period for synchronous mode (in picoseconds) */
+	u32 sync_clk;
+
+	/* Chip-select signal timings corresponding to GPMC_CS_CONFIG2 */
+	u32 cs_on;		/* Assertion time */
+	u32 cs_rd_off;		/* Read deassertion time */
+	u32 cs_wr_off;		/* Write deassertion time */
+
+	/* ADV signal timings corresponding to GPMC_CONFIG3 */
+	u32 adv_on;		/* Assertion time */
+	u32 adv_rd_off;		/* Read deassertion time */
+	u32 adv_wr_off;		/* Write deassertion time */
+
+	/* WE signals timings corresponding to GPMC_CONFIG4 */
+	u32 we_on;		/* WE assertion time */
+	u32 we_off;		/* WE deassertion time */
+
+	/* OE signals timings corresponding to GPMC_CONFIG4 */
+	u32 oe_on;		/* OE assertion time */
+	u32 oe_off;		/* OE deassertion time */
+
+	/* Access time and cycle time timings corresponding to GPMC_CONFIG5 */
+	u32 page_burst_access;	/* Multiple access word delay */
+	u32 access;		/* Start-cycle to first data valid delay */
+	u32 rd_cycle;		/* Total read cycle time */
+	u32 wr_cycle;		/* Total write cycle time */
+
+	u32 bus_turnaround;
+	u32 cycle2cycle_delay;
+
+	u32 wait_monitoring;
+	u32 clk_activation;
+
+	/* The following are only on OMAP3430 */
+	u32 wr_access;		/* WRACCESSTIME */
+	u32 wr_data_mux_bus;	/* WRDATAONADMUXBUS */
+
+	struct gpmc_bool_timings bool_timings;
+};
+
+
+/* Device timings in picoseconds */
+struct gpmc_device_timings {
+	u32 t_ceasu;	/* address setup to CS valid */
+	u32 t_avdasu;	/* address setup to ADV valid */
+	/* XXX: try to combine t_avdp_r & t_avdp_w. Issue is
+	 * of tusb using these timings even for sync whilst
+	 * ideally for adv_rd/(wr)_off it should have considered
+	 * t_avdh instead. This indirectly necessitates r/w
+	 * variations of t_avdp as it is possible to have one
+	 * sync & other async
+	 */
+	u32 t_avdp_r;	/* ADV low time (what about t_cer ?) */
+	u32 t_avdp_w;
+	u32 t_aavdh;	/* address hold time */
+	u32 t_oeasu;	/* address setup to OE valid */
+	u32 t_aa;	/* access time from ADV assertion */
+	u32 t_iaa;	/* initial access time */
+	u32 t_oe;	/* access time from OE assertion */
+	u32 t_ce;	/* access time from CS asertion */
+	u32 t_rd_cycle;	/* read cycle time */
+	u32 t_cez_r;	/* read CS deassertion to high Z */
+	u32 t_cez_w;	/* write CS deassertion to high Z */
+	u32 t_oez;	/* OE deassertion to high Z */
+	u32 t_weasu;	/* address setup to WE valid */
+	u32 t_wpl;	/* write assertion time */
+	u32 t_wph;	/* write deassertion time */
+	u32 t_wr_cycle;	/* write cycle time */
+
+	u32 clk;
+	u32 t_bacc;	/* burst access valid clock to output delay */
+	u32 t_ces;	/* CS setup time to clk */
+	u32 t_avds;	/* ADV setup time to clk */
+	u32 t_avdh;	/* ADV hold time from clk */
+	u32 t_ach;	/* address hold time from clk */
+	u32 t_rdyo;	/* clk to ready valid */
+
+	u32 t_ce_rdyz;	/* XXX: description ?, or use t_cez instead */
+	u32 t_ce_avd;	/* CS on to ADV on delay */
+
+	/* XXX: check the possibility of combining
+	 * cyc_aavhd_oe & cyc_aavdh_we
+	 */
+	u8 cyc_aavdh_oe;/* read address hold time in cycles */
+	u8 cyc_aavdh_we;/* write address hold time in cycles */
+	u8 cyc_oe;	/* access time from OE assertion in cycles */
+	u8 cyc_wpl;	/* write deassertion time in cycles */
+	u32 cyc_iaa;	/* initial access time in cycles */
+
+	/* extra delays */
+	bool ce_xdelay;
+	bool avd_xdelay;
+	bool oe_xdelay;
+	bool we_xdelay;
+};
+
+#define GPMC_BURST_4			4	/* 4 word burst */
+#define GPMC_BURST_8			8	/* 8 word burst */
+#define GPMC_BURST_16			16	/* 16 word burst */
+#define GPMC_DEVWIDTH_8BIT		1	/* 8-bit device width */
+#define GPMC_DEVWIDTH_16BIT		2	/* 16-bit device width */
+#define GPMC_MUX_AAD			1	/* Addr-Addr-Data multiplex */
+#define GPMC_MUX_AD			2	/* Addr-Data multiplex */
+
+struct gpmc_settings {
+	bool burst_wrap;	/* enables wrap bursting */
+	bool burst_read;	/* enables read page/burst mode */
+	bool burst_write;	/* enables write page/burst mode */
+	bool device_nand;	/* device is NAND */
+	bool sync_read;		/* enables synchronous reads */
+	bool sync_write;	/* enables synchronous writes */
+	bool wait_on_read;	/* monitor wait on reads */
+	bool wait_on_write;	/* monitor wait on writes */
+	u32 burst_len;		/* page/burst length */
+	u32 device_width;	/* device bus width (8 or 16 bit) */
+	u32 mux_add_data;	/* multiplex address & data */
+	u32 wait_pin;		/* wait-pin to be used */
+};
+
+
 /* Data for each chip select */
 struct gpmc_omap_cs_data {
 	bool valid;			/* data is valid */
 	bool is_nand;			/* device within this CS is NAND */
+	struct gpmc_settings *settings;
+	struct gpmc_device_timings *device_timings;
+	struct gpmc_timings *gpmc_timings;
 	struct platform_device *pdev;	/* device within this CS region */
 	unsigned pdata_size;
 };
-- 
1.8.3.2

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

* [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Since the Interrupt Events are used only by the NAND driver,
there is no point in managing the Interrupt registers
in the GPMC driver and complicating it with irqchip modeling.

Let's manage the interrupt registers directly in the NAND driver
and get rid of irqchip model from GPMC driver.

Get rid of IRQ commands and unused commands from gpmc_configure() in
the GPMC driver.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-nand.c              |   8 +-
 arch/arm/mach-omap2/gpmc.c                   | 168 ++-------------------------
 arch/arm/mach-omap2/gpmc.h                   |   8 +-
 drivers/mtd/nand/omap2.c                     |  76 ++++++------
 include/linux/platform_data/mtd-nand-omap2.h |   2 +
 5 files changed, 56 insertions(+), 206 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index 4349e82..3e6420b 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -31,9 +31,6 @@ static struct resource gpmc_nand_resource[] = {
 	{
 		.flags		= IORESOURCE_IRQ,
 	},
-	{
-		.flags		= IORESOURCE_IRQ,
-	},
 };
 
 static struct platform_device gpmc_nand_device = {
@@ -110,10 +107,7 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 	gpmc_nand_resource[0].end = gpmc_nand_resource[0].start +
 							NAND_IO_SIZE - 1;
 
-	gpmc_nand_resource[1].start =
-				gpmc_get_client_irq(GPMC_IRQ_FIFOEVENTENABLE);
-	gpmc_nand_resource[2].start =
-				gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT);
+	gpmc_nand_resource[1].start = gpmc_get_irq();
 
 	if (gpmc_t) {
 		err = gpmc_cs_set_timings(gpmc_nand_data->cs, gpmc_t);
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 9fe8c94..2524541 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -111,15 +111,6 @@
 
 #define GPMC_NR_WAITPINS		4
 
-/* XXX: Only NAND irq has been considered,currently these are the only ones used
- */
-#define	GPMC_NR_IRQ		2
-
-struct gpmc_client_irq	{
-	unsigned		irq;
-	u32			bitmask;
-};
-
 /* Structure to save gpmc cs context */
 struct gpmc_cs_config {
 	u32 config1;
@@ -147,10 +138,6 @@ struct omap3_gpmc_regs {
 	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
 };
 
-static struct gpmc_client_irq gpmc_client_irq[GPMC_NR_IRQ];
-static struct irq_chip gpmc_irq_chip;
-static int gpmc_irq_start;
-
 static struct resource	gpmc_mem_root;
 static struct resource	gpmc_cs_mem[GPMC_CS_NUM];
 static DEFINE_SPINLOCK(gpmc_mem_lock);
@@ -159,15 +146,13 @@ static unsigned int gpmc_cs_map = ((1 << GPMC_CS_NUM) - 1);
 static unsigned int gpmc_cs_num = GPMC_CS_NUM;
 static unsigned int gpmc_nr_waitpins;
 static struct device *gpmc_dev;
-static int gpmc_irq;
+static int gpmc_irq = -EINVAL;
 static resource_size_t phys_base, mem_size;
 static unsigned gpmc_capability;
 static void __iomem *gpmc_base;
 
 static struct clk *gpmc_l3_clk;
 
-static irqreturn_t gpmc_handle_irq(int irq, void *dev);
-
 static void gpmc_write_reg(int idx, u32 val)
 {
 	__raw_writel(val, gpmc_base + idx);
@@ -622,14 +607,6 @@ int gpmc_configure(int cmd, int wval)
 	u32 regval;
 
 	switch (cmd) {
-	case GPMC_ENABLE_IRQ:
-		gpmc_write_reg(GPMC_IRQENABLE, wval);
-		break;
-
-	case GPMC_SET_IRQ_STATUS:
-		gpmc_write_reg(GPMC_IRQSTATUS, wval);
-		break;
-
 	case GPMC_CONFIG_WP:
 		regval = gpmc_read_reg(GPMC_CONFIG);
 		if (wval)
@@ -653,6 +630,8 @@ void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs)
 	int i;
 
 	reg->gpmc_status = gpmc_base + GPMC_STATUS;
+	reg->gpmc_irqstatus = gpmc_base + GPMC_IRQSTATUS;
+	reg->gpmc_irqenable = gpmc_base + GPMC_IRQENABLE;
 	reg->gpmc_nand_command = gpmc_base + GPMC_CS0_OFFSET +
 				GPMC_CS_NAND_COMMAND + GPMC_CS_SIZE * cs;
 	reg->gpmc_nand_address = gpmc_base + GPMC_CS0_OFFSET +
@@ -680,113 +659,9 @@ void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs)
 	}
 }
 
-int gpmc_get_client_irq(unsigned irq_config)
-{
-	int i;
-
-	if (hweight32(irq_config) > 1)
-		return 0;
-
-	for (i = 0; i < GPMC_NR_IRQ; i++)
-		if (gpmc_client_irq[i].bitmask & irq_config)
-			return gpmc_client_irq[i].irq;
-
-	return 0;
-}
-
-static int gpmc_irq_endis(unsigned irq, bool endis)
-{
-	int i;
-	u32 regval;
-
-	for (i = 0; i < GPMC_NR_IRQ; i++)
-		if (irq == gpmc_client_irq[i].irq) {
-			regval = gpmc_read_reg(GPMC_IRQENABLE);
-			if (endis)
-				regval |= gpmc_client_irq[i].bitmask;
-			else
-				regval &= ~gpmc_client_irq[i].bitmask;
-			gpmc_write_reg(GPMC_IRQENABLE, regval);
-			break;
-		}
-
-	return 0;
-}
-
-static void gpmc_irq_disable(struct irq_data *p)
-{
-	gpmc_irq_endis(p->irq, false);
-}
-
-static void gpmc_irq_enable(struct irq_data *p)
-{
-	gpmc_irq_endis(p->irq, true);
-}
-
-static void gpmc_irq_noop(struct irq_data *data) { }
-
-static unsigned int gpmc_irq_noop_ret(struct irq_data *data) { return 0; }
-
-static int gpmc_setup_irq(void)
-{
-	int i;
-	u32 regval;
-
-	if (!gpmc_irq)
-		return -EINVAL;
-
-	gpmc_irq_start = irq_alloc_descs(-1, 0, GPMC_NR_IRQ, 0);
-	if (gpmc_irq_start < 0) {
-		pr_err("irq_alloc_descs failed\n");
-		return gpmc_irq_start;
-	}
-
-	gpmc_irq_chip.name = "gpmc";
-	gpmc_irq_chip.irq_startup = gpmc_irq_noop_ret;
-	gpmc_irq_chip.irq_enable = gpmc_irq_enable;
-	gpmc_irq_chip.irq_disable = gpmc_irq_disable;
-	gpmc_irq_chip.irq_shutdown = gpmc_irq_noop;
-	gpmc_irq_chip.irq_ack = gpmc_irq_noop;
-	gpmc_irq_chip.irq_mask = gpmc_irq_noop;
-	gpmc_irq_chip.irq_unmask = gpmc_irq_noop;
-
-	gpmc_client_irq[0].bitmask = GPMC_IRQ_FIFOEVENTENABLE;
-	gpmc_client_irq[1].bitmask = GPMC_IRQ_COUNT_EVENT;
-
-	for (i = 0; i < GPMC_NR_IRQ; i++) {
-		gpmc_client_irq[i].irq = gpmc_irq_start + i;
-		irq_set_chip_and_handler(gpmc_client_irq[i].irq,
-					&gpmc_irq_chip, handle_simple_irq);
-		set_irq_flags(gpmc_client_irq[i].irq,
-				IRQF_VALID | IRQF_NOAUTOEN);
-	}
-
-	/* Disable interrupts */
-	gpmc_write_reg(GPMC_IRQENABLE, 0);
-
-	/* clear interrupts */
-	regval = gpmc_read_reg(GPMC_IRQSTATUS);
-	gpmc_write_reg(GPMC_IRQSTATUS, regval);
-
-	return request_irq(gpmc_irq, gpmc_handle_irq, 0, "gpmc", NULL);
-}
-
-static int gpmc_free_irq(void)
+int gpmc_get_irq(void)
 {
-	int i;
-
-	if (gpmc_irq)
-		free_irq(gpmc_irq, NULL);
-
-	for (i = 0; i < GPMC_NR_IRQ; i++) {
-		irq_set_handler(gpmc_client_irq[i].irq, NULL);
-		irq_set_chip(gpmc_client_irq[i].irq, &no_irq_chip);
-		irq_modify_status(gpmc_client_irq[i].irq, 0, 0);
-	}
-
-	irq_free_descs(gpmc_irq_start, GPMC_NR_IRQ);
-
-	return 0;
+	return gpmc_irq;
 }
 
 static void gpmc_mem_exit(void)
@@ -1646,10 +1521,12 @@ static int gpmc_probe(struct platform_device *pdev)
 		return PTR_ERR(gpmc_base);
 
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-	if (res == NULL)
-		dev_warn(&pdev->dev, "Failed to get resource: irq\n");
-	else
-		gpmc_irq = res->start;
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get resource: irq\n");
+		return -EINVAL;
+	}
+
+	gpmc_irq = res->start;
 
 	gpmc_l3_clk = clk_get(&pdev->dev, "fck");
 	if (IS_ERR(gpmc_l3_clk)) {
@@ -1686,9 +1563,6 @@ static int gpmc_probe(struct platform_device *pdev)
 
 	gpmc_mem_init();
 
-	if (gpmc_setup_irq() < 0)
-		dev_warn(gpmc_dev, "gpmc_setup_irq failed\n");
-
 	/* Now the GPMC is initialised, unreserve the chip-selects */
 	gpmc_cs_map = 0;
 
@@ -1710,7 +1584,6 @@ static int gpmc_probe(struct platform_device *pdev)
 
 static int gpmc_remove(struct platform_device *pdev)
 {
-	gpmc_free_irq();
 	gpmc_mem_exit();
 	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
@@ -1787,25 +1660,6 @@ static int __init omap_gpmc_init(void)
 }
 omap_postcore_initcall(omap_gpmc_init);
 
-static irqreturn_t gpmc_handle_irq(int irq, void *dev)
-{
-	int i;
-	u32 regval;
-
-	regval = gpmc_read_reg(GPMC_IRQSTATUS);
-
-	if (!regval)
-		return IRQ_NONE;
-
-	for (i = 0; i < GPMC_NR_IRQ; i++)
-		if (regval & gpmc_client_irq[i].bitmask)
-			generic_handle_irq(gpmc_client_irq[i].irq);
-
-	gpmc_write_reg(GPMC_IRQSTATUS, regval);
-
-	return IRQ_HANDLED;
-}
-
 static struct omap3_gpmc_regs gpmc_context;
 
 void omap3_gpmc_save_context(void)
diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h
index 13554e7..a558ebd 100644
--- a/arch/arm/mach-omap2/gpmc.h
+++ b/arch/arm/mach-omap2/gpmc.h
@@ -26,14 +26,8 @@
 #define GPMC_CS_NAND_DATA	0x24
 
 /* Control Commands */
-#define GPMC_CONFIG_RDY_BSY	0x00000001
-#define GPMC_CONFIG_DEV_SIZE	0x00000002
-#define GPMC_CONFIG_DEV_TYPE	0x00000003
-#define GPMC_SET_IRQ_STATUS	0x00000004
 #define GPMC_CONFIG_WP		0x00000005
 
-#define GPMC_ENABLE_IRQ		0x0000000d
-
 /* ECC commands */
 #define GPMC_ECC_READ		0 /* Reset Hardware ECC for read */
 #define GPMC_ECC_WRITE		1 /* Reset Hardware ECC for write */
@@ -76,7 +70,7 @@ extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
 			     struct gpmc_device_timings *dev_t);
 
 extern void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs);
-extern int gpmc_get_client_irq(unsigned irq_config);
+int gpmc_get_irq(void);
 
 extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);
 
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 1ff49b8..8de1660 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -136,6 +136,10 @@
 
 #define BADBLOCK_MARKER_LENGTH		2
 
+/* GPMC IRQ REGISTER bits */
+#define GPMC_IRQ_FIFOEVENT	BIT(0)
+#define GPMC_IRQ_TERMCOUNT	BIT(1)
+
 #ifdef CONFIG_MTD_NAND_OMAP_BCH
 static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc,
 	0xac, 0x6b, 0xff, 0x99, 0x7b};
@@ -157,8 +161,7 @@ struct omap_nand_info {
 	enum omap_ecc			ecc_opt;
 	struct completion		comp;
 	struct dma_chan			*dma;
-	int				gpmc_irq_fifo;
-	int				gpmc_irq_count;
+	int				gpmc_irq;
 	enum {
 		OMAP_NAND_IO_READ = 0,	/* read */
 		OMAP_NAND_IO_WRITE,	/* write */
@@ -572,12 +575,16 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev)
 {
 	struct omap_nand_info *info = (struct omap_nand_info *) dev;
 	u32 bytes;
+	u32 irqstatus;
+	u32 irqenable;
+
+	irqstatus = readl(info->reg.gpmc_irqstatus);
 
 	bytes = readl(info->reg.gpmc_prefetch_status);
 	bytes = PREFETCH_STATUS_FIFO_CNT(bytes);
 	bytes = bytes  & 0xFFFC; /* io in multiple of 4 bytes */
 	if (info->iomode == OMAP_NAND_IO_WRITE) { /* checks for write io */
-		if (this_irq == info->gpmc_irq_count)
+		if (irqstatus & GPMC_IRQ_TERMCOUNT)
 			goto done;
 
 		if (info->buf_len && (info->buf_len < bytes))
@@ -594,17 +601,27 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev)
 						(u32 *)info->buf, bytes >> 2);
 		info->buf = info->buf + bytes;
 
-		if (this_irq == info->gpmc_irq_count)
+		if (irqstatus & GPMC_IRQ_TERMCOUNT)
 			goto done;
 	}
 
+	/* Clear FIFOEVENT STATUS */
+	irqstatus &= ~GPMC_IRQ_FIFOEVENT;
+	writel(irqstatus, info->reg.gpmc_irqstatus);
+
 	return IRQ_HANDLED;
 
 done:
 	complete(&info->comp);
 
-	disable_irq_nosync(info->gpmc_irq_fifo);
-	disable_irq_nosync(info->gpmc_irq_count);
+	/* Clear FIFOEVENT and TERMCOUNT STATUS */
+	irqstatus &= ~(GPMC_IRQ_TERMCOUNT | GPMC_IRQ_FIFOEVENT);
+	writel(irqstatus, info->reg.gpmc_irqstatus);
+
+	/* Disable Interrupt generation */
+	irqenable = readl(info->reg.gpmc_irqenable);
+	irqenable &= ~(GPMC_IRQ_TERMCOUNT | GPMC_IRQ_FIFOEVENT);
+	writel(irqenable, info->reg.gpmc_irqenable);
 
 	return IRQ_HANDLED;
 }
@@ -620,6 +637,7 @@ static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)
 	struct omap_nand_info *info = container_of(mtd,
 						struct omap_nand_info, mtd);
 	int ret = 0;
+	u32 irqenable;
 
 	if (len <= mtd->oobsize) {
 		omap_read_buf_pref(mtd, buf, len);
@@ -639,8 +657,10 @@ static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)
 
 	info->buf_len = len;
 
-	enable_irq(info->gpmc_irq_count);
-	enable_irq(info->gpmc_irq_fifo);
+	/* Enable Interrupt generation */
+	irqenable = readl(info->reg.gpmc_irqenable);
+	irqenable |= (GPMC_IRQ_FIFOEVENT | GPMC_IRQ_TERMCOUNT);
+	writel(irqenable, info->reg.gpmc_irqenable);
 
 	/* waiting for read to complete */
 	wait_for_completion(&info->comp);
@@ -670,6 +690,7 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd,
 	int ret = 0;
 	unsigned long tim, limit;
 	u32 val;
+	u32 irqenable;
 
 	if (len <= mtd->oobsize) {
 		omap_write_buf_pref(mtd, buf, len);
@@ -689,8 +710,10 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd,
 
 	info->buf_len = len;
 
-	enable_irq(info->gpmc_irq_count);
-	enable_irq(info->gpmc_irq_fifo);
+	/* Enable Interrupt generation */
+	irqenable = readl(info->reg.gpmc_irqenable);
+	irqenable |= (GPMC_IRQ_FIFOEVENT | GPMC_IRQ_TERMCOUNT);
+	writel(irqenable, info->reg.gpmc_irqenable);
 
 	/* waiting for write to complete */
 	wait_for_completion(&info->comp);
@@ -1689,35 +1712,18 @@ static int omap_nand_probe(struct platform_device *pdev)
 		break;
 
 	case NAND_OMAP_PREFETCH_IRQ:
-		info->gpmc_irq_fifo = platform_get_irq(pdev, 0);
-		if (info->gpmc_irq_fifo <= 0) {
-			dev_err(&pdev->dev, "error getting fifo irq\n");
-			err = -ENODEV;
-			goto return_error;
-		}
-		err = devm_request_irq(&pdev->dev, info->gpmc_irq_fifo,
-					omap_nand_irq, IRQF_SHARED,
-					"gpmc-nand-fifo", info);
-		if (err) {
-			dev_err(&pdev->dev, "requesting irq(%d) error:%d",
-						info->gpmc_irq_fifo, err);
-			info->gpmc_irq_fifo = 0;
-			goto return_error;
-		}
-
-		info->gpmc_irq_count = platform_get_irq(pdev, 1);
-		if (info->gpmc_irq_count <= 0) {
-			dev_err(&pdev->dev, "error getting count irq\n");
-			err = -ENODEV;
+		info->gpmc_irq = platform_get_irq(pdev, 0);
+		if (info->gpmc_irq < 0) {
+			dev_err(&pdev->dev, "error getting GPMC irq\n");
+			err = info->gpmc_irq;
 			goto return_error;
 		}
-		err = devm_request_irq(&pdev->dev, info->gpmc_irq_count,
-					omap_nand_irq, IRQF_SHARED,
-					"gpmc-nand-count", info);
+		err = devm_request_irq(&pdev->dev, info->gpmc_irq,
+				       omap_nand_irq, IRQF_SHARED,
+				       DRIVER_NAME, info);
 		if (err) {
 			dev_err(&pdev->dev, "requesting irq(%d) error:%d",
-						info->gpmc_irq_count, err);
-			info->gpmc_irq_count = 0;
+				info->gpmc_irq, err);
 			goto return_error;
 		}
 
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h
index 3e9dd66..97c9852 100644
--- a/include/linux/platform_data/mtd-nand-omap2.h
+++ b/include/linux/platform_data/mtd-nand-omap2.h
@@ -35,6 +35,8 @@ enum omap_ecc {
 
 struct gpmc_nand_regs {
 	void __iomem	*gpmc_status;
+	void __iomem	*gpmc_irqstatus;
+	void __iomem	*gpmc_irqenable;
 	void __iomem	*gpmc_nand_command;
 	void __iomem	*gpmc_nand_address;
 	void __iomem	*gpmc_nand_data;
-- 
1.8.3.2


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

* [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Since the Interrupt Events are used only by the NAND driver,
there is no point in managing the Interrupt registers
in the GPMC driver and complicating it with irqchip modeling.

Let's manage the interrupt registers directly in the NAND driver
and get rid of irqchip model from GPMC driver.

Get rid of IRQ commands and unused commands from gpmc_configure() in
the GPMC driver.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-nand.c              |   8 +-
 arch/arm/mach-omap2/gpmc.c                   | 168 ++-------------------------
 arch/arm/mach-omap2/gpmc.h                   |   8 +-
 drivers/mtd/nand/omap2.c                     |  76 ++++++------
 include/linux/platform_data/mtd-nand-omap2.h |   2 +
 5 files changed, 56 insertions(+), 206 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index 4349e82..3e6420b 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -31,9 +31,6 @@ static struct resource gpmc_nand_resource[] = {
 	{
 		.flags		= IORESOURCE_IRQ,
 	},
-	{
-		.flags		= IORESOURCE_IRQ,
-	},
 };
 
 static struct platform_device gpmc_nand_device = {
@@ -110,10 +107,7 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 	gpmc_nand_resource[0].end = gpmc_nand_resource[0].start +
 							NAND_IO_SIZE - 1;
 
-	gpmc_nand_resource[1].start =
-				gpmc_get_client_irq(GPMC_IRQ_FIFOEVENTENABLE);
-	gpmc_nand_resource[2].start =
-				gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT);
+	gpmc_nand_resource[1].start = gpmc_get_irq();
 
 	if (gpmc_t) {
 		err = gpmc_cs_set_timings(gpmc_nand_data->cs, gpmc_t);
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 9fe8c94..2524541 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -111,15 +111,6 @@
 
 #define GPMC_NR_WAITPINS		4
 
-/* XXX: Only NAND irq has been considered,currently these are the only ones used
- */
-#define	GPMC_NR_IRQ		2
-
-struct gpmc_client_irq	{
-	unsigned		irq;
-	u32			bitmask;
-};
-
 /* Structure to save gpmc cs context */
 struct gpmc_cs_config {
 	u32 config1;
@@ -147,10 +138,6 @@ struct omap3_gpmc_regs {
 	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
 };
 
-static struct gpmc_client_irq gpmc_client_irq[GPMC_NR_IRQ];
-static struct irq_chip gpmc_irq_chip;
-static int gpmc_irq_start;
-
 static struct resource	gpmc_mem_root;
 static struct resource	gpmc_cs_mem[GPMC_CS_NUM];
 static DEFINE_SPINLOCK(gpmc_mem_lock);
@@ -159,15 +146,13 @@ static unsigned int gpmc_cs_map = ((1 << GPMC_CS_NUM) - 1);
 static unsigned int gpmc_cs_num = GPMC_CS_NUM;
 static unsigned int gpmc_nr_waitpins;
 static struct device *gpmc_dev;
-static int gpmc_irq;
+static int gpmc_irq = -EINVAL;
 static resource_size_t phys_base, mem_size;
 static unsigned gpmc_capability;
 static void __iomem *gpmc_base;
 
 static struct clk *gpmc_l3_clk;
 
-static irqreturn_t gpmc_handle_irq(int irq, void *dev);
-
 static void gpmc_write_reg(int idx, u32 val)
 {
 	__raw_writel(val, gpmc_base + idx);
@@ -622,14 +607,6 @@ int gpmc_configure(int cmd, int wval)
 	u32 regval;
 
 	switch (cmd) {
-	case GPMC_ENABLE_IRQ:
-		gpmc_write_reg(GPMC_IRQENABLE, wval);
-		break;
-
-	case GPMC_SET_IRQ_STATUS:
-		gpmc_write_reg(GPMC_IRQSTATUS, wval);
-		break;
-
 	case GPMC_CONFIG_WP:
 		regval = gpmc_read_reg(GPMC_CONFIG);
 		if (wval)
@@ -653,6 +630,8 @@ void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs)
 	int i;
 
 	reg->gpmc_status = gpmc_base + GPMC_STATUS;
+	reg->gpmc_irqstatus = gpmc_base + GPMC_IRQSTATUS;
+	reg->gpmc_irqenable = gpmc_base + GPMC_IRQENABLE;
 	reg->gpmc_nand_command = gpmc_base + GPMC_CS0_OFFSET +
 				GPMC_CS_NAND_COMMAND + GPMC_CS_SIZE * cs;
 	reg->gpmc_nand_address = gpmc_base + GPMC_CS0_OFFSET +
@@ -680,113 +659,9 @@ void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs)
 	}
 }
 
-int gpmc_get_client_irq(unsigned irq_config)
-{
-	int i;
-
-	if (hweight32(irq_config) > 1)
-		return 0;
-
-	for (i = 0; i < GPMC_NR_IRQ; i++)
-		if (gpmc_client_irq[i].bitmask & irq_config)
-			return gpmc_client_irq[i].irq;
-
-	return 0;
-}
-
-static int gpmc_irq_endis(unsigned irq, bool endis)
-{
-	int i;
-	u32 regval;
-
-	for (i = 0; i < GPMC_NR_IRQ; i++)
-		if (irq == gpmc_client_irq[i].irq) {
-			regval = gpmc_read_reg(GPMC_IRQENABLE);
-			if (endis)
-				regval |= gpmc_client_irq[i].bitmask;
-			else
-				regval &= ~gpmc_client_irq[i].bitmask;
-			gpmc_write_reg(GPMC_IRQENABLE, regval);
-			break;
-		}
-
-	return 0;
-}
-
-static void gpmc_irq_disable(struct irq_data *p)
-{
-	gpmc_irq_endis(p->irq, false);
-}
-
-static void gpmc_irq_enable(struct irq_data *p)
-{
-	gpmc_irq_endis(p->irq, true);
-}
-
-static void gpmc_irq_noop(struct irq_data *data) { }
-
-static unsigned int gpmc_irq_noop_ret(struct irq_data *data) { return 0; }
-
-static int gpmc_setup_irq(void)
-{
-	int i;
-	u32 regval;
-
-	if (!gpmc_irq)
-		return -EINVAL;
-
-	gpmc_irq_start = irq_alloc_descs(-1, 0, GPMC_NR_IRQ, 0);
-	if (gpmc_irq_start < 0) {
-		pr_err("irq_alloc_descs failed\n");
-		return gpmc_irq_start;
-	}
-
-	gpmc_irq_chip.name = "gpmc";
-	gpmc_irq_chip.irq_startup = gpmc_irq_noop_ret;
-	gpmc_irq_chip.irq_enable = gpmc_irq_enable;
-	gpmc_irq_chip.irq_disable = gpmc_irq_disable;
-	gpmc_irq_chip.irq_shutdown = gpmc_irq_noop;
-	gpmc_irq_chip.irq_ack = gpmc_irq_noop;
-	gpmc_irq_chip.irq_mask = gpmc_irq_noop;
-	gpmc_irq_chip.irq_unmask = gpmc_irq_noop;
-
-	gpmc_client_irq[0].bitmask = GPMC_IRQ_FIFOEVENTENABLE;
-	gpmc_client_irq[1].bitmask = GPMC_IRQ_COUNT_EVENT;
-
-	for (i = 0; i < GPMC_NR_IRQ; i++) {
-		gpmc_client_irq[i].irq = gpmc_irq_start + i;
-		irq_set_chip_and_handler(gpmc_client_irq[i].irq,
-					&gpmc_irq_chip, handle_simple_irq);
-		set_irq_flags(gpmc_client_irq[i].irq,
-				IRQF_VALID | IRQF_NOAUTOEN);
-	}
-
-	/* Disable interrupts */
-	gpmc_write_reg(GPMC_IRQENABLE, 0);
-
-	/* clear interrupts */
-	regval = gpmc_read_reg(GPMC_IRQSTATUS);
-	gpmc_write_reg(GPMC_IRQSTATUS, regval);
-
-	return request_irq(gpmc_irq, gpmc_handle_irq, 0, "gpmc", NULL);
-}
-
-static int gpmc_free_irq(void)
+int gpmc_get_irq(void)
 {
-	int i;
-
-	if (gpmc_irq)
-		free_irq(gpmc_irq, NULL);
-
-	for (i = 0; i < GPMC_NR_IRQ; i++) {
-		irq_set_handler(gpmc_client_irq[i].irq, NULL);
-		irq_set_chip(gpmc_client_irq[i].irq, &no_irq_chip);
-		irq_modify_status(gpmc_client_irq[i].irq, 0, 0);
-	}
-
-	irq_free_descs(gpmc_irq_start, GPMC_NR_IRQ);
-
-	return 0;
+	return gpmc_irq;
 }
 
 static void gpmc_mem_exit(void)
@@ -1646,10 +1521,12 @@ static int gpmc_probe(struct platform_device *pdev)
 		return PTR_ERR(gpmc_base);
 
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-	if (res == NULL)
-		dev_warn(&pdev->dev, "Failed to get resource: irq\n");
-	else
-		gpmc_irq = res->start;
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get resource: irq\n");
+		return -EINVAL;
+	}
+
+	gpmc_irq = res->start;
 
 	gpmc_l3_clk = clk_get(&pdev->dev, "fck");
 	if (IS_ERR(gpmc_l3_clk)) {
@@ -1686,9 +1563,6 @@ static int gpmc_probe(struct platform_device *pdev)
 
 	gpmc_mem_init();
 
-	if (gpmc_setup_irq() < 0)
-		dev_warn(gpmc_dev, "gpmc_setup_irq failed\n");
-
 	/* Now the GPMC is initialised, unreserve the chip-selects */
 	gpmc_cs_map = 0;
 
@@ -1710,7 +1584,6 @@ static int gpmc_probe(struct platform_device *pdev)
 
 static int gpmc_remove(struct platform_device *pdev)
 {
-	gpmc_free_irq();
 	gpmc_mem_exit();
 	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
@@ -1787,25 +1660,6 @@ static int __init omap_gpmc_init(void)
 }
 omap_postcore_initcall(omap_gpmc_init);
 
-static irqreturn_t gpmc_handle_irq(int irq, void *dev)
-{
-	int i;
-	u32 regval;
-
-	regval = gpmc_read_reg(GPMC_IRQSTATUS);
-
-	if (!regval)
-		return IRQ_NONE;
-
-	for (i = 0; i < GPMC_NR_IRQ; i++)
-		if (regval & gpmc_client_irq[i].bitmask)
-			generic_handle_irq(gpmc_client_irq[i].irq);
-
-	gpmc_write_reg(GPMC_IRQSTATUS, regval);
-
-	return IRQ_HANDLED;
-}
-
 static struct omap3_gpmc_regs gpmc_context;
 
 void omap3_gpmc_save_context(void)
diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h
index 13554e7..a558ebd 100644
--- a/arch/arm/mach-omap2/gpmc.h
+++ b/arch/arm/mach-omap2/gpmc.h
@@ -26,14 +26,8 @@
 #define GPMC_CS_NAND_DATA	0x24
 
 /* Control Commands */
-#define GPMC_CONFIG_RDY_BSY	0x00000001
-#define GPMC_CONFIG_DEV_SIZE	0x00000002
-#define GPMC_CONFIG_DEV_TYPE	0x00000003
-#define GPMC_SET_IRQ_STATUS	0x00000004
 #define GPMC_CONFIG_WP		0x00000005
 
-#define GPMC_ENABLE_IRQ		0x0000000d
-
 /* ECC commands */
 #define GPMC_ECC_READ		0 /* Reset Hardware ECC for read */
 #define GPMC_ECC_WRITE		1 /* Reset Hardware ECC for write */
@@ -76,7 +70,7 @@ extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
 			     struct gpmc_device_timings *dev_t);
 
 extern void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs);
-extern int gpmc_get_client_irq(unsigned irq_config);
+int gpmc_get_irq(void);
 
 extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);
 
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 1ff49b8..8de1660 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -136,6 +136,10 @@
 
 #define BADBLOCK_MARKER_LENGTH		2
 
+/* GPMC IRQ REGISTER bits */
+#define GPMC_IRQ_FIFOEVENT	BIT(0)
+#define GPMC_IRQ_TERMCOUNT	BIT(1)
+
 #ifdef CONFIG_MTD_NAND_OMAP_BCH
 static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc,
 	0xac, 0x6b, 0xff, 0x99, 0x7b};
@@ -157,8 +161,7 @@ struct omap_nand_info {
 	enum omap_ecc			ecc_opt;
 	struct completion		comp;
 	struct dma_chan			*dma;
-	int				gpmc_irq_fifo;
-	int				gpmc_irq_count;
+	int				gpmc_irq;
 	enum {
 		OMAP_NAND_IO_READ = 0,	/* read */
 		OMAP_NAND_IO_WRITE,	/* write */
@@ -572,12 +575,16 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev)
 {
 	struct omap_nand_info *info = (struct omap_nand_info *) dev;
 	u32 bytes;
+	u32 irqstatus;
+	u32 irqenable;
+
+	irqstatus = readl(info->reg.gpmc_irqstatus);
 
 	bytes = readl(info->reg.gpmc_prefetch_status);
 	bytes = PREFETCH_STATUS_FIFO_CNT(bytes);
 	bytes = bytes  & 0xFFFC; /* io in multiple of 4 bytes */
 	if (info->iomode == OMAP_NAND_IO_WRITE) { /* checks for write io */
-		if (this_irq == info->gpmc_irq_count)
+		if (irqstatus & GPMC_IRQ_TERMCOUNT)
 			goto done;
 
 		if (info->buf_len && (info->buf_len < bytes))
@@ -594,17 +601,27 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev)
 						(u32 *)info->buf, bytes >> 2);
 		info->buf = info->buf + bytes;
 
-		if (this_irq == info->gpmc_irq_count)
+		if (irqstatus & GPMC_IRQ_TERMCOUNT)
 			goto done;
 	}
 
+	/* Clear FIFOEVENT STATUS */
+	irqstatus &= ~GPMC_IRQ_FIFOEVENT;
+	writel(irqstatus, info->reg.gpmc_irqstatus);
+
 	return IRQ_HANDLED;
 
 done:
 	complete(&info->comp);
 
-	disable_irq_nosync(info->gpmc_irq_fifo);
-	disable_irq_nosync(info->gpmc_irq_count);
+	/* Clear FIFOEVENT and TERMCOUNT STATUS */
+	irqstatus &= ~(GPMC_IRQ_TERMCOUNT | GPMC_IRQ_FIFOEVENT);
+	writel(irqstatus, info->reg.gpmc_irqstatus);
+
+	/* Disable Interrupt generation */
+	irqenable = readl(info->reg.gpmc_irqenable);
+	irqenable &= ~(GPMC_IRQ_TERMCOUNT | GPMC_IRQ_FIFOEVENT);
+	writel(irqenable, info->reg.gpmc_irqenable);
 
 	return IRQ_HANDLED;
 }
@@ -620,6 +637,7 @@ static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)
 	struct omap_nand_info *info = container_of(mtd,
 						struct omap_nand_info, mtd);
 	int ret = 0;
+	u32 irqenable;
 
 	if (len <= mtd->oobsize) {
 		omap_read_buf_pref(mtd, buf, len);
@@ -639,8 +657,10 @@ static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)
 
 	info->buf_len = len;
 
-	enable_irq(info->gpmc_irq_count);
-	enable_irq(info->gpmc_irq_fifo);
+	/* Enable Interrupt generation */
+	irqenable = readl(info->reg.gpmc_irqenable);
+	irqenable |= (GPMC_IRQ_FIFOEVENT | GPMC_IRQ_TERMCOUNT);
+	writel(irqenable, info->reg.gpmc_irqenable);
 
 	/* waiting for read to complete */
 	wait_for_completion(&info->comp);
@@ -670,6 +690,7 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd,
 	int ret = 0;
 	unsigned long tim, limit;
 	u32 val;
+	u32 irqenable;
 
 	if (len <= mtd->oobsize) {
 		omap_write_buf_pref(mtd, buf, len);
@@ -689,8 +710,10 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd,
 
 	info->buf_len = len;
 
-	enable_irq(info->gpmc_irq_count);
-	enable_irq(info->gpmc_irq_fifo);
+	/* Enable Interrupt generation */
+	irqenable = readl(info->reg.gpmc_irqenable);
+	irqenable |= (GPMC_IRQ_FIFOEVENT | GPMC_IRQ_TERMCOUNT);
+	writel(irqenable, info->reg.gpmc_irqenable);
 
 	/* waiting for write to complete */
 	wait_for_completion(&info->comp);
@@ -1689,35 +1712,18 @@ static int omap_nand_probe(struct platform_device *pdev)
 		break;
 
 	case NAND_OMAP_PREFETCH_IRQ:
-		info->gpmc_irq_fifo = platform_get_irq(pdev, 0);
-		if (info->gpmc_irq_fifo <= 0) {
-			dev_err(&pdev->dev, "error getting fifo irq\n");
-			err = -ENODEV;
-			goto return_error;
-		}
-		err = devm_request_irq(&pdev->dev, info->gpmc_irq_fifo,
-					omap_nand_irq, IRQF_SHARED,
-					"gpmc-nand-fifo", info);
-		if (err) {
-			dev_err(&pdev->dev, "requesting irq(%d) error:%d",
-						info->gpmc_irq_fifo, err);
-			info->gpmc_irq_fifo = 0;
-			goto return_error;
-		}
-
-		info->gpmc_irq_count = platform_get_irq(pdev, 1);
-		if (info->gpmc_irq_count <= 0) {
-			dev_err(&pdev->dev, "error getting count irq\n");
-			err = -ENODEV;
+		info->gpmc_irq = platform_get_irq(pdev, 0);
+		if (info->gpmc_irq < 0) {
+			dev_err(&pdev->dev, "error getting GPMC irq\n");
+			err = info->gpmc_irq;
 			goto return_error;
 		}
-		err = devm_request_irq(&pdev->dev, info->gpmc_irq_count,
-					omap_nand_irq, IRQF_SHARED,
-					"gpmc-nand-count", info);
+		err = devm_request_irq(&pdev->dev, info->gpmc_irq,
+				       omap_nand_irq, IRQF_SHARED,
+				       DRIVER_NAME, info);
 		if (err) {
 			dev_err(&pdev->dev, "requesting irq(%d) error:%d",
-						info->gpmc_irq_count, err);
-			info->gpmc_irq_count = 0;
+				info->gpmc_irq, err);
 			goto return_error;
 		}
 
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h
index 3e9dd66..97c9852 100644
--- a/include/linux/platform_data/mtd-nand-omap2.h
+++ b/include/linux/platform_data/mtd-nand-omap2.h
@@ -35,6 +35,8 @@ enum omap_ecc {
 
 struct gpmc_nand_regs {
 	void __iomem	*gpmc_status;
+	void __iomem	*gpmc_irqstatus;
+	void __iomem	*gpmc_irqenable;
 	void __iomem	*gpmc_nand_command;
 	void __iomem	*gpmc_nand_address;
 	void __iomem	*gpmc_nand_data;
-- 
1.8.3.2


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

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

* [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Since the Interrupt Events are used only by the NAND driver,
there is no point in managing the Interrupt registers
in the GPMC driver and complicating it with irqchip modeling.

Let's manage the interrupt registers directly in the NAND driver
and get rid of irqchip model from GPMC driver.

Get rid of IRQ commands and unused commands from gpmc_configure() in
the GPMC driver.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-nand.c              |   8 +-
 arch/arm/mach-omap2/gpmc.c                   | 168 ++-------------------------
 arch/arm/mach-omap2/gpmc.h                   |   8 +-
 drivers/mtd/nand/omap2.c                     |  76 ++++++------
 include/linux/platform_data/mtd-nand-omap2.h |   2 +
 5 files changed, 56 insertions(+), 206 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index 4349e82..3e6420b 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -31,9 +31,6 @@ static struct resource gpmc_nand_resource[] = {
 	{
 		.flags		= IORESOURCE_IRQ,
 	},
-	{
-		.flags		= IORESOURCE_IRQ,
-	},
 };
 
 static struct platform_device gpmc_nand_device = {
@@ -110,10 +107,7 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 	gpmc_nand_resource[0].end = gpmc_nand_resource[0].start +
 							NAND_IO_SIZE - 1;
 
-	gpmc_nand_resource[1].start =
-				gpmc_get_client_irq(GPMC_IRQ_FIFOEVENTENABLE);
-	gpmc_nand_resource[2].start =
-				gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT);
+	gpmc_nand_resource[1].start = gpmc_get_irq();
 
 	if (gpmc_t) {
 		err = gpmc_cs_set_timings(gpmc_nand_data->cs, gpmc_t);
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 9fe8c94..2524541 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -111,15 +111,6 @@
 
 #define GPMC_NR_WAITPINS		4
 
-/* XXX: Only NAND irq has been considered,currently these are the only ones used
- */
-#define	GPMC_NR_IRQ		2
-
-struct gpmc_client_irq	{
-	unsigned		irq;
-	u32			bitmask;
-};
-
 /* Structure to save gpmc cs context */
 struct gpmc_cs_config {
 	u32 config1;
@@ -147,10 +138,6 @@ struct omap3_gpmc_regs {
 	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
 };
 
-static struct gpmc_client_irq gpmc_client_irq[GPMC_NR_IRQ];
-static struct irq_chip gpmc_irq_chip;
-static int gpmc_irq_start;
-
 static struct resource	gpmc_mem_root;
 static struct resource	gpmc_cs_mem[GPMC_CS_NUM];
 static DEFINE_SPINLOCK(gpmc_mem_lock);
@@ -159,15 +146,13 @@ static unsigned int gpmc_cs_map = ((1 << GPMC_CS_NUM) - 1);
 static unsigned int gpmc_cs_num = GPMC_CS_NUM;
 static unsigned int gpmc_nr_waitpins;
 static struct device *gpmc_dev;
-static int gpmc_irq;
+static int gpmc_irq = -EINVAL;
 static resource_size_t phys_base, mem_size;
 static unsigned gpmc_capability;
 static void __iomem *gpmc_base;
 
 static struct clk *gpmc_l3_clk;
 
-static irqreturn_t gpmc_handle_irq(int irq, void *dev);
-
 static void gpmc_write_reg(int idx, u32 val)
 {
 	__raw_writel(val, gpmc_base + idx);
@@ -622,14 +607,6 @@ int gpmc_configure(int cmd, int wval)
 	u32 regval;
 
 	switch (cmd) {
-	case GPMC_ENABLE_IRQ:
-		gpmc_write_reg(GPMC_IRQENABLE, wval);
-		break;
-
-	case GPMC_SET_IRQ_STATUS:
-		gpmc_write_reg(GPMC_IRQSTATUS, wval);
-		break;
-
 	case GPMC_CONFIG_WP:
 		regval = gpmc_read_reg(GPMC_CONFIG);
 		if (wval)
@@ -653,6 +630,8 @@ void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs)
 	int i;
 
 	reg->gpmc_status = gpmc_base + GPMC_STATUS;
+	reg->gpmc_irqstatus = gpmc_base + GPMC_IRQSTATUS;
+	reg->gpmc_irqenable = gpmc_base + GPMC_IRQENABLE;
 	reg->gpmc_nand_command = gpmc_base + GPMC_CS0_OFFSET +
 				GPMC_CS_NAND_COMMAND + GPMC_CS_SIZE * cs;
 	reg->gpmc_nand_address = gpmc_base + GPMC_CS0_OFFSET +
@@ -680,113 +659,9 @@ void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs)
 	}
 }
 
-int gpmc_get_client_irq(unsigned irq_config)
-{
-	int i;
-
-	if (hweight32(irq_config) > 1)
-		return 0;
-
-	for (i = 0; i < GPMC_NR_IRQ; i++)
-		if (gpmc_client_irq[i].bitmask & irq_config)
-			return gpmc_client_irq[i].irq;
-
-	return 0;
-}
-
-static int gpmc_irq_endis(unsigned irq, bool endis)
-{
-	int i;
-	u32 regval;
-
-	for (i = 0; i < GPMC_NR_IRQ; i++)
-		if (irq == gpmc_client_irq[i].irq) {
-			regval = gpmc_read_reg(GPMC_IRQENABLE);
-			if (endis)
-				regval |= gpmc_client_irq[i].bitmask;
-			else
-				regval &= ~gpmc_client_irq[i].bitmask;
-			gpmc_write_reg(GPMC_IRQENABLE, regval);
-			break;
-		}
-
-	return 0;
-}
-
-static void gpmc_irq_disable(struct irq_data *p)
-{
-	gpmc_irq_endis(p->irq, false);
-}
-
-static void gpmc_irq_enable(struct irq_data *p)
-{
-	gpmc_irq_endis(p->irq, true);
-}
-
-static void gpmc_irq_noop(struct irq_data *data) { }
-
-static unsigned int gpmc_irq_noop_ret(struct irq_data *data) { return 0; }
-
-static int gpmc_setup_irq(void)
-{
-	int i;
-	u32 regval;
-
-	if (!gpmc_irq)
-		return -EINVAL;
-
-	gpmc_irq_start = irq_alloc_descs(-1, 0, GPMC_NR_IRQ, 0);
-	if (gpmc_irq_start < 0) {
-		pr_err("irq_alloc_descs failed\n");
-		return gpmc_irq_start;
-	}
-
-	gpmc_irq_chip.name = "gpmc";
-	gpmc_irq_chip.irq_startup = gpmc_irq_noop_ret;
-	gpmc_irq_chip.irq_enable = gpmc_irq_enable;
-	gpmc_irq_chip.irq_disable = gpmc_irq_disable;
-	gpmc_irq_chip.irq_shutdown = gpmc_irq_noop;
-	gpmc_irq_chip.irq_ack = gpmc_irq_noop;
-	gpmc_irq_chip.irq_mask = gpmc_irq_noop;
-	gpmc_irq_chip.irq_unmask = gpmc_irq_noop;
-
-	gpmc_client_irq[0].bitmask = GPMC_IRQ_FIFOEVENTENABLE;
-	gpmc_client_irq[1].bitmask = GPMC_IRQ_COUNT_EVENT;
-
-	for (i = 0; i < GPMC_NR_IRQ; i++) {
-		gpmc_client_irq[i].irq = gpmc_irq_start + i;
-		irq_set_chip_and_handler(gpmc_client_irq[i].irq,
-					&gpmc_irq_chip, handle_simple_irq);
-		set_irq_flags(gpmc_client_irq[i].irq,
-				IRQF_VALID | IRQF_NOAUTOEN);
-	}
-
-	/* Disable interrupts */
-	gpmc_write_reg(GPMC_IRQENABLE, 0);
-
-	/* clear interrupts */
-	regval = gpmc_read_reg(GPMC_IRQSTATUS);
-	gpmc_write_reg(GPMC_IRQSTATUS, regval);
-
-	return request_irq(gpmc_irq, gpmc_handle_irq, 0, "gpmc", NULL);
-}
-
-static int gpmc_free_irq(void)
+int gpmc_get_irq(void)
 {
-	int i;
-
-	if (gpmc_irq)
-		free_irq(gpmc_irq, NULL);
-
-	for (i = 0; i < GPMC_NR_IRQ; i++) {
-		irq_set_handler(gpmc_client_irq[i].irq, NULL);
-		irq_set_chip(gpmc_client_irq[i].irq, &no_irq_chip);
-		irq_modify_status(gpmc_client_irq[i].irq, 0, 0);
-	}
-
-	irq_free_descs(gpmc_irq_start, GPMC_NR_IRQ);
-
-	return 0;
+	return gpmc_irq;
 }
 
 static void gpmc_mem_exit(void)
@@ -1646,10 +1521,12 @@ static int gpmc_probe(struct platform_device *pdev)
 		return PTR_ERR(gpmc_base);
 
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-	if (res == NULL)
-		dev_warn(&pdev->dev, "Failed to get resource: irq\n");
-	else
-		gpmc_irq = res->start;
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get resource: irq\n");
+		return -EINVAL;
+	}
+
+	gpmc_irq = res->start;
 
 	gpmc_l3_clk = clk_get(&pdev->dev, "fck");
 	if (IS_ERR(gpmc_l3_clk)) {
@@ -1686,9 +1563,6 @@ static int gpmc_probe(struct platform_device *pdev)
 
 	gpmc_mem_init();
 
-	if (gpmc_setup_irq() < 0)
-		dev_warn(gpmc_dev, "gpmc_setup_irq failed\n");
-
 	/* Now the GPMC is initialised, unreserve the chip-selects */
 	gpmc_cs_map = 0;
 
@@ -1710,7 +1584,6 @@ static int gpmc_probe(struct platform_device *pdev)
 
 static int gpmc_remove(struct platform_device *pdev)
 {
-	gpmc_free_irq();
 	gpmc_mem_exit();
 	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
@@ -1787,25 +1660,6 @@ static int __init omap_gpmc_init(void)
 }
 omap_postcore_initcall(omap_gpmc_init);
 
-static irqreturn_t gpmc_handle_irq(int irq, void *dev)
-{
-	int i;
-	u32 regval;
-
-	regval = gpmc_read_reg(GPMC_IRQSTATUS);
-
-	if (!regval)
-		return IRQ_NONE;
-
-	for (i = 0; i < GPMC_NR_IRQ; i++)
-		if (regval & gpmc_client_irq[i].bitmask)
-			generic_handle_irq(gpmc_client_irq[i].irq);
-
-	gpmc_write_reg(GPMC_IRQSTATUS, regval);
-
-	return IRQ_HANDLED;
-}
-
 static struct omap3_gpmc_regs gpmc_context;
 
 void omap3_gpmc_save_context(void)
diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h
index 13554e7..a558ebd 100644
--- a/arch/arm/mach-omap2/gpmc.h
+++ b/arch/arm/mach-omap2/gpmc.h
@@ -26,14 +26,8 @@
 #define GPMC_CS_NAND_DATA	0x24
 
 /* Control Commands */
-#define GPMC_CONFIG_RDY_BSY	0x00000001
-#define GPMC_CONFIG_DEV_SIZE	0x00000002
-#define GPMC_CONFIG_DEV_TYPE	0x00000003
-#define GPMC_SET_IRQ_STATUS	0x00000004
 #define GPMC_CONFIG_WP		0x00000005
 
-#define GPMC_ENABLE_IRQ		0x0000000d
-
 /* ECC commands */
 #define GPMC_ECC_READ		0 /* Reset Hardware ECC for read */
 #define GPMC_ECC_WRITE		1 /* Reset Hardware ECC for write */
@@ -76,7 +70,7 @@ extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
 			     struct gpmc_device_timings *dev_t);
 
 extern void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs);
-extern int gpmc_get_client_irq(unsigned irq_config);
+int gpmc_get_irq(void);
 
 extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);
 
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 1ff49b8..8de1660 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -136,6 +136,10 @@
 
 #define BADBLOCK_MARKER_LENGTH		2
 
+/* GPMC IRQ REGISTER bits */
+#define GPMC_IRQ_FIFOEVENT	BIT(0)
+#define GPMC_IRQ_TERMCOUNT	BIT(1)
+
 #ifdef CONFIG_MTD_NAND_OMAP_BCH
 static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc,
 	0xac, 0x6b, 0xff, 0x99, 0x7b};
@@ -157,8 +161,7 @@ struct omap_nand_info {
 	enum omap_ecc			ecc_opt;
 	struct completion		comp;
 	struct dma_chan			*dma;
-	int				gpmc_irq_fifo;
-	int				gpmc_irq_count;
+	int				gpmc_irq;
 	enum {
 		OMAP_NAND_IO_READ = 0,	/* read */
 		OMAP_NAND_IO_WRITE,	/* write */
@@ -572,12 +575,16 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev)
 {
 	struct omap_nand_info *info = (struct omap_nand_info *) dev;
 	u32 bytes;
+	u32 irqstatus;
+	u32 irqenable;
+
+	irqstatus = readl(info->reg.gpmc_irqstatus);
 
 	bytes = readl(info->reg.gpmc_prefetch_status);
 	bytes = PREFETCH_STATUS_FIFO_CNT(bytes);
 	bytes = bytes  & 0xFFFC; /* io in multiple of 4 bytes */
 	if (info->iomode == OMAP_NAND_IO_WRITE) { /* checks for write io */
-		if (this_irq == info->gpmc_irq_count)
+		if (irqstatus & GPMC_IRQ_TERMCOUNT)
 			goto done;
 
 		if (info->buf_len && (info->buf_len < bytes))
@@ -594,17 +601,27 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev)
 						(u32 *)info->buf, bytes >> 2);
 		info->buf = info->buf + bytes;
 
-		if (this_irq == info->gpmc_irq_count)
+		if (irqstatus & GPMC_IRQ_TERMCOUNT)
 			goto done;
 	}
 
+	/* Clear FIFOEVENT STATUS */
+	irqstatus &= ~GPMC_IRQ_FIFOEVENT;
+	writel(irqstatus, info->reg.gpmc_irqstatus);
+
 	return IRQ_HANDLED;
 
 done:
 	complete(&info->comp);
 
-	disable_irq_nosync(info->gpmc_irq_fifo);
-	disable_irq_nosync(info->gpmc_irq_count);
+	/* Clear FIFOEVENT and TERMCOUNT STATUS */
+	irqstatus &= ~(GPMC_IRQ_TERMCOUNT | GPMC_IRQ_FIFOEVENT);
+	writel(irqstatus, info->reg.gpmc_irqstatus);
+
+	/* Disable Interrupt generation */
+	irqenable = readl(info->reg.gpmc_irqenable);
+	irqenable &= ~(GPMC_IRQ_TERMCOUNT | GPMC_IRQ_FIFOEVENT);
+	writel(irqenable, info->reg.gpmc_irqenable);
 
 	return IRQ_HANDLED;
 }
@@ -620,6 +637,7 @@ static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)
 	struct omap_nand_info *info = container_of(mtd,
 						struct omap_nand_info, mtd);
 	int ret = 0;
+	u32 irqenable;
 
 	if (len <= mtd->oobsize) {
 		omap_read_buf_pref(mtd, buf, len);
@@ -639,8 +657,10 @@ static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)
 
 	info->buf_len = len;
 
-	enable_irq(info->gpmc_irq_count);
-	enable_irq(info->gpmc_irq_fifo);
+	/* Enable Interrupt generation */
+	irqenable = readl(info->reg.gpmc_irqenable);
+	irqenable |= (GPMC_IRQ_FIFOEVENT | GPMC_IRQ_TERMCOUNT);
+	writel(irqenable, info->reg.gpmc_irqenable);
 
 	/* waiting for read to complete */
 	wait_for_completion(&info->comp);
@@ -670,6 +690,7 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd,
 	int ret = 0;
 	unsigned long tim, limit;
 	u32 val;
+	u32 irqenable;
 
 	if (len <= mtd->oobsize) {
 		omap_write_buf_pref(mtd, buf, len);
@@ -689,8 +710,10 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd,
 
 	info->buf_len = len;
 
-	enable_irq(info->gpmc_irq_count);
-	enable_irq(info->gpmc_irq_fifo);
+	/* Enable Interrupt generation */
+	irqenable = readl(info->reg.gpmc_irqenable);
+	irqenable |= (GPMC_IRQ_FIFOEVENT | GPMC_IRQ_TERMCOUNT);
+	writel(irqenable, info->reg.gpmc_irqenable);
 
 	/* waiting for write to complete */
 	wait_for_completion(&info->comp);
@@ -1689,35 +1712,18 @@ static int omap_nand_probe(struct platform_device *pdev)
 		break;
 
 	case NAND_OMAP_PREFETCH_IRQ:
-		info->gpmc_irq_fifo = platform_get_irq(pdev, 0);
-		if (info->gpmc_irq_fifo <= 0) {
-			dev_err(&pdev->dev, "error getting fifo irq\n");
-			err = -ENODEV;
-			goto return_error;
-		}
-		err = devm_request_irq(&pdev->dev, info->gpmc_irq_fifo,
-					omap_nand_irq, IRQF_SHARED,
-					"gpmc-nand-fifo", info);
-		if (err) {
-			dev_err(&pdev->dev, "requesting irq(%d) error:%d",
-						info->gpmc_irq_fifo, err);
-			info->gpmc_irq_fifo = 0;
-			goto return_error;
-		}
-
-		info->gpmc_irq_count = platform_get_irq(pdev, 1);
-		if (info->gpmc_irq_count <= 0) {
-			dev_err(&pdev->dev, "error getting count irq\n");
-			err = -ENODEV;
+		info->gpmc_irq = platform_get_irq(pdev, 0);
+		if (info->gpmc_irq < 0) {
+			dev_err(&pdev->dev, "error getting GPMC irq\n");
+			err = info->gpmc_irq;
 			goto return_error;
 		}
-		err = devm_request_irq(&pdev->dev, info->gpmc_irq_count,
-					omap_nand_irq, IRQF_SHARED,
-					"gpmc-nand-count", info);
+		err = devm_request_irq(&pdev->dev, info->gpmc_irq,
+				       omap_nand_irq, IRQF_SHARED,
+				       DRIVER_NAME, info);
 		if (err) {
 			dev_err(&pdev->dev, "requesting irq(%d) error:%d",
-						info->gpmc_irq_count, err);
-			info->gpmc_irq_count = 0;
+				info->gpmc_irq, err);
 			goto return_error;
 		}
 
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h
index 3e9dd66..97c9852 100644
--- a/include/linux/platform_data/mtd-nand-omap2.h
+++ b/include/linux/platform_data/mtd-nand-omap2.h
@@ -35,6 +35,8 @@ enum omap_ecc {
 
 struct gpmc_nand_regs {
 	void __iomem	*gpmc_status;
+	void __iomem	*gpmc_irqstatus;
+	void __iomem	*gpmc_irqenable;
 	void __iomem	*gpmc_nand_command;
 	void __iomem	*gpmc_nand_address;
 	void __iomem	*gpmc_nand_data;
-- 
1.8.3.2

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

* [PATCH 06/36] mtd: nand: omap: Move gpmc_update_nand_reg to nand driver
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

GPMC and NAND drivers share the same register space but never use the
same registers. As there is no clear address seperation between the
registers for GPMC and NAND, we can't easily split it up into 2 regions
i.e. one for GPMC and other for NAND. Instead, we simply remap the entire
register space in both the drivers. The NAND driver doesn't re-request
the region as it is already requested by the GPMC driver (parent).

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-nand.c              |  16 +++-
 arch/arm/mach-omap2/gpmc.c                   |  34 +-------
 arch/arm/mach-omap2/gpmc.h                   |   5 +-
 drivers/mtd/nand/omap2.c                     | 123 ++++++++++++++++++++++++---
 include/linux/platform_data/mtd-nand-omap2.h |   3 +-
 5 files changed, 127 insertions(+), 54 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index 3e6420b..aaebd2f 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -26,11 +26,16 @@
 
 static struct resource gpmc_nand_resource[] = {
 	{
+		/* GPMC I/O space */
 		.flags		= IORESOURCE_MEM,
 	},
 	{
-		.flags		= IORESOURCE_IRQ,
+		/* GPMC register space */
+		.flags		= IORESOURCE_MEM,
 	},
+	{
+		.flags		= IORESOURCE_IRQ,
+	}
 };
 
 static struct platform_device gpmc_nand_device = {
@@ -91,6 +96,7 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 	int err	= 0;
 	struct gpmc_settings s;
 	struct device *dev = &gpmc_nand_device.dev;
+	struct resource res;
 
 	memset(&s, 0, sizeof(struct gpmc_settings));
 
@@ -107,7 +113,11 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 	gpmc_nand_resource[0].end = gpmc_nand_resource[0].start +
 							NAND_IO_SIZE - 1;
 
-	gpmc_nand_resource[1].start = gpmc_get_irq();
+	gpmc_get_mem_resource(&res);
+	gpmc_nand_resource[1].start = res.start;
+	gpmc_nand_resource[1].end = res.end;
+
+	gpmc_nand_resource[2].start = gpmc_get_irq();
 
 	if (gpmc_t) {
 		err = gpmc_cs_set_timings(gpmc_nand_data->cs, gpmc_t);
@@ -132,8 +142,6 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 	if (err < 0)
 		goto out_free_cs;
 
-	gpmc_update_nand_reg(&gpmc_nand_data->reg, gpmc_nand_data->cs);
-
 	if (!gpmc_hwecc_bch_capable(gpmc_nand_data->ecc_opt)) {
 		dev_err(dev, "Unsupported NAND ECC scheme selected\n");
 		return -EINVAL;
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 2524541..0a8b6ca 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -625,38 +625,10 @@ int gpmc_configure(int cmd, int wval)
 }
 EXPORT_SYMBOL(gpmc_configure);
 
-void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs)
+void gpmc_get_mem_resource(struct resource *res)
 {
-	int i;
-
-	reg->gpmc_status = gpmc_base + GPMC_STATUS;
-	reg->gpmc_irqstatus = gpmc_base + GPMC_IRQSTATUS;
-	reg->gpmc_irqenable = gpmc_base + GPMC_IRQENABLE;
-	reg->gpmc_nand_command = gpmc_base + GPMC_CS0_OFFSET +
-				GPMC_CS_NAND_COMMAND + GPMC_CS_SIZE * cs;
-	reg->gpmc_nand_address = gpmc_base + GPMC_CS0_OFFSET +
-				GPMC_CS_NAND_ADDRESS + GPMC_CS_SIZE * cs;
-	reg->gpmc_nand_data = gpmc_base + GPMC_CS0_OFFSET +
-				GPMC_CS_NAND_DATA + GPMC_CS_SIZE * cs;
-	reg->gpmc_prefetch_config1 = gpmc_base + GPMC_PREFETCH_CONFIG1;
-	reg->gpmc_prefetch_config2 = gpmc_base + GPMC_PREFETCH_CONFIG2;
-	reg->gpmc_prefetch_control = gpmc_base + GPMC_PREFETCH_CONTROL;
-	reg->gpmc_prefetch_status = gpmc_base + GPMC_PREFETCH_STATUS;
-	reg->gpmc_ecc_config = gpmc_base + GPMC_ECC_CONFIG;
-	reg->gpmc_ecc_control = gpmc_base + GPMC_ECC_CONTROL;
-	reg->gpmc_ecc_size_config = gpmc_base + GPMC_ECC_SIZE_CONFIG;
-	reg->gpmc_ecc1_result = gpmc_base + GPMC_ECC1_RESULT;
-
-	for (i = 0; i < GPMC_BCH_NUM_REMAINDER; i++) {
-		reg->gpmc_bch_result0[i] = gpmc_base + GPMC_ECC_BCH_RESULT_0 +
-					   GPMC_BCH_SIZE * i;
-		reg->gpmc_bch_result1[i] = gpmc_base + GPMC_ECC_BCH_RESULT_1 +
-					   GPMC_BCH_SIZE * i;
-		reg->gpmc_bch_result2[i] = gpmc_base + GPMC_ECC_BCH_RESULT_2 +
-					   GPMC_BCH_SIZE * i;
-		reg->gpmc_bch_result3[i] = gpmc_base + GPMC_ECC_BCH_RESULT_3 +
-					   GPMC_BCH_SIZE * i;
-	}
+	res->start =  phys_base;
+	res->end = res->start + mem_size - 1;
 }
 
 int gpmc_get_irq(void)
diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h
index a558ebd..479ce84 100644
--- a/arch/arm/mach-omap2/gpmc.h
+++ b/arch/arm/mach-omap2/gpmc.h
@@ -21,9 +21,6 @@
 #define GPMC_CS_CONFIG5		0x10
 #define GPMC_CS_CONFIG6		0x14
 #define GPMC_CS_CONFIG7		0x18
-#define GPMC_CS_NAND_COMMAND	0x1c
-#define GPMC_CS_NAND_ADDRESS	0x20
-#define GPMC_CS_NAND_DATA	0x24
 
 /* Control Commands */
 #define GPMC_CONFIG_WP		0x00000005
@@ -69,7 +66,7 @@ extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
 			     struct gpmc_settings *gpmc_s,
 			     struct gpmc_device_timings *dev_t);
 
-extern void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs);
+void gpmc_get_mem_resource(struct resource *res);
 int gpmc_get_irq(void);
 
 extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 8de1660..120acee 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -140,6 +140,36 @@
 #define GPMC_IRQ_FIFOEVENT	BIT(0)
 #define GPMC_IRQ_TERMCOUNT	BIT(1)
 
+/* GPMC register offsets */
+#define GPMC_REVISION		0x00
+#define GPMC_SYSCONFIG		0x10
+#define GPMC_SYSSTATUS		0x14
+#define GPMC_IRQSTATUS		0x18
+#define GPMC_IRQENABLE		0x1c
+#define GPMC_TIMEOUT_CONTROL	0x40
+#define GPMC_ERR_ADDRESS	0x44
+#define GPMC_ERR_TYPE		0x48
+#define GPMC_CONFIG		0x50
+#define GPMC_STATUS		0x54
+#define GPMC_CS_NAND_COMMAND	0x7c
+#define GPMC_CS_NAND_ADDRESS	0x80
+#define GPMC_CS_NAND_DATA	0x84
+#define GPMC_PREFETCH_CONFIG1	0x1e0
+#define GPMC_PREFETCH_CONFIG2	0x1e4
+#define GPMC_PREFETCH_CONTROL	0x1ec
+#define GPMC_PREFETCH_STATUS	0x1f0
+#define GPMC_ECC_CONFIG		0x1f4
+#define GPMC_ECC_CONTROL	0x1f8
+#define GPMC_ECC_SIZE_CONFIG	0x1fc
+#define GPMC_ECC1_RESULT        0x200
+#define GPMC_ECC_BCH_RESULT_0   0x240   /* not available on OMAP2 */
+#define	GPMC_ECC_BCH_RESULT_1	0x244	/* not available on OMAP2 */
+#define	GPMC_ECC_BCH_RESULT_2	0x248	/* not available on OMAP2 */
+#define	GPMC_ECC_BCH_RESULT_3	0x24c	/* not available on OMAP2 */
+
+#define GPMC_CS_SIZE		0x30
+#define	GPMC_BCH_SIZE		0x10
+
 #ifdef CONFIG_MTD_NAND_OMAP_BCH
 static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc,
 	0xac, 0x6b, 0xff, 0x99, 0x7b};
@@ -158,6 +188,7 @@ struct omap_nand_info {
 
 	int				gpmc_cs;
 	unsigned long			phys_base;
+	void __iomem			*gpmc_base;
 	enum omap_ecc			ecc_opt;
 	struct completion		comp;
 	struct dma_chan			*dma;
@@ -1584,20 +1615,58 @@ static int is_elm_present(struct omap_nand_info *info,
 }
 #endif /* CONFIG_MTD_NAND_ECC_BCH */
 
+static void gpmc_update_nand_reg(struct omap_nand_info *info)
+{
+	int i;
+	struct gpmc_nand_regs *reg = &info->reg;
+	int cs = info->gpmc_cs;
+	void __iomem *gpmc_base = info->gpmc_base;
+
+	reg->gpmc_status = gpmc_base + GPMC_STATUS;
+	reg->gpmc_irqstatus = gpmc_base + GPMC_IRQSTATUS;
+	reg->gpmc_irqenable = gpmc_base + GPMC_IRQENABLE;
+	reg->gpmc_nand_command = gpmc_base + GPMC_CS_NAND_COMMAND +
+				 GPMC_CS_SIZE * cs;
+	reg->gpmc_nand_address = gpmc_base + GPMC_CS_NAND_ADDRESS +
+				 GPMC_CS_SIZE * cs;
+	reg->gpmc_nand_data = gpmc_base + GPMC_CS_NAND_DATA +
+				 GPMC_CS_SIZE * cs;
+	reg->gpmc_prefetch_config1 = gpmc_base + GPMC_PREFETCH_CONFIG1;
+	reg->gpmc_prefetch_config2 = gpmc_base + GPMC_PREFETCH_CONFIG2;
+	reg->gpmc_prefetch_control = gpmc_base + GPMC_PREFETCH_CONTROL;
+	reg->gpmc_prefetch_status = gpmc_base + GPMC_PREFETCH_STATUS;
+	reg->gpmc_ecc_config = gpmc_base + GPMC_ECC_CONFIG;
+	reg->gpmc_ecc_control = gpmc_base + GPMC_ECC_CONTROL;
+	reg->gpmc_ecc_size_config = gpmc_base + GPMC_ECC_SIZE_CONFIG;
+	reg->gpmc_ecc1_result = gpmc_base + GPMC_ECC1_RESULT;
+
+	for (i = 0; i < GPMC_BCH_NUM_REMAINDER; i++) {
+		reg->gpmc_bch_result0[i] = gpmc_base + GPMC_ECC_BCH_RESULT_0 +
+					   GPMC_BCH_SIZE * i;
+		reg->gpmc_bch_result1[i] = gpmc_base + GPMC_ECC_BCH_RESULT_1 +
+					   GPMC_BCH_SIZE * i;
+		reg->gpmc_bch_result2[i] = gpmc_base + GPMC_ECC_BCH_RESULT_2 +
+					   GPMC_BCH_SIZE * i;
+		reg->gpmc_bch_result3[i] = gpmc_base + GPMC_ECC_BCH_RESULT_3 +
+					   GPMC_BCH_SIZE * i;
+	}
+}
+
 static int omap_nand_probe(struct platform_device *pdev)
 {
-	struct omap_nand_info		*info;
-	struct omap_nand_platform_data	*pdata;
-	struct mtd_info			*mtd;
-	struct nand_chip		*nand_chip;
-	struct nand_ecclayout		*ecclayout;
-	int				err;
-	int				i;
-	dma_cap_mask_t			mask;
-	unsigned			sig;
-	unsigned			oob_index;
-	struct resource			*res;
-	struct mtd_part_parser_data	ppdata = {};
+	struct omap_nand_info *info;
+	struct omap_nand_platform_data *pdata;
+	struct mtd_info	*mtd;
+	struct nand_chip *nand_chip;
+	struct nand_ecclayout *ecclayout;
+	int err;
+	int i;
+	dma_cap_mask_t mask;
+	unsigned sig;
+	unsigned oob_index;
+	struct resource	*res;
+	struct mtd_part_parser_data ppdata = {};
+	struct device *dev = &pdev->dev;
 
 	pdata = dev_get_platdata(&pdev->dev);
 	if (pdata == NULL) {
@@ -1617,7 +1686,6 @@ static int omap_nand_probe(struct platform_device *pdev)
 
 	info->pdev		= pdev;
 	info->gpmc_cs		= pdata->cs;
-	info->reg		= pdata->reg;
 	info->of_node		= pdata->of_node;
 	info->ecc_opt		= pdata->ecc_opt;
 	mtd			= &info->mtd;
@@ -1628,8 +1696,14 @@ static int omap_nand_probe(struct platform_device *pdev)
 	nand_chip->ecc.priv	= NULL;
 	nand_chip->options	|= NAND_SKIP_BBTSCAN;
 
+	/* GPMC external I/O space */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
+	if (!res) {
+		dev_err(dev, "Can't get memory resource 0\n");
+		return -EINVAL;
+	}
+
+	nand_chip->IO_ADDR_R = devm_ioremap_resource(dev, res);
 	if (IS_ERR(nand_chip->IO_ADDR_R))
 		return PTR_ERR(nand_chip->IO_ADDR_R);
 
@@ -1640,6 +1714,27 @@ static int omap_nand_probe(struct platform_device *pdev)
 	nand_chip->IO_ADDR_W = nand_chip->IO_ADDR_R;
 	nand_chip->cmd_ctrl  = omap_hwcontrol;
 
+	/* GPMC internal registers */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		dev_err(dev, "Can't get memory resource 1\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * This resource is already requested by the GPMC driver
+	 * so we can't request it again. Instead, we just ioremap it.
+	 * This driver doesn't access the same registers as the GPMC
+	 * driver so it is safe.
+	 */
+	info->gpmc_base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!info->gpmc_base) {
+		dev_err(dev, "Can't ioremap resource 1\n");
+		return -EADDRNOTAVAIL;
+	}
+
+	gpmc_update_nand_reg(info);
+
 	/*
 	 * If RDY/BSY line is connected to OMAP then use the omap ready
 	 * function and the generic nand_wait function which reads the status
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h
index 97c9852..b71cfbdb6 100644
--- a/include/linux/platform_data/mtd-nand-omap2.h
+++ b/include/linux/platform_data/mtd-nand-omap2.h
@@ -62,10 +62,11 @@ struct omap_nand_platform_data {
 	enum nand_io		xfer_type;
 	int			devsize;
 	enum omap_ecc           ecc_opt;
-	struct gpmc_nand_regs	reg;
 
 	/* for passing the partitions */
 	struct device_node	*of_node;
 	struct device_node	*elm_of_node;
+
+	struct gpmc_nand_regs	reg;		/* deprecated */
 };
 #endif
-- 
1.8.3.2


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

* [PATCH 06/36] mtd: nand: omap: Move gpmc_update_nand_reg to nand driver
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

GPMC and NAND drivers share the same register space but never use the
same registers. As there is no clear address seperation between the
registers for GPMC and NAND, we can't easily split it up into 2 regions
i.e. one for GPMC and other for NAND. Instead, we simply remap the entire
register space in both the drivers. The NAND driver doesn't re-request
the region as it is already requested by the GPMC driver (parent).

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-nand.c              |  16 +++-
 arch/arm/mach-omap2/gpmc.c                   |  34 +-------
 arch/arm/mach-omap2/gpmc.h                   |   5 +-
 drivers/mtd/nand/omap2.c                     | 123 ++++++++++++++++++++++++---
 include/linux/platform_data/mtd-nand-omap2.h |   3 +-
 5 files changed, 127 insertions(+), 54 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index 3e6420b..aaebd2f 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -26,11 +26,16 @@
 
 static struct resource gpmc_nand_resource[] = {
 	{
+		/* GPMC I/O space */
 		.flags		= IORESOURCE_MEM,
 	},
 	{
-		.flags		= IORESOURCE_IRQ,
+		/* GPMC register space */
+		.flags		= IORESOURCE_MEM,
 	},
+	{
+		.flags		= IORESOURCE_IRQ,
+	}
 };
 
 static struct platform_device gpmc_nand_device = {
@@ -91,6 +96,7 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 	int err	= 0;
 	struct gpmc_settings s;
 	struct device *dev = &gpmc_nand_device.dev;
+	struct resource res;
 
 	memset(&s, 0, sizeof(struct gpmc_settings));
 
@@ -107,7 +113,11 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 	gpmc_nand_resource[0].end = gpmc_nand_resource[0].start +
 							NAND_IO_SIZE - 1;
 
-	gpmc_nand_resource[1].start = gpmc_get_irq();
+	gpmc_get_mem_resource(&res);
+	gpmc_nand_resource[1].start = res.start;
+	gpmc_nand_resource[1].end = res.end;
+
+	gpmc_nand_resource[2].start = gpmc_get_irq();
 
 	if (gpmc_t) {
 		err = gpmc_cs_set_timings(gpmc_nand_data->cs, gpmc_t);
@@ -132,8 +142,6 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 	if (err < 0)
 		goto out_free_cs;
 
-	gpmc_update_nand_reg(&gpmc_nand_data->reg, gpmc_nand_data->cs);
-
 	if (!gpmc_hwecc_bch_capable(gpmc_nand_data->ecc_opt)) {
 		dev_err(dev, "Unsupported NAND ECC scheme selected\n");
 		return -EINVAL;
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 2524541..0a8b6ca 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -625,38 +625,10 @@ int gpmc_configure(int cmd, int wval)
 }
 EXPORT_SYMBOL(gpmc_configure);
 
-void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs)
+void gpmc_get_mem_resource(struct resource *res)
 {
-	int i;
-
-	reg->gpmc_status = gpmc_base + GPMC_STATUS;
-	reg->gpmc_irqstatus = gpmc_base + GPMC_IRQSTATUS;
-	reg->gpmc_irqenable = gpmc_base + GPMC_IRQENABLE;
-	reg->gpmc_nand_command = gpmc_base + GPMC_CS0_OFFSET +
-				GPMC_CS_NAND_COMMAND + GPMC_CS_SIZE * cs;
-	reg->gpmc_nand_address = gpmc_base + GPMC_CS0_OFFSET +
-				GPMC_CS_NAND_ADDRESS + GPMC_CS_SIZE * cs;
-	reg->gpmc_nand_data = gpmc_base + GPMC_CS0_OFFSET +
-				GPMC_CS_NAND_DATA + GPMC_CS_SIZE * cs;
-	reg->gpmc_prefetch_config1 = gpmc_base + GPMC_PREFETCH_CONFIG1;
-	reg->gpmc_prefetch_config2 = gpmc_base + GPMC_PREFETCH_CONFIG2;
-	reg->gpmc_prefetch_control = gpmc_base + GPMC_PREFETCH_CONTROL;
-	reg->gpmc_prefetch_status = gpmc_base + GPMC_PREFETCH_STATUS;
-	reg->gpmc_ecc_config = gpmc_base + GPMC_ECC_CONFIG;
-	reg->gpmc_ecc_control = gpmc_base + GPMC_ECC_CONTROL;
-	reg->gpmc_ecc_size_config = gpmc_base + GPMC_ECC_SIZE_CONFIG;
-	reg->gpmc_ecc1_result = gpmc_base + GPMC_ECC1_RESULT;
-
-	for (i = 0; i < GPMC_BCH_NUM_REMAINDER; i++) {
-		reg->gpmc_bch_result0[i] = gpmc_base + GPMC_ECC_BCH_RESULT_0 +
-					   GPMC_BCH_SIZE * i;
-		reg->gpmc_bch_result1[i] = gpmc_base + GPMC_ECC_BCH_RESULT_1 +
-					   GPMC_BCH_SIZE * i;
-		reg->gpmc_bch_result2[i] = gpmc_base + GPMC_ECC_BCH_RESULT_2 +
-					   GPMC_BCH_SIZE * i;
-		reg->gpmc_bch_result3[i] = gpmc_base + GPMC_ECC_BCH_RESULT_3 +
-					   GPMC_BCH_SIZE * i;
-	}
+	res->start =  phys_base;
+	res->end = res->start + mem_size - 1;
 }
 
 int gpmc_get_irq(void)
diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h
index a558ebd..479ce84 100644
--- a/arch/arm/mach-omap2/gpmc.h
+++ b/arch/arm/mach-omap2/gpmc.h
@@ -21,9 +21,6 @@
 #define GPMC_CS_CONFIG5		0x10
 #define GPMC_CS_CONFIG6		0x14
 #define GPMC_CS_CONFIG7		0x18
-#define GPMC_CS_NAND_COMMAND	0x1c
-#define GPMC_CS_NAND_ADDRESS	0x20
-#define GPMC_CS_NAND_DATA	0x24
 
 /* Control Commands */
 #define GPMC_CONFIG_WP		0x00000005
@@ -69,7 +66,7 @@ extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
 			     struct gpmc_settings *gpmc_s,
 			     struct gpmc_device_timings *dev_t);
 
-extern void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs);
+void gpmc_get_mem_resource(struct resource *res);
 int gpmc_get_irq(void);
 
 extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 8de1660..120acee 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -140,6 +140,36 @@
 #define GPMC_IRQ_FIFOEVENT	BIT(0)
 #define GPMC_IRQ_TERMCOUNT	BIT(1)
 
+/* GPMC register offsets */
+#define GPMC_REVISION		0x00
+#define GPMC_SYSCONFIG		0x10
+#define GPMC_SYSSTATUS		0x14
+#define GPMC_IRQSTATUS		0x18
+#define GPMC_IRQENABLE		0x1c
+#define GPMC_TIMEOUT_CONTROL	0x40
+#define GPMC_ERR_ADDRESS	0x44
+#define GPMC_ERR_TYPE		0x48
+#define GPMC_CONFIG		0x50
+#define GPMC_STATUS		0x54
+#define GPMC_CS_NAND_COMMAND	0x7c
+#define GPMC_CS_NAND_ADDRESS	0x80
+#define GPMC_CS_NAND_DATA	0x84
+#define GPMC_PREFETCH_CONFIG1	0x1e0
+#define GPMC_PREFETCH_CONFIG2	0x1e4
+#define GPMC_PREFETCH_CONTROL	0x1ec
+#define GPMC_PREFETCH_STATUS	0x1f0
+#define GPMC_ECC_CONFIG		0x1f4
+#define GPMC_ECC_CONTROL	0x1f8
+#define GPMC_ECC_SIZE_CONFIG	0x1fc
+#define GPMC_ECC1_RESULT        0x200
+#define GPMC_ECC_BCH_RESULT_0   0x240   /* not available on OMAP2 */
+#define	GPMC_ECC_BCH_RESULT_1	0x244	/* not available on OMAP2 */
+#define	GPMC_ECC_BCH_RESULT_2	0x248	/* not available on OMAP2 */
+#define	GPMC_ECC_BCH_RESULT_3	0x24c	/* not available on OMAP2 */
+
+#define GPMC_CS_SIZE		0x30
+#define	GPMC_BCH_SIZE		0x10
+
 #ifdef CONFIG_MTD_NAND_OMAP_BCH
 static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc,
 	0xac, 0x6b, 0xff, 0x99, 0x7b};
@@ -158,6 +188,7 @@ struct omap_nand_info {
 
 	int				gpmc_cs;
 	unsigned long			phys_base;
+	void __iomem			*gpmc_base;
 	enum omap_ecc			ecc_opt;
 	struct completion		comp;
 	struct dma_chan			*dma;
@@ -1584,20 +1615,58 @@ static int is_elm_present(struct omap_nand_info *info,
 }
 #endif /* CONFIG_MTD_NAND_ECC_BCH */
 
+static void gpmc_update_nand_reg(struct omap_nand_info *info)
+{
+	int i;
+	struct gpmc_nand_regs *reg = &info->reg;
+	int cs = info->gpmc_cs;
+	void __iomem *gpmc_base = info->gpmc_base;
+
+	reg->gpmc_status = gpmc_base + GPMC_STATUS;
+	reg->gpmc_irqstatus = gpmc_base + GPMC_IRQSTATUS;
+	reg->gpmc_irqenable = gpmc_base + GPMC_IRQENABLE;
+	reg->gpmc_nand_command = gpmc_base + GPMC_CS_NAND_COMMAND +
+				 GPMC_CS_SIZE * cs;
+	reg->gpmc_nand_address = gpmc_base + GPMC_CS_NAND_ADDRESS +
+				 GPMC_CS_SIZE * cs;
+	reg->gpmc_nand_data = gpmc_base + GPMC_CS_NAND_DATA +
+				 GPMC_CS_SIZE * cs;
+	reg->gpmc_prefetch_config1 = gpmc_base + GPMC_PREFETCH_CONFIG1;
+	reg->gpmc_prefetch_config2 = gpmc_base + GPMC_PREFETCH_CONFIG2;
+	reg->gpmc_prefetch_control = gpmc_base + GPMC_PREFETCH_CONTROL;
+	reg->gpmc_prefetch_status = gpmc_base + GPMC_PREFETCH_STATUS;
+	reg->gpmc_ecc_config = gpmc_base + GPMC_ECC_CONFIG;
+	reg->gpmc_ecc_control = gpmc_base + GPMC_ECC_CONTROL;
+	reg->gpmc_ecc_size_config = gpmc_base + GPMC_ECC_SIZE_CONFIG;
+	reg->gpmc_ecc1_result = gpmc_base + GPMC_ECC1_RESULT;
+
+	for (i = 0; i < GPMC_BCH_NUM_REMAINDER; i++) {
+		reg->gpmc_bch_result0[i] = gpmc_base + GPMC_ECC_BCH_RESULT_0 +
+					   GPMC_BCH_SIZE * i;
+		reg->gpmc_bch_result1[i] = gpmc_base + GPMC_ECC_BCH_RESULT_1 +
+					   GPMC_BCH_SIZE * i;
+		reg->gpmc_bch_result2[i] = gpmc_base + GPMC_ECC_BCH_RESULT_2 +
+					   GPMC_BCH_SIZE * i;
+		reg->gpmc_bch_result3[i] = gpmc_base + GPMC_ECC_BCH_RESULT_3 +
+					   GPMC_BCH_SIZE * i;
+	}
+}
+
 static int omap_nand_probe(struct platform_device *pdev)
 {
-	struct omap_nand_info		*info;
-	struct omap_nand_platform_data	*pdata;
-	struct mtd_info			*mtd;
-	struct nand_chip		*nand_chip;
-	struct nand_ecclayout		*ecclayout;
-	int				err;
-	int				i;
-	dma_cap_mask_t			mask;
-	unsigned			sig;
-	unsigned			oob_index;
-	struct resource			*res;
-	struct mtd_part_parser_data	ppdata = {};
+	struct omap_nand_info *info;
+	struct omap_nand_platform_data *pdata;
+	struct mtd_info	*mtd;
+	struct nand_chip *nand_chip;
+	struct nand_ecclayout *ecclayout;
+	int err;
+	int i;
+	dma_cap_mask_t mask;
+	unsigned sig;
+	unsigned oob_index;
+	struct resource	*res;
+	struct mtd_part_parser_data ppdata = {};
+	struct device *dev = &pdev->dev;
 
 	pdata = dev_get_platdata(&pdev->dev);
 	if (pdata == NULL) {
@@ -1617,7 +1686,6 @@ static int omap_nand_probe(struct platform_device *pdev)
 
 	info->pdev		= pdev;
 	info->gpmc_cs		= pdata->cs;
-	info->reg		= pdata->reg;
 	info->of_node		= pdata->of_node;
 	info->ecc_opt		= pdata->ecc_opt;
 	mtd			= &info->mtd;
@@ -1628,8 +1696,14 @@ static int omap_nand_probe(struct platform_device *pdev)
 	nand_chip->ecc.priv	= NULL;
 	nand_chip->options	|= NAND_SKIP_BBTSCAN;
 
+	/* GPMC external I/O space */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
+	if (!res) {
+		dev_err(dev, "Can't get memory resource 0\n");
+		return -EINVAL;
+	}
+
+	nand_chip->IO_ADDR_R = devm_ioremap_resource(dev, res);
 	if (IS_ERR(nand_chip->IO_ADDR_R))
 		return PTR_ERR(nand_chip->IO_ADDR_R);
 
@@ -1640,6 +1714,27 @@ static int omap_nand_probe(struct platform_device *pdev)
 	nand_chip->IO_ADDR_W = nand_chip->IO_ADDR_R;
 	nand_chip->cmd_ctrl  = omap_hwcontrol;
 
+	/* GPMC internal registers */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		dev_err(dev, "Can't get memory resource 1\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * This resource is already requested by the GPMC driver
+	 * so we can't request it again. Instead, we just ioremap it.
+	 * This driver doesn't access the same registers as the GPMC
+	 * driver so it is safe.
+	 */
+	info->gpmc_base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!info->gpmc_base) {
+		dev_err(dev, "Can't ioremap resource 1\n");
+		return -EADDRNOTAVAIL;
+	}
+
+	gpmc_update_nand_reg(info);
+
 	/*
 	 * If RDY/BSY line is connected to OMAP then use the omap ready
 	 * function and the generic nand_wait function which reads the status
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h
index 97c9852..b71cfbdb6 100644
--- a/include/linux/platform_data/mtd-nand-omap2.h
+++ b/include/linux/platform_data/mtd-nand-omap2.h
@@ -62,10 +62,11 @@ struct omap_nand_platform_data {
 	enum nand_io		xfer_type;
 	int			devsize;
 	enum omap_ecc           ecc_opt;
-	struct gpmc_nand_regs	reg;
 
 	/* for passing the partitions */
 	struct device_node	*of_node;
 	struct device_node	*elm_of_node;
+
+	struct gpmc_nand_regs	reg;		/* deprecated */
 };
 #endif
-- 
1.8.3.2


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

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

* [PATCH 06/36] mtd: nand: omap: Move gpmc_update_nand_reg to nand driver
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

GPMC and NAND drivers share the same register space but never use the
same registers. As there is no clear address seperation between the
registers for GPMC and NAND, we can't easily split it up into 2 regions
i.e. one for GPMC and other for NAND. Instead, we simply remap the entire
register space in both the drivers. The NAND driver doesn't re-request
the region as it is already requested by the GPMC driver (parent).

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-nand.c              |  16 +++-
 arch/arm/mach-omap2/gpmc.c                   |  34 +-------
 arch/arm/mach-omap2/gpmc.h                   |   5 +-
 drivers/mtd/nand/omap2.c                     | 123 ++++++++++++++++++++++++---
 include/linux/platform_data/mtd-nand-omap2.h |   3 +-
 5 files changed, 127 insertions(+), 54 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index 3e6420b..aaebd2f 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -26,11 +26,16 @@
 
 static struct resource gpmc_nand_resource[] = {
 	{
+		/* GPMC I/O space */
 		.flags		= IORESOURCE_MEM,
 	},
 	{
-		.flags		= IORESOURCE_IRQ,
+		/* GPMC register space */
+		.flags		= IORESOURCE_MEM,
 	},
+	{
+		.flags		= IORESOURCE_IRQ,
+	}
 };
 
 static struct platform_device gpmc_nand_device = {
@@ -91,6 +96,7 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 	int err	= 0;
 	struct gpmc_settings s;
 	struct device *dev = &gpmc_nand_device.dev;
+	struct resource res;
 
 	memset(&s, 0, sizeof(struct gpmc_settings));
 
@@ -107,7 +113,11 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 	gpmc_nand_resource[0].end = gpmc_nand_resource[0].start +
 							NAND_IO_SIZE - 1;
 
-	gpmc_nand_resource[1].start = gpmc_get_irq();
+	gpmc_get_mem_resource(&res);
+	gpmc_nand_resource[1].start = res.start;
+	gpmc_nand_resource[1].end = res.end;
+
+	gpmc_nand_resource[2].start = gpmc_get_irq();
 
 	if (gpmc_t) {
 		err = gpmc_cs_set_timings(gpmc_nand_data->cs, gpmc_t);
@@ -132,8 +142,6 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 	if (err < 0)
 		goto out_free_cs;
 
-	gpmc_update_nand_reg(&gpmc_nand_data->reg, gpmc_nand_data->cs);
-
 	if (!gpmc_hwecc_bch_capable(gpmc_nand_data->ecc_opt)) {
 		dev_err(dev, "Unsupported NAND ECC scheme selected\n");
 		return -EINVAL;
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 2524541..0a8b6ca 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -625,38 +625,10 @@ int gpmc_configure(int cmd, int wval)
 }
 EXPORT_SYMBOL(gpmc_configure);
 
-void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs)
+void gpmc_get_mem_resource(struct resource *res)
 {
-	int i;
-
-	reg->gpmc_status = gpmc_base + GPMC_STATUS;
-	reg->gpmc_irqstatus = gpmc_base + GPMC_IRQSTATUS;
-	reg->gpmc_irqenable = gpmc_base + GPMC_IRQENABLE;
-	reg->gpmc_nand_command = gpmc_base + GPMC_CS0_OFFSET +
-				GPMC_CS_NAND_COMMAND + GPMC_CS_SIZE * cs;
-	reg->gpmc_nand_address = gpmc_base + GPMC_CS0_OFFSET +
-				GPMC_CS_NAND_ADDRESS + GPMC_CS_SIZE * cs;
-	reg->gpmc_nand_data = gpmc_base + GPMC_CS0_OFFSET +
-				GPMC_CS_NAND_DATA + GPMC_CS_SIZE * cs;
-	reg->gpmc_prefetch_config1 = gpmc_base + GPMC_PREFETCH_CONFIG1;
-	reg->gpmc_prefetch_config2 = gpmc_base + GPMC_PREFETCH_CONFIG2;
-	reg->gpmc_prefetch_control = gpmc_base + GPMC_PREFETCH_CONTROL;
-	reg->gpmc_prefetch_status = gpmc_base + GPMC_PREFETCH_STATUS;
-	reg->gpmc_ecc_config = gpmc_base + GPMC_ECC_CONFIG;
-	reg->gpmc_ecc_control = gpmc_base + GPMC_ECC_CONTROL;
-	reg->gpmc_ecc_size_config = gpmc_base + GPMC_ECC_SIZE_CONFIG;
-	reg->gpmc_ecc1_result = gpmc_base + GPMC_ECC1_RESULT;
-
-	for (i = 0; i < GPMC_BCH_NUM_REMAINDER; i++) {
-		reg->gpmc_bch_result0[i] = gpmc_base + GPMC_ECC_BCH_RESULT_0 +
-					   GPMC_BCH_SIZE * i;
-		reg->gpmc_bch_result1[i] = gpmc_base + GPMC_ECC_BCH_RESULT_1 +
-					   GPMC_BCH_SIZE * i;
-		reg->gpmc_bch_result2[i] = gpmc_base + GPMC_ECC_BCH_RESULT_2 +
-					   GPMC_BCH_SIZE * i;
-		reg->gpmc_bch_result3[i] = gpmc_base + GPMC_ECC_BCH_RESULT_3 +
-					   GPMC_BCH_SIZE * i;
-	}
+	res->start =  phys_base;
+	res->end = res->start + mem_size - 1;
 }
 
 int gpmc_get_irq(void)
diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h
index a558ebd..479ce84 100644
--- a/arch/arm/mach-omap2/gpmc.h
+++ b/arch/arm/mach-omap2/gpmc.h
@@ -21,9 +21,6 @@
 #define GPMC_CS_CONFIG5		0x10
 #define GPMC_CS_CONFIG6		0x14
 #define GPMC_CS_CONFIG7		0x18
-#define GPMC_CS_NAND_COMMAND	0x1c
-#define GPMC_CS_NAND_ADDRESS	0x20
-#define GPMC_CS_NAND_DATA	0x24
 
 /* Control Commands */
 #define GPMC_CONFIG_WP		0x00000005
@@ -69,7 +66,7 @@ extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
 			     struct gpmc_settings *gpmc_s,
 			     struct gpmc_device_timings *dev_t);
 
-extern void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs);
+void gpmc_get_mem_resource(struct resource *res);
 int gpmc_get_irq(void);
 
 extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 8de1660..120acee 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -140,6 +140,36 @@
 #define GPMC_IRQ_FIFOEVENT	BIT(0)
 #define GPMC_IRQ_TERMCOUNT	BIT(1)
 
+/* GPMC register offsets */
+#define GPMC_REVISION		0x00
+#define GPMC_SYSCONFIG		0x10
+#define GPMC_SYSSTATUS		0x14
+#define GPMC_IRQSTATUS		0x18
+#define GPMC_IRQENABLE		0x1c
+#define GPMC_TIMEOUT_CONTROL	0x40
+#define GPMC_ERR_ADDRESS	0x44
+#define GPMC_ERR_TYPE		0x48
+#define GPMC_CONFIG		0x50
+#define GPMC_STATUS		0x54
+#define GPMC_CS_NAND_COMMAND	0x7c
+#define GPMC_CS_NAND_ADDRESS	0x80
+#define GPMC_CS_NAND_DATA	0x84
+#define GPMC_PREFETCH_CONFIG1	0x1e0
+#define GPMC_PREFETCH_CONFIG2	0x1e4
+#define GPMC_PREFETCH_CONTROL	0x1ec
+#define GPMC_PREFETCH_STATUS	0x1f0
+#define GPMC_ECC_CONFIG		0x1f4
+#define GPMC_ECC_CONTROL	0x1f8
+#define GPMC_ECC_SIZE_CONFIG	0x1fc
+#define GPMC_ECC1_RESULT        0x200
+#define GPMC_ECC_BCH_RESULT_0   0x240   /* not available on OMAP2 */
+#define	GPMC_ECC_BCH_RESULT_1	0x244	/* not available on OMAP2 */
+#define	GPMC_ECC_BCH_RESULT_2	0x248	/* not available on OMAP2 */
+#define	GPMC_ECC_BCH_RESULT_3	0x24c	/* not available on OMAP2 */
+
+#define GPMC_CS_SIZE		0x30
+#define	GPMC_BCH_SIZE		0x10
+
 #ifdef CONFIG_MTD_NAND_OMAP_BCH
 static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc,
 	0xac, 0x6b, 0xff, 0x99, 0x7b};
@@ -158,6 +188,7 @@ struct omap_nand_info {
 
 	int				gpmc_cs;
 	unsigned long			phys_base;
+	void __iomem			*gpmc_base;
 	enum omap_ecc			ecc_opt;
 	struct completion		comp;
 	struct dma_chan			*dma;
@@ -1584,20 +1615,58 @@ static int is_elm_present(struct omap_nand_info *info,
 }
 #endif /* CONFIG_MTD_NAND_ECC_BCH */
 
+static void gpmc_update_nand_reg(struct omap_nand_info *info)
+{
+	int i;
+	struct gpmc_nand_regs *reg = &info->reg;
+	int cs = info->gpmc_cs;
+	void __iomem *gpmc_base = info->gpmc_base;
+
+	reg->gpmc_status = gpmc_base + GPMC_STATUS;
+	reg->gpmc_irqstatus = gpmc_base + GPMC_IRQSTATUS;
+	reg->gpmc_irqenable = gpmc_base + GPMC_IRQENABLE;
+	reg->gpmc_nand_command = gpmc_base + GPMC_CS_NAND_COMMAND +
+				 GPMC_CS_SIZE * cs;
+	reg->gpmc_nand_address = gpmc_base + GPMC_CS_NAND_ADDRESS +
+				 GPMC_CS_SIZE * cs;
+	reg->gpmc_nand_data = gpmc_base + GPMC_CS_NAND_DATA +
+				 GPMC_CS_SIZE * cs;
+	reg->gpmc_prefetch_config1 = gpmc_base + GPMC_PREFETCH_CONFIG1;
+	reg->gpmc_prefetch_config2 = gpmc_base + GPMC_PREFETCH_CONFIG2;
+	reg->gpmc_prefetch_control = gpmc_base + GPMC_PREFETCH_CONTROL;
+	reg->gpmc_prefetch_status = gpmc_base + GPMC_PREFETCH_STATUS;
+	reg->gpmc_ecc_config = gpmc_base + GPMC_ECC_CONFIG;
+	reg->gpmc_ecc_control = gpmc_base + GPMC_ECC_CONTROL;
+	reg->gpmc_ecc_size_config = gpmc_base + GPMC_ECC_SIZE_CONFIG;
+	reg->gpmc_ecc1_result = gpmc_base + GPMC_ECC1_RESULT;
+
+	for (i = 0; i < GPMC_BCH_NUM_REMAINDER; i++) {
+		reg->gpmc_bch_result0[i] = gpmc_base + GPMC_ECC_BCH_RESULT_0 +
+					   GPMC_BCH_SIZE * i;
+		reg->gpmc_bch_result1[i] = gpmc_base + GPMC_ECC_BCH_RESULT_1 +
+					   GPMC_BCH_SIZE * i;
+		reg->gpmc_bch_result2[i] = gpmc_base + GPMC_ECC_BCH_RESULT_2 +
+					   GPMC_BCH_SIZE * i;
+		reg->gpmc_bch_result3[i] = gpmc_base + GPMC_ECC_BCH_RESULT_3 +
+					   GPMC_BCH_SIZE * i;
+	}
+}
+
 static int omap_nand_probe(struct platform_device *pdev)
 {
-	struct omap_nand_info		*info;
-	struct omap_nand_platform_data	*pdata;
-	struct mtd_info			*mtd;
-	struct nand_chip		*nand_chip;
-	struct nand_ecclayout		*ecclayout;
-	int				err;
-	int				i;
-	dma_cap_mask_t			mask;
-	unsigned			sig;
-	unsigned			oob_index;
-	struct resource			*res;
-	struct mtd_part_parser_data	ppdata = {};
+	struct omap_nand_info *info;
+	struct omap_nand_platform_data *pdata;
+	struct mtd_info	*mtd;
+	struct nand_chip *nand_chip;
+	struct nand_ecclayout *ecclayout;
+	int err;
+	int i;
+	dma_cap_mask_t mask;
+	unsigned sig;
+	unsigned oob_index;
+	struct resource	*res;
+	struct mtd_part_parser_data ppdata = {};
+	struct device *dev = &pdev->dev;
 
 	pdata = dev_get_platdata(&pdev->dev);
 	if (pdata == NULL) {
@@ -1617,7 +1686,6 @@ static int omap_nand_probe(struct platform_device *pdev)
 
 	info->pdev		= pdev;
 	info->gpmc_cs		= pdata->cs;
-	info->reg		= pdata->reg;
 	info->of_node		= pdata->of_node;
 	info->ecc_opt		= pdata->ecc_opt;
 	mtd			= &info->mtd;
@@ -1628,8 +1696,14 @@ static int omap_nand_probe(struct platform_device *pdev)
 	nand_chip->ecc.priv	= NULL;
 	nand_chip->options	|= NAND_SKIP_BBTSCAN;
 
+	/* GPMC external I/O space */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
+	if (!res) {
+		dev_err(dev, "Can't get memory resource 0\n");
+		return -EINVAL;
+	}
+
+	nand_chip->IO_ADDR_R = devm_ioremap_resource(dev, res);
 	if (IS_ERR(nand_chip->IO_ADDR_R))
 		return PTR_ERR(nand_chip->IO_ADDR_R);
 
@@ -1640,6 +1714,27 @@ static int omap_nand_probe(struct platform_device *pdev)
 	nand_chip->IO_ADDR_W = nand_chip->IO_ADDR_R;
 	nand_chip->cmd_ctrl  = omap_hwcontrol;
 
+	/* GPMC internal registers */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		dev_err(dev, "Can't get memory resource 1\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * This resource is already requested by the GPMC driver
+	 * so we can't request it again. Instead, we just ioremap it.
+	 * This driver doesn't access the same registers as the GPMC
+	 * driver so it is safe.
+	 */
+	info->gpmc_base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!info->gpmc_base) {
+		dev_err(dev, "Can't ioremap resource 1\n");
+		return -EADDRNOTAVAIL;
+	}
+
+	gpmc_update_nand_reg(info);
+
 	/*
 	 * If RDY/BSY line is connected to OMAP then use the omap ready
 	 * function and the generic nand_wait function which reads the status
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h
index 97c9852..b71cfbdb6 100644
--- a/include/linux/platform_data/mtd-nand-omap2.h
+++ b/include/linux/platform_data/mtd-nand-omap2.h
@@ -62,10 +62,11 @@ struct omap_nand_platform_data {
 	enum nand_io		xfer_type;
 	int			devsize;
 	enum omap_ecc           ecc_opt;
-	struct gpmc_nand_regs	reg;
 
 	/* for passing the partitions */
 	struct device_node	*of_node;
 	struct device_node	*elm_of_node;
+
+	struct gpmc_nand_regs	reg;		/* deprecated */
 };
 #endif
-- 
1.8.3.2

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

* [PATCH 07/36] mtd: nand: omap: Move NAND write protect code from GPMC to NAND driver
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

The write protect (WP) pin is only used for NAND devices. So move
the code into the NAND driver.

Get rid of gpmc_configure() as it is no longer used.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-nand.c              |  4 ----
 arch/arm/mach-omap2/gpmc.c                   | 29 ----------------------------
 arch/arm/mach-omap2/gpmc.h                   |  5 -----
 drivers/mtd/nand/omap2.c                     | 23 ++++++++++++++++++++++
 include/linux/platform_data/mtd-nand-omap2.h |  1 +
 5 files changed, 24 insertions(+), 38 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index aaebd2f..9649fd9 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -138,10 +138,6 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 	if (err < 0)
 		goto out_free_cs;
 
-	err = gpmc_configure(GPMC_CONFIG_WP, 0);
-	if (err < 0)
-		goto out_free_cs;
-
 	if (!gpmc_hwecc_bch_capable(gpmc_nand_data->ecc_opt)) {
 		dev_err(dev, "Unsupported NAND ECC scheme selected\n");
 		return -EINVAL;
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 0a8b6ca..a0c2194 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -596,35 +596,6 @@ void gpmc_cs_free(int cs)
 }
 EXPORT_SYMBOL(gpmc_cs_free);
 
-/**
- * gpmc_configure - write request to configure gpmc
- * @cmd: command type
- * @wval: value to write
- * @return status of the operation
- */
-int gpmc_configure(int cmd, int wval)
-{
-	u32 regval;
-
-	switch (cmd) {
-	case GPMC_CONFIG_WP:
-		regval = gpmc_read_reg(GPMC_CONFIG);
-		if (wval)
-			regval &= ~GPMC_CONFIG_WRITEPROTECT; /* WP is ON */
-		else
-			regval |= GPMC_CONFIG_WRITEPROTECT;  /* WP is OFF */
-		gpmc_write_reg(GPMC_CONFIG, regval);
-		break;
-
-	default:
-		pr_err("%s: command not supported\n", __func__);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(gpmc_configure);
-
 void gpmc_get_mem_resource(struct resource *res)
 {
 	res->start =  phys_base;
diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h
index 479ce84..6204913 100644
--- a/arch/arm/mach-omap2/gpmc.h
+++ b/arch/arm/mach-omap2/gpmc.h
@@ -22,9 +22,6 @@
 #define GPMC_CS_CONFIG6		0x14
 #define GPMC_CS_CONFIG7		0x18
 
-/* Control Commands */
-#define GPMC_CONFIG_WP		0x00000005
-
 /* ECC commands */
 #define GPMC_ECC_READ		0 /* Reset Hardware ECC for read */
 #define GPMC_ECC_WRITE		1 /* Reset Hardware ECC for write */
@@ -57,7 +54,6 @@
 
 #define GPMC_DEVICETYPE_NOR		0
 #define GPMC_DEVICETYPE_NAND		2
-#define GPMC_CONFIG_WRITEPROTECT	0x00000010
 #define WR_RD_PIN_MONITORING		0x00600000
 #define GPMC_IRQ_FIFOEVENTENABLE	0x01
 #define GPMC_IRQ_COUNT_EVENT		0x02
@@ -79,7 +75,6 @@ extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
 extern void gpmc_cs_free(int cs);
 extern void omap3_gpmc_save_context(void);
 extern void omap3_gpmc_restore_context(void);
-extern int gpmc_configure(int cmd, int wval);
 extern void gpmc_read_settings_dt(struct device_node *np,
 				  struct gpmc_settings *p);
 
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 120acee..bb41796 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -140,6 +140,9 @@
 #define GPMC_IRQ_FIFOEVENT	BIT(0)
 #define GPMC_IRQ_TERMCOUNT	BIT(1)
 
+/* GPMC_CONFIG register bits */
+#define GPMC_CONFIG_WRITEPROTECT	BIT(4)
+
 /* GPMC register offsets */
 #define GPMC_REVISION		0x00
 #define GPMC_SYSCONFIG		0x10
@@ -206,6 +209,22 @@ struct omap_nand_info {
 };
 
 /**
+ * omap_nand_writeprotect - Control the WP line to the NAND chip
+ */
+static void omap_nand_writeprotect(struct omap_nand_info *info, bool on)
+{
+	u32 val;
+
+	val = readl(info->reg.gpmc_config);
+	if (on)
+		val |= GPMC_CONFIG_WRITEPROTECT;
+	else
+		val &= GPMC_CONFIG_WRITEPROTECT;
+
+	writel(val, info->reg.gpmc_config);
+}
+
+/**
  * omap_prefetch_enable - configures and starts prefetch transfer
  * @cs: cs (chip select) number
  * @fifo_th: fifo threshold to be used for read/ write
@@ -1622,6 +1641,7 @@ static void gpmc_update_nand_reg(struct omap_nand_info *info)
 	int cs = info->gpmc_cs;
 	void __iomem *gpmc_base = info->gpmc_base;
 
+	reg->gpmc_config = gpmc_base + GPMC_CONFIG;
 	reg->gpmc_status = gpmc_base + GPMC_STATUS;
 	reg->gpmc_irqstatus = gpmc_base + GPMC_IRQSTATUS;
 	reg->gpmc_irqenable = gpmc_base + GPMC_IRQENABLE;
@@ -2029,6 +2049,9 @@ static int omap_nand_probe(struct platform_device *pdev)
 		goto return_error;
 	}
 
+	/* turn off write protect */
+	omap_nand_writeprotect(info, false);
+
 	/* second phase scan */
 	if (nand_scan_tail(mtd)) {
 		err = -ENXIO;
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h
index b71cfbdb6..62a855e 100644
--- a/include/linux/platform_data/mtd-nand-omap2.h
+++ b/include/linux/platform_data/mtd-nand-omap2.h
@@ -34,6 +34,7 @@ enum omap_ecc {
 };
 
 struct gpmc_nand_regs {
+	void __iomem	*gpmc_config;
 	void __iomem	*gpmc_status;
 	void __iomem	*gpmc_irqstatus;
 	void __iomem	*gpmc_irqenable;
-- 
1.8.3.2


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

* [PATCH 07/36] mtd: nand: omap: Move NAND write protect code from GPMC to NAND driver
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

The write protect (WP) pin is only used for NAND devices. So move
the code into the NAND driver.

Get rid of gpmc_configure() as it is no longer used.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-nand.c              |  4 ----
 arch/arm/mach-omap2/gpmc.c                   | 29 ----------------------------
 arch/arm/mach-omap2/gpmc.h                   |  5 -----
 drivers/mtd/nand/omap2.c                     | 23 ++++++++++++++++++++++
 include/linux/platform_data/mtd-nand-omap2.h |  1 +
 5 files changed, 24 insertions(+), 38 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index aaebd2f..9649fd9 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -138,10 +138,6 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 	if (err < 0)
 		goto out_free_cs;
 
-	err = gpmc_configure(GPMC_CONFIG_WP, 0);
-	if (err < 0)
-		goto out_free_cs;
-
 	if (!gpmc_hwecc_bch_capable(gpmc_nand_data->ecc_opt)) {
 		dev_err(dev, "Unsupported NAND ECC scheme selected\n");
 		return -EINVAL;
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 0a8b6ca..a0c2194 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -596,35 +596,6 @@ void gpmc_cs_free(int cs)
 }
 EXPORT_SYMBOL(gpmc_cs_free);
 
-/**
- * gpmc_configure - write request to configure gpmc
- * @cmd: command type
- * @wval: value to write
- * @return status of the operation
- */
-int gpmc_configure(int cmd, int wval)
-{
-	u32 regval;
-
-	switch (cmd) {
-	case GPMC_CONFIG_WP:
-		regval = gpmc_read_reg(GPMC_CONFIG);
-		if (wval)
-			regval &= ~GPMC_CONFIG_WRITEPROTECT; /* WP is ON */
-		else
-			regval |= GPMC_CONFIG_WRITEPROTECT;  /* WP is OFF */
-		gpmc_write_reg(GPMC_CONFIG, regval);
-		break;
-
-	default:
-		pr_err("%s: command not supported\n", __func__);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(gpmc_configure);
-
 void gpmc_get_mem_resource(struct resource *res)
 {
 	res->start =  phys_base;
diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h
index 479ce84..6204913 100644
--- a/arch/arm/mach-omap2/gpmc.h
+++ b/arch/arm/mach-omap2/gpmc.h
@@ -22,9 +22,6 @@
 #define GPMC_CS_CONFIG6		0x14
 #define GPMC_CS_CONFIG7		0x18
 
-/* Control Commands */
-#define GPMC_CONFIG_WP		0x00000005
-
 /* ECC commands */
 #define GPMC_ECC_READ		0 /* Reset Hardware ECC for read */
 #define GPMC_ECC_WRITE		1 /* Reset Hardware ECC for write */
@@ -57,7 +54,6 @@
 
 #define GPMC_DEVICETYPE_NOR		0
 #define GPMC_DEVICETYPE_NAND		2
-#define GPMC_CONFIG_WRITEPROTECT	0x00000010
 #define WR_RD_PIN_MONITORING		0x00600000
 #define GPMC_IRQ_FIFOEVENTENABLE	0x01
 #define GPMC_IRQ_COUNT_EVENT		0x02
@@ -79,7 +75,6 @@ extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
 extern void gpmc_cs_free(int cs);
 extern void omap3_gpmc_save_context(void);
 extern void omap3_gpmc_restore_context(void);
-extern int gpmc_configure(int cmd, int wval);
 extern void gpmc_read_settings_dt(struct device_node *np,
 				  struct gpmc_settings *p);
 
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 120acee..bb41796 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -140,6 +140,9 @@
 #define GPMC_IRQ_FIFOEVENT	BIT(0)
 #define GPMC_IRQ_TERMCOUNT	BIT(1)
 
+/* GPMC_CONFIG register bits */
+#define GPMC_CONFIG_WRITEPROTECT	BIT(4)
+
 /* GPMC register offsets */
 #define GPMC_REVISION		0x00
 #define GPMC_SYSCONFIG		0x10
@@ -206,6 +209,22 @@ struct omap_nand_info {
 };
 
 /**
+ * omap_nand_writeprotect - Control the WP line to the NAND chip
+ */
+static void omap_nand_writeprotect(struct omap_nand_info *info, bool on)
+{
+	u32 val;
+
+	val = readl(info->reg.gpmc_config);
+	if (on)
+		val |= GPMC_CONFIG_WRITEPROTECT;
+	else
+		val &= GPMC_CONFIG_WRITEPROTECT;
+
+	writel(val, info->reg.gpmc_config);
+}
+
+/**
  * omap_prefetch_enable - configures and starts prefetch transfer
  * @cs: cs (chip select) number
  * @fifo_th: fifo threshold to be used for read/ write
@@ -1622,6 +1641,7 @@ static void gpmc_update_nand_reg(struct omap_nand_info *info)
 	int cs = info->gpmc_cs;
 	void __iomem *gpmc_base = info->gpmc_base;
 
+	reg->gpmc_config = gpmc_base + GPMC_CONFIG;
 	reg->gpmc_status = gpmc_base + GPMC_STATUS;
 	reg->gpmc_irqstatus = gpmc_base + GPMC_IRQSTATUS;
 	reg->gpmc_irqenable = gpmc_base + GPMC_IRQENABLE;
@@ -2029,6 +2049,9 @@ static int omap_nand_probe(struct platform_device *pdev)
 		goto return_error;
 	}
 
+	/* turn off write protect */
+	omap_nand_writeprotect(info, false);
+
 	/* second phase scan */
 	if (nand_scan_tail(mtd)) {
 		err = -ENXIO;
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h
index b71cfbdb6..62a855e 100644
--- a/include/linux/platform_data/mtd-nand-omap2.h
+++ b/include/linux/platform_data/mtd-nand-omap2.h
@@ -34,6 +34,7 @@ enum omap_ecc {
 };
 
 struct gpmc_nand_regs {
+	void __iomem	*gpmc_config;
 	void __iomem	*gpmc_status;
 	void __iomem	*gpmc_irqstatus;
 	void __iomem	*gpmc_irqenable;
-- 
1.8.3.2

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

* [PATCH 07/36] mtd: nand: omap: Move NAND write protect code from GPMC to NAND driver
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

The write protect (WP) pin is only used for NAND devices. So move
the code into the NAND driver.

Get rid of gpmc_configure() as it is no longer used.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-nand.c              |  4 ----
 arch/arm/mach-omap2/gpmc.c                   | 29 ----------------------------
 arch/arm/mach-omap2/gpmc.h                   |  5 -----
 drivers/mtd/nand/omap2.c                     | 23 ++++++++++++++++++++++
 include/linux/platform_data/mtd-nand-omap2.h |  1 +
 5 files changed, 24 insertions(+), 38 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index aaebd2f..9649fd9 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -138,10 +138,6 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 	if (err < 0)
 		goto out_free_cs;
 
-	err = gpmc_configure(GPMC_CONFIG_WP, 0);
-	if (err < 0)
-		goto out_free_cs;
-
 	if (!gpmc_hwecc_bch_capable(gpmc_nand_data->ecc_opt)) {
 		dev_err(dev, "Unsupported NAND ECC scheme selected\n");
 		return -EINVAL;
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 0a8b6ca..a0c2194 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -596,35 +596,6 @@ void gpmc_cs_free(int cs)
 }
 EXPORT_SYMBOL(gpmc_cs_free);
 
-/**
- * gpmc_configure - write request to configure gpmc
- * @cmd: command type
- * @wval: value to write
- * @return status of the operation
- */
-int gpmc_configure(int cmd, int wval)
-{
-	u32 regval;
-
-	switch (cmd) {
-	case GPMC_CONFIG_WP:
-		regval = gpmc_read_reg(GPMC_CONFIG);
-		if (wval)
-			regval &= ~GPMC_CONFIG_WRITEPROTECT; /* WP is ON */
-		else
-			regval |= GPMC_CONFIG_WRITEPROTECT;  /* WP is OFF */
-		gpmc_write_reg(GPMC_CONFIG, regval);
-		break;
-
-	default:
-		pr_err("%s: command not supported\n", __func__);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(gpmc_configure);
-
 void gpmc_get_mem_resource(struct resource *res)
 {
 	res->start =  phys_base;
diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h
index 479ce84..6204913 100644
--- a/arch/arm/mach-omap2/gpmc.h
+++ b/arch/arm/mach-omap2/gpmc.h
@@ -22,9 +22,6 @@
 #define GPMC_CS_CONFIG6		0x14
 #define GPMC_CS_CONFIG7		0x18
 
-/* Control Commands */
-#define GPMC_CONFIG_WP		0x00000005
-
 /* ECC commands */
 #define GPMC_ECC_READ		0 /* Reset Hardware ECC for read */
 #define GPMC_ECC_WRITE		1 /* Reset Hardware ECC for write */
@@ -57,7 +54,6 @@
 
 #define GPMC_DEVICETYPE_NOR		0
 #define GPMC_DEVICETYPE_NAND		2
-#define GPMC_CONFIG_WRITEPROTECT	0x00000010
 #define WR_RD_PIN_MONITORING		0x00600000
 #define GPMC_IRQ_FIFOEVENTENABLE	0x01
 #define GPMC_IRQ_COUNT_EVENT		0x02
@@ -79,7 +75,6 @@ extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
 extern void gpmc_cs_free(int cs);
 extern void omap3_gpmc_save_context(void);
 extern void omap3_gpmc_restore_context(void);
-extern int gpmc_configure(int cmd, int wval);
 extern void gpmc_read_settings_dt(struct device_node *np,
 				  struct gpmc_settings *p);
 
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 120acee..bb41796 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -140,6 +140,9 @@
 #define GPMC_IRQ_FIFOEVENT	BIT(0)
 #define GPMC_IRQ_TERMCOUNT	BIT(1)
 
+/* GPMC_CONFIG register bits */
+#define GPMC_CONFIG_WRITEPROTECT	BIT(4)
+
 /* GPMC register offsets */
 #define GPMC_REVISION		0x00
 #define GPMC_SYSCONFIG		0x10
@@ -206,6 +209,22 @@ struct omap_nand_info {
 };
 
 /**
+ * omap_nand_writeprotect - Control the WP line to the NAND chip
+ */
+static void omap_nand_writeprotect(struct omap_nand_info *info, bool on)
+{
+	u32 val;
+
+	val = readl(info->reg.gpmc_config);
+	if (on)
+		val |= GPMC_CONFIG_WRITEPROTECT;
+	else
+		val &= GPMC_CONFIG_WRITEPROTECT;
+
+	writel(val, info->reg.gpmc_config);
+}
+
+/**
  * omap_prefetch_enable - configures and starts prefetch transfer
  * @cs: cs (chip select) number
  * @fifo_th: fifo threshold to be used for read/ write
@@ -1622,6 +1641,7 @@ static void gpmc_update_nand_reg(struct omap_nand_info *info)
 	int cs = info->gpmc_cs;
 	void __iomem *gpmc_base = info->gpmc_base;
 
+	reg->gpmc_config = gpmc_base + GPMC_CONFIG;
 	reg->gpmc_status = gpmc_base + GPMC_STATUS;
 	reg->gpmc_irqstatus = gpmc_base + GPMC_IRQSTATUS;
 	reg->gpmc_irqenable = gpmc_base + GPMC_IRQENABLE;
@@ -2029,6 +2049,9 @@ static int omap_nand_probe(struct platform_device *pdev)
 		goto return_error;
 	}
 
+	/* turn off write protect */
+	omap_nand_writeprotect(info, false);
+
 	/* second phase scan */
 	if (nand_scan_tail(mtd)) {
 		err = -ENXIO;
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h
index b71cfbdb6..62a855e 100644
--- a/include/linux/platform_data/mtd-nand-omap2.h
+++ b/include/linux/platform_data/mtd-nand-omap2.h
@@ -34,6 +34,7 @@ enum omap_ecc {
 };
 
 struct gpmc_nand_regs {
+	void __iomem	*gpmc_config;
 	void __iomem	*gpmc_status;
 	void __iomem	*gpmc_irqstatus;
 	void __iomem	*gpmc_irqenable;
-- 
1.8.3.2

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

* [PATCH 08/36] mtd: nand: omap: Copy platform data parameters to omap_nand_info data
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Copy all the platform data parameters to the driver's local data
structure 'omap_nand_info' and use it in the entire driver. This will
make it easer for device tree migration.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/mtd/nand/omap2.c | 27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index bb41796..e205863 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -184,15 +184,19 @@ static struct nand_ecclayout omap_oobinfo;
 
 struct omap_nand_info {
 	struct nand_hw_control		controller;
-	struct omap_nand_platform_data	*pdata;
 	struct mtd_info			mtd;
 	struct nand_chip		nand;
 	struct platform_device		*pdev;
 
 	int				gpmc_cs;
+	bool				dev_ready;
+	enum nand_io			xfer_type;
+	int				devsize;
+	enum omap_ecc			ecc_opt;
+	struct device_node		*elm_of_node;
+
 	unsigned long			phys_base;
 	void __iomem			*gpmc_base;
-	enum omap_ecc			ecc_opt;
 	struct completion		comp;
 	struct dma_chan			*dma;
 	int				gpmc_irq;
@@ -1708,6 +1712,11 @@ static int omap_nand_probe(struct platform_device *pdev)
 	info->gpmc_cs		= pdata->cs;
 	info->of_node		= pdata->of_node;
 	info->ecc_opt		= pdata->ecc_opt;
+	info->dev_ready	= pdata->dev_ready;
+	info->xfer_type = pdata->xfer_type;
+	info->devsize = pdata->devsize;
+	info->elm_of_node = pdata->elm_of_node;
+
 	mtd			= &info->mtd;
 	mtd->priv		= &info->nand;
 	mtd->name		= dev_name(&pdev->dev);
@@ -1762,7 +1771,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 	 * chip delay which is slightly more than tR (AC Timing) of the NAND
 	 * device and read status register until you get a failure or success
 	 */
-	if (pdata->dev_ready) {
+	if (info->dev_ready) {
 		nand_chip->dev_ready = omap_dev_ready;
 		nand_chip->chip_delay = 0;
 	} else {
@@ -1771,7 +1780,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 	}
 
 	/* scan NAND device connected to chip controller */
-	nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16;
+	nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
 	if (nand_scan_ident(mtd, 1, NULL)) {
 		pr_err("nand device scan failed, may be bus-width mismatch\n");
 		err = -ENXIO;
@@ -1779,14 +1788,14 @@ static int omap_nand_probe(struct platform_device *pdev)
 	}
 
 	/* check for small page devices */
-	if ((mtd->oobsize < 64) && (pdata->ecc_opt != OMAP_ECC_HAM1_CODE_HW)) {
+	if ((mtd->oobsize < 64) && (info->ecc_opt != OMAP_ECC_HAM1_CODE_HW)) {
 		pr_err("small page devices are not supported\n");
 		err = -EINVAL;
 		goto return_error;
 	}
 
 	/* re-populate low-level callbacks based on xfer modes */
-	switch (pdata->xfer_type) {
+	switch (info->xfer_type) {
 	case NAND_OMAP_PREFETCH_POLLED:
 		nand_chip->read_buf   = omap_read_buf_pref;
 		nand_chip->write_buf  = omap_write_buf_pref;
@@ -1849,7 +1858,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 
 	default:
 		dev_err(&pdev->dev,
-			"xfer_type(%d) not supported!\n", pdata->xfer_type);
+			"xfer_type(%d) not supported!\n", info->xfer_type);
 		err = -EINVAL;
 		goto return_error;
 	}
@@ -1945,7 +1954,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 		ecclayout->oobfree->offset	=
 				ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
 		/* This ECC scheme requires ELM H/W block */
-		if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) {
+		if (is_elm_present(info, info->elm_of_node, BCH4_ECC) < 0) {
 			pr_err("nand: error: could not initialize ELM\n");
 			err = -ENODEV;
 			goto return_error;
@@ -2011,7 +2020,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 		nand_chip->ecc.read_page	= omap_read_page_bch;
 		nand_chip->ecc.write_page	= omap_write_page_bch;
 		/* This ECC scheme requires ELM H/W block */
-		err = is_elm_present(info, pdata->elm_of_node, BCH8_ECC);
+		err = is_elm_present(info, info->elm_of_node, BCH8_ECC);
 		if (err < 0) {
 			pr_err("nand: error: could not initialize ELM\n");
 			goto return_error;
-- 
1.8.3.2


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

* [PATCH 08/36] mtd: nand: omap: Copy platform data parameters to omap_nand_info data
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Copy all the platform data parameters to the driver's local data
structure 'omap_nand_info' and use it in the entire driver. This will
make it easer for device tree migration.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/mtd/nand/omap2.c | 27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index bb41796..e205863 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -184,15 +184,19 @@ static struct nand_ecclayout omap_oobinfo;
 
 struct omap_nand_info {
 	struct nand_hw_control		controller;
-	struct omap_nand_platform_data	*pdata;
 	struct mtd_info			mtd;
 	struct nand_chip		nand;
 	struct platform_device		*pdev;
 
 	int				gpmc_cs;
+	bool				dev_ready;
+	enum nand_io			xfer_type;
+	int				devsize;
+	enum omap_ecc			ecc_opt;
+	struct device_node		*elm_of_node;
+
 	unsigned long			phys_base;
 	void __iomem			*gpmc_base;
-	enum omap_ecc			ecc_opt;
 	struct completion		comp;
 	struct dma_chan			*dma;
 	int				gpmc_irq;
@@ -1708,6 +1712,11 @@ static int omap_nand_probe(struct platform_device *pdev)
 	info->gpmc_cs		= pdata->cs;
 	info->of_node		= pdata->of_node;
 	info->ecc_opt		= pdata->ecc_opt;
+	info->dev_ready	= pdata->dev_ready;
+	info->xfer_type = pdata->xfer_type;
+	info->devsize = pdata->devsize;
+	info->elm_of_node = pdata->elm_of_node;
+
 	mtd			= &info->mtd;
 	mtd->priv		= &info->nand;
 	mtd->name		= dev_name(&pdev->dev);
@@ -1762,7 +1771,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 	 * chip delay which is slightly more than tR (AC Timing) of the NAND
 	 * device and read status register until you get a failure or success
 	 */
-	if (pdata->dev_ready) {
+	if (info->dev_ready) {
 		nand_chip->dev_ready = omap_dev_ready;
 		nand_chip->chip_delay = 0;
 	} else {
@@ -1771,7 +1780,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 	}
 
 	/* scan NAND device connected to chip controller */
-	nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16;
+	nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
 	if (nand_scan_ident(mtd, 1, NULL)) {
 		pr_err("nand device scan failed, may be bus-width mismatch\n");
 		err = -ENXIO;
@@ -1779,14 +1788,14 @@ static int omap_nand_probe(struct platform_device *pdev)
 	}
 
 	/* check for small page devices */
-	if ((mtd->oobsize < 64) && (pdata->ecc_opt != OMAP_ECC_HAM1_CODE_HW)) {
+	if ((mtd->oobsize < 64) && (info->ecc_opt != OMAP_ECC_HAM1_CODE_HW)) {
 		pr_err("small page devices are not supported\n");
 		err = -EINVAL;
 		goto return_error;
 	}
 
 	/* re-populate low-level callbacks based on xfer modes */
-	switch (pdata->xfer_type) {
+	switch (info->xfer_type) {
 	case NAND_OMAP_PREFETCH_POLLED:
 		nand_chip->read_buf   = omap_read_buf_pref;
 		nand_chip->write_buf  = omap_write_buf_pref;
@@ -1849,7 +1858,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 
 	default:
 		dev_err(&pdev->dev,
-			"xfer_type(%d) not supported!\n", pdata->xfer_type);
+			"xfer_type(%d) not supported!\n", info->xfer_type);
 		err = -EINVAL;
 		goto return_error;
 	}
@@ -1945,7 +1954,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 		ecclayout->oobfree->offset	=
 				ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
 		/* This ECC scheme requires ELM H/W block */
-		if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) {
+		if (is_elm_present(info, info->elm_of_node, BCH4_ECC) < 0) {
 			pr_err("nand: error: could not initialize ELM\n");
 			err = -ENODEV;
 			goto return_error;
@@ -2011,7 +2020,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 		nand_chip->ecc.read_page	= omap_read_page_bch;
 		nand_chip->ecc.write_page	= omap_write_page_bch;
 		/* This ECC scheme requires ELM H/W block */
-		err = is_elm_present(info, pdata->elm_of_node, BCH8_ECC);
+		err = is_elm_present(info, info->elm_of_node, BCH8_ECC);
 		if (err < 0) {
 			pr_err("nand: error: could not initialize ELM\n");
 			goto return_error;
-- 
1.8.3.2


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

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

* [PATCH 08/36] mtd: nand: omap: Copy platform data parameters to omap_nand_info data
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Copy all the platform data parameters to the driver's local data
structure 'omap_nand_info' and use it in the entire driver. This will
make it easer for device tree migration.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/mtd/nand/omap2.c | 27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index bb41796..e205863 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -184,15 +184,19 @@ static struct nand_ecclayout omap_oobinfo;
 
 struct omap_nand_info {
 	struct nand_hw_control		controller;
-	struct omap_nand_platform_data	*pdata;
 	struct mtd_info			mtd;
 	struct nand_chip		nand;
 	struct platform_device		*pdev;
 
 	int				gpmc_cs;
+	bool				dev_ready;
+	enum nand_io			xfer_type;
+	int				devsize;
+	enum omap_ecc			ecc_opt;
+	struct device_node		*elm_of_node;
+
 	unsigned long			phys_base;
 	void __iomem			*gpmc_base;
-	enum omap_ecc			ecc_opt;
 	struct completion		comp;
 	struct dma_chan			*dma;
 	int				gpmc_irq;
@@ -1708,6 +1712,11 @@ static int omap_nand_probe(struct platform_device *pdev)
 	info->gpmc_cs		= pdata->cs;
 	info->of_node		= pdata->of_node;
 	info->ecc_opt		= pdata->ecc_opt;
+	info->dev_ready	= pdata->dev_ready;
+	info->xfer_type = pdata->xfer_type;
+	info->devsize = pdata->devsize;
+	info->elm_of_node = pdata->elm_of_node;
+
 	mtd			= &info->mtd;
 	mtd->priv		= &info->nand;
 	mtd->name		= dev_name(&pdev->dev);
@@ -1762,7 +1771,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 	 * chip delay which is slightly more than tR (AC Timing) of the NAND
 	 * device and read status register until you get a failure or success
 	 */
-	if (pdata->dev_ready) {
+	if (info->dev_ready) {
 		nand_chip->dev_ready = omap_dev_ready;
 		nand_chip->chip_delay = 0;
 	} else {
@@ -1771,7 +1780,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 	}
 
 	/* scan NAND device connected to chip controller */
-	nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16;
+	nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
 	if (nand_scan_ident(mtd, 1, NULL)) {
 		pr_err("nand device scan failed, may be bus-width mismatch\n");
 		err = -ENXIO;
@@ -1779,14 +1788,14 @@ static int omap_nand_probe(struct platform_device *pdev)
 	}
 
 	/* check for small page devices */
-	if ((mtd->oobsize < 64) && (pdata->ecc_opt != OMAP_ECC_HAM1_CODE_HW)) {
+	if ((mtd->oobsize < 64) && (info->ecc_opt != OMAP_ECC_HAM1_CODE_HW)) {
 		pr_err("small page devices are not supported\n");
 		err = -EINVAL;
 		goto return_error;
 	}
 
 	/* re-populate low-level callbacks based on xfer modes */
-	switch (pdata->xfer_type) {
+	switch (info->xfer_type) {
 	case NAND_OMAP_PREFETCH_POLLED:
 		nand_chip->read_buf   = omap_read_buf_pref;
 		nand_chip->write_buf  = omap_write_buf_pref;
@@ -1849,7 +1858,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 
 	default:
 		dev_err(&pdev->dev,
-			"xfer_type(%d) not supported!\n", pdata->xfer_type);
+			"xfer_type(%d) not supported!\n", info->xfer_type);
 		err = -EINVAL;
 		goto return_error;
 	}
@@ -1945,7 +1954,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 		ecclayout->oobfree->offset	=
 				ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
 		/* This ECC scheme requires ELM H/W block */
-		if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) {
+		if (is_elm_present(info, info->elm_of_node, BCH4_ECC) < 0) {
 			pr_err("nand: error: could not initialize ELM\n");
 			err = -ENODEV;
 			goto return_error;
@@ -2011,7 +2020,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 		nand_chip->ecc.read_page	= omap_read_page_bch;
 		nand_chip->ecc.write_page	= omap_write_page_bch;
 		/* This ECC scheme requires ELM H/W block */
-		err = is_elm_present(info, pdata->elm_of_node, BCH8_ECC);
+		err = is_elm_present(info, info->elm_of_node, BCH8_ECC);
 		if (err < 0) {
 			pr_err("nand: error: could not initialize ELM\n");
 			goto return_error;
-- 
1.8.3.2

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

* [PATCH 09/36] mtd: nand: omap: Clean up device tree support
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Move NAND specific device tree parsing to NAND driver.

The NAND controller node must have a compatible id, register space
resource and interrupt resource.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-nand.c              |   5 +-
 arch/arm/mach-omap2/gpmc.c                   | 128 ++++++---------------------
 drivers/mtd/nand/omap2.c                     | 125 ++++++++++++++++++++++----
 include/linux/platform_data/mtd-nand-omap2.h |   6 +-
 4 files changed, 139 insertions(+), 125 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index 9649fd9..f7491d0 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -127,10 +127,7 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 		}
 	}
 
-	if (gpmc_nand_data->of_node)
-		gpmc_read_settings_dt(gpmc_nand_data->of_node, &s);
-	else
-		gpmc_set_legacy(gpmc_nand_data, &s);
+	gpmc_set_legacy(gpmc_nand_data, &s);
 
 	s.device_nand = true;
 
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index a0c2194..c713616 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -29,7 +29,6 @@
 #include <linux/of_address.h>
 #include <linux/of_mtd.h>
 #include <linux/of_device.h>
-#include <linux/mtd/nand.h>
 #include <linux/pm_runtime.h>
 
 #include <linux/platform_data/mtd-nand-omap2.h>
@@ -40,7 +39,6 @@
 #include "common.h"
 #include "omap_device.h"
 #include "gpmc.h"
-#include "gpmc-nand.h"
 #include "gpmc-onenand.h"
 
 #define	DEVICE_NAME		"omap-gpmc"
@@ -1168,96 +1166,6 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
 		of_property_read_bool(np, "gpmc,time-para-granularity");
 }
 
-#if IS_ENABLED(CONFIG_MTD_NAND)
-
-static const char * const nand_xfer_types[] = {
-	[NAND_OMAP_PREFETCH_POLLED]		= "prefetch-polled",
-	[NAND_OMAP_POLLED]			= "polled",
-	[NAND_OMAP_PREFETCH_DMA]		= "prefetch-dma",
-	[NAND_OMAP_PREFETCH_IRQ]		= "prefetch-irq",
-};
-
-static int gpmc_probe_nand_child(struct platform_device *pdev,
-				 struct device_node *child)
-{
-	u32 val;
-	const char *s;
-	struct gpmc_timings gpmc_t;
-	struct omap_nand_platform_data *gpmc_nand_data;
-
-	if (of_property_read_u32(child, "reg", &val) < 0) {
-		dev_err(&pdev->dev, "%s has no 'reg' property\n",
-			child->full_name);
-		return -ENODEV;
-	}
-
-	gpmc_nand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_nand_data),
-				      GFP_KERNEL);
-	if (!gpmc_nand_data)
-		return -ENOMEM;
-
-	gpmc_nand_data->cs = val;
-	gpmc_nand_data->of_node = child;
-
-	/* Detect availability of ELM module */
-	gpmc_nand_data->elm_of_node = of_parse_phandle(child, "ti,elm-id", 0);
-	if (gpmc_nand_data->elm_of_node == NULL)
-		gpmc_nand_data->elm_of_node =
-					of_parse_phandle(child, "elm_id", 0);
-	if (gpmc_nand_data->elm_of_node == NULL)
-		pr_warn("%s: ti,elm-id property not found\n", __func__);
-
-	/* select ecc-scheme for NAND */
-	if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) {
-		pr_err("%s: ti,nand-ecc-opt not found\n", __func__);
-		return -ENODEV;
-	}
-	if (!strcmp(s, "ham1") || !strcmp(s, "sw") ||
-		!strcmp(s, "hw") || !strcmp(s, "hw-romcode"))
-		gpmc_nand_data->ecc_opt =
-				OMAP_ECC_HAM1_CODE_HW;
-	else if (!strcmp(s, "bch4"))
-		if (gpmc_nand_data->elm_of_node)
-			gpmc_nand_data->ecc_opt =
-				OMAP_ECC_BCH4_CODE_HW;
-		else
-			gpmc_nand_data->ecc_opt =
-				OMAP_ECC_BCH4_CODE_HW_DETECTION_SW;
-	else if (!strcmp(s, "bch8"))
-		if (gpmc_nand_data->elm_of_node)
-			gpmc_nand_data->ecc_opt =
-				OMAP_ECC_BCH8_CODE_HW;
-		else
-			gpmc_nand_data->ecc_opt =
-				OMAP_ECC_BCH8_CODE_HW_DETECTION_SW;
-	else
-		pr_err("%s: ti,nand-ecc-opt invalid value\n", __func__);
-
-	/* select data transfer mode for NAND controller */
-	if (!of_property_read_string(child, "ti,nand-xfer-type", &s))
-		for (val = 0; val < ARRAY_SIZE(nand_xfer_types); val++)
-			if (!strcasecmp(s, nand_xfer_types[val])) {
-				gpmc_nand_data->xfer_type = val;
-				break;
-			}
-
-	val = of_get_nand_bus_width(child);
-	if (val == 16)
-		gpmc_nand_data->devsize = NAND_BUSWIDTH_16;
-
-	gpmc_read_timings_dt(child, &gpmc_t);
-	gpmc_nand_init(gpmc_nand_data, &gpmc_t);
-
-	return 0;
-}
-#else
-static int gpmc_probe_nand_child(struct platform_device *pdev,
-				 struct device_node *child)
-{
-	return 0;
-}
-#endif
-
 #if IS_ENABLED(CONFIG_MTD_ONENAND)
 static int gpmc_probe_onenand_child(struct platform_device *pdev,
 				 struct device_node *child)
@@ -1363,9 +1271,32 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
 
 	gpmc_read_settings_dt(child, &gpmc_s);
 
-	ret = of_property_read_u32(child, "bank-width", &gpmc_s.device_width);
-	if (ret < 0)
-		goto err;
+	if (of_node_cmp(child->name, "nand") == 0) {
+		/* NAND specific setup */
+		u32 val;
+
+		val = of_get_nand_bus_width(child);
+		switch (val) {
+		case 8:
+			gpmc_s.device_width = GPMC_DEVWIDTH_8BIT;
+			break;
+		case 16:
+			gpmc_s.device_width = GPMC_DEVWIDTH_16BIT;
+			break;
+		default:
+			dev_err(&pdev->dev, "%s: invalid 'nand-bus-width'\n",
+				child->name);
+			ret = -EINVAL;
+			goto err;
+		}
+
+		gpmc_s.device_nand = true;
+	} else {
+		ret = of_property_read_u32(child, "bank-width",
+					   &gpmc_s.device_width);
+		if (ret < 0)
+			goto err;
+	}
 
 	ret = gpmc_cs_program_settings(cs, &gpmc_s);
 	if (ret < 0)
@@ -1423,13 +1354,12 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 		if (!child->name)
 			continue;
 
-		if (of_node_cmp(child->name, "nand") == 0)
-			ret = gpmc_probe_nand_child(pdev, child);
-		else if (of_node_cmp(child->name, "onenand") == 0)
+		if (of_node_cmp(child->name, "onenand") == 0)
 			ret = gpmc_probe_onenand_child(pdev, child);
 		else if (of_node_cmp(child->name, "ethernet") == 0 ||
 			 of_node_cmp(child->name, "nor") == 0 ||
-			 of_node_cmp(child->name, "uart") == 0)
+			 of_node_cmp(child->name, "uart") == 0 ||
+			 of_node_cmp(child->name, "nand") == 0)
 			ret = gpmc_probe_generic_child(pdev, child);
 
 		if (WARN(ret < 0, "%s: probing gpmc child %s failed\n",
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index e205863..d343552 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/of_mtd.h>
 
 #include <linux/mtd/nand_bch.h>
 #include <linux/platform_data/elm.h>
@@ -1676,10 +1677,82 @@ static void gpmc_update_nand_reg(struct omap_nand_info *info)
 	}
 }
 
+static const char * const nand_xfer_types[] = {
+	[NAND_OMAP_PREFETCH_POLLED] = "prefetch-polled",
+	[NAND_OMAP_POLLED] = "polled",
+	[NAND_OMAP_PREFETCH_DMA] = "prefetch-dma",
+	[NAND_OMAP_PREFETCH_IRQ] = "prefetch-irq",
+};
+
+static int omap_get_dt_info(struct device *dev, struct omap_nand_info *info)
+{
+	struct device_node *child = dev->of_node;
+	int i;
+	const char *s;
+
+	/* In old bindings, CS num is embedded in reg property */
+	if (of_property_read_u32(child, "reg", &info->gpmc_cs) < 0) {
+		dev_err(dev, "reg not found in DT\n");
+		return -EINVAL;
+	}
+
+	/* detect availability of ELM module. Won't be present pre-OMAP4 */
+	info->elm_of_node = of_parse_phandle(child, "ti,elm-id", 0);
+	if (info->elm_of_node == NULL)
+		dev_dbg(dev, "ti,elm-id not in DT\n");
+
+	/* select ecc-scheme */
+	if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) {
+		/* default to HAM1 */
+		info->ecc_opt = OMAP_ECC_HAM1_CODE_HW;
+		goto ecc_done;
+	}
+
+	if (!strcmp(s, "ham1") || !strcmp(s, "sw") ||
+	    !strcmp(s, "hw") || !strcmp(s, "hw-romcode")) {
+		info->ecc_opt = OMAP_ECC_HAM1_CODE_HW;
+
+	} else if (!strcmp(s, "bch4")) {
+		if (info->elm_of_node)
+			info->ecc_opt = OMAP_ECC_BCH4_CODE_HW;
+		else
+			info->ecc_opt = OMAP_ECC_BCH4_CODE_HW_DETECTION_SW;
+
+	} else if (!strcmp(s, "bch8")) {
+		if (info->elm_of_node)
+			info->ecc_opt = OMAP_ECC_BCH8_CODE_HW;
+		else
+			info->ecc_opt = OMAP_ECC_BCH8_CODE_HW_DETECTION_SW;
+	} else {
+		dev_err(dev, "unrecognized value for ti,nand-ecc-opt\n");
+		return -EINVAL;
+	}
+
+ecc_done:
+	/* select data transfer mode */
+	if (!of_property_read_string(child, "ti,nand-xfer-type", &s)) {
+		for (i = 0; i < ARRAY_SIZE(nand_xfer_types); i++) {
+			if (!strcasecmp(s, nand_xfer_types[i])) {
+				info->xfer_type = i;
+				goto found;
+			}
+		}
+
+		dev_err(dev, "unrecognized value for ti,nand-xfer-type\n");
+		return -EINVAL;
+	}
+
+found:
+	if (of_get_nand_bus_width(child) == 16)
+		info->devsize = NAND_BUSWIDTH_16;
+
+	return 0;
+}
+
 static int omap_nand_probe(struct platform_device *pdev)
 {
 	struct omap_nand_info *info;
-	struct omap_nand_platform_data *pdata;
+	struct omap_nand_platform_data *pdata = NULL;
 	struct mtd_info	*mtd;
 	struct nand_chip *nand_chip;
 	struct nand_ecclayout *ecclayout;
@@ -1692,31 +1765,37 @@ static int omap_nand_probe(struct platform_device *pdev)
 	struct mtd_part_parser_data ppdata = {};
 	struct device *dev = &pdev->dev;
 
-	pdata = dev_get_platdata(&pdev->dev);
-	if (pdata == NULL) {
-		dev_err(&pdev->dev, "platform data missing\n");
-		return -ENODEV;
-	}
 
 	info = devm_kzalloc(&pdev->dev, sizeof(struct omap_nand_info),
 				GFP_KERNEL);
 	if (!info)
 		return -ENOMEM;
 
+	info->pdev = pdev;
+
+	if (dev->of_node) {
+		if (omap_get_dt_info(dev, info))
+			return -EINVAL;
+	} else {
+		pdata = dev_get_platdata(&pdev->dev);
+		if (pdata == NULL) {
+			dev_err(&pdev->dev, "platform data missing\n");
+			return -EINVAL;
+		}
+
+		info->gpmc_cs = pdata->cs;
+		info->of_node = pdata->of_node;
+		info->ecc_opt = pdata->ecc_opt;
+		info->dev_ready	= pdata->dev_ready;
+		info->xfer_type = pdata->xfer_type;
+		info->devsize = pdata->devsize;
+	}
+
 	platform_set_drvdata(pdev, info);
 
 	spin_lock_init(&info->controller.lock);
 	init_waitqueue_head(&info->controller.wq);
 
-	info->pdev		= pdev;
-	info->gpmc_cs		= pdata->cs;
-	info->of_node		= pdata->of_node;
-	info->ecc_opt		= pdata->ecc_opt;
-	info->dev_ready	= pdata->dev_ready;
-	info->xfer_type = pdata->xfer_type;
-	info->devsize = pdata->devsize;
-	info->elm_of_node = pdata->elm_of_node;
-
 	mtd			= &info->mtd;
 	mtd->priv		= &info->nand;
 	mtd->name		= dev_name(&pdev->dev);
@@ -2067,9 +2146,13 @@ static int omap_nand_probe(struct platform_device *pdev)
 		goto return_error;
 	}
 
-	ppdata.of_node = pdata->of_node;
-	mtd_device_parse_register(mtd, NULL, &ppdata, pdata->parts,
-				  pdata->nr_parts);
+	if (dev->of_node) {
+		ppdata.of_node = dev->of_node;
+		mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
+
+	} else {
+		mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
+	}
 
 	platform_set_drvdata(pdev, mtd);
 
@@ -2101,12 +2184,18 @@ static int omap_nand_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct of_device_id omap_nand_ids[] = {
+	{ .compatible = "ti,omap2-nand", },
+	{},
+};
+
 static struct platform_driver omap_nand_driver = {
 	.probe		= omap_nand_probe,
 	.remove		= omap_nand_remove,
 	.driver		= {
 		.name	= DRIVER_NAME,
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(omap_nand_ids),
 	},
 };
 
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h
index 62a855e..45203a5 100644
--- a/include/linux/platform_data/mtd-nand-omap2.h
+++ b/include/linux/platform_data/mtd-nand-omap2.h
@@ -64,10 +64,8 @@ struct omap_nand_platform_data {
 	int			devsize;
 	enum omap_ecc           ecc_opt;
 
-	/* for passing the partitions */
-	struct device_node	*of_node;
-	struct device_node	*elm_of_node;
-
 	struct gpmc_nand_regs	reg;		/* deprecated */
+	struct device_node	*elm_of_node;	/* deprecated */
+	struct device_node	*of_node;	/* deprecated */
 };
 #endif
-- 
1.8.3.2


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

* [PATCH 09/36] mtd: nand: omap: Clean up device tree support
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Move NAND specific device tree parsing to NAND driver.

The NAND controller node must have a compatible id, register space
resource and interrupt resource.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-nand.c              |   5 +-
 arch/arm/mach-omap2/gpmc.c                   | 128 ++++++---------------------
 drivers/mtd/nand/omap2.c                     | 125 ++++++++++++++++++++++----
 include/linux/platform_data/mtd-nand-omap2.h |   6 +-
 4 files changed, 139 insertions(+), 125 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index 9649fd9..f7491d0 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -127,10 +127,7 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 		}
 	}
 
-	if (gpmc_nand_data->of_node)
-		gpmc_read_settings_dt(gpmc_nand_data->of_node, &s);
-	else
-		gpmc_set_legacy(gpmc_nand_data, &s);
+	gpmc_set_legacy(gpmc_nand_data, &s);
 
 	s.device_nand = true;
 
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index a0c2194..c713616 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -29,7 +29,6 @@
 #include <linux/of_address.h>
 #include <linux/of_mtd.h>
 #include <linux/of_device.h>
-#include <linux/mtd/nand.h>
 #include <linux/pm_runtime.h>
 
 #include <linux/platform_data/mtd-nand-omap2.h>
@@ -40,7 +39,6 @@
 #include "common.h"
 #include "omap_device.h"
 #include "gpmc.h"
-#include "gpmc-nand.h"
 #include "gpmc-onenand.h"
 
 #define	DEVICE_NAME		"omap-gpmc"
@@ -1168,96 +1166,6 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
 		of_property_read_bool(np, "gpmc,time-para-granularity");
 }
 
-#if IS_ENABLED(CONFIG_MTD_NAND)
-
-static const char * const nand_xfer_types[] = {
-	[NAND_OMAP_PREFETCH_POLLED]		= "prefetch-polled",
-	[NAND_OMAP_POLLED]			= "polled",
-	[NAND_OMAP_PREFETCH_DMA]		= "prefetch-dma",
-	[NAND_OMAP_PREFETCH_IRQ]		= "prefetch-irq",
-};
-
-static int gpmc_probe_nand_child(struct platform_device *pdev,
-				 struct device_node *child)
-{
-	u32 val;
-	const char *s;
-	struct gpmc_timings gpmc_t;
-	struct omap_nand_platform_data *gpmc_nand_data;
-
-	if (of_property_read_u32(child, "reg", &val) < 0) {
-		dev_err(&pdev->dev, "%s has no 'reg' property\n",
-			child->full_name);
-		return -ENODEV;
-	}
-
-	gpmc_nand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_nand_data),
-				      GFP_KERNEL);
-	if (!gpmc_nand_data)
-		return -ENOMEM;
-
-	gpmc_nand_data->cs = val;
-	gpmc_nand_data->of_node = child;
-
-	/* Detect availability of ELM module */
-	gpmc_nand_data->elm_of_node = of_parse_phandle(child, "ti,elm-id", 0);
-	if (gpmc_nand_data->elm_of_node == NULL)
-		gpmc_nand_data->elm_of_node =
-					of_parse_phandle(child, "elm_id", 0);
-	if (gpmc_nand_data->elm_of_node == NULL)
-		pr_warn("%s: ti,elm-id property not found\n", __func__);
-
-	/* select ecc-scheme for NAND */
-	if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) {
-		pr_err("%s: ti,nand-ecc-opt not found\n", __func__);
-		return -ENODEV;
-	}
-	if (!strcmp(s, "ham1") || !strcmp(s, "sw") ||
-		!strcmp(s, "hw") || !strcmp(s, "hw-romcode"))
-		gpmc_nand_data->ecc_opt =
-				OMAP_ECC_HAM1_CODE_HW;
-	else if (!strcmp(s, "bch4"))
-		if (gpmc_nand_data->elm_of_node)
-			gpmc_nand_data->ecc_opt =
-				OMAP_ECC_BCH4_CODE_HW;
-		else
-			gpmc_nand_data->ecc_opt =
-				OMAP_ECC_BCH4_CODE_HW_DETECTION_SW;
-	else if (!strcmp(s, "bch8"))
-		if (gpmc_nand_data->elm_of_node)
-			gpmc_nand_data->ecc_opt =
-				OMAP_ECC_BCH8_CODE_HW;
-		else
-			gpmc_nand_data->ecc_opt =
-				OMAP_ECC_BCH8_CODE_HW_DETECTION_SW;
-	else
-		pr_err("%s: ti,nand-ecc-opt invalid value\n", __func__);
-
-	/* select data transfer mode for NAND controller */
-	if (!of_property_read_string(child, "ti,nand-xfer-type", &s))
-		for (val = 0; val < ARRAY_SIZE(nand_xfer_types); val++)
-			if (!strcasecmp(s, nand_xfer_types[val])) {
-				gpmc_nand_data->xfer_type = val;
-				break;
-			}
-
-	val = of_get_nand_bus_width(child);
-	if (val == 16)
-		gpmc_nand_data->devsize = NAND_BUSWIDTH_16;
-
-	gpmc_read_timings_dt(child, &gpmc_t);
-	gpmc_nand_init(gpmc_nand_data, &gpmc_t);
-
-	return 0;
-}
-#else
-static int gpmc_probe_nand_child(struct platform_device *pdev,
-				 struct device_node *child)
-{
-	return 0;
-}
-#endif
-
 #if IS_ENABLED(CONFIG_MTD_ONENAND)
 static int gpmc_probe_onenand_child(struct platform_device *pdev,
 				 struct device_node *child)
@@ -1363,9 +1271,32 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
 
 	gpmc_read_settings_dt(child, &gpmc_s);
 
-	ret = of_property_read_u32(child, "bank-width", &gpmc_s.device_width);
-	if (ret < 0)
-		goto err;
+	if (of_node_cmp(child->name, "nand") == 0) {
+		/* NAND specific setup */
+		u32 val;
+
+		val = of_get_nand_bus_width(child);
+		switch (val) {
+		case 8:
+			gpmc_s.device_width = GPMC_DEVWIDTH_8BIT;
+			break;
+		case 16:
+			gpmc_s.device_width = GPMC_DEVWIDTH_16BIT;
+			break;
+		default:
+			dev_err(&pdev->dev, "%s: invalid 'nand-bus-width'\n",
+				child->name);
+			ret = -EINVAL;
+			goto err;
+		}
+
+		gpmc_s.device_nand = true;
+	} else {
+		ret = of_property_read_u32(child, "bank-width",
+					   &gpmc_s.device_width);
+		if (ret < 0)
+			goto err;
+	}
 
 	ret = gpmc_cs_program_settings(cs, &gpmc_s);
 	if (ret < 0)
@@ -1423,13 +1354,12 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 		if (!child->name)
 			continue;
 
-		if (of_node_cmp(child->name, "nand") == 0)
-			ret = gpmc_probe_nand_child(pdev, child);
-		else if (of_node_cmp(child->name, "onenand") == 0)
+		if (of_node_cmp(child->name, "onenand") == 0)
 			ret = gpmc_probe_onenand_child(pdev, child);
 		else if (of_node_cmp(child->name, "ethernet") == 0 ||
 			 of_node_cmp(child->name, "nor") == 0 ||
-			 of_node_cmp(child->name, "uart") == 0)
+			 of_node_cmp(child->name, "uart") == 0 ||
+			 of_node_cmp(child->name, "nand") == 0)
 			ret = gpmc_probe_generic_child(pdev, child);
 
 		if (WARN(ret < 0, "%s: probing gpmc child %s failed\n",
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index e205863..d343552 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/of_mtd.h>
 
 #include <linux/mtd/nand_bch.h>
 #include <linux/platform_data/elm.h>
@@ -1676,10 +1677,82 @@ static void gpmc_update_nand_reg(struct omap_nand_info *info)
 	}
 }
 
+static const char * const nand_xfer_types[] = {
+	[NAND_OMAP_PREFETCH_POLLED] = "prefetch-polled",
+	[NAND_OMAP_POLLED] = "polled",
+	[NAND_OMAP_PREFETCH_DMA] = "prefetch-dma",
+	[NAND_OMAP_PREFETCH_IRQ] = "prefetch-irq",
+};
+
+static int omap_get_dt_info(struct device *dev, struct omap_nand_info *info)
+{
+	struct device_node *child = dev->of_node;
+	int i;
+	const char *s;
+
+	/* In old bindings, CS num is embedded in reg property */
+	if (of_property_read_u32(child, "reg", &info->gpmc_cs) < 0) {
+		dev_err(dev, "reg not found in DT\n");
+		return -EINVAL;
+	}
+
+	/* detect availability of ELM module. Won't be present pre-OMAP4 */
+	info->elm_of_node = of_parse_phandle(child, "ti,elm-id", 0);
+	if (info->elm_of_node == NULL)
+		dev_dbg(dev, "ti,elm-id not in DT\n");
+
+	/* select ecc-scheme */
+	if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) {
+		/* default to HAM1 */
+		info->ecc_opt = OMAP_ECC_HAM1_CODE_HW;
+		goto ecc_done;
+	}
+
+	if (!strcmp(s, "ham1") || !strcmp(s, "sw") ||
+	    !strcmp(s, "hw") || !strcmp(s, "hw-romcode")) {
+		info->ecc_opt = OMAP_ECC_HAM1_CODE_HW;
+
+	} else if (!strcmp(s, "bch4")) {
+		if (info->elm_of_node)
+			info->ecc_opt = OMAP_ECC_BCH4_CODE_HW;
+		else
+			info->ecc_opt = OMAP_ECC_BCH4_CODE_HW_DETECTION_SW;
+
+	} else if (!strcmp(s, "bch8")) {
+		if (info->elm_of_node)
+			info->ecc_opt = OMAP_ECC_BCH8_CODE_HW;
+		else
+			info->ecc_opt = OMAP_ECC_BCH8_CODE_HW_DETECTION_SW;
+	} else {
+		dev_err(dev, "unrecognized value for ti,nand-ecc-opt\n");
+		return -EINVAL;
+	}
+
+ecc_done:
+	/* select data transfer mode */
+	if (!of_property_read_string(child, "ti,nand-xfer-type", &s)) {
+		for (i = 0; i < ARRAY_SIZE(nand_xfer_types); i++) {
+			if (!strcasecmp(s, nand_xfer_types[i])) {
+				info->xfer_type = i;
+				goto found;
+			}
+		}
+
+		dev_err(dev, "unrecognized value for ti,nand-xfer-type\n");
+		return -EINVAL;
+	}
+
+found:
+	if (of_get_nand_bus_width(child) == 16)
+		info->devsize = NAND_BUSWIDTH_16;
+
+	return 0;
+}
+
 static int omap_nand_probe(struct platform_device *pdev)
 {
 	struct omap_nand_info *info;
-	struct omap_nand_platform_data *pdata;
+	struct omap_nand_platform_data *pdata = NULL;
 	struct mtd_info	*mtd;
 	struct nand_chip *nand_chip;
 	struct nand_ecclayout *ecclayout;
@@ -1692,31 +1765,37 @@ static int omap_nand_probe(struct platform_device *pdev)
 	struct mtd_part_parser_data ppdata = {};
 	struct device *dev = &pdev->dev;
 
-	pdata = dev_get_platdata(&pdev->dev);
-	if (pdata == NULL) {
-		dev_err(&pdev->dev, "platform data missing\n");
-		return -ENODEV;
-	}
 
 	info = devm_kzalloc(&pdev->dev, sizeof(struct omap_nand_info),
 				GFP_KERNEL);
 	if (!info)
 		return -ENOMEM;
 
+	info->pdev = pdev;
+
+	if (dev->of_node) {
+		if (omap_get_dt_info(dev, info))
+			return -EINVAL;
+	} else {
+		pdata = dev_get_platdata(&pdev->dev);
+		if (pdata == NULL) {
+			dev_err(&pdev->dev, "platform data missing\n");
+			return -EINVAL;
+		}
+
+		info->gpmc_cs = pdata->cs;
+		info->of_node = pdata->of_node;
+		info->ecc_opt = pdata->ecc_opt;
+		info->dev_ready	= pdata->dev_ready;
+		info->xfer_type = pdata->xfer_type;
+		info->devsize = pdata->devsize;
+	}
+
 	platform_set_drvdata(pdev, info);
 
 	spin_lock_init(&info->controller.lock);
 	init_waitqueue_head(&info->controller.wq);
 
-	info->pdev		= pdev;
-	info->gpmc_cs		= pdata->cs;
-	info->of_node		= pdata->of_node;
-	info->ecc_opt		= pdata->ecc_opt;
-	info->dev_ready	= pdata->dev_ready;
-	info->xfer_type = pdata->xfer_type;
-	info->devsize = pdata->devsize;
-	info->elm_of_node = pdata->elm_of_node;
-
 	mtd			= &info->mtd;
 	mtd->priv		= &info->nand;
 	mtd->name		= dev_name(&pdev->dev);
@@ -2067,9 +2146,13 @@ static int omap_nand_probe(struct platform_device *pdev)
 		goto return_error;
 	}
 
-	ppdata.of_node = pdata->of_node;
-	mtd_device_parse_register(mtd, NULL, &ppdata, pdata->parts,
-				  pdata->nr_parts);
+	if (dev->of_node) {
+		ppdata.of_node = dev->of_node;
+		mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
+
+	} else {
+		mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
+	}
 
 	platform_set_drvdata(pdev, mtd);
 
@@ -2101,12 +2184,18 @@ static int omap_nand_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct of_device_id omap_nand_ids[] = {
+	{ .compatible = "ti,omap2-nand", },
+	{},
+};
+
 static struct platform_driver omap_nand_driver = {
 	.probe		= omap_nand_probe,
 	.remove		= omap_nand_remove,
 	.driver		= {
 		.name	= DRIVER_NAME,
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(omap_nand_ids),
 	},
 };
 
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h
index 62a855e..45203a5 100644
--- a/include/linux/platform_data/mtd-nand-omap2.h
+++ b/include/linux/platform_data/mtd-nand-omap2.h
@@ -64,10 +64,8 @@ struct omap_nand_platform_data {
 	int			devsize;
 	enum omap_ecc           ecc_opt;
 
-	/* for passing the partitions */
-	struct device_node	*of_node;
-	struct device_node	*elm_of_node;
-
 	struct gpmc_nand_regs	reg;		/* deprecated */
+	struct device_node	*elm_of_node;	/* deprecated */
+	struct device_node	*of_node;	/* deprecated */
 };
 #endif
-- 
1.8.3.2

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

* [PATCH 09/36] mtd: nand: omap: Clean up device tree support
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Move NAND specific device tree parsing to NAND driver.

The NAND controller node must have a compatible id, register space
resource and interrupt resource.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-nand.c              |   5 +-
 arch/arm/mach-omap2/gpmc.c                   | 128 ++++++---------------------
 drivers/mtd/nand/omap2.c                     | 125 ++++++++++++++++++++++----
 include/linux/platform_data/mtd-nand-omap2.h |   6 +-
 4 files changed, 139 insertions(+), 125 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index 9649fd9..f7491d0 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -127,10 +127,7 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 		}
 	}
 
-	if (gpmc_nand_data->of_node)
-		gpmc_read_settings_dt(gpmc_nand_data->of_node, &s);
-	else
-		gpmc_set_legacy(gpmc_nand_data, &s);
+	gpmc_set_legacy(gpmc_nand_data, &s);
 
 	s.device_nand = true;
 
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index a0c2194..c713616 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -29,7 +29,6 @@
 #include <linux/of_address.h>
 #include <linux/of_mtd.h>
 #include <linux/of_device.h>
-#include <linux/mtd/nand.h>
 #include <linux/pm_runtime.h>
 
 #include <linux/platform_data/mtd-nand-omap2.h>
@@ -40,7 +39,6 @@
 #include "common.h"
 #include "omap_device.h"
 #include "gpmc.h"
-#include "gpmc-nand.h"
 #include "gpmc-onenand.h"
 
 #define	DEVICE_NAME		"omap-gpmc"
@@ -1168,96 +1166,6 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
 		of_property_read_bool(np, "gpmc,time-para-granularity");
 }
 
-#if IS_ENABLED(CONFIG_MTD_NAND)
-
-static const char * const nand_xfer_types[] = {
-	[NAND_OMAP_PREFETCH_POLLED]		= "prefetch-polled",
-	[NAND_OMAP_POLLED]			= "polled",
-	[NAND_OMAP_PREFETCH_DMA]		= "prefetch-dma",
-	[NAND_OMAP_PREFETCH_IRQ]		= "prefetch-irq",
-};
-
-static int gpmc_probe_nand_child(struct platform_device *pdev,
-				 struct device_node *child)
-{
-	u32 val;
-	const char *s;
-	struct gpmc_timings gpmc_t;
-	struct omap_nand_platform_data *gpmc_nand_data;
-
-	if (of_property_read_u32(child, "reg", &val) < 0) {
-		dev_err(&pdev->dev, "%s has no 'reg' property\n",
-			child->full_name);
-		return -ENODEV;
-	}
-
-	gpmc_nand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_nand_data),
-				      GFP_KERNEL);
-	if (!gpmc_nand_data)
-		return -ENOMEM;
-
-	gpmc_nand_data->cs = val;
-	gpmc_nand_data->of_node = child;
-
-	/* Detect availability of ELM module */
-	gpmc_nand_data->elm_of_node = of_parse_phandle(child, "ti,elm-id", 0);
-	if (gpmc_nand_data->elm_of_node == NULL)
-		gpmc_nand_data->elm_of_node =
-					of_parse_phandle(child, "elm_id", 0);
-	if (gpmc_nand_data->elm_of_node == NULL)
-		pr_warn("%s: ti,elm-id property not found\n", __func__);
-
-	/* select ecc-scheme for NAND */
-	if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) {
-		pr_err("%s: ti,nand-ecc-opt not found\n", __func__);
-		return -ENODEV;
-	}
-	if (!strcmp(s, "ham1") || !strcmp(s, "sw") ||
-		!strcmp(s, "hw") || !strcmp(s, "hw-romcode"))
-		gpmc_nand_data->ecc_opt =
-				OMAP_ECC_HAM1_CODE_HW;
-	else if (!strcmp(s, "bch4"))
-		if (gpmc_nand_data->elm_of_node)
-			gpmc_nand_data->ecc_opt =
-				OMAP_ECC_BCH4_CODE_HW;
-		else
-			gpmc_nand_data->ecc_opt =
-				OMAP_ECC_BCH4_CODE_HW_DETECTION_SW;
-	else if (!strcmp(s, "bch8"))
-		if (gpmc_nand_data->elm_of_node)
-			gpmc_nand_data->ecc_opt =
-				OMAP_ECC_BCH8_CODE_HW;
-		else
-			gpmc_nand_data->ecc_opt =
-				OMAP_ECC_BCH8_CODE_HW_DETECTION_SW;
-	else
-		pr_err("%s: ti,nand-ecc-opt invalid value\n", __func__);
-
-	/* select data transfer mode for NAND controller */
-	if (!of_property_read_string(child, "ti,nand-xfer-type", &s))
-		for (val = 0; val < ARRAY_SIZE(nand_xfer_types); val++)
-			if (!strcasecmp(s, nand_xfer_types[val])) {
-				gpmc_nand_data->xfer_type = val;
-				break;
-			}
-
-	val = of_get_nand_bus_width(child);
-	if (val == 16)
-		gpmc_nand_data->devsize = NAND_BUSWIDTH_16;
-
-	gpmc_read_timings_dt(child, &gpmc_t);
-	gpmc_nand_init(gpmc_nand_data, &gpmc_t);
-
-	return 0;
-}
-#else
-static int gpmc_probe_nand_child(struct platform_device *pdev,
-				 struct device_node *child)
-{
-	return 0;
-}
-#endif
-
 #if IS_ENABLED(CONFIG_MTD_ONENAND)
 static int gpmc_probe_onenand_child(struct platform_device *pdev,
 				 struct device_node *child)
@@ -1363,9 +1271,32 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
 
 	gpmc_read_settings_dt(child, &gpmc_s);
 
-	ret = of_property_read_u32(child, "bank-width", &gpmc_s.device_width);
-	if (ret < 0)
-		goto err;
+	if (of_node_cmp(child->name, "nand") == 0) {
+		/* NAND specific setup */
+		u32 val;
+
+		val = of_get_nand_bus_width(child);
+		switch (val) {
+		case 8:
+			gpmc_s.device_width = GPMC_DEVWIDTH_8BIT;
+			break;
+		case 16:
+			gpmc_s.device_width = GPMC_DEVWIDTH_16BIT;
+			break;
+		default:
+			dev_err(&pdev->dev, "%s: invalid 'nand-bus-width'\n",
+				child->name);
+			ret = -EINVAL;
+			goto err;
+		}
+
+		gpmc_s.device_nand = true;
+	} else {
+		ret = of_property_read_u32(child, "bank-width",
+					   &gpmc_s.device_width);
+		if (ret < 0)
+			goto err;
+	}
 
 	ret = gpmc_cs_program_settings(cs, &gpmc_s);
 	if (ret < 0)
@@ -1423,13 +1354,12 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 		if (!child->name)
 			continue;
 
-		if (of_node_cmp(child->name, "nand") == 0)
-			ret = gpmc_probe_nand_child(pdev, child);
-		else if (of_node_cmp(child->name, "onenand") == 0)
+		if (of_node_cmp(child->name, "onenand") == 0)
 			ret = gpmc_probe_onenand_child(pdev, child);
 		else if (of_node_cmp(child->name, "ethernet") == 0 ||
 			 of_node_cmp(child->name, "nor") == 0 ||
-			 of_node_cmp(child->name, "uart") == 0)
+			 of_node_cmp(child->name, "uart") == 0 ||
+			 of_node_cmp(child->name, "nand") == 0)
 			ret = gpmc_probe_generic_child(pdev, child);
 
 		if (WARN(ret < 0, "%s: probing gpmc child %s failed\n",
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index e205863..d343552 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/of_mtd.h>
 
 #include <linux/mtd/nand_bch.h>
 #include <linux/platform_data/elm.h>
@@ -1676,10 +1677,82 @@ static void gpmc_update_nand_reg(struct omap_nand_info *info)
 	}
 }
 
+static const char * const nand_xfer_types[] = {
+	[NAND_OMAP_PREFETCH_POLLED] = "prefetch-polled",
+	[NAND_OMAP_POLLED] = "polled",
+	[NAND_OMAP_PREFETCH_DMA] = "prefetch-dma",
+	[NAND_OMAP_PREFETCH_IRQ] = "prefetch-irq",
+};
+
+static int omap_get_dt_info(struct device *dev, struct omap_nand_info *info)
+{
+	struct device_node *child = dev->of_node;
+	int i;
+	const char *s;
+
+	/* In old bindings, CS num is embedded in reg property */
+	if (of_property_read_u32(child, "reg", &info->gpmc_cs) < 0) {
+		dev_err(dev, "reg not found in DT\n");
+		return -EINVAL;
+	}
+
+	/* detect availability of ELM module. Won't be present pre-OMAP4 */
+	info->elm_of_node = of_parse_phandle(child, "ti,elm-id", 0);
+	if (info->elm_of_node == NULL)
+		dev_dbg(dev, "ti,elm-id not in DT\n");
+
+	/* select ecc-scheme */
+	if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) {
+		/* default to HAM1 */
+		info->ecc_opt = OMAP_ECC_HAM1_CODE_HW;
+		goto ecc_done;
+	}
+
+	if (!strcmp(s, "ham1") || !strcmp(s, "sw") ||
+	    !strcmp(s, "hw") || !strcmp(s, "hw-romcode")) {
+		info->ecc_opt = OMAP_ECC_HAM1_CODE_HW;
+
+	} else if (!strcmp(s, "bch4")) {
+		if (info->elm_of_node)
+			info->ecc_opt = OMAP_ECC_BCH4_CODE_HW;
+		else
+			info->ecc_opt = OMAP_ECC_BCH4_CODE_HW_DETECTION_SW;
+
+	} else if (!strcmp(s, "bch8")) {
+		if (info->elm_of_node)
+			info->ecc_opt = OMAP_ECC_BCH8_CODE_HW;
+		else
+			info->ecc_opt = OMAP_ECC_BCH8_CODE_HW_DETECTION_SW;
+	} else {
+		dev_err(dev, "unrecognized value for ti,nand-ecc-opt\n");
+		return -EINVAL;
+	}
+
+ecc_done:
+	/* select data transfer mode */
+	if (!of_property_read_string(child, "ti,nand-xfer-type", &s)) {
+		for (i = 0; i < ARRAY_SIZE(nand_xfer_types); i++) {
+			if (!strcasecmp(s, nand_xfer_types[i])) {
+				info->xfer_type = i;
+				goto found;
+			}
+		}
+
+		dev_err(dev, "unrecognized value for ti,nand-xfer-type\n");
+		return -EINVAL;
+	}
+
+found:
+	if (of_get_nand_bus_width(child) == 16)
+		info->devsize = NAND_BUSWIDTH_16;
+
+	return 0;
+}
+
 static int omap_nand_probe(struct platform_device *pdev)
 {
 	struct omap_nand_info *info;
-	struct omap_nand_platform_data *pdata;
+	struct omap_nand_platform_data *pdata = NULL;
 	struct mtd_info	*mtd;
 	struct nand_chip *nand_chip;
 	struct nand_ecclayout *ecclayout;
@@ -1692,31 +1765,37 @@ static int omap_nand_probe(struct platform_device *pdev)
 	struct mtd_part_parser_data ppdata = {};
 	struct device *dev = &pdev->dev;
 
-	pdata = dev_get_platdata(&pdev->dev);
-	if (pdata == NULL) {
-		dev_err(&pdev->dev, "platform data missing\n");
-		return -ENODEV;
-	}
 
 	info = devm_kzalloc(&pdev->dev, sizeof(struct omap_nand_info),
 				GFP_KERNEL);
 	if (!info)
 		return -ENOMEM;
 
+	info->pdev = pdev;
+
+	if (dev->of_node) {
+		if (omap_get_dt_info(dev, info))
+			return -EINVAL;
+	} else {
+		pdata = dev_get_platdata(&pdev->dev);
+		if (pdata == NULL) {
+			dev_err(&pdev->dev, "platform data missing\n");
+			return -EINVAL;
+		}
+
+		info->gpmc_cs = pdata->cs;
+		info->of_node = pdata->of_node;
+		info->ecc_opt = pdata->ecc_opt;
+		info->dev_ready	= pdata->dev_ready;
+		info->xfer_type = pdata->xfer_type;
+		info->devsize = pdata->devsize;
+	}
+
 	platform_set_drvdata(pdev, info);
 
 	spin_lock_init(&info->controller.lock);
 	init_waitqueue_head(&info->controller.wq);
 
-	info->pdev		= pdev;
-	info->gpmc_cs		= pdata->cs;
-	info->of_node		= pdata->of_node;
-	info->ecc_opt		= pdata->ecc_opt;
-	info->dev_ready	= pdata->dev_ready;
-	info->xfer_type = pdata->xfer_type;
-	info->devsize = pdata->devsize;
-	info->elm_of_node = pdata->elm_of_node;
-
 	mtd			= &info->mtd;
 	mtd->priv		= &info->nand;
 	mtd->name		= dev_name(&pdev->dev);
@@ -2067,9 +2146,13 @@ static int omap_nand_probe(struct platform_device *pdev)
 		goto return_error;
 	}
 
-	ppdata.of_node = pdata->of_node;
-	mtd_device_parse_register(mtd, NULL, &ppdata, pdata->parts,
-				  pdata->nr_parts);
+	if (dev->of_node) {
+		ppdata.of_node = dev->of_node;
+		mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
+
+	} else {
+		mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
+	}
 
 	platform_set_drvdata(pdev, mtd);
 
@@ -2101,12 +2184,18 @@ static int omap_nand_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct of_device_id omap_nand_ids[] = {
+	{ .compatible = "ti,omap2-nand", },
+	{},
+};
+
 static struct platform_driver omap_nand_driver = {
 	.probe		= omap_nand_probe,
 	.remove		= omap_nand_remove,
 	.driver		= {
 		.name	= DRIVER_NAME,
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(omap_nand_ids),
 	},
 };
 
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h
index 62a855e..45203a5 100644
--- a/include/linux/platform_data/mtd-nand-omap2.h
+++ b/include/linux/platform_data/mtd-nand-omap2.h
@@ -64,10 +64,8 @@ struct omap_nand_platform_data {
 	int			devsize;
 	enum omap_ecc           ecc_opt;
 
-	/* for passing the partitions */
-	struct device_node	*of_node;
-	struct device_node	*elm_of_node;
-
 	struct gpmc_nand_regs	reg;		/* deprecated */
+	struct device_node	*elm_of_node;	/* deprecated */
+	struct device_node	*of_node;	/* deprecated */
 };
 #endif
-- 
1.8.3.2

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

* [PATCH 10/36] ARM: dts: OMAP2+: Fix NAND device nodes
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Add compatible id, GPMC register resource and interrupt
resource to NAND controller nodes.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/boot/dts/am335x-evm.dts         |  8 ++++++--
 arch/arm/boot/dts/am335x-igep0033.dtsi   |  8 ++++++--
 arch/arm/boot/dts/am43x-epos-evm.dts     |  8 ++++++--
 arch/arm/boot/dts/omap3-devkit8000.dts   |  9 +++++++--
 arch/arm/boot/dts/omap3-evm-37xx.dts     | 10 +++++++---
 arch/arm/boot/dts/omap3-igep0020.dts     | 10 +++++++---
 arch/arm/boot/dts/omap3-igep0030.dts     |  8 ++++++--
 arch/arm/boot/dts/omap3-ldp.dts          | 10 +++++++---
 arch/arm/boot/dts/omap3-lilly-a83x.dtsi  | 10 +++++++---
 arch/arm/boot/dts/omap3-lilly-dbb056.dts |  7 ++++---
 arch/arm/boot/dts/omap3430-sdp.dts       |  8 ++++++--
 11 files changed, 69 insertions(+), 27 deletions(-)

diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
index 6028217..fa25f2b 100644
--- a/arch/arm/boot/dts/am335x-evm.dts
+++ b/arch/arm/boot/dts/am335x-evm.dts
@@ -437,9 +437,13 @@
 	status = "okay";
 	pinctrl-names = "default";
 	pinctrl-0 = <&nandflash_pins_s0>;
-	ranges = <0 0 0x08000000 0x10000000>;	/* CS0: NAND */
+	ranges = <0 0 0x08000000 0x10000000	/* CS0 space, 16MB */
+		  255 0 0x50000000 0x36c>;	/* GPMC reg */
 	nand@0,0 {
-		reg = <0 0 0>; /* CS0, offset 0 */
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* CS0, I/O window 4 bytes */
+		       255 0 0x36c>;	/* GPMC reg */
+		interrupts = <100>;
 		ti,nand-ecc-opt = "bch8";
 		ti,elm-id = <&elm>;
 		nand-bus-width = <8>;
diff --git a/arch/arm/boot/dts/am335x-igep0033.dtsi b/arch/arm/boot/dts/am335x-igep0033.dtsi
index 9f22c18..4c3f21f 100644
--- a/arch/arm/boot/dts/am335x-igep0033.dtsi
+++ b/arch/arm/boot/dts/am335x-igep0033.dtsi
@@ -112,10 +112,14 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&nandflash_pins>;
 
-	ranges = <0 0 0x08000000 0x10000000>;	/* CS0: NAND */
+	ranges = <0 0 0x08000000 0x10000000	/* CS0 space, 16MB */
+		  255 0 0x50000000 0x36c>;	/* GPMC reg */
 
 	nand@0,0 {
-		reg = <0 0 0>; /* CS0, offset 0 */
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* CS0, I/O window 4 bytes */
+		       255 0 0x36c>;	/* GPMC reg */
+		interrupts = <100>;
 		nand-bus-width = <8>;
 		ti,nand-ecc-opt = "bch8";
 		gpmc,device-width = <1>;
diff --git a/arch/arm/boot/dts/am43x-epos-evm.dts b/arch/arm/boot/dts/am43x-epos-evm.dts
index 167dbc8..d757134 100644
--- a/arch/arm/boot/dts/am43x-epos-evm.dts
+++ b/arch/arm/boot/dts/am43x-epos-evm.dts
@@ -268,9 +268,13 @@
 	status = "okay";
 	pinctrl-names = "default";
 	pinctrl-0 = <&nand_flash_x8>;
-	ranges = <0 0 0x08000000 0x10000000>;	/* CS0: NAND */
+	ranges = <0 0 0x08000000 0x10000000	/* CS0 space, 16MB */
+		  255 0 0x50000000 0x36c>;	/* GPMC reg */
 	nand@0,0 {
-		reg = <0 0 0>; /* CS0, offset 0 */
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* CS0, I/O window 4 bytes */
+		       255 0 0x36c>;	/* GPMC reg */
+		interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
 		ti,nand-ecc-opt = "bch8";
 		ti,elm-id = <&elm>;
 		nand-bus-width = <8>;
diff --git a/arch/arm/boot/dts/omap3-devkit8000.dts b/arch/arm/boot/dts/omap3-devkit8000.dts
index da402f0..c5c7bbd 100644
--- a/arch/arm/boot/dts/omap3-devkit8000.dts
+++ b/arch/arm/boot/dts/omap3-devkit8000.dts
@@ -106,10 +106,15 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x30000000 0x04>;       /* CS0: NAND */
+	ranges = <0 0 0x30000000 0x1000000	/* CS0 space, 16MB */
+		  255 0 0x6e000000 0x02d4>;	/* register space */
 
+	/* Chip select 0 */
 	nand@0,0 {
-		reg = <0 0 0>; /* CS0, offset 0 */
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* NAND I/O window, 4 bytes */
+		       255 0 0x02d4>;	/* GPMC register space */
+		interrupts = <20>;
 		nand-bus-width = <16>;
 
 		gpmc,sync-clk-ps = <0>;
diff --git a/arch/arm/boot/dts/omap3-evm-37xx.dts b/arch/arm/boot/dts/omap3-evm-37xx.dts
index 4df68ad..7b2b3f4 100644
--- a/arch/arm/boot/dts/omap3-evm-37xx.dts
+++ b/arch/arm/boot/dts/omap3-evm-37xx.dts
@@ -95,12 +95,16 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x00000000 0x20000000>,
-		 <5 0 0x2c000000 0x01000000>;
+	ranges = <0 0 0x00000000 0x1000000	/* CS0 space, 16MB */
+		  5 0 0x2c000000 0x1000000	/* CS5 space, 16MB */
+		  255 0 0x6e000000 0x02d4>;	/* GPMC reg */
 
 	nand@0,0 {
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* CS0, I/O window, 4 bytes */
+		       255 0 0x02d4>;	/* GPMC reg */
+		interrupts = <20>;
 		linux,mtd-name= "hynix,h8kds0un0mer-4em";
-		reg = <0 0 0>;
 		nand-bus-width = <16>;
 		ti,nand-ecc-opt = "bch8";
 
diff --git a/arch/arm/boot/dts/omap3-igep0020.dts b/arch/arm/boot/dts/omap3-igep0020.dts
index b22caaa..9bd1362 100644
--- a/arch/arm/boot/dts/omap3-igep0020.dts
+++ b/arch/arm/boot/dts/omap3-igep0020.dts
@@ -197,12 +197,16 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x00000000 0x20000000>,
-		 <5 0 0x2c000000 0x01000000>;
+	ranges = <0 0 0x00000000 0x1000000	/* CS0 space, 16MB */
+		  5 0 0x2c000000 0x1000000	/* CS5 space, 16MB */
+		  255 0 0x6e000000 0x02d4>;	/* GPMC reg */
 
 	nand@0,0 {
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* CS0, I/O window, 4 bytes */
+		       255 0 0x02d4>;	/* GPMC reg */
+		interrupts = <20>;
 		linux,mtd-name= "micron,mt29c4g96maz";
-		reg = <0 0 0>;
 		nand-bus-width = <16>;
 		ti,nand-ecc-opt = "bch8";
 
diff --git a/arch/arm/boot/dts/omap3-igep0030.dts b/arch/arm/boot/dts/omap3-igep0030.dts
index 2793749..1508154 100644
--- a/arch/arm/boot/dts/omap3-igep0030.dts
+++ b/arch/arm/boot/dts/omap3-igep0030.dts
@@ -55,11 +55,15 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x00000000 0x20000000>;
+	ranges = <0 0 0x00000000 0x1000000	/* CS0 space, 16MB */
+		  255 0 0x6e000000 0x02d4>;	/* GPMC reg */
 
 	nand@0,0 {
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* CS0, I/O window, 4 bytes */
+		       255 0 0x02d4>;	/* GPMC reg */
+		interrupts = <20>;
 		linux,mtd-name= "micron,mt29c4g96maz";
-		reg = <0 0 0>;
 		nand-bus-width = <16>;
 		ti,nand-ecc-opt = "bch8";
 
diff --git a/arch/arm/boot/dts/omap3-ldp.dts b/arch/arm/boot/dts/omap3-ldp.dts
index 0abe986..a219e11 100644
--- a/arch/arm/boot/dts/omap3-ldp.dts
+++ b/arch/arm/boot/dts/omap3-ldp.dts
@@ -96,12 +96,16 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x00000000 0x01000000>,
-		 <1 0 0x08000000 0x01000000>;
+	ranges = <0 0 0x00000000 0x1000000	/* CS0 space, 16MB */
+		  1 0 0x08000000 0x1000000	/* CS1 space, 16MB */
+		  255 0 0x6e000000 0x02d4>;	/* GPMC reg */
 
 	nand@0,0 {
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* CS0, I/O window, 4 bytes */
+		       255 0 0x02d4>;	/* GPMC reg */
+		interrupts = <20>;
 		linux,mtd-name= "micron,nand";
-		reg = <0 0 0>;
 		nand-bus-width = <16>;
 		ti,nand-ecc-opt = "bch8";
 
diff --git a/arch/arm/boot/dts/omap3-lilly-a83x.dtsi b/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
index cc1dce6..d0b64e7 100644
--- a/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
+++ b/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
@@ -358,11 +358,15 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x30000000 0x1000000>,
-		<7 0 0x15000000 0x01000000>;
+	ranges = <0 0 0x30000000 0x1000000
+		  7 0 0x15000000 0x1000000
+		  255 0 0x6e000000 0x02d4>;	/* GPMC reg */
 
 	nand@0,0 {
-		reg = <0 0 0x1000000>;
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* CS0, I/O window, 4 bytes */
+		       255 0 0x02d4>;	/* GPMC reg */
+		interrupts = <20>;
 		nand-bus-width = <16>;
 		ti,nand-ecc-opt = "bch8";
 		/* no elm on omap3 */
diff --git a/arch/arm/boot/dts/omap3-lilly-dbb056.dts b/arch/arm/boot/dts/omap3-lilly-dbb056.dts
index 834f7c6..3e09634 100644
--- a/arch/arm/boot/dts/omap3-lilly-dbb056.dts
+++ b/arch/arm/boot/dts/omap3-lilly-dbb056.dts
@@ -128,9 +128,10 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x30000000 0x1000000>,   /* nand assigned by COM a83x */
-		<4 0 0x20000000 0x01000000>,
-		<7 0 0x15000000 0x01000000>;   /* eth assigend by COM a83x */
+	ranges = <0 0 0x30000000 0x1000000	/* nand assigned by COM a83x */
+		  4 0 0x20000000 0x1000000
+		  7 0 0x15000000 0x1000000	/* eth assigend by COM a83x */
+		  255 0 0x6e000000 0x02d4>;	/* GPMC reg */
 
 	ethernet@4,0 {
 		compatible = "smsc,lan9117", "smsc,lan9115";
diff --git a/arch/arm/boot/dts/omap3430-sdp.dts b/arch/arm/boot/dts/omap3430-sdp.dts
index 02f69f4..bf5f8b9 100644
--- a/arch/arm/boot/dts/omap3430-sdp.dts
+++ b/arch/arm/boot/dts/omap3430-sdp.dts
@@ -52,7 +52,8 @@
 &gpmc {
 	ranges = <0 0 0x10000000 0x08000000>,
 		 <1 0 0x28000000 0x08000000>,
-		 <2 0 0x20000000 0x10000000>;
+		 <2 0 0x20000000 0x10000000>,
+		 <255 0 0x6e000000 0x02d4>;	/* GPMC reg */
 
 	nor@0,0 {
 		compatible = "cfi-flash";
@@ -103,10 +104,13 @@
 	};
 
 	nand@1,0 {
+		compatible = "ti,omap2-nand";
+		reg = <1 0 4		/* CS1, I/O window, 4 bytes */
+		       255 0 0x02d4>;	/* GPMC reg */
+		interrupts = <20>;
 		linux,mtd-name= "micron,mt29f1g08abb";
 		#address-cells = <1>;
 		#size-cells = <1>;
-		reg = <1 0 0x08000000>;
 		ti,nand-ecc-opt = "ham1";
 		nand-bus-width = <8>;
 		gpmc,cs-on-ns = <0>;
-- 
1.8.3.2


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

* [PATCH 10/36] ARM: dts: OMAP2+: Fix NAND device nodes
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Add compatible id, GPMC register resource and interrupt
resource to NAND controller nodes.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/boot/dts/am335x-evm.dts         |  8 ++++++--
 arch/arm/boot/dts/am335x-igep0033.dtsi   |  8 ++++++--
 arch/arm/boot/dts/am43x-epos-evm.dts     |  8 ++++++--
 arch/arm/boot/dts/omap3-devkit8000.dts   |  9 +++++++--
 arch/arm/boot/dts/omap3-evm-37xx.dts     | 10 +++++++---
 arch/arm/boot/dts/omap3-igep0020.dts     | 10 +++++++---
 arch/arm/boot/dts/omap3-igep0030.dts     |  8 ++++++--
 arch/arm/boot/dts/omap3-ldp.dts          | 10 +++++++---
 arch/arm/boot/dts/omap3-lilly-a83x.dtsi  | 10 +++++++---
 arch/arm/boot/dts/omap3-lilly-dbb056.dts |  7 ++++---
 arch/arm/boot/dts/omap3430-sdp.dts       |  8 ++++++--
 11 files changed, 69 insertions(+), 27 deletions(-)

diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
index 6028217..fa25f2b 100644
--- a/arch/arm/boot/dts/am335x-evm.dts
+++ b/arch/arm/boot/dts/am335x-evm.dts
@@ -437,9 +437,13 @@
 	status = "okay";
 	pinctrl-names = "default";
 	pinctrl-0 = <&nandflash_pins_s0>;
-	ranges = <0 0 0x08000000 0x10000000>;	/* CS0: NAND */
+	ranges = <0 0 0x08000000 0x10000000	/* CS0 space, 16MB */
+		  255 0 0x50000000 0x36c>;	/* GPMC reg */
 	nand@0,0 {
-		reg = <0 0 0>; /* CS0, offset 0 */
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* CS0, I/O window 4 bytes */
+		       255 0 0x36c>;	/* GPMC reg */
+		interrupts = <100>;
 		ti,nand-ecc-opt = "bch8";
 		ti,elm-id = <&elm>;
 		nand-bus-width = <8>;
diff --git a/arch/arm/boot/dts/am335x-igep0033.dtsi b/arch/arm/boot/dts/am335x-igep0033.dtsi
index 9f22c18..4c3f21f 100644
--- a/arch/arm/boot/dts/am335x-igep0033.dtsi
+++ b/arch/arm/boot/dts/am335x-igep0033.dtsi
@@ -112,10 +112,14 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&nandflash_pins>;
 
-	ranges = <0 0 0x08000000 0x10000000>;	/* CS0: NAND */
+	ranges = <0 0 0x08000000 0x10000000	/* CS0 space, 16MB */
+		  255 0 0x50000000 0x36c>;	/* GPMC reg */
 
 	nand@0,0 {
-		reg = <0 0 0>; /* CS0, offset 0 */
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* CS0, I/O window 4 bytes */
+		       255 0 0x36c>;	/* GPMC reg */
+		interrupts = <100>;
 		nand-bus-width = <8>;
 		ti,nand-ecc-opt = "bch8";
 		gpmc,device-width = <1>;
diff --git a/arch/arm/boot/dts/am43x-epos-evm.dts b/arch/arm/boot/dts/am43x-epos-evm.dts
index 167dbc8..d757134 100644
--- a/arch/arm/boot/dts/am43x-epos-evm.dts
+++ b/arch/arm/boot/dts/am43x-epos-evm.dts
@@ -268,9 +268,13 @@
 	status = "okay";
 	pinctrl-names = "default";
 	pinctrl-0 = <&nand_flash_x8>;
-	ranges = <0 0 0x08000000 0x10000000>;	/* CS0: NAND */
+	ranges = <0 0 0x08000000 0x10000000	/* CS0 space, 16MB */
+		  255 0 0x50000000 0x36c>;	/* GPMC reg */
 	nand@0,0 {
-		reg = <0 0 0>; /* CS0, offset 0 */
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* CS0, I/O window 4 bytes */
+		       255 0 0x36c>;	/* GPMC reg */
+		interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
 		ti,nand-ecc-opt = "bch8";
 		ti,elm-id = <&elm>;
 		nand-bus-width = <8>;
diff --git a/arch/arm/boot/dts/omap3-devkit8000.dts b/arch/arm/boot/dts/omap3-devkit8000.dts
index da402f0..c5c7bbd 100644
--- a/arch/arm/boot/dts/omap3-devkit8000.dts
+++ b/arch/arm/boot/dts/omap3-devkit8000.dts
@@ -106,10 +106,15 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x30000000 0x04>;       /* CS0: NAND */
+	ranges = <0 0 0x30000000 0x1000000	/* CS0 space, 16MB */
+		  255 0 0x6e000000 0x02d4>;	/* register space */
 
+	/* Chip select 0 */
 	nand@0,0 {
-		reg = <0 0 0>; /* CS0, offset 0 */
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* NAND I/O window, 4 bytes */
+		       255 0 0x02d4>;	/* GPMC register space */
+		interrupts = <20>;
 		nand-bus-width = <16>;
 
 		gpmc,sync-clk-ps = <0>;
diff --git a/arch/arm/boot/dts/omap3-evm-37xx.dts b/arch/arm/boot/dts/omap3-evm-37xx.dts
index 4df68ad..7b2b3f4 100644
--- a/arch/arm/boot/dts/omap3-evm-37xx.dts
+++ b/arch/arm/boot/dts/omap3-evm-37xx.dts
@@ -95,12 +95,16 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x00000000 0x20000000>,
-		 <5 0 0x2c000000 0x01000000>;
+	ranges = <0 0 0x00000000 0x1000000	/* CS0 space, 16MB */
+		  5 0 0x2c000000 0x1000000	/* CS5 space, 16MB */
+		  255 0 0x6e000000 0x02d4>;	/* GPMC reg */
 
 	nand@0,0 {
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* CS0, I/O window, 4 bytes */
+		       255 0 0x02d4>;	/* GPMC reg */
+		interrupts = <20>;
 		linux,mtd-name= "hynix,h8kds0un0mer-4em";
-		reg = <0 0 0>;
 		nand-bus-width = <16>;
 		ti,nand-ecc-opt = "bch8";
 
diff --git a/arch/arm/boot/dts/omap3-igep0020.dts b/arch/arm/boot/dts/omap3-igep0020.dts
index b22caaa..9bd1362 100644
--- a/arch/arm/boot/dts/omap3-igep0020.dts
+++ b/arch/arm/boot/dts/omap3-igep0020.dts
@@ -197,12 +197,16 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x00000000 0x20000000>,
-		 <5 0 0x2c000000 0x01000000>;
+	ranges = <0 0 0x00000000 0x1000000	/* CS0 space, 16MB */
+		  5 0 0x2c000000 0x1000000	/* CS5 space, 16MB */
+		  255 0 0x6e000000 0x02d4>;	/* GPMC reg */
 
 	nand@0,0 {
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* CS0, I/O window, 4 bytes */
+		       255 0 0x02d4>;	/* GPMC reg */
+		interrupts = <20>;
 		linux,mtd-name= "micron,mt29c4g96maz";
-		reg = <0 0 0>;
 		nand-bus-width = <16>;
 		ti,nand-ecc-opt = "bch8";
 
diff --git a/arch/arm/boot/dts/omap3-igep0030.dts b/arch/arm/boot/dts/omap3-igep0030.dts
index 2793749..1508154 100644
--- a/arch/arm/boot/dts/omap3-igep0030.dts
+++ b/arch/arm/boot/dts/omap3-igep0030.dts
@@ -55,11 +55,15 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x00000000 0x20000000>;
+	ranges = <0 0 0x00000000 0x1000000	/* CS0 space, 16MB */
+		  255 0 0x6e000000 0x02d4>;	/* GPMC reg */
 
 	nand@0,0 {
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* CS0, I/O window, 4 bytes */
+		       255 0 0x02d4>;	/* GPMC reg */
+		interrupts = <20>;
 		linux,mtd-name= "micron,mt29c4g96maz";
-		reg = <0 0 0>;
 		nand-bus-width = <16>;
 		ti,nand-ecc-opt = "bch8";
 
diff --git a/arch/arm/boot/dts/omap3-ldp.dts b/arch/arm/boot/dts/omap3-ldp.dts
index 0abe986..a219e11 100644
--- a/arch/arm/boot/dts/omap3-ldp.dts
+++ b/arch/arm/boot/dts/omap3-ldp.dts
@@ -96,12 +96,16 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x00000000 0x01000000>,
-		 <1 0 0x08000000 0x01000000>;
+	ranges = <0 0 0x00000000 0x1000000	/* CS0 space, 16MB */
+		  1 0 0x08000000 0x1000000	/* CS1 space, 16MB */
+		  255 0 0x6e000000 0x02d4>;	/* GPMC reg */
 
 	nand@0,0 {
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* CS0, I/O window, 4 bytes */
+		       255 0 0x02d4>;	/* GPMC reg */
+		interrupts = <20>;
 		linux,mtd-name= "micron,nand";
-		reg = <0 0 0>;
 		nand-bus-width = <16>;
 		ti,nand-ecc-opt = "bch8";
 
diff --git a/arch/arm/boot/dts/omap3-lilly-a83x.dtsi b/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
index cc1dce6..d0b64e7 100644
--- a/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
+++ b/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
@@ -358,11 +358,15 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x30000000 0x1000000>,
-		<7 0 0x15000000 0x01000000>;
+	ranges = <0 0 0x30000000 0x1000000
+		  7 0 0x15000000 0x1000000
+		  255 0 0x6e000000 0x02d4>;	/* GPMC reg */
 
 	nand@0,0 {
-		reg = <0 0 0x1000000>;
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* CS0, I/O window, 4 bytes */
+		       255 0 0x02d4>;	/* GPMC reg */
+		interrupts = <20>;
 		nand-bus-width = <16>;
 		ti,nand-ecc-opt = "bch8";
 		/* no elm on omap3 */
diff --git a/arch/arm/boot/dts/omap3-lilly-dbb056.dts b/arch/arm/boot/dts/omap3-lilly-dbb056.dts
index 834f7c6..3e09634 100644
--- a/arch/arm/boot/dts/omap3-lilly-dbb056.dts
+++ b/arch/arm/boot/dts/omap3-lilly-dbb056.dts
@@ -128,9 +128,10 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x30000000 0x1000000>,   /* nand assigned by COM a83x */
-		<4 0 0x20000000 0x01000000>,
-		<7 0 0x15000000 0x01000000>;   /* eth assigend by COM a83x */
+	ranges = <0 0 0x30000000 0x1000000	/* nand assigned by COM a83x */
+		  4 0 0x20000000 0x1000000
+		  7 0 0x15000000 0x1000000	/* eth assigend by COM a83x */
+		  255 0 0x6e000000 0x02d4>;	/* GPMC reg */
 
 	ethernet@4,0 {
 		compatible = "smsc,lan9117", "smsc,lan9115";
diff --git a/arch/arm/boot/dts/omap3430-sdp.dts b/arch/arm/boot/dts/omap3430-sdp.dts
index 02f69f4..bf5f8b9 100644
--- a/arch/arm/boot/dts/omap3430-sdp.dts
+++ b/arch/arm/boot/dts/omap3430-sdp.dts
@@ -52,7 +52,8 @@
 &gpmc {
 	ranges = <0 0 0x10000000 0x08000000>,
 		 <1 0 0x28000000 0x08000000>,
-		 <2 0 0x20000000 0x10000000>;
+		 <2 0 0x20000000 0x10000000>,
+		 <255 0 0x6e000000 0x02d4>;	/* GPMC reg */
 
 	nor@0,0 {
 		compatible = "cfi-flash";
@@ -103,10 +104,13 @@
 	};
 
 	nand@1,0 {
+		compatible = "ti,omap2-nand";
+		reg = <1 0 4		/* CS1, I/O window, 4 bytes */
+		       255 0 0x02d4>;	/* GPMC reg */
+		interrupts = <20>;
 		linux,mtd-name= "micron,mt29f1g08abb";
 		#address-cells = <1>;
 		#size-cells = <1>;
-		reg = <1 0 0x08000000>;
 		ti,nand-ecc-opt = "ham1";
 		nand-bus-width = <8>;
 		gpmc,cs-on-ns = <0>;
-- 
1.8.3.2


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

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

* [PATCH 10/36] ARM: dts: OMAP2+: Fix NAND device nodes
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Add compatible id, GPMC register resource and interrupt
resource to NAND controller nodes.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/boot/dts/am335x-evm.dts         |  8 ++++++--
 arch/arm/boot/dts/am335x-igep0033.dtsi   |  8 ++++++--
 arch/arm/boot/dts/am43x-epos-evm.dts     |  8 ++++++--
 arch/arm/boot/dts/omap3-devkit8000.dts   |  9 +++++++--
 arch/arm/boot/dts/omap3-evm-37xx.dts     | 10 +++++++---
 arch/arm/boot/dts/omap3-igep0020.dts     | 10 +++++++---
 arch/arm/boot/dts/omap3-igep0030.dts     |  8 ++++++--
 arch/arm/boot/dts/omap3-ldp.dts          | 10 +++++++---
 arch/arm/boot/dts/omap3-lilly-a83x.dtsi  | 10 +++++++---
 arch/arm/boot/dts/omap3-lilly-dbb056.dts |  7 ++++---
 arch/arm/boot/dts/omap3430-sdp.dts       |  8 ++++++--
 11 files changed, 69 insertions(+), 27 deletions(-)

diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
index 6028217..fa25f2b 100644
--- a/arch/arm/boot/dts/am335x-evm.dts
+++ b/arch/arm/boot/dts/am335x-evm.dts
@@ -437,9 +437,13 @@
 	status = "okay";
 	pinctrl-names = "default";
 	pinctrl-0 = <&nandflash_pins_s0>;
-	ranges = <0 0 0x08000000 0x10000000>;	/* CS0: NAND */
+	ranges = <0 0 0x08000000 0x10000000	/* CS0 space, 16MB */
+		  255 0 0x50000000 0x36c>;	/* GPMC reg */
 	nand@0,0 {
-		reg = <0 0 0>; /* CS0, offset 0 */
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* CS0, I/O window 4 bytes */
+		       255 0 0x36c>;	/* GPMC reg */
+		interrupts = <100>;
 		ti,nand-ecc-opt = "bch8";
 		ti,elm-id = <&elm>;
 		nand-bus-width = <8>;
diff --git a/arch/arm/boot/dts/am335x-igep0033.dtsi b/arch/arm/boot/dts/am335x-igep0033.dtsi
index 9f22c18..4c3f21f 100644
--- a/arch/arm/boot/dts/am335x-igep0033.dtsi
+++ b/arch/arm/boot/dts/am335x-igep0033.dtsi
@@ -112,10 +112,14 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&nandflash_pins>;
 
-	ranges = <0 0 0x08000000 0x10000000>;	/* CS0: NAND */
+	ranges = <0 0 0x08000000 0x10000000	/* CS0 space, 16MB */
+		  255 0 0x50000000 0x36c>;	/* GPMC reg */
 
 	nand@0,0 {
-		reg = <0 0 0>; /* CS0, offset 0 */
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* CS0, I/O window 4 bytes */
+		       255 0 0x36c>;	/* GPMC reg */
+		interrupts = <100>;
 		nand-bus-width = <8>;
 		ti,nand-ecc-opt = "bch8";
 		gpmc,device-width = <1>;
diff --git a/arch/arm/boot/dts/am43x-epos-evm.dts b/arch/arm/boot/dts/am43x-epos-evm.dts
index 167dbc8..d757134 100644
--- a/arch/arm/boot/dts/am43x-epos-evm.dts
+++ b/arch/arm/boot/dts/am43x-epos-evm.dts
@@ -268,9 +268,13 @@
 	status = "okay";
 	pinctrl-names = "default";
 	pinctrl-0 = <&nand_flash_x8>;
-	ranges = <0 0 0x08000000 0x10000000>;	/* CS0: NAND */
+	ranges = <0 0 0x08000000 0x10000000	/* CS0 space, 16MB */
+		  255 0 0x50000000 0x36c>;	/* GPMC reg */
 	nand@0,0 {
-		reg = <0 0 0>; /* CS0, offset 0 */
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* CS0, I/O window 4 bytes */
+		       255 0 0x36c>;	/* GPMC reg */
+		interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
 		ti,nand-ecc-opt = "bch8";
 		ti,elm-id = <&elm>;
 		nand-bus-width = <8>;
diff --git a/arch/arm/boot/dts/omap3-devkit8000.dts b/arch/arm/boot/dts/omap3-devkit8000.dts
index da402f0..c5c7bbd 100644
--- a/arch/arm/boot/dts/omap3-devkit8000.dts
+++ b/arch/arm/boot/dts/omap3-devkit8000.dts
@@ -106,10 +106,15 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x30000000 0x04>;       /* CS0: NAND */
+	ranges = <0 0 0x30000000 0x1000000	/* CS0 space, 16MB */
+		  255 0 0x6e000000 0x02d4>;	/* register space */
 
+	/* Chip select 0 */
 	nand@0,0 {
-		reg = <0 0 0>; /* CS0, offset 0 */
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* NAND I/O window, 4 bytes */
+		       255 0 0x02d4>;	/* GPMC register space */
+		interrupts = <20>;
 		nand-bus-width = <16>;
 
 		gpmc,sync-clk-ps = <0>;
diff --git a/arch/arm/boot/dts/omap3-evm-37xx.dts b/arch/arm/boot/dts/omap3-evm-37xx.dts
index 4df68ad..7b2b3f4 100644
--- a/arch/arm/boot/dts/omap3-evm-37xx.dts
+++ b/arch/arm/boot/dts/omap3-evm-37xx.dts
@@ -95,12 +95,16 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x00000000 0x20000000>,
-		 <5 0 0x2c000000 0x01000000>;
+	ranges = <0 0 0x00000000 0x1000000	/* CS0 space, 16MB */
+		  5 0 0x2c000000 0x1000000	/* CS5 space, 16MB */
+		  255 0 0x6e000000 0x02d4>;	/* GPMC reg */
 
 	nand@0,0 {
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* CS0, I/O window, 4 bytes */
+		       255 0 0x02d4>;	/* GPMC reg */
+		interrupts = <20>;
 		linux,mtd-name= "hynix,h8kds0un0mer-4em";
-		reg = <0 0 0>;
 		nand-bus-width = <16>;
 		ti,nand-ecc-opt = "bch8";
 
diff --git a/arch/arm/boot/dts/omap3-igep0020.dts b/arch/arm/boot/dts/omap3-igep0020.dts
index b22caaa..9bd1362 100644
--- a/arch/arm/boot/dts/omap3-igep0020.dts
+++ b/arch/arm/boot/dts/omap3-igep0020.dts
@@ -197,12 +197,16 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x00000000 0x20000000>,
-		 <5 0 0x2c000000 0x01000000>;
+	ranges = <0 0 0x00000000 0x1000000	/* CS0 space, 16MB */
+		  5 0 0x2c000000 0x1000000	/* CS5 space, 16MB */
+		  255 0 0x6e000000 0x02d4>;	/* GPMC reg */
 
 	nand@0,0 {
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* CS0, I/O window, 4 bytes */
+		       255 0 0x02d4>;	/* GPMC reg */
+		interrupts = <20>;
 		linux,mtd-name= "micron,mt29c4g96maz";
-		reg = <0 0 0>;
 		nand-bus-width = <16>;
 		ti,nand-ecc-opt = "bch8";
 
diff --git a/arch/arm/boot/dts/omap3-igep0030.dts b/arch/arm/boot/dts/omap3-igep0030.dts
index 2793749..1508154 100644
--- a/arch/arm/boot/dts/omap3-igep0030.dts
+++ b/arch/arm/boot/dts/omap3-igep0030.dts
@@ -55,11 +55,15 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x00000000 0x20000000>;
+	ranges = <0 0 0x00000000 0x1000000	/* CS0 space, 16MB */
+		  255 0 0x6e000000 0x02d4>;	/* GPMC reg */
 
 	nand@0,0 {
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* CS0, I/O window, 4 bytes */
+		       255 0 0x02d4>;	/* GPMC reg */
+		interrupts = <20>;
 		linux,mtd-name= "micron,mt29c4g96maz";
-		reg = <0 0 0>;
 		nand-bus-width = <16>;
 		ti,nand-ecc-opt = "bch8";
 
diff --git a/arch/arm/boot/dts/omap3-ldp.dts b/arch/arm/boot/dts/omap3-ldp.dts
index 0abe986..a219e11 100644
--- a/arch/arm/boot/dts/omap3-ldp.dts
+++ b/arch/arm/boot/dts/omap3-ldp.dts
@@ -96,12 +96,16 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x00000000 0x01000000>,
-		 <1 0 0x08000000 0x01000000>;
+	ranges = <0 0 0x00000000 0x1000000	/* CS0 space, 16MB */
+		  1 0 0x08000000 0x1000000	/* CS1 space, 16MB */
+		  255 0 0x6e000000 0x02d4>;	/* GPMC reg */
 
 	nand@0,0 {
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* CS0, I/O window, 4 bytes */
+		       255 0 0x02d4>;	/* GPMC reg */
+		interrupts = <20>;
 		linux,mtd-name= "micron,nand";
-		reg = <0 0 0>;
 		nand-bus-width = <16>;
 		ti,nand-ecc-opt = "bch8";
 
diff --git a/arch/arm/boot/dts/omap3-lilly-a83x.dtsi b/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
index cc1dce6..d0b64e7 100644
--- a/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
+++ b/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
@@ -358,11 +358,15 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x30000000 0x1000000>,
-		<7 0 0x15000000 0x01000000>;
+	ranges = <0 0 0x30000000 0x1000000
+		  7 0 0x15000000 0x1000000
+		  255 0 0x6e000000 0x02d4>;	/* GPMC reg */
 
 	nand@0,0 {
-		reg = <0 0 0x1000000>;
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* CS0, I/O window, 4 bytes */
+		       255 0 0x02d4>;	/* GPMC reg */
+		interrupts = <20>;
 		nand-bus-width = <16>;
 		ti,nand-ecc-opt = "bch8";
 		/* no elm on omap3 */
diff --git a/arch/arm/boot/dts/omap3-lilly-dbb056.dts b/arch/arm/boot/dts/omap3-lilly-dbb056.dts
index 834f7c6..3e09634 100644
--- a/arch/arm/boot/dts/omap3-lilly-dbb056.dts
+++ b/arch/arm/boot/dts/omap3-lilly-dbb056.dts
@@ -128,9 +128,10 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x30000000 0x1000000>,   /* nand assigned by COM a83x */
-		<4 0 0x20000000 0x01000000>,
-		<7 0 0x15000000 0x01000000>;   /* eth assigend by COM a83x */
+	ranges = <0 0 0x30000000 0x1000000	/* nand assigned by COM a83x */
+		  4 0 0x20000000 0x1000000
+		  7 0 0x15000000 0x1000000	/* eth assigend by COM a83x */
+		  255 0 0x6e000000 0x02d4>;	/* GPMC reg */
 
 	ethernet@4,0 {
 		compatible = "smsc,lan9117", "smsc,lan9115";
diff --git a/arch/arm/boot/dts/omap3430-sdp.dts b/arch/arm/boot/dts/omap3430-sdp.dts
index 02f69f4..bf5f8b9 100644
--- a/arch/arm/boot/dts/omap3430-sdp.dts
+++ b/arch/arm/boot/dts/omap3430-sdp.dts
@@ -52,7 +52,8 @@
 &gpmc {
 	ranges = <0 0 0x10000000 0x08000000>,
 		 <1 0 0x28000000 0x08000000>,
-		 <2 0 0x20000000 0x10000000>;
+		 <2 0 0x20000000 0x10000000>,
+		 <255 0 0x6e000000 0x02d4>;	/* GPMC reg */
 
 	nor@0,0 {
 		compatible = "cfi-flash";
@@ -103,10 +104,13 @@
 	};
 
 	nand@1,0 {
+		compatible = "ti,omap2-nand";
+		reg = <1 0 4		/* CS1, I/O window, 4 bytes */
+		       255 0 0x02d4>;	/* GPMC reg */
+		interrupts = <20>;
 		linux,mtd-name= "micron,mt29f1g08abb";
 		#address-cells = <1>;
 		#size-cells = <1>;
-		reg = <1 0 0x08000000>;
 		ti,nand-ecc-opt = "ham1";
 		nand-bus-width = <8>;
 		gpmc,cs-on-ns = <0>;
-- 
1.8.3.2

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

* [PATCH 11/36] mtd: nand: omap: Update DT binding documentation
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Add compatible id, interrupts and update reg property description.
As the NAND controller needs access to GPMC register space, we need
to pass a second memory resource to the NAND controller node.

Due to the wierd way the reg property has been implemented (i.e.
CS number required in 1st number of reg property) we will need to
use a number outside the possible CS numbers for the GPMC register space.

As a SoC can have fewer than 10 chip selects, 255 seems like a safe
bet for the GPMC register space.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 Documentation/devicetree/bindings/mtd/gpmc-nand.txt | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
index 5e1f31b..8831116 100644
--- a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
@@ -13,7 +13,13 @@ Documentation/devicetree/bindings/mtd/nand.txt
 
 Required properties:
 
+ - compatible:	"ti,omap2-nand"
  - reg:		The CS line the peripheral is connected to
+		Should contain 2 resource specifiers
+		- range id (CS number), base offset and length of the
+		  NAND I/O space
+		- range id,  base offset and length of the GPMC register space.
+ - interrupts:	Interrupt resource specifier for GPMC interrupt.
 
 Optional properties:
 
@@ -53,17 +59,21 @@ Example for an AM33xx board:
 	gpmc: gpmc@50000000 {
 		compatible = "ti,am3352-gpmc";
 		ti,hwmods = "gpmc";
-		reg = <0x50000000 0x1000000>;
+		reg = <0x50000000 0x36c>;
 		interrupts = <100>;
 		gpmc,num-cs = <8>;
 		gpmc,num-waitpins = <2>;
 		#address-cells = <2>;
 		#size-cells = <1>;
-		ranges = <0 0 0x08000000 0x2000>;	/* CS0: NAND */
+		ranges = <0 0 0x08000000 0x1000000	/* CS0 space, 16MB */
+			  255 0 0x50000000 0x36c>;	/* GPMC reg space */
 		elm_id = <&elm>;
 
 		nand@0,0 {
-			reg = <0 0 0>; /* CS0, offset 0 */
+			compatible = "ti,omap2-nand";
+			reg = <0 0 4		/* CS0, offset 0, NAND I/O window 4 */
+			       255 0 0x36c>;	/* GPMC reg space */
+			interrupts = <100>;
 			nand-bus-width = <16>;
 			ti,nand-ecc-opt = "bch8";
 			ti,nand-xfer-type = "polled";
-- 
1.8.3.2


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

* [PATCH 11/36] mtd: nand: omap: Update DT binding documentation
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Add compatible id, interrupts and update reg property description.
As the NAND controller needs access to GPMC register space, we need
to pass a second memory resource to the NAND controller node.

Due to the wierd way the reg property has been implemented (i.e.
CS number required in 1st number of reg property) we will need to
use a number outside the possible CS numbers for the GPMC register space.

As a SoC can have fewer than 10 chip selects, 255 seems like a safe
bet for the GPMC register space.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 Documentation/devicetree/bindings/mtd/gpmc-nand.txt | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
index 5e1f31b..8831116 100644
--- a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
@@ -13,7 +13,13 @@ Documentation/devicetree/bindings/mtd/nand.txt
 
 Required properties:
 
+ - compatible:	"ti,omap2-nand"
  - reg:		The CS line the peripheral is connected to
+		Should contain 2 resource specifiers
+		- range id (CS number), base offset and length of the
+		  NAND I/O space
+		- range id,  base offset and length of the GPMC register space.
+ - interrupts:	Interrupt resource specifier for GPMC interrupt.
 
 Optional properties:
 
@@ -53,17 +59,21 @@ Example for an AM33xx board:
 	gpmc: gpmc@50000000 {
 		compatible = "ti,am3352-gpmc";
 		ti,hwmods = "gpmc";
-		reg = <0x50000000 0x1000000>;
+		reg = <0x50000000 0x36c>;
 		interrupts = <100>;
 		gpmc,num-cs = <8>;
 		gpmc,num-waitpins = <2>;
 		#address-cells = <2>;
 		#size-cells = <1>;
-		ranges = <0 0 0x08000000 0x2000>;	/* CS0: NAND */
+		ranges = <0 0 0x08000000 0x1000000	/* CS0 space, 16MB */
+			  255 0 0x50000000 0x36c>;	/* GPMC reg space */
 		elm_id = <&elm>;
 
 		nand@0,0 {
-			reg = <0 0 0>; /* CS0, offset 0 */
+			compatible = "ti,omap2-nand";
+			reg = <0 0 4		/* CS0, offset 0, NAND I/O window 4 */
+			       255 0 0x36c>;	/* GPMC reg space */
+			interrupts = <100>;
 			nand-bus-width = <16>;
 			ti,nand-ecc-opt = "bch8";
 			ti,nand-xfer-type = "polled";
-- 
1.8.3.2

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

* [PATCH 11/36] mtd: nand: omap: Update DT binding documentation
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Add compatible id, interrupts and update reg property description.
As the NAND controller needs access to GPMC register space, we need
to pass a second memory resource to the NAND controller node.

Due to the wierd way the reg property has been implemented (i.e.
CS number required in 1st number of reg property) we will need to
use a number outside the possible CS numbers for the GPMC register space.

As a SoC can have fewer than 10 chip selects, 255 seems like a safe
bet for the GPMC register space.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 Documentation/devicetree/bindings/mtd/gpmc-nand.txt | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
index 5e1f31b..8831116 100644
--- a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
@@ -13,7 +13,13 @@ Documentation/devicetree/bindings/mtd/nand.txt
 
 Required properties:
 
+ - compatible:	"ti,omap2-nand"
  - reg:		The CS line the peripheral is connected to
+		Should contain 2 resource specifiers
+		- range id (CS number), base offset and length of the
+		  NAND I/O space
+		- range id,  base offset and length of the GPMC register space.
+ - interrupts:	Interrupt resource specifier for GPMC interrupt.
 
 Optional properties:
 
@@ -53,17 +59,21 @@ Example for an AM33xx board:
 	gpmc: gpmc@50000000 {
 		compatible = "ti,am3352-gpmc";
 		ti,hwmods = "gpmc";
-		reg = <0x50000000 0x1000000>;
+		reg = <0x50000000 0x36c>;
 		interrupts = <100>;
 		gpmc,num-cs = <8>;
 		gpmc,num-waitpins = <2>;
 		#address-cells = <2>;
 		#size-cells = <1>;
-		ranges = <0 0 0x08000000 0x2000>;	/* CS0: NAND */
+		ranges = <0 0 0x08000000 0x1000000	/* CS0 space, 16MB */
+			  255 0 0x50000000 0x36c>;	/* GPMC reg space */
 		elm_id = <&elm>;
 
 		nand@0,0 {
-			reg = <0 0 0>; /* CS0, offset 0 */
+			compatible = "ti,omap2-nand";
+			reg = <0 0 4		/* CS0, offset 0, NAND I/O window 4 */
+			       255 0 0x36c>;	/* GPMC reg space */
+			interrupts = <100>;
 			nand-bus-width = <16>;
 			ti,nand-ecc-opt = "bch8";
 			ti,nand-xfer-type = "polled";
-- 
1.8.3.2

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

* [PATCH 12/36] ARM: dts: omap3-beagle: Add NAND device
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

The beagle board contains a 16-bit NAND device connected to
chip select 0 of the GPMC controller.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/boot/dts/omap3-beagle.dts | 53 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts
index 3c3e6da..fafd229 100644
--- a/arch/arm/boot/dts/omap3-beagle.dts
+++ b/arch/arm/boot/dts/omap3-beagle.dts
@@ -350,3 +350,56 @@
 		};
 	};
 };
+
+&gpmc {
+	ranges = <0 0 0x30000000 0x1000000	/* CS0 space, 16MB */
+		  255 0 0x6e000000 0x02d4>;	/* register space */
+
+	/* Chip select 0 */
+	nand@0,0 {
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* NAND I/O window, 4 bytes */
+		       255 0 0x02d4>;	/* GPMC register space */
+		interrupts = <20>;
+		ti,nand-ecc-opt = "ham1";
+		nand-bus-width = <16>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		gpmc,cs-on-ns = <0>;
+		gpmc,cs-rd-off-ns = <36>;
+		gpmc,cs-wr-off-ns = <36>;
+		gpmc,adv-on-ns = <6>;
+		gpmc,adv-rd-off-ns = <24>;
+		gpmc,adv-wr-off-ns = <36>;
+		gpmc,oe-on-ns = <6>;
+		gpmc,oe-off-ns = <48>;
+		gpmc,we-on-ns = <6>;
+		gpmc,we-off-ns = <30>;
+		gpmc,rd-cycle-ns = <72>;
+		gpmc,wr-cycle-ns = <72>;
+		gpmc,access-ns = <54>;
+		gpmc,wr-access-ns = <30>;
+
+		partition@0 {
+			label = "X-Loader";
+			reg = <0 0x80000>;
+		};
+		partition@80000 {
+			label = "U-Boot";
+			reg = <0x80000 0x1e0000>;
+		};
+		partition@1c0000 {
+			label = "U-Boot Env";
+			reg = <0x260000 0x20000>;
+		};
+		partition@280000 {
+			label = "Kernel";
+			reg = <0x280000 0x400000>;
+		};
+		partition@780000 {
+			label = "Filesystem";
+			reg = <0x680000 0xf980000>;
+		};
+	};
+};
-- 
1.8.3.2


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

* [PATCH 12/36] ARM: dts: omap3-beagle: Add NAND device
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

The beagle board contains a 16-bit NAND device connected to
chip select 0 of the GPMC controller.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/boot/dts/omap3-beagle.dts | 53 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts
index 3c3e6da..fafd229 100644
--- a/arch/arm/boot/dts/omap3-beagle.dts
+++ b/arch/arm/boot/dts/omap3-beagle.dts
@@ -350,3 +350,56 @@
 		};
 	};
 };
+
+&gpmc {
+	ranges = <0 0 0x30000000 0x1000000	/* CS0 space, 16MB */
+		  255 0 0x6e000000 0x02d4>;	/* register space */
+
+	/* Chip select 0 */
+	nand@0,0 {
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* NAND I/O window, 4 bytes */
+		       255 0 0x02d4>;	/* GPMC register space */
+		interrupts = <20>;
+		ti,nand-ecc-opt = "ham1";
+		nand-bus-width = <16>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		gpmc,cs-on-ns = <0>;
+		gpmc,cs-rd-off-ns = <36>;
+		gpmc,cs-wr-off-ns = <36>;
+		gpmc,adv-on-ns = <6>;
+		gpmc,adv-rd-off-ns = <24>;
+		gpmc,adv-wr-off-ns = <36>;
+		gpmc,oe-on-ns = <6>;
+		gpmc,oe-off-ns = <48>;
+		gpmc,we-on-ns = <6>;
+		gpmc,we-off-ns = <30>;
+		gpmc,rd-cycle-ns = <72>;
+		gpmc,wr-cycle-ns = <72>;
+		gpmc,access-ns = <54>;
+		gpmc,wr-access-ns = <30>;
+
+		partition@0 {
+			label = "X-Loader";
+			reg = <0 0x80000>;
+		};
+		partition@80000 {
+			label = "U-Boot";
+			reg = <0x80000 0x1e0000>;
+		};
+		partition@1c0000 {
+			label = "U-Boot Env";
+			reg = <0x260000 0x20000>;
+		};
+		partition@280000 {
+			label = "Kernel";
+			reg = <0x280000 0x400000>;
+		};
+		partition@780000 {
+			label = "Filesystem";
+			reg = <0x680000 0xf980000>;
+		};
+	};
+};
-- 
1.8.3.2


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

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

* [PATCH 12/36] ARM: dts: omap3-beagle: Add NAND device
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

The beagle board contains a 16-bit NAND device connected to
chip select 0 of the GPMC controller.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/boot/dts/omap3-beagle.dts | 53 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts
index 3c3e6da..fafd229 100644
--- a/arch/arm/boot/dts/omap3-beagle.dts
+++ b/arch/arm/boot/dts/omap3-beagle.dts
@@ -350,3 +350,56 @@
 		};
 	};
 };
+
+&gpmc {
+	ranges = <0 0 0x30000000 0x1000000	/* CS0 space, 16MB */
+		  255 0 0x6e000000 0x02d4>;	/* register space */
+
+	/* Chip select 0 */
+	nand@0,0 {
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4		/* NAND I/O window, 4 bytes */
+		       255 0 0x02d4>;	/* GPMC register space */
+		interrupts = <20>;
+		ti,nand-ecc-opt = "ham1";
+		nand-bus-width = <16>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		gpmc,cs-on-ns = <0>;
+		gpmc,cs-rd-off-ns = <36>;
+		gpmc,cs-wr-off-ns = <36>;
+		gpmc,adv-on-ns = <6>;
+		gpmc,adv-rd-off-ns = <24>;
+		gpmc,adv-wr-off-ns = <36>;
+		gpmc,oe-on-ns = <6>;
+		gpmc,oe-off-ns = <48>;
+		gpmc,we-on-ns = <6>;
+		gpmc,we-off-ns = <30>;
+		gpmc,rd-cycle-ns = <72>;
+		gpmc,wr-cycle-ns = <72>;
+		gpmc,access-ns = <54>;
+		gpmc,wr-access-ns = <30>;
+
+		partition@0 {
+			label = "X-Loader";
+			reg = <0 0x80000>;
+		};
+		partition@80000 {
+			label = "U-Boot";
+			reg = <0x80000 0x1e0000>;
+		};
+		partition@1c0000 {
+			label = "U-Boot Env";
+			reg = <0x260000 0x20000>;
+		};
+		partition@280000 {
+			label = "Kernel";
+			reg = <0x280000 0x400000>;
+		};
+		partition@780000 {
+			label = "Filesystem";
+			reg = <0x680000 0xf980000>;
+		};
+	};
+};
-- 
1.8.3.2

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

* [PATCH 13/36] ARM: OMAP2+: gpmc.c: sanity check bank-width DT property
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Make sure bank-width property provided via DT is sane.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index c713616..70cb6b0 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1219,6 +1219,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
 	struct resource res;
 	unsigned long base;
 	int ret, cs;
+	struct device *dev = &pdev->dev;
 
 	if (of_property_read_u32(child, "reg", &cs) < 0) {
 		dev_err(&pdev->dev, "%s has no 'reg' property\n",
@@ -1284,7 +1285,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
 			gpmc_s.device_width = GPMC_DEVWIDTH_16BIT;
 			break;
 		default:
-			dev_err(&pdev->dev, "%s: invalid 'nand-bus-width'\n",
+			dev_err(dev, "%s: invalid 'nand-bus-width'\n",
 				child->name);
 			ret = -EINVAL;
 			goto err;
@@ -1292,10 +1293,18 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
 
 		gpmc_s.device_nand = true;
 	} else {
-		ret = of_property_read_u32(child, "bank-width",
-					   &gpmc_s.device_width);
-		if (ret < 0)
+		if (of_property_read_u32(child, "bank-width",
+					 &gpmc_s.device_width)) {
+			dev_err(dev, "%s: no 'bank-width' property\n",
+				child->name);
+			goto err;
+		}
+
+		if (gpmc_s.device_width < 1 || gpmc_s.device_width > 2) {
+			dev_err(dev, "%s: invalid 'bank-width'\n",
+				child->name);
 			goto err;
+		}
 	}
 
 	ret = gpmc_cs_program_settings(cs, &gpmc_s);
-- 
1.8.3.2


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

* [PATCH 13/36] ARM: OMAP2+: gpmc.c: sanity check bank-width DT property
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Make sure bank-width property provided via DT is sane.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index c713616..70cb6b0 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1219,6 +1219,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
 	struct resource res;
 	unsigned long base;
 	int ret, cs;
+	struct device *dev = &pdev->dev;
 
 	if (of_property_read_u32(child, "reg", &cs) < 0) {
 		dev_err(&pdev->dev, "%s has no 'reg' property\n",
@@ -1284,7 +1285,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
 			gpmc_s.device_width = GPMC_DEVWIDTH_16BIT;
 			break;
 		default:
-			dev_err(&pdev->dev, "%s: invalid 'nand-bus-width'\n",
+			dev_err(dev, "%s: invalid 'nand-bus-width'\n",
 				child->name);
 			ret = -EINVAL;
 			goto err;
@@ -1292,10 +1293,18 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
 
 		gpmc_s.device_nand = true;
 	} else {
-		ret = of_property_read_u32(child, "bank-width",
-					   &gpmc_s.device_width);
-		if (ret < 0)
+		if (of_property_read_u32(child, "bank-width",
+					 &gpmc_s.device_width)) {
+			dev_err(dev, "%s: no 'bank-width' property\n",
+				child->name);
+			goto err;
+		}
+
+		if (gpmc_s.device_width < 1 || gpmc_s.device_width > 2) {
+			dev_err(dev, "%s: invalid 'bank-width'\n",
+				child->name);
 			goto err;
+		}
 	}
 
 	ret = gpmc_cs_program_settings(cs, &gpmc_s);
-- 
1.8.3.2


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

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

* [PATCH 13/36] ARM: OMAP2+: gpmc.c: sanity check bank-width DT property
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Make sure bank-width property provided via DT is sane.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index c713616..70cb6b0 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1219,6 +1219,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
 	struct resource res;
 	unsigned long base;
 	int ret, cs;
+	struct device *dev = &pdev->dev;
 
 	if (of_property_read_u32(child, "reg", &cs) < 0) {
 		dev_err(&pdev->dev, "%s has no 'reg' property\n",
@@ -1284,7 +1285,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
 			gpmc_s.device_width = GPMC_DEVWIDTH_16BIT;
 			break;
 		default:
-			dev_err(&pdev->dev, "%s: invalid 'nand-bus-width'\n",
+			dev_err(dev, "%s: invalid 'nand-bus-width'\n",
 				child->name);
 			ret = -EINVAL;
 			goto err;
@@ -1292,10 +1293,18 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
 
 		gpmc_s.device_nand = true;
 	} else {
-		ret = of_property_read_u32(child, "bank-width",
-					   &gpmc_s.device_width);
-		if (ret < 0)
+		if (of_property_read_u32(child, "bank-width",
+					 &gpmc_s.device_width)) {
+			dev_err(dev, "%s: no 'bank-width' property\n",
+				child->name);
+			goto err;
+		}
+
+		if (gpmc_s.device_width < 1 || gpmc_s.device_width > 2) {
+			dev_err(dev, "%s: invalid 'bank-width'\n",
+				child->name);
 			goto err;
+		}
 	}
 
 	ret = gpmc_cs_program_settings(cs, &gpmc_s);
-- 
1.8.3.2

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

* [PATCH 14/36] ARM: OMAP2+: gpmc: Allow drivers to reconfigure GPMC settings & timings
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Some devices (e.g. TUSB6010, omap-onenand) need to reconfigure the GPMC
timings in order to operate with different peripheral clock frequencies.
Introduce omap_gpmc_retime() to allow them to do that. The driver
needs to pass the chips select number, GPMC settings and Device timings to
omap_gpmc_retime().

NOTE: Device tree and board code must still pass the most conservative
timings to GPMC so that the device can be probed by the respective driver.
e.g. Onenand must operate in asynchronous mode at bootup. The device driver
can then request for more optimal timings via omap_gpmc_retime().

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.c              | 36 +++++++++++++++++++++++++++++++++
 include/linux/platform_data/gpmc-omap.h | 12 +++++++++++
 2 files changed, 48 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 70cb6b0..90b7686 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1542,6 +1542,42 @@ static int __init omap_gpmc_init(void)
 }
 omap_postcore_initcall(omap_gpmc_init);
 
+/**
+ * omap_gpmc_retime - Reconfigre GPMC timings for the device
+ *
+ * @cs		Chip select number
+ * @gpmc_s	GPMC settings
+ * @dev_t	New device timings to set
+ */
+int omap_gpmc_retime(int cs, struct gpmc_settings *gpmc_s,
+		     struct gpmc_device_timings *dev_t)
+{
+	struct gpmc_timings gpmc_t;
+	struct device *dev = gpmc_dev;
+
+	if (!gpmc_dev)
+		return -ENODEV;
+
+	if (cs < 0 || cs >= gpmc_cs_num) {
+		dev_err(dev, "%s: Invalid find Chip Select\n", __func__);
+		return cs;
+	}
+
+	if (gpmc_cs_program_settings(cs, gpmc_s)) {
+		dev_err(dev, "%s: Failed to set GPMC settings\n", __func__);
+		return -EINVAL;
+	}
+
+	gpmc_calc_timings(&gpmc_t, gpmc_s, dev_t);
+	if (gpmc_cs_set_timings(cs, &gpmc_t)) {
+		dev_err(dev, "%s: Failed to set GPMC timings\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(omap_gpmc_retime);
+
 static struct omap3_gpmc_regs gpmc_context;
 
 void omap3_gpmc_save_context(void)
diff --git a/include/linux/platform_data/gpmc-omap.h b/include/linux/platform_data/gpmc-omap.h
index e861112..0d40c2a 100644
--- a/include/linux/platform_data/gpmc-omap.h
+++ b/include/linux/platform_data/gpmc-omap.h
@@ -166,4 +166,16 @@ struct gpmc_omap_platform_data {
 	struct gpmc_omap_cs_data cs[GPMC_CS_NUM];
 };
 
+#ifdef CONFIG_ARCH_OMAP2PLUS
+int omap_gpmc_retime(int cs, struct gpmc_settings *gpmc_s,
+		     struct gpmc_device_timings *dev_t);
+#else
+static inline int omap_gpmc_retime(int cs,
+				   struct gpmc_settings *gpmc_s,
+				   struct gpmc_device_timings *dev_t)
+{
+	return 0;
+}
+#endif /* CONFIG_ARCH_OMAP2PLUS */
+
 #endif /* _GPMC_OMAP_H */
-- 
1.8.3.2


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

* [PATCH 14/36] ARM: OMAP2+: gpmc: Allow drivers to reconfigure GPMC settings & timings
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Some devices (e.g. TUSB6010, omap-onenand) need to reconfigure the GPMC
timings in order to operate with different peripheral clock frequencies.
Introduce omap_gpmc_retime() to allow them to do that. The driver
needs to pass the chips select number, GPMC settings and Device timings to
omap_gpmc_retime().

NOTE: Device tree and board code must still pass the most conservative
timings to GPMC so that the device can be probed by the respective driver.
e.g. Onenand must operate in asynchronous mode at bootup. The device driver
can then request for more optimal timings via omap_gpmc_retime().

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.c              | 36 +++++++++++++++++++++++++++++++++
 include/linux/platform_data/gpmc-omap.h | 12 +++++++++++
 2 files changed, 48 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 70cb6b0..90b7686 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1542,6 +1542,42 @@ static int __init omap_gpmc_init(void)
 }
 omap_postcore_initcall(omap_gpmc_init);
 
+/**
+ * omap_gpmc_retime - Reconfigre GPMC timings for the device
+ *
+ * @cs		Chip select number
+ * @gpmc_s	GPMC settings
+ * @dev_t	New device timings to set
+ */
+int omap_gpmc_retime(int cs, struct gpmc_settings *gpmc_s,
+		     struct gpmc_device_timings *dev_t)
+{
+	struct gpmc_timings gpmc_t;
+	struct device *dev = gpmc_dev;
+
+	if (!gpmc_dev)
+		return -ENODEV;
+
+	if (cs < 0 || cs >= gpmc_cs_num) {
+		dev_err(dev, "%s: Invalid find Chip Select\n", __func__);
+		return cs;
+	}
+
+	if (gpmc_cs_program_settings(cs, gpmc_s)) {
+		dev_err(dev, "%s: Failed to set GPMC settings\n", __func__);
+		return -EINVAL;
+	}
+
+	gpmc_calc_timings(&gpmc_t, gpmc_s, dev_t);
+	if (gpmc_cs_set_timings(cs, &gpmc_t)) {
+		dev_err(dev, "%s: Failed to set GPMC timings\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(omap_gpmc_retime);
+
 static struct omap3_gpmc_regs gpmc_context;
 
 void omap3_gpmc_save_context(void)
diff --git a/include/linux/platform_data/gpmc-omap.h b/include/linux/platform_data/gpmc-omap.h
index e861112..0d40c2a 100644
--- a/include/linux/platform_data/gpmc-omap.h
+++ b/include/linux/platform_data/gpmc-omap.h
@@ -166,4 +166,16 @@ struct gpmc_omap_platform_data {
 	struct gpmc_omap_cs_data cs[GPMC_CS_NUM];
 };
 
+#ifdef CONFIG_ARCH_OMAP2PLUS
+int omap_gpmc_retime(int cs, struct gpmc_settings *gpmc_s,
+		     struct gpmc_device_timings *dev_t);
+#else
+static inline int omap_gpmc_retime(int cs,
+				   struct gpmc_settings *gpmc_s,
+				   struct gpmc_device_timings *dev_t)
+{
+	return 0;
+}
+#endif /* CONFIG_ARCH_OMAP2PLUS */
+
 #endif /* _GPMC_OMAP_H */
-- 
1.8.3.2

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

* [PATCH 14/36] ARM: OMAP2+: gpmc: Allow drivers to reconfigure GPMC settings & timings
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Some devices (e.g. TUSB6010, omap-onenand) need to reconfigure the GPMC
timings in order to operate with different peripheral clock frequencies.
Introduce omap_gpmc_retime() to allow them to do that. The driver
needs to pass the chips select number, GPMC settings and Device timings to
omap_gpmc_retime().

NOTE: Device tree and board code must still pass the most conservative
timings to GPMC so that the device can be probed by the respective driver.
e.g. Onenand must operate in asynchronous mode at bootup. The device driver
can then request for more optimal timings via omap_gpmc_retime().

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.c              | 36 +++++++++++++++++++++++++++++++++
 include/linux/platform_data/gpmc-omap.h | 12 +++++++++++
 2 files changed, 48 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 70cb6b0..90b7686 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1542,6 +1542,42 @@ static int __init omap_gpmc_init(void)
 }
 omap_postcore_initcall(omap_gpmc_init);
 
+/**
+ * omap_gpmc_retime - Reconfigre GPMC timings for the device
+ *
+ * @cs		Chip select number
+ * @gpmc_s	GPMC settings
+ * @dev_t	New device timings to set
+ */
+int omap_gpmc_retime(int cs, struct gpmc_settings *gpmc_s,
+		     struct gpmc_device_timings *dev_t)
+{
+	struct gpmc_timings gpmc_t;
+	struct device *dev = gpmc_dev;
+
+	if (!gpmc_dev)
+		return -ENODEV;
+
+	if (cs < 0 || cs >= gpmc_cs_num) {
+		dev_err(dev, "%s: Invalid find Chip Select\n", __func__);
+		return cs;
+	}
+
+	if (gpmc_cs_program_settings(cs, gpmc_s)) {
+		dev_err(dev, "%s: Failed to set GPMC settings\n", __func__);
+		return -EINVAL;
+	}
+
+	gpmc_calc_timings(&gpmc_t, gpmc_s, dev_t);
+	if (gpmc_cs_set_timings(cs, &gpmc_t)) {
+		dev_err(dev, "%s: Failed to set GPMC timings\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(omap_gpmc_retime);
+
 static struct omap3_gpmc_regs gpmc_context;
 
 void omap3_gpmc_save_context(void)
diff --git a/include/linux/platform_data/gpmc-omap.h b/include/linux/platform_data/gpmc-omap.h
index e861112..0d40c2a 100644
--- a/include/linux/platform_data/gpmc-omap.h
+++ b/include/linux/platform_data/gpmc-omap.h
@@ -166,4 +166,16 @@ struct gpmc_omap_platform_data {
 	struct gpmc_omap_cs_data cs[GPMC_CS_NUM];
 };
 
+#ifdef CONFIG_ARCH_OMAP2PLUS
+int omap_gpmc_retime(int cs, struct gpmc_settings *gpmc_s,
+		     struct gpmc_device_timings *dev_t);
+#else
+static inline int omap_gpmc_retime(int cs,
+				   struct gpmc_settings *gpmc_s,
+				   struct gpmc_device_timings *dev_t)
+{
+	return 0;
+}
+#endif /* CONFIG_ARCH_OMAP2PLUS */
+
 #endif /* _GPMC_OMAP_H */
-- 
1.8.3.2

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

* [PATCH 15/36] ARM: OMAP2+: gpmc: Allow drivers to query GPMC_CLK period
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

GPMC_CLK is the external clock output pin that is used for syncronous
accesses.

Device drivers need to know the fastest possible GPMC_CLK period in order
to calculate the most optimal device timings. Add the function
omap_gpmc_get_clk_period() to allow drivers to get the nearset possible
(equal to or greater than) GPMC_CLK period given the minimum
clock period supported by the attached device.

This is especially needed by the onenand driver as it calculates
device timings on the fly for various onenand speed grades.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.c              | 38 +++++++++++++++++++++++++++++++++
 include/linux/platform_data/gpmc-omap.h |  8 +++++++
 2 files changed, 46 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 90b7686..50ef1a9 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1578,6 +1578,44 @@ int omap_gpmc_retime(int cs, struct gpmc_settings *gpmc_s,
 }
 EXPORT_SYMBOL_GPL(omap_gpmc_retime);
 
+/**
+ * omap_gpmc_get_clk_period - Get the nearest possible (equal to or higer) GPMC
+ *				synchronous clock (GPMC_CLK) period.
+ *
+ * @cs		Chip select number
+ * @min_ps	Minimum synchronous clock period supporded by the device
+ *
+ * Returns the nearest possible GPMC clock period in picoseconds, equal to or
+ * higher than the requested period. 0 in case of error.
+ */
+unsigned long omap_gpmc_get_clk_period(int cs,
+				       unsigned long min_ps)
+{
+	int div;
+	unsigned long clk_ps;
+	struct device *dev = gpmc_dev;
+
+	if (!gpmc_dev)
+		return 0;
+
+	if (cs < 0 || cs >= gpmc_cs_num) {
+		dev_err(dev, "%s: Invalid Chip Select\n", __func__);
+		return cs;
+	}
+
+	div = gpmc_calc_divider(min_ps);
+	if (div < 0) {
+		dev_err(dev, "%s: Can't support requested clock period %lu ps\n",
+			__func__, min_ps);
+		return 0;
+	}
+
+	clk_ps = gpmc_get_fclk_period() * div;
+
+	return clk_ps;
+}
+EXPORT_SYMBOL_GPL(omap_gpmc_get_clk_period);
+
 static struct omap3_gpmc_regs gpmc_context;
 
 void omap3_gpmc_save_context(void)
diff --git a/include/linux/platform_data/gpmc-omap.h b/include/linux/platform_data/gpmc-omap.h
index 0d40c2a..05e4b6f 100644
--- a/include/linux/platform_data/gpmc-omap.h
+++ b/include/linux/platform_data/gpmc-omap.h
@@ -169,6 +169,8 @@ struct gpmc_omap_platform_data {
 #ifdef CONFIG_ARCH_OMAP2PLUS
 int omap_gpmc_retime(int cs, struct gpmc_settings *gpmc_s,
 		     struct gpmc_device_timings *dev_t);
+unsigned long omap_gpmc_get_clk_period(int cs,
+				       unsigned long min_ps);
 #else
 static inline int omap_gpmc_retime(int cs,
 				   struct gpmc_settings *gpmc_s,
@@ -176,6 +178,12 @@ static inline int omap_gpmc_retime(int cs,
 {
 	return 0;
 }
+
+static inline unsigned long omap_gpmc_get_clk_period(int cs,
+						     unsigned long min_ps)
+{
+	return 0;
+}
 #endif /* CONFIG_ARCH_OMAP2PLUS */
 
 #endif /* _GPMC_OMAP_H */
-- 
1.8.3.2


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

* [PATCH 15/36] ARM: OMAP2+: gpmc: Allow drivers to query GPMC_CLK period
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

GPMC_CLK is the external clock output pin that is used for syncronous
accesses.

Device drivers need to know the fastest possible GPMC_CLK period in order
to calculate the most optimal device timings. Add the function
omap_gpmc_get_clk_period() to allow drivers to get the nearset possible
(equal to or greater than) GPMC_CLK period given the minimum
clock period supported by the attached device.

This is especially needed by the onenand driver as it calculates
device timings on the fly for various onenand speed grades.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.c              | 38 +++++++++++++++++++++++++++++++++
 include/linux/platform_data/gpmc-omap.h |  8 +++++++
 2 files changed, 46 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 90b7686..50ef1a9 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1578,6 +1578,44 @@ int omap_gpmc_retime(int cs, struct gpmc_settings *gpmc_s,
 }
 EXPORT_SYMBOL_GPL(omap_gpmc_retime);
 
+/**
+ * omap_gpmc_get_clk_period - Get the nearest possible (equal to or higer) GPMC
+ *				synchronous clock (GPMC_CLK) period.
+ *
+ * @cs		Chip select number
+ * @min_ps	Minimum synchronous clock period supporded by the device
+ *
+ * Returns the nearest possible GPMC clock period in picoseconds, equal to or
+ * higher than the requested period. 0 in case of error.
+ */
+unsigned long omap_gpmc_get_clk_period(int cs,
+				       unsigned long min_ps)
+{
+	int div;
+	unsigned long clk_ps;
+	struct device *dev = gpmc_dev;
+
+	if (!gpmc_dev)
+		return 0;
+
+	if (cs < 0 || cs >= gpmc_cs_num) {
+		dev_err(dev, "%s: Invalid Chip Select\n", __func__);
+		return cs;
+	}
+
+	div = gpmc_calc_divider(min_ps);
+	if (div < 0) {
+		dev_err(dev, "%s: Can't support requested clock period %lu ps\n",
+			__func__, min_ps);
+		return 0;
+	}
+
+	clk_ps = gpmc_get_fclk_period() * div;
+
+	return clk_ps;
+}
+EXPORT_SYMBOL_GPL(omap_gpmc_get_clk_period);
+
 static struct omap3_gpmc_regs gpmc_context;
 
 void omap3_gpmc_save_context(void)
diff --git a/include/linux/platform_data/gpmc-omap.h b/include/linux/platform_data/gpmc-omap.h
index 0d40c2a..05e4b6f 100644
--- a/include/linux/platform_data/gpmc-omap.h
+++ b/include/linux/platform_data/gpmc-omap.h
@@ -169,6 +169,8 @@ struct gpmc_omap_platform_data {
 #ifdef CONFIG_ARCH_OMAP2PLUS
 int omap_gpmc_retime(int cs, struct gpmc_settings *gpmc_s,
 		     struct gpmc_device_timings *dev_t);
+unsigned long omap_gpmc_get_clk_period(int cs,
+				       unsigned long min_ps);
 #else
 static inline int omap_gpmc_retime(int cs,
 				   struct gpmc_settings *gpmc_s,
@@ -176,6 +178,12 @@ static inline int omap_gpmc_retime(int cs,
 {
 	return 0;
 }
+
+static inline unsigned long omap_gpmc_get_clk_period(int cs,
+						     unsigned long min_ps)
+{
+	return 0;
+}
 #endif /* CONFIG_ARCH_OMAP2PLUS */
 
 #endif /* _GPMC_OMAP_H */
-- 
1.8.3.2


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

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

* [PATCH 15/36] ARM: OMAP2+: gpmc: Allow drivers to query GPMC_CLK period
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

GPMC_CLK is the external clock output pin that is used for syncronous
accesses.

Device drivers need to know the fastest possible GPMC_CLK period in order
to calculate the most optimal device timings. Add the function
omap_gpmc_get_clk_period() to allow drivers to get the nearset possible
(equal to or greater than) GPMC_CLK period given the minimum
clock period supported by the attached device.

This is especially needed by the onenand driver as it calculates
device timings on the fly for various onenand speed grades.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.c              | 38 +++++++++++++++++++++++++++++++++
 include/linux/platform_data/gpmc-omap.h |  8 +++++++
 2 files changed, 46 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 90b7686..50ef1a9 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1578,6 +1578,44 @@ int omap_gpmc_retime(int cs, struct gpmc_settings *gpmc_s,
 }
 EXPORT_SYMBOL_GPL(omap_gpmc_retime);
 
+/**
+ * omap_gpmc_get_clk_period - Get the nearest possible (equal to or higer) GPMC
+ *				synchronous clock (GPMC_CLK) period.
+ *
+ * @cs		Chip select number
+ * @min_ps	Minimum synchronous clock period supporded by the device
+ *
+ * Returns the nearest possible GPMC clock period in picoseconds, equal to or
+ * higher than the requested period. 0 in case of error.
+ */
+unsigned long omap_gpmc_get_clk_period(int cs,
+				       unsigned long min_ps)
+{
+	int div;
+	unsigned long clk_ps;
+	struct device *dev = gpmc_dev;
+
+	if (!gpmc_dev)
+		return 0;
+
+	if (cs < 0 || cs >= gpmc_cs_num) {
+		dev_err(dev, "%s: Invalid Chip Select\n", __func__);
+		return cs;
+	}
+
+	div = gpmc_calc_divider(min_ps);
+	if (div < 0) {
+		dev_err(dev, "%s: Can't support requested clock period %lu ps\n",
+			__func__, min_ps);
+		return 0;
+	}
+
+	clk_ps = gpmc_get_fclk_period() * div;
+
+	return clk_ps;
+}
+EXPORT_SYMBOL_GPL(omap_gpmc_get_clk_period);
+
 static struct omap3_gpmc_regs gpmc_context;
 
 void omap3_gpmc_save_context(void)
diff --git a/include/linux/platform_data/gpmc-omap.h b/include/linux/platform_data/gpmc-omap.h
index 0d40c2a..05e4b6f 100644
--- a/include/linux/platform_data/gpmc-omap.h
+++ b/include/linux/platform_data/gpmc-omap.h
@@ -169,6 +169,8 @@ struct gpmc_omap_platform_data {
 #ifdef CONFIG_ARCH_OMAP2PLUS
 int omap_gpmc_retime(int cs, struct gpmc_settings *gpmc_s,
 		     struct gpmc_device_timings *dev_t);
+unsigned long omap_gpmc_get_clk_period(int cs,
+				       unsigned long min_ps);
 #else
 static inline int omap_gpmc_retime(int cs,
 				   struct gpmc_settings *gpmc_s,
@@ -176,6 +178,12 @@ static inline int omap_gpmc_retime(int cs,
 {
 	return 0;
 }
+
+static inline unsigned long omap_gpmc_get_clk_period(int cs,
+						     unsigned long min_ps)
+{
+	return 0;
+}
 #endif /* CONFIG_ARCH_OMAP2PLUS */
 
 #endif /* _GPMC_OMAP_H */
-- 
1.8.3.2

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

* [PATCH 16/36] mtd: onenand: omap: Remove regulator management code
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

None of the OMAP platforms are suppying the "regulator_can_sleep"
parameter via platform data. Regulator management is generic
enough to be done in onenand_base driver if required.

Mark the "regulator_can_sleep" platform data parameter as deprecated.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/mtd/onenand/omap2.c                     | 42 +------------------------
 include/linux/platform_data/mtd-onenand-omap2.h |  3 +-
 2 files changed, 3 insertions(+), 42 deletions(-)

diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index d945473..a5f5ad8 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -34,7 +34,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/io.h>
 #include <linux/slab.h>
-#include <linux/regulator/consumer.h>
 
 #include <asm/mach/flash.h>
 #include <linux/platform_data/mtd-onenand-omap2.h>
@@ -59,7 +58,6 @@ struct omap2_onenand {
 	int dma_channel;
 	int freq;
 	int (*setup)(void __iomem *base, int *freq_ptr);
-	struct regulator *regulator;
 	u8 flags;
 };
 
@@ -583,30 +581,6 @@ static void omap2_onenand_shutdown(struct platform_device *pdev)
 	memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE);
 }
 
-static int omap2_onenand_enable(struct mtd_info *mtd)
-{
-	int ret;
-	struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
-
-	ret = regulator_enable(c->regulator);
-	if (ret != 0)
-		dev_err(&c->pdev->dev, "can't enable regulator\n");
-
-	return ret;
-}
-
-static int omap2_onenand_disable(struct mtd_info *mtd)
-{
-	int ret;
-	struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
-
-	ret = regulator_disable(c->regulator);
-	if (ret != 0)
-		dev_err(&c->pdev->dev, "can't disable regulator\n");
-
-	return ret;
-}
-
 static int omap2_onenand_probe(struct platform_device *pdev)
 {
 	struct omap_onenand_platform_data *pdata;
@@ -728,22 +702,11 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 		}
 	}
 
-	if (pdata->regulator_can_sleep) {
-		c->regulator = regulator_get(&pdev->dev, "vonenand");
-		if (IS_ERR(c->regulator)) {
-			dev_err(&pdev->dev,  "Failed to get regulator\n");
-			r = PTR_ERR(c->regulator);
-			goto err_release_dma;
-		}
-		c->onenand.enable = omap2_onenand_enable;
-		c->onenand.disable = omap2_onenand_disable;
-	}
-
 	if (pdata->skip_initial_unlocking)
 		this->options |= ONENAND_SKIP_INITIAL_UNLOCKING;
 
 	if ((r = onenand_scan(&c->mtd, 1)) < 0)
-		goto err_release_regulator;
+		goto err_release_dma;
 
 	ppdata.of_node = pdata->of_node;
 	r = mtd_device_parse_register(&c->mtd, NULL, &ppdata,
@@ -758,8 +721,6 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 
 err_release_onenand:
 	onenand_release(&c->mtd);
-err_release_regulator:
-	regulator_put(c->regulator);
 err_release_dma:
 	if (c->dma_channel != -1)
 		omap_free_dma(c->dma_channel);
@@ -783,7 +744,6 @@ static int omap2_onenand_remove(struct platform_device *pdev)
 	struct omap2_onenand *c = dev_get_drvdata(&pdev->dev);
 
 	onenand_release(&c->mtd);
-	regulator_put(c->regulator);
 	if (c->dma_channel != -1)
 		omap_free_dma(c->dma_channel);
 	omap2_onenand_shutdown(pdev);
diff --git a/include/linux/platform_data/mtd-onenand-omap2.h b/include/linux/platform_data/mtd-onenand-omap2.h
index 56ff0e6..445b41e 100644
--- a/include/linux/platform_data/mtd-onenand-omap2.h
+++ b/include/linux/platform_data/mtd-onenand-omap2.h
@@ -25,10 +25,11 @@ struct omap_onenand_platform_data {
 	int			(*onenand_setup)(void __iomem *, int *freq_ptr);
 	int			dma_channel;
 	u8			flags;
-	u8			regulator_can_sleep;
 	u8			skip_initial_unlocking;
 
 	/* for passing the partitions */
 	struct device_node	*of_node;
+
+	u8			regulator_can_sleep;	/* deprecated */
 };
 #endif
-- 
1.8.3.2


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

* [PATCH 16/36] mtd: onenand: omap: Remove regulator management code
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

None of the OMAP platforms are suppying the "regulator_can_sleep"
parameter via platform data. Regulator management is generic
enough to be done in onenand_base driver if required.

Mark the "regulator_can_sleep" platform data parameter as deprecated.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/mtd/onenand/omap2.c                     | 42 +------------------------
 include/linux/platform_data/mtd-onenand-omap2.h |  3 +-
 2 files changed, 3 insertions(+), 42 deletions(-)

diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index d945473..a5f5ad8 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -34,7 +34,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/io.h>
 #include <linux/slab.h>
-#include <linux/regulator/consumer.h>
 
 #include <asm/mach/flash.h>
 #include <linux/platform_data/mtd-onenand-omap2.h>
@@ -59,7 +58,6 @@ struct omap2_onenand {
 	int dma_channel;
 	int freq;
 	int (*setup)(void __iomem *base, int *freq_ptr);
-	struct regulator *regulator;
 	u8 flags;
 };
 
@@ -583,30 +581,6 @@ static void omap2_onenand_shutdown(struct platform_device *pdev)
 	memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE);
 }
 
-static int omap2_onenand_enable(struct mtd_info *mtd)
-{
-	int ret;
-	struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
-
-	ret = regulator_enable(c->regulator);
-	if (ret != 0)
-		dev_err(&c->pdev->dev, "can't enable regulator\n");
-
-	return ret;
-}
-
-static int omap2_onenand_disable(struct mtd_info *mtd)
-{
-	int ret;
-	struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
-
-	ret = regulator_disable(c->regulator);
-	if (ret != 0)
-		dev_err(&c->pdev->dev, "can't disable regulator\n");
-
-	return ret;
-}
-
 static int omap2_onenand_probe(struct platform_device *pdev)
 {
 	struct omap_onenand_platform_data *pdata;
@@ -728,22 +702,11 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 		}
 	}
 
-	if (pdata->regulator_can_sleep) {
-		c->regulator = regulator_get(&pdev->dev, "vonenand");
-		if (IS_ERR(c->regulator)) {
-			dev_err(&pdev->dev,  "Failed to get regulator\n");
-			r = PTR_ERR(c->regulator);
-			goto err_release_dma;
-		}
-		c->onenand.enable = omap2_onenand_enable;
-		c->onenand.disable = omap2_onenand_disable;
-	}
-
 	if (pdata->skip_initial_unlocking)
 		this->options |= ONENAND_SKIP_INITIAL_UNLOCKING;
 
 	if ((r = onenand_scan(&c->mtd, 1)) < 0)
-		goto err_release_regulator;
+		goto err_release_dma;
 
 	ppdata.of_node = pdata->of_node;
 	r = mtd_device_parse_register(&c->mtd, NULL, &ppdata,
@@ -758,8 +721,6 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 
 err_release_onenand:
 	onenand_release(&c->mtd);
-err_release_regulator:
-	regulator_put(c->regulator);
 err_release_dma:
 	if (c->dma_channel != -1)
 		omap_free_dma(c->dma_channel);
@@ -783,7 +744,6 @@ static int omap2_onenand_remove(struct platform_device *pdev)
 	struct omap2_onenand *c = dev_get_drvdata(&pdev->dev);
 
 	onenand_release(&c->mtd);
-	regulator_put(c->regulator);
 	if (c->dma_channel != -1)
 		omap_free_dma(c->dma_channel);
 	omap2_onenand_shutdown(pdev);
diff --git a/include/linux/platform_data/mtd-onenand-omap2.h b/include/linux/platform_data/mtd-onenand-omap2.h
index 56ff0e6..445b41e 100644
--- a/include/linux/platform_data/mtd-onenand-omap2.h
+++ b/include/linux/platform_data/mtd-onenand-omap2.h
@@ -25,10 +25,11 @@ struct omap_onenand_platform_data {
 	int			(*onenand_setup)(void __iomem *, int *freq_ptr);
 	int			dma_channel;
 	u8			flags;
-	u8			regulator_can_sleep;
 	u8			skip_initial_unlocking;
 
 	/* for passing the partitions */
 	struct device_node	*of_node;
+
+	u8			regulator_can_sleep;	/* deprecated */
 };
 #endif
-- 
1.8.3.2


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

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

* [PATCH 16/36] mtd: onenand: omap: Remove regulator management code
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

None of the OMAP platforms are suppying the "regulator_can_sleep"
parameter via platform data. Regulator management is generic
enough to be done in onenand_base driver if required.

Mark the "regulator_can_sleep" platform data parameter as deprecated.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/mtd/onenand/omap2.c                     | 42 +------------------------
 include/linux/platform_data/mtd-onenand-omap2.h |  3 +-
 2 files changed, 3 insertions(+), 42 deletions(-)

diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index d945473..a5f5ad8 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -34,7 +34,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/io.h>
 #include <linux/slab.h>
-#include <linux/regulator/consumer.h>
 
 #include <asm/mach/flash.h>
 #include <linux/platform_data/mtd-onenand-omap2.h>
@@ -59,7 +58,6 @@ struct omap2_onenand {
 	int dma_channel;
 	int freq;
 	int (*setup)(void __iomem *base, int *freq_ptr);
-	struct regulator *regulator;
 	u8 flags;
 };
 
@@ -583,30 +581,6 @@ static void omap2_onenand_shutdown(struct platform_device *pdev)
 	memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE);
 }
 
-static int omap2_onenand_enable(struct mtd_info *mtd)
-{
-	int ret;
-	struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
-
-	ret = regulator_enable(c->regulator);
-	if (ret != 0)
-		dev_err(&c->pdev->dev, "can't enable regulator\n");
-
-	return ret;
-}
-
-static int omap2_onenand_disable(struct mtd_info *mtd)
-{
-	int ret;
-	struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
-
-	ret = regulator_disable(c->regulator);
-	if (ret != 0)
-		dev_err(&c->pdev->dev, "can't disable regulator\n");
-
-	return ret;
-}
-
 static int omap2_onenand_probe(struct platform_device *pdev)
 {
 	struct omap_onenand_platform_data *pdata;
@@ -728,22 +702,11 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 		}
 	}
 
-	if (pdata->regulator_can_sleep) {
-		c->regulator = regulator_get(&pdev->dev, "vonenand");
-		if (IS_ERR(c->regulator)) {
-			dev_err(&pdev->dev,  "Failed to get regulator\n");
-			r = PTR_ERR(c->regulator);
-			goto err_release_dma;
-		}
-		c->onenand.enable = omap2_onenand_enable;
-		c->onenand.disable = omap2_onenand_disable;
-	}
-
 	if (pdata->skip_initial_unlocking)
 		this->options |= ONENAND_SKIP_INITIAL_UNLOCKING;
 
 	if ((r = onenand_scan(&c->mtd, 1)) < 0)
-		goto err_release_regulator;
+		goto err_release_dma;
 
 	ppdata.of_node = pdata->of_node;
 	r = mtd_device_parse_register(&c->mtd, NULL, &ppdata,
@@ -758,8 +721,6 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 
 err_release_onenand:
 	onenand_release(&c->mtd);
-err_release_regulator:
-	regulator_put(c->regulator);
 err_release_dma:
 	if (c->dma_channel != -1)
 		omap_free_dma(c->dma_channel);
@@ -783,7 +744,6 @@ static int omap2_onenand_remove(struct platform_device *pdev)
 	struct omap2_onenand *c = dev_get_drvdata(&pdev->dev);
 
 	onenand_release(&c->mtd);
-	regulator_put(c->regulator);
 	if (c->dma_channel != -1)
 		omap_free_dma(c->dma_channel);
 	omap2_onenand_shutdown(pdev);
diff --git a/include/linux/platform_data/mtd-onenand-omap2.h b/include/linux/platform_data/mtd-onenand-omap2.h
index 56ff0e6..445b41e 100644
--- a/include/linux/platform_data/mtd-onenand-omap2.h
+++ b/include/linux/platform_data/mtd-onenand-omap2.h
@@ -25,10 +25,11 @@ struct omap_onenand_platform_data {
 	int			(*onenand_setup)(void __iomem *, int *freq_ptr);
 	int			dma_channel;
 	u8			flags;
-	u8			regulator_can_sleep;
 	u8			skip_initial_unlocking;
 
 	/* for passing the partitions */
 	struct device_node	*of_node;
+
+	u8			regulator_can_sleep;	/* deprecated */
 };
 #endif
-- 
1.8.3.2

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

* [PATCH 17/36] ARM: OMAP2+: gpmc-onenand: Use Async settings/timings by default
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Onenand device operates in Asynchronous mode by default. So
configure GPMC settings/timings based on Async mode before the onenand
device is created.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-onenand.c | 66 ++++++++++++++++++--------------------
 1 file changed, 32 insertions(+), 34 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index 8b6876c..bed8efe 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -61,9 +61,8 @@ static struct gpmc_settings onenand_sync = {
 	.wait_pin	= 0,
 };
 
-static void omap2_onenand_calc_async_timings(struct gpmc_timings *t)
+static void omap2_onenand_get_async_timings(struct gpmc_device_timings *dev_t)
 {
-	struct gpmc_device_timings dev_t;
 	const int t_cer = 15;
 	const int t_avdp = 12;
 	const int t_aavdh = 7;
@@ -74,20 +73,18 @@ static void omap2_onenand_calc_async_timings(struct gpmc_timings *t)
 	const int t_wpl = 40;
 	const int t_wph = 30;
 
-	memset(&dev_t, 0, sizeof(dev_t));
-
-	dev_t.t_avdp_r = max_t(int, t_avdp, t_cer) * 1000;
-	dev_t.t_avdp_w = dev_t.t_avdp_r;
-	dev_t.t_aavdh = t_aavdh * 1000;
-	dev_t.t_aa = t_aa * 1000;
-	dev_t.t_ce = t_ce * 1000;
-	dev_t.t_oe = t_oe * 1000;
-	dev_t.t_cez_r = t_cez * 1000;
-	dev_t.t_cez_w = dev_t.t_cez_r;
-	dev_t.t_wpl = t_wpl * 1000;
-	dev_t.t_wph = t_wph * 1000;
-
-	gpmc_calc_timings(t, &onenand_async, &dev_t);
+	memset(dev_t, 0, sizeof(*dev_t));
+
+	dev_t->t_avdp_r = max_t(int, t_avdp, t_cer) * 1000;
+	dev_t->t_avdp_w = dev_t->t_avdp_r;
+	dev_t->t_aavdh = t_aavdh * 1000;
+	dev_t->t_aa = t_aa * 1000;
+	dev_t->t_ce = t_ce * 1000;
+	dev_t->t_oe = t_oe * 1000;
+	dev_t->t_cez_r = t_cez * 1000;
+	dev_t->t_cez_w = dev_t->t_cez_r;
+	dev_t->t_wpl = t_wpl * 1000;
+	dev_t->t_wph = t_wph * 1000;
 }
 
 static void omap2_onenand_set_async_mode(void __iomem *onenand_base)
@@ -267,9 +264,10 @@ static void omap2_onenand_calc_sync_timings(struct gpmc_timings *t,
 	gpmc_calc_timings(t, &onenand_sync, &dev_t);
 }
 
-static int omap2_onenand_setup_async(void __iomem *onenand_base)
+static int omap2_onenand_setup_async(void)
 {
-	struct gpmc_timings t;
+	struct gpmc_timings gpmc_t;
+	struct gpmc_device_timings dev_t;
 	int ret;
 
 	if (gpmc_onenand_data->of_node) {
@@ -286,19 +284,14 @@ static int omap2_onenand_setup_async(void __iomem *onenand_base)
 		}
 	}
 
-	omap2_onenand_set_async_mode(onenand_base);
-
-	omap2_onenand_calc_async_timings(&t);
-
 	ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_async);
 	if (ret < 0)
 		return ret;
 
-	ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t);
-	if (ret < 0)
-		return ret;
-
-	omap2_onenand_set_async_mode(onenand_base);
+	omap2_onenand_get_async_timings(&dev_t);
+	gpmc_calc_timings(&gpmc_t, &onenand_async, &dev_t);
+	if (gpmc_cs_set_timings(gpmc_onenand_data->cs, &gpmc_t))
+		return -EINVAL;
 
 	return 0;
 }
@@ -349,11 +342,7 @@ static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr)
 	unsigned l = ONENAND_SYNC_READ | ONENAND_SYNC_READWRITE;
 	int ret;
 
-	ret = omap2_onenand_setup_async(onenand_base);
-	if (ret) {
-		dev_err(dev, "unable to set to async mode\n");
-		return ret;
-	}
+	omap2_onenand_set_async_mode(onenand_base);
 
 	if (!(gpmc_onenand_data->flags & l))
 		return 0;
@@ -396,9 +385,18 @@ void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
 	gpmc_onenand_resource.end = gpmc_onenand_resource.start +
 							ONENAND_IO_SIZE - 1;
 
+	if (omap2_onenand_setup_async()) {
+		pr_err("%s: Failed to setup ASYNC timings\n", __func__);
+		goto fail;
+	}
+
 	if (platform_device_register(&gpmc_onenand_device) < 0) {
 		dev_err(dev, "Unable to register OneNAND device\n");
-		gpmc_cs_free(gpmc_onenand_data->cs);
-		return;
+		goto fail;
 	}
+
+	return;
+
+fail:
+	gpmc_cs_free(gpmc_onenand_data->cs);
 }
-- 
1.8.3.2


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

* [PATCH 17/36] ARM: OMAP2+: gpmc-onenand: Use Async settings/timings by default
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Onenand device operates in Asynchronous mode by default. So
configure GPMC settings/timings based on Async mode before the onenand
device is created.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-onenand.c | 66 ++++++++++++++++++--------------------
 1 file changed, 32 insertions(+), 34 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index 8b6876c..bed8efe 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -61,9 +61,8 @@ static struct gpmc_settings onenand_sync = {
 	.wait_pin	= 0,
 };
 
-static void omap2_onenand_calc_async_timings(struct gpmc_timings *t)
+static void omap2_onenand_get_async_timings(struct gpmc_device_timings *dev_t)
 {
-	struct gpmc_device_timings dev_t;
 	const int t_cer = 15;
 	const int t_avdp = 12;
 	const int t_aavdh = 7;
@@ -74,20 +73,18 @@ static void omap2_onenand_calc_async_timings(struct gpmc_timings *t)
 	const int t_wpl = 40;
 	const int t_wph = 30;
 
-	memset(&dev_t, 0, sizeof(dev_t));
-
-	dev_t.t_avdp_r = max_t(int, t_avdp, t_cer) * 1000;
-	dev_t.t_avdp_w = dev_t.t_avdp_r;
-	dev_t.t_aavdh = t_aavdh * 1000;
-	dev_t.t_aa = t_aa * 1000;
-	dev_t.t_ce = t_ce * 1000;
-	dev_t.t_oe = t_oe * 1000;
-	dev_t.t_cez_r = t_cez * 1000;
-	dev_t.t_cez_w = dev_t.t_cez_r;
-	dev_t.t_wpl = t_wpl * 1000;
-	dev_t.t_wph = t_wph * 1000;
-
-	gpmc_calc_timings(t, &onenand_async, &dev_t);
+	memset(dev_t, 0, sizeof(*dev_t));
+
+	dev_t->t_avdp_r = max_t(int, t_avdp, t_cer) * 1000;
+	dev_t->t_avdp_w = dev_t->t_avdp_r;
+	dev_t->t_aavdh = t_aavdh * 1000;
+	dev_t->t_aa = t_aa * 1000;
+	dev_t->t_ce = t_ce * 1000;
+	dev_t->t_oe = t_oe * 1000;
+	dev_t->t_cez_r = t_cez * 1000;
+	dev_t->t_cez_w = dev_t->t_cez_r;
+	dev_t->t_wpl = t_wpl * 1000;
+	dev_t->t_wph = t_wph * 1000;
 }
 
 static void omap2_onenand_set_async_mode(void __iomem *onenand_base)
@@ -267,9 +264,10 @@ static void omap2_onenand_calc_sync_timings(struct gpmc_timings *t,
 	gpmc_calc_timings(t, &onenand_sync, &dev_t);
 }
 
-static int omap2_onenand_setup_async(void __iomem *onenand_base)
+static int omap2_onenand_setup_async(void)
 {
-	struct gpmc_timings t;
+	struct gpmc_timings gpmc_t;
+	struct gpmc_device_timings dev_t;
 	int ret;
 
 	if (gpmc_onenand_data->of_node) {
@@ -286,19 +284,14 @@ static int omap2_onenand_setup_async(void __iomem *onenand_base)
 		}
 	}
 
-	omap2_onenand_set_async_mode(onenand_base);
-
-	omap2_onenand_calc_async_timings(&t);
-
 	ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_async);
 	if (ret < 0)
 		return ret;
 
-	ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t);
-	if (ret < 0)
-		return ret;
-
-	omap2_onenand_set_async_mode(onenand_base);
+	omap2_onenand_get_async_timings(&dev_t);
+	gpmc_calc_timings(&gpmc_t, &onenand_async, &dev_t);
+	if (gpmc_cs_set_timings(gpmc_onenand_data->cs, &gpmc_t))
+		return -EINVAL;
 
 	return 0;
 }
@@ -349,11 +342,7 @@ static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr)
 	unsigned l = ONENAND_SYNC_READ | ONENAND_SYNC_READWRITE;
 	int ret;
 
-	ret = omap2_onenand_setup_async(onenand_base);
-	if (ret) {
-		dev_err(dev, "unable to set to async mode\n");
-		return ret;
-	}
+	omap2_onenand_set_async_mode(onenand_base);
 
 	if (!(gpmc_onenand_data->flags & l))
 		return 0;
@@ -396,9 +385,18 @@ void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
 	gpmc_onenand_resource.end = gpmc_onenand_resource.start +
 							ONENAND_IO_SIZE - 1;
 
+	if (omap2_onenand_setup_async()) {
+		pr_err("%s: Failed to setup ASYNC timings\n", __func__);
+		goto fail;
+	}
+
 	if (platform_device_register(&gpmc_onenand_device) < 0) {
 		dev_err(dev, "Unable to register OneNAND device\n");
-		gpmc_cs_free(gpmc_onenand_data->cs);
-		return;
+		goto fail;
 	}
+
+	return;
+
+fail:
+	gpmc_cs_free(gpmc_onenand_data->cs);
 }
-- 
1.8.3.2

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

* [PATCH 17/36] ARM: OMAP2+: gpmc-onenand: Use Async settings/timings by default
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Onenand device operates in Asynchronous mode by default. So
configure GPMC settings/timings based on Async mode before the onenand
device is created.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-onenand.c | 66 ++++++++++++++++++--------------------
 1 file changed, 32 insertions(+), 34 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index 8b6876c..bed8efe 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -61,9 +61,8 @@ static struct gpmc_settings onenand_sync = {
 	.wait_pin	= 0,
 };
 
-static void omap2_onenand_calc_async_timings(struct gpmc_timings *t)
+static void omap2_onenand_get_async_timings(struct gpmc_device_timings *dev_t)
 {
-	struct gpmc_device_timings dev_t;
 	const int t_cer = 15;
 	const int t_avdp = 12;
 	const int t_aavdh = 7;
@@ -74,20 +73,18 @@ static void omap2_onenand_calc_async_timings(struct gpmc_timings *t)
 	const int t_wpl = 40;
 	const int t_wph = 30;
 
-	memset(&dev_t, 0, sizeof(dev_t));
-
-	dev_t.t_avdp_r = max_t(int, t_avdp, t_cer) * 1000;
-	dev_t.t_avdp_w = dev_t.t_avdp_r;
-	dev_t.t_aavdh = t_aavdh * 1000;
-	dev_t.t_aa = t_aa * 1000;
-	dev_t.t_ce = t_ce * 1000;
-	dev_t.t_oe = t_oe * 1000;
-	dev_t.t_cez_r = t_cez * 1000;
-	dev_t.t_cez_w = dev_t.t_cez_r;
-	dev_t.t_wpl = t_wpl * 1000;
-	dev_t.t_wph = t_wph * 1000;
-
-	gpmc_calc_timings(t, &onenand_async, &dev_t);
+	memset(dev_t, 0, sizeof(*dev_t));
+
+	dev_t->t_avdp_r = max_t(int, t_avdp, t_cer) * 1000;
+	dev_t->t_avdp_w = dev_t->t_avdp_r;
+	dev_t->t_aavdh = t_aavdh * 1000;
+	dev_t->t_aa = t_aa * 1000;
+	dev_t->t_ce = t_ce * 1000;
+	dev_t->t_oe = t_oe * 1000;
+	dev_t->t_cez_r = t_cez * 1000;
+	dev_t->t_cez_w = dev_t->t_cez_r;
+	dev_t->t_wpl = t_wpl * 1000;
+	dev_t->t_wph = t_wph * 1000;
 }
 
 static void omap2_onenand_set_async_mode(void __iomem *onenand_base)
@@ -267,9 +264,10 @@ static void omap2_onenand_calc_sync_timings(struct gpmc_timings *t,
 	gpmc_calc_timings(t, &onenand_sync, &dev_t);
 }
 
-static int omap2_onenand_setup_async(void __iomem *onenand_base)
+static int omap2_onenand_setup_async(void)
 {
-	struct gpmc_timings t;
+	struct gpmc_timings gpmc_t;
+	struct gpmc_device_timings dev_t;
 	int ret;
 
 	if (gpmc_onenand_data->of_node) {
@@ -286,19 +284,14 @@ static int omap2_onenand_setup_async(void __iomem *onenand_base)
 		}
 	}
 
-	omap2_onenand_set_async_mode(onenand_base);
-
-	omap2_onenand_calc_async_timings(&t);
-
 	ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_async);
 	if (ret < 0)
 		return ret;
 
-	ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t);
-	if (ret < 0)
-		return ret;
-
-	omap2_onenand_set_async_mode(onenand_base);
+	omap2_onenand_get_async_timings(&dev_t);
+	gpmc_calc_timings(&gpmc_t, &onenand_async, &dev_t);
+	if (gpmc_cs_set_timings(gpmc_onenand_data->cs, &gpmc_t))
+		return -EINVAL;
 
 	return 0;
 }
@@ -349,11 +342,7 @@ static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr)
 	unsigned l = ONENAND_SYNC_READ | ONENAND_SYNC_READWRITE;
 	int ret;
 
-	ret = omap2_onenand_setup_async(onenand_base);
-	if (ret) {
-		dev_err(dev, "unable to set to async mode\n");
-		return ret;
-	}
+	omap2_onenand_set_async_mode(onenand_base);
 
 	if (!(gpmc_onenand_data->flags & l))
 		return 0;
@@ -396,9 +385,18 @@ void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
 	gpmc_onenand_resource.end = gpmc_onenand_resource.start +
 							ONENAND_IO_SIZE - 1;
 
+	if (omap2_onenand_setup_async()) {
+		pr_err("%s: Failed to setup ASYNC timings\n", __func__);
+		goto fail;
+	}
+
 	if (platform_device_register(&gpmc_onenand_device) < 0) {
 		dev_err(dev, "Unable to register OneNAND device\n");
-		gpmc_cs_free(gpmc_onenand_data->cs);
-		return;
+		goto fail;
 	}
+
+	return;
+
+fail:
+	gpmc_cs_free(gpmc_onenand_data->cs);
 }
-- 
1.8.3.2

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

* [PATCH 18/36] ARM: OMAP2+: gpmc-onenand: Move Synchronous setting code to drivers/
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Move the code that puts the onenand in synchronous mode
into the appropriate place i.e. drivers/mtd/onenand/omap2.c.

Make use of omap_gpmc_get_clk_period() and omap_gpmc_retime()
to calculate the necessary timings and configure the GPMC
parent's timings.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-onenand.c              | 262 +----------------------
 drivers/mtd/onenand/omap2.c                     | 264 +++++++++++++++++++++++-
 include/linux/platform_data/mtd-onenand-omap2.h |   2 +-
 3 files changed, 258 insertions(+), 270 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index bed8efe..d09c342 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -26,16 +26,6 @@
 
 #define	ONENAND_IO_SIZE	SZ_128K
 
-#define	ONENAND_FLAG_SYNCREAD	(1 << 0)
-#define	ONENAND_FLAG_SYNCWRITE	(1 << 1)
-#define	ONENAND_FLAG_HF		(1 << 2)
-#define	ONENAND_FLAG_VHF	(1 << 3)
-
-static unsigned onenand_flags;
-static unsigned latency;
-
-static struct omap_onenand_platform_data *gpmc_onenand_data;
-
 static struct resource gpmc_onenand_resource = {
 	.flags		= IORESOURCE_MEM,
 };
@@ -52,15 +42,6 @@ static struct gpmc_settings onenand_async = {
 	.mux_add_data	= GPMC_MUX_AD,
 };
 
-static struct gpmc_settings onenand_sync = {
-	.burst_read	= true,
-	.burst_wrap	= true,
-	.burst_len	= GPMC_BURST_16,
-	.device_width	= GPMC_DEVWIDTH_16BIT,
-	.mux_add_data	= GPMC_MUX_AD,
-	.wait_pin	= 0,
-};
-
 static void omap2_onenand_get_async_timings(struct gpmc_device_timings *dev_t)
 {
 	const int t_cer = 15;
@@ -87,184 +68,8 @@ static void omap2_onenand_get_async_timings(struct gpmc_device_timings *dev_t)
 	dev_t->t_wph = t_wph * 1000;
 }
 
-static void omap2_onenand_set_async_mode(void __iomem *onenand_base)
-{
-	u32 reg;
-
-	/* Ensure sync read and sync write are disabled */
-	reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
-	reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE;
-	writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
-}
-
-static void set_onenand_cfg(void __iomem *onenand_base)
-{
-	u32 reg;
-
-	reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
-	reg &= ~((0x7 << ONENAND_SYS_CFG1_BRL_SHIFT) | (0x7 << 9));
-	reg |=	(latency << ONENAND_SYS_CFG1_BRL_SHIFT) |
-		ONENAND_SYS_CFG1_BL_16;
-	if (onenand_flags & ONENAND_FLAG_SYNCREAD)
-		reg |= ONENAND_SYS_CFG1_SYNC_READ;
-	else
-		reg &= ~ONENAND_SYS_CFG1_SYNC_READ;
-	if (onenand_flags & ONENAND_FLAG_SYNCWRITE)
-		reg |= ONENAND_SYS_CFG1_SYNC_WRITE;
-	else
-		reg &= ~ONENAND_SYS_CFG1_SYNC_WRITE;
-	if (onenand_flags & ONENAND_FLAG_HF)
-		reg |= ONENAND_SYS_CFG1_HF;
-	else
-		reg &= ~ONENAND_SYS_CFG1_HF;
-	if (onenand_flags & ONENAND_FLAG_VHF)
-		reg |= ONENAND_SYS_CFG1_VHF;
-	else
-		reg &= ~ONENAND_SYS_CFG1_VHF;
-	writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
-}
-
-static int omap2_onenand_get_freq(struct omap_onenand_platform_data *cfg,
-				  void __iomem *onenand_base)
-{
-	u16 ver = readw(onenand_base + ONENAND_REG_VERSION_ID);
-	int freq;
-
-	switch ((ver >> 4) & 0xf) {
-	case 0:
-		freq = 40;
-		break;
-	case 1:
-		freq = 54;
-		break;
-	case 2:
-		freq = 66;
-		break;
-	case 3:
-		freq = 83;
-		break;
-	case 4:
-		freq = 104;
-		break;
-	default:
-		freq = 54;
-		break;
-	}
-
-	return freq;
-}
-
-static void omap2_onenand_calc_sync_timings(struct gpmc_timings *t,
-					    unsigned int flags,
-					    int freq)
-{
-	struct gpmc_device_timings dev_t;
-	const int t_cer  = 15;
-	const int t_avdp = 12;
-	const int t_cez  = 20; /* max of t_cez, t_oez */
-	const int t_wpl  = 40;
-	const int t_wph  = 30;
-	int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo;
-	int div, gpmc_clk_ns;
-
-	if (flags & ONENAND_SYNC_READ)
-		onenand_flags = ONENAND_FLAG_SYNCREAD;
-	else if (flags & ONENAND_SYNC_READWRITE)
-		onenand_flags = ONENAND_FLAG_SYNCREAD | ONENAND_FLAG_SYNCWRITE;
-
-	switch (freq) {
-	case 104:
-		min_gpmc_clk_period = 9600; /* 104 MHz */
-		t_ces   = 3;
-		t_avds  = 4;
-		t_avdh  = 2;
-		t_ach   = 3;
-		t_aavdh = 6;
-		t_rdyo  = 6;
-		break;
-	case 83:
-		min_gpmc_clk_period = 12000; /* 83 MHz */
-		t_ces   = 5;
-		t_avds  = 4;
-		t_avdh  = 2;
-		t_ach   = 6;
-		t_aavdh = 6;
-		t_rdyo  = 9;
-		break;
-	case 66:
-		min_gpmc_clk_period = 15000; /* 66 MHz */
-		t_ces   = 6;
-		t_avds  = 5;
-		t_avdh  = 2;
-		t_ach   = 6;
-		t_aavdh = 6;
-		t_rdyo  = 11;
-		break;
-	default:
-		min_gpmc_clk_period = 18500; /* 54 MHz */
-		t_ces   = 7;
-		t_avds  = 7;
-		t_avdh  = 7;
-		t_ach   = 9;
-		t_aavdh = 7;
-		t_rdyo  = 15;
-		onenand_flags &= ~ONENAND_FLAG_SYNCWRITE;
-		break;
-	}
-
-	div = gpmc_calc_divider(min_gpmc_clk_period);
-	gpmc_clk_ns = gpmc_ticks_to_ns(div);
-	if (gpmc_clk_ns < 15) /* >66Mhz */
-		onenand_flags |= ONENAND_FLAG_HF;
-	else
-		onenand_flags &= ~ONENAND_FLAG_HF;
-	if (gpmc_clk_ns < 12) /* >83Mhz */
-		onenand_flags |= ONENAND_FLAG_VHF;
-	else
-		onenand_flags &= ~ONENAND_FLAG_VHF;
-	if (onenand_flags & ONENAND_FLAG_VHF)
-		latency = 8;
-	else if (onenand_flags & ONENAND_FLAG_HF)
-		latency = 6;
-	else if (gpmc_clk_ns >= 25) /* 40 MHz*/
-		latency = 3;
-	else
-		latency = 4;
-
-	/* Set synchronous read timings */
-	memset(&dev_t, 0, sizeof(dev_t));
-
-	if (onenand_flags & ONENAND_FLAG_SYNCREAD)
-		onenand_sync.sync_read = true;
-	if (onenand_flags & ONENAND_FLAG_SYNCWRITE) {
-		onenand_sync.sync_write = true;
-		onenand_sync.burst_write = true;
-	} else {
-		dev_t.t_avdp_w = max(t_avdp, t_cer) * 1000;
-		dev_t.t_wpl = t_wpl * 1000;
-		dev_t.t_wph = t_wph * 1000;
-		dev_t.t_aavdh = t_aavdh * 1000;
-	}
-	dev_t.ce_xdelay = true;
-	dev_t.avd_xdelay = true;
-	dev_t.oe_xdelay = true;
-	dev_t.we_xdelay = true;
-	dev_t.clk = min_gpmc_clk_period;
-	dev_t.t_bacc = dev_t.clk;
-	dev_t.t_ces = t_ces * 1000;
-	dev_t.t_avds = t_avds * 1000;
-	dev_t.t_avdh = t_avdh * 1000;
-	dev_t.t_ach = t_ach * 1000;
-	dev_t.cyc_iaa = (latency + 1);
-	dev_t.t_cez_r = t_cez * 1000;
-	dev_t.t_cez_w = dev_t.t_cez_r;
-	dev_t.cyc_aavdh_oe = 1;
-	dev_t.t_rdyo = t_rdyo * 1000 + min_gpmc_clk_period;
-
-	gpmc_calc_timings(t, &onenand_sync, &dev_t);
-}
-
-static int omap2_onenand_setup_async(void)
+static int omap2_onenand_setup_async(struct omap_onenand_platform_data
+				     *gpmc_onenand_data)
 {
 	struct gpmc_timings gpmc_t;
 	struct gpmc_device_timings dev_t;
@@ -296,70 +101,11 @@ static int omap2_onenand_setup_async(void)
 	return 0;
 }
 
-static int omap2_onenand_setup_sync(void __iomem *onenand_base, int *freq_ptr)
-{
-	int ret, freq = *freq_ptr;
-	struct gpmc_timings t;
-
-	if (!freq) {
-		/* Very first call freq is not known */
-		freq = omap2_onenand_get_freq(gpmc_onenand_data, onenand_base);
-		set_onenand_cfg(onenand_base);
-	}
-
-	if (gpmc_onenand_data->of_node) {
-		gpmc_read_settings_dt(gpmc_onenand_data->of_node,
-				      &onenand_sync);
-	} else {
-		/*
-		 * FIXME: Appears to be legacy code from initial ONENAND commit.
-		 * Unclear what boards this is for and if this can be removed.
-		 */
-		if (!cpu_is_omap34xx())
-			onenand_sync.wait_on_read = true;
-	}
-
-	omap2_onenand_calc_sync_timings(&t, gpmc_onenand_data->flags, freq);
-
-	ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_sync);
-	if (ret < 0)
-		return ret;
-
-	ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t);
-	if (ret < 0)
-		return ret;
-
-	set_onenand_cfg(onenand_base);
-
-	*freq_ptr = freq;
-
-	return 0;
-}
-
-static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr)
-{
-	struct device *dev = &gpmc_onenand_device.dev;
-	unsigned l = ONENAND_SYNC_READ | ONENAND_SYNC_READWRITE;
-	int ret;
-
-	omap2_onenand_set_async_mode(onenand_base);
-
-	if (!(gpmc_onenand_data->flags & l))
-		return 0;
-
-	ret = omap2_onenand_setup_sync(onenand_base, freq_ptr);
-	if (ret)
-		dev_err(dev, "unable to set to sync mode\n");
-	return ret;
-}
-
-void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
+void gpmc_onenand_init(struct omap_onenand_platform_data *gpmc_onenand_data)
 {
 	int err;
 	struct device *dev = &gpmc_onenand_device.dev;
 
-	gpmc_onenand_data = _onenand_data;
-	gpmc_onenand_data->onenand_setup = gpmc_onenand_setup;
 	gpmc_onenand_device.dev.platform_data = gpmc_onenand_data;
 
 	if (cpu_is_omap24xx() &&
@@ -385,7 +131,7 @@ void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
 	gpmc_onenand_resource.end = gpmc_onenand_resource.start +
 							ONENAND_IO_SIZE - 1;
 
-	if (omap2_onenand_setup_async()) {
+	if (omap2_onenand_setup_async(gpmc_onenand_data)) {
 		pr_err("%s: Failed to setup ASYNC timings\n", __func__);
 		goto fail;
 	}
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index a5f5ad8..238dd7a 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -37,6 +37,7 @@
 
 #include <asm/mach/flash.h>
 #include <linux/platform_data/mtd-onenand-omap2.h>
+#include <linux/platform_data/gpmc-omap.h>
 #include <asm/gpio.h>
 
 #include <linux/omap-dma.h>
@@ -45,6 +46,12 @@
 
 #define ONENAND_BUFRAM_SIZE	(1024 * 5)
 
+/* Private flags */
+#define	ONENAND_FLAG_SYNCREAD	(1 << 0)
+#define	ONENAND_FLAG_SYNCWRITE	(1 << 1)
+#define	ONENAND_FLAG_HF		(1 << 2)
+#define	ONENAND_FLAG_VHF	(1 << 3)
+
 struct omap2_onenand {
 	struct platform_device *pdev;
 	int gpmc_cs;
@@ -57,8 +64,10 @@ struct omap2_onenand {
 	struct completion dma_done;
 	int dma_channel;
 	int freq;
-	int (*setup)(void __iomem *base, int *freq_ptr);
-	u8 flags;
+	u8 flags;		/* as per platform_data/mtd-onenand-omap2.h */
+	u8 priv_flags;		/* our internal flags */
+	unsigned latency;	/* latency settings for onenand SYS_CFG1 */
+	struct gpmc_settings sync_settings;	/* Synchronous GPMC settings */
 };
 
 static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data)
@@ -568,6 +577,243 @@ static int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area,
 
 #endif
 
+static void set_onenand_cfg(struct omap2_onenand *c)
+{
+	u32 reg;
+
+	reg = read_reg(c, ONENAND_REG_SYS_CFG1);
+	reg &= ~((0x7 << ONENAND_SYS_CFG1_BRL_SHIFT) | (0x7 << 9));
+	reg |=	(c->latency << ONENAND_SYS_CFG1_BRL_SHIFT) |
+		ONENAND_SYS_CFG1_BL_16;
+	if (c->priv_flags & ONENAND_FLAG_SYNCREAD)
+		reg |= ONENAND_SYS_CFG1_SYNC_READ;
+	else
+		reg &= ~ONENAND_SYS_CFG1_SYNC_READ;
+
+	if (c->priv_flags & ONENAND_FLAG_SYNCWRITE)
+		reg |= ONENAND_SYS_CFG1_SYNC_WRITE;
+	else
+		reg &= ~ONENAND_SYS_CFG1_SYNC_WRITE;
+
+	if (c->priv_flags & ONENAND_FLAG_HF)
+		reg |= ONENAND_SYS_CFG1_HF;
+	else
+		reg &= ~ONENAND_SYS_CFG1_HF;
+
+	if (c->priv_flags & ONENAND_FLAG_VHF)
+		reg |= ONENAND_SYS_CFG1_VHF;
+	else
+		reg &= ~ONENAND_SYS_CFG1_VHF;
+
+	write_reg(c, reg, ONENAND_REG_SYS_CFG1);
+}
+
+static int omap2_onenand_get_freq(struct omap2_onenand *c)
+{
+	u16 ver = read_reg(c, ONENAND_REG_VERSION_ID);
+	int freq;
+
+	switch ((ver >> 4) & 0xf) {
+	case 0:
+		freq = 40;
+		break;
+	case 1:
+		freq = 54;
+		break;
+	case 2:
+		freq = 66;
+		break;
+	case 3:
+		freq = 83;
+		break;
+	case 4:
+		freq = 104;
+		break;
+	default:
+		freq = 54;
+		break;
+	}
+
+	return freq;
+}
+
+static void omap2_onenand_get_sync_timings(struct omap2_onenand *c,
+					   struct gpmc_device_timings *dev_t)
+{
+	const int t_cer  = 15;
+	const int t_avdp = 12;
+	const int t_cez  = 20; /* max of t_cez, t_oez */
+	const int t_wpl  = 40;
+	const int t_wph  = 30;
+	int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo;
+	int gpmc_clk_ns;
+
+	/*
+	 * Synchronous settings can't be read from platform data or DT as
+	 * they provide Asynchronous settings for maximum compatibility.
+	 * If required to be different, e.g. wait pin, then we need to add
+	 * that setting in platform data or DT for omap2-onenand device.
+	 */
+	c->sync_settings.burst_read = true;
+	c->sync_settings.burst_wrap = true;
+	c->sync_settings.burst_len = GPMC_BURST_16;
+	c->sync_settings.device_width = GPMC_DEVWIDTH_16BIT;
+	c->sync_settings.mux_add_data = GPMC_MUX_AD;
+	/*
+	 * FIXME: wait pin must come from platform_data or DT.
+	 * Till then, no wait pin monitoring
+	 */
+	c->sync_settings.wait_on_read = false;
+	c->sync_settings.wait_on_write = false;
+
+	if (!c->freq) {
+		/* Initially, freq is not known */
+		c->freq = omap2_onenand_get_freq(c);
+	}
+
+	if (c->flags & ONENAND_SYNC_READ)
+		c->priv_flags = ONENAND_FLAG_SYNCREAD;
+	else if (c->flags & ONENAND_SYNC_READWRITE)
+		c->priv_flags = ONENAND_FLAG_SYNCREAD | ONENAND_FLAG_SYNCWRITE;
+
+	switch (c->freq) {
+	case 104:
+		min_gpmc_clk_period = 9600; /* 104 MHz */
+		t_ces   = 3;
+		t_avds  = 4;
+		t_avdh  = 2;
+		t_ach   = 3;
+		t_aavdh = 6;
+		t_rdyo  = 6;
+		break;
+	case 83:
+		min_gpmc_clk_period = 12000; /* 83 MHz */
+		t_ces   = 5;
+		t_avds  = 4;
+		t_avdh  = 2;
+		t_ach   = 6;
+		t_aavdh = 6;
+		t_rdyo  = 9;
+		break;
+	case 66:
+		min_gpmc_clk_period = 15000; /* 66 MHz */
+		t_ces   = 6;
+		t_avds  = 5;
+		t_avdh  = 2;
+		t_ach   = 6;
+		t_aavdh = 6;
+		t_rdyo  = 11;
+		break;
+	default:
+		min_gpmc_clk_period = 18500; /* 54 MHz */
+		t_ces   = 7;
+		t_avds  = 7;
+		t_avdh  = 7;
+		t_ach   = 9;
+		t_aavdh = 7;
+		t_rdyo  = 15;
+		c->priv_flags &= ~ONENAND_FLAG_SYNCWRITE;
+		break;
+	}
+
+	gpmc_clk_ns = omap_gpmc_get_clk_period(c->gpmc_cs,
+					       min_gpmc_clk_period);
+	gpmc_clk_ns /= 1000; /* ps to ns */
+
+	if (gpmc_clk_ns < 15) /* >66Mhz */
+		c->priv_flags |= ONENAND_FLAG_HF;
+	else
+		c->priv_flags &= ~ONENAND_FLAG_HF;
+
+	if (gpmc_clk_ns < 12) /* >83Mhz */
+		c->priv_flags |= ONENAND_FLAG_VHF;
+	else
+		c->priv_flags &= ~ONENAND_FLAG_VHF;
+
+	if (c->priv_flags & ONENAND_FLAG_VHF)
+		c->latency = 8;
+	else if (c->priv_flags & ONENAND_FLAG_HF)
+		c->latency = 6;
+	else if (gpmc_clk_ns >= 25) /* 40 MHz*/
+		c->latency = 3;
+	else
+		c->latency = 4;
+
+	/* Set synchronous read timings */
+	memset(dev_t, 0, sizeof(*dev_t));
+
+	if (c->priv_flags & ONENAND_FLAG_SYNCREAD)
+		c->sync_settings.sync_read = true;
+	if (c->priv_flags & ONENAND_FLAG_SYNCWRITE) {
+		c->sync_settings.sync_write = true;
+		c->sync_settings.burst_write = true;
+	} else {
+		dev_t->t_avdp_w = max(t_avdp, t_cer) * 1000;
+		dev_t->t_wpl = t_wpl * 1000;
+		dev_t->t_wph = t_wph * 1000;
+		dev_t->t_aavdh = t_aavdh * 1000;
+	}
+	dev_t->ce_xdelay = true;
+	dev_t->avd_xdelay = true;
+	dev_t->oe_xdelay = true;
+	dev_t->we_xdelay = true;
+	dev_t->clk = min_gpmc_clk_period;
+	dev_t->t_bacc = dev_t->clk;
+	dev_t->t_ces = t_ces * 1000;
+	dev_t->t_avds = t_avds * 1000;
+	dev_t->t_avdh = t_avdh * 1000;
+	dev_t->t_ach = t_ach * 1000;
+	dev_t->cyc_iaa = (c->latency + 1);
+	dev_t->t_cez_r = t_cez * 1000;
+	dev_t->t_cez_w = dev_t->t_cez_r;
+	dev_t->cyc_aavdh_oe = 1;
+	dev_t->t_rdyo = t_rdyo * 1000 + min_gpmc_clk_period;
+}
+
+static int omap2_onenand_setup_sync(struct omap2_onenand *c)
+{
+	int ret;
+	struct gpmc_device_timings dev_t;
+
+	omap2_onenand_get_sync_timings(c, &dev_t);
+
+	ret = omap_gpmc_retime(c->gpmc_cs, &c->sync_settings, &dev_t);
+	if (ret < 0)
+		return ret;
+
+	set_onenand_cfg(c);
+
+	return 0;
+}
+
+static void omap2_onenand_set_async_mode(struct omap2_onenand *c)
+{
+	u32 reg;
+
+	/* Ensure sync read and sync write are disabled */
+	reg = read_reg(c, ONENAND_REG_SYS_CFG1);
+	reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE;
+	write_reg(c, reg, ONENAND_REG_SYS_CFG1);
+}
+
+static int omap2_onenand_setup(struct omap2_onenand *c)
+{
+	struct device *dev = &c->pdev->dev;
+	unsigned l = ONENAND_SYNC_READ | ONENAND_SYNC_READWRITE;
+	int ret;
+
+	omap2_onenand_set_async_mode(c);
+
+	if (!(c->flags & l))
+		return 0;
+
+	ret = omap2_onenand_setup_sync(c);
+	if (ret)
+		dev_err(dev, "unable to switch to Synchronous mode\n");
+
+	return ret;
+}
+
 static struct platform_driver omap2_onenand_driver;
 
 static void omap2_onenand_shutdown(struct platform_device *pdev)
@@ -602,6 +848,7 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 
 	init_completion(&c->irq_done);
 	init_completion(&c->dma_done);
+	c->pdev = pdev;
 	c->flags = pdata->flags;
 	c->gpmc_cs = pdata->cs;
 	c->gpio_irq = pdata->gpio_irq;
@@ -634,14 +881,10 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 		goto err_release_mem_region;
 	}
 
-	if (pdata->onenand_setup != NULL) {
-		r = pdata->onenand_setup(c->onenand.base, &c->freq);
-		if (r < 0) {
-			dev_err(&pdev->dev, "Onenand platform setup failed: "
-				"%d\n", r);
-			goto err_iounmap;
-		}
-		c->setup = pdata->onenand_setup;
+	r = omap2_onenand_setup(c);
+	if (r < 0) {
+		dev_err(&pdev->dev, "setup failed:%d\n", r);
+		goto err_iounmap;
 	}
 
 	if (c->gpio_irq) {
@@ -683,7 +926,6 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 		 "base %p, freq %d MHz\n", c->gpmc_cs, c->phys_base,
 		 c->onenand.base, c->freq);
 
-	c->pdev = pdev;
 	c->mtd.name = dev_name(&pdev->dev);
 	c->mtd.priv = &c->onenand;
 	c->mtd.owner = THIS_MODULE;
diff --git a/include/linux/platform_data/mtd-onenand-omap2.h b/include/linux/platform_data/mtd-onenand-omap2.h
index 445b41e..ac1e6f3 100644
--- a/include/linux/platform_data/mtd-onenand-omap2.h
+++ b/include/linux/platform_data/mtd-onenand-omap2.h
@@ -22,7 +22,6 @@ struct omap_onenand_platform_data {
 	int			gpio_irq;
 	struct mtd_partition	*parts;
 	int			nr_parts;
-	int			(*onenand_setup)(void __iomem *, int *freq_ptr);
 	int			dma_channel;
 	u8			flags;
 	u8			skip_initial_unlocking;
@@ -31,5 +30,6 @@ struct omap_onenand_platform_data {
 	struct device_node	*of_node;
 
 	u8			regulator_can_sleep;	/* deprecated */
+	int (*onenand_setup)(void __iomem *, int *freq_ptr);	/* deprecated */
 };
 #endif
-- 
1.8.3.2


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

* [PATCH 18/36] ARM: OMAP2+: gpmc-onenand: Move Synchronous setting code to drivers/
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Move the code that puts the onenand in synchronous mode
into the appropriate place i.e. drivers/mtd/onenand/omap2.c.

Make use of omap_gpmc_get_clk_period() and omap_gpmc_retime()
to calculate the necessary timings and configure the GPMC
parent's timings.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-onenand.c              | 262 +----------------------
 drivers/mtd/onenand/omap2.c                     | 264 +++++++++++++++++++++++-
 include/linux/platform_data/mtd-onenand-omap2.h |   2 +-
 3 files changed, 258 insertions(+), 270 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index bed8efe..d09c342 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -26,16 +26,6 @@
 
 #define	ONENAND_IO_SIZE	SZ_128K
 
-#define	ONENAND_FLAG_SYNCREAD	(1 << 0)
-#define	ONENAND_FLAG_SYNCWRITE	(1 << 1)
-#define	ONENAND_FLAG_HF		(1 << 2)
-#define	ONENAND_FLAG_VHF	(1 << 3)
-
-static unsigned onenand_flags;
-static unsigned latency;
-
-static struct omap_onenand_platform_data *gpmc_onenand_data;
-
 static struct resource gpmc_onenand_resource = {
 	.flags		= IORESOURCE_MEM,
 };
@@ -52,15 +42,6 @@ static struct gpmc_settings onenand_async = {
 	.mux_add_data	= GPMC_MUX_AD,
 };
 
-static struct gpmc_settings onenand_sync = {
-	.burst_read	= true,
-	.burst_wrap	= true,
-	.burst_len	= GPMC_BURST_16,
-	.device_width	= GPMC_DEVWIDTH_16BIT,
-	.mux_add_data	= GPMC_MUX_AD,
-	.wait_pin	= 0,
-};
-
 static void omap2_onenand_get_async_timings(struct gpmc_device_timings *dev_t)
 {
 	const int t_cer = 15;
@@ -87,184 +68,8 @@ static void omap2_onenand_get_async_timings(struct gpmc_device_timings *dev_t)
 	dev_t->t_wph = t_wph * 1000;
 }
 
-static void omap2_onenand_set_async_mode(void __iomem *onenand_base)
-{
-	u32 reg;
-
-	/* Ensure sync read and sync write are disabled */
-	reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
-	reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE;
-	writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
-}
-
-static void set_onenand_cfg(void __iomem *onenand_base)
-{
-	u32 reg;
-
-	reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
-	reg &= ~((0x7 << ONENAND_SYS_CFG1_BRL_SHIFT) | (0x7 << 9));
-	reg |=	(latency << ONENAND_SYS_CFG1_BRL_SHIFT) |
-		ONENAND_SYS_CFG1_BL_16;
-	if (onenand_flags & ONENAND_FLAG_SYNCREAD)
-		reg |= ONENAND_SYS_CFG1_SYNC_READ;
-	else
-		reg &= ~ONENAND_SYS_CFG1_SYNC_READ;
-	if (onenand_flags & ONENAND_FLAG_SYNCWRITE)
-		reg |= ONENAND_SYS_CFG1_SYNC_WRITE;
-	else
-		reg &= ~ONENAND_SYS_CFG1_SYNC_WRITE;
-	if (onenand_flags & ONENAND_FLAG_HF)
-		reg |= ONENAND_SYS_CFG1_HF;
-	else
-		reg &= ~ONENAND_SYS_CFG1_HF;
-	if (onenand_flags & ONENAND_FLAG_VHF)
-		reg |= ONENAND_SYS_CFG1_VHF;
-	else
-		reg &= ~ONENAND_SYS_CFG1_VHF;
-	writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
-}
-
-static int omap2_onenand_get_freq(struct omap_onenand_platform_data *cfg,
-				  void __iomem *onenand_base)
-{
-	u16 ver = readw(onenand_base + ONENAND_REG_VERSION_ID);
-	int freq;
-
-	switch ((ver >> 4) & 0xf) {
-	case 0:
-		freq = 40;
-		break;
-	case 1:
-		freq = 54;
-		break;
-	case 2:
-		freq = 66;
-		break;
-	case 3:
-		freq = 83;
-		break;
-	case 4:
-		freq = 104;
-		break;
-	default:
-		freq = 54;
-		break;
-	}
-
-	return freq;
-}
-
-static void omap2_onenand_calc_sync_timings(struct gpmc_timings *t,
-					    unsigned int flags,
-					    int freq)
-{
-	struct gpmc_device_timings dev_t;
-	const int t_cer  = 15;
-	const int t_avdp = 12;
-	const int t_cez  = 20; /* max of t_cez, t_oez */
-	const int t_wpl  = 40;
-	const int t_wph  = 30;
-	int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo;
-	int div, gpmc_clk_ns;
-
-	if (flags & ONENAND_SYNC_READ)
-		onenand_flags = ONENAND_FLAG_SYNCREAD;
-	else if (flags & ONENAND_SYNC_READWRITE)
-		onenand_flags = ONENAND_FLAG_SYNCREAD | ONENAND_FLAG_SYNCWRITE;
-
-	switch (freq) {
-	case 104:
-		min_gpmc_clk_period = 9600; /* 104 MHz */
-		t_ces   = 3;
-		t_avds  = 4;
-		t_avdh  = 2;
-		t_ach   = 3;
-		t_aavdh = 6;
-		t_rdyo  = 6;
-		break;
-	case 83:
-		min_gpmc_clk_period = 12000; /* 83 MHz */
-		t_ces   = 5;
-		t_avds  = 4;
-		t_avdh  = 2;
-		t_ach   = 6;
-		t_aavdh = 6;
-		t_rdyo  = 9;
-		break;
-	case 66:
-		min_gpmc_clk_period = 15000; /* 66 MHz */
-		t_ces   = 6;
-		t_avds  = 5;
-		t_avdh  = 2;
-		t_ach   = 6;
-		t_aavdh = 6;
-		t_rdyo  = 11;
-		break;
-	default:
-		min_gpmc_clk_period = 18500; /* 54 MHz */
-		t_ces   = 7;
-		t_avds  = 7;
-		t_avdh  = 7;
-		t_ach   = 9;
-		t_aavdh = 7;
-		t_rdyo  = 15;
-		onenand_flags &= ~ONENAND_FLAG_SYNCWRITE;
-		break;
-	}
-
-	div = gpmc_calc_divider(min_gpmc_clk_period);
-	gpmc_clk_ns = gpmc_ticks_to_ns(div);
-	if (gpmc_clk_ns < 15) /* >66Mhz */
-		onenand_flags |= ONENAND_FLAG_HF;
-	else
-		onenand_flags &= ~ONENAND_FLAG_HF;
-	if (gpmc_clk_ns < 12) /* >83Mhz */
-		onenand_flags |= ONENAND_FLAG_VHF;
-	else
-		onenand_flags &= ~ONENAND_FLAG_VHF;
-	if (onenand_flags & ONENAND_FLAG_VHF)
-		latency = 8;
-	else if (onenand_flags & ONENAND_FLAG_HF)
-		latency = 6;
-	else if (gpmc_clk_ns >= 25) /* 40 MHz*/
-		latency = 3;
-	else
-		latency = 4;
-
-	/* Set synchronous read timings */
-	memset(&dev_t, 0, sizeof(dev_t));
-
-	if (onenand_flags & ONENAND_FLAG_SYNCREAD)
-		onenand_sync.sync_read = true;
-	if (onenand_flags & ONENAND_FLAG_SYNCWRITE) {
-		onenand_sync.sync_write = true;
-		onenand_sync.burst_write = true;
-	} else {
-		dev_t.t_avdp_w = max(t_avdp, t_cer) * 1000;
-		dev_t.t_wpl = t_wpl * 1000;
-		dev_t.t_wph = t_wph * 1000;
-		dev_t.t_aavdh = t_aavdh * 1000;
-	}
-	dev_t.ce_xdelay = true;
-	dev_t.avd_xdelay = true;
-	dev_t.oe_xdelay = true;
-	dev_t.we_xdelay = true;
-	dev_t.clk = min_gpmc_clk_period;
-	dev_t.t_bacc = dev_t.clk;
-	dev_t.t_ces = t_ces * 1000;
-	dev_t.t_avds = t_avds * 1000;
-	dev_t.t_avdh = t_avdh * 1000;
-	dev_t.t_ach = t_ach * 1000;
-	dev_t.cyc_iaa = (latency + 1);
-	dev_t.t_cez_r = t_cez * 1000;
-	dev_t.t_cez_w = dev_t.t_cez_r;
-	dev_t.cyc_aavdh_oe = 1;
-	dev_t.t_rdyo = t_rdyo * 1000 + min_gpmc_clk_period;
-
-	gpmc_calc_timings(t, &onenand_sync, &dev_t);
-}
-
-static int omap2_onenand_setup_async(void)
+static int omap2_onenand_setup_async(struct omap_onenand_platform_data
+				     *gpmc_onenand_data)
 {
 	struct gpmc_timings gpmc_t;
 	struct gpmc_device_timings dev_t;
@@ -296,70 +101,11 @@ static int omap2_onenand_setup_async(void)
 	return 0;
 }
 
-static int omap2_onenand_setup_sync(void __iomem *onenand_base, int *freq_ptr)
-{
-	int ret, freq = *freq_ptr;
-	struct gpmc_timings t;
-
-	if (!freq) {
-		/* Very first call freq is not known */
-		freq = omap2_onenand_get_freq(gpmc_onenand_data, onenand_base);
-		set_onenand_cfg(onenand_base);
-	}
-
-	if (gpmc_onenand_data->of_node) {
-		gpmc_read_settings_dt(gpmc_onenand_data->of_node,
-				      &onenand_sync);
-	} else {
-		/*
-		 * FIXME: Appears to be legacy code from initial ONENAND commit.
-		 * Unclear what boards this is for and if this can be removed.
-		 */
-		if (!cpu_is_omap34xx())
-			onenand_sync.wait_on_read = true;
-	}
-
-	omap2_onenand_calc_sync_timings(&t, gpmc_onenand_data->flags, freq);
-
-	ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_sync);
-	if (ret < 0)
-		return ret;
-
-	ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t);
-	if (ret < 0)
-		return ret;
-
-	set_onenand_cfg(onenand_base);
-
-	*freq_ptr = freq;
-
-	return 0;
-}
-
-static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr)
-{
-	struct device *dev = &gpmc_onenand_device.dev;
-	unsigned l = ONENAND_SYNC_READ | ONENAND_SYNC_READWRITE;
-	int ret;
-
-	omap2_onenand_set_async_mode(onenand_base);
-
-	if (!(gpmc_onenand_data->flags & l))
-		return 0;
-
-	ret = omap2_onenand_setup_sync(onenand_base, freq_ptr);
-	if (ret)
-		dev_err(dev, "unable to set to sync mode\n");
-	return ret;
-}
-
-void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
+void gpmc_onenand_init(struct omap_onenand_platform_data *gpmc_onenand_data)
 {
 	int err;
 	struct device *dev = &gpmc_onenand_device.dev;
 
-	gpmc_onenand_data = _onenand_data;
-	gpmc_onenand_data->onenand_setup = gpmc_onenand_setup;
 	gpmc_onenand_device.dev.platform_data = gpmc_onenand_data;
 
 	if (cpu_is_omap24xx() &&
@@ -385,7 +131,7 @@ void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
 	gpmc_onenand_resource.end = gpmc_onenand_resource.start +
 							ONENAND_IO_SIZE - 1;
 
-	if (omap2_onenand_setup_async()) {
+	if (omap2_onenand_setup_async(gpmc_onenand_data)) {
 		pr_err("%s: Failed to setup ASYNC timings\n", __func__);
 		goto fail;
 	}
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index a5f5ad8..238dd7a 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -37,6 +37,7 @@
 
 #include <asm/mach/flash.h>
 #include <linux/platform_data/mtd-onenand-omap2.h>
+#include <linux/platform_data/gpmc-omap.h>
 #include <asm/gpio.h>
 
 #include <linux/omap-dma.h>
@@ -45,6 +46,12 @@
 
 #define ONENAND_BUFRAM_SIZE	(1024 * 5)
 
+/* Private flags */
+#define	ONENAND_FLAG_SYNCREAD	(1 << 0)
+#define	ONENAND_FLAG_SYNCWRITE	(1 << 1)
+#define	ONENAND_FLAG_HF		(1 << 2)
+#define	ONENAND_FLAG_VHF	(1 << 3)
+
 struct omap2_onenand {
 	struct platform_device *pdev;
 	int gpmc_cs;
@@ -57,8 +64,10 @@ struct omap2_onenand {
 	struct completion dma_done;
 	int dma_channel;
 	int freq;
-	int (*setup)(void __iomem *base, int *freq_ptr);
-	u8 flags;
+	u8 flags;		/* as per platform_data/mtd-onenand-omap2.h */
+	u8 priv_flags;		/* our internal flags */
+	unsigned latency;	/* latency settings for onenand SYS_CFG1 */
+	struct gpmc_settings sync_settings;	/* Synchronous GPMC settings */
 };
 
 static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data)
@@ -568,6 +577,243 @@ static int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area,
 
 #endif
 
+static void set_onenand_cfg(struct omap2_onenand *c)
+{
+	u32 reg;
+
+	reg = read_reg(c, ONENAND_REG_SYS_CFG1);
+	reg &= ~((0x7 << ONENAND_SYS_CFG1_BRL_SHIFT) | (0x7 << 9));
+	reg |=	(c->latency << ONENAND_SYS_CFG1_BRL_SHIFT) |
+		ONENAND_SYS_CFG1_BL_16;
+	if (c->priv_flags & ONENAND_FLAG_SYNCREAD)
+		reg |= ONENAND_SYS_CFG1_SYNC_READ;
+	else
+		reg &= ~ONENAND_SYS_CFG1_SYNC_READ;
+
+	if (c->priv_flags & ONENAND_FLAG_SYNCWRITE)
+		reg |= ONENAND_SYS_CFG1_SYNC_WRITE;
+	else
+		reg &= ~ONENAND_SYS_CFG1_SYNC_WRITE;
+
+	if (c->priv_flags & ONENAND_FLAG_HF)
+		reg |= ONENAND_SYS_CFG1_HF;
+	else
+		reg &= ~ONENAND_SYS_CFG1_HF;
+
+	if (c->priv_flags & ONENAND_FLAG_VHF)
+		reg |= ONENAND_SYS_CFG1_VHF;
+	else
+		reg &= ~ONENAND_SYS_CFG1_VHF;
+
+	write_reg(c, reg, ONENAND_REG_SYS_CFG1);
+}
+
+static int omap2_onenand_get_freq(struct omap2_onenand *c)
+{
+	u16 ver = read_reg(c, ONENAND_REG_VERSION_ID);
+	int freq;
+
+	switch ((ver >> 4) & 0xf) {
+	case 0:
+		freq = 40;
+		break;
+	case 1:
+		freq = 54;
+		break;
+	case 2:
+		freq = 66;
+		break;
+	case 3:
+		freq = 83;
+		break;
+	case 4:
+		freq = 104;
+		break;
+	default:
+		freq = 54;
+		break;
+	}
+
+	return freq;
+}
+
+static void omap2_onenand_get_sync_timings(struct omap2_onenand *c,
+					   struct gpmc_device_timings *dev_t)
+{
+	const int t_cer  = 15;
+	const int t_avdp = 12;
+	const int t_cez  = 20; /* max of t_cez, t_oez */
+	const int t_wpl  = 40;
+	const int t_wph  = 30;
+	int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo;
+	int gpmc_clk_ns;
+
+	/*
+	 * Synchronous settings can't be read from platform data or DT as
+	 * they provide Asynchronous settings for maximum compatibility.
+	 * If required to be different, e.g. wait pin, then we need to add
+	 * that setting in platform data or DT for omap2-onenand device.
+	 */
+	c->sync_settings.burst_read = true;
+	c->sync_settings.burst_wrap = true;
+	c->sync_settings.burst_len = GPMC_BURST_16;
+	c->sync_settings.device_width = GPMC_DEVWIDTH_16BIT;
+	c->sync_settings.mux_add_data = GPMC_MUX_AD;
+	/*
+	 * FIXME: wait pin must come from platform_data or DT.
+	 * Till then, no wait pin monitoring
+	 */
+	c->sync_settings.wait_on_read = false;
+	c->sync_settings.wait_on_write = false;
+
+	if (!c->freq) {
+		/* Initially, freq is not known */
+		c->freq = omap2_onenand_get_freq(c);
+	}
+
+	if (c->flags & ONENAND_SYNC_READ)
+		c->priv_flags = ONENAND_FLAG_SYNCREAD;
+	else if (c->flags & ONENAND_SYNC_READWRITE)
+		c->priv_flags = ONENAND_FLAG_SYNCREAD | ONENAND_FLAG_SYNCWRITE;
+
+	switch (c->freq) {
+	case 104:
+		min_gpmc_clk_period = 9600; /* 104 MHz */
+		t_ces   = 3;
+		t_avds  = 4;
+		t_avdh  = 2;
+		t_ach   = 3;
+		t_aavdh = 6;
+		t_rdyo  = 6;
+		break;
+	case 83:
+		min_gpmc_clk_period = 12000; /* 83 MHz */
+		t_ces   = 5;
+		t_avds  = 4;
+		t_avdh  = 2;
+		t_ach   = 6;
+		t_aavdh = 6;
+		t_rdyo  = 9;
+		break;
+	case 66:
+		min_gpmc_clk_period = 15000; /* 66 MHz */
+		t_ces   = 6;
+		t_avds  = 5;
+		t_avdh  = 2;
+		t_ach   = 6;
+		t_aavdh = 6;
+		t_rdyo  = 11;
+		break;
+	default:
+		min_gpmc_clk_period = 18500; /* 54 MHz */
+		t_ces   = 7;
+		t_avds  = 7;
+		t_avdh  = 7;
+		t_ach   = 9;
+		t_aavdh = 7;
+		t_rdyo  = 15;
+		c->priv_flags &= ~ONENAND_FLAG_SYNCWRITE;
+		break;
+	}
+
+	gpmc_clk_ns = omap_gpmc_get_clk_period(c->gpmc_cs,
+					       min_gpmc_clk_period);
+	gpmc_clk_ns /= 1000; /* ps to ns */
+
+	if (gpmc_clk_ns < 15) /* >66Mhz */
+		c->priv_flags |= ONENAND_FLAG_HF;
+	else
+		c->priv_flags &= ~ONENAND_FLAG_HF;
+
+	if (gpmc_clk_ns < 12) /* >83Mhz */
+		c->priv_flags |= ONENAND_FLAG_VHF;
+	else
+		c->priv_flags &= ~ONENAND_FLAG_VHF;
+
+	if (c->priv_flags & ONENAND_FLAG_VHF)
+		c->latency = 8;
+	else if (c->priv_flags & ONENAND_FLAG_HF)
+		c->latency = 6;
+	else if (gpmc_clk_ns >= 25) /* 40 MHz*/
+		c->latency = 3;
+	else
+		c->latency = 4;
+
+	/* Set synchronous read timings */
+	memset(dev_t, 0, sizeof(*dev_t));
+
+	if (c->priv_flags & ONENAND_FLAG_SYNCREAD)
+		c->sync_settings.sync_read = true;
+	if (c->priv_flags & ONENAND_FLAG_SYNCWRITE) {
+		c->sync_settings.sync_write = true;
+		c->sync_settings.burst_write = true;
+	} else {
+		dev_t->t_avdp_w = max(t_avdp, t_cer) * 1000;
+		dev_t->t_wpl = t_wpl * 1000;
+		dev_t->t_wph = t_wph * 1000;
+		dev_t->t_aavdh = t_aavdh * 1000;
+	}
+	dev_t->ce_xdelay = true;
+	dev_t->avd_xdelay = true;
+	dev_t->oe_xdelay = true;
+	dev_t->we_xdelay = true;
+	dev_t->clk = min_gpmc_clk_period;
+	dev_t->t_bacc = dev_t->clk;
+	dev_t->t_ces = t_ces * 1000;
+	dev_t->t_avds = t_avds * 1000;
+	dev_t->t_avdh = t_avdh * 1000;
+	dev_t->t_ach = t_ach * 1000;
+	dev_t->cyc_iaa = (c->latency + 1);
+	dev_t->t_cez_r = t_cez * 1000;
+	dev_t->t_cez_w = dev_t->t_cez_r;
+	dev_t->cyc_aavdh_oe = 1;
+	dev_t->t_rdyo = t_rdyo * 1000 + min_gpmc_clk_period;
+}
+
+static int omap2_onenand_setup_sync(struct omap2_onenand *c)
+{
+	int ret;
+	struct gpmc_device_timings dev_t;
+
+	omap2_onenand_get_sync_timings(c, &dev_t);
+
+	ret = omap_gpmc_retime(c->gpmc_cs, &c->sync_settings, &dev_t);
+	if (ret < 0)
+		return ret;
+
+	set_onenand_cfg(c);
+
+	return 0;
+}
+
+static void omap2_onenand_set_async_mode(struct omap2_onenand *c)
+{
+	u32 reg;
+
+	/* Ensure sync read and sync write are disabled */
+	reg = read_reg(c, ONENAND_REG_SYS_CFG1);
+	reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE;
+	write_reg(c, reg, ONENAND_REG_SYS_CFG1);
+}
+
+static int omap2_onenand_setup(struct omap2_onenand *c)
+{
+	struct device *dev = &c->pdev->dev;
+	unsigned l = ONENAND_SYNC_READ | ONENAND_SYNC_READWRITE;
+	int ret;
+
+	omap2_onenand_set_async_mode(c);
+
+	if (!(c->flags & l))
+		return 0;
+
+	ret = omap2_onenand_setup_sync(c);
+	if (ret)
+		dev_err(dev, "unable to switch to Synchronous mode\n");
+
+	return ret;
+}
+
 static struct platform_driver omap2_onenand_driver;
 
 static void omap2_onenand_shutdown(struct platform_device *pdev)
@@ -602,6 +848,7 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 
 	init_completion(&c->irq_done);
 	init_completion(&c->dma_done);
+	c->pdev = pdev;
 	c->flags = pdata->flags;
 	c->gpmc_cs = pdata->cs;
 	c->gpio_irq = pdata->gpio_irq;
@@ -634,14 +881,10 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 		goto err_release_mem_region;
 	}
 
-	if (pdata->onenand_setup != NULL) {
-		r = pdata->onenand_setup(c->onenand.base, &c->freq);
-		if (r < 0) {
-			dev_err(&pdev->dev, "Onenand platform setup failed: "
-				"%d\n", r);
-			goto err_iounmap;
-		}
-		c->setup = pdata->onenand_setup;
+	r = omap2_onenand_setup(c);
+	if (r < 0) {
+		dev_err(&pdev->dev, "setup failed:%d\n", r);
+		goto err_iounmap;
 	}
 
 	if (c->gpio_irq) {
@@ -683,7 +926,6 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 		 "base %p, freq %d MHz\n", c->gpmc_cs, c->phys_base,
 		 c->onenand.base, c->freq);
 
-	c->pdev = pdev;
 	c->mtd.name = dev_name(&pdev->dev);
 	c->mtd.priv = &c->onenand;
 	c->mtd.owner = THIS_MODULE;
diff --git a/include/linux/platform_data/mtd-onenand-omap2.h b/include/linux/platform_data/mtd-onenand-omap2.h
index 445b41e..ac1e6f3 100644
--- a/include/linux/platform_data/mtd-onenand-omap2.h
+++ b/include/linux/platform_data/mtd-onenand-omap2.h
@@ -22,7 +22,6 @@ struct omap_onenand_platform_data {
 	int			gpio_irq;
 	struct mtd_partition	*parts;
 	int			nr_parts;
-	int			(*onenand_setup)(void __iomem *, int *freq_ptr);
 	int			dma_channel;
 	u8			flags;
 	u8			skip_initial_unlocking;
@@ -31,5 +30,6 @@ struct omap_onenand_platform_data {
 	struct device_node	*of_node;
 
 	u8			regulator_can_sleep;	/* deprecated */
+	int (*onenand_setup)(void __iomem *, int *freq_ptr);	/* deprecated */
 };
 #endif
-- 
1.8.3.2

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

* [PATCH 18/36] ARM: OMAP2+: gpmc-onenand: Move Synchronous setting code to drivers/
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Move the code that puts the onenand in synchronous mode
into the appropriate place i.e. drivers/mtd/onenand/omap2.c.

Make use of omap_gpmc_get_clk_period() and omap_gpmc_retime()
to calculate the necessary timings and configure the GPMC
parent's timings.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-onenand.c              | 262 +----------------------
 drivers/mtd/onenand/omap2.c                     | 264 +++++++++++++++++++++++-
 include/linux/platform_data/mtd-onenand-omap2.h |   2 +-
 3 files changed, 258 insertions(+), 270 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index bed8efe..d09c342 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -26,16 +26,6 @@
 
 #define	ONENAND_IO_SIZE	SZ_128K
 
-#define	ONENAND_FLAG_SYNCREAD	(1 << 0)
-#define	ONENAND_FLAG_SYNCWRITE	(1 << 1)
-#define	ONENAND_FLAG_HF		(1 << 2)
-#define	ONENAND_FLAG_VHF	(1 << 3)
-
-static unsigned onenand_flags;
-static unsigned latency;
-
-static struct omap_onenand_platform_data *gpmc_onenand_data;
-
 static struct resource gpmc_onenand_resource = {
 	.flags		= IORESOURCE_MEM,
 };
@@ -52,15 +42,6 @@ static struct gpmc_settings onenand_async = {
 	.mux_add_data	= GPMC_MUX_AD,
 };
 
-static struct gpmc_settings onenand_sync = {
-	.burst_read	= true,
-	.burst_wrap	= true,
-	.burst_len	= GPMC_BURST_16,
-	.device_width	= GPMC_DEVWIDTH_16BIT,
-	.mux_add_data	= GPMC_MUX_AD,
-	.wait_pin	= 0,
-};
-
 static void omap2_onenand_get_async_timings(struct gpmc_device_timings *dev_t)
 {
 	const int t_cer = 15;
@@ -87,184 +68,8 @@ static void omap2_onenand_get_async_timings(struct gpmc_device_timings *dev_t)
 	dev_t->t_wph = t_wph * 1000;
 }
 
-static void omap2_onenand_set_async_mode(void __iomem *onenand_base)
-{
-	u32 reg;
-
-	/* Ensure sync read and sync write are disabled */
-	reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
-	reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE;
-	writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
-}
-
-static void set_onenand_cfg(void __iomem *onenand_base)
-{
-	u32 reg;
-
-	reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
-	reg &= ~((0x7 << ONENAND_SYS_CFG1_BRL_SHIFT) | (0x7 << 9));
-	reg |=	(latency << ONENAND_SYS_CFG1_BRL_SHIFT) |
-		ONENAND_SYS_CFG1_BL_16;
-	if (onenand_flags & ONENAND_FLAG_SYNCREAD)
-		reg |= ONENAND_SYS_CFG1_SYNC_READ;
-	else
-		reg &= ~ONENAND_SYS_CFG1_SYNC_READ;
-	if (onenand_flags & ONENAND_FLAG_SYNCWRITE)
-		reg |= ONENAND_SYS_CFG1_SYNC_WRITE;
-	else
-		reg &= ~ONENAND_SYS_CFG1_SYNC_WRITE;
-	if (onenand_flags & ONENAND_FLAG_HF)
-		reg |= ONENAND_SYS_CFG1_HF;
-	else
-		reg &= ~ONENAND_SYS_CFG1_HF;
-	if (onenand_flags & ONENAND_FLAG_VHF)
-		reg |= ONENAND_SYS_CFG1_VHF;
-	else
-		reg &= ~ONENAND_SYS_CFG1_VHF;
-	writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
-}
-
-static int omap2_onenand_get_freq(struct omap_onenand_platform_data *cfg,
-				  void __iomem *onenand_base)
-{
-	u16 ver = readw(onenand_base + ONENAND_REG_VERSION_ID);
-	int freq;
-
-	switch ((ver >> 4) & 0xf) {
-	case 0:
-		freq = 40;
-		break;
-	case 1:
-		freq = 54;
-		break;
-	case 2:
-		freq = 66;
-		break;
-	case 3:
-		freq = 83;
-		break;
-	case 4:
-		freq = 104;
-		break;
-	default:
-		freq = 54;
-		break;
-	}
-
-	return freq;
-}
-
-static void omap2_onenand_calc_sync_timings(struct gpmc_timings *t,
-					    unsigned int flags,
-					    int freq)
-{
-	struct gpmc_device_timings dev_t;
-	const int t_cer  = 15;
-	const int t_avdp = 12;
-	const int t_cez  = 20; /* max of t_cez, t_oez */
-	const int t_wpl  = 40;
-	const int t_wph  = 30;
-	int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo;
-	int div, gpmc_clk_ns;
-
-	if (flags & ONENAND_SYNC_READ)
-		onenand_flags = ONENAND_FLAG_SYNCREAD;
-	else if (flags & ONENAND_SYNC_READWRITE)
-		onenand_flags = ONENAND_FLAG_SYNCREAD | ONENAND_FLAG_SYNCWRITE;
-
-	switch (freq) {
-	case 104:
-		min_gpmc_clk_period = 9600; /* 104 MHz */
-		t_ces   = 3;
-		t_avds  = 4;
-		t_avdh  = 2;
-		t_ach   = 3;
-		t_aavdh = 6;
-		t_rdyo  = 6;
-		break;
-	case 83:
-		min_gpmc_clk_period = 12000; /* 83 MHz */
-		t_ces   = 5;
-		t_avds  = 4;
-		t_avdh  = 2;
-		t_ach   = 6;
-		t_aavdh = 6;
-		t_rdyo  = 9;
-		break;
-	case 66:
-		min_gpmc_clk_period = 15000; /* 66 MHz */
-		t_ces   = 6;
-		t_avds  = 5;
-		t_avdh  = 2;
-		t_ach   = 6;
-		t_aavdh = 6;
-		t_rdyo  = 11;
-		break;
-	default:
-		min_gpmc_clk_period = 18500; /* 54 MHz */
-		t_ces   = 7;
-		t_avds  = 7;
-		t_avdh  = 7;
-		t_ach   = 9;
-		t_aavdh = 7;
-		t_rdyo  = 15;
-		onenand_flags &= ~ONENAND_FLAG_SYNCWRITE;
-		break;
-	}
-
-	div = gpmc_calc_divider(min_gpmc_clk_period);
-	gpmc_clk_ns = gpmc_ticks_to_ns(div);
-	if (gpmc_clk_ns < 15) /* >66Mhz */
-		onenand_flags |= ONENAND_FLAG_HF;
-	else
-		onenand_flags &= ~ONENAND_FLAG_HF;
-	if (gpmc_clk_ns < 12) /* >83Mhz */
-		onenand_flags |= ONENAND_FLAG_VHF;
-	else
-		onenand_flags &= ~ONENAND_FLAG_VHF;
-	if (onenand_flags & ONENAND_FLAG_VHF)
-		latency = 8;
-	else if (onenand_flags & ONENAND_FLAG_HF)
-		latency = 6;
-	else if (gpmc_clk_ns >= 25) /* 40 MHz*/
-		latency = 3;
-	else
-		latency = 4;
-
-	/* Set synchronous read timings */
-	memset(&dev_t, 0, sizeof(dev_t));
-
-	if (onenand_flags & ONENAND_FLAG_SYNCREAD)
-		onenand_sync.sync_read = true;
-	if (onenand_flags & ONENAND_FLAG_SYNCWRITE) {
-		onenand_sync.sync_write = true;
-		onenand_sync.burst_write = true;
-	} else {
-		dev_t.t_avdp_w = max(t_avdp, t_cer) * 1000;
-		dev_t.t_wpl = t_wpl * 1000;
-		dev_t.t_wph = t_wph * 1000;
-		dev_t.t_aavdh = t_aavdh * 1000;
-	}
-	dev_t.ce_xdelay = true;
-	dev_t.avd_xdelay = true;
-	dev_t.oe_xdelay = true;
-	dev_t.we_xdelay = true;
-	dev_t.clk = min_gpmc_clk_period;
-	dev_t.t_bacc = dev_t.clk;
-	dev_t.t_ces = t_ces * 1000;
-	dev_t.t_avds = t_avds * 1000;
-	dev_t.t_avdh = t_avdh * 1000;
-	dev_t.t_ach = t_ach * 1000;
-	dev_t.cyc_iaa = (latency + 1);
-	dev_t.t_cez_r = t_cez * 1000;
-	dev_t.t_cez_w = dev_t.t_cez_r;
-	dev_t.cyc_aavdh_oe = 1;
-	dev_t.t_rdyo = t_rdyo * 1000 + min_gpmc_clk_period;
-
-	gpmc_calc_timings(t, &onenand_sync, &dev_t);
-}
-
-static int omap2_onenand_setup_async(void)
+static int omap2_onenand_setup_async(struct omap_onenand_platform_data
+				     *gpmc_onenand_data)
 {
 	struct gpmc_timings gpmc_t;
 	struct gpmc_device_timings dev_t;
@@ -296,70 +101,11 @@ static int omap2_onenand_setup_async(void)
 	return 0;
 }
 
-static int omap2_onenand_setup_sync(void __iomem *onenand_base, int *freq_ptr)
-{
-	int ret, freq = *freq_ptr;
-	struct gpmc_timings t;
-
-	if (!freq) {
-		/* Very first call freq is not known */
-		freq = omap2_onenand_get_freq(gpmc_onenand_data, onenand_base);
-		set_onenand_cfg(onenand_base);
-	}
-
-	if (gpmc_onenand_data->of_node) {
-		gpmc_read_settings_dt(gpmc_onenand_data->of_node,
-				      &onenand_sync);
-	} else {
-		/*
-		 * FIXME: Appears to be legacy code from initial ONENAND commit.
-		 * Unclear what boards this is for and if this can be removed.
-		 */
-		if (!cpu_is_omap34xx())
-			onenand_sync.wait_on_read = true;
-	}
-
-	omap2_onenand_calc_sync_timings(&t, gpmc_onenand_data->flags, freq);
-
-	ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_sync);
-	if (ret < 0)
-		return ret;
-
-	ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t);
-	if (ret < 0)
-		return ret;
-
-	set_onenand_cfg(onenand_base);
-
-	*freq_ptr = freq;
-
-	return 0;
-}
-
-static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr)
-{
-	struct device *dev = &gpmc_onenand_device.dev;
-	unsigned l = ONENAND_SYNC_READ | ONENAND_SYNC_READWRITE;
-	int ret;
-
-	omap2_onenand_set_async_mode(onenand_base);
-
-	if (!(gpmc_onenand_data->flags & l))
-		return 0;
-
-	ret = omap2_onenand_setup_sync(onenand_base, freq_ptr);
-	if (ret)
-		dev_err(dev, "unable to set to sync mode\n");
-	return ret;
-}
-
-void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
+void gpmc_onenand_init(struct omap_onenand_platform_data *gpmc_onenand_data)
 {
 	int err;
 	struct device *dev = &gpmc_onenand_device.dev;
 
-	gpmc_onenand_data = _onenand_data;
-	gpmc_onenand_data->onenand_setup = gpmc_onenand_setup;
 	gpmc_onenand_device.dev.platform_data = gpmc_onenand_data;
 
 	if (cpu_is_omap24xx() &&
@@ -385,7 +131,7 @@ void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
 	gpmc_onenand_resource.end = gpmc_onenand_resource.start +
 							ONENAND_IO_SIZE - 1;
 
-	if (omap2_onenand_setup_async()) {
+	if (omap2_onenand_setup_async(gpmc_onenand_data)) {
 		pr_err("%s: Failed to setup ASYNC timings\n", __func__);
 		goto fail;
 	}
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index a5f5ad8..238dd7a 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -37,6 +37,7 @@
 
 #include <asm/mach/flash.h>
 #include <linux/platform_data/mtd-onenand-omap2.h>
+#include <linux/platform_data/gpmc-omap.h>
 #include <asm/gpio.h>
 
 #include <linux/omap-dma.h>
@@ -45,6 +46,12 @@
 
 #define ONENAND_BUFRAM_SIZE	(1024 * 5)
 
+/* Private flags */
+#define	ONENAND_FLAG_SYNCREAD	(1 << 0)
+#define	ONENAND_FLAG_SYNCWRITE	(1 << 1)
+#define	ONENAND_FLAG_HF		(1 << 2)
+#define	ONENAND_FLAG_VHF	(1 << 3)
+
 struct omap2_onenand {
 	struct platform_device *pdev;
 	int gpmc_cs;
@@ -57,8 +64,10 @@ struct omap2_onenand {
 	struct completion dma_done;
 	int dma_channel;
 	int freq;
-	int (*setup)(void __iomem *base, int *freq_ptr);
-	u8 flags;
+	u8 flags;		/* as per platform_data/mtd-onenand-omap2.h */
+	u8 priv_flags;		/* our internal flags */
+	unsigned latency;	/* latency settings for onenand SYS_CFG1 */
+	struct gpmc_settings sync_settings;	/* Synchronous GPMC settings */
 };
 
 static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data)
@@ -568,6 +577,243 @@ static int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area,
 
 #endif
 
+static void set_onenand_cfg(struct omap2_onenand *c)
+{
+	u32 reg;
+
+	reg = read_reg(c, ONENAND_REG_SYS_CFG1);
+	reg &= ~((0x7 << ONENAND_SYS_CFG1_BRL_SHIFT) | (0x7 << 9));
+	reg |=	(c->latency << ONENAND_SYS_CFG1_BRL_SHIFT) |
+		ONENAND_SYS_CFG1_BL_16;
+	if (c->priv_flags & ONENAND_FLAG_SYNCREAD)
+		reg |= ONENAND_SYS_CFG1_SYNC_READ;
+	else
+		reg &= ~ONENAND_SYS_CFG1_SYNC_READ;
+
+	if (c->priv_flags & ONENAND_FLAG_SYNCWRITE)
+		reg |= ONENAND_SYS_CFG1_SYNC_WRITE;
+	else
+		reg &= ~ONENAND_SYS_CFG1_SYNC_WRITE;
+
+	if (c->priv_flags & ONENAND_FLAG_HF)
+		reg |= ONENAND_SYS_CFG1_HF;
+	else
+		reg &= ~ONENAND_SYS_CFG1_HF;
+
+	if (c->priv_flags & ONENAND_FLAG_VHF)
+		reg |= ONENAND_SYS_CFG1_VHF;
+	else
+		reg &= ~ONENAND_SYS_CFG1_VHF;
+
+	write_reg(c, reg, ONENAND_REG_SYS_CFG1);
+}
+
+static int omap2_onenand_get_freq(struct omap2_onenand *c)
+{
+	u16 ver = read_reg(c, ONENAND_REG_VERSION_ID);
+	int freq;
+
+	switch ((ver >> 4) & 0xf) {
+	case 0:
+		freq = 40;
+		break;
+	case 1:
+		freq = 54;
+		break;
+	case 2:
+		freq = 66;
+		break;
+	case 3:
+		freq = 83;
+		break;
+	case 4:
+		freq = 104;
+		break;
+	default:
+		freq = 54;
+		break;
+	}
+
+	return freq;
+}
+
+static void omap2_onenand_get_sync_timings(struct omap2_onenand *c,
+					   struct gpmc_device_timings *dev_t)
+{
+	const int t_cer  = 15;
+	const int t_avdp = 12;
+	const int t_cez  = 20; /* max of t_cez, t_oez */
+	const int t_wpl  = 40;
+	const int t_wph  = 30;
+	int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo;
+	int gpmc_clk_ns;
+
+	/*
+	 * Synchronous settings can't be read from platform data or DT as
+	 * they provide Asynchronous settings for maximum compatibility.
+	 * If required to be different, e.g. wait pin, then we need to add
+	 * that setting in platform data or DT for omap2-onenand device.
+	 */
+	c->sync_settings.burst_read = true;
+	c->sync_settings.burst_wrap = true;
+	c->sync_settings.burst_len = GPMC_BURST_16;
+	c->sync_settings.device_width = GPMC_DEVWIDTH_16BIT;
+	c->sync_settings.mux_add_data = GPMC_MUX_AD;
+	/*
+	 * FIXME: wait pin must come from platform_data or DT.
+	 * Till then, no wait pin monitoring
+	 */
+	c->sync_settings.wait_on_read = false;
+	c->sync_settings.wait_on_write = false;
+
+	if (!c->freq) {
+		/* Initially, freq is not known */
+		c->freq = omap2_onenand_get_freq(c);
+	}
+
+	if (c->flags & ONENAND_SYNC_READ)
+		c->priv_flags = ONENAND_FLAG_SYNCREAD;
+	else if (c->flags & ONENAND_SYNC_READWRITE)
+		c->priv_flags = ONENAND_FLAG_SYNCREAD | ONENAND_FLAG_SYNCWRITE;
+
+	switch (c->freq) {
+	case 104:
+		min_gpmc_clk_period = 9600; /* 104 MHz */
+		t_ces   = 3;
+		t_avds  = 4;
+		t_avdh  = 2;
+		t_ach   = 3;
+		t_aavdh = 6;
+		t_rdyo  = 6;
+		break;
+	case 83:
+		min_gpmc_clk_period = 12000; /* 83 MHz */
+		t_ces   = 5;
+		t_avds  = 4;
+		t_avdh  = 2;
+		t_ach   = 6;
+		t_aavdh = 6;
+		t_rdyo  = 9;
+		break;
+	case 66:
+		min_gpmc_clk_period = 15000; /* 66 MHz */
+		t_ces   = 6;
+		t_avds  = 5;
+		t_avdh  = 2;
+		t_ach   = 6;
+		t_aavdh = 6;
+		t_rdyo  = 11;
+		break;
+	default:
+		min_gpmc_clk_period = 18500; /* 54 MHz */
+		t_ces   = 7;
+		t_avds  = 7;
+		t_avdh  = 7;
+		t_ach   = 9;
+		t_aavdh = 7;
+		t_rdyo  = 15;
+		c->priv_flags &= ~ONENAND_FLAG_SYNCWRITE;
+		break;
+	}
+
+	gpmc_clk_ns = omap_gpmc_get_clk_period(c->gpmc_cs,
+					       min_gpmc_clk_period);
+	gpmc_clk_ns /= 1000; /* ps to ns */
+
+	if (gpmc_clk_ns < 15) /* >66Mhz */
+		c->priv_flags |= ONENAND_FLAG_HF;
+	else
+		c->priv_flags &= ~ONENAND_FLAG_HF;
+
+	if (gpmc_clk_ns < 12) /* >83Mhz */
+		c->priv_flags |= ONENAND_FLAG_VHF;
+	else
+		c->priv_flags &= ~ONENAND_FLAG_VHF;
+
+	if (c->priv_flags & ONENAND_FLAG_VHF)
+		c->latency = 8;
+	else if (c->priv_flags & ONENAND_FLAG_HF)
+		c->latency = 6;
+	else if (gpmc_clk_ns >= 25) /* 40 MHz*/
+		c->latency = 3;
+	else
+		c->latency = 4;
+
+	/* Set synchronous read timings */
+	memset(dev_t, 0, sizeof(*dev_t));
+
+	if (c->priv_flags & ONENAND_FLAG_SYNCREAD)
+		c->sync_settings.sync_read = true;
+	if (c->priv_flags & ONENAND_FLAG_SYNCWRITE) {
+		c->sync_settings.sync_write = true;
+		c->sync_settings.burst_write = true;
+	} else {
+		dev_t->t_avdp_w = max(t_avdp, t_cer) * 1000;
+		dev_t->t_wpl = t_wpl * 1000;
+		dev_t->t_wph = t_wph * 1000;
+		dev_t->t_aavdh = t_aavdh * 1000;
+	}
+	dev_t->ce_xdelay = true;
+	dev_t->avd_xdelay = true;
+	dev_t->oe_xdelay = true;
+	dev_t->we_xdelay = true;
+	dev_t->clk = min_gpmc_clk_period;
+	dev_t->t_bacc = dev_t->clk;
+	dev_t->t_ces = t_ces * 1000;
+	dev_t->t_avds = t_avds * 1000;
+	dev_t->t_avdh = t_avdh * 1000;
+	dev_t->t_ach = t_ach * 1000;
+	dev_t->cyc_iaa = (c->latency + 1);
+	dev_t->t_cez_r = t_cez * 1000;
+	dev_t->t_cez_w = dev_t->t_cez_r;
+	dev_t->cyc_aavdh_oe = 1;
+	dev_t->t_rdyo = t_rdyo * 1000 + min_gpmc_clk_period;
+}
+
+static int omap2_onenand_setup_sync(struct omap2_onenand *c)
+{
+	int ret;
+	struct gpmc_device_timings dev_t;
+
+	omap2_onenand_get_sync_timings(c, &dev_t);
+
+	ret = omap_gpmc_retime(c->gpmc_cs, &c->sync_settings, &dev_t);
+	if (ret < 0)
+		return ret;
+
+	set_onenand_cfg(c);
+
+	return 0;
+}
+
+static void omap2_onenand_set_async_mode(struct omap2_onenand *c)
+{
+	u32 reg;
+
+	/* Ensure sync read and sync write are disabled */
+	reg = read_reg(c, ONENAND_REG_SYS_CFG1);
+	reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE;
+	write_reg(c, reg, ONENAND_REG_SYS_CFG1);
+}
+
+static int omap2_onenand_setup(struct omap2_onenand *c)
+{
+	struct device *dev = &c->pdev->dev;
+	unsigned l = ONENAND_SYNC_READ | ONENAND_SYNC_READWRITE;
+	int ret;
+
+	omap2_onenand_set_async_mode(c);
+
+	if (!(c->flags & l))
+		return 0;
+
+	ret = omap2_onenand_setup_sync(c);
+	if (ret)
+		dev_err(dev, "unable to switch to Synchronous mode\n");
+
+	return ret;
+}
+
 static struct platform_driver omap2_onenand_driver;
 
 static void omap2_onenand_shutdown(struct platform_device *pdev)
@@ -602,6 +848,7 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 
 	init_completion(&c->irq_done);
 	init_completion(&c->dma_done);
+	c->pdev = pdev;
 	c->flags = pdata->flags;
 	c->gpmc_cs = pdata->cs;
 	c->gpio_irq = pdata->gpio_irq;
@@ -634,14 +881,10 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 		goto err_release_mem_region;
 	}
 
-	if (pdata->onenand_setup != NULL) {
-		r = pdata->onenand_setup(c->onenand.base, &c->freq);
-		if (r < 0) {
-			dev_err(&pdev->dev, "Onenand platform setup failed: "
-				"%d\n", r);
-			goto err_iounmap;
-		}
-		c->setup = pdata->onenand_setup;
+	r = omap2_onenand_setup(c);
+	if (r < 0) {
+		dev_err(&pdev->dev, "setup failed:%d\n", r);
+		goto err_iounmap;
 	}
 
 	if (c->gpio_irq) {
@@ -683,7 +926,6 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 		 "base %p, freq %d MHz\n", c->gpmc_cs, c->phys_base,
 		 c->onenand.base, c->freq);
 
-	c->pdev = pdev;
 	c->mtd.name = dev_name(&pdev->dev);
 	c->mtd.priv = &c->onenand;
 	c->mtd.owner = THIS_MODULE;
diff --git a/include/linux/platform_data/mtd-onenand-omap2.h b/include/linux/platform_data/mtd-onenand-omap2.h
index 445b41e..ac1e6f3 100644
--- a/include/linux/platform_data/mtd-onenand-omap2.h
+++ b/include/linux/platform_data/mtd-onenand-omap2.h
@@ -22,7 +22,6 @@ struct omap_onenand_platform_data {
 	int			gpio_irq;
 	struct mtd_partition	*parts;
 	int			nr_parts;
-	int			(*onenand_setup)(void __iomem *, int *freq_ptr);
 	int			dma_channel;
 	u8			flags;
 	u8			skip_initial_unlocking;
@@ -31,5 +30,6 @@ struct omap_onenand_platform_data {
 	struct device_node	*of_node;
 
 	u8			regulator_can_sleep;	/* deprecated */
+	int (*onenand_setup)(void __iomem *, int *freq_ptr);	/* deprecated */
 };
 #endif
-- 
1.8.3.2

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

* [PATCH 19/36] mtd: onenand: omap: Use devres managed resources
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Use devres managed resources for Memory, GPIO and Interrupt
resources.

0 is a valid gpio, so use gpio_is_valid() to check for
valid gpio number.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/mtd/onenand/omap2.c | 92 ++++++++++++++++-----------------------------
 1 file changed, 33 insertions(+), 59 deletions(-)

diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index 238dd7a..b6a9ec0 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -38,8 +38,7 @@
 #include <asm/mach/flash.h>
 #include <linux/platform_data/mtd-onenand-omap2.h>
 #include <linux/platform_data/gpmc-omap.h>
-#include <asm/gpio.h>
-
+#include <linux/gpio.h>
 #include <linux/omap-dma.h>
 
 #define DRIVER_NAME "omap2-onenand"
@@ -835,6 +834,7 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 	int r;
 	struct resource *res;
 	struct mtd_part_parser_data ppdata = {};
+	struct device *dev = &pdev->dev;
 
 	pdata = dev_get_platdata(&pdev->dev);
 	if (pdata == NULL) {
@@ -842,7 +842,7 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
-	c = kzalloc(sizeof(struct omap2_onenand), GFP_KERNEL);
+	c = devm_kzalloc(dev, sizeof(struct omap2_onenand), GFP_KERNEL);
 	if (!c)
 		return -ENOMEM;
 
@@ -855,50 +855,40 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 	c->dma_channel = pdata->dma_channel;
 	if (c->dma_channel < 0) {
 		/* if -1, don't use DMA */
-		c->gpio_irq = 0;
+		c->gpio_irq = -EINVAL;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res == NULL) {
-		r = -EINVAL;
-		dev_err(&pdev->dev, "error getting memory resource\n");
-		goto err_kfree;
-	}
+	c->onenand.base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(c->onenand.base))
+		return PTR_ERR(c->onenand.base);
 
 	c->phys_base = res->start;
 	c->mem_size = resource_size(res);
 
-	if (request_mem_region(c->phys_base, c->mem_size,
-			       pdev->dev.driver->name) == NULL) {
-		dev_err(&pdev->dev, "Cannot reserve memory region at 0x%08lx, size: 0x%x\n",
-						c->phys_base, c->mem_size);
-		r = -EBUSY;
-		goto err_kfree;
-	}
-	c->onenand.base = ioremap(c->phys_base, c->mem_size);
-	if (c->onenand.base == NULL) {
-		r = -ENOMEM;
-		goto err_release_mem_region;
-	}
-
 	r = omap2_onenand_setup(c);
-	if (r < 0) {
-		dev_err(&pdev->dev, "setup failed:%d\n", r);
-		goto err_iounmap;
-	}
+	if (r)
+		return -ENODEV;
 
-	if (c->gpio_irq) {
-		if ((r = gpio_request(c->gpio_irq, "OneNAND irq")) < 0) {
-			dev_err(&pdev->dev,  "Failed to request GPIO%d for "
-				"OneNAND\n", c->gpio_irq);
-			goto err_iounmap;
-	}
-	gpio_direction_input(c->gpio_irq);
+	if (gpio_is_valid(c->gpio_irq)) {
+		r = devm_gpio_request(dev, c->gpio_irq, "OneNAND irq");
+		if (r) {
+			dev_err(dev, "Failed to request GPIO %d",
+				c->gpio_irq);
+			return r;
+		}
+
+		gpio_direction_input(c->gpio_irq);
 
-	if ((r = request_irq(gpio_to_irq(c->gpio_irq),
-			     omap2_onenand_interrupt, IRQF_TRIGGER_RISING,
-			     pdev->dev.driver->name, c)) < 0)
-		goto err_release_gpio;
+		r = devm_request_irq(dev, gpio_to_irq(c->gpio_irq),
+				     omap2_onenand_interrupt,
+				     IRQF_TRIGGER_RISING,
+				     pdev->dev.driver->name, c);
+		if (r) {
+			dev_err(dev, "failed to request IRQ %d:%d\n",
+				c->gpio_irq, r);
+			return r;
+		}
 	}
 
 	if (c->dma_channel >= 0) {
@@ -915,9 +905,8 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 			omap_set_dma_dest_burst_mode(c->dma_channel,
 						     OMAP_DMA_DATA_BURST_8);
 		} else {
-			dev_info(&pdev->dev,
-				 "failed to allocate DMA for OneNAND, "
-				 "using PIO instead\n");
+			dev_info(dev,
+				 "failed to allocate DMA for OneNAND, using PIO instead\n");
 			c->dma_channel = -1;
 		}
 	}
@@ -947,8 +936,11 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 	if (pdata->skip_initial_unlocking)
 		this->options |= ONENAND_SKIP_INITIAL_UNLOCKING;
 
-	if ((r = onenand_scan(&c->mtd, 1)) < 0)
+	r = onenand_scan(&c->mtd, 1);
+	if (r) {
+		dev_err(dev, "OneNAND scan failed :%d\n", r);
 		goto err_release_dma;
+	}
 
 	ppdata.of_node = pdata->of_node;
 	r = mtd_device_parse_register(&c->mtd, NULL, &ppdata,
@@ -966,17 +958,6 @@ err_release_onenand:
 err_release_dma:
 	if (c->dma_channel != -1)
 		omap_free_dma(c->dma_channel);
-	if (c->gpio_irq)
-		free_irq(gpio_to_irq(c->gpio_irq), c);
-err_release_gpio:
-	if (c->gpio_irq)
-		gpio_free(c->gpio_irq);
-err_iounmap:
-	iounmap(c->onenand.base);
-err_release_mem_region:
-	release_mem_region(c->phys_base, c->mem_size);
-err_kfree:
-	kfree(c);
 
 	return r;
 }
@@ -989,13 +970,6 @@ static int omap2_onenand_remove(struct platform_device *pdev)
 	if (c->dma_channel != -1)
 		omap_free_dma(c->dma_channel);
 	omap2_onenand_shutdown(pdev);
-	if (c->gpio_irq) {
-		free_irq(gpio_to_irq(c->gpio_irq), c);
-		gpio_free(c->gpio_irq);
-	}
-	iounmap(c->onenand.base);
-	release_mem_region(c->phys_base, c->mem_size);
-	kfree(c);
 
 	return 0;
 }
-- 
1.8.3.2


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

* [PATCH 19/36] mtd: onenand: omap: Use devres managed resources
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Use devres managed resources for Memory, GPIO and Interrupt
resources.

0 is a valid gpio, so use gpio_is_valid() to check for
valid gpio number.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/mtd/onenand/omap2.c | 92 ++++++++++++++++-----------------------------
 1 file changed, 33 insertions(+), 59 deletions(-)

diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index 238dd7a..b6a9ec0 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -38,8 +38,7 @@
 #include <asm/mach/flash.h>
 #include <linux/platform_data/mtd-onenand-omap2.h>
 #include <linux/platform_data/gpmc-omap.h>
-#include <asm/gpio.h>
-
+#include <linux/gpio.h>
 #include <linux/omap-dma.h>
 
 #define DRIVER_NAME "omap2-onenand"
@@ -835,6 +834,7 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 	int r;
 	struct resource *res;
 	struct mtd_part_parser_data ppdata = {};
+	struct device *dev = &pdev->dev;
 
 	pdata = dev_get_platdata(&pdev->dev);
 	if (pdata == NULL) {
@@ -842,7 +842,7 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
-	c = kzalloc(sizeof(struct omap2_onenand), GFP_KERNEL);
+	c = devm_kzalloc(dev, sizeof(struct omap2_onenand), GFP_KERNEL);
 	if (!c)
 		return -ENOMEM;
 
@@ -855,50 +855,40 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 	c->dma_channel = pdata->dma_channel;
 	if (c->dma_channel < 0) {
 		/* if -1, don't use DMA */
-		c->gpio_irq = 0;
+		c->gpio_irq = -EINVAL;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res == NULL) {
-		r = -EINVAL;
-		dev_err(&pdev->dev, "error getting memory resource\n");
-		goto err_kfree;
-	}
+	c->onenand.base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(c->onenand.base))
+		return PTR_ERR(c->onenand.base);
 
 	c->phys_base = res->start;
 	c->mem_size = resource_size(res);
 
-	if (request_mem_region(c->phys_base, c->mem_size,
-			       pdev->dev.driver->name) == NULL) {
-		dev_err(&pdev->dev, "Cannot reserve memory region at 0x%08lx, size: 0x%x\n",
-						c->phys_base, c->mem_size);
-		r = -EBUSY;
-		goto err_kfree;
-	}
-	c->onenand.base = ioremap(c->phys_base, c->mem_size);
-	if (c->onenand.base == NULL) {
-		r = -ENOMEM;
-		goto err_release_mem_region;
-	}
-
 	r = omap2_onenand_setup(c);
-	if (r < 0) {
-		dev_err(&pdev->dev, "setup failed:%d\n", r);
-		goto err_iounmap;
-	}
+	if (r)
+		return -ENODEV;
 
-	if (c->gpio_irq) {
-		if ((r = gpio_request(c->gpio_irq, "OneNAND irq")) < 0) {
-			dev_err(&pdev->dev,  "Failed to request GPIO%d for "
-				"OneNAND\n", c->gpio_irq);
-			goto err_iounmap;
-	}
-	gpio_direction_input(c->gpio_irq);
+	if (gpio_is_valid(c->gpio_irq)) {
+		r = devm_gpio_request(dev, c->gpio_irq, "OneNAND irq");
+		if (r) {
+			dev_err(dev, "Failed to request GPIO %d",
+				c->gpio_irq);
+			return r;
+		}
+
+		gpio_direction_input(c->gpio_irq);
 
-	if ((r = request_irq(gpio_to_irq(c->gpio_irq),
-			     omap2_onenand_interrupt, IRQF_TRIGGER_RISING,
-			     pdev->dev.driver->name, c)) < 0)
-		goto err_release_gpio;
+		r = devm_request_irq(dev, gpio_to_irq(c->gpio_irq),
+				     omap2_onenand_interrupt,
+				     IRQF_TRIGGER_RISING,
+				     pdev->dev.driver->name, c);
+		if (r) {
+			dev_err(dev, "failed to request IRQ %d:%d\n",
+				c->gpio_irq, r);
+			return r;
+		}
 	}
 
 	if (c->dma_channel >= 0) {
@@ -915,9 +905,8 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 			omap_set_dma_dest_burst_mode(c->dma_channel,
 						     OMAP_DMA_DATA_BURST_8);
 		} else {
-			dev_info(&pdev->dev,
-				 "failed to allocate DMA for OneNAND, "
-				 "using PIO instead\n");
+			dev_info(dev,
+				 "failed to allocate DMA for OneNAND, using PIO instead\n");
 			c->dma_channel = -1;
 		}
 	}
@@ -947,8 +936,11 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 	if (pdata->skip_initial_unlocking)
 		this->options |= ONENAND_SKIP_INITIAL_UNLOCKING;
 
-	if ((r = onenand_scan(&c->mtd, 1)) < 0)
+	r = onenand_scan(&c->mtd, 1);
+	if (r) {
+		dev_err(dev, "OneNAND scan failed :%d\n", r);
 		goto err_release_dma;
+	}
 
 	ppdata.of_node = pdata->of_node;
 	r = mtd_device_parse_register(&c->mtd, NULL, &ppdata,
@@ -966,17 +958,6 @@ err_release_onenand:
 err_release_dma:
 	if (c->dma_channel != -1)
 		omap_free_dma(c->dma_channel);
-	if (c->gpio_irq)
-		free_irq(gpio_to_irq(c->gpio_irq), c);
-err_release_gpio:
-	if (c->gpio_irq)
-		gpio_free(c->gpio_irq);
-err_iounmap:
-	iounmap(c->onenand.base);
-err_release_mem_region:
-	release_mem_region(c->phys_base, c->mem_size);
-err_kfree:
-	kfree(c);
 
 	return r;
 }
@@ -989,13 +970,6 @@ static int omap2_onenand_remove(struct platform_device *pdev)
 	if (c->dma_channel != -1)
 		omap_free_dma(c->dma_channel);
 	omap2_onenand_shutdown(pdev);
-	if (c->gpio_irq) {
-		free_irq(gpio_to_irq(c->gpio_irq), c);
-		gpio_free(c->gpio_irq);
-	}
-	iounmap(c->onenand.base);
-	release_mem_region(c->phys_base, c->mem_size);
-	kfree(c);
 
 	return 0;
 }
-- 
1.8.3.2

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

* [PATCH 19/36] mtd: onenand: omap: Use devres managed resources
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Use devres managed resources for Memory, GPIO and Interrupt
resources.

0 is a valid gpio, so use gpio_is_valid() to check for
valid gpio number.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/mtd/onenand/omap2.c | 92 ++++++++++++++++-----------------------------
 1 file changed, 33 insertions(+), 59 deletions(-)

diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index 238dd7a..b6a9ec0 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -38,8 +38,7 @@
 #include <asm/mach/flash.h>
 #include <linux/platform_data/mtd-onenand-omap2.h>
 #include <linux/platform_data/gpmc-omap.h>
-#include <asm/gpio.h>
-
+#include <linux/gpio.h>
 #include <linux/omap-dma.h>
 
 #define DRIVER_NAME "omap2-onenand"
@@ -835,6 +834,7 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 	int r;
 	struct resource *res;
 	struct mtd_part_parser_data ppdata = {};
+	struct device *dev = &pdev->dev;
 
 	pdata = dev_get_platdata(&pdev->dev);
 	if (pdata == NULL) {
@@ -842,7 +842,7 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
-	c = kzalloc(sizeof(struct omap2_onenand), GFP_KERNEL);
+	c = devm_kzalloc(dev, sizeof(struct omap2_onenand), GFP_KERNEL);
 	if (!c)
 		return -ENOMEM;
 
@@ -855,50 +855,40 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 	c->dma_channel = pdata->dma_channel;
 	if (c->dma_channel < 0) {
 		/* if -1, don't use DMA */
-		c->gpio_irq = 0;
+		c->gpio_irq = -EINVAL;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res == NULL) {
-		r = -EINVAL;
-		dev_err(&pdev->dev, "error getting memory resource\n");
-		goto err_kfree;
-	}
+	c->onenand.base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(c->onenand.base))
+		return PTR_ERR(c->onenand.base);
 
 	c->phys_base = res->start;
 	c->mem_size = resource_size(res);
 
-	if (request_mem_region(c->phys_base, c->mem_size,
-			       pdev->dev.driver->name) == NULL) {
-		dev_err(&pdev->dev, "Cannot reserve memory region at 0x%08lx, size: 0x%x\n",
-						c->phys_base, c->mem_size);
-		r = -EBUSY;
-		goto err_kfree;
-	}
-	c->onenand.base = ioremap(c->phys_base, c->mem_size);
-	if (c->onenand.base == NULL) {
-		r = -ENOMEM;
-		goto err_release_mem_region;
-	}
-
 	r = omap2_onenand_setup(c);
-	if (r < 0) {
-		dev_err(&pdev->dev, "setup failed:%d\n", r);
-		goto err_iounmap;
-	}
+	if (r)
+		return -ENODEV;
 
-	if (c->gpio_irq) {
-		if ((r = gpio_request(c->gpio_irq, "OneNAND irq")) < 0) {
-			dev_err(&pdev->dev,  "Failed to request GPIO%d for "
-				"OneNAND\n", c->gpio_irq);
-			goto err_iounmap;
-	}
-	gpio_direction_input(c->gpio_irq);
+	if (gpio_is_valid(c->gpio_irq)) {
+		r = devm_gpio_request(dev, c->gpio_irq, "OneNAND irq");
+		if (r) {
+			dev_err(dev, "Failed to request GPIO %d",
+				c->gpio_irq);
+			return r;
+		}
+
+		gpio_direction_input(c->gpio_irq);
 
-	if ((r = request_irq(gpio_to_irq(c->gpio_irq),
-			     omap2_onenand_interrupt, IRQF_TRIGGER_RISING,
-			     pdev->dev.driver->name, c)) < 0)
-		goto err_release_gpio;
+		r = devm_request_irq(dev, gpio_to_irq(c->gpio_irq),
+				     omap2_onenand_interrupt,
+				     IRQF_TRIGGER_RISING,
+				     pdev->dev.driver->name, c);
+		if (r) {
+			dev_err(dev, "failed to request IRQ %d:%d\n",
+				c->gpio_irq, r);
+			return r;
+		}
 	}
 
 	if (c->dma_channel >= 0) {
@@ -915,9 +905,8 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 			omap_set_dma_dest_burst_mode(c->dma_channel,
 						     OMAP_DMA_DATA_BURST_8);
 		} else {
-			dev_info(&pdev->dev,
-				 "failed to allocate DMA for OneNAND, "
-				 "using PIO instead\n");
+			dev_info(dev,
+				 "failed to allocate DMA for OneNAND, using PIO instead\n");
 			c->dma_channel = -1;
 		}
 	}
@@ -947,8 +936,11 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 	if (pdata->skip_initial_unlocking)
 		this->options |= ONENAND_SKIP_INITIAL_UNLOCKING;
 
-	if ((r = onenand_scan(&c->mtd, 1)) < 0)
+	r = onenand_scan(&c->mtd, 1);
+	if (r) {
+		dev_err(dev, "OneNAND scan failed :%d\n", r);
 		goto err_release_dma;
+	}
 
 	ppdata.of_node = pdata->of_node;
 	r = mtd_device_parse_register(&c->mtd, NULL, &ppdata,
@@ -966,17 +958,6 @@ err_release_onenand:
 err_release_dma:
 	if (c->dma_channel != -1)
 		omap_free_dma(c->dma_channel);
-	if (c->gpio_irq)
-		free_irq(gpio_to_irq(c->gpio_irq), c);
-err_release_gpio:
-	if (c->gpio_irq)
-		gpio_free(c->gpio_irq);
-err_iounmap:
-	iounmap(c->onenand.base);
-err_release_mem_region:
-	release_mem_region(c->phys_base, c->mem_size);
-err_kfree:
-	kfree(c);
 
 	return r;
 }
@@ -989,13 +970,6 @@ static int omap2_onenand_remove(struct platform_device *pdev)
 	if (c->dma_channel != -1)
 		omap_free_dma(c->dma_channel);
 	omap2_onenand_shutdown(pdev);
-	if (c->gpio_irq) {
-		free_irq(gpio_to_irq(c->gpio_irq), c);
-		gpio_free(c->gpio_irq);
-	}
-	iounmap(c->onenand.base);
-	release_mem_region(c->phys_base, c->mem_size);
-	kfree(c);
 
 	return 0;
 }
-- 
1.8.3.2

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

* [PATCH 20/36] mtd: onenand: omap: Clean up device tree support
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Move OneNAND specific device tree parsing to NAND driver.
The OneNAND device node must have its own compatible id.

Add a new property 'ti,onenand-sync-rw' to indicate
synchronous read + write support. Default mode would be
only synchronous reads.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 .../devicetree/bindings/mtd/gpmc-onenand.txt       |  4 +
 arch/arm/mach-omap2/gpmc-onenand.c                 | 14 ----
 arch/arm/mach-omap2/gpmc.c                         | 55 +++----------
 drivers/mtd/onenand/omap2.c                        | 90 ++++++++++++++++------
 include/linux/platform_data/mtd-onenand-omap2.h    |  4 +-
 5 files changed, 84 insertions(+), 83 deletions(-)

diff --git a/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt b/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt
index b752942..7fc9c13 100644
--- a/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt
+++ b/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt
@@ -9,9 +9,12 @@ Documentation/devicetree/bindings/bus/ti-gpmc.txt
 
 Required properties:
 
+ - compatible:		"ti,omap2-onenand"
  - reg:			The CS line the peripheral is connected to
  - gpmc,device-width	Width of the ONENAND device connected to the GPMC
 			in bytes. Must be 1 or 2.
+ - ti,onenand-sync-rw:	Bool. Enable synchronous Read and Write. If not
+			present, only Synchronous Read is enabled.
 
 Optional properties:
 
@@ -35,6 +38,7 @@ Example for an OMAP3430 board:
 		#size-cells = <1>;
 
 		onenand@0 {
+			compatible = "ti,omap2-onenand"
 			reg = <0 0 0>; /* CS0, offset 0 */
 			gpmc,device-width = <2>;
 
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index d09c342..37ed4f1 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -75,20 +75,6 @@ static int omap2_onenand_setup_async(struct omap_onenand_platform_data
 	struct gpmc_device_timings dev_t;
 	int ret;
 
-	if (gpmc_onenand_data->of_node) {
-		gpmc_read_settings_dt(gpmc_onenand_data->of_node,
-				      &onenand_async);
-		if (onenand_async.sync_read || onenand_async.sync_write) {
-			if (onenand_async.sync_write)
-				gpmc_onenand_data->flags |=
-					ONENAND_SYNC_READWRITE;
-			else
-				gpmc_onenand_data->flags |= ONENAND_SYNC_READ;
-			onenand_async.sync_read = false;
-			onenand_async.sync_write = false;
-		}
-	}
-
 	ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_async);
 	if (ret < 0)
 		return ret;
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 50ef1a9..ee030cd 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -39,7 +39,6 @@
 #include "common.h"
 #include "omap_device.h"
 #include "gpmc.h"
-#include "gpmc-onenand.h"
 
 #define	DEVICE_NAME		"omap-gpmc"
 
@@ -1166,43 +1165,6 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
 		of_property_read_bool(np, "gpmc,time-para-granularity");
 }
 
-#if IS_ENABLED(CONFIG_MTD_ONENAND)
-static int gpmc_probe_onenand_child(struct platform_device *pdev,
-				 struct device_node *child)
-{
-	u32 val;
-	struct omap_onenand_platform_data *gpmc_onenand_data;
-
-	if (of_property_read_u32(child, "reg", &val) < 0) {
-		dev_err(&pdev->dev, "%s has no 'reg' property\n",
-			child->full_name);
-		return -ENODEV;
-	}
-
-	gpmc_onenand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_onenand_data),
-					 GFP_KERNEL);
-	if (!gpmc_onenand_data)
-		return -ENOMEM;
-
-	gpmc_onenand_data->cs = val;
-	gpmc_onenand_data->of_node = child;
-	gpmc_onenand_data->dma_channel = -1;
-
-	if (!of_property_read_u32(child, "dma-channel", &val))
-		gpmc_onenand_data->dma_channel = val;
-
-	gpmc_onenand_init(gpmc_onenand_data);
-
-	return 0;
-}
-#else
-static int gpmc_probe_onenand_child(struct platform_device *pdev,
-				    struct device_node *child)
-{
-	return 0;
-}
-#endif
-
 /**
  * gpmc_probe_generic_child - configures the gpmc for a child device
  * @pdev:	pointer to gpmc platform device
@@ -1292,6 +1254,12 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
 		}
 
 		gpmc_s.device_nand = true;
+
+	} else if (of_node_cmp(child->name, "onenand") == 0) {
+		/* DT incorrectly sets sync modes, onenand default is async */
+		gpmc_s.sync_read = false;
+		gpmc_s.sync_write = false;
+
 	} else {
 		if (of_property_read_u32(child, "bank-width",
 					 &gpmc_s.device_width)) {
@@ -1363,12 +1331,11 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 		if (!child->name)
 			continue;
 
-		if (of_node_cmp(child->name, "onenand") == 0)
-			ret = gpmc_probe_onenand_child(pdev, child);
-		else if (of_node_cmp(child->name, "ethernet") == 0 ||
-			 of_node_cmp(child->name, "nor") == 0 ||
-			 of_node_cmp(child->name, "uart") == 0 ||
-			 of_node_cmp(child->name, "nand") == 0)
+		if (of_node_cmp(child->name, "ethernet") == 0 ||
+		    of_node_cmp(child->name, "nor") == 0 ||
+		    of_node_cmp(child->name, "uart") == 0 ||
+		    of_node_cmp(child->name, "nand") == 0 ||
+		    of_node_cmp(child->name, "onenand") == 0)
 			ret = gpmc_probe_generic_child(pdev, child);
 
 		if (WARN(ret < 0, "%s: probing gpmc child %s failed\n",
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index b6a9ec0..35d2d39 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -40,6 +40,10 @@
 #include <linux/platform_data/gpmc-omap.h>
 #include <linux/gpio.h>
 #include <linux/omap-dma.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_mtd.h>
+#include <linux/of_gpio.h>
 
 #define DRIVER_NAME "omap2-onenand"
 
@@ -826,9 +830,33 @@ static void omap2_onenand_shutdown(struct platform_device *pdev)
 	memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE);
 }
 
+static int omap2_onenand_get_dt_info(struct device *dev,
+				     struct omap2_onenand *c)
+{
+	struct device_node *node = dev->of_node;
+
+	/* Chip Select number */
+	if (of_property_read_u32(node, "reg", &c->gpmc_cs) < 0) {
+		dev_err(dev, "No 'reg' property\n");
+		return -EINVAL;
+	}
+
+	/* Enable synchronous read by default */
+	c->flags = ONENAND_SYNC_READ;
+	/* Enable synchronous write only if indicated by DT */
+	if (of_property_read_bool(node, "ti,onenand-sync-rw"))
+		c->flags = ONENAND_SYNC_READWRITE;
+
+	/* TODO: DMA channel, GPIO IRQ for wait */
+	c->dma_channel = -1;
+	c->gpio_irq = -EINVAL;
+
+	return 0;
+}
+
 static int omap2_onenand_probe(struct platform_device *pdev)
 {
-	struct omap_onenand_platform_data *pdata;
+	struct omap_onenand_platform_data *pdata = NULL;
 	struct omap2_onenand *c;
 	struct onenand_chip *this;
 	int r;
@@ -836,28 +864,40 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 	struct mtd_part_parser_data ppdata = {};
 	struct device *dev = &pdev->dev;
 
-	pdata = dev_get_platdata(&pdev->dev);
-	if (pdata == NULL) {
-		dev_err(&pdev->dev, "platform data missing\n");
-		return -ENODEV;
-	}
-
 	c = devm_kzalloc(dev, sizeof(struct omap2_onenand), GFP_KERNEL);
 	if (!c)
 		return -ENOMEM;
 
-	init_completion(&c->irq_done);
-	init_completion(&c->dma_done);
-	c->pdev = pdev;
-	c->flags = pdata->flags;
-	c->gpmc_cs = pdata->cs;
-	c->gpio_irq = pdata->gpio_irq;
-	c->dma_channel = pdata->dma_channel;
+	this = &c->onenand;
+
+	if (dev->of_node) {
+		if (omap2_onenand_get_dt_info(dev, c))
+			return -EINVAL;
+
+	} else {
+		pdata = dev_get_platdata(dev);
+		if (pdata == NULL) {
+			dev_err(dev, "platform data missing\n");
+			return -ENODEV;
+		}
+
+		c->flags = pdata->flags;
+		c->gpio_irq = pdata->gpio_irq;
+		c->dma_channel = pdata->dma_channel;
+
+		if (pdata->skip_initial_unlocking)
+			this->options |= ONENAND_SKIP_INITIAL_UNLOCKING;
+	}
+
 	if (c->dma_channel < 0) {
 		/* if -1, don't use DMA */
 		c->gpio_irq = -EINVAL;
 	}
 
+	init_completion(&c->irq_done);
+	init_completion(&c->dma_done);
+	c->pdev = pdev;
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	c->onenand.base = devm_ioremap_resource(dev, res);
 	if (IS_ERR(c->onenand.base))
@@ -921,7 +961,6 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 
 	c->mtd.dev.parent = &pdev->dev;
 
-	this = &c->onenand;
 	if (c->dma_channel >= 0) {
 		this->wait = omap2_onenand_wait;
 		if (c->flags & ONENAND_IN_OMAP34XX) {
@@ -933,19 +972,20 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 		}
 	}
 
-	if (pdata->skip_initial_unlocking)
-		this->options |= ONENAND_SKIP_INITIAL_UNLOCKING;
-
 	r = onenand_scan(&c->mtd, 1);
 	if (r) {
 		dev_err(dev, "OneNAND scan failed :%d\n", r);
 		goto err_release_dma;
 	}
 
-	ppdata.of_node = pdata->of_node;
-	r = mtd_device_parse_register(&c->mtd, NULL, &ppdata,
-				      pdata ? pdata->parts : NULL,
-				      pdata ? pdata->nr_parts : 0);
+	if (dev->of_node) {
+		ppdata.of_node = dev->of_node;
+		r = mtd_device_parse_register(&c->mtd, NULL, &ppdata, NULL, 0);
+
+	} else {
+		r = mtd_device_register(&c->mtd, pdata->parts, pdata->nr_parts);
+	}
+
 	if (r)
 		goto err_release_onenand;
 
@@ -974,6 +1014,11 @@ static int omap2_onenand_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct of_device_id omap2_onenand_ids[] = {
+	{ .compatible = "ti,omap2-onenand", },
+	{},
+};
+
 static struct platform_driver omap2_onenand_driver = {
 	.probe		= omap2_onenand_probe,
 	.remove		= omap2_onenand_remove,
@@ -981,6 +1026,7 @@ static struct platform_driver omap2_onenand_driver = {
 	.driver		= {
 		.name	= DRIVER_NAME,
 		.owner  = THIS_MODULE,
+		.of_match_table = of_match_ptr(omap2_onenand_ids),
 	},
 };
 
diff --git a/include/linux/platform_data/mtd-onenand-omap2.h b/include/linux/platform_data/mtd-onenand-omap2.h
index ac1e6f3..99d8716 100644
--- a/include/linux/platform_data/mtd-onenand-omap2.h
+++ b/include/linux/platform_data/mtd-onenand-omap2.h
@@ -26,10 +26,8 @@ struct omap_onenand_platform_data {
 	u8			flags;
 	u8			skip_initial_unlocking;
 
-	/* for passing the partitions */
-	struct device_node	*of_node;
-
 	u8			regulator_can_sleep;	/* deprecated */
 	int (*onenand_setup)(void __iomem *, int *freq_ptr);	/* deprecated */
+	struct device_node	*of_node;		/* deprecated */
 };
 #endif
-- 
1.8.3.2


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

* [PATCH 20/36] mtd: onenand: omap: Clean up device tree support
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Move OneNAND specific device tree parsing to NAND driver.
The OneNAND device node must have its own compatible id.

Add a new property 'ti,onenand-sync-rw' to indicate
synchronous read + write support. Default mode would be
only synchronous reads.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 .../devicetree/bindings/mtd/gpmc-onenand.txt       |  4 +
 arch/arm/mach-omap2/gpmc-onenand.c                 | 14 ----
 arch/arm/mach-omap2/gpmc.c                         | 55 +++----------
 drivers/mtd/onenand/omap2.c                        | 90 ++++++++++++++++------
 include/linux/platform_data/mtd-onenand-omap2.h    |  4 +-
 5 files changed, 84 insertions(+), 83 deletions(-)

diff --git a/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt b/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt
index b752942..7fc9c13 100644
--- a/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt
+++ b/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt
@@ -9,9 +9,12 @@ Documentation/devicetree/bindings/bus/ti-gpmc.txt
 
 Required properties:
 
+ - compatible:		"ti,omap2-onenand"
  - reg:			The CS line the peripheral is connected to
  - gpmc,device-width	Width of the ONENAND device connected to the GPMC
 			in bytes. Must be 1 or 2.
+ - ti,onenand-sync-rw:	Bool. Enable synchronous Read and Write. If not
+			present, only Synchronous Read is enabled.
 
 Optional properties:
 
@@ -35,6 +38,7 @@ Example for an OMAP3430 board:
 		#size-cells = <1>;
 
 		onenand@0 {
+			compatible = "ti,omap2-onenand"
 			reg = <0 0 0>; /* CS0, offset 0 */
 			gpmc,device-width = <2>;
 
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index d09c342..37ed4f1 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -75,20 +75,6 @@ static int omap2_onenand_setup_async(struct omap_onenand_platform_data
 	struct gpmc_device_timings dev_t;
 	int ret;
 
-	if (gpmc_onenand_data->of_node) {
-		gpmc_read_settings_dt(gpmc_onenand_data->of_node,
-				      &onenand_async);
-		if (onenand_async.sync_read || onenand_async.sync_write) {
-			if (onenand_async.sync_write)
-				gpmc_onenand_data->flags |=
-					ONENAND_SYNC_READWRITE;
-			else
-				gpmc_onenand_data->flags |= ONENAND_SYNC_READ;
-			onenand_async.sync_read = false;
-			onenand_async.sync_write = false;
-		}
-	}
-
 	ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_async);
 	if (ret < 0)
 		return ret;
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 50ef1a9..ee030cd 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -39,7 +39,6 @@
 #include "common.h"
 #include "omap_device.h"
 #include "gpmc.h"
-#include "gpmc-onenand.h"
 
 #define	DEVICE_NAME		"omap-gpmc"
 
@@ -1166,43 +1165,6 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
 		of_property_read_bool(np, "gpmc,time-para-granularity");
 }
 
-#if IS_ENABLED(CONFIG_MTD_ONENAND)
-static int gpmc_probe_onenand_child(struct platform_device *pdev,
-				 struct device_node *child)
-{
-	u32 val;
-	struct omap_onenand_platform_data *gpmc_onenand_data;
-
-	if (of_property_read_u32(child, "reg", &val) < 0) {
-		dev_err(&pdev->dev, "%s has no 'reg' property\n",
-			child->full_name);
-		return -ENODEV;
-	}
-
-	gpmc_onenand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_onenand_data),
-					 GFP_KERNEL);
-	if (!gpmc_onenand_data)
-		return -ENOMEM;
-
-	gpmc_onenand_data->cs = val;
-	gpmc_onenand_data->of_node = child;
-	gpmc_onenand_data->dma_channel = -1;
-
-	if (!of_property_read_u32(child, "dma-channel", &val))
-		gpmc_onenand_data->dma_channel = val;
-
-	gpmc_onenand_init(gpmc_onenand_data);
-
-	return 0;
-}
-#else
-static int gpmc_probe_onenand_child(struct platform_device *pdev,
-				    struct device_node *child)
-{
-	return 0;
-}
-#endif
-
 /**
  * gpmc_probe_generic_child - configures the gpmc for a child device
  * @pdev:	pointer to gpmc platform device
@@ -1292,6 +1254,12 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
 		}
 
 		gpmc_s.device_nand = true;
+
+	} else if (of_node_cmp(child->name, "onenand") == 0) {
+		/* DT incorrectly sets sync modes, onenand default is async */
+		gpmc_s.sync_read = false;
+		gpmc_s.sync_write = false;
+
 	} else {
 		if (of_property_read_u32(child, "bank-width",
 					 &gpmc_s.device_width)) {
@@ -1363,12 +1331,11 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 		if (!child->name)
 			continue;
 
-		if (of_node_cmp(child->name, "onenand") == 0)
-			ret = gpmc_probe_onenand_child(pdev, child);
-		else if (of_node_cmp(child->name, "ethernet") == 0 ||
-			 of_node_cmp(child->name, "nor") == 0 ||
-			 of_node_cmp(child->name, "uart") == 0 ||
-			 of_node_cmp(child->name, "nand") == 0)
+		if (of_node_cmp(child->name, "ethernet") == 0 ||
+		    of_node_cmp(child->name, "nor") == 0 ||
+		    of_node_cmp(child->name, "uart") == 0 ||
+		    of_node_cmp(child->name, "nand") == 0 ||
+		    of_node_cmp(child->name, "onenand") == 0)
 			ret = gpmc_probe_generic_child(pdev, child);
 
 		if (WARN(ret < 0, "%s: probing gpmc child %s failed\n",
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index b6a9ec0..35d2d39 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -40,6 +40,10 @@
 #include <linux/platform_data/gpmc-omap.h>
 #include <linux/gpio.h>
 #include <linux/omap-dma.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_mtd.h>
+#include <linux/of_gpio.h>
 
 #define DRIVER_NAME "omap2-onenand"
 
@@ -826,9 +830,33 @@ static void omap2_onenand_shutdown(struct platform_device *pdev)
 	memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE);
 }
 
+static int omap2_onenand_get_dt_info(struct device *dev,
+				     struct omap2_onenand *c)
+{
+	struct device_node *node = dev->of_node;
+
+	/* Chip Select number */
+	if (of_property_read_u32(node, "reg", &c->gpmc_cs) < 0) {
+		dev_err(dev, "No 'reg' property\n");
+		return -EINVAL;
+	}
+
+	/* Enable synchronous read by default */
+	c->flags = ONENAND_SYNC_READ;
+	/* Enable synchronous write only if indicated by DT */
+	if (of_property_read_bool(node, "ti,onenand-sync-rw"))
+		c->flags = ONENAND_SYNC_READWRITE;
+
+	/* TODO: DMA channel, GPIO IRQ for wait */
+	c->dma_channel = -1;
+	c->gpio_irq = -EINVAL;
+
+	return 0;
+}
+
 static int omap2_onenand_probe(struct platform_device *pdev)
 {
-	struct omap_onenand_platform_data *pdata;
+	struct omap_onenand_platform_data *pdata = NULL;
 	struct omap2_onenand *c;
 	struct onenand_chip *this;
 	int r;
@@ -836,28 +864,40 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 	struct mtd_part_parser_data ppdata = {};
 	struct device *dev = &pdev->dev;
 
-	pdata = dev_get_platdata(&pdev->dev);
-	if (pdata == NULL) {
-		dev_err(&pdev->dev, "platform data missing\n");
-		return -ENODEV;
-	}
-
 	c = devm_kzalloc(dev, sizeof(struct omap2_onenand), GFP_KERNEL);
 	if (!c)
 		return -ENOMEM;
 
-	init_completion(&c->irq_done);
-	init_completion(&c->dma_done);
-	c->pdev = pdev;
-	c->flags = pdata->flags;
-	c->gpmc_cs = pdata->cs;
-	c->gpio_irq = pdata->gpio_irq;
-	c->dma_channel = pdata->dma_channel;
+	this = &c->onenand;
+
+	if (dev->of_node) {
+		if (omap2_onenand_get_dt_info(dev, c))
+			return -EINVAL;
+
+	} else {
+		pdata = dev_get_platdata(dev);
+		if (pdata == NULL) {
+			dev_err(dev, "platform data missing\n");
+			return -ENODEV;
+		}
+
+		c->flags = pdata->flags;
+		c->gpio_irq = pdata->gpio_irq;
+		c->dma_channel = pdata->dma_channel;
+
+		if (pdata->skip_initial_unlocking)
+			this->options |= ONENAND_SKIP_INITIAL_UNLOCKING;
+	}
+
 	if (c->dma_channel < 0) {
 		/* if -1, don't use DMA */
 		c->gpio_irq = -EINVAL;
 	}
 
+	init_completion(&c->irq_done);
+	init_completion(&c->dma_done);
+	c->pdev = pdev;
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	c->onenand.base = devm_ioremap_resource(dev, res);
 	if (IS_ERR(c->onenand.base))
@@ -921,7 +961,6 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 
 	c->mtd.dev.parent = &pdev->dev;
 
-	this = &c->onenand;
 	if (c->dma_channel >= 0) {
 		this->wait = omap2_onenand_wait;
 		if (c->flags & ONENAND_IN_OMAP34XX) {
@@ -933,19 +972,20 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 		}
 	}
 
-	if (pdata->skip_initial_unlocking)
-		this->options |= ONENAND_SKIP_INITIAL_UNLOCKING;
-
 	r = onenand_scan(&c->mtd, 1);
 	if (r) {
 		dev_err(dev, "OneNAND scan failed :%d\n", r);
 		goto err_release_dma;
 	}
 
-	ppdata.of_node = pdata->of_node;
-	r = mtd_device_parse_register(&c->mtd, NULL, &ppdata,
-				      pdata ? pdata->parts : NULL,
-				      pdata ? pdata->nr_parts : 0);
+	if (dev->of_node) {
+		ppdata.of_node = dev->of_node;
+		r = mtd_device_parse_register(&c->mtd, NULL, &ppdata, NULL, 0);
+
+	} else {
+		r = mtd_device_register(&c->mtd, pdata->parts, pdata->nr_parts);
+	}
+
 	if (r)
 		goto err_release_onenand;
 
@@ -974,6 +1014,11 @@ static int omap2_onenand_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct of_device_id omap2_onenand_ids[] = {
+	{ .compatible = "ti,omap2-onenand", },
+	{},
+};
+
 static struct platform_driver omap2_onenand_driver = {
 	.probe		= omap2_onenand_probe,
 	.remove		= omap2_onenand_remove,
@@ -981,6 +1026,7 @@ static struct platform_driver omap2_onenand_driver = {
 	.driver		= {
 		.name	= DRIVER_NAME,
 		.owner  = THIS_MODULE,
+		.of_match_table = of_match_ptr(omap2_onenand_ids),
 	},
 };
 
diff --git a/include/linux/platform_data/mtd-onenand-omap2.h b/include/linux/platform_data/mtd-onenand-omap2.h
index ac1e6f3..99d8716 100644
--- a/include/linux/platform_data/mtd-onenand-omap2.h
+++ b/include/linux/platform_data/mtd-onenand-omap2.h
@@ -26,10 +26,8 @@ struct omap_onenand_platform_data {
 	u8			flags;
 	u8			skip_initial_unlocking;
 
-	/* for passing the partitions */
-	struct device_node	*of_node;
-
 	u8			regulator_can_sleep;	/* deprecated */
 	int (*onenand_setup)(void __iomem *, int *freq_ptr);	/* deprecated */
+	struct device_node	*of_node;		/* deprecated */
 };
 #endif
-- 
1.8.3.2


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

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

* [PATCH 20/36] mtd: onenand: omap: Clean up device tree support
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Move OneNAND specific device tree parsing to NAND driver.
The OneNAND device node must have its own compatible id.

Add a new property 'ti,onenand-sync-rw' to indicate
synchronous read + write support. Default mode would be
only synchronous reads.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 .../devicetree/bindings/mtd/gpmc-onenand.txt       |  4 +
 arch/arm/mach-omap2/gpmc-onenand.c                 | 14 ----
 arch/arm/mach-omap2/gpmc.c                         | 55 +++----------
 drivers/mtd/onenand/omap2.c                        | 90 ++++++++++++++++------
 include/linux/platform_data/mtd-onenand-omap2.h    |  4 +-
 5 files changed, 84 insertions(+), 83 deletions(-)

diff --git a/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt b/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt
index b752942..7fc9c13 100644
--- a/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt
+++ b/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt
@@ -9,9 +9,12 @@ Documentation/devicetree/bindings/bus/ti-gpmc.txt
 
 Required properties:
 
+ - compatible:		"ti,omap2-onenand"
  - reg:			The CS line the peripheral is connected to
  - gpmc,device-width	Width of the ONENAND device connected to the GPMC
 			in bytes. Must be 1 or 2.
+ - ti,onenand-sync-rw:	Bool. Enable synchronous Read and Write. If not
+			present, only Synchronous Read is enabled.
 
 Optional properties:
 
@@ -35,6 +38,7 @@ Example for an OMAP3430 board:
 		#size-cells = <1>;
 
 		onenand@0 {
+			compatible = "ti,omap2-onenand"
 			reg = <0 0 0>; /* CS0, offset 0 */
 			gpmc,device-width = <2>;
 
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index d09c342..37ed4f1 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -75,20 +75,6 @@ static int omap2_onenand_setup_async(struct omap_onenand_platform_data
 	struct gpmc_device_timings dev_t;
 	int ret;
 
-	if (gpmc_onenand_data->of_node) {
-		gpmc_read_settings_dt(gpmc_onenand_data->of_node,
-				      &onenand_async);
-		if (onenand_async.sync_read || onenand_async.sync_write) {
-			if (onenand_async.sync_write)
-				gpmc_onenand_data->flags |=
-					ONENAND_SYNC_READWRITE;
-			else
-				gpmc_onenand_data->flags |= ONENAND_SYNC_READ;
-			onenand_async.sync_read = false;
-			onenand_async.sync_write = false;
-		}
-	}
-
 	ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_async);
 	if (ret < 0)
 		return ret;
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 50ef1a9..ee030cd 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -39,7 +39,6 @@
 #include "common.h"
 #include "omap_device.h"
 #include "gpmc.h"
-#include "gpmc-onenand.h"
 
 #define	DEVICE_NAME		"omap-gpmc"
 
@@ -1166,43 +1165,6 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
 		of_property_read_bool(np, "gpmc,time-para-granularity");
 }
 
-#if IS_ENABLED(CONFIG_MTD_ONENAND)
-static int gpmc_probe_onenand_child(struct platform_device *pdev,
-				 struct device_node *child)
-{
-	u32 val;
-	struct omap_onenand_platform_data *gpmc_onenand_data;
-
-	if (of_property_read_u32(child, "reg", &val) < 0) {
-		dev_err(&pdev->dev, "%s has no 'reg' property\n",
-			child->full_name);
-		return -ENODEV;
-	}
-
-	gpmc_onenand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_onenand_data),
-					 GFP_KERNEL);
-	if (!gpmc_onenand_data)
-		return -ENOMEM;
-
-	gpmc_onenand_data->cs = val;
-	gpmc_onenand_data->of_node = child;
-	gpmc_onenand_data->dma_channel = -1;
-
-	if (!of_property_read_u32(child, "dma-channel", &val))
-		gpmc_onenand_data->dma_channel = val;
-
-	gpmc_onenand_init(gpmc_onenand_data);
-
-	return 0;
-}
-#else
-static int gpmc_probe_onenand_child(struct platform_device *pdev,
-				    struct device_node *child)
-{
-	return 0;
-}
-#endif
-
 /**
  * gpmc_probe_generic_child - configures the gpmc for a child device
  * @pdev:	pointer to gpmc platform device
@@ -1292,6 +1254,12 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
 		}
 
 		gpmc_s.device_nand = true;
+
+	} else if (of_node_cmp(child->name, "onenand") == 0) {
+		/* DT incorrectly sets sync modes, onenand default is async */
+		gpmc_s.sync_read = false;
+		gpmc_s.sync_write = false;
+
 	} else {
 		if (of_property_read_u32(child, "bank-width",
 					 &gpmc_s.device_width)) {
@@ -1363,12 +1331,11 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 		if (!child->name)
 			continue;
 
-		if (of_node_cmp(child->name, "onenand") == 0)
-			ret = gpmc_probe_onenand_child(pdev, child);
-		else if (of_node_cmp(child->name, "ethernet") == 0 ||
-			 of_node_cmp(child->name, "nor") == 0 ||
-			 of_node_cmp(child->name, "uart") == 0 ||
-			 of_node_cmp(child->name, "nand") == 0)
+		if (of_node_cmp(child->name, "ethernet") == 0 ||
+		    of_node_cmp(child->name, "nor") == 0 ||
+		    of_node_cmp(child->name, "uart") == 0 ||
+		    of_node_cmp(child->name, "nand") == 0 ||
+		    of_node_cmp(child->name, "onenand") == 0)
 			ret = gpmc_probe_generic_child(pdev, child);
 
 		if (WARN(ret < 0, "%s: probing gpmc child %s failed\n",
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index b6a9ec0..35d2d39 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -40,6 +40,10 @@
 #include <linux/platform_data/gpmc-omap.h>
 #include <linux/gpio.h>
 #include <linux/omap-dma.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_mtd.h>
+#include <linux/of_gpio.h>
 
 #define DRIVER_NAME "omap2-onenand"
 
@@ -826,9 +830,33 @@ static void omap2_onenand_shutdown(struct platform_device *pdev)
 	memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE);
 }
 
+static int omap2_onenand_get_dt_info(struct device *dev,
+				     struct omap2_onenand *c)
+{
+	struct device_node *node = dev->of_node;
+
+	/* Chip Select number */
+	if (of_property_read_u32(node, "reg", &c->gpmc_cs) < 0) {
+		dev_err(dev, "No 'reg' property\n");
+		return -EINVAL;
+	}
+
+	/* Enable synchronous read by default */
+	c->flags = ONENAND_SYNC_READ;
+	/* Enable synchronous write only if indicated by DT */
+	if (of_property_read_bool(node, "ti,onenand-sync-rw"))
+		c->flags = ONENAND_SYNC_READWRITE;
+
+	/* TODO: DMA channel, GPIO IRQ for wait */
+	c->dma_channel = -1;
+	c->gpio_irq = -EINVAL;
+
+	return 0;
+}
+
 static int omap2_onenand_probe(struct platform_device *pdev)
 {
-	struct omap_onenand_platform_data *pdata;
+	struct omap_onenand_platform_data *pdata = NULL;
 	struct omap2_onenand *c;
 	struct onenand_chip *this;
 	int r;
@@ -836,28 +864,40 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 	struct mtd_part_parser_data ppdata = {};
 	struct device *dev = &pdev->dev;
 
-	pdata = dev_get_platdata(&pdev->dev);
-	if (pdata == NULL) {
-		dev_err(&pdev->dev, "platform data missing\n");
-		return -ENODEV;
-	}
-
 	c = devm_kzalloc(dev, sizeof(struct omap2_onenand), GFP_KERNEL);
 	if (!c)
 		return -ENOMEM;
 
-	init_completion(&c->irq_done);
-	init_completion(&c->dma_done);
-	c->pdev = pdev;
-	c->flags = pdata->flags;
-	c->gpmc_cs = pdata->cs;
-	c->gpio_irq = pdata->gpio_irq;
-	c->dma_channel = pdata->dma_channel;
+	this = &c->onenand;
+
+	if (dev->of_node) {
+		if (omap2_onenand_get_dt_info(dev, c))
+			return -EINVAL;
+
+	} else {
+		pdata = dev_get_platdata(dev);
+		if (pdata == NULL) {
+			dev_err(dev, "platform data missing\n");
+			return -ENODEV;
+		}
+
+		c->flags = pdata->flags;
+		c->gpio_irq = pdata->gpio_irq;
+		c->dma_channel = pdata->dma_channel;
+
+		if (pdata->skip_initial_unlocking)
+			this->options |= ONENAND_SKIP_INITIAL_UNLOCKING;
+	}
+
 	if (c->dma_channel < 0) {
 		/* if -1, don't use DMA */
 		c->gpio_irq = -EINVAL;
 	}
 
+	init_completion(&c->irq_done);
+	init_completion(&c->dma_done);
+	c->pdev = pdev;
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	c->onenand.base = devm_ioremap_resource(dev, res);
 	if (IS_ERR(c->onenand.base))
@@ -921,7 +961,6 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 
 	c->mtd.dev.parent = &pdev->dev;
 
-	this = &c->onenand;
 	if (c->dma_channel >= 0) {
 		this->wait = omap2_onenand_wait;
 		if (c->flags & ONENAND_IN_OMAP34XX) {
@@ -933,19 +972,20 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 		}
 	}
 
-	if (pdata->skip_initial_unlocking)
-		this->options |= ONENAND_SKIP_INITIAL_UNLOCKING;
-
 	r = onenand_scan(&c->mtd, 1);
 	if (r) {
 		dev_err(dev, "OneNAND scan failed :%d\n", r);
 		goto err_release_dma;
 	}
 
-	ppdata.of_node = pdata->of_node;
-	r = mtd_device_parse_register(&c->mtd, NULL, &ppdata,
-				      pdata ? pdata->parts : NULL,
-				      pdata ? pdata->nr_parts : 0);
+	if (dev->of_node) {
+		ppdata.of_node = dev->of_node;
+		r = mtd_device_parse_register(&c->mtd, NULL, &ppdata, NULL, 0);
+
+	} else {
+		r = mtd_device_register(&c->mtd, pdata->parts, pdata->nr_parts);
+	}
+
 	if (r)
 		goto err_release_onenand;
 
@@ -974,6 +1014,11 @@ static int omap2_onenand_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct of_device_id omap2_onenand_ids[] = {
+	{ .compatible = "ti,omap2-onenand", },
+	{},
+};
+
 static struct platform_driver omap2_onenand_driver = {
 	.probe		= omap2_onenand_probe,
 	.remove		= omap2_onenand_remove,
@@ -981,6 +1026,7 @@ static struct platform_driver omap2_onenand_driver = {
 	.driver		= {
 		.name	= DRIVER_NAME,
 		.owner  = THIS_MODULE,
+		.of_match_table = of_match_ptr(omap2_onenand_ids),
 	},
 };
 
diff --git a/include/linux/platform_data/mtd-onenand-omap2.h b/include/linux/platform_data/mtd-onenand-omap2.h
index ac1e6f3..99d8716 100644
--- a/include/linux/platform_data/mtd-onenand-omap2.h
+++ b/include/linux/platform_data/mtd-onenand-omap2.h
@@ -26,10 +26,8 @@ struct omap_onenand_platform_data {
 	u8			flags;
 	u8			skip_initial_unlocking;
 
-	/* for passing the partitions */
-	struct device_node	*of_node;
-
 	u8			regulator_can_sleep;	/* deprecated */
 	int (*onenand_setup)(void __iomem *, int *freq_ptr);	/* deprecated */
+	struct device_node	*of_node;		/* deprecated */
 };
 #endif
-- 
1.8.3.2

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

* [PATCH 21/36] ARM: dts: OMAP2+: Fix OneNAND device nodes
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Add compatible id, fix chip select partition size and
I/O space size. OneNAND devices just need 128KB for I/O
and the minimum possible chips select partition can be
16MB.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/boot/dts/omap2420-n8x0-common.dtsi | 5 +++--
 arch/arm/boot/dts/omap3-n900.dts            | 6 ++++--
 arch/arm/boot/dts/omap3-n950-n9.dtsi        | 6 ++++--
 arch/arm/boot/dts/omap3430-sdp.dts          | 8 +++++---
 4 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/arch/arm/boot/dts/omap2420-n8x0-common.dtsi b/arch/arm/boot/dts/omap2420-n8x0-common.dtsi
index 89608b2..14a67fb3 100644
--- a/arch/arm/boot/dts/omap2420-n8x0-common.dtsi
+++ b/arch/arm/boot/dts/omap2420-n8x0-common.dtsi
@@ -34,14 +34,15 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x04000000 0x10000000>;
+	ranges = <0 0 0x04000000 0x1000000>;	/* CS0 space, 16MB min. */
 
 	/* gpio-irq for dma: 26 */
 
 	onenand@0,0 {
+		compatible = "ti,omap2-onenand";
 		#address-cells = <1>;
 		#size-cells = <1>;
-		reg = <0 0 0x10000000>;
+		reg = <0 0 0x20000>;	/* OneNAND I/O 128K */
 
 		gpmc,sync-read;
 		gpmc,burst-length = <16>;
diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts
index 1a57b61..0c5af81 100644
--- a/arch/arm/boot/dts/omap3-n900.dts
+++ b/arch/arm/boot/dts/omap3-n900.dts
@@ -501,14 +501,16 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x04000000 0x10000000>; /* 256MB */
+	ranges = <0 0 0x04000000 0x1000000>;	/* CS0 space, 16MB min. */
 
 	/* gpio-irq for dma: 65 */
 
 	onenand@0,0 {
+		compatible = "ti,omap2-onenand";
 		#address-cells = <1>;
 		#size-cells = <1>;
-		reg = <0 0 0x10000000>;
+		reg = <0 0 0x20000>;	/* OneNAND I/O 128K */
+		ti,onenand-sync-rw;
 
 		gpmc,sync-read;
 		gpmc,sync-write;
diff --git a/arch/arm/boot/dts/omap3-n950-n9.dtsi b/arch/arm/boot/dts/omap3-n950-n9.dtsi
index 5c26c18..9dcb367 100644
--- a/arch/arm/boot/dts/omap3-n950-n9.dtsi
+++ b/arch/arm/boot/dts/omap3-n950-n9.dtsi
@@ -101,12 +101,14 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x04000000 0x20000000>;
+	ranges = <0 0 0x04000000 0x1000000>;	/* CS0 space, 16MB min. */
 
 	onenand@0,0 {
+		compatible = "ti,omap2-onenand";
 		#address-cells = <1>;
 		#size-cells = <1>;
-		reg = <0 0 0x20000000>;
+		reg = <0 0 0x20000>;	/* OneNAND I/O 128K */
+		ti,onenand-sync-rw;
 
 		gpmc,sync-read;
 		gpmc,sync-write;
diff --git a/arch/arm/boot/dts/omap3430-sdp.dts b/arch/arm/boot/dts/omap3430-sdp.dts
index bf5f8b9..d6fe226 100644
--- a/arch/arm/boot/dts/omap3430-sdp.dts
+++ b/arch/arm/boot/dts/omap3430-sdp.dts
@@ -52,7 +52,7 @@
 &gpmc {
 	ranges = <0 0 0x10000000 0x08000000>,
 		 <1 0 0x28000000 0x08000000>,
-		 <2 0 0x20000000 0x10000000>,
+		 <2 0 0x20000000 0x1000000>,	/* CS2, 16MB min. */
 		 <255 0 0x6e000000 0x02d4>;	/* GPMC reg */
 
 	nor@0,0 {
@@ -151,10 +151,11 @@
 	};
 
 	onenand@2,0 {
-		linux,mtd-name= "samsung,kfm2g16q2m-deb8";
+		compatible = "ti,omap2-onenand";
 		#address-cells = <1>;
 		#size-cells = <1>;
-		reg = <2 0 0x10000000>;
+		reg = <2 0 0x20000>;	/* OneNAND I/O 128K */
+		ti,onenand-sync-rw;
 
 		gpmc,device-width = <2>;
 		gpmc,mux-add-data = <2>;
@@ -173,6 +174,7 @@
 		gpmc,access-ns = <78>;
 		gpmc,wr-data-mux-bus-ns = <30>;
 
+		linux,mtd-name= "samsung,kfm2g16q2m-deb8";
 		partition@0 {
 			label = "xloader-onenand";
 			reg = <0 0x80000>;
-- 
1.8.3.2


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

* [PATCH 21/36] ARM: dts: OMAP2+: Fix OneNAND device nodes
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Add compatible id, fix chip select partition size and
I/O space size. OneNAND devices just need 128KB for I/O
and the minimum possible chips select partition can be
16MB.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/boot/dts/omap2420-n8x0-common.dtsi | 5 +++--
 arch/arm/boot/dts/omap3-n900.dts            | 6 ++++--
 arch/arm/boot/dts/omap3-n950-n9.dtsi        | 6 ++++--
 arch/arm/boot/dts/omap3430-sdp.dts          | 8 +++++---
 4 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/arch/arm/boot/dts/omap2420-n8x0-common.dtsi b/arch/arm/boot/dts/omap2420-n8x0-common.dtsi
index 89608b2..14a67fb3 100644
--- a/arch/arm/boot/dts/omap2420-n8x0-common.dtsi
+++ b/arch/arm/boot/dts/omap2420-n8x0-common.dtsi
@@ -34,14 +34,15 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x04000000 0x10000000>;
+	ranges = <0 0 0x04000000 0x1000000>;	/* CS0 space, 16MB min. */
 
 	/* gpio-irq for dma: 26 */
 
 	onenand@0,0 {
+		compatible = "ti,omap2-onenand";
 		#address-cells = <1>;
 		#size-cells = <1>;
-		reg = <0 0 0x10000000>;
+		reg = <0 0 0x20000>;	/* OneNAND I/O 128K */
 
 		gpmc,sync-read;
 		gpmc,burst-length = <16>;
diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts
index 1a57b61..0c5af81 100644
--- a/arch/arm/boot/dts/omap3-n900.dts
+++ b/arch/arm/boot/dts/omap3-n900.dts
@@ -501,14 +501,16 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x04000000 0x10000000>; /* 256MB */
+	ranges = <0 0 0x04000000 0x1000000>;	/* CS0 space, 16MB min. */
 
 	/* gpio-irq for dma: 65 */
 
 	onenand@0,0 {
+		compatible = "ti,omap2-onenand";
 		#address-cells = <1>;
 		#size-cells = <1>;
-		reg = <0 0 0x10000000>;
+		reg = <0 0 0x20000>;	/* OneNAND I/O 128K */
+		ti,onenand-sync-rw;
 
 		gpmc,sync-read;
 		gpmc,sync-write;
diff --git a/arch/arm/boot/dts/omap3-n950-n9.dtsi b/arch/arm/boot/dts/omap3-n950-n9.dtsi
index 5c26c18..9dcb367 100644
--- a/arch/arm/boot/dts/omap3-n950-n9.dtsi
+++ b/arch/arm/boot/dts/omap3-n950-n9.dtsi
@@ -101,12 +101,14 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x04000000 0x20000000>;
+	ranges = <0 0 0x04000000 0x1000000>;	/* CS0 space, 16MB min. */
 
 	onenand@0,0 {
+		compatible = "ti,omap2-onenand";
 		#address-cells = <1>;
 		#size-cells = <1>;
-		reg = <0 0 0x20000000>;
+		reg = <0 0 0x20000>;	/* OneNAND I/O 128K */
+		ti,onenand-sync-rw;
 
 		gpmc,sync-read;
 		gpmc,sync-write;
diff --git a/arch/arm/boot/dts/omap3430-sdp.dts b/arch/arm/boot/dts/omap3430-sdp.dts
index bf5f8b9..d6fe226 100644
--- a/arch/arm/boot/dts/omap3430-sdp.dts
+++ b/arch/arm/boot/dts/omap3430-sdp.dts
@@ -52,7 +52,7 @@
 &gpmc {
 	ranges = <0 0 0x10000000 0x08000000>,
 		 <1 0 0x28000000 0x08000000>,
-		 <2 0 0x20000000 0x10000000>,
+		 <2 0 0x20000000 0x1000000>,	/* CS2, 16MB min. */
 		 <255 0 0x6e000000 0x02d4>;	/* GPMC reg */
 
 	nor@0,0 {
@@ -151,10 +151,11 @@
 	};
 
 	onenand@2,0 {
-		linux,mtd-name= "samsung,kfm2g16q2m-deb8";
+		compatible = "ti,omap2-onenand";
 		#address-cells = <1>;
 		#size-cells = <1>;
-		reg = <2 0 0x10000000>;
+		reg = <2 0 0x20000>;	/* OneNAND I/O 128K */
+		ti,onenand-sync-rw;
 
 		gpmc,device-width = <2>;
 		gpmc,mux-add-data = <2>;
@@ -173,6 +174,7 @@
 		gpmc,access-ns = <78>;
 		gpmc,wr-data-mux-bus-ns = <30>;
 
+		linux,mtd-name= "samsung,kfm2g16q2m-deb8";
 		partition@0 {
 			label = "xloader-onenand";
 			reg = <0 0x80000>;
-- 
1.8.3.2


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

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

* [PATCH 21/36] ARM: dts: OMAP2+: Fix OneNAND device nodes
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Add compatible id, fix chip select partition size and
I/O space size. OneNAND devices just need 128KB for I/O
and the minimum possible chips select partition can be
16MB.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/boot/dts/omap2420-n8x0-common.dtsi | 5 +++--
 arch/arm/boot/dts/omap3-n900.dts            | 6 ++++--
 arch/arm/boot/dts/omap3-n950-n9.dtsi        | 6 ++++--
 arch/arm/boot/dts/omap3430-sdp.dts          | 8 +++++---
 4 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/arch/arm/boot/dts/omap2420-n8x0-common.dtsi b/arch/arm/boot/dts/omap2420-n8x0-common.dtsi
index 89608b2..14a67fb3 100644
--- a/arch/arm/boot/dts/omap2420-n8x0-common.dtsi
+++ b/arch/arm/boot/dts/omap2420-n8x0-common.dtsi
@@ -34,14 +34,15 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x04000000 0x10000000>;
+	ranges = <0 0 0x04000000 0x1000000>;	/* CS0 space, 16MB min. */
 
 	/* gpio-irq for dma: 26 */
 
 	onenand@0,0 {
+		compatible = "ti,omap2-onenand";
 		#address-cells = <1>;
 		#size-cells = <1>;
-		reg = <0 0 0x10000000>;
+		reg = <0 0 0x20000>;	/* OneNAND I/O 128K */
 
 		gpmc,sync-read;
 		gpmc,burst-length = <16>;
diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts
index 1a57b61..0c5af81 100644
--- a/arch/arm/boot/dts/omap3-n900.dts
+++ b/arch/arm/boot/dts/omap3-n900.dts
@@ -501,14 +501,16 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x04000000 0x10000000>; /* 256MB */
+	ranges = <0 0 0x04000000 0x1000000>;	/* CS0 space, 16MB min. */
 
 	/* gpio-irq for dma: 65 */
 
 	onenand@0,0 {
+		compatible = "ti,omap2-onenand";
 		#address-cells = <1>;
 		#size-cells = <1>;
-		reg = <0 0 0x10000000>;
+		reg = <0 0 0x20000>;	/* OneNAND I/O 128K */
+		ti,onenand-sync-rw;
 
 		gpmc,sync-read;
 		gpmc,sync-write;
diff --git a/arch/arm/boot/dts/omap3-n950-n9.dtsi b/arch/arm/boot/dts/omap3-n950-n9.dtsi
index 5c26c18..9dcb367 100644
--- a/arch/arm/boot/dts/omap3-n950-n9.dtsi
+++ b/arch/arm/boot/dts/omap3-n950-n9.dtsi
@@ -101,12 +101,14 @@
 };
 
 &gpmc {
-	ranges = <0 0 0x04000000 0x20000000>;
+	ranges = <0 0 0x04000000 0x1000000>;	/* CS0 space, 16MB min. */
 
 	onenand@0,0 {
+		compatible = "ti,omap2-onenand";
 		#address-cells = <1>;
 		#size-cells = <1>;
-		reg = <0 0 0x20000000>;
+		reg = <0 0 0x20000>;	/* OneNAND I/O 128K */
+		ti,onenand-sync-rw;
 
 		gpmc,sync-read;
 		gpmc,sync-write;
diff --git a/arch/arm/boot/dts/omap3430-sdp.dts b/arch/arm/boot/dts/omap3430-sdp.dts
index bf5f8b9..d6fe226 100644
--- a/arch/arm/boot/dts/omap3430-sdp.dts
+++ b/arch/arm/boot/dts/omap3430-sdp.dts
@@ -52,7 +52,7 @@
 &gpmc {
 	ranges = <0 0 0x10000000 0x08000000>,
 		 <1 0 0x28000000 0x08000000>,
-		 <2 0 0x20000000 0x10000000>,
+		 <2 0 0x20000000 0x1000000>,	/* CS2, 16MB min. */
 		 <255 0 0x6e000000 0x02d4>;	/* GPMC reg */
 
 	nor@0,0 {
@@ -151,10 +151,11 @@
 	};
 
 	onenand@2,0 {
-		linux,mtd-name= "samsung,kfm2g16q2m-deb8";
+		compatible = "ti,omap2-onenand";
 		#address-cells = <1>;
 		#size-cells = <1>;
-		reg = <2 0 0x10000000>;
+		reg = <2 0 0x20000>;	/* OneNAND I/O 128K */
+		ti,onenand-sync-rw;
 
 		gpmc,device-width = <2>;
 		gpmc,mux-add-data = <2>;
@@ -173,6 +174,7 @@
 		gpmc,access-ns = <78>;
 		gpmc,wr-data-mux-bus-ns = <30>;
 
+		linux,mtd-name= "samsung,kfm2g16q2m-deb8";
 		partition@0 {
 			label = "xloader-onenand";
 			reg = <0 0x80000>;
-- 
1.8.3.2

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

* [PATCH 22/36] ARM: OMAP2+: gmpc: add gpmc_generic_init()
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

This function populates platform data for the specified Chip Select.
It should be called by board init code.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/gpmc.h |  6 ++++
 2 files changed, 85 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index ee030cd..d3a64ed 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -30,6 +30,7 @@
 #include <linux/of_mtd.h>
 #include <linux/of_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/slab.h>
 
 #include <linux/platform_data/mtd-nand-omap2.h>
 
@@ -108,6 +109,8 @@
 
 #define GPMC_NR_WAITPINS		4
 
+static struct gpmc_omap_platform_data gpmc_pdata;
+
 /* Structure to save gpmc cs context */
 struct gpmc_cs_config {
 	u32 config1;
@@ -1510,6 +1513,82 @@ static int __init omap_gpmc_init(void)
 omap_postcore_initcall(omap_gpmc_init);
 
 /**
+ * gpmc_generic_init - Initialize platform data for a Chip Select
+ *
+ * @cs		chip select number
+ * @is_nand	true if device is NAND flash.
+ * @settings	GPMC settings
+ * @device_timings	device timings for device on this CS
+ * @gpmc_timings	GPMC timings
+ * @pdev	platform device for the device on this CS
+ * @pdata_size	platform data size for the platform device
+ */
+int gpmc_generic_init(int cs, bool is_nand,
+		      struct gpmc_settings *settings,
+		      struct gpmc_device_timings *device_timings,
+		      struct gpmc_timings *gpmc_timings,
+		      struct platform_device *pdev, unsigned pdata_size)
+{
+	struct gpmc_settings *gpmc_s = NULL;
+	struct gpmc_device_timings *gpmc_dev_t = NULL;
+	struct gpmc_timings *gpmc_t;
+
+	if (cs >= GPMC_CS_NUM) {
+		pr_err("%s: Invalid cs specified. Max CS = %d\n",
+		       __func__, GPMC_CS_NUM);
+		return -EINVAL;
+	}
+
+	if (gpmc_pdata.cs[cs].valid) {
+		pr_err("%s: cs %d already requested, ignoring new request\n",
+		       __func__, cs);
+		return -EINVAL;
+	}
+
+	if (settings) {
+		gpmc_s = kmemdup(settings, sizeof(*settings), GFP_KERNEL);
+		if (!gpmc_s)
+			return -ENOMEM;
+
+		gpmc_pdata.cs[cs].settings = gpmc_s;
+	}
+
+	if (device_timings) {
+		gpmc_dev_t = kmemdup(device_timings, sizeof(*device_timings),
+				     GFP_KERNEL);
+		if (!gpmc_dev_t)
+			goto dev_t_fail;
+
+		gpmc_pdata.cs[cs].device_timings = gpmc_dev_t;
+	}
+
+	if (gpmc_timings) {
+		gpmc_t = kmemdup(gpmc_timings, sizeof(*gpmc_timings),
+				 GFP_KERNEL);
+		if (!gpmc_t)
+			goto gpmc_t_fail;
+
+		gpmc_pdata.cs[cs].gpmc_timings = gpmc_t;
+	}
+
+	gpmc_pdata.cs[cs].is_nand = is_nand;
+	gpmc_pdata.cs[cs].pdev = pdev;
+	gpmc_pdata.cs[cs].pdata_size = pdata_size;
+	gpmc_pdata.cs[cs].valid = true;
+
+	return 0;
+
+gpmc_t_fail:
+	if (device_timings)
+		kfree(gpmc_dev_t);
+dev_t_fail:
+	if (settings)
+		kfree(gpmc_s);
+
+	return -ENOMEM;
+}
+
+/**
  * omap_gpmc_retime - Reconfigre GPMC timings for the device
  *
  * @cs		Chip select number
diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h
index 6204913..301bc66 100644
--- a/arch/arm/mach-omap2/gpmc.h
+++ b/arch/arm/mach-omap2/gpmc.h
@@ -77,5 +77,11 @@ extern void omap3_gpmc_save_context(void);
 extern void omap3_gpmc_restore_context(void);
 extern void gpmc_read_settings_dt(struct device_node *np,
 				  struct gpmc_settings *p);
+int gpmc_generic_init(int cs, bool is_nand,
+		      struct gpmc_settings *settings,
+		      struct gpmc_device_timings *device_timings,
+		      struct gpmc_timings *gpmc_timings,
+		      struct platform_device *pdev,
+		      unsigned pdata_size);
 
 #endif
-- 
1.8.3.2


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

* [PATCH 22/36] ARM: OMAP2+: gmpc: add gpmc_generic_init()
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

This function populates platform data for the specified Chip Select.
It should be called by board init code.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/gpmc.h |  6 ++++
 2 files changed, 85 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index ee030cd..d3a64ed 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -30,6 +30,7 @@
 #include <linux/of_mtd.h>
 #include <linux/of_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/slab.h>
 
 #include <linux/platform_data/mtd-nand-omap2.h>
 
@@ -108,6 +109,8 @@
 
 #define GPMC_NR_WAITPINS		4
 
+static struct gpmc_omap_platform_data gpmc_pdata;
+
 /* Structure to save gpmc cs context */
 struct gpmc_cs_config {
 	u32 config1;
@@ -1510,6 +1513,82 @@ static int __init omap_gpmc_init(void)
 omap_postcore_initcall(omap_gpmc_init);
 
 /**
+ * gpmc_generic_init - Initialize platform data for a Chip Select
+ *
+ * @cs		chip select number
+ * @is_nand	true if device is NAND flash.
+ * @settings	GPMC settings
+ * @device_timings	device timings for device on this CS
+ * @gpmc_timings	GPMC timings
+ * @pdev	platform device for the device on this CS
+ * @pdata_size	platform data size for the platform device
+ */
+int gpmc_generic_init(int cs, bool is_nand,
+		      struct gpmc_settings *settings,
+		      struct gpmc_device_timings *device_timings,
+		      struct gpmc_timings *gpmc_timings,
+		      struct platform_device *pdev, unsigned pdata_size)
+{
+	struct gpmc_settings *gpmc_s = NULL;
+	struct gpmc_device_timings *gpmc_dev_t = NULL;
+	struct gpmc_timings *gpmc_t;
+
+	if (cs >= GPMC_CS_NUM) {
+		pr_err("%s: Invalid cs specified. Max CS = %d\n",
+		       __func__, GPMC_CS_NUM);
+		return -EINVAL;
+	}
+
+	if (gpmc_pdata.cs[cs].valid) {
+		pr_err("%s: cs %d already requested, ignoring new request\n",
+		       __func__, cs);
+		return -EINVAL;
+	}
+
+	if (settings) {
+		gpmc_s = kmemdup(settings, sizeof(*settings), GFP_KERNEL);
+		if (!gpmc_s)
+			return -ENOMEM;
+
+		gpmc_pdata.cs[cs].settings = gpmc_s;
+	}
+
+	if (device_timings) {
+		gpmc_dev_t = kmemdup(device_timings, sizeof(*device_timings),
+				     GFP_KERNEL);
+		if (!gpmc_dev_t)
+			goto dev_t_fail;
+
+		gpmc_pdata.cs[cs].device_timings = gpmc_dev_t;
+	}
+
+	if (gpmc_timings) {
+		gpmc_t = kmemdup(gpmc_timings, sizeof(*gpmc_timings),
+				 GFP_KERNEL);
+		if (!gpmc_t)
+			goto gpmc_t_fail;
+
+		gpmc_pdata.cs[cs].gpmc_timings = gpmc_t;
+	}
+
+	gpmc_pdata.cs[cs].is_nand = is_nand;
+	gpmc_pdata.cs[cs].pdev = pdev;
+	gpmc_pdata.cs[cs].pdata_size = pdata_size;
+	gpmc_pdata.cs[cs].valid = true;
+
+	return 0;
+
+gpmc_t_fail:
+	if (device_timings)
+		kfree(gpmc_dev_t);
+dev_t_fail:
+	if (settings)
+		kfree(gpmc_s);
+
+	return -ENOMEM;
+}
+
+/**
  * omap_gpmc_retime - Reconfigre GPMC timings for the device
  *
  * @cs		Chip select number
diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h
index 6204913..301bc66 100644
--- a/arch/arm/mach-omap2/gpmc.h
+++ b/arch/arm/mach-omap2/gpmc.h
@@ -77,5 +77,11 @@ extern void omap3_gpmc_save_context(void);
 extern void omap3_gpmc_restore_context(void);
 extern void gpmc_read_settings_dt(struct device_node *np,
 				  struct gpmc_settings *p);
+int gpmc_generic_init(int cs, bool is_nand,
+		      struct gpmc_settings *settings,
+		      struct gpmc_device_timings *device_timings,
+		      struct gpmc_timings *gpmc_timings,
+		      struct platform_device *pdev,
+		      unsigned pdata_size);
 
 #endif
-- 
1.8.3.2


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

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

* [PATCH 22/36] ARM: OMAP2+: gmpc: add gpmc_generic_init()
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

This function populates platform data for the specified Chip Select.
It should be called by board init code.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/gpmc.h |  6 ++++
 2 files changed, 85 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index ee030cd..d3a64ed 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -30,6 +30,7 @@
 #include <linux/of_mtd.h>
 #include <linux/of_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/slab.h>
 
 #include <linux/platform_data/mtd-nand-omap2.h>
 
@@ -108,6 +109,8 @@
 
 #define GPMC_NR_WAITPINS		4
 
+static struct gpmc_omap_platform_data gpmc_pdata;
+
 /* Structure to save gpmc cs context */
 struct gpmc_cs_config {
 	u32 config1;
@@ -1510,6 +1513,82 @@ static int __init omap_gpmc_init(void)
 omap_postcore_initcall(omap_gpmc_init);
 
 /**
+ * gpmc_generic_init - Initialize platform data for a Chip Select
+ *
+ * @cs		chip select number
+ * @is_nand	true if device is NAND flash.
+ * @settings	GPMC settings
+ * @device_timings	device timings for device on this CS
+ * @gpmc_timings	GPMC timings
+ * @pdev	platform device for the device on this CS
+ * @pdata_size	platform data size for the platform device
+ */
+int gpmc_generic_init(int cs, bool is_nand,
+		      struct gpmc_settings *settings,
+		      struct gpmc_device_timings *device_timings,
+		      struct gpmc_timings *gpmc_timings,
+		      struct platform_device *pdev, unsigned pdata_size)
+{
+	struct gpmc_settings *gpmc_s = NULL;
+	struct gpmc_device_timings *gpmc_dev_t = NULL;
+	struct gpmc_timings *gpmc_t;
+
+	if (cs >= GPMC_CS_NUM) {
+		pr_err("%s: Invalid cs specified. Max CS = %d\n",
+		       __func__, GPMC_CS_NUM);
+		return -EINVAL;
+	}
+
+	if (gpmc_pdata.cs[cs].valid) {
+		pr_err("%s: cs %d already requested, ignoring new request\n",
+		       __func__, cs);
+		return -EINVAL;
+	}
+
+	if (settings) {
+		gpmc_s = kmemdup(settings, sizeof(*settings), GFP_KERNEL);
+		if (!gpmc_s)
+			return -ENOMEM;
+
+		gpmc_pdata.cs[cs].settings = gpmc_s;
+	}
+
+	if (device_timings) {
+		gpmc_dev_t = kmemdup(device_timings, sizeof(*device_timings),
+				     GFP_KERNEL);
+		if (!gpmc_dev_t)
+			goto dev_t_fail;
+
+		gpmc_pdata.cs[cs].device_timings = gpmc_dev_t;
+	}
+
+	if (gpmc_timings) {
+		gpmc_t = kmemdup(gpmc_timings, sizeof(*gpmc_timings),
+				 GFP_KERNEL);
+		if (!gpmc_t)
+			goto gpmc_t_fail;
+
+		gpmc_pdata.cs[cs].gpmc_timings = gpmc_t;
+	}
+
+	gpmc_pdata.cs[cs].is_nand = is_nand;
+	gpmc_pdata.cs[cs].pdev = pdev;
+	gpmc_pdata.cs[cs].pdata_size = pdata_size;
+	gpmc_pdata.cs[cs].valid = true;
+
+	return 0;
+
+gpmc_t_fail:
+	if (device_timings)
+		kfree(gpmc_dev_t);
+dev_t_fail:
+	if (settings)
+		kfree(gpmc_s);
+
+	return -ENOMEM;
+}
+
+/**
  * omap_gpmc_retime - Reconfigre GPMC timings for the device
  *
  * @cs		Chip select number
diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h
index 6204913..301bc66 100644
--- a/arch/arm/mach-omap2/gpmc.h
+++ b/arch/arm/mach-omap2/gpmc.h
@@ -77,5 +77,11 @@ extern void omap3_gpmc_save_context(void);
 extern void omap3_gpmc_restore_context(void);
 extern void gpmc_read_settings_dt(struct device_node *np,
 				  struct gpmc_settings *p);
+int gpmc_generic_init(int cs, bool is_nand,
+		      struct gpmc_settings *settings,
+		      struct gpmc_device_timings *device_timings,
+		      struct gpmc_timings *gpmc_timings,
+		      struct platform_device *pdev,
+		      unsigned pdata_size);
 
 #endif
-- 
1.8.3.2

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

* [PATCH 23/36] ARM: OMAP2+: gpmc: use platform data to configure CS space and poplulate device
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Add gpmc_probe_legacy() that will be called for non DT boots. This function
will use platform data to setup each chip select and populate the child
platform device for each of the chip selects.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.c | 129 ++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 111 insertions(+), 18 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index d3a64ed..c26ba3f 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1302,11 +1302,6 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 {
 	int ret;
 	struct device_node *child;
-	const struct of_device_id *of_id =
-		of_match_device(gpmc_dt_ids, &pdev->dev);
-
-	if (!of_id)
-		return 0;
 
 	ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-cs",
 				   &gpmc_cs_num);
@@ -1355,11 +1350,106 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 }
 #endif
 
+static void gpmc_probe_legacy(struct platform_device *pdev)
+{
+	int i, rc;
+	struct device *dev = &pdev->dev;
+	struct gpmc_omap_platform_data *gpmc_pdata;
+
+	gpmc_pdata = dev->platform_data;
+	gpmc_cs_num = GPMC_CS_NUM;
+	gpmc_nr_waitpins = GPMC_NR_WAITPINS;
+
+	if (!gpmc_pdata)
+		return;
+
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		struct resource *mem_res;
+		unsigned long cs_base;
+		resource_size_t size;
+		struct gpmc_timings gpmc_timings;
+		struct gpmc_omap_cs_data *cs;
+
+		cs = &gpmc_pdata->cs[i];
+		if (!cs->valid)
+			continue;
+
+		/*
+		 * Request a CS space. Use size from
+		 * platform device's MEM resource
+		 */
+		if (!cs->pdev)
+			goto skip_mem;
+
+		mem_res = cs->pdev->resource;
+		if (cs->pdev->num_resources < 1 ||
+		    resource_type(mem_res) != IORESOURCE_MEM) {
+			dev_err(dev, "Invalid IOMEM resource for CS %d\n", i);
+			continue;
+		}
+
+		size = mem_res->end - mem_res->start + 1;
+		if (gpmc_cs_request(i, size, &cs_base)) {
+			dev_err(dev, "Couldn't request resource for CS %d\n",
+				i);
+			continue;
+		}
+
+		mem_res->start = cs_base;
+		mem_res->end = cs_base + size - 1;
+
+		/* FIXME: When do we need to call gpmc_cs_remap()? */
+skip_mem:
+
+		if (cs->settings) {
+			if (gpmc_cs_program_settings(i, cs->settings)) {
+				dev_err(dev,
+					"Couldn't program settings for CS %d\n",
+					i);
+				continue;
+			}
+		}
+
+		/* give device_timings priority over gpmc_timings */
+		if (cs->device_timings) {
+			gpmc_calc_timings(&gpmc_timings, cs->settings,
+					  cs->device_timings);
+
+			if (gpmc_cs_set_timings(i, &gpmc_timings)) {
+				dev_err(dev,
+					"Couldn't program timings for CS %d\n",
+					i);
+				continue;
+			}
+		} else if (cs->gpmc_timings) {
+			if (gpmc_cs_set_timings(i, cs->gpmc_timings)) {
+				dev_err(dev,
+					"Couldn't program timings for CS %d\n",
+					i);
+				continue;
+			}
+		}
+
+		if (!cs->pdev)
+			continue;
+
+		cs->pdev->dev.parent = dev;
+		rc = platform_device_register(cs->pdev);
+		if (rc < 0) {
+			dev_err(dev,
+				"Failed to register device %s on CS %d\n",
+				cs->pdev->name, i);
+			continue;
+		}
+	}
+}
+
 static int gpmc_probe(struct platform_device *pdev)
 {
 	int rc;
 	u32 l;
 	struct resource *res;
+	struct device *dev = &pdev->dev;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (res == NULL)
@@ -1390,7 +1480,7 @@ static int gpmc_probe(struct platform_device *pdev)
 	pm_runtime_enable(&pdev->dev);
 	pm_runtime_get_sync(&pdev->dev);
 
-	gpmc_dev = &pdev->dev;
+	gpmc_dev = dev;
 
 	l = gpmc_read_reg(GPMC_REVISION);
 
@@ -1410,7 +1500,7 @@ static int gpmc_probe(struct platform_device *pdev)
 		gpmc_capability = GPMC_HAS_WR_ACCESS | GPMC_HAS_WR_DATA_MUX_BUS;
 	if (GPMC_REVISION_MAJOR(l) > 0x5)
 		gpmc_capability |= GPMC_HAS_MUX_AAD;
-	dev_info(gpmc_dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l),
+	dev_info(dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l),
 		 GPMC_REVISION_MINOR(l));
 
 	gpmc_mem_init();
@@ -1418,20 +1508,23 @@ static int gpmc_probe(struct platform_device *pdev)
 	/* Now the GPMC is initialised, unreserve the chip-selects */
 	gpmc_cs_map = 0;
 
-	if (!pdev->dev.of_node) {
-		gpmc_cs_num	 = GPMC_CS_NUM;
-		gpmc_nr_waitpins = GPMC_NR_WAITPINS;
-	}
-
-	rc = gpmc_probe_dt(pdev);
-	if (rc < 0) {
-		pm_runtime_put_sync(&pdev->dev);
-		clk_put(gpmc_l3_clk);
-		dev_err(gpmc_dev, "failed to probe DT parameters\n");
-		return rc;
+	if (dev->of_node) {
+		rc = gpmc_probe_dt(pdev);
+		if (rc) {
+			dev_err(dev, "gpmc_probe_dt() failed\n");
+			goto error;
+		}
+	} else {
+		/* Legacy probing based on platform data */
+		gpmc_probe_legacy(pdev);
 	}
 
 	return 0;
+
+error:
+	pm_runtime_put_sync(dev);
+	clk_put(gpmc_l3_clk);
+	return rc;
 }
 
 static int gpmc_remove(struct platform_device *pdev)
-- 
1.8.3.2


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

* [PATCH 23/36] ARM: OMAP2+: gpmc: use platform data to configure CS space and poplulate device
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Add gpmc_probe_legacy() that will be called for non DT boots. This function
will use platform data to setup each chip select and populate the child
platform device for each of the chip selects.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.c | 129 ++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 111 insertions(+), 18 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index d3a64ed..c26ba3f 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1302,11 +1302,6 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 {
 	int ret;
 	struct device_node *child;
-	const struct of_device_id *of_id =
-		of_match_device(gpmc_dt_ids, &pdev->dev);
-
-	if (!of_id)
-		return 0;
 
 	ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-cs",
 				   &gpmc_cs_num);
@@ -1355,11 +1350,106 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 }
 #endif
 
+static void gpmc_probe_legacy(struct platform_device *pdev)
+{
+	int i, rc;
+	struct device *dev = &pdev->dev;
+	struct gpmc_omap_platform_data *gpmc_pdata;
+
+	gpmc_pdata = dev->platform_data;
+	gpmc_cs_num = GPMC_CS_NUM;
+	gpmc_nr_waitpins = GPMC_NR_WAITPINS;
+
+	if (!gpmc_pdata)
+		return;
+
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		struct resource *mem_res;
+		unsigned long cs_base;
+		resource_size_t size;
+		struct gpmc_timings gpmc_timings;
+		struct gpmc_omap_cs_data *cs;
+
+		cs = &gpmc_pdata->cs[i];
+		if (!cs->valid)
+			continue;
+
+		/*
+		 * Request a CS space. Use size from
+		 * platform device's MEM resource
+		 */
+		if (!cs->pdev)
+			goto skip_mem;
+
+		mem_res = cs->pdev->resource;
+		if (cs->pdev->num_resources < 1 ||
+		    resource_type(mem_res) != IORESOURCE_MEM) {
+			dev_err(dev, "Invalid IOMEM resource for CS %d\n", i);
+			continue;
+		}
+
+		size = mem_res->end - mem_res->start + 1;
+		if (gpmc_cs_request(i, size, &cs_base)) {
+			dev_err(dev, "Couldn't request resource for CS %d\n",
+				i);
+			continue;
+		}
+
+		mem_res->start = cs_base;
+		mem_res->end = cs_base + size - 1;
+
+		/* FIXME: When do we need to call gpmc_cs_remap()? */
+skip_mem:
+
+		if (cs->settings) {
+			if (gpmc_cs_program_settings(i, cs->settings)) {
+				dev_err(dev,
+					"Couldn't program settings for CS %d\n",
+					i);
+				continue;
+			}
+		}
+
+		/* give device_timings priority over gpmc_timings */
+		if (cs->device_timings) {
+			gpmc_calc_timings(&gpmc_timings, cs->settings,
+					  cs->device_timings);
+
+			if (gpmc_cs_set_timings(i, &gpmc_timings)) {
+				dev_err(dev,
+					"Couldn't program timings for CS %d\n",
+					i);
+				continue;
+			}
+		} else if (cs->gpmc_timings) {
+			if (gpmc_cs_set_timings(i, cs->gpmc_timings)) {
+				dev_err(dev,
+					"Couldn't program timings for CS %d\n",
+					i);
+				continue;
+			}
+		}
+
+		if (!cs->pdev)
+			continue;
+
+		cs->pdev->dev.parent = dev;
+		rc = platform_device_register(cs->pdev);
+		if (rc < 0) {
+			dev_err(dev,
+				"Failed to register device %s on CS %d\n",
+				cs->pdev->name, i);
+			continue;
+		}
+	}
+}
+
 static int gpmc_probe(struct platform_device *pdev)
 {
 	int rc;
 	u32 l;
 	struct resource *res;
+	struct device *dev = &pdev->dev;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (res == NULL)
@@ -1390,7 +1480,7 @@ static int gpmc_probe(struct platform_device *pdev)
 	pm_runtime_enable(&pdev->dev);
 	pm_runtime_get_sync(&pdev->dev);
 
-	gpmc_dev = &pdev->dev;
+	gpmc_dev = dev;
 
 	l = gpmc_read_reg(GPMC_REVISION);
 
@@ -1410,7 +1500,7 @@ static int gpmc_probe(struct platform_device *pdev)
 		gpmc_capability = GPMC_HAS_WR_ACCESS | GPMC_HAS_WR_DATA_MUX_BUS;
 	if (GPMC_REVISION_MAJOR(l) > 0x5)
 		gpmc_capability |= GPMC_HAS_MUX_AAD;
-	dev_info(gpmc_dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l),
+	dev_info(dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l),
 		 GPMC_REVISION_MINOR(l));
 
 	gpmc_mem_init();
@@ -1418,20 +1508,23 @@ static int gpmc_probe(struct platform_device *pdev)
 	/* Now the GPMC is initialised, unreserve the chip-selects */
 	gpmc_cs_map = 0;
 
-	if (!pdev->dev.of_node) {
-		gpmc_cs_num	 = GPMC_CS_NUM;
-		gpmc_nr_waitpins = GPMC_NR_WAITPINS;
-	}
-
-	rc = gpmc_probe_dt(pdev);
-	if (rc < 0) {
-		pm_runtime_put_sync(&pdev->dev);
-		clk_put(gpmc_l3_clk);
-		dev_err(gpmc_dev, "failed to probe DT parameters\n");
-		return rc;
+	if (dev->of_node) {
+		rc = gpmc_probe_dt(pdev);
+		if (rc) {
+			dev_err(dev, "gpmc_probe_dt() failed\n");
+			goto error;
+		}
+	} else {
+		/* Legacy probing based on platform data */
+		gpmc_probe_legacy(pdev);
 	}
 
 	return 0;
+
+error:
+	pm_runtime_put_sync(dev);
+	clk_put(gpmc_l3_clk);
+	return rc;
 }
 
 static int gpmc_remove(struct platform_device *pdev)
-- 
1.8.3.2


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

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

* [PATCH 23/36] ARM: OMAP2+: gpmc: use platform data to configure CS space and poplulate device
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Add gpmc_probe_legacy() that will be called for non DT boots. This function
will use platform data to setup each chip select and populate the child
platform device for each of the chip selects.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.c | 129 ++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 111 insertions(+), 18 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index d3a64ed..c26ba3f 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1302,11 +1302,6 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 {
 	int ret;
 	struct device_node *child;
-	const struct of_device_id *of_id =
-		of_match_device(gpmc_dt_ids, &pdev->dev);
-
-	if (!of_id)
-		return 0;
 
 	ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-cs",
 				   &gpmc_cs_num);
@@ -1355,11 +1350,106 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 }
 #endif
 
+static void gpmc_probe_legacy(struct platform_device *pdev)
+{
+	int i, rc;
+	struct device *dev = &pdev->dev;
+	struct gpmc_omap_platform_data *gpmc_pdata;
+
+	gpmc_pdata = dev->platform_data;
+	gpmc_cs_num = GPMC_CS_NUM;
+	gpmc_nr_waitpins = GPMC_NR_WAITPINS;
+
+	if (!gpmc_pdata)
+		return;
+
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		struct resource *mem_res;
+		unsigned long cs_base;
+		resource_size_t size;
+		struct gpmc_timings gpmc_timings;
+		struct gpmc_omap_cs_data *cs;
+
+		cs = &gpmc_pdata->cs[i];
+		if (!cs->valid)
+			continue;
+
+		/*
+		 * Request a CS space. Use size from
+		 * platform device's MEM resource
+		 */
+		if (!cs->pdev)
+			goto skip_mem;
+
+		mem_res = cs->pdev->resource;
+		if (cs->pdev->num_resources < 1 ||
+		    resource_type(mem_res) != IORESOURCE_MEM) {
+			dev_err(dev, "Invalid IOMEM resource for CS %d\n", i);
+			continue;
+		}
+
+		size = mem_res->end - mem_res->start + 1;
+		if (gpmc_cs_request(i, size, &cs_base)) {
+			dev_err(dev, "Couldn't request resource for CS %d\n",
+				i);
+			continue;
+		}
+
+		mem_res->start = cs_base;
+		mem_res->end = cs_base + size - 1;
+
+		/* FIXME: When do we need to call gpmc_cs_remap()? */
+skip_mem:
+
+		if (cs->settings) {
+			if (gpmc_cs_program_settings(i, cs->settings)) {
+				dev_err(dev,
+					"Couldn't program settings for CS %d\n",
+					i);
+				continue;
+			}
+		}
+
+		/* give device_timings priority over gpmc_timings */
+		if (cs->device_timings) {
+			gpmc_calc_timings(&gpmc_timings, cs->settings,
+					  cs->device_timings);
+
+			if (gpmc_cs_set_timings(i, &gpmc_timings)) {
+				dev_err(dev,
+					"Couldn't program timings for CS %d\n",
+					i);
+				continue;
+			}
+		} else if (cs->gpmc_timings) {
+			if (gpmc_cs_set_timings(i, cs->gpmc_timings)) {
+				dev_err(dev,
+					"Couldn't program timings for CS %d\n",
+					i);
+				continue;
+			}
+		}
+
+		if (!cs->pdev)
+			continue;
+
+		cs->pdev->dev.parent = dev;
+		rc = platform_device_register(cs->pdev);
+		if (rc < 0) {
+			dev_err(dev,
+				"Failed to register device %s on CS %d\n",
+				cs->pdev->name, i);
+			continue;
+		}
+	}
+}
+
 static int gpmc_probe(struct platform_device *pdev)
 {
 	int rc;
 	u32 l;
 	struct resource *res;
+	struct device *dev = &pdev->dev;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (res == NULL)
@@ -1390,7 +1480,7 @@ static int gpmc_probe(struct platform_device *pdev)
 	pm_runtime_enable(&pdev->dev);
 	pm_runtime_get_sync(&pdev->dev);
 
-	gpmc_dev = &pdev->dev;
+	gpmc_dev = dev;
 
 	l = gpmc_read_reg(GPMC_REVISION);
 
@@ -1410,7 +1500,7 @@ static int gpmc_probe(struct platform_device *pdev)
 		gpmc_capability = GPMC_HAS_WR_ACCESS | GPMC_HAS_WR_DATA_MUX_BUS;
 	if (GPMC_REVISION_MAJOR(l) > 0x5)
 		gpmc_capability |= GPMC_HAS_MUX_AAD;
-	dev_info(gpmc_dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l),
+	dev_info(dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l),
 		 GPMC_REVISION_MINOR(l));
 
 	gpmc_mem_init();
@@ -1418,20 +1508,23 @@ static int gpmc_probe(struct platform_device *pdev)
 	/* Now the GPMC is initialised, unreserve the chip-selects */
 	gpmc_cs_map = 0;
 
-	if (!pdev->dev.of_node) {
-		gpmc_cs_num	 = GPMC_CS_NUM;
-		gpmc_nr_waitpins = GPMC_NR_WAITPINS;
-	}
-
-	rc = gpmc_probe_dt(pdev);
-	if (rc < 0) {
-		pm_runtime_put_sync(&pdev->dev);
-		clk_put(gpmc_l3_clk);
-		dev_err(gpmc_dev, "failed to probe DT parameters\n");
-		return rc;
+	if (dev->of_node) {
+		rc = gpmc_probe_dt(pdev);
+		if (rc) {
+			dev_err(dev, "gpmc_probe_dt() failed\n");
+			goto error;
+		}
+	} else {
+		/* Legacy probing based on platform data */
+		gpmc_probe_legacy(pdev);
 	}
 
 	return 0;
+
+error:
+	pm_runtime_put_sync(dev);
+	clk_put(gpmc_l3_clk);
+	return rc;
 }
 
 static int gpmc_remove(struct platform_device *pdev)
-- 
1.8.3.2

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

* [PATCH 24/36] ARM: OMAP2+: gpmc: add NAND specific setup
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Provide NAND specific resources and platform data.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index c26ba3f..5563360 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1350,6 +1350,42 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 }
 #endif
 
+static int gpmc_nand_setup(struct platform_device *parent_pdev,
+			   struct gpmc_omap_cs_data *cs)
+{
+	struct resource *res;
+	struct resource *res_gpmc;
+
+	if (!cs->pdev)
+		return -EINVAL;
+
+	res = cs->pdev->resource;
+
+	if (cs->pdev->num_resources < 3)
+		return -EINVAL;
+
+	if (resource_type(&res[1]) != IORESOURCE_MEM ||
+	    resource_type(&res[2]) != IORESOURCE_IRQ)
+		return -EINVAL;
+
+	if (!cs->settings)
+		return -EINVAL;
+
+	/* GPMC register space */
+	res_gpmc = platform_get_resource(parent_pdev, IORESOURCE_MEM, 0);
+	if (!res_gpmc)
+		return -EINVAL;
+
+	res[1] = *res_gpmc;
+
+	/* setup IRQ resources */
+	res[2].start = gpmc_irq;
+
+	cs->settings->device_nand = true;
+
+	return 0;
+}
+
 static void gpmc_probe_legacy(struct platform_device *pdev)
 {
 	int i, rc;
@@ -1401,6 +1437,15 @@ static void gpmc_probe_legacy(struct platform_device *pdev)
 		/* FIXME: When do we need to call gpmc_cs_remap()? */
 skip_mem:
 
+		/* Customized NAND setup */
+		if (cs->is_nand) {
+			if (gpmc_nand_setup(pdev, cs)) {
+				dev_err(dev, "Error setting up NAND on CS %d\n",
+					i);
+				continue;
+			}
+		}
+
 		if (cs->settings) {
 			if (gpmc_cs_program_settings(i, cs->settings)) {
 				dev_err(dev,
-- 
1.8.3.2


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

* [PATCH 24/36] ARM: OMAP2+: gpmc: add NAND specific setup
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Provide NAND specific resources and platform data.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index c26ba3f..5563360 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1350,6 +1350,42 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 }
 #endif
 
+static int gpmc_nand_setup(struct platform_device *parent_pdev,
+			   struct gpmc_omap_cs_data *cs)
+{
+	struct resource *res;
+	struct resource *res_gpmc;
+
+	if (!cs->pdev)
+		return -EINVAL;
+
+	res = cs->pdev->resource;
+
+	if (cs->pdev->num_resources < 3)
+		return -EINVAL;
+
+	if (resource_type(&res[1]) != IORESOURCE_MEM ||
+	    resource_type(&res[2]) != IORESOURCE_IRQ)
+		return -EINVAL;
+
+	if (!cs->settings)
+		return -EINVAL;
+
+	/* GPMC register space */
+	res_gpmc = platform_get_resource(parent_pdev, IORESOURCE_MEM, 0);
+	if (!res_gpmc)
+		return -EINVAL;
+
+	res[1] = *res_gpmc;
+
+	/* setup IRQ resources */
+	res[2].start = gpmc_irq;
+
+	cs->settings->device_nand = true;
+
+	return 0;
+}
+
 static void gpmc_probe_legacy(struct platform_device *pdev)
 {
 	int i, rc;
@@ -1401,6 +1437,15 @@ static void gpmc_probe_legacy(struct platform_device *pdev)
 		/* FIXME: When do we need to call gpmc_cs_remap()? */
 skip_mem:
 
+		/* Customized NAND setup */
+		if (cs->is_nand) {
+			if (gpmc_nand_setup(pdev, cs)) {
+				dev_err(dev, "Error setting up NAND on CS %d\n",
+					i);
+				continue;
+			}
+		}
+
 		if (cs->settings) {
 			if (gpmc_cs_program_settings(i, cs->settings)) {
 				dev_err(dev,
-- 
1.8.3.2


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

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

* [PATCH 24/36] ARM: OMAP2+: gpmc: add NAND specific setup
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Provide NAND specific resources and platform data.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index c26ba3f..5563360 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1350,6 +1350,42 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 }
 #endif
 
+static int gpmc_nand_setup(struct platform_device *parent_pdev,
+			   struct gpmc_omap_cs_data *cs)
+{
+	struct resource *res;
+	struct resource *res_gpmc;
+
+	if (!cs->pdev)
+		return -EINVAL;
+
+	res = cs->pdev->resource;
+
+	if (cs->pdev->num_resources < 3)
+		return -EINVAL;
+
+	if (resource_type(&res[1]) != IORESOURCE_MEM ||
+	    resource_type(&res[2]) != IORESOURCE_IRQ)
+		return -EINVAL;
+
+	if (!cs->settings)
+		return -EINVAL;
+
+	/* GPMC register space */
+	res_gpmc = platform_get_resource(parent_pdev, IORESOURCE_MEM, 0);
+	if (!res_gpmc)
+		return -EINVAL;
+
+	res[1] = *res_gpmc;
+
+	/* setup IRQ resources */
+	res[2].start = gpmc_irq;
+
+	cs->settings->device_nand = true;
+
+	return 0;
+}
+
 static void gpmc_probe_legacy(struct platform_device *pdev)
 {
 	int i, rc;
@@ -1401,6 +1437,15 @@ static void gpmc_probe_legacy(struct platform_device *pdev)
 		/* FIXME: When do we need to call gpmc_cs_remap()? */
 skip_mem:
 
+		/* Customized NAND setup */
+		if (cs->is_nand) {
+			if (gpmc_nand_setup(pdev, cs)) {
+				dev_err(dev, "Error setting up NAND on CS %d\n",
+					i);
+				continue;
+			}
+		}
+
 		if (cs->settings) {
 			if (gpmc_cs_program_settings(i, cs->settings)) {
 				dev_err(dev,
-- 
1.8.3.2

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

* [PATCH 25/36] ARM: OMAP2+: gpmc: Support multiple Chip Selects per device
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Some devices (e.g. tusb6010) need 2 chip selects to work with
2 separate IOMEM resources. Allow such use case. The user just
needs to call gpmc_generic_init() for as many chip selects
with the same platform_device pointer. The GPMC driver will
take care of fixing up the memory resources.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.c | 134 ++++++++++++++++++++++++++++++---------------
 1 file changed, 91 insertions(+), 43 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 5563360..34545ca 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1388,9 +1388,14 @@ static int gpmc_nand_setup(struct platform_device *parent_pdev,
 
 static void gpmc_probe_legacy(struct platform_device *pdev)
 {
-	int i, rc;
+	int i, rc, j;
 	struct device *dev = &pdev->dev;
 	struct gpmc_omap_platform_data *gpmc_pdata;
+	struct resource *mem_res;
+	unsigned long cs_base;
+	resource_size_t size;
+	struct gpmc_timings gpmc_timings;
+	struct gpmc_omap_cs_data *cs;
 
 	gpmc_pdata = dev->platform_data;
 	gpmc_cs_num = GPMC_CS_NUM;
@@ -1400,52 +1405,10 @@ static void gpmc_probe_legacy(struct platform_device *pdev)
 		return;
 
 	for (i = 0; i < GPMC_CS_NUM; i++) {
-		struct resource *mem_res;
-		unsigned long cs_base;
-		resource_size_t size;
-		struct gpmc_timings gpmc_timings;
-		struct gpmc_omap_cs_data *cs;
-
 		cs = &gpmc_pdata->cs[i];
 		if (!cs->valid)
 			continue;
 
-		/*
-		 * Request a CS space. Use size from
-		 * platform device's MEM resource
-		 */
-		if (!cs->pdev)
-			goto skip_mem;
-
-		mem_res = cs->pdev->resource;
-		if (cs->pdev->num_resources < 1 ||
-		    resource_type(mem_res) != IORESOURCE_MEM) {
-			dev_err(dev, "Invalid IOMEM resource for CS %d\n", i);
-			continue;
-		}
-
-		size = mem_res->end - mem_res->start + 1;
-		if (gpmc_cs_request(i, size, &cs_base)) {
-			dev_err(dev, "Couldn't request resource for CS %d\n",
-				i);
-			continue;
-		}
-
-		mem_res->start = cs_base;
-		mem_res->end = cs_base + size - 1;
-
-		/* FIXME: When do we need to call gpmc_cs_remap()? */
-skip_mem:
-
-		/* Customized NAND setup */
-		if (cs->is_nand) {
-			if (gpmc_nand_setup(pdev, cs)) {
-				dev_err(dev, "Error setting up NAND on CS %d\n",
-					i);
-				continue;
-			}
-		}
-
 		if (cs->settings) {
 			if (gpmc_cs_program_settings(i, cs->settings)) {
 				dev_err(dev,
@@ -1474,10 +1437,95 @@ skip_mem:
 				continue;
 			}
 		}
+	}
+
+	/*
+	 * All Chip Selects must be configured before platform devices are
+	 * created as some devices (e.g. tusb6010) can use multiple
+	 * Chip selects.
+	 */
+
+	/* Fixup Memory resources */
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		int required_resources;
+
+		cs = &gpmc_pdata->cs[i];
+		if (!cs->valid)
+			continue;
 
 		if (!cs->pdev)
 			continue;
 
+		/* Customized NAND setup */
+		if (cs->is_nand) {
+			if (gpmc_nand_setup(pdev, cs)) {
+				dev_err(dev, "Error setting up NAND on CS %d\n",
+					i);
+				continue;
+			}
+		}
+
+		mem_res = cs->pdev->resource;
+
+		/*
+		 * If device is present multiple times, fix the subsequent
+		 * resources
+		 */
+		required_resources = 1;
+		for (j = 0; j < i; j++) {
+			if (gpmc_pdata->cs[j].pdev == cs->pdev) {
+				mem_res++;
+				required_resources++;
+			}
+		}
+
+		if (cs->pdev->num_resources < required_resources ||
+		    resource_type(mem_res) != IORESOURCE_MEM) {
+			dev_err(dev, "Invalid IOMEM resource for CS %d\n", i);
+			continue;
+		}
+
+		/*
+		 * Request a CS space. Use size from
+		 * platform device's MEM resource
+		 */
+		size = mem_res->end - mem_res->start + 1;
+		if (gpmc_cs_request(i, size, &cs_base)) {
+			dev_err(dev, "Couldn't request resource for CS %d\n",
+				i);
+			continue;
+		}
+
+		mem_res->start = cs_base;
+		mem_res->end = cs_base + size - 1;
+	}
+
+	/* create the platform devices */
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		bool registered;
+
+		cs = &gpmc_pdata->cs[i];
+		if (!cs->valid)
+			continue;
+
+		if (!cs->pdev)
+			continue;
+
+		/*
+		 * same device can be present on multiple CS, don't
+		 * register device more than once.
+		 */
+		registered = false;
+		for (j = 0; j < i; j++) {
+			if (gpmc_pdata->cs[j].pdev == cs->pdev) {
+				registered = true;
+				break;
+			}
+		}
+
+		if (registered)
+			continue;
+
 		cs->pdev->dev.parent = dev;
 		rc = platform_device_register(cs->pdev);
 		if (rc < 0) {
-- 
1.8.3.2


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

* [PATCH 25/36] ARM: OMAP2+: gpmc: Support multiple Chip Selects per device
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Some devices (e.g. tusb6010) need 2 chip selects to work with
2 separate IOMEM resources. Allow such use case. The user just
needs to call gpmc_generic_init() for as many chip selects
with the same platform_device pointer. The GPMC driver will
take care of fixing up the memory resources.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.c | 134 ++++++++++++++++++++++++++++++---------------
 1 file changed, 91 insertions(+), 43 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 5563360..34545ca 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1388,9 +1388,14 @@ static int gpmc_nand_setup(struct platform_device *parent_pdev,
 
 static void gpmc_probe_legacy(struct platform_device *pdev)
 {
-	int i, rc;
+	int i, rc, j;
 	struct device *dev = &pdev->dev;
 	struct gpmc_omap_platform_data *gpmc_pdata;
+	struct resource *mem_res;
+	unsigned long cs_base;
+	resource_size_t size;
+	struct gpmc_timings gpmc_timings;
+	struct gpmc_omap_cs_data *cs;
 
 	gpmc_pdata = dev->platform_data;
 	gpmc_cs_num = GPMC_CS_NUM;
@@ -1400,52 +1405,10 @@ static void gpmc_probe_legacy(struct platform_device *pdev)
 		return;
 
 	for (i = 0; i < GPMC_CS_NUM; i++) {
-		struct resource *mem_res;
-		unsigned long cs_base;
-		resource_size_t size;
-		struct gpmc_timings gpmc_timings;
-		struct gpmc_omap_cs_data *cs;
-
 		cs = &gpmc_pdata->cs[i];
 		if (!cs->valid)
 			continue;
 
-		/*
-		 * Request a CS space. Use size from
-		 * platform device's MEM resource
-		 */
-		if (!cs->pdev)
-			goto skip_mem;
-
-		mem_res = cs->pdev->resource;
-		if (cs->pdev->num_resources < 1 ||
-		    resource_type(mem_res) != IORESOURCE_MEM) {
-			dev_err(dev, "Invalid IOMEM resource for CS %d\n", i);
-			continue;
-		}
-
-		size = mem_res->end - mem_res->start + 1;
-		if (gpmc_cs_request(i, size, &cs_base)) {
-			dev_err(dev, "Couldn't request resource for CS %d\n",
-				i);
-			continue;
-		}
-
-		mem_res->start = cs_base;
-		mem_res->end = cs_base + size - 1;
-
-		/* FIXME: When do we need to call gpmc_cs_remap()? */
-skip_mem:
-
-		/* Customized NAND setup */
-		if (cs->is_nand) {
-			if (gpmc_nand_setup(pdev, cs)) {
-				dev_err(dev, "Error setting up NAND on CS %d\n",
-					i);
-				continue;
-			}
-		}
-
 		if (cs->settings) {
 			if (gpmc_cs_program_settings(i, cs->settings)) {
 				dev_err(dev,
@@ -1474,10 +1437,95 @@ skip_mem:
 				continue;
 			}
 		}
+	}
+
+	/*
+	 * All Chip Selects must be configured before platform devices are
+	 * created as some devices (e.g. tusb6010) can use multiple
+	 * Chip selects.
+	 */
+
+	/* Fixup Memory resources */
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		int required_resources;
+
+		cs = &gpmc_pdata->cs[i];
+		if (!cs->valid)
+			continue;
 
 		if (!cs->pdev)
 			continue;
 
+		/* Customized NAND setup */
+		if (cs->is_nand) {
+			if (gpmc_nand_setup(pdev, cs)) {
+				dev_err(dev, "Error setting up NAND on CS %d\n",
+					i);
+				continue;
+			}
+		}
+
+		mem_res = cs->pdev->resource;
+
+		/*
+		 * If device is present multiple times, fix the subsequent
+		 * resources
+		 */
+		required_resources = 1;
+		for (j = 0; j < i; j++) {
+			if (gpmc_pdata->cs[j].pdev == cs->pdev) {
+				mem_res++;
+				required_resources++;
+			}
+		}
+
+		if (cs->pdev->num_resources < required_resources ||
+		    resource_type(mem_res) != IORESOURCE_MEM) {
+			dev_err(dev, "Invalid IOMEM resource for CS %d\n", i);
+			continue;
+		}
+
+		/*
+		 * Request a CS space. Use size from
+		 * platform device's MEM resource
+		 */
+		size = mem_res->end - mem_res->start + 1;
+		if (gpmc_cs_request(i, size, &cs_base)) {
+			dev_err(dev, "Couldn't request resource for CS %d\n",
+				i);
+			continue;
+		}
+
+		mem_res->start = cs_base;
+		mem_res->end = cs_base + size - 1;
+	}
+
+	/* create the platform devices */
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		bool registered;
+
+		cs = &gpmc_pdata->cs[i];
+		if (!cs->valid)
+			continue;
+
+		if (!cs->pdev)
+			continue;
+
+		/*
+		 * same device can be present on multiple CS, don't
+		 * register device more than once.
+		 */
+		registered = false;
+		for (j = 0; j < i; j++) {
+			if (gpmc_pdata->cs[j].pdev == cs->pdev) {
+				registered = true;
+				break;
+			}
+		}
+
+		if (registered)
+			continue;
+
 		cs->pdev->dev.parent = dev;
 		rc = platform_device_register(cs->pdev);
 		if (rc < 0) {
-- 
1.8.3.2

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

* [PATCH 25/36] ARM: OMAP2+: gpmc: Support multiple Chip Selects per device
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Some devices (e.g. tusb6010) need 2 chip selects to work with
2 separate IOMEM resources. Allow such use case. The user just
needs to call gpmc_generic_init() for as many chip selects
with the same platform_device pointer. The GPMC driver will
take care of fixing up the memory resources.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.c | 134 ++++++++++++++++++++++++++++++---------------
 1 file changed, 91 insertions(+), 43 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 5563360..34545ca 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1388,9 +1388,14 @@ static int gpmc_nand_setup(struct platform_device *parent_pdev,
 
 static void gpmc_probe_legacy(struct platform_device *pdev)
 {
-	int i, rc;
+	int i, rc, j;
 	struct device *dev = &pdev->dev;
 	struct gpmc_omap_platform_data *gpmc_pdata;
+	struct resource *mem_res;
+	unsigned long cs_base;
+	resource_size_t size;
+	struct gpmc_timings gpmc_timings;
+	struct gpmc_omap_cs_data *cs;
 
 	gpmc_pdata = dev->platform_data;
 	gpmc_cs_num = GPMC_CS_NUM;
@@ -1400,52 +1405,10 @@ static void gpmc_probe_legacy(struct platform_device *pdev)
 		return;
 
 	for (i = 0; i < GPMC_CS_NUM; i++) {
-		struct resource *mem_res;
-		unsigned long cs_base;
-		resource_size_t size;
-		struct gpmc_timings gpmc_timings;
-		struct gpmc_omap_cs_data *cs;
-
 		cs = &gpmc_pdata->cs[i];
 		if (!cs->valid)
 			continue;
 
-		/*
-		 * Request a CS space. Use size from
-		 * platform device's MEM resource
-		 */
-		if (!cs->pdev)
-			goto skip_mem;
-
-		mem_res = cs->pdev->resource;
-		if (cs->pdev->num_resources < 1 ||
-		    resource_type(mem_res) != IORESOURCE_MEM) {
-			dev_err(dev, "Invalid IOMEM resource for CS %d\n", i);
-			continue;
-		}
-
-		size = mem_res->end - mem_res->start + 1;
-		if (gpmc_cs_request(i, size, &cs_base)) {
-			dev_err(dev, "Couldn't request resource for CS %d\n",
-				i);
-			continue;
-		}
-
-		mem_res->start = cs_base;
-		mem_res->end = cs_base + size - 1;
-
-		/* FIXME: When do we need to call gpmc_cs_remap()? */
-skip_mem:
-
-		/* Customized NAND setup */
-		if (cs->is_nand) {
-			if (gpmc_nand_setup(pdev, cs)) {
-				dev_err(dev, "Error setting up NAND on CS %d\n",
-					i);
-				continue;
-			}
-		}
-
 		if (cs->settings) {
 			if (gpmc_cs_program_settings(i, cs->settings)) {
 				dev_err(dev,
@@ -1474,10 +1437,95 @@ skip_mem:
 				continue;
 			}
 		}
+	}
+
+	/*
+	 * All Chip Selects must be configured before platform devices are
+	 * created as some devices (e.g. tusb6010) can use multiple
+	 * Chip selects.
+	 */
+
+	/* Fixup Memory resources */
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		int required_resources;
+
+		cs = &gpmc_pdata->cs[i];
+		if (!cs->valid)
+			continue;
 
 		if (!cs->pdev)
 			continue;
 
+		/* Customized NAND setup */
+		if (cs->is_nand) {
+			if (gpmc_nand_setup(pdev, cs)) {
+				dev_err(dev, "Error setting up NAND on CS %d\n",
+					i);
+				continue;
+			}
+		}
+
+		mem_res = cs->pdev->resource;
+
+		/*
+		 * If device is present multiple times, fix the subsequent
+		 * resources
+		 */
+		required_resources = 1;
+		for (j = 0; j < i; j++) {
+			if (gpmc_pdata->cs[j].pdev == cs->pdev) {
+				mem_res++;
+				required_resources++;
+			}
+		}
+
+		if (cs->pdev->num_resources < required_resources ||
+		    resource_type(mem_res) != IORESOURCE_MEM) {
+			dev_err(dev, "Invalid IOMEM resource for CS %d\n", i);
+			continue;
+		}
+
+		/*
+		 * Request a CS space. Use size from
+		 * platform device's MEM resource
+		 */
+		size = mem_res->end - mem_res->start + 1;
+		if (gpmc_cs_request(i, size, &cs_base)) {
+			dev_err(dev, "Couldn't request resource for CS %d\n",
+				i);
+			continue;
+		}
+
+		mem_res->start = cs_base;
+		mem_res->end = cs_base + size - 1;
+	}
+
+	/* create the platform devices */
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		bool registered;
+
+		cs = &gpmc_pdata->cs[i];
+		if (!cs->valid)
+			continue;
+
+		if (!cs->pdev)
+			continue;
+
+		/*
+		 * same device can be present on multiple CS, don't
+		 * register device more than once.
+		 */
+		registered = false;
+		for (j = 0; j < i; j++) {
+			if (gpmc_pdata->cs[j].pdev == cs->pdev) {
+				registered = true;
+				break;
+			}
+		}
+
+		if (registered)
+			continue;
+
 		cs->pdev->dev.parent = dev;
 		rc = platform_device_register(cs->pdev);
 		if (rc < 0) {
-- 
1.8.3.2

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

* [PATCH 26/36] ARM: OMAP2+: gpmc-smc91x: Get rid of retime() from omap_smc91x_platform_data
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

The retime() function is not provided by board files so get rid of
it from omap_smc91x_platform_data().

Instead change it to smc91c96_get_device_timing() to get the device
timings.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/board-3430sdp.c |  8 ++++--
 arch/arm/mach-omap2/gpmc-smc91x.c   | 55 ++++++++++++++-----------------------
 arch/arm/mach-omap2/gpmc-smc91x.h   |  1 -
 3 files changed, 27 insertions(+), 37 deletions(-)

diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index d95d0ef..b781090 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -411,8 +411,12 @@ static int __init omap3430_i2c_init(void)
 
 static struct omap_smc91x_platform_data board_smc91x_data = {
 	.cs		= 3,
-	.flags		= GPMC_MUX_ADD_DATA | GPMC_TIMINGS_SMC91C96 |
-				IORESOURCE_IRQ_LOWLEVEL,
+	/*
+	 * Don't use GPMC_TIMINGS_SMC91C96 flag here as generic
+	 * timing doesn't seem to have worked.
+	 * Leave bootloader timing intact.
+	 */
+	.flags		= GPMC_MUX_ADD_DATA | IORESOURCE_IRQ_LOWLEVEL,
 };
 
 static void __init board_smc91x_init(void)
diff --git a/arch/arm/mach-omap2/gpmc-smc91x.c b/arch/arm/mach-omap2/gpmc-smc91x.c
index 61a0635..7f5d84a 100644
--- a/arch/arm/mach-omap2/gpmc-smc91x.c
+++ b/arch/arm/mach-omap2/gpmc-smc91x.c
@@ -59,10 +59,8 @@ static struct gpmc_settings smc91x_settings = {
  * http://www.smsc.com/main/catalog/lan91c96.html
  * REVISIT: Level shifters can add at least to the access latency.
  */
-static int smc91c96_gpmc_retime(void)
+static void smc91c96_get_device_timing(struct gpmc_device_timings *dev_t)
 {
-	struct gpmc_timings t;
-	struct gpmc_device_timings dev_t;
 	const int t3 = 10;	/* Figure 12.2 read and 12.4 write */
 	const int t4_r = 20;	/* Figure 12.2 read */
 	const int t4_w = 5;	/* Figure 12.4 write */
@@ -72,33 +70,19 @@ static int smc91c96_gpmc_retime(void)
 	const int t8 = 5;	/* Figure 12.4 write */
 	const int t20 = 185;	/* Figure 12.2 read and 12.4 write */
 
-	/*
-	 * FIXME: Calculate the address and data bus muxed timings.
-	 * Note that at least adv_rd_off needs to be changed according
-	 * to omap3430 TRM Figure 11-11. Are the sdp boards using the
-	 * FPGA in between smc91x and omap as the timings are different
-	 * from above?
-	 */
-	if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)
-		return 0;
-
-	memset(&dev_t, 0, sizeof(dev_t));
-
-	dev_t.t_oeasu = t3 * 1000;
-	dev_t.t_oe = t5 * 1000;
-	dev_t.t_cez_r = t4_r * 1000;
-	dev_t.t_oez = t6 * 1000;
-	dev_t.t_rd_cycle = (t20 - t3) * 1000;
+	memset(dev_t, 0, sizeof(*dev_t));
 
-	dev_t.t_weasu = t3 * 1000;
-	dev_t.t_wpl = t7 * 1000;
-	dev_t.t_wph = t8 * 1000;
-	dev_t.t_cez_w = t4_w * 1000;
-	dev_t.t_wr_cycle = (t20 - t3) * 1000;
+	dev_t->t_oeasu = t3 * 1000;
+	dev_t->t_oe = t5 * 1000;
+	dev_t->t_cez_r = t4_r * 1000;
+	dev_t->t_oez = t6 * 1000;
+	dev_t->t_rd_cycle = (t20 - t3) * 1000;
 
-	gpmc_calc_timings(&t, &smc91x_settings, &dev_t);
-
-	return gpmc_cs_set_timings(gpmc_cfg->cs, &t);
+	dev_t->t_weasu = t3 * 1000;
+	dev_t->t_wpl = t7 * 1000;
+	dev_t->t_wph = t8 * 1000;
+	dev_t->t_cez_w = t4_w * 1000;
+	dev_t->t_wr_cycle = (t20 - t3) * 1000;
 }
 
 /*
@@ -110,12 +94,10 @@ void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data)
 {
 	unsigned long cs_mem_base;
 	int ret;
+	struct gpmc_device_timings dev_t;
 
 	gpmc_cfg = board_data;
 
-	if (gpmc_cfg->flags & GPMC_TIMINGS_SMC91C96)
-		gpmc_cfg->retime = smc91c96_gpmc_retime;
-
 	if (gpmc_cs_request(gpmc_cfg->cs, SZ_16M, &cs_mem_base) < 0) {
 		printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
 		return;
@@ -137,10 +119,15 @@ void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data)
 	if (ret < 0)
 		goto free1;
 
-	if (gpmc_cfg->retime) {
-		ret = gpmc_cfg->retime();
-		if (ret != 0)
+	if (gpmc_cfg->flags & GPMC_TIMINGS_SMC91C96) {
+		struct gpmc_timings gpmc_t;
+
+		smc91c96_get_device_timing(&dev_t);
+		gpmc_calc_timings(&gpmc_t, &smc91x_settings, &dev_t);
+		if (gpmc_cs_set_timings(gpmc_cfg->cs, &gpmc_t)) {
+			pr_err("%s: failed to set GPMC timings\n", __func__);
 			goto free1;
+		}
 	}
 
 	if (gpio_request_one(gpmc_cfg->gpio_irq, GPIOF_IN, "SMC91X irq") < 0)
diff --git a/arch/arm/mach-omap2/gpmc-smc91x.h b/arch/arm/mach-omap2/gpmc-smc91x.h
index b64fbee..1da09a0 100644
--- a/arch/arm/mach-omap2/gpmc-smc91x.h
+++ b/arch/arm/mach-omap2/gpmc-smc91x.h
@@ -22,7 +22,6 @@ struct omap_smc91x_platform_data {
 	int	gpio_reset;
 	int	wait_pin;	/* Optional GPMC_CONFIG1_WAITPINSELECT */
 	u32	flags;
-	int	(*retime)(void);
 };
 
 #if defined(CONFIG_SMC91X) || \
-- 
1.8.3.2


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

* [PATCH 26/36] ARM: OMAP2+: gpmc-smc91x: Get rid of retime() from omap_smc91x_platform_data
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

The retime() function is not provided by board files so get rid of
it from omap_smc91x_platform_data().

Instead change it to smc91c96_get_device_timing() to get the device
timings.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/board-3430sdp.c |  8 ++++--
 arch/arm/mach-omap2/gpmc-smc91x.c   | 55 ++++++++++++++-----------------------
 arch/arm/mach-omap2/gpmc-smc91x.h   |  1 -
 3 files changed, 27 insertions(+), 37 deletions(-)

diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index d95d0ef..b781090 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -411,8 +411,12 @@ static int __init omap3430_i2c_init(void)
 
 static struct omap_smc91x_platform_data board_smc91x_data = {
 	.cs		= 3,
-	.flags		= GPMC_MUX_ADD_DATA | GPMC_TIMINGS_SMC91C96 |
-				IORESOURCE_IRQ_LOWLEVEL,
+	/*
+	 * Don't use GPMC_TIMINGS_SMC91C96 flag here as generic
+	 * timing doesn't seem to have worked.
+	 * Leave bootloader timing intact.
+	 */
+	.flags		= GPMC_MUX_ADD_DATA | IORESOURCE_IRQ_LOWLEVEL,
 };
 
 static void __init board_smc91x_init(void)
diff --git a/arch/arm/mach-omap2/gpmc-smc91x.c b/arch/arm/mach-omap2/gpmc-smc91x.c
index 61a0635..7f5d84a 100644
--- a/arch/arm/mach-omap2/gpmc-smc91x.c
+++ b/arch/arm/mach-omap2/gpmc-smc91x.c
@@ -59,10 +59,8 @@ static struct gpmc_settings smc91x_settings = {
  * http://www.smsc.com/main/catalog/lan91c96.html
  * REVISIT: Level shifters can add at least to the access latency.
  */
-static int smc91c96_gpmc_retime(void)
+static void smc91c96_get_device_timing(struct gpmc_device_timings *dev_t)
 {
-	struct gpmc_timings t;
-	struct gpmc_device_timings dev_t;
 	const int t3 = 10;	/* Figure 12.2 read and 12.4 write */
 	const int t4_r = 20;	/* Figure 12.2 read */
 	const int t4_w = 5;	/* Figure 12.4 write */
@@ -72,33 +70,19 @@ static int smc91c96_gpmc_retime(void)
 	const int t8 = 5;	/* Figure 12.4 write */
 	const int t20 = 185;	/* Figure 12.2 read and 12.4 write */
 
-	/*
-	 * FIXME: Calculate the address and data bus muxed timings.
-	 * Note that at least adv_rd_off needs to be changed according
-	 * to omap3430 TRM Figure 11-11. Are the sdp boards using the
-	 * FPGA in between smc91x and omap as the timings are different
-	 * from above?
-	 */
-	if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)
-		return 0;
-
-	memset(&dev_t, 0, sizeof(dev_t));
-
-	dev_t.t_oeasu = t3 * 1000;
-	dev_t.t_oe = t5 * 1000;
-	dev_t.t_cez_r = t4_r * 1000;
-	dev_t.t_oez = t6 * 1000;
-	dev_t.t_rd_cycle = (t20 - t3) * 1000;
+	memset(dev_t, 0, sizeof(*dev_t));
 
-	dev_t.t_weasu = t3 * 1000;
-	dev_t.t_wpl = t7 * 1000;
-	dev_t.t_wph = t8 * 1000;
-	dev_t.t_cez_w = t4_w * 1000;
-	dev_t.t_wr_cycle = (t20 - t3) * 1000;
+	dev_t->t_oeasu = t3 * 1000;
+	dev_t->t_oe = t5 * 1000;
+	dev_t->t_cez_r = t4_r * 1000;
+	dev_t->t_oez = t6 * 1000;
+	dev_t->t_rd_cycle = (t20 - t3) * 1000;
 
-	gpmc_calc_timings(&t, &smc91x_settings, &dev_t);
-
-	return gpmc_cs_set_timings(gpmc_cfg->cs, &t);
+	dev_t->t_weasu = t3 * 1000;
+	dev_t->t_wpl = t7 * 1000;
+	dev_t->t_wph = t8 * 1000;
+	dev_t->t_cez_w = t4_w * 1000;
+	dev_t->t_wr_cycle = (t20 - t3) * 1000;
 }
 
 /*
@@ -110,12 +94,10 @@ void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data)
 {
 	unsigned long cs_mem_base;
 	int ret;
+	struct gpmc_device_timings dev_t;
 
 	gpmc_cfg = board_data;
 
-	if (gpmc_cfg->flags & GPMC_TIMINGS_SMC91C96)
-		gpmc_cfg->retime = smc91c96_gpmc_retime;
-
 	if (gpmc_cs_request(gpmc_cfg->cs, SZ_16M, &cs_mem_base) < 0) {
 		printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
 		return;
@@ -137,10 +119,15 @@ void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data)
 	if (ret < 0)
 		goto free1;
 
-	if (gpmc_cfg->retime) {
-		ret = gpmc_cfg->retime();
-		if (ret != 0)
+	if (gpmc_cfg->flags & GPMC_TIMINGS_SMC91C96) {
+		struct gpmc_timings gpmc_t;
+
+		smc91c96_get_device_timing(&dev_t);
+		gpmc_calc_timings(&gpmc_t, &smc91x_settings, &dev_t);
+		if (gpmc_cs_set_timings(gpmc_cfg->cs, &gpmc_t)) {
+			pr_err("%s: failed to set GPMC timings\n", __func__);
 			goto free1;
+		}
 	}
 
 	if (gpio_request_one(gpmc_cfg->gpio_irq, GPIOF_IN, "SMC91X irq") < 0)
diff --git a/arch/arm/mach-omap2/gpmc-smc91x.h b/arch/arm/mach-omap2/gpmc-smc91x.h
index b64fbee..1da09a0 100644
--- a/arch/arm/mach-omap2/gpmc-smc91x.h
+++ b/arch/arm/mach-omap2/gpmc-smc91x.h
@@ -22,7 +22,6 @@ struct omap_smc91x_platform_data {
 	int	gpio_reset;
 	int	wait_pin;	/* Optional GPMC_CONFIG1_WAITPINSELECT */
 	u32	flags;
-	int	(*retime)(void);
 };
 
 #if defined(CONFIG_SMC91X) || \
-- 
1.8.3.2


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

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

* [PATCH 26/36] ARM: OMAP2+: gpmc-smc91x: Get rid of retime() from omap_smc91x_platform_data
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

The retime() function is not provided by board files so get rid of
it from omap_smc91x_platform_data().

Instead change it to smc91c96_get_device_timing() to get the device
timings.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/board-3430sdp.c |  8 ++++--
 arch/arm/mach-omap2/gpmc-smc91x.c   | 55 ++++++++++++++-----------------------
 arch/arm/mach-omap2/gpmc-smc91x.h   |  1 -
 3 files changed, 27 insertions(+), 37 deletions(-)

diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index d95d0ef..b781090 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -411,8 +411,12 @@ static int __init omap3430_i2c_init(void)
 
 static struct omap_smc91x_platform_data board_smc91x_data = {
 	.cs		= 3,
-	.flags		= GPMC_MUX_ADD_DATA | GPMC_TIMINGS_SMC91C96 |
-				IORESOURCE_IRQ_LOWLEVEL,
+	/*
+	 * Don't use GPMC_TIMINGS_SMC91C96 flag here as generic
+	 * timing doesn't seem to have worked.
+	 * Leave bootloader timing intact.
+	 */
+	.flags		= GPMC_MUX_ADD_DATA | IORESOURCE_IRQ_LOWLEVEL,
 };
 
 static void __init board_smc91x_init(void)
diff --git a/arch/arm/mach-omap2/gpmc-smc91x.c b/arch/arm/mach-omap2/gpmc-smc91x.c
index 61a0635..7f5d84a 100644
--- a/arch/arm/mach-omap2/gpmc-smc91x.c
+++ b/arch/arm/mach-omap2/gpmc-smc91x.c
@@ -59,10 +59,8 @@ static struct gpmc_settings smc91x_settings = {
  * http://www.smsc.com/main/catalog/lan91c96.html
  * REVISIT: Level shifters can add at least to the access latency.
  */
-static int smc91c96_gpmc_retime(void)
+static void smc91c96_get_device_timing(struct gpmc_device_timings *dev_t)
 {
-	struct gpmc_timings t;
-	struct gpmc_device_timings dev_t;
 	const int t3 = 10;	/* Figure 12.2 read and 12.4 write */
 	const int t4_r = 20;	/* Figure 12.2 read */
 	const int t4_w = 5;	/* Figure 12.4 write */
@@ -72,33 +70,19 @@ static int smc91c96_gpmc_retime(void)
 	const int t8 = 5;	/* Figure 12.4 write */
 	const int t20 = 185;	/* Figure 12.2 read and 12.4 write */
 
-	/*
-	 * FIXME: Calculate the address and data bus muxed timings.
-	 * Note that at least adv_rd_off needs to be changed according
-	 * to omap3430 TRM Figure 11-11. Are the sdp boards using the
-	 * FPGA in between smc91x and omap as the timings are different
-	 * from above?
-	 */
-	if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)
-		return 0;
-
-	memset(&dev_t, 0, sizeof(dev_t));
-
-	dev_t.t_oeasu = t3 * 1000;
-	dev_t.t_oe = t5 * 1000;
-	dev_t.t_cez_r = t4_r * 1000;
-	dev_t.t_oez = t6 * 1000;
-	dev_t.t_rd_cycle = (t20 - t3) * 1000;
+	memset(dev_t, 0, sizeof(*dev_t));
 
-	dev_t.t_weasu = t3 * 1000;
-	dev_t.t_wpl = t7 * 1000;
-	dev_t.t_wph = t8 * 1000;
-	dev_t.t_cez_w = t4_w * 1000;
-	dev_t.t_wr_cycle = (t20 - t3) * 1000;
+	dev_t->t_oeasu = t3 * 1000;
+	dev_t->t_oe = t5 * 1000;
+	dev_t->t_cez_r = t4_r * 1000;
+	dev_t->t_oez = t6 * 1000;
+	dev_t->t_rd_cycle = (t20 - t3) * 1000;
 
-	gpmc_calc_timings(&t, &smc91x_settings, &dev_t);
-
-	return gpmc_cs_set_timings(gpmc_cfg->cs, &t);
+	dev_t->t_weasu = t3 * 1000;
+	dev_t->t_wpl = t7 * 1000;
+	dev_t->t_wph = t8 * 1000;
+	dev_t->t_cez_w = t4_w * 1000;
+	dev_t->t_wr_cycle = (t20 - t3) * 1000;
 }
 
 /*
@@ -110,12 +94,10 @@ void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data)
 {
 	unsigned long cs_mem_base;
 	int ret;
+	struct gpmc_device_timings dev_t;
 
 	gpmc_cfg = board_data;
 
-	if (gpmc_cfg->flags & GPMC_TIMINGS_SMC91C96)
-		gpmc_cfg->retime = smc91c96_gpmc_retime;
-
 	if (gpmc_cs_request(gpmc_cfg->cs, SZ_16M, &cs_mem_base) < 0) {
 		printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
 		return;
@@ -137,10 +119,15 @@ void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data)
 	if (ret < 0)
 		goto free1;
 
-	if (gpmc_cfg->retime) {
-		ret = gpmc_cfg->retime();
-		if (ret != 0)
+	if (gpmc_cfg->flags & GPMC_TIMINGS_SMC91C96) {
+		struct gpmc_timings gpmc_t;
+
+		smc91c96_get_device_timing(&dev_t);
+		gpmc_calc_timings(&gpmc_t, &smc91x_settings, &dev_t);
+		if (gpmc_cs_set_timings(gpmc_cfg->cs, &gpmc_t)) {
+			pr_err("%s: failed to set GPMC timings\n", __func__);
 			goto free1;
+		}
 	}
 
 	if (gpio_request_one(gpmc_cfg->gpio_irq, GPIOF_IN, "SMC91X irq") < 0)
diff --git a/arch/arm/mach-omap2/gpmc-smc91x.h b/arch/arm/mach-omap2/gpmc-smc91x.h
index b64fbee..1da09a0 100644
--- a/arch/arm/mach-omap2/gpmc-smc91x.h
+++ b/arch/arm/mach-omap2/gpmc-smc91x.h
@@ -22,7 +22,6 @@ struct omap_smc91x_platform_data {
 	int	gpio_reset;
 	int	wait_pin;	/* Optional GPMC_CONFIG1_WAITPINSELECT */
 	u32	flags;
-	int	(*retime)(void);
 };
 
 #if defined(CONFIG_SMC91X) || \
-- 
1.8.3.2

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

* [PATCH 27/36] ARM: OMAP2+: usb-tusb6010: Use omap_gpmc_retime()
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros,
	Felipe Balbi

In order to change the GPMC settings/timings on the fly,
we must use omap_gpmc_retime(). The other gpmc_*() functions
will soon be made private and moved out of arch/mach-omap2/

CC: Felipe Balbi <balbi@ti.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/usb-tusb6010.c | 94 ++++++++++++++++++--------------------
 1 file changed, 44 insertions(+), 50 deletions(-)

diff --git a/arch/arm/mach-omap2/usb-tusb6010.c b/arch/arm/mach-omap2/usb-tusb6010.c
index e832bc7..71e6246 100644
--- a/arch/arm/mach-omap2/usb-tusb6010.c
+++ b/arch/arm/mach-omap2/usb-tusb6010.c
@@ -48,58 +48,48 @@ static struct gpmc_settings tusb_sync = {
 
 /* NOTE:  timings are from tusb 6010 datasheet Rev 1.8, 12-Sept 2006 */
 
-static int tusb_set_async_mode(unsigned sysclk_ps)
+static void tusb_get_async_timings(unsigned sysclk_ps,
+				   struct gpmc_device_timings *dev_t)
 {
-	struct gpmc_device_timings dev_t;
-	struct gpmc_timings	t;
-	unsigned		t_acsnh_advnh = sysclk_ps + 3000;
-
-	memset(&dev_t, 0, sizeof(dev_t));
-
-	dev_t.t_ceasu = 8 * 1000;
-	dev_t.t_avdasu = t_acsnh_advnh - 7000;
-	dev_t.t_ce_avd = 1000;
-	dev_t.t_avdp_r = t_acsnh_advnh;
-	dev_t.t_oeasu = t_acsnh_advnh + 1000;
-	dev_t.t_oe = 300;
-	dev_t.t_cez_r = 7000;
-	dev_t.t_cez_w = dev_t.t_cez_r;
-	dev_t.t_avdp_w = t_acsnh_advnh;
-	dev_t.t_weasu = t_acsnh_advnh + 1000;
-	dev_t.t_wpl = 300;
-	dev_t.cyc_aavdh_we = 1;
-
-	gpmc_calc_timings(&t, &tusb_async, &dev_t);
-
-	return gpmc_cs_set_timings(async_cs, &t);
+	unsigned t_acsnh_advnh = sysclk_ps + 3000;
+
+	memset(dev_t, 0, sizeof(*dev_t));
+
+	dev_t->t_ceasu = 8 * 1000;
+	dev_t->t_avdasu = t_acsnh_advnh - 7000;
+	dev_t->t_ce_avd = 1000;
+	dev_t->t_avdp_r = t_acsnh_advnh;
+	dev_t->t_oeasu = t_acsnh_advnh + 1000;
+	dev_t->t_oe = 300;
+	dev_t->t_cez_r = 7000;
+	dev_t->t_cez_w = dev_t->t_cez_r;
+	dev_t->t_avdp_w = t_acsnh_advnh;
+	dev_t->t_weasu = t_acsnh_advnh + 1000;
+	dev_t->t_wpl = 300;
+	dev_t->cyc_aavdh_we = 1;
 }
 
-static int tusb_set_sync_mode(unsigned sysclk_ps)
+static void tusb_get_sync_timings(unsigned sysclk_ps,
+				  struct gpmc_device_timings *dev_t)
 {
-	struct gpmc_device_timings dev_t;
-	struct gpmc_timings	t;
-	unsigned		t_scsnh_advnh = sysclk_ps + 3000;
-
-	memset(&dev_t, 0, sizeof(dev_t));
-
-	dev_t.clk = 11100;
-	dev_t.t_bacc = 1000;
-	dev_t.t_ces = 1000;
-	dev_t.t_ceasu = 8 * 1000;
-	dev_t.t_avdasu = t_scsnh_advnh - 7000;
-	dev_t.t_ce_avd = 1000;
-	dev_t.t_avdp_r = t_scsnh_advnh;
-	dev_t.cyc_aavdh_oe = 3;
-	dev_t.cyc_oe = 5;
-	dev_t.t_ce_rdyz = 7000;
-	dev_t.t_avdp_w = t_scsnh_advnh;
-	dev_t.cyc_aavdh_we = 3;
-	dev_t.cyc_wpl = 6;
-	dev_t.t_ce_rdyz = 7000;
-
-	gpmc_calc_timings(&t, &tusb_sync, &dev_t);
-
-	return gpmc_cs_set_timings(sync_cs, &t);
+	unsigned t_scsnh_advnh = sysclk_ps + 3000;
+
+	memset(dev_t, 0, sizeof(dev_t));
+
+	dev_t->clk = 11100;
+	dev_t->t_bacc = 1000;
+	dev_t->t_ces = 1000;
+	dev_t->t_ceasu = 8 * 1000;
+	dev_t->t_avdasu = t_scsnh_advnh - 7000;
+	dev_t->t_ce_avd = 1000;
+	dev_t->t_avdp_r = t_scsnh_advnh;
+	dev_t->cyc_aavdh_oe = 3;
+	dev_t->cyc_oe = 5;
+	dev_t->t_ce_rdyz = 7000;
+	dev_t->t_avdp_w = t_scsnh_advnh;
+	dev_t->cyc_aavdh_we = 3;
+	dev_t->cyc_wpl = 6;
+	dev_t->t_ce_rdyz = 7000;
 }
 
 /* tusb driver calls this when it changes the chip's clocking */
@@ -110,18 +100,22 @@ int tusb6010_platform_retime(unsigned is_refclk)
 
 	unsigned	sysclk_ps;
 	int		status;
+	struct gpmc_device_timings dev_t;
 
 	if (!refclk_psec)
 		return -ENODEV;
 
 	sysclk_ps = is_refclk ? refclk_psec : TUSB6010_OSCCLK_60;
 
-	status = tusb_set_async_mode(sysclk_ps);
+	tusb_get_async_timings(sysclk_ps, &dev_t);
+	status = omap_gpmc_retime(async_cs, &tusb_async, &dev_t);
 	if (status < 0) {
 		printk(error, "async", status);
 		goto done;
 	}
-	status = tusb_set_sync_mode(sysclk_ps);
+
+	tusb_get_sync_timings(sysclk_ps, &dev_t);
+	status = omap_gpmc_retime(sync_cs, &tusb_sync, &dev_t);
 	if (status < 0)
 		printk(error, "sync", status);
 done:
-- 
1.8.3.2


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

* [PATCH 27/36] ARM: OMAP2+: usb-tusb6010: Use omap_gpmc_retime()
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros,
	Felipe Balbi

In order to change the GPMC settings/timings on the fly,
we must use omap_gpmc_retime(). The other gpmc_*() functions
will soon be made private and moved out of arch/mach-omap2/

CC: Felipe Balbi <balbi@ti.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/usb-tusb6010.c | 94 ++++++++++++++++++--------------------
 1 file changed, 44 insertions(+), 50 deletions(-)

diff --git a/arch/arm/mach-omap2/usb-tusb6010.c b/arch/arm/mach-omap2/usb-tusb6010.c
index e832bc7..71e6246 100644
--- a/arch/arm/mach-omap2/usb-tusb6010.c
+++ b/arch/arm/mach-omap2/usb-tusb6010.c
@@ -48,58 +48,48 @@ static struct gpmc_settings tusb_sync = {
 
 /* NOTE:  timings are from tusb 6010 datasheet Rev 1.8, 12-Sept 2006 */
 
-static int tusb_set_async_mode(unsigned sysclk_ps)
+static void tusb_get_async_timings(unsigned sysclk_ps,
+				   struct gpmc_device_timings *dev_t)
 {
-	struct gpmc_device_timings dev_t;
-	struct gpmc_timings	t;
-	unsigned		t_acsnh_advnh = sysclk_ps + 3000;
-
-	memset(&dev_t, 0, sizeof(dev_t));
-
-	dev_t.t_ceasu = 8 * 1000;
-	dev_t.t_avdasu = t_acsnh_advnh - 7000;
-	dev_t.t_ce_avd = 1000;
-	dev_t.t_avdp_r = t_acsnh_advnh;
-	dev_t.t_oeasu = t_acsnh_advnh + 1000;
-	dev_t.t_oe = 300;
-	dev_t.t_cez_r = 7000;
-	dev_t.t_cez_w = dev_t.t_cez_r;
-	dev_t.t_avdp_w = t_acsnh_advnh;
-	dev_t.t_weasu = t_acsnh_advnh + 1000;
-	dev_t.t_wpl = 300;
-	dev_t.cyc_aavdh_we = 1;
-
-	gpmc_calc_timings(&t, &tusb_async, &dev_t);
-
-	return gpmc_cs_set_timings(async_cs, &t);
+	unsigned t_acsnh_advnh = sysclk_ps + 3000;
+
+	memset(dev_t, 0, sizeof(*dev_t));
+
+	dev_t->t_ceasu = 8 * 1000;
+	dev_t->t_avdasu = t_acsnh_advnh - 7000;
+	dev_t->t_ce_avd = 1000;
+	dev_t->t_avdp_r = t_acsnh_advnh;
+	dev_t->t_oeasu = t_acsnh_advnh + 1000;
+	dev_t->t_oe = 300;
+	dev_t->t_cez_r = 7000;
+	dev_t->t_cez_w = dev_t->t_cez_r;
+	dev_t->t_avdp_w = t_acsnh_advnh;
+	dev_t->t_weasu = t_acsnh_advnh + 1000;
+	dev_t->t_wpl = 300;
+	dev_t->cyc_aavdh_we = 1;
 }
 
-static int tusb_set_sync_mode(unsigned sysclk_ps)
+static void tusb_get_sync_timings(unsigned sysclk_ps,
+				  struct gpmc_device_timings *dev_t)
 {
-	struct gpmc_device_timings dev_t;
-	struct gpmc_timings	t;
-	unsigned		t_scsnh_advnh = sysclk_ps + 3000;
-
-	memset(&dev_t, 0, sizeof(dev_t));
-
-	dev_t.clk = 11100;
-	dev_t.t_bacc = 1000;
-	dev_t.t_ces = 1000;
-	dev_t.t_ceasu = 8 * 1000;
-	dev_t.t_avdasu = t_scsnh_advnh - 7000;
-	dev_t.t_ce_avd = 1000;
-	dev_t.t_avdp_r = t_scsnh_advnh;
-	dev_t.cyc_aavdh_oe = 3;
-	dev_t.cyc_oe = 5;
-	dev_t.t_ce_rdyz = 7000;
-	dev_t.t_avdp_w = t_scsnh_advnh;
-	dev_t.cyc_aavdh_we = 3;
-	dev_t.cyc_wpl = 6;
-	dev_t.t_ce_rdyz = 7000;
-
-	gpmc_calc_timings(&t, &tusb_sync, &dev_t);
-
-	return gpmc_cs_set_timings(sync_cs, &t);
+	unsigned t_scsnh_advnh = sysclk_ps + 3000;
+
+	memset(dev_t, 0, sizeof(dev_t));
+
+	dev_t->clk = 11100;
+	dev_t->t_bacc = 1000;
+	dev_t->t_ces = 1000;
+	dev_t->t_ceasu = 8 * 1000;
+	dev_t->t_avdasu = t_scsnh_advnh - 7000;
+	dev_t->t_ce_avd = 1000;
+	dev_t->t_avdp_r = t_scsnh_advnh;
+	dev_t->cyc_aavdh_oe = 3;
+	dev_t->cyc_oe = 5;
+	dev_t->t_ce_rdyz = 7000;
+	dev_t->t_avdp_w = t_scsnh_advnh;
+	dev_t->cyc_aavdh_we = 3;
+	dev_t->cyc_wpl = 6;
+	dev_t->t_ce_rdyz = 7000;
 }
 
 /* tusb driver calls this when it changes the chip's clocking */
@@ -110,18 +100,22 @@ int tusb6010_platform_retime(unsigned is_refclk)
 
 	unsigned	sysclk_ps;
 	int		status;
+	struct gpmc_device_timings dev_t;
 
 	if (!refclk_psec)
 		return -ENODEV;
 
 	sysclk_ps = is_refclk ? refclk_psec : TUSB6010_OSCCLK_60;
 
-	status = tusb_set_async_mode(sysclk_ps);
+	tusb_get_async_timings(sysclk_ps, &dev_t);
+	status = omap_gpmc_retime(async_cs, &tusb_async, &dev_t);
 	if (status < 0) {
 		printk(error, "async", status);
 		goto done;
 	}
-	status = tusb_set_sync_mode(sysclk_ps);
+
+	tusb_get_sync_timings(sysclk_ps, &dev_t);
+	status = omap_gpmc_retime(sync_cs, &tusb_sync, &dev_t);
 	if (status < 0)
 		printk(error, "sync", status);
 done:
-- 
1.8.3.2

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

* [PATCH 27/36] ARM: OMAP2+: usb-tusb6010: Use omap_gpmc_retime()
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, Felipe Balbi, kyungmin.park,
	linux-mtd, pekon, ezequiel.garcia, javier, linux-omap,
	Roger Quadros

In order to change the GPMC settings/timings on the fly,
we must use omap_gpmc_retime(). The other gpmc_*() functions
will soon be made private and moved out of arch/mach-omap2/

CC: Felipe Balbi <balbi@ti.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/usb-tusb6010.c | 94 ++++++++++++++++++--------------------
 1 file changed, 44 insertions(+), 50 deletions(-)

diff --git a/arch/arm/mach-omap2/usb-tusb6010.c b/arch/arm/mach-omap2/usb-tusb6010.c
index e832bc7..71e6246 100644
--- a/arch/arm/mach-omap2/usb-tusb6010.c
+++ b/arch/arm/mach-omap2/usb-tusb6010.c
@@ -48,58 +48,48 @@ static struct gpmc_settings tusb_sync = {
 
 /* NOTE:  timings are from tusb 6010 datasheet Rev 1.8, 12-Sept 2006 */
 
-static int tusb_set_async_mode(unsigned sysclk_ps)
+static void tusb_get_async_timings(unsigned sysclk_ps,
+				   struct gpmc_device_timings *dev_t)
 {
-	struct gpmc_device_timings dev_t;
-	struct gpmc_timings	t;
-	unsigned		t_acsnh_advnh = sysclk_ps + 3000;
-
-	memset(&dev_t, 0, sizeof(dev_t));
-
-	dev_t.t_ceasu = 8 * 1000;
-	dev_t.t_avdasu = t_acsnh_advnh - 7000;
-	dev_t.t_ce_avd = 1000;
-	dev_t.t_avdp_r = t_acsnh_advnh;
-	dev_t.t_oeasu = t_acsnh_advnh + 1000;
-	dev_t.t_oe = 300;
-	dev_t.t_cez_r = 7000;
-	dev_t.t_cez_w = dev_t.t_cez_r;
-	dev_t.t_avdp_w = t_acsnh_advnh;
-	dev_t.t_weasu = t_acsnh_advnh + 1000;
-	dev_t.t_wpl = 300;
-	dev_t.cyc_aavdh_we = 1;
-
-	gpmc_calc_timings(&t, &tusb_async, &dev_t);
-
-	return gpmc_cs_set_timings(async_cs, &t);
+	unsigned t_acsnh_advnh = sysclk_ps + 3000;
+
+	memset(dev_t, 0, sizeof(*dev_t));
+
+	dev_t->t_ceasu = 8 * 1000;
+	dev_t->t_avdasu = t_acsnh_advnh - 7000;
+	dev_t->t_ce_avd = 1000;
+	dev_t->t_avdp_r = t_acsnh_advnh;
+	dev_t->t_oeasu = t_acsnh_advnh + 1000;
+	dev_t->t_oe = 300;
+	dev_t->t_cez_r = 7000;
+	dev_t->t_cez_w = dev_t->t_cez_r;
+	dev_t->t_avdp_w = t_acsnh_advnh;
+	dev_t->t_weasu = t_acsnh_advnh + 1000;
+	dev_t->t_wpl = 300;
+	dev_t->cyc_aavdh_we = 1;
 }
 
-static int tusb_set_sync_mode(unsigned sysclk_ps)
+static void tusb_get_sync_timings(unsigned sysclk_ps,
+				  struct gpmc_device_timings *dev_t)
 {
-	struct gpmc_device_timings dev_t;
-	struct gpmc_timings	t;
-	unsigned		t_scsnh_advnh = sysclk_ps + 3000;
-
-	memset(&dev_t, 0, sizeof(dev_t));
-
-	dev_t.clk = 11100;
-	dev_t.t_bacc = 1000;
-	dev_t.t_ces = 1000;
-	dev_t.t_ceasu = 8 * 1000;
-	dev_t.t_avdasu = t_scsnh_advnh - 7000;
-	dev_t.t_ce_avd = 1000;
-	dev_t.t_avdp_r = t_scsnh_advnh;
-	dev_t.cyc_aavdh_oe = 3;
-	dev_t.cyc_oe = 5;
-	dev_t.t_ce_rdyz = 7000;
-	dev_t.t_avdp_w = t_scsnh_advnh;
-	dev_t.cyc_aavdh_we = 3;
-	dev_t.cyc_wpl = 6;
-	dev_t.t_ce_rdyz = 7000;
-
-	gpmc_calc_timings(&t, &tusb_sync, &dev_t);
-
-	return gpmc_cs_set_timings(sync_cs, &t);
+	unsigned t_scsnh_advnh = sysclk_ps + 3000;
+
+	memset(dev_t, 0, sizeof(dev_t));
+
+	dev_t->clk = 11100;
+	dev_t->t_bacc = 1000;
+	dev_t->t_ces = 1000;
+	dev_t->t_ceasu = 8 * 1000;
+	dev_t->t_avdasu = t_scsnh_advnh - 7000;
+	dev_t->t_ce_avd = 1000;
+	dev_t->t_avdp_r = t_scsnh_advnh;
+	dev_t->cyc_aavdh_oe = 3;
+	dev_t->cyc_oe = 5;
+	dev_t->t_ce_rdyz = 7000;
+	dev_t->t_avdp_w = t_scsnh_advnh;
+	dev_t->cyc_aavdh_we = 3;
+	dev_t->cyc_wpl = 6;
+	dev_t->t_ce_rdyz = 7000;
 }
 
 /* tusb driver calls this when it changes the chip's clocking */
@@ -110,18 +100,22 @@ int tusb6010_platform_retime(unsigned is_refclk)
 
 	unsigned	sysclk_ps;
 	int		status;
+	struct gpmc_device_timings dev_t;
 
 	if (!refclk_psec)
 		return -ENODEV;
 
 	sysclk_ps = is_refclk ? refclk_psec : TUSB6010_OSCCLK_60;
 
-	status = tusb_set_async_mode(sysclk_ps);
+	tusb_get_async_timings(sysclk_ps, &dev_t);
+	status = omap_gpmc_retime(async_cs, &tusb_async, &dev_t);
 	if (status < 0) {
 		printk(error, "async", status);
 		goto done;
 	}
-	status = tusb_set_sync_mode(sysclk_ps);
+
+	tusb_get_sync_timings(sysclk_ps, &dev_t);
+	status = omap_gpmc_retime(sync_cs, &tusb_sync, &dev_t);
 	if (status < 0)
 		printk(error, "sync", status);
 done:
-- 
1.8.3.2

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

* [PATCH 28/36] ARM: OMAP2+: nand: Update gpmc_nand_init() to use generic_gpmc_init()
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

This function should only be called by board init code for
legacy boot.

Re-arrange init order so that gpmc device is created after
the gpmc platform data is initialized by board files.
i.e. move omap_gpmc_init() to subsys_initcall.

Load gpmc platform driver later in the boot process.
i.e. move gpmc_init() to module_initcall.

NOTE: this will break legacy boot since they call gpmc_cs_*()
functions before gpmc_mem_init() is called. They will eventually
be fixed.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-nand.c | 51 ++++++++---------------------------------
 arch/arm/mach-omap2/gpmc.c      | 17 +++++++++-----
 2 files changed, 21 insertions(+), 47 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index f7491d0..42371e3 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -25,9 +25,12 @@
 #define	NAND_IO_SIZE	4
 
 static struct resource gpmc_nand_resource[] = {
+/* GPMC driver will fixup all the resources, see gpmc_probe_legacy () */
 	{
 		/* GPMC I/O space */
 		.flags		= IORESOURCE_MEM,
+		.start		= 0,
+		.end		= NAND_IO_SIZE - 1,
 	},
 	{
 		/* GPMC register space */
@@ -95,61 +98,27 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 {
 	int err	= 0;
 	struct gpmc_settings s;
-	struct device *dev = &gpmc_nand_device.dev;
-	struct resource res;
 
 	memset(&s, 0, sizeof(struct gpmc_settings));
 
 	gpmc_nand_device.dev.platform_data = gpmc_nand_data;
 
-	err = gpmc_cs_request(gpmc_nand_data->cs, NAND_IO_SIZE,
-				(unsigned long *)&gpmc_nand_resource[0].start);
-	if (err < 0) {
-		dev_err(dev, "Cannot request GPMC CS %d, error %d\n",
-			gpmc_nand_data->cs, err);
-		return err;
-	}
-
-	gpmc_nand_resource[0].end = gpmc_nand_resource[0].start +
-							NAND_IO_SIZE - 1;
-
-	gpmc_get_mem_resource(&res);
-	gpmc_nand_resource[1].start = res.start;
-	gpmc_nand_resource[1].end = res.end;
-
-	gpmc_nand_resource[2].start = gpmc_get_irq();
-
-	if (gpmc_t) {
-		err = gpmc_cs_set_timings(gpmc_nand_data->cs, gpmc_t);
-		if (err < 0) {
-			dev_err(dev, "Unable to set gpmc timings: %d\n", err);
-			return err;
-		}
-	}
-
 	gpmc_set_legacy(gpmc_nand_data, &s);
 
 	s.device_nand = true;
 
-	err = gpmc_cs_program_settings(gpmc_nand_data->cs, &s);
-	if (err < 0)
-		goto out_free_cs;
-
 	if (!gpmc_hwecc_bch_capable(gpmc_nand_data->ecc_opt)) {
-		dev_err(dev, "Unsupported NAND ECC scheme selected\n");
+		pr_err("%s: Unsupported NAND ECC scheme selected\n", __func__);
 		return -EINVAL;
 	}
 
-	err = platform_device_register(&gpmc_nand_device);
-	if (err < 0) {
-		dev_err(dev, "Unable to register NAND device\n");
-		goto out_free_cs;
+	err = gpmc_generic_init(gpmc_nand_data->cs, true,
+				&s, NULL, gpmc_t,
+				&gpmc_nand_device, sizeof(*gpmc_nand_data));
+	if (err) {
+		pr_err("%s: gpmc_generic_init() failed %d\n", __func__, err);
+		return err;
 	}
 
 	return 0;
-
-out_free_cs:
-	gpmc_cs_free(gpmc_nand_data->cs);
-
-	return err;
 }
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 34545ca..7a667ca 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1401,9 +1401,6 @@ static void gpmc_probe_legacy(struct platform_device *pdev)
 	gpmc_cs_num = GPMC_CS_NUM;
 	gpmc_nr_waitpins = GPMC_NR_WAITPINS;
 
-	if (!gpmc_pdata)
-		return;
-
 	for (i = 0; i < GPMC_CS_NUM; i++) {
 		cs = &gpmc_pdata->cs[i];
 		if (!cs->valid)
@@ -1609,6 +1606,12 @@ static int gpmc_probe(struct platform_device *pdev)
 		}
 	} else {
 		/* Legacy probing based on platform data */
+		if (!dev->platform_data) {
+			dev_err(dev, "No platform data\n");
+			rc = -EINVAL;
+			goto error;
+		}
+
 		gpmc_probe_legacy(pdev);
 	}
 
@@ -1669,7 +1672,7 @@ static __exit void gpmc_exit(void)
 
 }
 
-omap_postcore_initcall(gpmc_init);
+module_init(gpmc_init);
 module_exit(gpmc_exit);
 
 static int __init omap_gpmc_init(void)
@@ -1691,12 +1694,14 @@ static int __init omap_gpmc_init(void)
 		return -ENODEV;
 	}
 
-	pdev = omap_device_build(DEVICE_NAME, -1, oh, NULL, 0);
+	pdev = omap_device_build(DEVICE_NAME, -1, oh, (void *)&gpmc_pdata,
+				 sizeof(gpmc_pdata));
 	WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
 
 	return PTR_RET(pdev);
 }
-omap_postcore_initcall(omap_gpmc_init);
+/* must run after machine_init code. i.e. arch_init */
+omap_subsys_initcall(omap_gpmc_init);
 
 /**
  * gpmc_generic_init - Initialize platform data for a Chip Select
-- 
1.8.3.2


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

* [PATCH 28/36] ARM: OMAP2+: nand: Update gpmc_nand_init() to use generic_gpmc_init()
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

This function should only be called by board init code for
legacy boot.

Re-arrange init order so that gpmc device is created after
the gpmc platform data is initialized by board files.
i.e. move omap_gpmc_init() to subsys_initcall.

Load gpmc platform driver later in the boot process.
i.e. move gpmc_init() to module_initcall.

NOTE: this will break legacy boot since they call gpmc_cs_*()
functions before gpmc_mem_init() is called. They will eventually
be fixed.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-nand.c | 51 ++++++++---------------------------------
 arch/arm/mach-omap2/gpmc.c      | 17 +++++++++-----
 2 files changed, 21 insertions(+), 47 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index f7491d0..42371e3 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -25,9 +25,12 @@
 #define	NAND_IO_SIZE	4
 
 static struct resource gpmc_nand_resource[] = {
+/* GPMC driver will fixup all the resources, see gpmc_probe_legacy () */
 	{
 		/* GPMC I/O space */
 		.flags		= IORESOURCE_MEM,
+		.start		= 0,
+		.end		= NAND_IO_SIZE - 1,
 	},
 	{
 		/* GPMC register space */
@@ -95,61 +98,27 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 {
 	int err	= 0;
 	struct gpmc_settings s;
-	struct device *dev = &gpmc_nand_device.dev;
-	struct resource res;
 
 	memset(&s, 0, sizeof(struct gpmc_settings));
 
 	gpmc_nand_device.dev.platform_data = gpmc_nand_data;
 
-	err = gpmc_cs_request(gpmc_nand_data->cs, NAND_IO_SIZE,
-				(unsigned long *)&gpmc_nand_resource[0].start);
-	if (err < 0) {
-		dev_err(dev, "Cannot request GPMC CS %d, error %d\n",
-			gpmc_nand_data->cs, err);
-		return err;
-	}
-
-	gpmc_nand_resource[0].end = gpmc_nand_resource[0].start +
-							NAND_IO_SIZE - 1;
-
-	gpmc_get_mem_resource(&res);
-	gpmc_nand_resource[1].start = res.start;
-	gpmc_nand_resource[1].end = res.end;
-
-	gpmc_nand_resource[2].start = gpmc_get_irq();
-
-	if (gpmc_t) {
-		err = gpmc_cs_set_timings(gpmc_nand_data->cs, gpmc_t);
-		if (err < 0) {
-			dev_err(dev, "Unable to set gpmc timings: %d\n", err);
-			return err;
-		}
-	}
-
 	gpmc_set_legacy(gpmc_nand_data, &s);
 
 	s.device_nand = true;
 
-	err = gpmc_cs_program_settings(gpmc_nand_data->cs, &s);
-	if (err < 0)
-		goto out_free_cs;
-
 	if (!gpmc_hwecc_bch_capable(gpmc_nand_data->ecc_opt)) {
-		dev_err(dev, "Unsupported NAND ECC scheme selected\n");
+		pr_err("%s: Unsupported NAND ECC scheme selected\n", __func__);
 		return -EINVAL;
 	}
 
-	err = platform_device_register(&gpmc_nand_device);
-	if (err < 0) {
-		dev_err(dev, "Unable to register NAND device\n");
-		goto out_free_cs;
+	err = gpmc_generic_init(gpmc_nand_data->cs, true,
+				&s, NULL, gpmc_t,
+				&gpmc_nand_device, sizeof(*gpmc_nand_data));
+	if (err) {
+		pr_err("%s: gpmc_generic_init() failed %d\n", __func__, err);
+		return err;
 	}
 
 	return 0;
-
-out_free_cs:
-	gpmc_cs_free(gpmc_nand_data->cs);
-
-	return err;
 }
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 34545ca..7a667ca 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1401,9 +1401,6 @@ static void gpmc_probe_legacy(struct platform_device *pdev)
 	gpmc_cs_num = GPMC_CS_NUM;
 	gpmc_nr_waitpins = GPMC_NR_WAITPINS;
 
-	if (!gpmc_pdata)
-		return;
-
 	for (i = 0; i < GPMC_CS_NUM; i++) {
 		cs = &gpmc_pdata->cs[i];
 		if (!cs->valid)
@@ -1609,6 +1606,12 @@ static int gpmc_probe(struct platform_device *pdev)
 		}
 	} else {
 		/* Legacy probing based on platform data */
+		if (!dev->platform_data) {
+			dev_err(dev, "No platform data\n");
+			rc = -EINVAL;
+			goto error;
+		}
+
 		gpmc_probe_legacy(pdev);
 	}
 
@@ -1669,7 +1672,7 @@ static __exit void gpmc_exit(void)
 
 }
 
-omap_postcore_initcall(gpmc_init);
+module_init(gpmc_init);
 module_exit(gpmc_exit);
 
 static int __init omap_gpmc_init(void)
@@ -1691,12 +1694,14 @@ static int __init omap_gpmc_init(void)
 		return -ENODEV;
 	}
 
-	pdev = omap_device_build(DEVICE_NAME, -1, oh, NULL, 0);
+	pdev = omap_device_build(DEVICE_NAME, -1, oh, (void *)&gpmc_pdata,
+				 sizeof(gpmc_pdata));
 	WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
 
 	return PTR_RET(pdev);
 }
-omap_postcore_initcall(omap_gpmc_init);
+/* must run after machine_init code. i.e. arch_init */
+omap_subsys_initcall(omap_gpmc_init);
 
 /**
  * gpmc_generic_init - Initialize platform data for a Chip Select
-- 
1.8.3.2


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

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

* [PATCH 28/36] ARM: OMAP2+: nand: Update gpmc_nand_init() to use generic_gpmc_init()
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

This function should only be called by board init code for
legacy boot.

Re-arrange init order so that gpmc device is created after
the gpmc platform data is initialized by board files.
i.e. move omap_gpmc_init() to subsys_initcall.

Load gpmc platform driver later in the boot process.
i.e. move gpmc_init() to module_initcall.

NOTE: this will break legacy boot since they call gpmc_cs_*()
functions before gpmc_mem_init() is called. They will eventually
be fixed.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-nand.c | 51 ++++++++---------------------------------
 arch/arm/mach-omap2/gpmc.c      | 17 +++++++++-----
 2 files changed, 21 insertions(+), 47 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index f7491d0..42371e3 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -25,9 +25,12 @@
 #define	NAND_IO_SIZE	4
 
 static struct resource gpmc_nand_resource[] = {
+/* GPMC driver will fixup all the resources, see gpmc_probe_legacy () */
 	{
 		/* GPMC I/O space */
 		.flags		= IORESOURCE_MEM,
+		.start		= 0,
+		.end		= NAND_IO_SIZE - 1,
 	},
 	{
 		/* GPMC register space */
@@ -95,61 +98,27 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 {
 	int err	= 0;
 	struct gpmc_settings s;
-	struct device *dev = &gpmc_nand_device.dev;
-	struct resource res;
 
 	memset(&s, 0, sizeof(struct gpmc_settings));
 
 	gpmc_nand_device.dev.platform_data = gpmc_nand_data;
 
-	err = gpmc_cs_request(gpmc_nand_data->cs, NAND_IO_SIZE,
-				(unsigned long *)&gpmc_nand_resource[0].start);
-	if (err < 0) {
-		dev_err(dev, "Cannot request GPMC CS %d, error %d\n",
-			gpmc_nand_data->cs, err);
-		return err;
-	}
-
-	gpmc_nand_resource[0].end = gpmc_nand_resource[0].start +
-							NAND_IO_SIZE - 1;
-
-	gpmc_get_mem_resource(&res);
-	gpmc_nand_resource[1].start = res.start;
-	gpmc_nand_resource[1].end = res.end;
-
-	gpmc_nand_resource[2].start = gpmc_get_irq();
-
-	if (gpmc_t) {
-		err = gpmc_cs_set_timings(gpmc_nand_data->cs, gpmc_t);
-		if (err < 0) {
-			dev_err(dev, "Unable to set gpmc timings: %d\n", err);
-			return err;
-		}
-	}
-
 	gpmc_set_legacy(gpmc_nand_data, &s);
 
 	s.device_nand = true;
 
-	err = gpmc_cs_program_settings(gpmc_nand_data->cs, &s);
-	if (err < 0)
-		goto out_free_cs;
-
 	if (!gpmc_hwecc_bch_capable(gpmc_nand_data->ecc_opt)) {
-		dev_err(dev, "Unsupported NAND ECC scheme selected\n");
+		pr_err("%s: Unsupported NAND ECC scheme selected\n", __func__);
 		return -EINVAL;
 	}
 
-	err = platform_device_register(&gpmc_nand_device);
-	if (err < 0) {
-		dev_err(dev, "Unable to register NAND device\n");
-		goto out_free_cs;
+	err = gpmc_generic_init(gpmc_nand_data->cs, true,
+				&s, NULL, gpmc_t,
+				&gpmc_nand_device, sizeof(*gpmc_nand_data));
+	if (err) {
+		pr_err("%s: gpmc_generic_init() failed %d\n", __func__, err);
+		return err;
 	}
 
 	return 0;
-
-out_free_cs:
-	gpmc_cs_free(gpmc_nand_data->cs);
-
-	return err;
 }
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 34545ca..7a667ca 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1401,9 +1401,6 @@ static void gpmc_probe_legacy(struct platform_device *pdev)
 	gpmc_cs_num = GPMC_CS_NUM;
 	gpmc_nr_waitpins = GPMC_NR_WAITPINS;
 
-	if (!gpmc_pdata)
-		return;
-
 	for (i = 0; i < GPMC_CS_NUM; i++) {
 		cs = &gpmc_pdata->cs[i];
 		if (!cs->valid)
@@ -1609,6 +1606,12 @@ static int gpmc_probe(struct platform_device *pdev)
 		}
 	} else {
 		/* Legacy probing based on platform data */
+		if (!dev->platform_data) {
+			dev_err(dev, "No platform data\n");
+			rc = -EINVAL;
+			goto error;
+		}
+
 		gpmc_probe_legacy(pdev);
 	}
 
@@ -1669,7 +1672,7 @@ static __exit void gpmc_exit(void)
 
 }
 
-omap_postcore_initcall(gpmc_init);
+module_init(gpmc_init);
 module_exit(gpmc_exit);
 
 static int __init omap_gpmc_init(void)
@@ -1691,12 +1694,14 @@ static int __init omap_gpmc_init(void)
 		return -ENODEV;
 	}
 
-	pdev = omap_device_build(DEVICE_NAME, -1, oh, NULL, 0);
+	pdev = omap_device_build(DEVICE_NAME, -1, oh, (void *)&gpmc_pdata,
+				 sizeof(gpmc_pdata));
 	WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
 
 	return PTR_RET(pdev);
 }
-omap_postcore_initcall(omap_gpmc_init);
+/* must run after machine_init code. i.e. arch_init */
+omap_subsys_initcall(omap_gpmc_init);
 
 /**
  * gpmc_generic_init - Initialize platform data for a Chip Select
-- 
1.8.3.2

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

* [PATCH 29/36] ARM: OMAP2+: gpmc-smc91x: Use gpmc_generic_init()
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Don't access any GPMC registers here. Use gpmc_generic_init()
to pass GPMC Chip Select settings, platform device and platform data
to the GPMC driver.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-smc91x.c | 50 +++++++++++++++------------------------
 1 file changed, 19 insertions(+), 31 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-smc91x.c b/arch/arm/mach-omap2/gpmc-smc91x.c
index 7f5d84a..4ac0d4d 100644
--- a/arch/arm/mach-omap2/gpmc-smc91x.c
+++ b/arch/arm/mach-omap2/gpmc-smc91x.c
@@ -25,8 +25,11 @@
 static struct omap_smc91x_platform_data *gpmc_cfg;
 
 static struct resource gpmc_smc91x_resources[] = {
+/* GPMC driver will fixup the 1st memory resource, see gpmc_probe_legacy () */
 	[0] = {
 		.flags		= IORESOURCE_MEM,
+		.start		= 0,
+		.end		= 0xf,
 	},
 	[1] = {
 		.flags		= IORESOURCE_IRQ,
@@ -92,21 +95,11 @@ static void smc91c96_get_device_timing(struct gpmc_device_timings *dev_t)
  */
 void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data)
 {
-	unsigned long cs_mem_base;
 	int ret;
 	struct gpmc_device_timings dev_t;
 
 	gpmc_cfg = board_data;
 
-	if (gpmc_cs_request(gpmc_cfg->cs, SZ_16M, &cs_mem_base) < 0) {
-		printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
-		return;
-	}
-
-	gpmc_smc91x_resources[0].start = cs_mem_base + 0x300;
-	gpmc_smc91x_resources[0].end = cs_mem_base + 0x30f;
-	gpmc_smc91x_resources[1].flags |= (gpmc_cfg->flags & IRQF_TRIGGER_MASK);
-
 	if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)
 		smc91x_settings.mux_add_data = GPMC_MUX_AD;
 	if (gpmc_cfg->flags & GPMC_READ_MON)
@@ -115,34 +108,24 @@ void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data)
 		smc91x_settings.wait_on_write = true;
 	if (gpmc_cfg->wait_pin)
 		smc91x_settings.wait_pin = gpmc_cfg->wait_pin;
-	ret = gpmc_cs_program_settings(gpmc_cfg->cs, &smc91x_settings);
-	if (ret < 0)
-		goto free1;
-
-	if (gpmc_cfg->flags & GPMC_TIMINGS_SMC91C96) {
-		struct gpmc_timings gpmc_t;
 
+	if (gpmc_cfg->flags & GPMC_TIMINGS_SMC91C96)
 		smc91c96_get_device_timing(&dev_t);
-		gpmc_calc_timings(&gpmc_t, &smc91x_settings, &dev_t);
-		if (gpmc_cs_set_timings(gpmc_cfg->cs, &gpmc_t)) {
-			pr_err("%s: failed to set GPMC timings\n", __func__);
-			goto free1;
-		}
-	}
 
 	if (gpio_request_one(gpmc_cfg->gpio_irq, GPIOF_IN, "SMC91X irq") < 0)
 		goto free1;
 
 	gpmc_smc91x_resources[1].start = gpio_to_irq(gpmc_cfg->gpio_irq);
+	gpmc_smc91x_resources[1].flags |= (gpmc_cfg->flags & IRQF_TRIGGER_MASK);
 
-	if (gpmc_cfg->gpio_pwrdwn) {
+	if (gpio_is_valid(gpmc_cfg->gpio_pwrdwn)) {
 		ret = gpio_request_one(gpmc_cfg->gpio_pwrdwn,
 				       GPIOF_OUT_INIT_LOW, "SMC91X powerdown");
 		if (ret)
 			goto free2;
 	}
 
-	if (gpmc_cfg->gpio_reset) {
+	if (gpio_is_valid(gpmc_cfg->gpio_reset)) {
 		ret = gpio_request_one(gpmc_cfg->gpio_reset,
 				       GPIOF_OUT_INIT_LOW, "SMC91X reset");
 		if (ret)
@@ -153,21 +136,26 @@ void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data)
 		gpio_set_value(gpmc_cfg->gpio_reset, 0);
 	}
 
-	if (platform_device_register(&gpmc_smc91x_device) < 0) {
-		printk(KERN_ERR "Unable to register smc91x device\n");
-		gpio_free(gpmc_cfg->gpio_reset);
-		goto free3;
+	ret = gpmc_generic_init(gpmc_cfg->cs, false,
+				&smc91x_settings,
+				gpmc_cfg->flags & GPMC_TIMINGS_SMC91C96 ?
+				&dev_t : NULL, NULL,
+				&gpmc_smc91x_device, sizeof(gpmc_smc91x_info));
+	if (ret) {
+		pr_err("%s: gpmc_generic_init() failed %d\n", __func__, ret);
+		goto free4;
 	}
 
 	return;
 
+free4:
+	if (gpio_is_valid(gpmc_cfg->gpio_reset))
+		gpio_free(gpmc_cfg->gpio_reset);
 free3:
-	if (gpmc_cfg->gpio_pwrdwn)
+	if (gpio_is_valid(gpmc_cfg->gpio_pwrdwn))
 		gpio_free(gpmc_cfg->gpio_pwrdwn);
 free2:
 	gpio_free(gpmc_cfg->gpio_irq);
 free1:
-	gpmc_cs_free(gpmc_cfg->cs);
-
 	printk(KERN_ERR "Could not initialize smc91x\n");
 }
-- 
1.8.3.2


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

* [PATCH 29/36] ARM: OMAP2+: gpmc-smc91x: Use gpmc_generic_init()
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Don't access any GPMC registers here. Use gpmc_generic_init()
to pass GPMC Chip Select settings, platform device and platform data
to the GPMC driver.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-smc91x.c | 50 +++++++++++++++------------------------
 1 file changed, 19 insertions(+), 31 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-smc91x.c b/arch/arm/mach-omap2/gpmc-smc91x.c
index 7f5d84a..4ac0d4d 100644
--- a/arch/arm/mach-omap2/gpmc-smc91x.c
+++ b/arch/arm/mach-omap2/gpmc-smc91x.c
@@ -25,8 +25,11 @@
 static struct omap_smc91x_platform_data *gpmc_cfg;
 
 static struct resource gpmc_smc91x_resources[] = {
+/* GPMC driver will fixup the 1st memory resource, see gpmc_probe_legacy () */
 	[0] = {
 		.flags		= IORESOURCE_MEM,
+		.start		= 0,
+		.end		= 0xf,
 	},
 	[1] = {
 		.flags		= IORESOURCE_IRQ,
@@ -92,21 +95,11 @@ static void smc91c96_get_device_timing(struct gpmc_device_timings *dev_t)
  */
 void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data)
 {
-	unsigned long cs_mem_base;
 	int ret;
 	struct gpmc_device_timings dev_t;
 
 	gpmc_cfg = board_data;
 
-	if (gpmc_cs_request(gpmc_cfg->cs, SZ_16M, &cs_mem_base) < 0) {
-		printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
-		return;
-	}
-
-	gpmc_smc91x_resources[0].start = cs_mem_base + 0x300;
-	gpmc_smc91x_resources[0].end = cs_mem_base + 0x30f;
-	gpmc_smc91x_resources[1].flags |= (gpmc_cfg->flags & IRQF_TRIGGER_MASK);
-
 	if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)
 		smc91x_settings.mux_add_data = GPMC_MUX_AD;
 	if (gpmc_cfg->flags & GPMC_READ_MON)
@@ -115,34 +108,24 @@ void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data)
 		smc91x_settings.wait_on_write = true;
 	if (gpmc_cfg->wait_pin)
 		smc91x_settings.wait_pin = gpmc_cfg->wait_pin;
-	ret = gpmc_cs_program_settings(gpmc_cfg->cs, &smc91x_settings);
-	if (ret < 0)
-		goto free1;
-
-	if (gpmc_cfg->flags & GPMC_TIMINGS_SMC91C96) {
-		struct gpmc_timings gpmc_t;
 
+	if (gpmc_cfg->flags & GPMC_TIMINGS_SMC91C96)
 		smc91c96_get_device_timing(&dev_t);
-		gpmc_calc_timings(&gpmc_t, &smc91x_settings, &dev_t);
-		if (gpmc_cs_set_timings(gpmc_cfg->cs, &gpmc_t)) {
-			pr_err("%s: failed to set GPMC timings\n", __func__);
-			goto free1;
-		}
-	}
 
 	if (gpio_request_one(gpmc_cfg->gpio_irq, GPIOF_IN, "SMC91X irq") < 0)
 		goto free1;
 
 	gpmc_smc91x_resources[1].start = gpio_to_irq(gpmc_cfg->gpio_irq);
+	gpmc_smc91x_resources[1].flags |= (gpmc_cfg->flags & IRQF_TRIGGER_MASK);
 
-	if (gpmc_cfg->gpio_pwrdwn) {
+	if (gpio_is_valid(gpmc_cfg->gpio_pwrdwn)) {
 		ret = gpio_request_one(gpmc_cfg->gpio_pwrdwn,
 				       GPIOF_OUT_INIT_LOW, "SMC91X powerdown");
 		if (ret)
 			goto free2;
 	}
 
-	if (gpmc_cfg->gpio_reset) {
+	if (gpio_is_valid(gpmc_cfg->gpio_reset)) {
 		ret = gpio_request_one(gpmc_cfg->gpio_reset,
 				       GPIOF_OUT_INIT_LOW, "SMC91X reset");
 		if (ret)
@@ -153,21 +136,26 @@ void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data)
 		gpio_set_value(gpmc_cfg->gpio_reset, 0);
 	}
 
-	if (platform_device_register(&gpmc_smc91x_device) < 0) {
-		printk(KERN_ERR "Unable to register smc91x device\n");
-		gpio_free(gpmc_cfg->gpio_reset);
-		goto free3;
+	ret = gpmc_generic_init(gpmc_cfg->cs, false,
+				&smc91x_settings,
+				gpmc_cfg->flags & GPMC_TIMINGS_SMC91C96 ?
+				&dev_t : NULL, NULL,
+				&gpmc_smc91x_device, sizeof(gpmc_smc91x_info));
+	if (ret) {
+		pr_err("%s: gpmc_generic_init() failed %d\n", __func__, ret);
+		goto free4;
 	}
 
 	return;
 
+free4:
+	if (gpio_is_valid(gpmc_cfg->gpio_reset))
+		gpio_free(gpmc_cfg->gpio_reset);
 free3:
-	if (gpmc_cfg->gpio_pwrdwn)
+	if (gpio_is_valid(gpmc_cfg->gpio_pwrdwn))
 		gpio_free(gpmc_cfg->gpio_pwrdwn);
 free2:
 	gpio_free(gpmc_cfg->gpio_irq);
 free1:
-	gpmc_cs_free(gpmc_cfg->cs);
-
 	printk(KERN_ERR "Could not initialize smc91x\n");
 }
-- 
1.8.3.2

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

* [PATCH 29/36] ARM: OMAP2+: gpmc-smc91x: Use gpmc_generic_init()
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Don't access any GPMC registers here. Use gpmc_generic_init()
to pass GPMC Chip Select settings, platform device and platform data
to the GPMC driver.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-smc91x.c | 50 +++++++++++++++------------------------
 1 file changed, 19 insertions(+), 31 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-smc91x.c b/arch/arm/mach-omap2/gpmc-smc91x.c
index 7f5d84a..4ac0d4d 100644
--- a/arch/arm/mach-omap2/gpmc-smc91x.c
+++ b/arch/arm/mach-omap2/gpmc-smc91x.c
@@ -25,8 +25,11 @@
 static struct omap_smc91x_platform_data *gpmc_cfg;
 
 static struct resource gpmc_smc91x_resources[] = {
+/* GPMC driver will fixup the 1st memory resource, see gpmc_probe_legacy () */
 	[0] = {
 		.flags		= IORESOURCE_MEM,
+		.start		= 0,
+		.end		= 0xf,
 	},
 	[1] = {
 		.flags		= IORESOURCE_IRQ,
@@ -92,21 +95,11 @@ static void smc91c96_get_device_timing(struct gpmc_device_timings *dev_t)
  */
 void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data)
 {
-	unsigned long cs_mem_base;
 	int ret;
 	struct gpmc_device_timings dev_t;
 
 	gpmc_cfg = board_data;
 
-	if (gpmc_cs_request(gpmc_cfg->cs, SZ_16M, &cs_mem_base) < 0) {
-		printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
-		return;
-	}
-
-	gpmc_smc91x_resources[0].start = cs_mem_base + 0x300;
-	gpmc_smc91x_resources[0].end = cs_mem_base + 0x30f;
-	gpmc_smc91x_resources[1].flags |= (gpmc_cfg->flags & IRQF_TRIGGER_MASK);
-
 	if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)
 		smc91x_settings.mux_add_data = GPMC_MUX_AD;
 	if (gpmc_cfg->flags & GPMC_READ_MON)
@@ -115,34 +108,24 @@ void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data)
 		smc91x_settings.wait_on_write = true;
 	if (gpmc_cfg->wait_pin)
 		smc91x_settings.wait_pin = gpmc_cfg->wait_pin;
-	ret = gpmc_cs_program_settings(gpmc_cfg->cs, &smc91x_settings);
-	if (ret < 0)
-		goto free1;
-
-	if (gpmc_cfg->flags & GPMC_TIMINGS_SMC91C96) {
-		struct gpmc_timings gpmc_t;
 
+	if (gpmc_cfg->flags & GPMC_TIMINGS_SMC91C96)
 		smc91c96_get_device_timing(&dev_t);
-		gpmc_calc_timings(&gpmc_t, &smc91x_settings, &dev_t);
-		if (gpmc_cs_set_timings(gpmc_cfg->cs, &gpmc_t)) {
-			pr_err("%s: failed to set GPMC timings\n", __func__);
-			goto free1;
-		}
-	}
 
 	if (gpio_request_one(gpmc_cfg->gpio_irq, GPIOF_IN, "SMC91X irq") < 0)
 		goto free1;
 
 	gpmc_smc91x_resources[1].start = gpio_to_irq(gpmc_cfg->gpio_irq);
+	gpmc_smc91x_resources[1].flags |= (gpmc_cfg->flags & IRQF_TRIGGER_MASK);
 
-	if (gpmc_cfg->gpio_pwrdwn) {
+	if (gpio_is_valid(gpmc_cfg->gpio_pwrdwn)) {
 		ret = gpio_request_one(gpmc_cfg->gpio_pwrdwn,
 				       GPIOF_OUT_INIT_LOW, "SMC91X powerdown");
 		if (ret)
 			goto free2;
 	}
 
-	if (gpmc_cfg->gpio_reset) {
+	if (gpio_is_valid(gpmc_cfg->gpio_reset)) {
 		ret = gpio_request_one(gpmc_cfg->gpio_reset,
 				       GPIOF_OUT_INIT_LOW, "SMC91X reset");
 		if (ret)
@@ -153,21 +136,26 @@ void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data)
 		gpio_set_value(gpmc_cfg->gpio_reset, 0);
 	}
 
-	if (platform_device_register(&gpmc_smc91x_device) < 0) {
-		printk(KERN_ERR "Unable to register smc91x device\n");
-		gpio_free(gpmc_cfg->gpio_reset);
-		goto free3;
+	ret = gpmc_generic_init(gpmc_cfg->cs, false,
+				&smc91x_settings,
+				gpmc_cfg->flags & GPMC_TIMINGS_SMC91C96 ?
+				&dev_t : NULL, NULL,
+				&gpmc_smc91x_device, sizeof(gpmc_smc91x_info));
+	if (ret) {
+		pr_err("%s: gpmc_generic_init() failed %d\n", __func__, ret);
+		goto free4;
 	}
 
 	return;
 
+free4:
+	if (gpio_is_valid(gpmc_cfg->gpio_reset))
+		gpio_free(gpmc_cfg->gpio_reset);
 free3:
-	if (gpmc_cfg->gpio_pwrdwn)
+	if (gpio_is_valid(gpmc_cfg->gpio_pwrdwn))
 		gpio_free(gpmc_cfg->gpio_pwrdwn);
 free2:
 	gpio_free(gpmc_cfg->gpio_irq);
 free1:
-	gpmc_cs_free(gpmc_cfg->cs);
-
 	printk(KERN_ERR "Could not initialize smc91x\n");
 }
-- 
1.8.3.2

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

* [PATCH 30/36] ARM: OMAP2+: gpmc-smsc911x: Use gpmc_generic_init()
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Don't access any GPMC registers here. Use gpmc_generic_init()
to pass GPMC Chip Select settings, platform device and platform data
to the GPMC driver.

Some boards use multiple smsc911x devices, so we dynamically
allocate pdev and pdata.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-smsc911x.c | 76 ++++++++++++++++++++++---------------
 1 file changed, 46 insertions(+), 30 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-smsc911x.c b/arch/arm/mach-omap2/gpmc-smsc911x.c
index 2757504..9492db0 100644
--- a/arch/arm/mach-omap2/gpmc-smsc911x.c
+++ b/arch/arm/mach-omap2/gpmc-smsc911x.c
@@ -19,19 +19,11 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/smsc911x.h>
+#include <linux/slab.h>
 
 #include "gpmc.h"
 #include "gpmc-smsc911x.h"
 
-static struct resource gpmc_smsc911x_resources[] = {
-	[0] = {
-		.flags		= IORESOURCE_MEM,
-	},
-	[1] = {
-		.flags		= IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
-	},
-};
-
 static struct smsc911x_platform_config gpmc_smsc911x_config = {
 	.phy_interface	= PHY_INTERFACE_MODE_MII,
 	.irq_polarity	= SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
@@ -45,24 +37,43 @@ static struct smsc911x_platform_config gpmc_smsc911x_config = {
  */
 void __init gpmc_smsc911x_init(struct omap_smsc911x_platform_data *gpmc_cfg)
 {
-	struct platform_device *pdev;
-	unsigned long cs_mem_base;
 	int ret;
+	struct platform_device *pdev;
+	struct resource *res;
+
+	/*
+	 * This function can be called multiple times per board so the platform
+	 * device and resources have to be allocated separately for each
+	 * device.
+	 */
+	pdev = kzalloc(sizeof(*pdev), GFP_KERNEL);
+	if (!pdev)
+		goto fail;
+
+	/* needs 2 resources */
+	res = kzalloc(2 * sizeof(*res), GFP_KERNEL);
+	if (!res)
+		goto free1;
 
-	if (gpmc_cs_request(gpmc_cfg->cs, SZ_16M, &cs_mem_base) < 0) {
-		pr_err("Failed to request GPMC mem region\n");
-		return;
-	}
+	pdev->name = "smsc911x";
+	pdev->id = gpmc_cfg->id;
+	pdev->dev.platform_data = &gpmc_smsc911x_config,
+	pdev->num_resources = 2;
+	pdev->resource = res;
+
+	/* res[0]  Will be relocated by GPMC driver, see gpmc_probe_legacy() */
+	res[0].flags = IORESOURCE_MEM;
+	res[0].start = 0;
+	res[0].end = 0xff;
 
-	gpmc_smsc911x_resources[0].start = cs_mem_base + 0x0;
-	gpmc_smsc911x_resources[0].end = cs_mem_base + 0xff;
 
 	if (gpio_request_one(gpmc_cfg->gpio_irq, GPIOF_IN, "smsc911x irq")) {
 		pr_err("Failed to request IRQ GPIO%d\n", gpmc_cfg->gpio_irq);
-		goto free1;
+		goto free2;
 	}
 
-	gpmc_smsc911x_resources[1].start = gpio_to_irq(gpmc_cfg->gpio_irq);
+	res[1].start = gpio_to_irq(gpmc_cfg->gpio_irq);
+	res[1].flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL;
 
 	if (gpio_is_valid(gpmc_cfg->gpio_reset)) {
 		ret = gpio_request_one(gpmc_cfg->gpio_reset,
@@ -70,7 +81,7 @@ void __init gpmc_smsc911x_init(struct omap_smsc911x_platform_data *gpmc_cfg)
 		if (ret) {
 			pr_err("Failed to request reset GPIO%d\n",
 			       gpmc_cfg->gpio_reset);
-			goto free2;
+			goto free3;
 		}
 
 		gpio_set_value(gpmc_cfg->gpio_reset, 0);
@@ -80,21 +91,26 @@ void __init gpmc_smsc911x_init(struct omap_smsc911x_platform_data *gpmc_cfg)
 
 	gpmc_smsc911x_config.flags = gpmc_cfg->flags ? : SMSC911X_USE_16BIT;
 
-	pdev = platform_device_register_resndata(NULL, "smsc911x", gpmc_cfg->id,
-		 gpmc_smsc911x_resources, ARRAY_SIZE(gpmc_smsc911x_resources),
-		 &gpmc_smsc911x_config, sizeof(gpmc_smsc911x_config));
-	if (IS_ERR(pdev)) {
-		pr_err("Unable to register platform device\n");
-		gpio_free(gpmc_cfg->gpio_reset);
-		goto free2;
+	ret = gpmc_generic_init(gpmc_cfg->cs, false,
+				NULL, NULL, NULL,
+				pdev,
+				sizeof(gpmc_smsc911x_config));
+	if (ret) {
+		pr_err("%s: gpmc_generic_init() failed %d\n", __func__, ret);
+		goto free4;
 	}
 
 	return;
 
-free2:
+free4:
+	if (gpio_is_valid(gpmc_cfg->gpio_reset))
+		gpio_free(gpmc_cfg->gpio_reset);
+free3:
 	gpio_free(gpmc_cfg->gpio_irq);
+free2:
+	kfree(res);
 free1:
-	gpmc_cs_free(gpmc_cfg->cs);
-
+	kfree(pdev);
+fail:
 	pr_err("Could not initialize smsc911x device\n");
 }
-- 
1.8.3.2


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

* [PATCH 30/36] ARM: OMAP2+: gpmc-smsc911x: Use gpmc_generic_init()
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Don't access any GPMC registers here. Use gpmc_generic_init()
to pass GPMC Chip Select settings, platform device and platform data
to the GPMC driver.

Some boards use multiple smsc911x devices, so we dynamically
allocate pdev and pdata.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-smsc911x.c | 76 ++++++++++++++++++++++---------------
 1 file changed, 46 insertions(+), 30 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-smsc911x.c b/arch/arm/mach-omap2/gpmc-smsc911x.c
index 2757504..9492db0 100644
--- a/arch/arm/mach-omap2/gpmc-smsc911x.c
+++ b/arch/arm/mach-omap2/gpmc-smsc911x.c
@@ -19,19 +19,11 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/smsc911x.h>
+#include <linux/slab.h>
 
 #include "gpmc.h"
 #include "gpmc-smsc911x.h"
 
-static struct resource gpmc_smsc911x_resources[] = {
-	[0] = {
-		.flags		= IORESOURCE_MEM,
-	},
-	[1] = {
-		.flags		= IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
-	},
-};
-
 static struct smsc911x_platform_config gpmc_smsc911x_config = {
 	.phy_interface	= PHY_INTERFACE_MODE_MII,
 	.irq_polarity	= SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
@@ -45,24 +37,43 @@ static struct smsc911x_platform_config gpmc_smsc911x_config = {
  */
 void __init gpmc_smsc911x_init(struct omap_smsc911x_platform_data *gpmc_cfg)
 {
-	struct platform_device *pdev;
-	unsigned long cs_mem_base;
 	int ret;
+	struct platform_device *pdev;
+	struct resource *res;
+
+	/*
+	 * This function can be called multiple times per board so the platform
+	 * device and resources have to be allocated separately for each
+	 * device.
+	 */
+	pdev = kzalloc(sizeof(*pdev), GFP_KERNEL);
+	if (!pdev)
+		goto fail;
+
+	/* needs 2 resources */
+	res = kzalloc(2 * sizeof(*res), GFP_KERNEL);
+	if (!res)
+		goto free1;
 
-	if (gpmc_cs_request(gpmc_cfg->cs, SZ_16M, &cs_mem_base) < 0) {
-		pr_err("Failed to request GPMC mem region\n");
-		return;
-	}
+	pdev->name = "smsc911x";
+	pdev->id = gpmc_cfg->id;
+	pdev->dev.platform_data = &gpmc_smsc911x_config,
+	pdev->num_resources = 2;
+	pdev->resource = res;
+
+	/* res[0]  Will be relocated by GPMC driver, see gpmc_probe_legacy() */
+	res[0].flags = IORESOURCE_MEM;
+	res[0].start = 0;
+	res[0].end = 0xff;
 
-	gpmc_smsc911x_resources[0].start = cs_mem_base + 0x0;
-	gpmc_smsc911x_resources[0].end = cs_mem_base + 0xff;
 
 	if (gpio_request_one(gpmc_cfg->gpio_irq, GPIOF_IN, "smsc911x irq")) {
 		pr_err("Failed to request IRQ GPIO%d\n", gpmc_cfg->gpio_irq);
-		goto free1;
+		goto free2;
 	}
 
-	gpmc_smsc911x_resources[1].start = gpio_to_irq(gpmc_cfg->gpio_irq);
+	res[1].start = gpio_to_irq(gpmc_cfg->gpio_irq);
+	res[1].flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL;
 
 	if (gpio_is_valid(gpmc_cfg->gpio_reset)) {
 		ret = gpio_request_one(gpmc_cfg->gpio_reset,
@@ -70,7 +81,7 @@ void __init gpmc_smsc911x_init(struct omap_smsc911x_platform_data *gpmc_cfg)
 		if (ret) {
 			pr_err("Failed to request reset GPIO%d\n",
 			       gpmc_cfg->gpio_reset);
-			goto free2;
+			goto free3;
 		}
 
 		gpio_set_value(gpmc_cfg->gpio_reset, 0);
@@ -80,21 +91,26 @@ void __init gpmc_smsc911x_init(struct omap_smsc911x_platform_data *gpmc_cfg)
 
 	gpmc_smsc911x_config.flags = gpmc_cfg->flags ? : SMSC911X_USE_16BIT;
 
-	pdev = platform_device_register_resndata(NULL, "smsc911x", gpmc_cfg->id,
-		 gpmc_smsc911x_resources, ARRAY_SIZE(gpmc_smsc911x_resources),
-		 &gpmc_smsc911x_config, sizeof(gpmc_smsc911x_config));
-	if (IS_ERR(pdev)) {
-		pr_err("Unable to register platform device\n");
-		gpio_free(gpmc_cfg->gpio_reset);
-		goto free2;
+	ret = gpmc_generic_init(gpmc_cfg->cs, false,
+				NULL, NULL, NULL,
+				pdev,
+				sizeof(gpmc_smsc911x_config));
+	if (ret) {
+		pr_err("%s: gpmc_generic_init() failed %d\n", __func__, ret);
+		goto free4;
 	}
 
 	return;
 
-free2:
+free4:
+	if (gpio_is_valid(gpmc_cfg->gpio_reset))
+		gpio_free(gpmc_cfg->gpio_reset);
+free3:
 	gpio_free(gpmc_cfg->gpio_irq);
+free2:
+	kfree(res);
 free1:
-	gpmc_cs_free(gpmc_cfg->cs);
-
+	kfree(pdev);
+fail:
 	pr_err("Could not initialize smsc911x device\n");
 }
-- 
1.8.3.2


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

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

* [PATCH 30/36] ARM: OMAP2+: gpmc-smsc911x: Use gpmc_generic_init()
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Don't access any GPMC registers here. Use gpmc_generic_init()
to pass GPMC Chip Select settings, platform device and platform data
to the GPMC driver.

Some boards use multiple smsc911x devices, so we dynamically
allocate pdev and pdata.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-smsc911x.c | 76 ++++++++++++++++++++++---------------
 1 file changed, 46 insertions(+), 30 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-smsc911x.c b/arch/arm/mach-omap2/gpmc-smsc911x.c
index 2757504..9492db0 100644
--- a/arch/arm/mach-omap2/gpmc-smsc911x.c
+++ b/arch/arm/mach-omap2/gpmc-smsc911x.c
@@ -19,19 +19,11 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/smsc911x.h>
+#include <linux/slab.h>
 
 #include "gpmc.h"
 #include "gpmc-smsc911x.h"
 
-static struct resource gpmc_smsc911x_resources[] = {
-	[0] = {
-		.flags		= IORESOURCE_MEM,
-	},
-	[1] = {
-		.flags		= IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
-	},
-};
-
 static struct smsc911x_platform_config gpmc_smsc911x_config = {
 	.phy_interface	= PHY_INTERFACE_MODE_MII,
 	.irq_polarity	= SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
@@ -45,24 +37,43 @@ static struct smsc911x_platform_config gpmc_smsc911x_config = {
  */
 void __init gpmc_smsc911x_init(struct omap_smsc911x_platform_data *gpmc_cfg)
 {
-	struct platform_device *pdev;
-	unsigned long cs_mem_base;
 	int ret;
+	struct platform_device *pdev;
+	struct resource *res;
+
+	/*
+	 * This function can be called multiple times per board so the platform
+	 * device and resources have to be allocated separately for each
+	 * device.
+	 */
+	pdev = kzalloc(sizeof(*pdev), GFP_KERNEL);
+	if (!pdev)
+		goto fail;
+
+	/* needs 2 resources */
+	res = kzalloc(2 * sizeof(*res), GFP_KERNEL);
+	if (!res)
+		goto free1;
 
-	if (gpmc_cs_request(gpmc_cfg->cs, SZ_16M, &cs_mem_base) < 0) {
-		pr_err("Failed to request GPMC mem region\n");
-		return;
-	}
+	pdev->name = "smsc911x";
+	pdev->id = gpmc_cfg->id;
+	pdev->dev.platform_data = &gpmc_smsc911x_config,
+	pdev->num_resources = 2;
+	pdev->resource = res;
+
+	/* res[0]  Will be relocated by GPMC driver, see gpmc_probe_legacy() */
+	res[0].flags = IORESOURCE_MEM;
+	res[0].start = 0;
+	res[0].end = 0xff;
 
-	gpmc_smsc911x_resources[0].start = cs_mem_base + 0x0;
-	gpmc_smsc911x_resources[0].end = cs_mem_base + 0xff;
 
 	if (gpio_request_one(gpmc_cfg->gpio_irq, GPIOF_IN, "smsc911x irq")) {
 		pr_err("Failed to request IRQ GPIO%d\n", gpmc_cfg->gpio_irq);
-		goto free1;
+		goto free2;
 	}
 
-	gpmc_smsc911x_resources[1].start = gpio_to_irq(gpmc_cfg->gpio_irq);
+	res[1].start = gpio_to_irq(gpmc_cfg->gpio_irq);
+	res[1].flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL;
 
 	if (gpio_is_valid(gpmc_cfg->gpio_reset)) {
 		ret = gpio_request_one(gpmc_cfg->gpio_reset,
@@ -70,7 +81,7 @@ void __init gpmc_smsc911x_init(struct omap_smsc911x_platform_data *gpmc_cfg)
 		if (ret) {
 			pr_err("Failed to request reset GPIO%d\n",
 			       gpmc_cfg->gpio_reset);
-			goto free2;
+			goto free3;
 		}
 
 		gpio_set_value(gpmc_cfg->gpio_reset, 0);
@@ -80,21 +91,26 @@ void __init gpmc_smsc911x_init(struct omap_smsc911x_platform_data *gpmc_cfg)
 
 	gpmc_smsc911x_config.flags = gpmc_cfg->flags ? : SMSC911X_USE_16BIT;
 
-	pdev = platform_device_register_resndata(NULL, "smsc911x", gpmc_cfg->id,
-		 gpmc_smsc911x_resources, ARRAY_SIZE(gpmc_smsc911x_resources),
-		 &gpmc_smsc911x_config, sizeof(gpmc_smsc911x_config));
-	if (IS_ERR(pdev)) {
-		pr_err("Unable to register platform device\n");
-		gpio_free(gpmc_cfg->gpio_reset);
-		goto free2;
+	ret = gpmc_generic_init(gpmc_cfg->cs, false,
+				NULL, NULL, NULL,
+				pdev,
+				sizeof(gpmc_smsc911x_config));
+	if (ret) {
+		pr_err("%s: gpmc_generic_init() failed %d\n", __func__, ret);
+		goto free4;
 	}
 
 	return;
 
-free2:
+free4:
+	if (gpio_is_valid(gpmc_cfg->gpio_reset))
+		gpio_free(gpmc_cfg->gpio_reset);
+free3:
 	gpio_free(gpmc_cfg->gpio_irq);
+free2:
+	kfree(res);
 free1:
-	gpmc_cs_free(gpmc_cfg->cs);
-
+	kfree(pdev);
+fail:
 	pr_err("Could not initialize smsc911x device\n");
 }
-- 
1.8.3.2

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

* [PATCH 31/36] ARM: OMAP2: usb-tusb6010: Use gpmc_generic_init()
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros,
	Felipe Balbi

Don't access any GPMC registers here. Use gpmc_generic_init()
to pass GPMC Chip Select settings, platform device and platform data
to the GPMC driver.

CC: Felipe Balbi <balbi@ti.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/usb-tusb6010.c | 78 +++++++++++++++++++-------------------
 1 file changed, 39 insertions(+), 39 deletions(-)

diff --git a/arch/arm/mach-omap2/usb-tusb6010.c b/arch/arm/mach-omap2/usb-tusb6010.c
index 71e6246..d28f5cd 100644
--- a/arch/arm/mach-omap2/usb-tusb6010.c
+++ b/arch/arm/mach-omap2/usb-tusb6010.c
@@ -125,13 +125,17 @@ EXPORT_SYMBOL_GPL(tusb6010_platform_retime);
 
 static struct resource tusb_resources[] = {
 	/* Order is significant!  The start/end fields
-	 * are updated during setup..
+	 * are updated by GPMC driver, see gpmc_probe_legacy()
 	 */
-	{ /* Asynchronous access */
-		.flags	= IORESOURCE_MEM,
+	{ /* Asynchronous access, for PIO */
+		.flags = IORESOURCE_MEM,
+		.start = 0,
+		.end = 0x9ff,
 	},
-	{ /* Synchronous access */
-		.flags	= IORESOURCE_MEM,
+	{ /* Synchronous access, for DMA */
+		.flags = IORESOURCE_MEM,
+		.start = 0,
+		.end = 0x9ff,
 	},
 	{ /* IRQ */
 		.name	= "mc",
@@ -163,37 +167,16 @@ tusb6010_setup_interface(struct musb_hdrc_platform_data *data,
 	int		status;
 	static char	error[] __initdata =
 		KERN_ERR "tusb6010 init error %d, %d\n";
+	struct gpmc_device_timings dev_async_t;
+	struct gpmc_device_timings dev_sync_t;
 
-	/* ASYNC region, primarily for PIO */
-	status = gpmc_cs_request(async, SZ_16M, (unsigned long *)
-				&tusb_resources[0].start);
-	if (status < 0) {
-		printk(error, 1, status);
-		return status;
-	}
-	tusb_resources[0].end = tusb_resources[0].start + 0x9ff;
+	/* GPMC settings */
 	tusb_async.wait_pin = waitpin;
 	async_cs = async;
 
-	status = gpmc_cs_program_settings(async_cs, &tusb_async);
-	if (status < 0)
-		return status;
-
-	/* SYNC region, primarily for DMA */
-	status = gpmc_cs_request(sync, SZ_16M, (unsigned long *)
-				&tusb_resources[1].start);
-	if (status < 0) {
-		printk(error, 2, status);
-		return status;
-	}
-	tusb_resources[1].end = tusb_resources[1].start + 0x9ff;
 	tusb_sync.wait_pin = waitpin;
 	sync_cs = sync;
 
-	status = gpmc_cs_program_settings(sync_cs, &tusb_sync);
-	if (status < 0)
-		return status;
-
 	/* IRQ */
 	status = gpio_request_one(irq, GPIOF_IN, "TUSB6010 irq");
 	if (status < 0) {
@@ -208,11 +191,10 @@ tusb6010_setup_interface(struct musb_hdrc_platform_data *data,
 		return -ENODEV;
 	}
 	refclk_psec = ps_refclk;
-	status = tusb6010_platform_retime(1);
-	if (status < 0) {
-		printk(error, 5, status);
-		return status;
-	}
+
+	/* device timings */
+	tusb_get_async_timings(ps_refclk, &dev_async_t);
+	tusb_get_sync_timings(ps_refclk, &dev_sync_t);
 
 	/* finish device setup ... */
 	if (!data) {
@@ -240,11 +222,29 @@ tusb6010_setup_interface(struct musb_hdrc_platform_data *data,
 			omap_mux_init_signal("sys_ndmareq5", 0);
 	}
 
-	/* so far so good ... register the device */
-	status = platform_device_register(&tusb_device);
-	if (status < 0) {
-		printk(error, 7, status);
-		return status;
+	/* Register ASYNC region */
+	status = gpmc_generic_init(async_cs, false,
+				   &tusb_async, &dev_async_t, NULL,
+				   &tusb_device, sizeof(*data));
+
+	if (status) {
+		pr_err("%s: failed to register ASYNC region\n", __func__);
+		goto fail;
 	}
+
+	/* Register SYNC region */
+	status = gpmc_generic_init(sync_cs, false,
+				   &tusb_sync, &dev_sync_t, NULL,
+				   &tusb_device, sizeof(*data));
+	if (status) {
+		pr_err("%s: failed to register SYNC region\n", __func__);
+		goto fail;
+	}
+
 	return 0;
+
+fail:
+	gpio_free(irq);
+	return status;
+
 }
-- 
1.8.3.2


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

* [PATCH 31/36] ARM: OMAP2: usb-tusb6010: Use gpmc_generic_init()
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros,
	Felipe Balbi

Don't access any GPMC registers here. Use gpmc_generic_init()
to pass GPMC Chip Select settings, platform device and platform data
to the GPMC driver.

CC: Felipe Balbi <balbi@ti.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/usb-tusb6010.c | 78 +++++++++++++++++++-------------------
 1 file changed, 39 insertions(+), 39 deletions(-)

diff --git a/arch/arm/mach-omap2/usb-tusb6010.c b/arch/arm/mach-omap2/usb-tusb6010.c
index 71e6246..d28f5cd 100644
--- a/arch/arm/mach-omap2/usb-tusb6010.c
+++ b/arch/arm/mach-omap2/usb-tusb6010.c
@@ -125,13 +125,17 @@ EXPORT_SYMBOL_GPL(tusb6010_platform_retime);
 
 static struct resource tusb_resources[] = {
 	/* Order is significant!  The start/end fields
-	 * are updated during setup..
+	 * are updated by GPMC driver, see gpmc_probe_legacy()
 	 */
-	{ /* Asynchronous access */
-		.flags	= IORESOURCE_MEM,
+	{ /* Asynchronous access, for PIO */
+		.flags = IORESOURCE_MEM,
+		.start = 0,
+		.end = 0x9ff,
 	},
-	{ /* Synchronous access */
-		.flags	= IORESOURCE_MEM,
+	{ /* Synchronous access, for DMA */
+		.flags = IORESOURCE_MEM,
+		.start = 0,
+		.end = 0x9ff,
 	},
 	{ /* IRQ */
 		.name	= "mc",
@@ -163,37 +167,16 @@ tusb6010_setup_interface(struct musb_hdrc_platform_data *data,
 	int		status;
 	static char	error[] __initdata =
 		KERN_ERR "tusb6010 init error %d, %d\n";
+	struct gpmc_device_timings dev_async_t;
+	struct gpmc_device_timings dev_sync_t;
 
-	/* ASYNC region, primarily for PIO */
-	status = gpmc_cs_request(async, SZ_16M, (unsigned long *)
-				&tusb_resources[0].start);
-	if (status < 0) {
-		printk(error, 1, status);
-		return status;
-	}
-	tusb_resources[0].end = tusb_resources[0].start + 0x9ff;
+	/* GPMC settings */
 	tusb_async.wait_pin = waitpin;
 	async_cs = async;
 
-	status = gpmc_cs_program_settings(async_cs, &tusb_async);
-	if (status < 0)
-		return status;
-
-	/* SYNC region, primarily for DMA */
-	status = gpmc_cs_request(sync, SZ_16M, (unsigned long *)
-				&tusb_resources[1].start);
-	if (status < 0) {
-		printk(error, 2, status);
-		return status;
-	}
-	tusb_resources[1].end = tusb_resources[1].start + 0x9ff;
 	tusb_sync.wait_pin = waitpin;
 	sync_cs = sync;
 
-	status = gpmc_cs_program_settings(sync_cs, &tusb_sync);
-	if (status < 0)
-		return status;
-
 	/* IRQ */
 	status = gpio_request_one(irq, GPIOF_IN, "TUSB6010 irq");
 	if (status < 0) {
@@ -208,11 +191,10 @@ tusb6010_setup_interface(struct musb_hdrc_platform_data *data,
 		return -ENODEV;
 	}
 	refclk_psec = ps_refclk;
-	status = tusb6010_platform_retime(1);
-	if (status < 0) {
-		printk(error, 5, status);
-		return status;
-	}
+
+	/* device timings */
+	tusb_get_async_timings(ps_refclk, &dev_async_t);
+	tusb_get_sync_timings(ps_refclk, &dev_sync_t);
 
 	/* finish device setup ... */
 	if (!data) {
@@ -240,11 +222,29 @@ tusb6010_setup_interface(struct musb_hdrc_platform_data *data,
 			omap_mux_init_signal("sys_ndmareq5", 0);
 	}
 
-	/* so far so good ... register the device */
-	status = platform_device_register(&tusb_device);
-	if (status < 0) {
-		printk(error, 7, status);
-		return status;
+	/* Register ASYNC region */
+	status = gpmc_generic_init(async_cs, false,
+				   &tusb_async, &dev_async_t, NULL,
+				   &tusb_device, sizeof(*data));
+
+	if (status) {
+		pr_err("%s: failed to register ASYNC region\n", __func__);
+		goto fail;
 	}
+
+	/* Register SYNC region */
+	status = gpmc_generic_init(sync_cs, false,
+				   &tusb_sync, &dev_sync_t, NULL,
+				   &tusb_device, sizeof(*data));
+	if (status) {
+		pr_err("%s: failed to register SYNC region\n", __func__);
+		goto fail;
+	}
+
 	return 0;
+
+fail:
+	gpio_free(irq);
+	return status;
+
 }
-- 
1.8.3.2

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

* [PATCH 31/36] ARM: OMAP2: usb-tusb6010: Use gpmc_generic_init()
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, Felipe Balbi, kyungmin.park,
	linux-mtd, pekon, ezequiel.garcia, javier, linux-omap,
	Roger Quadros

Don't access any GPMC registers here. Use gpmc_generic_init()
to pass GPMC Chip Select settings, platform device and platform data
to the GPMC driver.

CC: Felipe Balbi <balbi@ti.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/usb-tusb6010.c | 78 +++++++++++++++++++-------------------
 1 file changed, 39 insertions(+), 39 deletions(-)

diff --git a/arch/arm/mach-omap2/usb-tusb6010.c b/arch/arm/mach-omap2/usb-tusb6010.c
index 71e6246..d28f5cd 100644
--- a/arch/arm/mach-omap2/usb-tusb6010.c
+++ b/arch/arm/mach-omap2/usb-tusb6010.c
@@ -125,13 +125,17 @@ EXPORT_SYMBOL_GPL(tusb6010_platform_retime);
 
 static struct resource tusb_resources[] = {
 	/* Order is significant!  The start/end fields
-	 * are updated during setup..
+	 * are updated by GPMC driver, see gpmc_probe_legacy()
 	 */
-	{ /* Asynchronous access */
-		.flags	= IORESOURCE_MEM,
+	{ /* Asynchronous access, for PIO */
+		.flags = IORESOURCE_MEM,
+		.start = 0,
+		.end = 0x9ff,
 	},
-	{ /* Synchronous access */
-		.flags	= IORESOURCE_MEM,
+	{ /* Synchronous access, for DMA */
+		.flags = IORESOURCE_MEM,
+		.start = 0,
+		.end = 0x9ff,
 	},
 	{ /* IRQ */
 		.name	= "mc",
@@ -163,37 +167,16 @@ tusb6010_setup_interface(struct musb_hdrc_platform_data *data,
 	int		status;
 	static char	error[] __initdata =
 		KERN_ERR "tusb6010 init error %d, %d\n";
+	struct gpmc_device_timings dev_async_t;
+	struct gpmc_device_timings dev_sync_t;
 
-	/* ASYNC region, primarily for PIO */
-	status = gpmc_cs_request(async, SZ_16M, (unsigned long *)
-				&tusb_resources[0].start);
-	if (status < 0) {
-		printk(error, 1, status);
-		return status;
-	}
-	tusb_resources[0].end = tusb_resources[0].start + 0x9ff;
+	/* GPMC settings */
 	tusb_async.wait_pin = waitpin;
 	async_cs = async;
 
-	status = gpmc_cs_program_settings(async_cs, &tusb_async);
-	if (status < 0)
-		return status;
-
-	/* SYNC region, primarily for DMA */
-	status = gpmc_cs_request(sync, SZ_16M, (unsigned long *)
-				&tusb_resources[1].start);
-	if (status < 0) {
-		printk(error, 2, status);
-		return status;
-	}
-	tusb_resources[1].end = tusb_resources[1].start + 0x9ff;
 	tusb_sync.wait_pin = waitpin;
 	sync_cs = sync;
 
-	status = gpmc_cs_program_settings(sync_cs, &tusb_sync);
-	if (status < 0)
-		return status;
-
 	/* IRQ */
 	status = gpio_request_one(irq, GPIOF_IN, "TUSB6010 irq");
 	if (status < 0) {
@@ -208,11 +191,10 @@ tusb6010_setup_interface(struct musb_hdrc_platform_data *data,
 		return -ENODEV;
 	}
 	refclk_psec = ps_refclk;
-	status = tusb6010_platform_retime(1);
-	if (status < 0) {
-		printk(error, 5, status);
-		return status;
-	}
+
+	/* device timings */
+	tusb_get_async_timings(ps_refclk, &dev_async_t);
+	tusb_get_sync_timings(ps_refclk, &dev_sync_t);
 
 	/* finish device setup ... */
 	if (!data) {
@@ -240,11 +222,29 @@ tusb6010_setup_interface(struct musb_hdrc_platform_data *data,
 			omap_mux_init_signal("sys_ndmareq5", 0);
 	}
 
-	/* so far so good ... register the device */
-	status = platform_device_register(&tusb_device);
-	if (status < 0) {
-		printk(error, 7, status);
-		return status;
+	/* Register ASYNC region */
+	status = gpmc_generic_init(async_cs, false,
+				   &tusb_async, &dev_async_t, NULL,
+				   &tusb_device, sizeof(*data));
+
+	if (status) {
+		pr_err("%s: failed to register ASYNC region\n", __func__);
+		goto fail;
 	}
+
+	/* Register SYNC region */
+	status = gpmc_generic_init(sync_cs, false,
+				   &tusb_sync, &dev_sync_t, NULL,
+				   &tusb_device, sizeof(*data));
+	if (status) {
+		pr_err("%s: failed to register SYNC region\n", __func__);
+		goto fail;
+	}
+
 	return 0;
+
+fail:
+	gpio_free(irq);
+	return status;
+
 }
-- 
1.8.3.2

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

* [PATCH 32/36] ARM: OMAP2+: onenand: Use gpmc_generic_init()
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Don't access any GPMC registers here. Use gpmc_generic_init()
to pass GPMC Chip Select settings, platform device and platform data
to the GPMC driver.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-onenand.c | 53 ++++++++------------------------------
 1 file changed, 11 insertions(+), 42 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index 37ed4f1..139b3dd 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -27,7 +27,10 @@
 #define	ONENAND_IO_SIZE	SZ_128K
 
 static struct resource gpmc_onenand_resource = {
+/* GPMC driver will fixup the memory resource, see gpmc_probe_legacy() */
 	.flags		= IORESOURCE_MEM,
+	.start		= 0,
+	.end		= ONENAND_IO_SIZE - 1,
 };
 
 static struct platform_device gpmc_onenand_device = {
@@ -68,29 +71,11 @@ static void omap2_onenand_get_async_timings(struct gpmc_device_timings *dev_t)
 	dev_t->t_wph = t_wph * 1000;
 }
 
-static int omap2_onenand_setup_async(struct omap_onenand_platform_data
-				     *gpmc_onenand_data)
-{
-	struct gpmc_timings gpmc_t;
-	struct gpmc_device_timings dev_t;
-	int ret;
-
-	ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_async);
-	if (ret < 0)
-		return ret;
-
-	omap2_onenand_get_async_timings(&dev_t);
-	gpmc_calc_timings(&gpmc_t, &onenand_async, &dev_t);
-	if (gpmc_cs_set_timings(gpmc_onenand_data->cs, &gpmc_t))
-		return -EINVAL;
-
-	return 0;
-}
-
 void gpmc_onenand_init(struct omap_onenand_platform_data *gpmc_onenand_data)
 {
 	int err;
 	struct device *dev = &gpmc_onenand_device.dev;
+	struct gpmc_device_timings dev_t;
 
 	gpmc_onenand_device.dev.platform_data = gpmc_onenand_data;
 
@@ -106,29 +91,13 @@ void gpmc_onenand_init(struct omap_onenand_platform_data *gpmc_onenand_data)
 	else
 		gpmc_onenand_data->flags &= ~ONENAND_IN_OMAP34XX;
 
-	err = gpmc_cs_request(gpmc_onenand_data->cs, ONENAND_IO_SIZE,
-				(unsigned long *)&gpmc_onenand_resource.start);
-	if (err < 0) {
-		dev_err(dev, "Cannot request GPMC CS %d, error %d\n",
-			gpmc_onenand_data->cs, err);
-		return;
-	}
-
-	gpmc_onenand_resource.end = gpmc_onenand_resource.start +
-							ONENAND_IO_SIZE - 1;
-
-	if (omap2_onenand_setup_async(gpmc_onenand_data)) {
-		pr_err("%s: Failed to setup ASYNC timings\n", __func__);
-		goto fail;
-	}
-
-	if (platform_device_register(&gpmc_onenand_device) < 0) {
-		dev_err(dev, "Unable to register OneNAND device\n");
-		goto fail;
-	}
 
-	return;
+	omap2_onenand_get_async_timings(&dev_t);
 
-fail:
-	gpmc_cs_free(gpmc_onenand_data->cs);
+	err = gpmc_generic_init(gpmc_onenand_data->cs, false,
+				&onenand_async, &dev_t, NULL,
+				&gpmc_onenand_device,
+				sizeof(*gpmc_onenand_data));
+	if (err)
+		pr_err("%s: gpmc_generic_init() failed %d\n", __func__, err);
 }
-- 
1.8.3.2


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

* [PATCH 32/36] ARM: OMAP2+: onenand: Use gpmc_generic_init()
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Don't access any GPMC registers here. Use gpmc_generic_init()
to pass GPMC Chip Select settings, platform device and platform data
to the GPMC driver.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-onenand.c | 53 ++++++++------------------------------
 1 file changed, 11 insertions(+), 42 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index 37ed4f1..139b3dd 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -27,7 +27,10 @@
 #define	ONENAND_IO_SIZE	SZ_128K
 
 static struct resource gpmc_onenand_resource = {
+/* GPMC driver will fixup the memory resource, see gpmc_probe_legacy() */
 	.flags		= IORESOURCE_MEM,
+	.start		= 0,
+	.end		= ONENAND_IO_SIZE - 1,
 };
 
 static struct platform_device gpmc_onenand_device = {
@@ -68,29 +71,11 @@ static void omap2_onenand_get_async_timings(struct gpmc_device_timings *dev_t)
 	dev_t->t_wph = t_wph * 1000;
 }
 
-static int omap2_onenand_setup_async(struct omap_onenand_platform_data
-				     *gpmc_onenand_data)
-{
-	struct gpmc_timings gpmc_t;
-	struct gpmc_device_timings dev_t;
-	int ret;
-
-	ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_async);
-	if (ret < 0)
-		return ret;
-
-	omap2_onenand_get_async_timings(&dev_t);
-	gpmc_calc_timings(&gpmc_t, &onenand_async, &dev_t);
-	if (gpmc_cs_set_timings(gpmc_onenand_data->cs, &gpmc_t))
-		return -EINVAL;
-
-	return 0;
-}
-
 void gpmc_onenand_init(struct omap_onenand_platform_data *gpmc_onenand_data)
 {
 	int err;
 	struct device *dev = &gpmc_onenand_device.dev;
+	struct gpmc_device_timings dev_t;
 
 	gpmc_onenand_device.dev.platform_data = gpmc_onenand_data;
 
@@ -106,29 +91,13 @@ void gpmc_onenand_init(struct omap_onenand_platform_data *gpmc_onenand_data)
 	else
 		gpmc_onenand_data->flags &= ~ONENAND_IN_OMAP34XX;
 
-	err = gpmc_cs_request(gpmc_onenand_data->cs, ONENAND_IO_SIZE,
-				(unsigned long *)&gpmc_onenand_resource.start);
-	if (err < 0) {
-		dev_err(dev, "Cannot request GPMC CS %d, error %d\n",
-			gpmc_onenand_data->cs, err);
-		return;
-	}
-
-	gpmc_onenand_resource.end = gpmc_onenand_resource.start +
-							ONENAND_IO_SIZE - 1;
-
-	if (omap2_onenand_setup_async(gpmc_onenand_data)) {
-		pr_err("%s: Failed to setup ASYNC timings\n", __func__);
-		goto fail;
-	}
-
-	if (platform_device_register(&gpmc_onenand_device) < 0) {
-		dev_err(dev, "Unable to register OneNAND device\n");
-		goto fail;
-	}
 
-	return;
+	omap2_onenand_get_async_timings(&dev_t);
 
-fail:
-	gpmc_cs_free(gpmc_onenand_data->cs);
+	err = gpmc_generic_init(gpmc_onenand_data->cs, false,
+				&onenand_async, &dev_t, NULL,
+				&gpmc_onenand_device,
+				sizeof(*gpmc_onenand_data));
+	if (err)
+		pr_err("%s: gpmc_generic_init() failed %d\n", __func__, err);
 }
-- 
1.8.3.2

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

* [PATCH 32/36] ARM: OMAP2+: onenand: Use gpmc_generic_init()
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Don't access any GPMC registers here. Use gpmc_generic_init()
to pass GPMC Chip Select settings, platform device and platform data
to the GPMC driver.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-onenand.c | 53 ++++++++------------------------------
 1 file changed, 11 insertions(+), 42 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index 37ed4f1..139b3dd 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -27,7 +27,10 @@
 #define	ONENAND_IO_SIZE	SZ_128K
 
 static struct resource gpmc_onenand_resource = {
+/* GPMC driver will fixup the memory resource, see gpmc_probe_legacy() */
 	.flags		= IORESOURCE_MEM,
+	.start		= 0,
+	.end		= ONENAND_IO_SIZE - 1,
 };
 
 static struct platform_device gpmc_onenand_device = {
@@ -68,29 +71,11 @@ static void omap2_onenand_get_async_timings(struct gpmc_device_timings *dev_t)
 	dev_t->t_wph = t_wph * 1000;
 }
 
-static int omap2_onenand_setup_async(struct omap_onenand_platform_data
-				     *gpmc_onenand_data)
-{
-	struct gpmc_timings gpmc_t;
-	struct gpmc_device_timings dev_t;
-	int ret;
-
-	ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_async);
-	if (ret < 0)
-		return ret;
-
-	omap2_onenand_get_async_timings(&dev_t);
-	gpmc_calc_timings(&gpmc_t, &onenand_async, &dev_t);
-	if (gpmc_cs_set_timings(gpmc_onenand_data->cs, &gpmc_t))
-		return -EINVAL;
-
-	return 0;
-}
-
 void gpmc_onenand_init(struct omap_onenand_platform_data *gpmc_onenand_data)
 {
 	int err;
 	struct device *dev = &gpmc_onenand_device.dev;
+	struct gpmc_device_timings dev_t;
 
 	gpmc_onenand_device.dev.platform_data = gpmc_onenand_data;
 
@@ -106,29 +91,13 @@ void gpmc_onenand_init(struct omap_onenand_platform_data *gpmc_onenand_data)
 	else
 		gpmc_onenand_data->flags &= ~ONENAND_IN_OMAP34XX;
 
-	err = gpmc_cs_request(gpmc_onenand_data->cs, ONENAND_IO_SIZE,
-				(unsigned long *)&gpmc_onenand_resource.start);
-	if (err < 0) {
-		dev_err(dev, "Cannot request GPMC CS %d, error %d\n",
-			gpmc_onenand_data->cs, err);
-		return;
-	}
-
-	gpmc_onenand_resource.end = gpmc_onenand_resource.start +
-							ONENAND_IO_SIZE - 1;
-
-	if (omap2_onenand_setup_async(gpmc_onenand_data)) {
-		pr_err("%s: Failed to setup ASYNC timings\n", __func__);
-		goto fail;
-	}
-
-	if (platform_device_register(&gpmc_onenand_device) < 0) {
-		dev_err(dev, "Unable to register OneNAND device\n");
-		goto fail;
-	}
 
-	return;
+	omap2_onenand_get_async_timings(&dev_t);
 
-fail:
-	gpmc_cs_free(gpmc_onenand_data->cs);
+	err = gpmc_generic_init(gpmc_onenand_data->cs, false,
+				&onenand_async, &dev_t, NULL,
+				&gpmc_onenand_device,
+				sizeof(*gpmc_onenand_data));
+	if (err)
+		pr_err("%s: gpmc_generic_init() failed %d\n", __func__, err);
 }
-- 
1.8.3.2

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

* [PATCH 33/36] ARM: OMAP2+: board-flash: Use gpmc_generic_init() for NOR
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Don't access any GPMC registers here. Use gpmc_generic_init()
to pass GPMC Chip Select settings, platform device and platform data
to the GPMC driver.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/board-flash.c | 28 +++++++++++-----------------
 1 file changed, 11 insertions(+), 17 deletions(-)

diff --git a/arch/arm/mach-omap2/board-flash.c b/arch/arm/mach-omap2/board-flash.c
index b6885e4..617e441 100644
--- a/arch/arm/mach-omap2/board-flash.c
+++ b/arch/arm/mach-omap2/board-flash.c
@@ -41,7 +41,10 @@ static struct physmap_flash_data board_nor_data = {
 };
 
 static struct resource board_nor_resource = {
+	/* GPMC driver will fixup the resource, see gpmc_probe_legacy () */
 	.flags		= IORESOURCE_MEM,
+	.start		= 0,
+	.end		= FLASH_SIZE_SDPV1 - 1,	/* fixed @runtime for SDPV2 */
 };
 
 static struct platform_device board_nor_device = {
@@ -62,23 +65,14 @@ __init board_nor_init(struct mtd_partition *nor_parts, u8 nr_parts, u8 cs)
 	board_nor_data.parts	= nor_parts;
 	board_nor_data.nr_parts	= nr_parts;
 
-	/* Configure start address and size of NOR device */
-	if (omap_rev() >= OMAP3430_REV_ES1_0) {
-		err = gpmc_cs_request(cs, FLASH_SIZE_SDPV2 - 1,
-				(unsigned long *)&board_nor_resource.start);
-		board_nor_resource.end = board_nor_resource.start
-					+ FLASH_SIZE_SDPV2 - 1;
-	} else {
-		err = gpmc_cs_request(cs, FLASH_SIZE_SDPV1 - 1,
-				(unsigned long *)&board_nor_resource.start);
-		board_nor_resource.end = board_nor_resource.start
-					+ FLASH_SIZE_SDPV1 - 1;
-	}
-	if (err < 0) {
-		pr_err("NOR: Can't request GPMC CS\n");
-		return;
-	}
-	if (platform_device_register(&board_nor_device) < 0)
+	/* Configure size of NOR device */
+	if (omap_rev() >= OMAP3430_REV_ES1_0)
+		board_nor_resource.end = FLASH_SIZE_SDPV2 - 1;
+
+	err = gpmc_generic_init(cs, false,
+				NULL, NULL, NULL,
+				&board_nor_device, sizeof(board_nor_data));
+	if (err)
 		pr_err("Unable to register NOR device\n");
 }
 
-- 
1.8.3.2


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

* [PATCH 33/36] ARM: OMAP2+: board-flash: Use gpmc_generic_init() for NOR
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Don't access any GPMC registers here. Use gpmc_generic_init()
to pass GPMC Chip Select settings, platform device and platform data
to the GPMC driver.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/board-flash.c | 28 +++++++++++-----------------
 1 file changed, 11 insertions(+), 17 deletions(-)

diff --git a/arch/arm/mach-omap2/board-flash.c b/arch/arm/mach-omap2/board-flash.c
index b6885e4..617e441 100644
--- a/arch/arm/mach-omap2/board-flash.c
+++ b/arch/arm/mach-omap2/board-flash.c
@@ -41,7 +41,10 @@ static struct physmap_flash_data board_nor_data = {
 };
 
 static struct resource board_nor_resource = {
+	/* GPMC driver will fixup the resource, see gpmc_probe_legacy () */
 	.flags		= IORESOURCE_MEM,
+	.start		= 0,
+	.end		= FLASH_SIZE_SDPV1 - 1,	/* fixed @runtime for SDPV2 */
 };
 
 static struct platform_device board_nor_device = {
@@ -62,23 +65,14 @@ __init board_nor_init(struct mtd_partition *nor_parts, u8 nr_parts, u8 cs)
 	board_nor_data.parts	= nor_parts;
 	board_nor_data.nr_parts	= nr_parts;
 
-	/* Configure start address and size of NOR device */
-	if (omap_rev() >= OMAP3430_REV_ES1_0) {
-		err = gpmc_cs_request(cs, FLASH_SIZE_SDPV2 - 1,
-				(unsigned long *)&board_nor_resource.start);
-		board_nor_resource.end = board_nor_resource.start
-					+ FLASH_SIZE_SDPV2 - 1;
-	} else {
-		err = gpmc_cs_request(cs, FLASH_SIZE_SDPV1 - 1,
-				(unsigned long *)&board_nor_resource.start);
-		board_nor_resource.end = board_nor_resource.start
-					+ FLASH_SIZE_SDPV1 - 1;
-	}
-	if (err < 0) {
-		pr_err("NOR: Can't request GPMC CS\n");
-		return;
-	}
-	if (platform_device_register(&board_nor_device) < 0)
+	/* Configure size of NOR device */
+	if (omap_rev() >= OMAP3430_REV_ES1_0)
+		board_nor_resource.end = FLASH_SIZE_SDPV2 - 1;
+
+	err = gpmc_generic_init(cs, false,
+				NULL, NULL, NULL,
+				&board_nor_device, sizeof(board_nor_data));
+	if (err)
 		pr_err("Unable to register NOR device\n");
 }
 
-- 
1.8.3.2

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

* [PATCH 33/36] ARM: OMAP2+: board-flash: Use gpmc_generic_init() for NOR
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Don't access any GPMC registers here. Use gpmc_generic_init()
to pass GPMC Chip Select settings, platform device and platform data
to the GPMC driver.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/board-flash.c | 28 +++++++++++-----------------
 1 file changed, 11 insertions(+), 17 deletions(-)

diff --git a/arch/arm/mach-omap2/board-flash.c b/arch/arm/mach-omap2/board-flash.c
index b6885e4..617e441 100644
--- a/arch/arm/mach-omap2/board-flash.c
+++ b/arch/arm/mach-omap2/board-flash.c
@@ -41,7 +41,10 @@ static struct physmap_flash_data board_nor_data = {
 };
 
 static struct resource board_nor_resource = {
+	/* GPMC driver will fixup the resource, see gpmc_probe_legacy () */
 	.flags		= IORESOURCE_MEM,
+	.start		= 0,
+	.end		= FLASH_SIZE_SDPV1 - 1,	/* fixed @runtime for SDPV2 */
 };
 
 static struct platform_device board_nor_device = {
@@ -62,23 +65,14 @@ __init board_nor_init(struct mtd_partition *nor_parts, u8 nr_parts, u8 cs)
 	board_nor_data.parts	= nor_parts;
 	board_nor_data.nr_parts	= nr_parts;
 
-	/* Configure start address and size of NOR device */
-	if (omap_rev() >= OMAP3430_REV_ES1_0) {
-		err = gpmc_cs_request(cs, FLASH_SIZE_SDPV2 - 1,
-				(unsigned long *)&board_nor_resource.start);
-		board_nor_resource.end = board_nor_resource.start
-					+ FLASH_SIZE_SDPV2 - 1;
-	} else {
-		err = gpmc_cs_request(cs, FLASH_SIZE_SDPV1 - 1,
-				(unsigned long *)&board_nor_resource.start);
-		board_nor_resource.end = board_nor_resource.start
-					+ FLASH_SIZE_SDPV1 - 1;
-	}
-	if (err < 0) {
-		pr_err("NOR: Can't request GPMC CS\n");
-		return;
-	}
-	if (platform_device_register(&board_nor_device) < 0)
+	/* Configure size of NOR device */
+	if (omap_rev() >= OMAP3430_REV_ES1_0)
+		board_nor_resource.end = FLASH_SIZE_SDPV2 - 1;
+
+	err = gpmc_generic_init(cs, false,
+				NULL, NULL, NULL,
+				&board_nor_device, sizeof(board_nor_data));
+	if (err)
 		pr_err("Unable to register NOR device\n");
 }
 
-- 
1.8.3.2

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

* [PATCH 34/36] ARM: OMAP2+: gpmc: Make externally unused functions/defines private
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Most of the GPMC functions are now not used by other drivers.
Make them private.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.c | 84 ++++++++++++++++++++++++++++++----------------
 arch/arm/mach-omap2/gpmc.h | 63 ----------------------------------
 2 files changed, 56 insertions(+), 91 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 7a667ca..9173f71 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -80,6 +80,45 @@
 #define GPMC_ECC_CTRL_ECCREG8		0x008
 #define GPMC_ECC_CTRL_ECCREG9		0x009
 
+/* ECC commands */
+#define GPMC_ECC_READ		0 /* Reset Hardware ECC for read */
+#define GPMC_ECC_WRITE		1 /* Reset Hardware ECC for write */
+#define GPMC_ECC_READSYN	2 /* Reset before syndrom is read back */
+
+/* CS CONFIG registers */
+#define GPMC_CS_CONFIG1		0x00
+#define GPMC_CS_CONFIG2		0x04
+#define GPMC_CS_CONFIG3		0x08
+#define GPMC_CS_CONFIG4		0x0c
+#define GPMC_CS_CONFIG5		0x10
+#define GPMC_CS_CONFIG6		0x14
+#define GPMC_CS_CONFIG7		0x18
+
+#define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
+#define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
+#define GPMC_CONFIG1_READTYPE_ASYNC     (0 << 29)
+#define GPMC_CONFIG1_READTYPE_SYNC      (1 << 29)
+#define GPMC_CONFIG1_WRITEMULTIPLE_SUPP (1 << 28)
+#define GPMC_CONFIG1_WRITETYPE_ASYNC    (0 << 27)
+#define GPMC_CONFIG1_WRITETYPE_SYNC     (1 << 27)
+#define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val & 3) << 25)
+#define GPMC_CONFIG1_PAGE_LEN(val)      ((val & 3) << 23)
+#define GPMC_CONFIG1_WAIT_READ_MON      (1 << 22)
+#define GPMC_CONFIG1_WAIT_WRITE_MON     (1 << 21)
+#define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18)
+#define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val & 3) << 16)
+#define GPMC_CONFIG1_DEVICESIZE(val)    ((val & 3) << 12)
+#define GPMC_CONFIG1_DEVICESIZE_16      GPMC_CONFIG1_DEVICESIZE(1)
+#define GPMC_CONFIG1_DEVICETYPE(val)    ((val & 3) << 10)
+#define GPMC_CONFIG1_DEVICETYPE_NOR     GPMC_CONFIG1_DEVICETYPE(0)
+#define GPMC_CONFIG1_MUXTYPE(val)       ((val & 3) << 8)
+#define GPMC_CONFIG1_TIME_PARA_GRAN     (1 << 4)
+#define GPMC_CONFIG1_FCLK_DIV(val)      (val & 3)
+#define GPMC_CONFIG1_FCLK_DIV2          (GPMC_CONFIG1_FCLK_DIV(1))
+#define GPMC_CONFIG1_FCLK_DIV3          (GPMC_CONFIG1_FCLK_DIV(2))
+#define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
+#define GPMC_CONFIG7_CSVALID		(1 << 6)
+
 #define	GPMC_CONFIG2_CSEXTRADELAY		BIT(7)
 #define	GPMC_CONFIG3_ADVEXTRADELAY		BIT(7)
 #define	GPMC_CONFIG4_OEEXTRADELAY		BIT(7)
@@ -87,6 +126,12 @@
 #define	GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN	BIT(6)
 #define	GPMC_CONFIG6_CYCLE2CYCLESAMECSEN	BIT(7)
 
+#define GPMC_DEVICETYPE_NOR		0
+#define GPMC_DEVICETYPE_NAND		2
+#define WR_RD_PIN_MONITORING		0x00600000
+#define GPMC_IRQ_FIFOEVENTENABLE	0x01
+#define GPMC_IRQ_COUNT_EVENT		0x02
+
 #define GPMC_CS0_OFFSET		0x60
 #define GPMC_CS_SIZE		0x30
 #define	GPMC_BCH_SIZE		0x10
@@ -163,7 +208,7 @@ static u32 gpmc_read_reg(int idx)
 	return __raw_readl(gpmc_base + idx);
 }
 
-void gpmc_cs_write_reg(int cs, int idx, u32 val)
+static void gpmc_cs_write_reg(int cs, int idx, u32 val)
 {
 	void __iomem *reg_addr;
 
@@ -215,11 +260,6 @@ static unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
 	return (time_ps + tick_ps - 1) / tick_ps;
 }
 
-unsigned int gpmc_ticks_to_ns(unsigned int ticks)
-{
-	return ticks * gpmc_get_fclk_period() / 1000;
-}
-
 static unsigned int gpmc_ticks_to_ps(unsigned int ticks)
 {
 	return ticks * gpmc_get_fclk_period();
@@ -315,7 +355,7 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
 		return -1
 #endif
 
-int gpmc_calc_divider(unsigned int sync_clk)
+static int gpmc_calc_divider(unsigned int sync_clk)
 {
 	int div;
 	u32 l;
@@ -330,7 +370,7 @@ int gpmc_calc_divider(unsigned int sync_clk)
 	return div;
 }
 
-int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
+static int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
 {
 	int div;
 	u32 l;
@@ -537,7 +577,7 @@ static int gpmc_cs_remap(int cs, u32 base)
 	return 0;
 }
 
-int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
+static int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
 {
 	struct resource *res = &gpmc_cs_mem[cs];
 	int r = -1;
@@ -575,9 +615,8 @@ out:
 	spin_unlock(&gpmc_mem_lock);
 	return r;
 }
-EXPORT_SYMBOL(gpmc_cs_request);
 
-void gpmc_cs_free(int cs)
+static void gpmc_cs_free(int cs)
 {
 	struct resource	*res = &gpmc_cs_mem[cs];
 
@@ -594,18 +633,6 @@ void gpmc_cs_free(int cs)
 	gpmc_cs_set_reserved(cs, 0);
 	spin_unlock(&gpmc_mem_lock);
 }
-EXPORT_SYMBOL(gpmc_cs_free);
-
-void gpmc_get_mem_resource(struct resource *res)
-{
-	res->start =  phys_base;
-	res->end = res->start + mem_size - 1;
-}
-
-int gpmc_get_irq(void)
-{
-	return gpmc_irq;
-}
 
 static void gpmc_mem_exit(void)
 {
@@ -937,9 +964,9 @@ static void gpmc_convert_ps_to_ns(struct gpmc_timings *t)
 	t->wr_data_mux_bus /= 1000;
 }
 
-int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
-		      struct gpmc_settings *gpmc_s,
-		      struct gpmc_device_timings *dev_t)
+static int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
+			     struct gpmc_settings *gpmc_s,
+			     struct gpmc_device_timings *dev_t)
 {
 	bool mux = false, sync = false;
 
@@ -980,7 +1007,7 @@ int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
  * register will be initialised to zero by this function. Returns 0 on
  * success and appropriate negative error code on failure.
  */
-int gpmc_cs_program_settings(int cs, struct gpmc_settings *p)
+static int gpmc_cs_program_settings(int cs, struct gpmc_settings *p)
 {
 	u32 config1;
 
@@ -1073,7 +1100,8 @@ MODULE_DEVICE_TABLE(of, gpmc_dt_ids);
  * structure is initialised to zero by this function and so any
  * previously stored settings will be cleared.
  */
-void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p)
+static void gpmc_read_settings_dt(struct device_node *np,
+				  struct gpmc_settings *p)
 {
 	memset(p, 0, sizeof(struct gpmc_settings));
 
diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h
index 301bc66..c8af000 100644
--- a/arch/arm/mach-omap2/gpmc.h
+++ b/arch/arm/mach-omap2/gpmc.h
@@ -11,77 +11,14 @@
 #ifndef __OMAP2_GPMC_H
 #define __OMAP2_GPMC_H
 
-#include <linux/platform_data/mtd-nand-omap2.h>
 #include <linux/platform_data/gpmc-omap.h>
 
-#define GPMC_CS_CONFIG1		0x00
-#define GPMC_CS_CONFIG2		0x04
-#define GPMC_CS_CONFIG3		0x08
-#define GPMC_CS_CONFIG4		0x0c
-#define GPMC_CS_CONFIG5		0x10
-#define GPMC_CS_CONFIG6		0x14
-#define GPMC_CS_CONFIG7		0x18
-
-/* ECC commands */
-#define GPMC_ECC_READ		0 /* Reset Hardware ECC for read */
-#define GPMC_ECC_WRITE		1 /* Reset Hardware ECC for write */
-#define GPMC_ECC_READSYN	2 /* Reset before syndrom is read back */
-
-#define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
-#define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
-#define GPMC_CONFIG1_READTYPE_ASYNC     (0 << 29)
-#define GPMC_CONFIG1_READTYPE_SYNC      (1 << 29)
-#define GPMC_CONFIG1_WRITEMULTIPLE_SUPP (1 << 28)
-#define GPMC_CONFIG1_WRITETYPE_ASYNC    (0 << 27)
-#define GPMC_CONFIG1_WRITETYPE_SYNC     (1 << 27)
-#define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val & 3) << 25)
-#define GPMC_CONFIG1_PAGE_LEN(val)      ((val & 3) << 23)
-#define GPMC_CONFIG1_WAIT_READ_MON      (1 << 22)
-#define GPMC_CONFIG1_WAIT_WRITE_MON     (1 << 21)
-#define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18)
-#define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val & 3) << 16)
-#define GPMC_CONFIG1_DEVICESIZE(val)    ((val & 3) << 12)
-#define GPMC_CONFIG1_DEVICESIZE_16      GPMC_CONFIG1_DEVICESIZE(1)
-#define GPMC_CONFIG1_DEVICETYPE(val)    ((val & 3) << 10)
-#define GPMC_CONFIG1_DEVICETYPE_NOR     GPMC_CONFIG1_DEVICETYPE(0)
-#define GPMC_CONFIG1_MUXTYPE(val)       ((val & 3) << 8)
-#define GPMC_CONFIG1_TIME_PARA_GRAN     (1 << 4)
-#define GPMC_CONFIG1_FCLK_DIV(val)      (val & 3)
-#define GPMC_CONFIG1_FCLK_DIV2          (GPMC_CONFIG1_FCLK_DIV(1))
-#define GPMC_CONFIG1_FCLK_DIV3          (GPMC_CONFIG1_FCLK_DIV(2))
-#define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
-#define GPMC_CONFIG7_CSVALID		(1 << 6)
-
-#define GPMC_DEVICETYPE_NOR		0
-#define GPMC_DEVICETYPE_NAND		2
-#define WR_RD_PIN_MONITORING		0x00600000
-#define GPMC_IRQ_FIFOEVENTENABLE	0x01
-#define GPMC_IRQ_COUNT_EVENT		0x02
-
-extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
-			     struct gpmc_settings *gpmc_s,
-			     struct gpmc_device_timings *dev_t);
-
-void gpmc_get_mem_resource(struct resource *res);
-int gpmc_get_irq(void);
-
-extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);
-
-extern void gpmc_cs_write_reg(int cs, int idx, u32 val);
-extern int gpmc_calc_divider(unsigned int sync_clk);
-extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t);
-extern int gpmc_cs_program_settings(int cs, struct gpmc_settings *p);
-extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
-extern void gpmc_cs_free(int cs);
 extern void omap3_gpmc_save_context(void);
 extern void omap3_gpmc_restore_context(void);
-extern void gpmc_read_settings_dt(struct device_node *np,
-				  struct gpmc_settings *p);
 int gpmc_generic_init(int cs, bool is_nand,
 		      struct gpmc_settings *settings,
 		      struct gpmc_device_timings *device_timings,
 		      struct gpmc_timings *gpmc_timings,
 		      struct platform_device *pdev,
 		      unsigned pdata_size);
-
 #endif
-- 
1.8.3.2


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

* [PATCH 34/36] ARM: OMAP2+: gpmc: Make externally unused functions/defines private
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Most of the GPMC functions are now not used by other drivers.
Make them private.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.c | 84 ++++++++++++++++++++++++++++++----------------
 arch/arm/mach-omap2/gpmc.h | 63 ----------------------------------
 2 files changed, 56 insertions(+), 91 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 7a667ca..9173f71 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -80,6 +80,45 @@
 #define GPMC_ECC_CTRL_ECCREG8		0x008
 #define GPMC_ECC_CTRL_ECCREG9		0x009
 
+/* ECC commands */
+#define GPMC_ECC_READ		0 /* Reset Hardware ECC for read */
+#define GPMC_ECC_WRITE		1 /* Reset Hardware ECC for write */
+#define GPMC_ECC_READSYN	2 /* Reset before syndrom is read back */
+
+/* CS CONFIG registers */
+#define GPMC_CS_CONFIG1		0x00
+#define GPMC_CS_CONFIG2		0x04
+#define GPMC_CS_CONFIG3		0x08
+#define GPMC_CS_CONFIG4		0x0c
+#define GPMC_CS_CONFIG5		0x10
+#define GPMC_CS_CONFIG6		0x14
+#define GPMC_CS_CONFIG7		0x18
+
+#define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
+#define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
+#define GPMC_CONFIG1_READTYPE_ASYNC     (0 << 29)
+#define GPMC_CONFIG1_READTYPE_SYNC      (1 << 29)
+#define GPMC_CONFIG1_WRITEMULTIPLE_SUPP (1 << 28)
+#define GPMC_CONFIG1_WRITETYPE_ASYNC    (0 << 27)
+#define GPMC_CONFIG1_WRITETYPE_SYNC     (1 << 27)
+#define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val & 3) << 25)
+#define GPMC_CONFIG1_PAGE_LEN(val)      ((val & 3) << 23)
+#define GPMC_CONFIG1_WAIT_READ_MON      (1 << 22)
+#define GPMC_CONFIG1_WAIT_WRITE_MON     (1 << 21)
+#define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18)
+#define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val & 3) << 16)
+#define GPMC_CONFIG1_DEVICESIZE(val)    ((val & 3) << 12)
+#define GPMC_CONFIG1_DEVICESIZE_16      GPMC_CONFIG1_DEVICESIZE(1)
+#define GPMC_CONFIG1_DEVICETYPE(val)    ((val & 3) << 10)
+#define GPMC_CONFIG1_DEVICETYPE_NOR     GPMC_CONFIG1_DEVICETYPE(0)
+#define GPMC_CONFIG1_MUXTYPE(val)       ((val & 3) << 8)
+#define GPMC_CONFIG1_TIME_PARA_GRAN     (1 << 4)
+#define GPMC_CONFIG1_FCLK_DIV(val)      (val & 3)
+#define GPMC_CONFIG1_FCLK_DIV2          (GPMC_CONFIG1_FCLK_DIV(1))
+#define GPMC_CONFIG1_FCLK_DIV3          (GPMC_CONFIG1_FCLK_DIV(2))
+#define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
+#define GPMC_CONFIG7_CSVALID		(1 << 6)
+
 #define	GPMC_CONFIG2_CSEXTRADELAY		BIT(7)
 #define	GPMC_CONFIG3_ADVEXTRADELAY		BIT(7)
 #define	GPMC_CONFIG4_OEEXTRADELAY		BIT(7)
@@ -87,6 +126,12 @@
 #define	GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN	BIT(6)
 #define	GPMC_CONFIG6_CYCLE2CYCLESAMECSEN	BIT(7)
 
+#define GPMC_DEVICETYPE_NOR		0
+#define GPMC_DEVICETYPE_NAND		2
+#define WR_RD_PIN_MONITORING		0x00600000
+#define GPMC_IRQ_FIFOEVENTENABLE	0x01
+#define GPMC_IRQ_COUNT_EVENT		0x02
+
 #define GPMC_CS0_OFFSET		0x60
 #define GPMC_CS_SIZE		0x30
 #define	GPMC_BCH_SIZE		0x10
@@ -163,7 +208,7 @@ static u32 gpmc_read_reg(int idx)
 	return __raw_readl(gpmc_base + idx);
 }
 
-void gpmc_cs_write_reg(int cs, int idx, u32 val)
+static void gpmc_cs_write_reg(int cs, int idx, u32 val)
 {
 	void __iomem *reg_addr;
 
@@ -215,11 +260,6 @@ static unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
 	return (time_ps + tick_ps - 1) / tick_ps;
 }
 
-unsigned int gpmc_ticks_to_ns(unsigned int ticks)
-{
-	return ticks * gpmc_get_fclk_period() / 1000;
-}
-
 static unsigned int gpmc_ticks_to_ps(unsigned int ticks)
 {
 	return ticks * gpmc_get_fclk_period();
@@ -315,7 +355,7 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
 		return -1
 #endif
 
-int gpmc_calc_divider(unsigned int sync_clk)
+static int gpmc_calc_divider(unsigned int sync_clk)
 {
 	int div;
 	u32 l;
@@ -330,7 +370,7 @@ int gpmc_calc_divider(unsigned int sync_clk)
 	return div;
 }
 
-int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
+static int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
 {
 	int div;
 	u32 l;
@@ -537,7 +577,7 @@ static int gpmc_cs_remap(int cs, u32 base)
 	return 0;
 }
 
-int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
+static int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
 {
 	struct resource *res = &gpmc_cs_mem[cs];
 	int r = -1;
@@ -575,9 +615,8 @@ out:
 	spin_unlock(&gpmc_mem_lock);
 	return r;
 }
-EXPORT_SYMBOL(gpmc_cs_request);
 
-void gpmc_cs_free(int cs)
+static void gpmc_cs_free(int cs)
 {
 	struct resource	*res = &gpmc_cs_mem[cs];
 
@@ -594,18 +633,6 @@ void gpmc_cs_free(int cs)
 	gpmc_cs_set_reserved(cs, 0);
 	spin_unlock(&gpmc_mem_lock);
 }
-EXPORT_SYMBOL(gpmc_cs_free);
-
-void gpmc_get_mem_resource(struct resource *res)
-{
-	res->start =  phys_base;
-	res->end = res->start + mem_size - 1;
-}
-
-int gpmc_get_irq(void)
-{
-	return gpmc_irq;
-}
 
 static void gpmc_mem_exit(void)
 {
@@ -937,9 +964,9 @@ static void gpmc_convert_ps_to_ns(struct gpmc_timings *t)
 	t->wr_data_mux_bus /= 1000;
 }
 
-int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
-		      struct gpmc_settings *gpmc_s,
-		      struct gpmc_device_timings *dev_t)
+static int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
+			     struct gpmc_settings *gpmc_s,
+			     struct gpmc_device_timings *dev_t)
 {
 	bool mux = false, sync = false;
 
@@ -980,7 +1007,7 @@ int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
  * register will be initialised to zero by this function. Returns 0 on
  * success and appropriate negative error code on failure.
  */
-int gpmc_cs_program_settings(int cs, struct gpmc_settings *p)
+static int gpmc_cs_program_settings(int cs, struct gpmc_settings *p)
 {
 	u32 config1;
 
@@ -1073,7 +1100,8 @@ MODULE_DEVICE_TABLE(of, gpmc_dt_ids);
  * structure is initialised to zero by this function and so any
  * previously stored settings will be cleared.
  */
-void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p)
+static void gpmc_read_settings_dt(struct device_node *np,
+				  struct gpmc_settings *p)
 {
 	memset(p, 0, sizeof(struct gpmc_settings));
 
diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h
index 301bc66..c8af000 100644
--- a/arch/arm/mach-omap2/gpmc.h
+++ b/arch/arm/mach-omap2/gpmc.h
@@ -11,77 +11,14 @@
 #ifndef __OMAP2_GPMC_H
 #define __OMAP2_GPMC_H
 
-#include <linux/platform_data/mtd-nand-omap2.h>
 #include <linux/platform_data/gpmc-omap.h>
 
-#define GPMC_CS_CONFIG1		0x00
-#define GPMC_CS_CONFIG2		0x04
-#define GPMC_CS_CONFIG3		0x08
-#define GPMC_CS_CONFIG4		0x0c
-#define GPMC_CS_CONFIG5		0x10
-#define GPMC_CS_CONFIG6		0x14
-#define GPMC_CS_CONFIG7		0x18
-
-/* ECC commands */
-#define GPMC_ECC_READ		0 /* Reset Hardware ECC for read */
-#define GPMC_ECC_WRITE		1 /* Reset Hardware ECC for write */
-#define GPMC_ECC_READSYN	2 /* Reset before syndrom is read back */
-
-#define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
-#define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
-#define GPMC_CONFIG1_READTYPE_ASYNC     (0 << 29)
-#define GPMC_CONFIG1_READTYPE_SYNC      (1 << 29)
-#define GPMC_CONFIG1_WRITEMULTIPLE_SUPP (1 << 28)
-#define GPMC_CONFIG1_WRITETYPE_ASYNC    (0 << 27)
-#define GPMC_CONFIG1_WRITETYPE_SYNC     (1 << 27)
-#define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val & 3) << 25)
-#define GPMC_CONFIG1_PAGE_LEN(val)      ((val & 3) << 23)
-#define GPMC_CONFIG1_WAIT_READ_MON      (1 << 22)
-#define GPMC_CONFIG1_WAIT_WRITE_MON     (1 << 21)
-#define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18)
-#define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val & 3) << 16)
-#define GPMC_CONFIG1_DEVICESIZE(val)    ((val & 3) << 12)
-#define GPMC_CONFIG1_DEVICESIZE_16      GPMC_CONFIG1_DEVICESIZE(1)
-#define GPMC_CONFIG1_DEVICETYPE(val)    ((val & 3) << 10)
-#define GPMC_CONFIG1_DEVICETYPE_NOR     GPMC_CONFIG1_DEVICETYPE(0)
-#define GPMC_CONFIG1_MUXTYPE(val)       ((val & 3) << 8)
-#define GPMC_CONFIG1_TIME_PARA_GRAN     (1 << 4)
-#define GPMC_CONFIG1_FCLK_DIV(val)      (val & 3)
-#define GPMC_CONFIG1_FCLK_DIV2          (GPMC_CONFIG1_FCLK_DIV(1))
-#define GPMC_CONFIG1_FCLK_DIV3          (GPMC_CONFIG1_FCLK_DIV(2))
-#define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
-#define GPMC_CONFIG7_CSVALID		(1 << 6)
-
-#define GPMC_DEVICETYPE_NOR		0
-#define GPMC_DEVICETYPE_NAND		2
-#define WR_RD_PIN_MONITORING		0x00600000
-#define GPMC_IRQ_FIFOEVENTENABLE	0x01
-#define GPMC_IRQ_COUNT_EVENT		0x02
-
-extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
-			     struct gpmc_settings *gpmc_s,
-			     struct gpmc_device_timings *dev_t);
-
-void gpmc_get_mem_resource(struct resource *res);
-int gpmc_get_irq(void);
-
-extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);
-
-extern void gpmc_cs_write_reg(int cs, int idx, u32 val);
-extern int gpmc_calc_divider(unsigned int sync_clk);
-extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t);
-extern int gpmc_cs_program_settings(int cs, struct gpmc_settings *p);
-extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
-extern void gpmc_cs_free(int cs);
 extern void omap3_gpmc_save_context(void);
 extern void omap3_gpmc_restore_context(void);
-extern void gpmc_read_settings_dt(struct device_node *np,
-				  struct gpmc_settings *p);
 int gpmc_generic_init(int cs, bool is_nand,
 		      struct gpmc_settings *settings,
 		      struct gpmc_device_timings *device_timings,
 		      struct gpmc_timings *gpmc_timings,
 		      struct platform_device *pdev,
 		      unsigned pdata_size);
-
 #endif
-- 
1.8.3.2

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

* [PATCH 34/36] ARM: OMAP2+: gpmc: Make externally unused functions/defines private
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Most of the GPMC functions are now not used by other drivers.
Make them private.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc.c | 84 ++++++++++++++++++++++++++++++----------------
 arch/arm/mach-omap2/gpmc.h | 63 ----------------------------------
 2 files changed, 56 insertions(+), 91 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 7a667ca..9173f71 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -80,6 +80,45 @@
 #define GPMC_ECC_CTRL_ECCREG8		0x008
 #define GPMC_ECC_CTRL_ECCREG9		0x009
 
+/* ECC commands */
+#define GPMC_ECC_READ		0 /* Reset Hardware ECC for read */
+#define GPMC_ECC_WRITE		1 /* Reset Hardware ECC for write */
+#define GPMC_ECC_READSYN	2 /* Reset before syndrom is read back */
+
+/* CS CONFIG registers */
+#define GPMC_CS_CONFIG1		0x00
+#define GPMC_CS_CONFIG2		0x04
+#define GPMC_CS_CONFIG3		0x08
+#define GPMC_CS_CONFIG4		0x0c
+#define GPMC_CS_CONFIG5		0x10
+#define GPMC_CS_CONFIG6		0x14
+#define GPMC_CS_CONFIG7		0x18
+
+#define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
+#define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
+#define GPMC_CONFIG1_READTYPE_ASYNC     (0 << 29)
+#define GPMC_CONFIG1_READTYPE_SYNC      (1 << 29)
+#define GPMC_CONFIG1_WRITEMULTIPLE_SUPP (1 << 28)
+#define GPMC_CONFIG1_WRITETYPE_ASYNC    (0 << 27)
+#define GPMC_CONFIG1_WRITETYPE_SYNC     (1 << 27)
+#define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val & 3) << 25)
+#define GPMC_CONFIG1_PAGE_LEN(val)      ((val & 3) << 23)
+#define GPMC_CONFIG1_WAIT_READ_MON      (1 << 22)
+#define GPMC_CONFIG1_WAIT_WRITE_MON     (1 << 21)
+#define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18)
+#define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val & 3) << 16)
+#define GPMC_CONFIG1_DEVICESIZE(val)    ((val & 3) << 12)
+#define GPMC_CONFIG1_DEVICESIZE_16      GPMC_CONFIG1_DEVICESIZE(1)
+#define GPMC_CONFIG1_DEVICETYPE(val)    ((val & 3) << 10)
+#define GPMC_CONFIG1_DEVICETYPE_NOR     GPMC_CONFIG1_DEVICETYPE(0)
+#define GPMC_CONFIG1_MUXTYPE(val)       ((val & 3) << 8)
+#define GPMC_CONFIG1_TIME_PARA_GRAN     (1 << 4)
+#define GPMC_CONFIG1_FCLK_DIV(val)      (val & 3)
+#define GPMC_CONFIG1_FCLK_DIV2          (GPMC_CONFIG1_FCLK_DIV(1))
+#define GPMC_CONFIG1_FCLK_DIV3          (GPMC_CONFIG1_FCLK_DIV(2))
+#define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
+#define GPMC_CONFIG7_CSVALID		(1 << 6)
+
 #define	GPMC_CONFIG2_CSEXTRADELAY		BIT(7)
 #define	GPMC_CONFIG3_ADVEXTRADELAY		BIT(7)
 #define	GPMC_CONFIG4_OEEXTRADELAY		BIT(7)
@@ -87,6 +126,12 @@
 #define	GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN	BIT(6)
 #define	GPMC_CONFIG6_CYCLE2CYCLESAMECSEN	BIT(7)
 
+#define GPMC_DEVICETYPE_NOR		0
+#define GPMC_DEVICETYPE_NAND		2
+#define WR_RD_PIN_MONITORING		0x00600000
+#define GPMC_IRQ_FIFOEVENTENABLE	0x01
+#define GPMC_IRQ_COUNT_EVENT		0x02
+
 #define GPMC_CS0_OFFSET		0x60
 #define GPMC_CS_SIZE		0x30
 #define	GPMC_BCH_SIZE		0x10
@@ -163,7 +208,7 @@ static u32 gpmc_read_reg(int idx)
 	return __raw_readl(gpmc_base + idx);
 }
 
-void gpmc_cs_write_reg(int cs, int idx, u32 val)
+static void gpmc_cs_write_reg(int cs, int idx, u32 val)
 {
 	void __iomem *reg_addr;
 
@@ -215,11 +260,6 @@ static unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
 	return (time_ps + tick_ps - 1) / tick_ps;
 }
 
-unsigned int gpmc_ticks_to_ns(unsigned int ticks)
-{
-	return ticks * gpmc_get_fclk_period() / 1000;
-}
-
 static unsigned int gpmc_ticks_to_ps(unsigned int ticks)
 {
 	return ticks * gpmc_get_fclk_period();
@@ -315,7 +355,7 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
 		return -1
 #endif
 
-int gpmc_calc_divider(unsigned int sync_clk)
+static int gpmc_calc_divider(unsigned int sync_clk)
 {
 	int div;
 	u32 l;
@@ -330,7 +370,7 @@ int gpmc_calc_divider(unsigned int sync_clk)
 	return div;
 }
 
-int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
+static int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
 {
 	int div;
 	u32 l;
@@ -537,7 +577,7 @@ static int gpmc_cs_remap(int cs, u32 base)
 	return 0;
 }
 
-int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
+static int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
 {
 	struct resource *res = &gpmc_cs_mem[cs];
 	int r = -1;
@@ -575,9 +615,8 @@ out:
 	spin_unlock(&gpmc_mem_lock);
 	return r;
 }
-EXPORT_SYMBOL(gpmc_cs_request);
 
-void gpmc_cs_free(int cs)
+static void gpmc_cs_free(int cs)
 {
 	struct resource	*res = &gpmc_cs_mem[cs];
 
@@ -594,18 +633,6 @@ void gpmc_cs_free(int cs)
 	gpmc_cs_set_reserved(cs, 0);
 	spin_unlock(&gpmc_mem_lock);
 }
-EXPORT_SYMBOL(gpmc_cs_free);
-
-void gpmc_get_mem_resource(struct resource *res)
-{
-	res->start =  phys_base;
-	res->end = res->start + mem_size - 1;
-}
-
-int gpmc_get_irq(void)
-{
-	return gpmc_irq;
-}
 
 static void gpmc_mem_exit(void)
 {
@@ -937,9 +964,9 @@ static void gpmc_convert_ps_to_ns(struct gpmc_timings *t)
 	t->wr_data_mux_bus /= 1000;
 }
 
-int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
-		      struct gpmc_settings *gpmc_s,
-		      struct gpmc_device_timings *dev_t)
+static int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
+			     struct gpmc_settings *gpmc_s,
+			     struct gpmc_device_timings *dev_t)
 {
 	bool mux = false, sync = false;
 
@@ -980,7 +1007,7 @@ int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
  * register will be initialised to zero by this function. Returns 0 on
  * success and appropriate negative error code on failure.
  */
-int gpmc_cs_program_settings(int cs, struct gpmc_settings *p)
+static int gpmc_cs_program_settings(int cs, struct gpmc_settings *p)
 {
 	u32 config1;
 
@@ -1073,7 +1100,8 @@ MODULE_DEVICE_TABLE(of, gpmc_dt_ids);
  * structure is initialised to zero by this function and so any
  * previously stored settings will be cleared.
  */
-void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p)
+static void gpmc_read_settings_dt(struct device_node *np,
+				  struct gpmc_settings *p)
 {
 	memset(p, 0, sizeof(struct gpmc_settings));
 
diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h
index 301bc66..c8af000 100644
--- a/arch/arm/mach-omap2/gpmc.h
+++ b/arch/arm/mach-omap2/gpmc.h
@@ -11,77 +11,14 @@
 #ifndef __OMAP2_GPMC_H
 #define __OMAP2_GPMC_H
 
-#include <linux/platform_data/mtd-nand-omap2.h>
 #include <linux/platform_data/gpmc-omap.h>
 
-#define GPMC_CS_CONFIG1		0x00
-#define GPMC_CS_CONFIG2		0x04
-#define GPMC_CS_CONFIG3		0x08
-#define GPMC_CS_CONFIG4		0x0c
-#define GPMC_CS_CONFIG5		0x10
-#define GPMC_CS_CONFIG6		0x14
-#define GPMC_CS_CONFIG7		0x18
-
-/* ECC commands */
-#define GPMC_ECC_READ		0 /* Reset Hardware ECC for read */
-#define GPMC_ECC_WRITE		1 /* Reset Hardware ECC for write */
-#define GPMC_ECC_READSYN	2 /* Reset before syndrom is read back */
-
-#define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
-#define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
-#define GPMC_CONFIG1_READTYPE_ASYNC     (0 << 29)
-#define GPMC_CONFIG1_READTYPE_SYNC      (1 << 29)
-#define GPMC_CONFIG1_WRITEMULTIPLE_SUPP (1 << 28)
-#define GPMC_CONFIG1_WRITETYPE_ASYNC    (0 << 27)
-#define GPMC_CONFIG1_WRITETYPE_SYNC     (1 << 27)
-#define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val & 3) << 25)
-#define GPMC_CONFIG1_PAGE_LEN(val)      ((val & 3) << 23)
-#define GPMC_CONFIG1_WAIT_READ_MON      (1 << 22)
-#define GPMC_CONFIG1_WAIT_WRITE_MON     (1 << 21)
-#define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18)
-#define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val & 3) << 16)
-#define GPMC_CONFIG1_DEVICESIZE(val)    ((val & 3) << 12)
-#define GPMC_CONFIG1_DEVICESIZE_16      GPMC_CONFIG1_DEVICESIZE(1)
-#define GPMC_CONFIG1_DEVICETYPE(val)    ((val & 3) << 10)
-#define GPMC_CONFIG1_DEVICETYPE_NOR     GPMC_CONFIG1_DEVICETYPE(0)
-#define GPMC_CONFIG1_MUXTYPE(val)       ((val & 3) << 8)
-#define GPMC_CONFIG1_TIME_PARA_GRAN     (1 << 4)
-#define GPMC_CONFIG1_FCLK_DIV(val)      (val & 3)
-#define GPMC_CONFIG1_FCLK_DIV2          (GPMC_CONFIG1_FCLK_DIV(1))
-#define GPMC_CONFIG1_FCLK_DIV3          (GPMC_CONFIG1_FCLK_DIV(2))
-#define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
-#define GPMC_CONFIG7_CSVALID		(1 << 6)
-
-#define GPMC_DEVICETYPE_NOR		0
-#define GPMC_DEVICETYPE_NAND		2
-#define WR_RD_PIN_MONITORING		0x00600000
-#define GPMC_IRQ_FIFOEVENTENABLE	0x01
-#define GPMC_IRQ_COUNT_EVENT		0x02
-
-extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
-			     struct gpmc_settings *gpmc_s,
-			     struct gpmc_device_timings *dev_t);
-
-void gpmc_get_mem_resource(struct resource *res);
-int gpmc_get_irq(void);
-
-extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);
-
-extern void gpmc_cs_write_reg(int cs, int idx, u32 val);
-extern int gpmc_calc_divider(unsigned int sync_clk);
-extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t);
-extern int gpmc_cs_program_settings(int cs, struct gpmc_settings *p);
-extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
-extern void gpmc_cs_free(int cs);
 extern void omap3_gpmc_save_context(void);
 extern void omap3_gpmc_restore_context(void);
-extern void gpmc_read_settings_dt(struct device_node *np,
-				  struct gpmc_settings *p);
 int gpmc_generic_init(int cs, bool is_nand,
 		      struct gpmc_settings *settings,
 		      struct gpmc_device_timings *device_timings,
 		      struct gpmc_timings *gpmc_timings,
 		      struct platform_device *pdev,
 		      unsigned pdata_size);
-
 #endif
-- 
1.8.3.2

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

* [PATCH 35/36] ARM: OMAP2+: gpmc: move GPMC driver into drivers/memory
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Move the GPMC driver out of mach-omap2. We leave behind only
the mach-omap2 specific bits in mach-omap2/gpmc_legacy.c
i.e. gpmc_generic_init() for use by board files to register
the GPMC configuration and omap3_gpmc_save/restore_context() for
use by OMAP3 OFF mode support.

The GPMC driver is now enabled by its own kernel config option
TI_GPMC. The other drivers that need GPMC to work i.e. MTD_ONENAND_OMAP2
and MTD_NAND_OMAP2 are made to depend on TI_GPMC.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/Makefile      |    2 +-
 arch/arm/mach-omap2/gpmc.c        | 1947 -------------------------------------
 arch/arm/mach-omap2/gpmc_legacy.c |  296 ++++++
 drivers/memory/Kconfig            |   10 +
 drivers/memory/Makefile           |    1 +
 drivers/memory/ti-gpmc.c          | 1829 ++++++++++++++++++++++++++++++++++
 drivers/mtd/nand/Kconfig          |    2 +-
 drivers/mtd/onenand/Kconfig       |    6 +-
 8 files changed, 2141 insertions(+), 1952 deletions(-)
 delete mode 100644 arch/arm/mach-omap2/gpmc.c
 create mode 100644 arch/arm/mach-omap2/gpmc_legacy.c
 create mode 100644 drivers/memory/ti-gpmc.c

diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 8421f38..a2e7426 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -6,7 +6,7 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
 	-I$(srctree)/arch/arm/plat-omap/include
 
 # Common support
-obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o gpmc.o timer.o pm.o \
+obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o gpmc_legacy.o timer.o pm.o \
 	 common.o gpio.o dma.o wd_timer.o display.o i2c.o hdq1w.o omap_hwmod.o \
 	 omap_device.o sram.o drm.o
 
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
deleted file mode 100644
index 9173f71..0000000
--- a/arch/arm/mach-omap2/gpmc.c
+++ /dev/null
@@ -1,1947 +0,0 @@
-/*
- * GPMC support functions
- *
- * Copyright (C) 2005-2006 Nokia Corporation
- *
- * Author: Juha Yrjola
- *
- * Copyright (C) 2009 Texas Instruments
- * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.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.
- */
-#undef DEBUG
-
-#include <linux/irq.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/ioport.h>
-#include <linux/spinlock.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_mtd.h>
-#include <linux/of_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/slab.h>
-
-#include <linux/platform_data/mtd-nand-omap2.h>
-
-#include <asm/mach-types.h>
-
-#include "soc.h"
-#include "common.h"
-#include "omap_device.h"
-#include "gpmc.h"
-
-#define	DEVICE_NAME		"omap-gpmc"
-
-/* GPMC register offsets */
-#define GPMC_REVISION		0x00
-#define GPMC_SYSCONFIG		0x10
-#define GPMC_SYSSTATUS		0x14
-#define GPMC_IRQSTATUS		0x18
-#define GPMC_IRQENABLE		0x1c
-#define GPMC_TIMEOUT_CONTROL	0x40
-#define GPMC_ERR_ADDRESS	0x44
-#define GPMC_ERR_TYPE		0x48
-#define GPMC_CONFIG		0x50
-#define GPMC_STATUS		0x54
-#define GPMC_PREFETCH_CONFIG1	0x1e0
-#define GPMC_PREFETCH_CONFIG2	0x1e4
-#define GPMC_PREFETCH_CONTROL	0x1ec
-#define GPMC_PREFETCH_STATUS	0x1f0
-#define GPMC_ECC_CONFIG		0x1f4
-#define GPMC_ECC_CONTROL	0x1f8
-#define GPMC_ECC_SIZE_CONFIG	0x1fc
-#define GPMC_ECC1_RESULT        0x200
-#define GPMC_ECC_BCH_RESULT_0   0x240   /* not available on OMAP2 */
-#define	GPMC_ECC_BCH_RESULT_1	0x244	/* not available on OMAP2 */
-#define	GPMC_ECC_BCH_RESULT_2	0x248	/* not available on OMAP2 */
-#define	GPMC_ECC_BCH_RESULT_3	0x24c	/* not available on OMAP2 */
-
-/* GPMC ECC control settings */
-#define GPMC_ECC_CTRL_ECCCLEAR		0x100
-#define GPMC_ECC_CTRL_ECCDISABLE	0x000
-#define GPMC_ECC_CTRL_ECCREG1		0x001
-#define GPMC_ECC_CTRL_ECCREG2		0x002
-#define GPMC_ECC_CTRL_ECCREG3		0x003
-#define GPMC_ECC_CTRL_ECCREG4		0x004
-#define GPMC_ECC_CTRL_ECCREG5		0x005
-#define GPMC_ECC_CTRL_ECCREG6		0x006
-#define GPMC_ECC_CTRL_ECCREG7		0x007
-#define GPMC_ECC_CTRL_ECCREG8		0x008
-#define GPMC_ECC_CTRL_ECCREG9		0x009
-
-/* ECC commands */
-#define GPMC_ECC_READ		0 /* Reset Hardware ECC for read */
-#define GPMC_ECC_WRITE		1 /* Reset Hardware ECC for write */
-#define GPMC_ECC_READSYN	2 /* Reset before syndrom is read back */
-
-/* CS CONFIG registers */
-#define GPMC_CS_CONFIG1		0x00
-#define GPMC_CS_CONFIG2		0x04
-#define GPMC_CS_CONFIG3		0x08
-#define GPMC_CS_CONFIG4		0x0c
-#define GPMC_CS_CONFIG5		0x10
-#define GPMC_CS_CONFIG6		0x14
-#define GPMC_CS_CONFIG7		0x18
-
-#define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
-#define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
-#define GPMC_CONFIG1_READTYPE_ASYNC     (0 << 29)
-#define GPMC_CONFIG1_READTYPE_SYNC      (1 << 29)
-#define GPMC_CONFIG1_WRITEMULTIPLE_SUPP (1 << 28)
-#define GPMC_CONFIG1_WRITETYPE_ASYNC    (0 << 27)
-#define GPMC_CONFIG1_WRITETYPE_SYNC     (1 << 27)
-#define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val & 3) << 25)
-#define GPMC_CONFIG1_PAGE_LEN(val)      ((val & 3) << 23)
-#define GPMC_CONFIG1_WAIT_READ_MON      (1 << 22)
-#define GPMC_CONFIG1_WAIT_WRITE_MON     (1 << 21)
-#define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18)
-#define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val & 3) << 16)
-#define GPMC_CONFIG1_DEVICESIZE(val)    ((val & 3) << 12)
-#define GPMC_CONFIG1_DEVICESIZE_16      GPMC_CONFIG1_DEVICESIZE(1)
-#define GPMC_CONFIG1_DEVICETYPE(val)    ((val & 3) << 10)
-#define GPMC_CONFIG1_DEVICETYPE_NOR     GPMC_CONFIG1_DEVICETYPE(0)
-#define GPMC_CONFIG1_MUXTYPE(val)       ((val & 3) << 8)
-#define GPMC_CONFIG1_TIME_PARA_GRAN     (1 << 4)
-#define GPMC_CONFIG1_FCLK_DIV(val)      (val & 3)
-#define GPMC_CONFIG1_FCLK_DIV2          (GPMC_CONFIG1_FCLK_DIV(1))
-#define GPMC_CONFIG1_FCLK_DIV3          (GPMC_CONFIG1_FCLK_DIV(2))
-#define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
-#define GPMC_CONFIG7_CSVALID		(1 << 6)
-
-#define	GPMC_CONFIG2_CSEXTRADELAY		BIT(7)
-#define	GPMC_CONFIG3_ADVEXTRADELAY		BIT(7)
-#define	GPMC_CONFIG4_OEEXTRADELAY		BIT(7)
-#define	GPMC_CONFIG4_WEEXTRADELAY		BIT(23)
-#define	GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN	BIT(6)
-#define	GPMC_CONFIG6_CYCLE2CYCLESAMECSEN	BIT(7)
-
-#define GPMC_DEVICETYPE_NOR		0
-#define GPMC_DEVICETYPE_NAND		2
-#define WR_RD_PIN_MONITORING		0x00600000
-#define GPMC_IRQ_FIFOEVENTENABLE	0x01
-#define GPMC_IRQ_COUNT_EVENT		0x02
-
-#define GPMC_CS0_OFFSET		0x60
-#define GPMC_CS_SIZE		0x30
-#define	GPMC_BCH_SIZE		0x10
-
-#define GPMC_MEM_END		0x3FFFFFFF
-
-#define GPMC_CHUNK_SHIFT	24		/* 16 MB */
-#define GPMC_SECTION_SHIFT	28		/* 128 MB */
-
-#define CS_NUM_SHIFT		24
-#define ENABLE_PREFETCH		(0x1 << 7)
-#define DMA_MPU_MODE		2
-
-#define	GPMC_REVISION_MAJOR(l)		((l >> 4) & 0xf)
-#define	GPMC_REVISION_MINOR(l)		(l & 0xf)
-
-#define	GPMC_HAS_WR_ACCESS		0x1
-#define	GPMC_HAS_WR_DATA_MUX_BUS	0x2
-#define	GPMC_HAS_MUX_AAD		0x4
-
-#define GPMC_NR_WAITPINS		4
-
-static struct gpmc_omap_platform_data gpmc_pdata;
-
-/* Structure to save gpmc cs context */
-struct gpmc_cs_config {
-	u32 config1;
-	u32 config2;
-	u32 config3;
-	u32 config4;
-	u32 config5;
-	u32 config6;
-	u32 config7;
-	int is_valid;
-};
-
-/*
- * Structure to save/restore gpmc context
- * to support core off on OMAP3
- */
-struct omap3_gpmc_regs {
-	u32 sysconfig;
-	u32 irqenable;
-	u32 timeout_ctrl;
-	u32 config;
-	u32 prefetch_config1;
-	u32 prefetch_config2;
-	u32 prefetch_control;
-	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
-};
-
-static struct resource	gpmc_mem_root;
-static struct resource	gpmc_cs_mem[GPMC_CS_NUM];
-static DEFINE_SPINLOCK(gpmc_mem_lock);
-/* Define chip-selects as reserved by default until probe completes */
-static unsigned int gpmc_cs_map = ((1 << GPMC_CS_NUM) - 1);
-static unsigned int gpmc_cs_num = GPMC_CS_NUM;
-static unsigned int gpmc_nr_waitpins;
-static struct device *gpmc_dev;
-static int gpmc_irq = -EINVAL;
-static resource_size_t phys_base, mem_size;
-static unsigned gpmc_capability;
-static void __iomem *gpmc_base;
-
-static struct clk *gpmc_l3_clk;
-
-static void gpmc_write_reg(int idx, u32 val)
-{
-	__raw_writel(val, gpmc_base + idx);
-}
-
-static u32 gpmc_read_reg(int idx)
-{
-	return __raw_readl(gpmc_base + idx);
-}
-
-static void gpmc_cs_write_reg(int cs, int idx, u32 val)
-{
-	void __iomem *reg_addr;
-
-	reg_addr = gpmc_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
-	__raw_writel(val, reg_addr);
-}
-
-static u32 gpmc_cs_read_reg(int cs, int idx)
-{
-	void __iomem *reg_addr;
-
-	reg_addr = gpmc_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
-	return __raw_readl(reg_addr);
-}
-
-/* TODO: Add support for gpmc_fck to clock framework and use it */
-static unsigned long gpmc_get_fclk_period(void)
-{
-	unsigned long rate = clk_get_rate(gpmc_l3_clk);
-
-	if (rate == 0) {
-		printk(KERN_WARNING "gpmc_l3_clk not enabled\n");
-		return 0;
-	}
-
-	rate /= 1000;
-	rate = 1000000000 / rate;	/* In picoseconds */
-
-	return rate;
-}
-
-static unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
-{
-	unsigned long tick_ps;
-
-	/* Calculate in picosecs to yield more exact results */
-	tick_ps = gpmc_get_fclk_period();
-
-	return (time_ns * 1000 + tick_ps - 1) / tick_ps;
-}
-
-static unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
-{
-	unsigned long tick_ps;
-
-	/* Calculate in picosecs to yield more exact results */
-	tick_ps = gpmc_get_fclk_period();
-
-	return (time_ps + tick_ps - 1) / tick_ps;
-}
-
-static unsigned int gpmc_ticks_to_ps(unsigned int ticks)
-{
-	return ticks * gpmc_get_fclk_period();
-}
-
-static unsigned int gpmc_round_ps_to_ticks(unsigned int time_ps)
-{
-	unsigned long ticks = gpmc_ps_to_ticks(time_ps);
-
-	return ticks * gpmc_get_fclk_period();
-}
-
-static inline void gpmc_cs_modify_reg(int cs, int reg, u32 mask, bool value)
-{
-	u32 l;
-
-	l = gpmc_cs_read_reg(cs, reg);
-	if (value)
-		l |= mask;
-	else
-		l &= ~mask;
-	gpmc_cs_write_reg(cs, reg, l);
-}
-
-static void gpmc_cs_bool_timings(int cs, const struct gpmc_bool_timings *p)
-{
-	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG1,
-			   GPMC_CONFIG1_TIME_PARA_GRAN,
-			   p->time_para_granularity);
-	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG2,
-			   GPMC_CONFIG2_CSEXTRADELAY, p->cs_extra_delay);
-	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG3,
-			   GPMC_CONFIG3_ADVEXTRADELAY, p->adv_extra_delay);
-	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG4,
-			   GPMC_CONFIG4_OEEXTRADELAY, p->oe_extra_delay);
-	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG4,
-			   GPMC_CONFIG4_OEEXTRADELAY, p->we_extra_delay);
-	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG6,
-			   GPMC_CONFIG6_CYCLE2CYCLESAMECSEN,
-			   p->cycle2cyclesamecsen);
-	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG6,
-			   GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN,
-			   p->cycle2cyclediffcsen);
-}
-
-#ifdef DEBUG
-static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
-			       int time, const char *name)
-#else
-static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
-			       int time)
-#endif
-{
-	u32 l;
-	int ticks, mask, nr_bits;
-
-	if (time == 0)
-		ticks = 0;
-	else
-		ticks = gpmc_ns_to_ticks(time);
-	nr_bits = end_bit - st_bit + 1;
-	if (ticks >= 1 << nr_bits) {
-#ifdef DEBUG
-		printk(KERN_INFO "GPMC CS%d: %-10s* %3d ns, %3d ticks >= %d\n",
-				cs, name, time, ticks, 1 << nr_bits);
-#endif
-		return -1;
-	}
-
-	mask = (1 << nr_bits) - 1;
-	l = gpmc_cs_read_reg(cs, reg);
-#ifdef DEBUG
-	printk(KERN_INFO
-		"GPMC CS%d: %-10s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n",
-	       cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000,
-			(l >> st_bit) & mask, time);
-#endif
-	l &= ~(mask << st_bit);
-	l |= ticks << st_bit;
-	gpmc_cs_write_reg(cs, reg, l);
-
-	return 0;
-}
-
-#ifdef DEBUG
-#define GPMC_SET_ONE(reg, st, end, field) \
-	if (set_gpmc_timing_reg(cs, (reg), (st), (end),		\
-			t->field, #field) < 0)			\
-		return -1
-#else
-#define GPMC_SET_ONE(reg, st, end, field) \
-	if (set_gpmc_timing_reg(cs, (reg), (st), (end), t->field) < 0) \
-		return -1
-#endif
-
-static int gpmc_calc_divider(unsigned int sync_clk)
-{
-	int div;
-	u32 l;
-
-	l = sync_clk + (gpmc_get_fclk_period() - 1);
-	div = l / gpmc_get_fclk_period();
-	if (div > 4)
-		return -1;
-	if (div <= 0)
-		div = 1;
-
-	return div;
-}
-
-static int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
-{
-	int div;
-	u32 l;
-
-	div = gpmc_calc_divider(t->sync_clk);
-	if (div < 0)
-		return div;
-
-	GPMC_SET_ONE(GPMC_CS_CONFIG2,  0,  3, cs_on);
-	GPMC_SET_ONE(GPMC_CS_CONFIG2,  8, 12, cs_rd_off);
-	GPMC_SET_ONE(GPMC_CS_CONFIG2, 16, 20, cs_wr_off);
-
-	GPMC_SET_ONE(GPMC_CS_CONFIG3,  0,  3, adv_on);
-	GPMC_SET_ONE(GPMC_CS_CONFIG3,  8, 12, adv_rd_off);
-	GPMC_SET_ONE(GPMC_CS_CONFIG3, 16, 20, adv_wr_off);
-
-	GPMC_SET_ONE(GPMC_CS_CONFIG4,  0,  3, oe_on);
-	GPMC_SET_ONE(GPMC_CS_CONFIG4,  8, 12, oe_off);
-	GPMC_SET_ONE(GPMC_CS_CONFIG4, 16, 19, we_on);
-	GPMC_SET_ONE(GPMC_CS_CONFIG4, 24, 28, we_off);
-
-	GPMC_SET_ONE(GPMC_CS_CONFIG5,  0,  4, rd_cycle);
-	GPMC_SET_ONE(GPMC_CS_CONFIG5,  8, 12, wr_cycle);
-	GPMC_SET_ONE(GPMC_CS_CONFIG5, 16, 20, access);
-
-	GPMC_SET_ONE(GPMC_CS_CONFIG5, 24, 27, page_burst_access);
-
-	GPMC_SET_ONE(GPMC_CS_CONFIG6, 0, 3, bus_turnaround);
-	GPMC_SET_ONE(GPMC_CS_CONFIG6, 8, 11, cycle2cycle_delay);
-
-	GPMC_SET_ONE(GPMC_CS_CONFIG1, 18, 19, wait_monitoring);
-	GPMC_SET_ONE(GPMC_CS_CONFIG1, 25, 26, clk_activation);
-
-	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
-		GPMC_SET_ONE(GPMC_CS_CONFIG6, 16, 19, wr_data_mux_bus);
-	if (gpmc_capability & GPMC_HAS_WR_ACCESS)
-		GPMC_SET_ONE(GPMC_CS_CONFIG6, 24, 28, wr_access);
-
-	/* caller is expected to have initialized CONFIG1 to cover
-	 * at least sync vs async
-	 */
-	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
-	if (l & (GPMC_CONFIG1_READTYPE_SYNC | GPMC_CONFIG1_WRITETYPE_SYNC)) {
-#ifdef DEBUG
-		printk(KERN_INFO "GPMC CS%d CLK period is %lu ns (div %d)\n",
-				cs, (div * gpmc_get_fclk_period()) / 1000, div);
-#endif
-		l &= ~0x03;
-		l |= (div - 1);
-		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
-	}
-
-	gpmc_cs_bool_timings(cs, &t->bool_timings);
-
-	return 0;
-}
-
-static int gpmc_cs_enable_mem(int cs, u32 base, u32 size)
-{
-	u32 l;
-	u32 mask;
-
-	/*
-	 * Ensure that base address is aligned on a
-	 * boundary equal to or greater than size.
-	 */
-	if (base & (size - 1))
-		return -EINVAL;
-
-	mask = (1 << GPMC_SECTION_SHIFT) - size;
-	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
-	l &= ~0x3f;
-	l = (base >> GPMC_CHUNK_SHIFT) & 0x3f;
-	l &= ~(0x0f << 8);
-	l |= ((mask >> GPMC_CHUNK_SHIFT) & 0x0f) << 8;
-	l |= GPMC_CONFIG7_CSVALID;
-	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
-
-	return 0;
-}
-
-static void gpmc_cs_disable_mem(int cs)
-{
-	u32 l;
-
-	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
-	l &= ~GPMC_CONFIG7_CSVALID;
-	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
-}
-
-static void gpmc_cs_get_memconf(int cs, u32 *base, u32 *size)
-{
-	u32 l;
-	u32 mask;
-
-	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
-	*base = (l & 0x3f) << GPMC_CHUNK_SHIFT;
-	mask = (l >> 8) & 0x0f;
-	*size = (1 << GPMC_SECTION_SHIFT) - (mask << GPMC_CHUNK_SHIFT);
-}
-
-static int gpmc_cs_mem_enabled(int cs)
-{
-	u32 l;
-
-	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
-	return l & GPMC_CONFIG7_CSVALID;
-}
-
-static void gpmc_cs_set_reserved(int cs, int reserved)
-{
-	gpmc_cs_map &= ~(1 << cs);
-	gpmc_cs_map |= (reserved ? 1 : 0) << cs;
-}
-
-static bool gpmc_cs_reserved(int cs)
-{
-	return gpmc_cs_map & (1 << cs);
-}
-
-static unsigned long gpmc_mem_align(unsigned long size)
-{
-	int order;
-
-	size = (size - 1) >> (GPMC_CHUNK_SHIFT - 1);
-	order = GPMC_CHUNK_SHIFT - 1;
-	do {
-		size >>= 1;
-		order++;
-	} while (size);
-	size = 1 << order;
-	return size;
-}
-
-static int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size)
-{
-	struct resource	*res = &gpmc_cs_mem[cs];
-	int r;
-
-	size = gpmc_mem_align(size);
-	spin_lock(&gpmc_mem_lock);
-	res->start = base;
-	res->end = base + size - 1;
-	r = request_resource(&gpmc_mem_root, res);
-	spin_unlock(&gpmc_mem_lock);
-
-	return r;
-}
-
-static int gpmc_cs_delete_mem(int cs)
-{
-	struct resource	*res = &gpmc_cs_mem[cs];
-	int r;
-
-	spin_lock(&gpmc_mem_lock);
-	r = release_resource(res);
-	res->start = 0;
-	res->end = 0;
-	spin_unlock(&gpmc_mem_lock);
-
-	return r;
-}
-
-/**
- * gpmc_cs_remap - remaps a chip-select physical base address
- * @cs:		chip-select to remap
- * @base:	physical base address to re-map chip-select to
- *
- * Re-maps a chip-select to a new physical base address specified by
- * "base". Returns 0 on success and appropriate negative error code
- * on failure.
- */
-static int gpmc_cs_remap(int cs, u32 base)
-{
-	int ret;
-	u32 old_base, size;
-
-	if (cs > gpmc_cs_num) {
-		pr_err("%s: requested chip-select is disabled\n", __func__);
-		return -ENODEV;
-	}
-
-	/*
-	 * Make sure we ignore any device offsets from the GPMC partition
-	 * allocated for the chip select and that the new base confirms
-	 * to the GPMC 16MB minimum granularity.
-	 */ 
-	base &= ~(SZ_16M - 1);
-
-	gpmc_cs_get_memconf(cs, &old_base, &size);
-	if (base == old_base)
-		return 0;
-	gpmc_cs_disable_mem(cs);
-	ret = gpmc_cs_delete_mem(cs);
-	if (ret < 0)
-		return ret;
-	ret = gpmc_cs_insert_mem(cs, base, size);
-	if (ret < 0)
-		return ret;
-	ret = gpmc_cs_enable_mem(cs, base, size);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
-static int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
-{
-	struct resource *res = &gpmc_cs_mem[cs];
-	int r = -1;
-
-	if (cs > gpmc_cs_num) {
-		pr_err("%s: requested chip-select is disabled\n", __func__);
-		return -ENODEV;
-	}
-	size = gpmc_mem_align(size);
-	if (size > (1 << GPMC_SECTION_SHIFT))
-		return -ENOMEM;
-
-	spin_lock(&gpmc_mem_lock);
-	if (gpmc_cs_reserved(cs)) {
-		r = -EBUSY;
-		goto out;
-	}
-	if (gpmc_cs_mem_enabled(cs))
-		r = adjust_resource(res, res->start & ~(size - 1), size);
-	if (r < 0)
-		r = allocate_resource(&gpmc_mem_root, res, size, 0, ~0,
-				      size, NULL, NULL);
-	if (r < 0)
-		goto out;
-
-	r = gpmc_cs_enable_mem(cs, res->start, resource_size(res));
-	if (r < 0) {
-		release_resource(res);
-		goto out;
-	}
-
-	*base = res->start;
-	gpmc_cs_set_reserved(cs, 1);
-out:
-	spin_unlock(&gpmc_mem_lock);
-	return r;
-}
-
-static void gpmc_cs_free(int cs)
-{
-	struct resource	*res = &gpmc_cs_mem[cs];
-
-	spin_lock(&gpmc_mem_lock);
-	if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) {
-		printk(KERN_ERR "Trying to free non-reserved GPMC CS%d\n", cs);
-		BUG();
-		spin_unlock(&gpmc_mem_lock);
-		return;
-	}
-	gpmc_cs_disable_mem(cs);
-	if (res->flags)
-		release_resource(res);
-	gpmc_cs_set_reserved(cs, 0);
-	spin_unlock(&gpmc_mem_lock);
-}
-
-static void gpmc_mem_exit(void)
-{
-	int cs;
-
-	for (cs = 0; cs < gpmc_cs_num; cs++) {
-		if (!gpmc_cs_mem_enabled(cs))
-			continue;
-		gpmc_cs_delete_mem(cs);
-	}
-
-}
-
-static void gpmc_mem_init(void)
-{
-	int cs;
-
-	/*
-	 * The first 1MB of GPMC address space is typically mapped to
-	 * the internal ROM. Never allocate the first page, to
-	 * facilitate bug detection; even if we didn't boot from ROM.
-	 */
-	gpmc_mem_root.start = SZ_1M;
-	gpmc_mem_root.end = GPMC_MEM_END;
-
-	/* Reserve all regions that has been set up by bootloader */
-	for (cs = 0; cs < gpmc_cs_num; cs++) {
-		u32 base, size;
-
-		if (!gpmc_cs_mem_enabled(cs))
-			continue;
-		gpmc_cs_get_memconf(cs, &base, &size);
-		if (gpmc_cs_insert_mem(cs, base, size)) {
-			pr_warn("%s: disabling cs %d mapped at 0x%x-0x%x\n",
-				__func__, cs, base, base + size);
-			gpmc_cs_disable_mem(cs);
-		}
-	}
-}
-
-static u32 gpmc_round_ps_to_sync_clk(u32 time_ps, u32 sync_clk)
-{
-	u32 temp;
-	int div;
-
-	div = gpmc_calc_divider(sync_clk);
-	temp = gpmc_ps_to_ticks(time_ps);
-	temp = (temp + div - 1) / div;
-	return gpmc_ticks_to_ps(temp * div);
-}
-
-/* XXX: can the cycles be avoided ? */
-static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t,
-				       struct gpmc_device_timings *dev_t,
-				       bool mux)
-{
-	u32 temp;
-
-	/* adv_rd_off */
-	temp = dev_t->t_avdp_r;
-	/* XXX: mux check required ? */
-	if (mux) {
-		/* XXX: t_avdp not to be required for sync, only added for tusb
-		 * this indirectly necessitates requirement of t_avdp_r and
-		 * t_avdp_w instead of having a single t_avdp
-		 */
-		temp = max_t(u32, temp,	gpmc_t->clk_activation + dev_t->t_avdh);
-		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
-	}
-	gpmc_t->adv_rd_off = gpmc_round_ps_to_ticks(temp);
-
-	/* oe_on */
-	temp = dev_t->t_oeasu; /* XXX: remove this ? */
-	if (mux) {
-		temp = max_t(u32, temp,	gpmc_t->clk_activation + dev_t->t_ach);
-		temp = max_t(u32, temp, gpmc_t->adv_rd_off +
-				gpmc_ticks_to_ps(dev_t->cyc_aavdh_oe));
-	}
-	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
-
-	/* access */
-	/* XXX: any scope for improvement ?, by combining oe_on
-	 * and clk_activation, need to check whether
-	 * access = clk_activation + round to sync clk ?
-	 */
-	temp = max_t(u32, dev_t->t_iaa,	dev_t->cyc_iaa * gpmc_t->sync_clk);
-	temp += gpmc_t->clk_activation;
-	if (dev_t->cyc_oe)
-		temp = max_t(u32, temp, gpmc_t->oe_on +
-				gpmc_ticks_to_ps(dev_t->cyc_oe));
-	gpmc_t->access = gpmc_round_ps_to_ticks(temp);
-
-	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ps(1);
-	gpmc_t->cs_rd_off = gpmc_t->oe_off;
-
-	/* rd_cycle */
-	temp = max_t(u32, dev_t->t_cez_r, dev_t->t_oez);
-	temp = gpmc_round_ps_to_sync_clk(temp, gpmc_t->sync_clk) +
-							gpmc_t->access;
-	/* XXX: barter t_ce_rdyz with t_cez_r ? */
-	if (dev_t->t_ce_rdyz)
-		temp = max_t(u32, temp,	gpmc_t->cs_rd_off + dev_t->t_ce_rdyz);
-	gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp);
-
-	return 0;
-}
-
-static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t,
-					struct gpmc_device_timings *dev_t,
-					bool mux)
-{
-	u32 temp;
-
-	/* adv_wr_off */
-	temp = dev_t->t_avdp_w;
-	if (mux) {
-		temp = max_t(u32, temp,
-			gpmc_t->clk_activation + dev_t->t_avdh);
-		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
-	}
-	gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp);
-
-	/* wr_data_mux_bus */
-	temp = max_t(u32, dev_t->t_weasu,
-			gpmc_t->clk_activation + dev_t->t_rdyo);
-	/* XXX: shouldn't mux be kept as a whole for wr_data_mux_bus ?,
-	 * and in that case remember to handle we_on properly
-	 */
-	if (mux) {
-		temp = max_t(u32, temp,
-			gpmc_t->adv_wr_off + dev_t->t_aavdh);
-		temp = max_t(u32, temp, gpmc_t->adv_wr_off +
-				gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
-	}
-	gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp);
-
-	/* we_on */
-	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
-		gpmc_t->we_on = gpmc_round_ps_to_ticks(dev_t->t_weasu);
-	else
-		gpmc_t->we_on = gpmc_t->wr_data_mux_bus;
-
-	/* wr_access */
-	/* XXX: gpmc_capability check reqd ? , even if not, will not harm */
-	gpmc_t->wr_access = gpmc_t->access;
-
-	/* we_off */
-	temp = gpmc_t->we_on + dev_t->t_wpl;
-	temp = max_t(u32, temp,
-			gpmc_t->wr_access + gpmc_ticks_to_ps(1));
-	temp = max_t(u32, temp,
-		gpmc_t->we_on + gpmc_ticks_to_ps(dev_t->cyc_wpl));
-	gpmc_t->we_off = gpmc_round_ps_to_ticks(temp);
-
-	gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off +
-							dev_t->t_wph);
-
-	/* wr_cycle */
-	temp = gpmc_round_ps_to_sync_clk(dev_t->t_cez_w, gpmc_t->sync_clk);
-	temp += gpmc_t->wr_access;
-	/* XXX: barter t_ce_rdyz with t_cez_w ? */
-	if (dev_t->t_ce_rdyz)
-		temp = max_t(u32, temp,
-				 gpmc_t->cs_wr_off + dev_t->t_ce_rdyz);
-	gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp);
-
-	return 0;
-}
-
-static int gpmc_calc_async_read_timings(struct gpmc_timings *gpmc_t,
-					struct gpmc_device_timings *dev_t,
-					bool mux)
-{
-	u32 temp;
-
-	/* adv_rd_off */
-	temp = dev_t->t_avdp_r;
-	if (mux)
-		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
-	gpmc_t->adv_rd_off = gpmc_round_ps_to_ticks(temp);
-
-	/* oe_on */
-	temp = dev_t->t_oeasu;
-	if (mux)
-		temp = max_t(u32, temp,
-			gpmc_t->adv_rd_off + dev_t->t_aavdh);
-	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
-
-	/* access */
-	temp = max_t(u32, dev_t->t_iaa, /* XXX: remove t_iaa in async ? */
-				gpmc_t->oe_on + dev_t->t_oe);
-	temp = max_t(u32, temp,
-				gpmc_t->cs_on + dev_t->t_ce);
-	temp = max_t(u32, temp,
-				gpmc_t->adv_on + dev_t->t_aa);
-	gpmc_t->access = gpmc_round_ps_to_ticks(temp);
-
-	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ps(1);
-	gpmc_t->cs_rd_off = gpmc_t->oe_off;
-
-	/* rd_cycle */
-	temp = max_t(u32, dev_t->t_rd_cycle,
-			gpmc_t->cs_rd_off + dev_t->t_cez_r);
-	temp = max_t(u32, temp, gpmc_t->oe_off + dev_t->t_oez);
-	gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp);
-
-	return 0;
-}
-
-static int gpmc_calc_async_write_timings(struct gpmc_timings *gpmc_t,
-					 struct gpmc_device_timings *dev_t,
-					 bool mux)
-{
-	u32 temp;
-
-	/* adv_wr_off */
-	temp = dev_t->t_avdp_w;
-	if (mux)
-		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
-	gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp);
-
-	/* wr_data_mux_bus */
-	temp = dev_t->t_weasu;
-	if (mux) {
-		temp = max_t(u32, temp,	gpmc_t->adv_wr_off + dev_t->t_aavdh);
-		temp = max_t(u32, temp, gpmc_t->adv_wr_off +
-				gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
-	}
-	gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp);
-
-	/* we_on */
-	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
-		gpmc_t->we_on = gpmc_round_ps_to_ticks(dev_t->t_weasu);
-	else
-		gpmc_t->we_on = gpmc_t->wr_data_mux_bus;
-
-	/* we_off */
-	temp = gpmc_t->we_on + dev_t->t_wpl;
-	gpmc_t->we_off = gpmc_round_ps_to_ticks(temp);
-
-	gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off +
-							dev_t->t_wph);
-
-	/* wr_cycle */
-	temp = max_t(u32, dev_t->t_wr_cycle,
-				gpmc_t->cs_wr_off + dev_t->t_cez_w);
-	gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp);
-
-	return 0;
-}
-
-static int gpmc_calc_sync_common_timings(struct gpmc_timings *gpmc_t,
-			struct gpmc_device_timings *dev_t)
-{
-	u32 temp;
-
-	gpmc_t->sync_clk = gpmc_calc_divider(dev_t->clk) *
-						gpmc_get_fclk_period();
-
-	gpmc_t->page_burst_access = gpmc_round_ps_to_sync_clk(
-					dev_t->t_bacc,
-					gpmc_t->sync_clk);
-
-	temp = max_t(u32, dev_t->t_ces, dev_t->t_avds);
-	gpmc_t->clk_activation = gpmc_round_ps_to_ticks(temp);
-
-	if (gpmc_calc_divider(gpmc_t->sync_clk) != 1)
-		return 0;
-
-	if (dev_t->ce_xdelay)
-		gpmc_t->bool_timings.cs_extra_delay = true;
-	if (dev_t->avd_xdelay)
-		gpmc_t->bool_timings.adv_extra_delay = true;
-	if (dev_t->oe_xdelay)
-		gpmc_t->bool_timings.oe_extra_delay = true;
-	if (dev_t->we_xdelay)
-		gpmc_t->bool_timings.we_extra_delay = true;
-
-	return 0;
-}
-
-static int gpmc_calc_common_timings(struct gpmc_timings *gpmc_t,
-				    struct gpmc_device_timings *dev_t,
-				    bool sync)
-{
-	u32 temp;
-
-	/* cs_on */
-	gpmc_t->cs_on = gpmc_round_ps_to_ticks(dev_t->t_ceasu);
-
-	/* adv_on */
-	temp = dev_t->t_avdasu;
-	if (dev_t->t_ce_avd)
-		temp = max_t(u32, temp,
-				gpmc_t->cs_on + dev_t->t_ce_avd);
-	gpmc_t->adv_on = gpmc_round_ps_to_ticks(temp);
-
-	if (sync)
-		gpmc_calc_sync_common_timings(gpmc_t, dev_t);
-
-	return 0;
-}
-
-/* TODO: remove this function once all peripherals are confirmed to
- * work with generic timing. Simultaneously gpmc_cs_set_timings()
- * has to be modified to handle timings in ps instead of ns
-*/
-static void gpmc_convert_ps_to_ns(struct gpmc_timings *t)
-{
-	t->cs_on /= 1000;
-	t->cs_rd_off /= 1000;
-	t->cs_wr_off /= 1000;
-	t->adv_on /= 1000;
-	t->adv_rd_off /= 1000;
-	t->adv_wr_off /= 1000;
-	t->we_on /= 1000;
-	t->we_off /= 1000;
-	t->oe_on /= 1000;
-	t->oe_off /= 1000;
-	t->page_burst_access /= 1000;
-	t->access /= 1000;
-	t->rd_cycle /= 1000;
-	t->wr_cycle /= 1000;
-	t->bus_turnaround /= 1000;
-	t->cycle2cycle_delay /= 1000;
-	t->wait_monitoring /= 1000;
-	t->clk_activation /= 1000;
-	t->wr_access /= 1000;
-	t->wr_data_mux_bus /= 1000;
-}
-
-static int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
-			     struct gpmc_settings *gpmc_s,
-			     struct gpmc_device_timings *dev_t)
-{
-	bool mux = false, sync = false;
-
-	if (gpmc_s) {
-		mux = gpmc_s->mux_add_data ? true : false;
-		sync = (gpmc_s->sync_read || gpmc_s->sync_write);
-	}
-
-	memset(gpmc_t, 0, sizeof(*gpmc_t));
-
-	gpmc_calc_common_timings(gpmc_t, dev_t, sync);
-
-	if (gpmc_s && gpmc_s->sync_read)
-		gpmc_calc_sync_read_timings(gpmc_t, dev_t, mux);
-	else
-		gpmc_calc_async_read_timings(gpmc_t, dev_t, mux);
-
-	if (gpmc_s && gpmc_s->sync_write)
-		gpmc_calc_sync_write_timings(gpmc_t, dev_t, mux);
-	else
-		gpmc_calc_async_write_timings(gpmc_t, dev_t, mux);
-
-	/* TODO: remove, see function definition */
-	gpmc_convert_ps_to_ns(gpmc_t);
-
-	return 0;
-}
-
-/**
- * gpmc_cs_program_settings - programs non-timing related settings
- * @cs:		GPMC chip-select to program
- * @p:		pointer to GPMC settings structure
- *
- * Programs non-timing related settings for a GPMC chip-select, such as
- * bus-width, burst configuration, etc. Function should be called once
- * for each chip-select that is being used and must be called before
- * calling gpmc_cs_set_timings() as timing parameters in the CONFIG1
- * register will be initialised to zero by this function. Returns 0 on
- * success and appropriate negative error code on failure.
- */
-static int gpmc_cs_program_settings(int cs, struct gpmc_settings *p)
-{
-	u32 config1;
-
-	if ((!p->device_width) || (p->device_width > GPMC_DEVWIDTH_16BIT)) {
-		pr_err("%s: invalid width %d!", __func__, p->device_width);
-		return -EINVAL;
-	}
-
-	/* Address-data multiplexing not supported for NAND devices */
-	if (p->device_nand && p->mux_add_data) {
-		pr_err("%s: invalid configuration!\n", __func__);
-		return -EINVAL;
-	}
-
-	if ((p->mux_add_data > GPMC_MUX_AD) ||
-	    ((p->mux_add_data == GPMC_MUX_AAD) &&
-	     !(gpmc_capability & GPMC_HAS_MUX_AAD))) {
-		pr_err("%s: invalid multiplex configuration!\n", __func__);
-		return -EINVAL;
-	}
-
-	/* Page/burst mode supports lengths of 4, 8 and 16 bytes */
-	if (p->burst_read || p->burst_write) {
-		switch (p->burst_len) {
-		case GPMC_BURST_4:
-		case GPMC_BURST_8:
-		case GPMC_BURST_16:
-			break;
-		default:
-			pr_err("%s: invalid page/burst-length (%d)\n",
-			       __func__, p->burst_len);
-			return -EINVAL;
-		}
-	}
-
-	if ((p->wait_on_read || p->wait_on_write) &&
-	    (p->wait_pin > gpmc_nr_waitpins)) {
-		pr_err("%s: invalid wait-pin (%d)\n", __func__, p->wait_pin);
-		return -EINVAL;
-	}
-
-	config1 = GPMC_CONFIG1_DEVICESIZE((p->device_width - 1));
-
-	if (p->sync_read)
-		config1 |= GPMC_CONFIG1_READTYPE_SYNC;
-	if (p->sync_write)
-		config1 |= GPMC_CONFIG1_WRITETYPE_SYNC;
-	if (p->wait_on_read)
-		config1 |= GPMC_CONFIG1_WAIT_READ_MON;
-	if (p->wait_on_write)
-		config1 |= GPMC_CONFIG1_WAIT_WRITE_MON;
-	if (p->wait_on_read || p->wait_on_write)
-		config1 |= GPMC_CONFIG1_WAIT_PIN_SEL(p->wait_pin);
-	if (p->device_nand)
-		config1	|= GPMC_CONFIG1_DEVICETYPE(GPMC_DEVICETYPE_NAND);
-	if (p->mux_add_data)
-		config1	|= GPMC_CONFIG1_MUXTYPE(p->mux_add_data);
-	if (p->burst_read)
-		config1 |= GPMC_CONFIG1_READMULTIPLE_SUPP;
-	if (p->burst_write)
-		config1 |= GPMC_CONFIG1_WRITEMULTIPLE_SUPP;
-	if (p->burst_read || p->burst_write) {
-		config1 |= GPMC_CONFIG1_PAGE_LEN(p->burst_len >> 3);
-		config1 |= p->burst_wrap ? GPMC_CONFIG1_WRAPBURST_SUPP : 0;
-	}
-
-	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, config1);
-
-	return 0;
-}
-
-#ifdef CONFIG_OF
-static struct of_device_id gpmc_dt_ids[] = {
-	{ .compatible = "ti,omap2420-gpmc" },
-	{ .compatible = "ti,omap2430-gpmc" },
-	{ .compatible = "ti,omap3430-gpmc" },	/* omap3430 & omap3630 */
-	{ .compatible = "ti,omap4430-gpmc" },	/* omap4430 & omap4460 & omap543x */
-	{ .compatible = "ti,am3352-gpmc" },	/* am335x devices */
-	{ }
-};
-MODULE_DEVICE_TABLE(of, gpmc_dt_ids);
-
-/**
- * gpmc_read_settings_dt - read gpmc settings from device-tree
- * @np:		pointer to device-tree node for a gpmc child device
- * @p:		pointer to gpmc settings structure
- *
- * Reads the GPMC settings for a GPMC child device from device-tree and
- * stores them in the GPMC settings structure passed. The GPMC settings
- * structure is initialised to zero by this function and so any
- * previously stored settings will be cleared.
- */
-static void gpmc_read_settings_dt(struct device_node *np,
-				  struct gpmc_settings *p)
-{
-	memset(p, 0, sizeof(struct gpmc_settings));
-
-	p->sync_read = of_property_read_bool(np, "gpmc,sync-read");
-	p->sync_write = of_property_read_bool(np, "gpmc,sync-write");
-	of_property_read_u32(np, "gpmc,device-width", &p->device_width);
-	of_property_read_u32(np, "gpmc,mux-add-data", &p->mux_add_data);
-
-	if (!of_property_read_u32(np, "gpmc,burst-length", &p->burst_len)) {
-		p->burst_wrap = of_property_read_bool(np, "gpmc,burst-wrap");
-		p->burst_read = of_property_read_bool(np, "gpmc,burst-read");
-		p->burst_write = of_property_read_bool(np, "gpmc,burst-write");
-		if (!p->burst_read && !p->burst_write)
-			pr_warn("%s: page/burst-length set but not used!\n",
-				__func__);
-	}
-
-	if (!of_property_read_u32(np, "gpmc,wait-pin", &p->wait_pin)) {
-		p->wait_on_read = of_property_read_bool(np,
-							"gpmc,wait-on-read");
-		p->wait_on_write = of_property_read_bool(np,
-							 "gpmc,wait-on-write");
-		if (!p->wait_on_read && !p->wait_on_write)
-			pr_warn("%s: read/write wait monitoring not enabled!\n",
-				__func__);
-	}
-}
-
-static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
-						struct gpmc_timings *gpmc_t)
-{
-	struct gpmc_bool_timings *p;
-
-	if (!np || !gpmc_t)
-		return;
-
-	memset(gpmc_t, 0, sizeof(*gpmc_t));
-
-	/* minimum clock period for syncronous mode */
-	of_property_read_u32(np, "gpmc,sync-clk-ps", &gpmc_t->sync_clk);
-
-	/* chip select timtings */
-	of_property_read_u32(np, "gpmc,cs-on-ns", &gpmc_t->cs_on);
-	of_property_read_u32(np, "gpmc,cs-rd-off-ns", &gpmc_t->cs_rd_off);
-	of_property_read_u32(np, "gpmc,cs-wr-off-ns", &gpmc_t->cs_wr_off);
-
-	/* ADV signal timings */
-	of_property_read_u32(np, "gpmc,adv-on-ns", &gpmc_t->adv_on);
-	of_property_read_u32(np, "gpmc,adv-rd-off-ns", &gpmc_t->adv_rd_off);
-	of_property_read_u32(np, "gpmc,adv-wr-off-ns", &gpmc_t->adv_wr_off);
-
-	/* WE signal timings */
-	of_property_read_u32(np, "gpmc,we-on-ns", &gpmc_t->we_on);
-	of_property_read_u32(np, "gpmc,we-off-ns", &gpmc_t->we_off);
-
-	/* OE signal timings */
-	of_property_read_u32(np, "gpmc,oe-on-ns", &gpmc_t->oe_on);
-	of_property_read_u32(np, "gpmc,oe-off-ns", &gpmc_t->oe_off);
-
-	/* access and cycle timings */
-	of_property_read_u32(np, "gpmc,page-burst-access-ns",
-			     &gpmc_t->page_burst_access);
-	of_property_read_u32(np, "gpmc,access-ns", &gpmc_t->access);
-	of_property_read_u32(np, "gpmc,rd-cycle-ns", &gpmc_t->rd_cycle);
-	of_property_read_u32(np, "gpmc,wr-cycle-ns", &gpmc_t->wr_cycle);
-	of_property_read_u32(np, "gpmc,bus-turnaround-ns",
-			     &gpmc_t->bus_turnaround);
-	of_property_read_u32(np, "gpmc,cycle2cycle-delay-ns",
-			     &gpmc_t->cycle2cycle_delay);
-	of_property_read_u32(np, "gpmc,wait-monitoring-ns",
-			     &gpmc_t->wait_monitoring);
-	of_property_read_u32(np, "gpmc,clk-activation-ns",
-			     &gpmc_t->clk_activation);
-
-	/* only applicable to OMAP3+ */
-	of_property_read_u32(np, "gpmc,wr-access-ns", &gpmc_t->wr_access);
-	of_property_read_u32(np, "gpmc,wr-data-mux-bus-ns",
-			     &gpmc_t->wr_data_mux_bus);
-
-	/* bool timing parameters */
-	p = &gpmc_t->bool_timings;
-
-	p->cycle2cyclediffcsen =
-		of_property_read_bool(np, "gpmc,cycle2cycle-diffcsen");
-	p->cycle2cyclesamecsen =
-		of_property_read_bool(np, "gpmc,cycle2cycle-samecsen");
-	p->we_extra_delay = of_property_read_bool(np, "gpmc,we-extra-delay");
-	p->oe_extra_delay = of_property_read_bool(np, "gpmc,oe-extra-delay");
-	p->adv_extra_delay = of_property_read_bool(np, "gpmc,adv-extra-delay");
-	p->cs_extra_delay = of_property_read_bool(np, "gpmc,cs-extra-delay");
-	p->time_para_granularity =
-		of_property_read_bool(np, "gpmc,time-para-granularity");
-}
-
-/**
- * gpmc_probe_generic_child - configures the gpmc for a child device
- * @pdev:	pointer to gpmc platform device
- * @child:	pointer to device-tree node for child device
- *
- * Allocates and configures a GPMC chip-select for a child device.
- * Returns 0 on success and appropriate negative error code on failure.
- */
-static int gpmc_probe_generic_child(struct platform_device *pdev,
-				struct device_node *child)
-{
-	struct gpmc_settings gpmc_s;
-	struct gpmc_timings gpmc_t;
-	struct resource res;
-	unsigned long base;
-	int ret, cs;
-	struct device *dev = &pdev->dev;
-
-	if (of_property_read_u32(child, "reg", &cs) < 0) {
-		dev_err(&pdev->dev, "%s has no 'reg' property\n",
-			child->full_name);
-		return -ENODEV;
-	}
-
-	if (of_address_to_resource(child, 0, &res) < 0) {
-		dev_err(&pdev->dev, "%s has malformed 'reg' property\n",
-			child->full_name);
-		return -ENODEV;
-	}
-
-	ret = gpmc_cs_request(cs, resource_size(&res), &base);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "cannot request GPMC CS %d\n", cs);
-		return ret;
-	}
-
-	/*
-	 * For some GPMC devices we still need to rely on the bootloader
-	 * timings because the devices can be connected via FPGA. So far
-	 * the list is smc91x on the omap2 SDP boards, and 8250 on zooms.
-	 * REVISIT: Add timing support from slls644g.pdf and from the
-	 * lan91c96 manual.
-	 */
-	if (of_device_is_compatible(child, "ns16550a") ||
-	    of_device_is_compatible(child, "smsc,lan91c94") ||
-	    of_device_is_compatible(child, "smsc,lan91c111")) {
-		dev_warn(&pdev->dev,
-			 "%s using bootloader timings on CS%d\n",
-			 child->name, cs);
-		goto no_timings;
-	}
-
-	/*
-	 * FIXME: gpmc_cs_request() will map the CS to an arbitary
-	 * location in the gpmc address space. When booting with
-	 * device-tree we want the NOR flash to be mapped to the
-	 * location specified in the device-tree blob. So remap the
-	 * CS to this location. Once DT migration is complete should
-	 * just make gpmc_cs_request() map a specific address.
-	 */
-	ret = gpmc_cs_remap(cs, res.start);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "cannot remap GPMC CS %d to %pa\n",
-			cs, &res.start);
-		goto err;
-	}
-
-	gpmc_read_settings_dt(child, &gpmc_s);
-
-	if (of_node_cmp(child->name, "nand") == 0) {
-		/* NAND specific setup */
-		u32 val;
-
-		val = of_get_nand_bus_width(child);
-		switch (val) {
-		case 8:
-			gpmc_s.device_width = GPMC_DEVWIDTH_8BIT;
-			break;
-		case 16:
-			gpmc_s.device_width = GPMC_DEVWIDTH_16BIT;
-			break;
-		default:
-			dev_err(dev, "%s: invalid 'nand-bus-width'\n",
-				child->name);
-			ret = -EINVAL;
-			goto err;
-		}
-
-		gpmc_s.device_nand = true;
-
-	} else if (of_node_cmp(child->name, "onenand") == 0) {
-		/* DT incorrectly sets sync modes, onenand default is async */
-		gpmc_s.sync_read = false;
-		gpmc_s.sync_write = false;
-
-	} else {
-		if (of_property_read_u32(child, "bank-width",
-					 &gpmc_s.device_width)) {
-			dev_err(dev, "%s: no 'bank-width' property\n",
-				child->name);
-			goto err;
-		}
-
-		if (gpmc_s.device_width < 1 || gpmc_s.device_width > 2) {
-			dev_err(dev, "%s: invalid 'bank-width'\n",
-				child->name);
-			goto err;
-		}
-	}
-
-	ret = gpmc_cs_program_settings(cs, &gpmc_s);
-	if (ret < 0)
-		goto err;
-
-	gpmc_read_timings_dt(child, &gpmc_t);
-	gpmc_cs_set_timings(cs, &gpmc_t);
-
-no_timings:
-	if (of_platform_device_create(child, NULL, &pdev->dev))
-		return 0;
-
-	dev_err(&pdev->dev, "failed to create gpmc child %s\n", child->name);
-	ret = -ENODEV;
-
-err:
-	gpmc_cs_free(cs);
-
-	return ret;
-}
-
-static int gpmc_probe_dt(struct platform_device *pdev)
-{
-	int ret;
-	struct device_node *child;
-
-	ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-cs",
-				   &gpmc_cs_num);
-	if (ret < 0) {
-		pr_err("%s: number of chip-selects not defined\n", __func__);
-		return ret;
-	} else if (gpmc_cs_num < 1) {
-		pr_err("%s: all chip-selects are disabled\n", __func__);
-		return -EINVAL;
-	} else if (gpmc_cs_num > GPMC_CS_NUM) {
-		pr_err("%s: number of supported chip-selects cannot be > %d\n",
-					 __func__, GPMC_CS_NUM);
-		return -EINVAL;
-	}
-
-	ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-waitpins",
-				   &gpmc_nr_waitpins);
-	if (ret < 0) {
-		pr_err("%s: number of wait pins not found!\n", __func__);
-		return ret;
-	}
-
-	for_each_child_of_node(pdev->dev.of_node, child) {
-
-		if (!child->name)
-			continue;
-
-		if (of_node_cmp(child->name, "ethernet") == 0 ||
-		    of_node_cmp(child->name, "nor") == 0 ||
-		    of_node_cmp(child->name, "uart") == 0 ||
-		    of_node_cmp(child->name, "nand") == 0 ||
-		    of_node_cmp(child->name, "onenand") == 0)
-			ret = gpmc_probe_generic_child(pdev, child);
-
-		if (WARN(ret < 0, "%s: probing gpmc child %s failed\n",
-			 __func__, child->full_name))
-			of_node_put(child);
-	}
-
-	return 0;
-}
-#else
-static int gpmc_probe_dt(struct platform_device *pdev)
-{
-	return 0;
-}
-#endif
-
-static int gpmc_nand_setup(struct platform_device *parent_pdev,
-			   struct gpmc_omap_cs_data *cs)
-{
-	struct resource *res;
-	struct resource *res_gpmc;
-
-	if (!cs->pdev)
-		return -EINVAL;
-
-	res = cs->pdev->resource;
-
-	if (cs->pdev->num_resources < 3)
-		return -EINVAL;
-
-	if (resource_type(&res[1]) != IORESOURCE_MEM ||
-	    resource_type(&res[2]) != IORESOURCE_IRQ)
-		return -EINVAL;
-
-	if (!cs->settings)
-		return -EINVAL;
-
-	/* GPMC register space */
-	res_gpmc = platform_get_resource(parent_pdev, IORESOURCE_MEM, 0);
-	if (!res_gpmc)
-		return -EINVAL;
-
-	res[1] = *res_gpmc;
-
-	/* setup IRQ resources */
-	res[2].start = gpmc_irq;
-
-	cs->settings->device_nand = true;
-
-	return 0;
-}
-
-static void gpmc_probe_legacy(struct platform_device *pdev)
-{
-	int i, rc, j;
-	struct device *dev = &pdev->dev;
-	struct gpmc_omap_platform_data *gpmc_pdata;
-	struct resource *mem_res;
-	unsigned long cs_base;
-	resource_size_t size;
-	struct gpmc_timings gpmc_timings;
-	struct gpmc_omap_cs_data *cs;
-
-	gpmc_pdata = dev->platform_data;
-	gpmc_cs_num = GPMC_CS_NUM;
-	gpmc_nr_waitpins = GPMC_NR_WAITPINS;
-
-	for (i = 0; i < GPMC_CS_NUM; i++) {
-		cs = &gpmc_pdata->cs[i];
-		if (!cs->valid)
-			continue;
-
-		if (cs->settings) {
-			if (gpmc_cs_program_settings(i, cs->settings)) {
-				dev_err(dev,
-					"Couldn't program settings for CS %d\n",
-					i);
-				continue;
-			}
-		}
-
-		/* give device_timings priority over gpmc_timings */
-		if (cs->device_timings) {
-			gpmc_calc_timings(&gpmc_timings, cs->settings,
-					  cs->device_timings);
-
-			if (gpmc_cs_set_timings(i, &gpmc_timings)) {
-				dev_err(dev,
-					"Couldn't program timings for CS %d\n",
-					i);
-				continue;
-			}
-		} else if (cs->gpmc_timings) {
-			if (gpmc_cs_set_timings(i, cs->gpmc_timings)) {
-				dev_err(dev,
-					"Couldn't program timings for CS %d\n",
-					i);
-				continue;
-			}
-		}
-	}
-
-	/*
-	 * All Chip Selects must be configured before platform devices are
-	 * created as some devices (e.g. tusb6010) can use multiple
-	 * Chip selects.
-	 */
-
-	/* Fixup Memory resources */
-	for (i = 0; i < GPMC_CS_NUM; i++) {
-		int required_resources;
-
-		cs = &gpmc_pdata->cs[i];
-		if (!cs->valid)
-			continue;
-
-		if (!cs->pdev)
-			continue;
-
-		/* Customized NAND setup */
-		if (cs->is_nand) {
-			if (gpmc_nand_setup(pdev, cs)) {
-				dev_err(dev, "Error setting up NAND on CS %d\n",
-					i);
-				continue;
-			}
-		}
-
-		mem_res = cs->pdev->resource;
-
-		/*
-		 * If device is present multiple times, fix the subsequent
-		 * resources
-		 */
-		required_resources = 1;
-		for (j = 0; j < i; j++) {
-			if (gpmc_pdata->cs[j].pdev == cs->pdev) {
-				mem_res++;
-				required_resources++;
-			}
-		}
-
-		if (cs->pdev->num_resources < required_resources ||
-		    resource_type(mem_res) != IORESOURCE_MEM) {
-			dev_err(dev, "Invalid IOMEM resource for CS %d\n", i);
-			continue;
-		}
-
-		/*
-		 * Request a CS space. Use size from
-		 * platform device's MEM resource
-		 */
-		size = mem_res->end - mem_res->start + 1;
-		if (gpmc_cs_request(i, size, &cs_base)) {
-			dev_err(dev, "Couldn't request resource for CS %d\n",
-				i);
-			continue;
-		}
-
-		mem_res->start = cs_base;
-		mem_res->end = cs_base + size - 1;
-	}
-
-	/* create the platform devices */
-	for (i = 0; i < GPMC_CS_NUM; i++) {
-		bool registered;
-
-		cs = &gpmc_pdata->cs[i];
-		if (!cs->valid)
-			continue;
-
-		if (!cs->pdev)
-			continue;
-
-		/*
-		 * same device can be present on multiple CS, don't
-		 * register device more than once.
-		 */
-		registered = false;
-		for (j = 0; j < i; j++) {
-			if (gpmc_pdata->cs[j].pdev == cs->pdev) {
-				registered = true;
-				break;
-			}
-		}
-
-		if (registered)
-			continue;
-
-		cs->pdev->dev.parent = dev;
-		rc = platform_device_register(cs->pdev);
-		if (rc < 0) {
-			dev_err(dev,
-				"Failed to register device %s on CS %d\n",
-				cs->pdev->name, i);
-			continue;
-		}
-	}
-}
-
-static int gpmc_probe(struct platform_device *pdev)
-{
-	int rc;
-	u32 l;
-	struct resource *res;
-	struct device *dev = &pdev->dev;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res == NULL)
-		return -ENOENT;
-
-	phys_base = res->start;
-	mem_size = resource_size(res);
-
-	gpmc_base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(gpmc_base))
-		return PTR_ERR(gpmc_base);
-
-	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "Failed to get resource: irq\n");
-		return -EINVAL;
-	}
-
-	gpmc_irq = res->start;
-
-	gpmc_l3_clk = clk_get(&pdev->dev, "fck");
-	if (IS_ERR(gpmc_l3_clk)) {
-		dev_err(&pdev->dev, "error: clk_get\n");
-		gpmc_irq = 0;
-		return PTR_ERR(gpmc_l3_clk);
-	}
-
-	pm_runtime_enable(&pdev->dev);
-	pm_runtime_get_sync(&pdev->dev);
-
-	gpmc_dev = dev;
-
-	l = gpmc_read_reg(GPMC_REVISION);
-
-	/*
-	 * FIXME: Once device-tree migration is complete the below flags
-	 * should be populated based upon the device-tree compatible
-	 * string. For now just use the IP revision. OMAP3+ devices have
-	 * the wr_access and wr_data_mux_bus register fields. OMAP4+
-	 * devices support the addr-addr-data multiplex protocol.
-	 *
-	 * GPMC IP revisions:
-	 * - OMAP24xx			= 2.0
-	 * - OMAP3xxx			= 5.0
-	 * - OMAP44xx/54xx/AM335x	= 6.0
-	 */
-	if (GPMC_REVISION_MAJOR(l) > 0x4)
-		gpmc_capability = GPMC_HAS_WR_ACCESS | GPMC_HAS_WR_DATA_MUX_BUS;
-	if (GPMC_REVISION_MAJOR(l) > 0x5)
-		gpmc_capability |= GPMC_HAS_MUX_AAD;
-	dev_info(dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l),
-		 GPMC_REVISION_MINOR(l));
-
-	gpmc_mem_init();
-
-	/* Now the GPMC is initialised, unreserve the chip-selects */
-	gpmc_cs_map = 0;
-
-	if (dev->of_node) {
-		rc = gpmc_probe_dt(pdev);
-		if (rc) {
-			dev_err(dev, "gpmc_probe_dt() failed\n");
-			goto error;
-		}
-	} else {
-		/* Legacy probing based on platform data */
-		if (!dev->platform_data) {
-			dev_err(dev, "No platform data\n");
-			rc = -EINVAL;
-			goto error;
-		}
-
-		gpmc_probe_legacy(pdev);
-	}
-
-	return 0;
-
-error:
-	pm_runtime_put_sync(dev);
-	clk_put(gpmc_l3_clk);
-	return rc;
-}
-
-static int gpmc_remove(struct platform_device *pdev)
-{
-	gpmc_mem_exit();
-	pm_runtime_put_sync(&pdev->dev);
-	pm_runtime_disable(&pdev->dev);
-	gpmc_dev = NULL;
-	return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int gpmc_suspend(struct device *dev)
-{
-	omap3_gpmc_save_context();
-	pm_runtime_put_sync(dev);
-	return 0;
-}
-
-static int gpmc_resume(struct device *dev)
-{
-	pm_runtime_get_sync(dev);
-	omap3_gpmc_restore_context();
-	return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(gpmc_pm_ops, gpmc_suspend, gpmc_resume);
-
-static struct platform_driver gpmc_driver = {
-	.probe		= gpmc_probe,
-	.remove		= gpmc_remove,
-	.driver		= {
-		.name	= DEVICE_NAME,
-		.owner	= THIS_MODULE,
-		.of_match_table = of_match_ptr(gpmc_dt_ids),
-		.pm	= &gpmc_pm_ops,
-	},
-};
-
-static __init int gpmc_init(void)
-{
-	return platform_driver_register(&gpmc_driver);
-}
-
-static __exit void gpmc_exit(void)
-{
-	platform_driver_unregister(&gpmc_driver);
-
-}
-
-module_init(gpmc_init);
-module_exit(gpmc_exit);
-
-static int __init omap_gpmc_init(void)
-{
-	struct omap_hwmod *oh;
-	struct platform_device *pdev;
-	char *oh_name = "gpmc";
-
-	/*
-	 * if the board boots up with a populated DT, do not
-	 * manually add the device from this initcall
-	 */
-	if (of_have_populated_dt())
-		return -ENODEV;
-
-	oh = omap_hwmod_lookup(oh_name);
-	if (!oh) {
-		pr_err("Could not look up %s\n", oh_name);
-		return -ENODEV;
-	}
-
-	pdev = omap_device_build(DEVICE_NAME, -1, oh, (void *)&gpmc_pdata,
-				 sizeof(gpmc_pdata));
-	WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
-
-	return PTR_RET(pdev);
-}
-/* must run after machine_init code. i.e. arch_init */
-omap_subsys_initcall(omap_gpmc_init);
-
-/**
- * gpmc_generic_init - Initialize platform data for a Chip Select
- *
- * @cs		chip select number
- * @is_nand	true if device is NAND flash.
- * @settings	GPMC settings
- * @device_timings	device timings for device on this CS
- * @gpmc_timings	GPMC timings
- * @pdev	platform device for the device on this CS
- * @pdata_size	platform data size for the platform device
- */
-int gpmc_generic_init(int cs, bool is_nand,
-		      struct gpmc_settings *settings,
-		      struct gpmc_device_timings *device_timings,
-		      struct gpmc_timings *gpmc_timings,
-		      struct platform_device *pdev, unsigned pdata_size)
-{
-	struct gpmc_settings *gpmc_s = NULL;
-	struct gpmc_device_timings *gpmc_dev_t = NULL;
-	struct gpmc_timings *gpmc_t;
-
-	if (cs >= GPMC_CS_NUM) {
-		pr_err("%s: Invalid cs specified. Max CS = %d\n",
-		       __func__, GPMC_CS_NUM);
-		return -EINVAL;
-	}
-
-	if (gpmc_pdata.cs[cs].valid) {
-		pr_err("%s: cs %d already requested, ignoring new request\n",
-		       __func__, cs);
-		return -EINVAL;
-	}
-
-	if (settings) {
-		gpmc_s = kmemdup(settings, sizeof(*settings), GFP_KERNEL);
-		if (!gpmc_s)
-			return -ENOMEM;
-
-		gpmc_pdata.cs[cs].settings = gpmc_s;
-	}
-
-	if (device_timings) {
-		gpmc_dev_t = kmemdup(device_timings, sizeof(*device_timings),
-				     GFP_KERNEL);
-		if (!gpmc_dev_t)
-			goto dev_t_fail;
-
-		gpmc_pdata.cs[cs].device_timings = gpmc_dev_t;
-	}
-
-	if (gpmc_timings) {
-		gpmc_t = kmemdup(gpmc_timings, sizeof(*gpmc_timings),
-				 GFP_KERNEL);
-		if (!gpmc_t)
-			goto gpmc_t_fail;
-
-		gpmc_pdata.cs[cs].gpmc_timings = gpmc_t;
-	}
-
-	gpmc_pdata.cs[cs].is_nand = is_nand;
-	gpmc_pdata.cs[cs].pdev = pdev;
-	gpmc_pdata.cs[cs].pdata_size = pdata_size;
-	gpmc_pdata.cs[cs].valid = true;
-
-	return 0;
-
-gpmc_t_fail:
-	if (device_timings)
-		kfree(gpmc_dev_t);
-dev_t_fail:
-	if (settings)
-		kfree(gpmc_s);
-
-	return -ENOMEM;
-}
-
-/**
- * omap_gpmc_retime - Reconfigre GPMC timings for the device
- *
- * @cs		Chip select number
- * @gpmc_s	GPMC settings
- * @dev_t	New device timings to set
- */
-int omap_gpmc_retime(int cs, struct gpmc_settings *gpmc_s,
-		     struct gpmc_device_timings *dev_t)
-{
-	struct gpmc_timings gpmc_t;
-	struct device *dev = gpmc_dev;
-
-	if (!gpmc_dev)
-		return -ENODEV;
-
-	if (cs < 0 || cs >= gpmc_cs_num) {
-		dev_err(dev, "%s: Invalid find Chip Select\n", __func__);
-		return cs;
-	}
-
-	if (gpmc_cs_program_settings(cs, gpmc_s)) {
-		dev_err(dev, "%s: Failed to set GPMC settings\n", __func__);
-		return -EINVAL;
-	}
-
-	gpmc_calc_timings(&gpmc_t, gpmc_s, dev_t);
-	if (gpmc_cs_set_timings(cs, &gpmc_t)) {
-		dev_err(dev, "%s: Failed to set GPMC timings\n", __func__);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(omap_gpmc_retime);
-
-/**
- * omap_gpmc_get_clk_period - Get the nearest possible (equal to or higer) GPMC
- *				synchronous clock (GPMC_CLK) period.
- *
- * @cs		Chip select number
- * @min_ps	Minimum synchronous clock period supporded by the device
- *
- * Returns the nearest possible GPMC clock period in picoseconds, equal to or
- * higher than the requested period. 0 in case of error.
- */
-unsigned long omap_gpmc_get_clk_period(int cs,
-				       unsigned long min_ps)
-{
-	int div;
-	unsigned long clk_ps;
-	struct device *dev = gpmc_dev;
-
-	if (!gpmc_dev)
-		return 0;
-
-	if (cs < 0 || cs >= gpmc_cs_num) {
-		dev_err(dev, "%s: Invalid Chip Select\n", __func__);
-		return cs;
-	}
-
-	div = gpmc_calc_divider(min_ps);
-	if (div < 0) {
-		dev_err(dev, "%s: Can't support requested clock period %lu ps\n",
-			__func__, min_ps);
-		return 0;
-	}
-
-	clk_ps = gpmc_get_fclk_period() * div;
-
-	return clk_ps;
-}
-EXPORT_SYMBOL_GPL(omap_gpmc_get_clk_period);
-
-static struct omap3_gpmc_regs gpmc_context;
-
-void omap3_gpmc_save_context(void)
-{
-	int i;
-
-	gpmc_context.sysconfig = gpmc_read_reg(GPMC_SYSCONFIG);
-	gpmc_context.irqenable = gpmc_read_reg(GPMC_IRQENABLE);
-	gpmc_context.timeout_ctrl = gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
-	gpmc_context.config = gpmc_read_reg(GPMC_CONFIG);
-	gpmc_context.prefetch_config1 = gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
-	gpmc_context.prefetch_config2 = gpmc_read_reg(GPMC_PREFETCH_CONFIG2);
-	gpmc_context.prefetch_control = gpmc_read_reg(GPMC_PREFETCH_CONTROL);
-	for (i = 0; i < gpmc_cs_num; i++) {
-		gpmc_context.cs_context[i].is_valid = gpmc_cs_mem_enabled(i);
-		if (gpmc_context.cs_context[i].is_valid) {
-			gpmc_context.cs_context[i].config1 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG1);
-			gpmc_context.cs_context[i].config2 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG2);
-			gpmc_context.cs_context[i].config3 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG3);
-			gpmc_context.cs_context[i].config4 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG4);
-			gpmc_context.cs_context[i].config5 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG5);
-			gpmc_context.cs_context[i].config6 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG6);
-			gpmc_context.cs_context[i].config7 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
-		}
-	}
-}
-
-void omap3_gpmc_restore_context(void)
-{
-	int i;
-
-	gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig);
-	gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable);
-	gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl);
-	gpmc_write_reg(GPMC_CONFIG, gpmc_context.config);
-	gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1);
-	gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2);
-	gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control);
-	for (i = 0; i < gpmc_cs_num; i++) {
-		if (gpmc_context.cs_context[i].is_valid) {
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG1,
-				gpmc_context.cs_context[i].config1);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG2,
-				gpmc_context.cs_context[i].config2);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG3,
-				gpmc_context.cs_context[i].config3);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG4,
-				gpmc_context.cs_context[i].config4);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG5,
-				gpmc_context.cs_context[i].config5);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG6,
-				gpmc_context.cs_context[i].config6);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG7,
-				gpmc_context.cs_context[i].config7);
-		}
-	}
-}
diff --git a/arch/arm/mach-omap2/gpmc_legacy.c b/arch/arm/mach-omap2/gpmc_legacy.c
new file mode 100644
index 0000000..3b3f86e
--- /dev/null
+++ b/arch/arm/mach-omap2/gpmc_legacy.c
@@ -0,0 +1,296 @@
+/*
+ * GPMC support functions
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation
+ *
+ * Author: Juha Yrjola
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#include "soc.h"
+#include "gpmc.h"
+#include "omap_device.h"
+
+#define	DEVICE_NAME		"omap-gpmc"
+
+/* CS CONFIG registers */
+#define GPMC_CS_CONFIG1		0x00
+#define GPMC_CS_CONFIG2		0x04
+#define GPMC_CS_CONFIG3		0x08
+#define GPMC_CS_CONFIG4		0x0c
+#define GPMC_CS_CONFIG5		0x10
+#define GPMC_CS_CONFIG6		0x14
+#define GPMC_CS_CONFIG7		0x18
+
+#define GPMC_CS0_OFFSET		0x60
+#define GPMC_CS_SIZE		0x30
+
+/* GPMC register offsets */
+#define GPMC_SYSCONFIG		0x10
+#define GPMC_IRQENABLE		0x1c
+#define GPMC_TIMEOUT_CONTROL	0x40
+#define GPMC_CONFIG		0x50
+#define GPMC_PREFETCH_CONFIG1	0x1e0
+#define GPMC_PREFETCH_CONFIG2	0x1e4
+#define GPMC_PREFETCH_CONTROL	0x1ec
+
+#define GPMC_CONFIG7_CSVALID		(1 << 6)
+
+static struct gpmc_omap_platform_data gpmc_pdata;
+
+/* Structure to save gpmc cs context */
+struct gpmc_cs_config {
+	u32 config1;
+	u32 config2;
+	u32 config3;
+	u32 config4;
+	u32 config5;
+	u32 config6;
+	u32 config7;
+	int is_valid;
+};
+
+/*
+ * Structure to save/restore gpmc context
+ * to support core off on OMAP3
+ */
+struct omap3_gpmc_regs {
+	u32 sysconfig;
+	u32 irqenable;
+	u32 timeout_ctrl;
+	u32 config;
+	u32 prefetch_config1;
+	u32 prefetch_config2;
+	u32 prefetch_control;
+	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
+};
+
+static int __init omap_gpmc_init(void)
+{
+	struct omap_hwmod *oh;
+	struct platform_device *pdev;
+	char *oh_name = "gpmc";
+
+	/*
+	 * if the board boots up with a populated DT, do not
+	 * manually add the device from this initcall
+	 */
+	if (of_have_populated_dt())
+		return -ENODEV;
+
+	oh = omap_hwmod_lookup(oh_name);
+	if (!oh) {
+		pr_err("Could not look up %s\n", oh_name);
+		return -ENODEV;
+	}
+
+	pdev = omap_device_build(DEVICE_NAME, -1, oh, (void *)&gpmc_pdata,
+				 sizeof(gpmc_pdata));
+	WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
+
+	return PTR_RET(pdev);
+}
+/* must run after machine_init code. i.e. arch_init */
+omap_subsys_initcall(omap_gpmc_init);
+
+/**
+ * gpmc_generic_init - Initialize platform data for a Chip Select
+ *
+ * @cs		chip select number
+ * @type	GPMC_OMAP_TYPE
+ * @settings	GPMC settings
+ * @device_timings	device timings for device on this CS
+ * @gpmc_timings	GPMC timings
+ * @pdev	platform device for the device on this CS
+ * @pdata_size	platform data size for the platform device
+ */
+int gpmc_generic_init(int cs, bool is_nand,
+		      struct gpmc_settings *settings,
+		      struct gpmc_device_timings *device_timings,
+		      struct gpmc_timings *gpmc_timings,
+		      struct platform_device *pdev, unsigned pdata_size)
+{
+	struct gpmc_settings *gpmc_s = NULL;
+	struct gpmc_device_timings *gpmc_dev_t = NULL;
+	struct gpmc_timings *gpmc_t;
+
+	if (cs >= GPMC_CS_NUM) {
+		pr_err("%s: Invalid cs specified. Max CS = %d\n",
+		       __func__, GPMC_CS_NUM);
+		return -EINVAL;
+	}
+
+	if (gpmc_pdata.cs[cs].valid) {
+		pr_err("%s: cs %d already requested, ignoring new request\n",
+		       __func__, cs);
+		return -EINVAL;
+	}
+
+	if (settings) {
+		gpmc_s = kmemdup(settings, sizeof(*settings), GFP_KERNEL);
+		if (!gpmc_s)
+			return -ENOMEM;
+
+		gpmc_pdata.cs[cs].settings = gpmc_s;
+	}
+
+	if (device_timings) {
+		gpmc_dev_t = kmemdup(device_timings, sizeof(*device_timings),
+				     GFP_KERNEL);
+		if (!gpmc_dev_t)
+			goto dev_t_fail;
+
+		gpmc_pdata.cs[cs].device_timings = gpmc_dev_t;
+	}
+
+	if (gpmc_timings) {
+		gpmc_t = kmemdup(gpmc_timings, sizeof(*gpmc_timings),
+				 GFP_KERNEL);
+		if (!gpmc_t)
+			goto gpmc_t_fail;
+
+		gpmc_pdata.cs[cs].gpmc_timings = gpmc_t;
+	}
+
+	gpmc_pdata.cs[cs].is_nand = is_nand;
+	gpmc_pdata.cs[cs].pdev = pdev;
+	gpmc_pdata.cs[cs].pdata_size = pdata_size;
+	gpmc_pdata.cs[cs].valid = true;
+
+	return 0;
+
+gpmc_t_fail:
+	if (device_timings)
+		kfree(gpmc_dev_t);
+dev_t_fail:
+	if (settings)
+		kfree(gpmc_s);
+
+	return -ENOMEM;
+}
+
+
+static struct omap3_gpmc_regs gpmc_context;
+
+/*
+ * Below code only for OMAP3 OFF mode support.
+ * This code must be left back in mach-omap2.
+ */
+void __iomem *omap2_gpmc_base;
+
+void __init omap2_set_globals_gpmc(void __iomem *gpmc)
+{
+	omap2_gpmc_base = gpmc;
+}
+
+static u32 _gpmc_read_reg(u16 reg)
+{
+	return __raw_readl(omap2_gpmc_base + reg);
+}
+
+static void _gpmc_write_reg(u32 val, u16 reg)
+{
+	__raw_readl(omap2_gpmc_base + reg);
+}
+
+static u32 _gpmc_cs_read_reg(int cs, int idx)
+{
+	u16 reg;
+
+	reg = GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
+
+	return _gpmc_read_reg(reg);
+}
+
+static void _gpmc_cs_write_reg(int cs, int idx, u32 val)
+{
+	u16 reg;
+
+	reg = GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
+	_gpmc_write_reg(val, reg);
+}
+
+void omap3_gpmc_save_context(void)
+{
+	int i;
+	u32 val;
+
+	if (!omap2_gpmc_base)
+		return;
+
+	gpmc_context.sysconfig = _gpmc_read_reg(GPMC_SYSCONFIG);
+	gpmc_context.irqenable = _gpmc_read_reg(GPMC_IRQENABLE);
+	gpmc_context.timeout_ctrl = _gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
+	gpmc_context.config = _gpmc_read_reg(GPMC_CONFIG);
+	gpmc_context.prefetch_config1 = _gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
+	gpmc_context.prefetch_config2 = _gpmc_read_reg(GPMC_PREFETCH_CONFIG2);
+	gpmc_context.prefetch_control = _gpmc_read_reg(GPMC_PREFETCH_CONTROL);
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		/* check if valid */
+		val = _gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
+		gpmc_context.cs_context[i].is_valid =
+						val & GPMC_CONFIG7_CSVALID;
+
+		if (gpmc_context.cs_context[i].is_valid) {
+			gpmc_context.cs_context[i].config1 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG1);
+			gpmc_context.cs_context[i].config2 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG2);
+			gpmc_context.cs_context[i].config3 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG3);
+			gpmc_context.cs_context[i].config4 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG4);
+			gpmc_context.cs_context[i].config5 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG5);
+			gpmc_context.cs_context[i].config6 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG6);
+			gpmc_context.cs_context[i].config7 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
+		}
+	}
+}
+
+void omap3_gpmc_restore_context(void)
+{
+	int i;
+
+	if (!omap2_gpmc_base)
+		return;
+
+	_gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig);
+	_gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable);
+	_gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl);
+	_gpmc_write_reg(GPMC_CONFIG, gpmc_context.config);
+	_gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1);
+	_gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2);
+	_gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control);
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		if (gpmc_context.cs_context[i].is_valid) {
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG1,
+					   gpmc_context.cs_context[i].config1);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG2,
+					   gpmc_context.cs_context[i].config2);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG3,
+					   gpmc_context.cs_context[i].config3);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG4,
+					   gpmc_context.cs_context[i].config4);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG5,
+					   gpmc_context.cs_context[i].config5);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG6,
+					   gpmc_context.cs_context[i].config6);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG7,
+					   gpmc_context.cs_context[i].config7);
+		}
+	}
+}
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index c59e9c9..ce611b0 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -31,6 +31,16 @@ config TI_EMIF
 	  parameters and other settings during frequency, voltage and
 	  temperature changes
 
+config TI_GPMC
+	bool "Texas Instruments GPMC driver"
+	depends on ARCH_OMAP2PLUS
+	default y
+	help
+	 This driver is for the General Purpose Memory Controller (GPMC)
+	 present on Texas Instruments SoCs (e.g. OMAP2+). GPMC allows
+	 interfacing to a variety of asynchronous as well as synchronous
+	 memory drives like NOR, NAND, OneNAND, SRAM.
+
 config MVEBU_DEVBUS
 	bool "Marvell EBU Device Bus Controller"
 	default y
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index 71160a2..329b7b6 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_OF)		+= of_memory.o
 endif
 obj-$(CONFIG_TI_AEMIF)		+= ti-aemif.o
 obj-$(CONFIG_TI_EMIF)		+= emif.o
+obj-$(CONFIG_TI_GPMC)		+= ti-gpmc.o
 obj-$(CONFIG_FSL_IFC)		+= fsl_ifc.o
 obj-$(CONFIG_MVEBU_DEVBUS)	+= mvebu-devbus.o
 obj-$(CONFIG_TEGRA20_MC)	+= tegra20-mc.o
diff --git a/drivers/memory/ti-gpmc.c b/drivers/memory/ti-gpmc.c
new file mode 100644
index 0000000..3bb2fd6
--- /dev/null
+++ b/drivers/memory/ti-gpmc.c
@@ -0,0 +1,1829 @@
+/*
+ * GPMC support functions
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation
+ *
+ * Author: Juha Yrjola
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.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.
+ */
+#undef DEBUG
+
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_mtd.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+
+#include <linux/platform_data/mtd-nand-omap2.h>
+#include <linux/platform_data/gpmc-omap.h>
+
+#define	DEVICE_NAME		"omap-gpmc"
+
+/* GPMC register offsets */
+#define GPMC_REVISION		0x00
+#define GPMC_SYSCONFIG		0x10
+#define GPMC_SYSSTATUS		0x14
+#define GPMC_IRQSTATUS		0x18
+#define GPMC_IRQENABLE		0x1c
+#define GPMC_TIMEOUT_CONTROL	0x40
+#define GPMC_ERR_ADDRESS	0x44
+#define GPMC_ERR_TYPE		0x48
+#define GPMC_CONFIG		0x50
+#define GPMC_STATUS		0x54
+#define GPMC_PREFETCH_CONFIG1	0x1e0
+#define GPMC_PREFETCH_CONFIG2	0x1e4
+#define GPMC_PREFETCH_CONTROL	0x1ec
+#define GPMC_PREFETCH_STATUS	0x1f0
+#define GPMC_ECC_CONFIG		0x1f4
+#define GPMC_ECC_CONTROL	0x1f8
+#define GPMC_ECC_SIZE_CONFIG	0x1fc
+#define GPMC_ECC1_RESULT        0x200
+#define GPMC_ECC_BCH_RESULT_0   0x240   /* not available on OMAP2 */
+#define	GPMC_ECC_BCH_RESULT_1	0x244	/* not available on OMAP2 */
+#define	GPMC_ECC_BCH_RESULT_2	0x248	/* not available on OMAP2 */
+#define	GPMC_ECC_BCH_RESULT_3	0x24c	/* not available on OMAP2 */
+
+/* GPMC ECC control settings */
+#define GPMC_ECC_CTRL_ECCCLEAR		0x100
+#define GPMC_ECC_CTRL_ECCDISABLE	0x000
+#define GPMC_ECC_CTRL_ECCREG1		0x001
+#define GPMC_ECC_CTRL_ECCREG2		0x002
+#define GPMC_ECC_CTRL_ECCREG3		0x003
+#define GPMC_ECC_CTRL_ECCREG4		0x004
+#define GPMC_ECC_CTRL_ECCREG5		0x005
+#define GPMC_ECC_CTRL_ECCREG6		0x006
+#define GPMC_ECC_CTRL_ECCREG7		0x007
+#define GPMC_ECC_CTRL_ECCREG8		0x008
+#define GPMC_ECC_CTRL_ECCREG9		0x009
+
+/* ECC commands */
+#define GPMC_ECC_READ		0 /* Reset Hardware ECC for read */
+#define GPMC_ECC_WRITE		1 /* Reset Hardware ECC for write */
+#define GPMC_ECC_READSYN	2 /* Reset before syndrom is read back */
+
+/* CS CONFIG registers */
+#define GPMC_CS_CONFIG1		0x00
+#define GPMC_CS_CONFIG2		0x04
+#define GPMC_CS_CONFIG3		0x08
+#define GPMC_CS_CONFIG4		0x0c
+#define GPMC_CS_CONFIG5		0x10
+#define GPMC_CS_CONFIG6		0x14
+#define GPMC_CS_CONFIG7		0x18
+
+#define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
+#define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
+#define GPMC_CONFIG1_READTYPE_ASYNC     (0 << 29)
+#define GPMC_CONFIG1_READTYPE_SYNC      (1 << 29)
+#define GPMC_CONFIG1_WRITEMULTIPLE_SUPP (1 << 28)
+#define GPMC_CONFIG1_WRITETYPE_ASYNC    (0 << 27)
+#define GPMC_CONFIG1_WRITETYPE_SYNC     (1 << 27)
+#define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val & 3) << 25)
+#define GPMC_CONFIG1_PAGE_LEN(val)      ((val & 3) << 23)
+#define GPMC_CONFIG1_WAIT_READ_MON      (1 << 22)
+#define GPMC_CONFIG1_WAIT_WRITE_MON     (1 << 21)
+#define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18)
+#define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val & 3) << 16)
+#define GPMC_CONFIG1_DEVICESIZE(val)    ((val & 3) << 12)
+#define GPMC_CONFIG1_DEVICESIZE_16      GPMC_CONFIG1_DEVICESIZE(1)
+#define GPMC_CONFIG1_DEVICETYPE(val)    ((val & 3) << 10)
+#define GPMC_CONFIG1_DEVICETYPE_NOR     GPMC_CONFIG1_DEVICETYPE(0)
+#define GPMC_CONFIG1_MUXTYPE(val)       ((val & 3) << 8)
+#define GPMC_CONFIG1_TIME_PARA_GRAN     (1 << 4)
+#define GPMC_CONFIG1_FCLK_DIV(val)      (val & 3)
+#define GPMC_CONFIG1_FCLK_DIV2          (GPMC_CONFIG1_FCLK_DIV(1))
+#define GPMC_CONFIG1_FCLK_DIV3          (GPMC_CONFIG1_FCLK_DIV(2))
+#define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
+#define GPMC_CONFIG7_CSVALID		(1 << 6)
+
+#define	GPMC_CONFIG2_CSEXTRADELAY		BIT(7)
+#define	GPMC_CONFIG3_ADVEXTRADELAY		BIT(7)
+#define	GPMC_CONFIG4_OEEXTRADELAY		BIT(7)
+#define	GPMC_CONFIG4_WEEXTRADELAY		BIT(23)
+#define	GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN	BIT(6)
+#define	GPMC_CONFIG6_CYCLE2CYCLESAMECSEN	BIT(7)
+
+#define GPMC_DEVICETYPE_NOR		0
+#define GPMC_DEVICETYPE_NAND		2
+#define WR_RD_PIN_MONITORING		0x00600000
+#define GPMC_IRQ_FIFOEVENTENABLE	0x01
+#define GPMC_IRQ_COUNT_EVENT		0x02
+
+#define GPMC_CS0_OFFSET		0x60
+#define GPMC_CS_SIZE		0x30
+#define	GPMC_BCH_SIZE		0x10
+
+#define GPMC_MEM_END		0x3FFFFFFF
+
+#define GPMC_CHUNK_SHIFT	24		/* 16 MB */
+#define GPMC_SECTION_SHIFT	28		/* 128 MB */
+
+#define CS_NUM_SHIFT		24
+#define ENABLE_PREFETCH		(0x1 << 7)
+#define DMA_MPU_MODE		2
+
+#define	GPMC_REVISION_MAJOR(l)		((l >> 4) & 0xf)
+#define	GPMC_REVISION_MINOR(l)		(l & 0xf)
+
+#define	GPMC_HAS_WR_ACCESS		0x1
+#define	GPMC_HAS_WR_DATA_MUX_BUS	0x2
+#define	GPMC_HAS_MUX_AAD		0x4
+
+#define GPMC_NR_WAITPINS		4
+
+static struct resource	gpmc_mem_root;
+static struct resource	gpmc_cs_mem[GPMC_CS_NUM];
+static DEFINE_SPINLOCK(gpmc_mem_lock);
+/* Define chip-selects as reserved by default until probe completes */
+static unsigned int gpmc_cs_map = ((1 << GPMC_CS_NUM) - 1);
+static unsigned int gpmc_cs_num = GPMC_CS_NUM;
+static unsigned int gpmc_nr_waitpins;
+static struct device *gpmc_dev;
+static int gpmc_irq = -EINVAL;
+static resource_size_t phys_base, mem_size;
+static unsigned gpmc_capability;
+static void __iomem *gpmc_base;
+
+static struct clk *gpmc_l3_clk;
+
+static void gpmc_write_reg(int idx, u32 val)
+{
+	__raw_writel(val, gpmc_base + idx);
+}
+
+static u32 gpmc_read_reg(int idx)
+{
+	return __raw_readl(gpmc_base + idx);
+}
+
+static void gpmc_cs_write_reg(int cs, int idx, u32 val)
+{
+	void __iomem *reg_addr;
+
+	reg_addr = gpmc_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
+	__raw_writel(val, reg_addr);
+}
+
+static u32 gpmc_cs_read_reg(int cs, int idx)
+{
+	void __iomem *reg_addr;
+
+	reg_addr = gpmc_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
+	return __raw_readl(reg_addr);
+}
+
+/* TODO: Add support for gpmc_fck to clock framework and use it */
+static unsigned long gpmc_get_fclk_period(void)
+{
+	unsigned long rate = clk_get_rate(gpmc_l3_clk);
+
+	if (rate == 0) {
+		pr_warn("%s: gpmc_l3_clk not enabled\n", __func__);
+		return 0;
+	}
+
+	rate /= 1000;
+	rate = 1000000000 / rate;	/* In picoseconds */
+
+	return rate;
+}
+
+static unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
+{
+	unsigned long tick_ps;
+
+	/* Calculate in picosecs to yield more exact results */
+	tick_ps = gpmc_get_fclk_period();
+
+	return (time_ns * 1000 + tick_ps - 1) / tick_ps;
+}
+
+static unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
+{
+	unsigned long tick_ps;
+
+	/* Calculate in picosecs to yield more exact results */
+	tick_ps = gpmc_get_fclk_period();
+
+	return (time_ps + tick_ps - 1) / tick_ps;
+}
+
+static unsigned int gpmc_ticks_to_ps(unsigned int ticks)
+{
+	return ticks * gpmc_get_fclk_period();
+}
+
+static unsigned int gpmc_round_ps_to_ticks(unsigned int time_ps)
+{
+	unsigned long ticks = gpmc_ps_to_ticks(time_ps);
+
+	return ticks * gpmc_get_fclk_period();
+}
+
+static inline void gpmc_cs_modify_reg(int cs, int reg, u32 mask, bool value)
+{
+	u32 l;
+
+	l = gpmc_cs_read_reg(cs, reg);
+	if (value)
+		l |= mask;
+	else
+		l &= ~mask;
+	gpmc_cs_write_reg(cs, reg, l);
+}
+
+static void gpmc_cs_bool_timings(int cs, const struct gpmc_bool_timings *p)
+{
+	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG1,
+			   GPMC_CONFIG1_TIME_PARA_GRAN,
+			   p->time_para_granularity);
+	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG2,
+			   GPMC_CONFIG2_CSEXTRADELAY, p->cs_extra_delay);
+	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG3,
+			   GPMC_CONFIG3_ADVEXTRADELAY, p->adv_extra_delay);
+	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG4,
+			   GPMC_CONFIG4_OEEXTRADELAY, p->oe_extra_delay);
+	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG4,
+			   GPMC_CONFIG4_OEEXTRADELAY, p->we_extra_delay);
+	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG6,
+			   GPMC_CONFIG6_CYCLE2CYCLESAMECSEN,
+			   p->cycle2cyclesamecsen);
+	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG6,
+			   GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN,
+			   p->cycle2cyclediffcsen);
+}
+
+#ifdef DEBUG
+static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
+			       int time, const char *name)
+#else
+static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
+			       int time)
+#endif
+{
+	u32 l;
+	int ticks, mask, nr_bits;
+
+	if (time == 0)
+		ticks = 0;
+	else
+		ticks = gpmc_ns_to_ticks(time);
+	nr_bits = end_bit - st_bit + 1;
+	if (ticks >= 1 << nr_bits) {
+#ifdef DEBUG
+		pr_info("GPMC CS%d: %-10s* %3d ns, %3d ticks >= %d\n",
+			cs, name, time, ticks, 1 << nr_bits);
+#endif
+		return -1;
+	}
+
+	mask = (1 << nr_bits) - 1;
+	l = gpmc_cs_read_reg(cs, reg);
+#ifdef DEBUG
+	pr_info("GPMC CS%d: %-10s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n",
+		cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000,
+		(l >> st_bit) & mask, time);
+#endif
+	l &= ~(mask << st_bit);
+	l |= ticks << st_bit;
+	gpmc_cs_write_reg(cs, reg, l);
+
+	return 0;
+}
+
+#ifdef DEBUG
+#define GPMC_SET_ONE(reg, st, end, field) \
+	set_gpmc_timing_reg(cs, (reg), (st), (end),		\
+			t->field, #field)
+#else
+#define GPMC_SET_ONE(reg, st, end, field) \
+	set_gpmc_timing_reg(cs, (reg), (st), (end), t->field)
+#endif
+
+static int gpmc_calc_divider(unsigned int sync_clk)
+{
+	int div;
+	u32 l;
+
+	l = sync_clk + (gpmc_get_fclk_period() - 1);
+	div = l / gpmc_get_fclk_period();
+	if (div > 4)
+		return -1;
+	if (div <= 0)
+		div = 1;
+
+	return div;
+}
+
+static int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
+{
+	int div;
+	u32 l;
+
+	div = gpmc_calc_divider(t->sync_clk);
+	if (div < 0)
+		return div;
+
+	GPMC_SET_ONE(GPMC_CS_CONFIG2,  0,  3, cs_on);
+	GPMC_SET_ONE(GPMC_CS_CONFIG2,  8, 12, cs_rd_off);
+	GPMC_SET_ONE(GPMC_CS_CONFIG2, 16, 20, cs_wr_off);
+
+	GPMC_SET_ONE(GPMC_CS_CONFIG3,  0,  3, adv_on);
+	GPMC_SET_ONE(GPMC_CS_CONFIG3,  8, 12, adv_rd_off);
+	GPMC_SET_ONE(GPMC_CS_CONFIG3, 16, 20, adv_wr_off);
+
+	GPMC_SET_ONE(GPMC_CS_CONFIG4,  0,  3, oe_on);
+	GPMC_SET_ONE(GPMC_CS_CONFIG4,  8, 12, oe_off);
+	GPMC_SET_ONE(GPMC_CS_CONFIG4, 16, 19, we_on);
+	GPMC_SET_ONE(GPMC_CS_CONFIG4, 24, 28, we_off);
+
+	GPMC_SET_ONE(GPMC_CS_CONFIG5,  0,  4, rd_cycle);
+	GPMC_SET_ONE(GPMC_CS_CONFIG5,  8, 12, wr_cycle);
+	GPMC_SET_ONE(GPMC_CS_CONFIG5, 16, 20, access);
+
+	GPMC_SET_ONE(GPMC_CS_CONFIG5, 24, 27, page_burst_access);
+
+	GPMC_SET_ONE(GPMC_CS_CONFIG6, 0, 3, bus_turnaround);
+	GPMC_SET_ONE(GPMC_CS_CONFIG6, 8, 11, cycle2cycle_delay);
+
+	GPMC_SET_ONE(GPMC_CS_CONFIG1, 18, 19, wait_monitoring);
+	GPMC_SET_ONE(GPMC_CS_CONFIG1, 25, 26, clk_activation);
+
+	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
+		GPMC_SET_ONE(GPMC_CS_CONFIG6, 16, 19, wr_data_mux_bus);
+	if (gpmc_capability & GPMC_HAS_WR_ACCESS)
+		GPMC_SET_ONE(GPMC_CS_CONFIG6, 24, 28, wr_access);
+
+	/* caller is expected to have initialized CONFIG1 to cover
+	 * at least sync vs async
+	 */
+	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+	if (l & (GPMC_CONFIG1_READTYPE_SYNC | GPMC_CONFIG1_WRITETYPE_SYNC)) {
+#ifdef DEBUG
+		pr_info("GPMC CS%d CLK period is %lu ns (div %d)\n",
+			cs, (div * gpmc_get_fclk_period()) / 1000, div);
+#endif
+		l &= ~0x03;
+		l |= (div - 1);
+		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
+	}
+
+	gpmc_cs_bool_timings(cs, &t->bool_timings);
+
+	return 0;
+}
+
+static int gpmc_cs_enable_mem(int cs, u32 base, u32 size)
+{
+	u32 l;
+	u32 mask;
+
+	/*
+	 * Ensure that base address is aligned on a
+	 * boundary equal to or greater than size.
+	 */
+	if (base & (size - 1))
+		return -EINVAL;
+
+	mask = (1 << GPMC_SECTION_SHIFT) - size;
+	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+	l &= ~0x3f;
+	l = (base >> GPMC_CHUNK_SHIFT) & 0x3f;
+	l &= ~(0x0f << 8);
+	l |= ((mask >> GPMC_CHUNK_SHIFT) & 0x0f) << 8;
+	l |= GPMC_CONFIG7_CSVALID;
+	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
+
+	return 0;
+}
+
+static void gpmc_cs_disable_mem(int cs)
+{
+	u32 l;
+
+	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+	l &= ~GPMC_CONFIG7_CSVALID;
+	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
+}
+
+static void gpmc_cs_get_memconf(int cs, u32 *base, u32 *size)
+{
+	u32 l;
+	u32 mask;
+
+	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+	*base = (l & 0x3f) << GPMC_CHUNK_SHIFT;
+	mask = (l >> 8) & 0x0f;
+	*size = (1 << GPMC_SECTION_SHIFT) - (mask << GPMC_CHUNK_SHIFT);
+}
+
+static int gpmc_cs_mem_enabled(int cs)
+{
+	u32 l;
+
+	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+	return l & GPMC_CONFIG7_CSVALID;
+}
+
+static void gpmc_cs_set_reserved(int cs, int reserved)
+{
+	gpmc_cs_map &= ~(1 << cs);
+	gpmc_cs_map |= (reserved ? 1 : 0) << cs;
+}
+
+static bool gpmc_cs_reserved(int cs)
+{
+	return gpmc_cs_map & (1 << cs);
+}
+
+static unsigned long gpmc_mem_align(unsigned long size)
+{
+	int order;
+
+	size = (size - 1) >> (GPMC_CHUNK_SHIFT - 1);
+	order = GPMC_CHUNK_SHIFT - 1;
+	do {
+		size >>= 1;
+		order++;
+	} while (size);
+	size = 1 << order;
+	return size;
+}
+
+static int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size)
+{
+	struct resource	*res = &gpmc_cs_mem[cs];
+	int r;
+
+	size = gpmc_mem_align(size);
+	spin_lock(&gpmc_mem_lock);
+	res->start = base;
+	res->end = base + size - 1;
+	r = request_resource(&gpmc_mem_root, res);
+	spin_unlock(&gpmc_mem_lock);
+
+	return r;
+}
+
+static int gpmc_cs_delete_mem(int cs)
+{
+	struct resource	*res = &gpmc_cs_mem[cs];
+	int r;
+
+	spin_lock(&gpmc_mem_lock);
+	r = release_resource(res);
+	res->start = 0;
+	res->end = 0;
+	spin_unlock(&gpmc_mem_lock);
+
+	return r;
+}
+
+/**
+ * gpmc_cs_remap - remaps a chip-select physical base address
+ * @cs:		chip-select to remap
+ * @base:	physical base address to re-map chip-select to
+ *
+ * Re-maps a chip-select to a new physical base address specified by
+ * "base". Returns 0 on success and appropriate negative error code
+ * on failure.
+ */
+static int gpmc_cs_remap(int cs, u32 base)
+{
+	int ret;
+	u32 old_base, size;
+
+	if (cs > gpmc_cs_num) {
+		pr_err("%s: requested chip-select is disabled\n", __func__);
+		return -ENODEV;
+	}
+
+	/*
+	 * Make sure we ignore any device offsets from the GPMC partition
+	 * allocated for the chip select and that the new base confirms
+	 * to the GPMC 16MB minimum granularity.
+	 */
+	base &= ~(SZ_16M - 1);
+
+	gpmc_cs_get_memconf(cs, &old_base, &size);
+	if (base == old_base)
+		return 0;
+	gpmc_cs_disable_mem(cs);
+	ret = gpmc_cs_delete_mem(cs);
+	if (ret < 0)
+		return ret;
+	ret = gpmc_cs_insert_mem(cs, base, size);
+	if (ret < 0)
+		return ret;
+	ret = gpmc_cs_enable_mem(cs, base, size);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
+{
+	struct resource *res = &gpmc_cs_mem[cs];
+	int r = -1;
+
+	if (cs > gpmc_cs_num) {
+		pr_err("%s: requested chip-select is disabled\n", __func__);
+		return -ENODEV;
+	}
+	size = gpmc_mem_align(size);
+	if (size > (1 << GPMC_SECTION_SHIFT))
+		return -ENOMEM;
+
+	spin_lock(&gpmc_mem_lock);
+	if (gpmc_cs_reserved(cs)) {
+		r = -EBUSY;
+		goto out;
+	}
+	if (gpmc_cs_mem_enabled(cs))
+		r = adjust_resource(res, res->start & ~(size - 1), size);
+	if (r < 0)
+		r = allocate_resource(&gpmc_mem_root, res, size, 0, ~0,
+				      size, NULL, NULL);
+	if (r < 0)
+		goto out;
+
+	r = gpmc_cs_enable_mem(cs, res->start, resource_size(res));
+	if (r < 0) {
+		release_resource(res);
+		goto out;
+	}
+
+	*base = res->start;
+	gpmc_cs_set_reserved(cs, 1);
+out:
+	spin_unlock(&gpmc_mem_lock);
+	return r;
+}
+
+static void gpmc_cs_free(int cs)
+{
+	struct resource	*res = &gpmc_cs_mem[cs];
+
+	spin_lock(&gpmc_mem_lock);
+	if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) {
+		pr_err("Trying to free non-reserved GPMC CS%d\n", cs);
+		BUG();
+		spin_unlock(&gpmc_mem_lock);
+		return;
+	}
+	gpmc_cs_disable_mem(cs);
+	if (res->flags)
+		release_resource(res);
+	gpmc_cs_set_reserved(cs, 0);
+	spin_unlock(&gpmc_mem_lock);
+}
+
+static void gpmc_mem_exit(void)
+{
+	int cs;
+
+	for (cs = 0; cs < gpmc_cs_num; cs++) {
+		if (!gpmc_cs_mem_enabled(cs))
+			continue;
+		gpmc_cs_delete_mem(cs);
+	}
+}
+
+static void gpmc_mem_init(void)
+{
+	int cs;
+
+	/*
+	 * The first 1MB of GPMC address space is typically mapped to
+	 * the internal ROM. Never allocate the first page, to
+	 * facilitate bug detection; even if we didn't boot from ROM.
+	 */
+	gpmc_mem_root.start = SZ_1M;
+	gpmc_mem_root.end = GPMC_MEM_END;
+
+	/* Reserve all regions that has been set up by bootloader */
+	for (cs = 0; cs < gpmc_cs_num; cs++) {
+		u32 base, size;
+
+		if (!gpmc_cs_mem_enabled(cs))
+			continue;
+		gpmc_cs_get_memconf(cs, &base, &size);
+		if (gpmc_cs_insert_mem(cs, base, size)) {
+			pr_warn("%s: disabling cs %d mapped at 0x%x-0x%x\n",
+				__func__, cs, base, base + size);
+			gpmc_cs_disable_mem(cs);
+		}
+	}
+}
+
+static u32 gpmc_round_ps_to_sync_clk(u32 time_ps, u32 sync_clk)
+{
+	u32 temp;
+	int div;
+
+	div = gpmc_calc_divider(sync_clk);
+	temp = gpmc_ps_to_ticks(time_ps);
+	temp = (temp + div - 1) / div;
+	return gpmc_ticks_to_ps(temp * div);
+}
+
+/* XXX: can the cycles be avoided ? */
+static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t,
+				       struct gpmc_device_timings *dev_t,
+				       bool mux)
+{
+	u32 temp;
+
+	/* adv_rd_off */
+	temp = dev_t->t_avdp_r;
+	/* XXX: mux check required ? */
+	if (mux) {
+		/* XXX: t_avdp not to be required for sync, only added for tusb
+		 * this indirectly necessitates requirement of t_avdp_r and
+		 * t_avdp_w instead of having a single t_avdp
+		 */
+		temp = max_t(u32, temp,	gpmc_t->clk_activation + dev_t->t_avdh);
+		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
+	}
+	gpmc_t->adv_rd_off = gpmc_round_ps_to_ticks(temp);
+
+	/* oe_on */
+	temp = dev_t->t_oeasu; /* XXX: remove this ? */
+	if (mux) {
+		temp = max_t(u32, temp,	gpmc_t->clk_activation + dev_t->t_ach);
+		temp = max_t(u32, temp, gpmc_t->adv_rd_off +
+			     gpmc_ticks_to_ps(dev_t->cyc_aavdh_oe));
+	}
+	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
+
+	/* access */
+	/* XXX: any scope for improvement ?, by combining oe_on
+	 * and clk_activation, need to check whether
+	 * access = clk_activation + round to sync clk ?
+	 */
+	temp = max_t(u32, dev_t->t_iaa,	dev_t->cyc_iaa * gpmc_t->sync_clk);
+	temp += gpmc_t->clk_activation;
+	if (dev_t->cyc_oe)
+		temp = max_t(u32, temp, gpmc_t->oe_on +
+			     gpmc_ticks_to_ps(dev_t->cyc_oe));
+	gpmc_t->access = gpmc_round_ps_to_ticks(temp);
+
+	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ps(1);
+	gpmc_t->cs_rd_off = gpmc_t->oe_off;
+
+	/* rd_cycle */
+	temp = max_t(u32, dev_t->t_cez_r, dev_t->t_oez);
+	temp = gpmc_round_ps_to_sync_clk(temp, gpmc_t->sync_clk) +
+					 gpmc_t->access;
+	/* XXX: barter t_ce_rdyz with t_cez_r ? */
+	if (dev_t->t_ce_rdyz)
+		temp = max_t(u32, temp,	gpmc_t->cs_rd_off + dev_t->t_ce_rdyz);
+	gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp);
+
+	return 0;
+}
+
+static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t,
+					struct gpmc_device_timings *dev_t,
+					bool mux)
+{
+	u32 temp;
+
+	/* adv_wr_off */
+	temp = dev_t->t_avdp_w;
+	if (mux) {
+		temp = max_t(u32, temp,
+			     gpmc_t->clk_activation + dev_t->t_avdh);
+		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
+	}
+	gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp);
+
+	/* wr_data_mux_bus */
+	temp = max_t(u32, dev_t->t_weasu,
+		     gpmc_t->clk_activation + dev_t->t_rdyo);
+	/* XXX: shouldn't mux be kept as a whole for wr_data_mux_bus ?,
+	 * and in that case remember to handle we_on properly
+	 */
+	if (mux) {
+		temp = max_t(u32, temp,
+			     gpmc_t->adv_wr_off + dev_t->t_aavdh);
+		temp = max_t(u32, temp, gpmc_t->adv_wr_off +
+			     gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
+	}
+	gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp);
+
+	/* we_on */
+	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
+		gpmc_t->we_on = gpmc_round_ps_to_ticks(dev_t->t_weasu);
+	else
+		gpmc_t->we_on = gpmc_t->wr_data_mux_bus;
+
+	/* wr_access */
+	/* XXX: gpmc_capability check reqd ? , even if not, will not harm */
+	gpmc_t->wr_access = gpmc_t->access;
+
+	/* we_off */
+	temp = gpmc_t->we_on + dev_t->t_wpl;
+	temp = max_t(u32, temp,
+		     gpmc_t->wr_access + gpmc_ticks_to_ps(1));
+	temp = max_t(u32, temp,
+		     gpmc_t->we_on + gpmc_ticks_to_ps(dev_t->cyc_wpl));
+	gpmc_t->we_off = gpmc_round_ps_to_ticks(temp);
+
+	gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off +
+						   dev_t->t_wph);
+
+	/* wr_cycle */
+	temp = gpmc_round_ps_to_sync_clk(dev_t->t_cez_w, gpmc_t->sync_clk);
+	temp += gpmc_t->wr_access;
+	/* XXX: barter t_ce_rdyz with t_cez_w ? */
+	if (dev_t->t_ce_rdyz)
+		temp = max_t(u32, temp,
+			     gpmc_t->cs_wr_off + dev_t->t_ce_rdyz);
+	gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp);
+
+	return 0;
+}
+
+static int gpmc_calc_async_read_timings(struct gpmc_timings *gpmc_t,
+					struct gpmc_device_timings *dev_t,
+					bool mux)
+{
+	u32 temp;
+
+	/* adv_rd_off */
+	temp = dev_t->t_avdp_r;
+	if (mux)
+		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
+	gpmc_t->adv_rd_off = gpmc_round_ps_to_ticks(temp);
+
+	/* oe_on */
+	temp = dev_t->t_oeasu;
+	if (mux)
+		temp = max_t(u32, temp,
+			     gpmc_t->adv_rd_off + dev_t->t_aavdh);
+	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
+
+	/* access */
+	temp = max_t(u32, dev_t->t_iaa, /* XXX: remove t_iaa in async ? */
+		     gpmc_t->oe_on + dev_t->t_oe);
+	temp = max_t(u32, temp,
+		     gpmc_t->cs_on + dev_t->t_ce);
+	temp = max_t(u32, temp,
+		     gpmc_t->adv_on + dev_t->t_aa);
+	gpmc_t->access = gpmc_round_ps_to_ticks(temp);
+
+	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ps(1);
+	gpmc_t->cs_rd_off = gpmc_t->oe_off;
+
+	/* rd_cycle */
+	temp = max_t(u32, dev_t->t_rd_cycle,
+		     gpmc_t->cs_rd_off + dev_t->t_cez_r);
+	temp = max_t(u32, temp, gpmc_t->oe_off + dev_t->t_oez);
+	gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp);
+
+	return 0;
+}
+
+static int gpmc_calc_async_write_timings(struct gpmc_timings *gpmc_t,
+					 struct gpmc_device_timings *dev_t,
+					 bool mux)
+{
+	u32 temp;
+
+	/* adv_wr_off */
+	temp = dev_t->t_avdp_w;
+	if (mux)
+		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
+	gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp);
+
+	/* wr_data_mux_bus */
+	temp = dev_t->t_weasu;
+	if (mux) {
+		temp = max_t(u32, temp,	gpmc_t->adv_wr_off + dev_t->t_aavdh);
+		temp = max_t(u32, temp, gpmc_t->adv_wr_off +
+			     gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
+	}
+	gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp);
+
+	/* we_on */
+	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
+		gpmc_t->we_on = gpmc_round_ps_to_ticks(dev_t->t_weasu);
+	else
+		gpmc_t->we_on = gpmc_t->wr_data_mux_bus;
+
+	/* we_off */
+	temp = gpmc_t->we_on + dev_t->t_wpl;
+	gpmc_t->we_off = gpmc_round_ps_to_ticks(temp);
+
+	gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off +
+						   dev_t->t_wph);
+
+	/* wr_cycle */
+	temp = max_t(u32, dev_t->t_wr_cycle,
+		     gpmc_t->cs_wr_off + dev_t->t_cez_w);
+	gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp);
+
+	return 0;
+}
+
+static int gpmc_calc_sync_common_timings(struct gpmc_timings *gpmc_t,
+					 struct gpmc_device_timings *dev_t)
+{
+	u32 temp;
+
+	gpmc_t->sync_clk = gpmc_calc_divider(dev_t->clk) *
+					     gpmc_get_fclk_period();
+
+	gpmc_t->page_burst_access = gpmc_round_ps_to_sync_clk(dev_t->t_bacc,
+							      gpmc_t->sync_clk);
+
+	temp = max_t(u32, dev_t->t_ces, dev_t->t_avds);
+	gpmc_t->clk_activation = gpmc_round_ps_to_ticks(temp);
+
+	if (gpmc_calc_divider(gpmc_t->sync_clk) != 1)
+		return 0;
+
+	if (dev_t->ce_xdelay)
+		gpmc_t->bool_timings.cs_extra_delay = true;
+	if (dev_t->avd_xdelay)
+		gpmc_t->bool_timings.adv_extra_delay = true;
+	if (dev_t->oe_xdelay)
+		gpmc_t->bool_timings.oe_extra_delay = true;
+	if (dev_t->we_xdelay)
+		gpmc_t->bool_timings.we_extra_delay = true;
+
+	return 0;
+}
+
+static int gpmc_calc_common_timings(struct gpmc_timings *gpmc_t,
+				    struct gpmc_device_timings *dev_t,
+				    bool sync)
+{
+	u32 temp;
+
+	/* cs_on */
+	gpmc_t->cs_on = gpmc_round_ps_to_ticks(dev_t->t_ceasu);
+
+	/* adv_on */
+	temp = dev_t->t_avdasu;
+	if (dev_t->t_ce_avd)
+		temp = max_t(u32, temp,
+			     gpmc_t->cs_on + dev_t->t_ce_avd);
+	gpmc_t->adv_on = gpmc_round_ps_to_ticks(temp);
+
+	if (sync)
+		gpmc_calc_sync_common_timings(gpmc_t, dev_t);
+
+	return 0;
+}
+
+/* TODO: remove this function once all peripherals are confirmed to
+ * work with generic timing. Simultaneously gpmc_cs_set_timings()
+ * has to be modified to handle timings in ps instead of ns
+*/
+static void gpmc_convert_ps_to_ns(struct gpmc_timings *t)
+{
+	t->cs_on /= 1000;
+	t->cs_rd_off /= 1000;
+	t->cs_wr_off /= 1000;
+	t->adv_on /= 1000;
+	t->adv_rd_off /= 1000;
+	t->adv_wr_off /= 1000;
+	t->we_on /= 1000;
+	t->we_off /= 1000;
+	t->oe_on /= 1000;
+	t->oe_off /= 1000;
+	t->page_burst_access /= 1000;
+	t->access /= 1000;
+	t->rd_cycle /= 1000;
+	t->wr_cycle /= 1000;
+	t->bus_turnaround /= 1000;
+	t->cycle2cycle_delay /= 1000;
+	t->wait_monitoring /= 1000;
+	t->clk_activation /= 1000;
+	t->wr_access /= 1000;
+	t->wr_data_mux_bus /= 1000;
+}
+
+static int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
+			     struct gpmc_settings *gpmc_s,
+			     struct gpmc_device_timings *dev_t)
+{
+	bool mux = false, sync = false;
+
+	if (gpmc_s) {
+		mux = gpmc_s->mux_add_data ? true : false;
+		sync = (gpmc_s->sync_read || gpmc_s->sync_write);
+	}
+
+	memset(gpmc_t, 0, sizeof(*gpmc_t));
+
+	gpmc_calc_common_timings(gpmc_t, dev_t, sync);
+
+	if (gpmc_s && gpmc_s->sync_read)
+		gpmc_calc_sync_read_timings(gpmc_t, dev_t, mux);
+	else
+		gpmc_calc_async_read_timings(gpmc_t, dev_t, mux);
+
+	if (gpmc_s && gpmc_s->sync_write)
+		gpmc_calc_sync_write_timings(gpmc_t, dev_t, mux);
+	else
+		gpmc_calc_async_write_timings(gpmc_t, dev_t, mux);
+
+	/* TODO: remove, see function definition */
+	gpmc_convert_ps_to_ns(gpmc_t);
+
+	return 0;
+}
+
+/**
+ * gpmc_cs_program_settings - programs non-timing related settings
+ * @cs:		GPMC chip-select to program
+ * @p:		pointer to GPMC settings structure
+ *
+ * Programs non-timing related settings for a GPMC chip-select, such as
+ * bus-width, burst configuration, etc. Function should be called once
+ * for each chip-select that is being used and must be called before
+ * calling gpmc_cs_set_timings() as timing parameters in the CONFIG1
+ * register will be initialised to zero by this function. Returns 0 on
+ * success and appropriate negative error code on failure.
+ */
+static int gpmc_cs_program_settings(int cs, struct gpmc_settings *p)
+{
+	u32 config1;
+
+	if ((!p->device_width) || (p->device_width > GPMC_DEVWIDTH_16BIT)) {
+		pr_err("%s: invalid width %d!", __func__, p->device_width);
+		return -EINVAL;
+	}
+
+	/* Address-data multiplexing not supported for NAND devices */
+	if (p->device_nand && p->mux_add_data) {
+		pr_err("%s: invalid configuration!\n", __func__);
+		return -EINVAL;
+	}
+
+	if ((p->mux_add_data > GPMC_MUX_AD) ||
+	    ((p->mux_add_data == GPMC_MUX_AAD) &&
+	     !(gpmc_capability & GPMC_HAS_MUX_AAD))) {
+		pr_err("%s: invalid multiplex configuration!\n", __func__);
+		return -EINVAL;
+	}
+
+	/* Page/burst mode supports lengths of 4, 8 and 16 bytes */
+	if (p->burst_read || p->burst_write) {
+		switch (p->burst_len) {
+		case GPMC_BURST_4:
+		case GPMC_BURST_8:
+		case GPMC_BURST_16:
+			break;
+		default:
+			pr_err("%s: invalid page/burst-length (%d)\n",
+			       __func__, p->burst_len);
+			return -EINVAL;
+		}
+	}
+
+	if ((p->wait_on_read || p->wait_on_write) &&
+	    (p->wait_pin > gpmc_nr_waitpins)) {
+		pr_err("%s: invalid wait-pin (%d)\n", __func__, p->wait_pin);
+		return -EINVAL;
+	}
+
+	config1 = GPMC_CONFIG1_DEVICESIZE((p->device_width - 1));
+
+	if (p->sync_read)
+		config1 |= GPMC_CONFIG1_READTYPE_SYNC;
+	if (p->sync_write)
+		config1 |= GPMC_CONFIG1_WRITETYPE_SYNC;
+	if (p->wait_on_read)
+		config1 |= GPMC_CONFIG1_WAIT_READ_MON;
+	if (p->wait_on_write)
+		config1 |= GPMC_CONFIG1_WAIT_WRITE_MON;
+	if (p->wait_on_read || p->wait_on_write)
+		config1 |= GPMC_CONFIG1_WAIT_PIN_SEL(p->wait_pin);
+	if (p->device_nand)
+		config1	|= GPMC_CONFIG1_DEVICETYPE(GPMC_DEVICETYPE_NAND);
+	if (p->mux_add_data)
+		config1	|= GPMC_CONFIG1_MUXTYPE(p->mux_add_data);
+	if (p->burst_read)
+		config1 |= GPMC_CONFIG1_READMULTIPLE_SUPP;
+	if (p->burst_write)
+		config1 |= GPMC_CONFIG1_WRITEMULTIPLE_SUPP;
+	if (p->burst_read || p->burst_write) {
+		config1 |= GPMC_CONFIG1_PAGE_LEN(p->burst_len >> 3);
+		config1 |= p->burst_wrap ? GPMC_CONFIG1_WRAPBURST_SUPP : 0;
+	}
+
+	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, config1);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id gpmc_dt_ids[] = {
+	{ .compatible = "ti,omap2420-gpmc" },
+	{ .compatible = "ti,omap2430-gpmc" },
+	{ .compatible = "ti,omap3430-gpmc" },	/* omap3430 & omap3630 */
+	{ .compatible = "ti,omap4430-gpmc" },	/* omap4 & omap543x */
+	{ .compatible = "ti,am3352-gpmc" },	/* am335x devices */
+	{ }
+};
+MODULE_DEVICE_TABLE(of, gpmc_dt_ids);
+
+/**
+ * gpmc_read_settings_dt - read gpmc settings from device-tree
+ * @np:		pointer to device-tree node for a gpmc child device
+ * @p:		pointer to gpmc settings structure
+ *
+ * Reads the GPMC settings for a GPMC child device from device-tree and
+ * stores them in the GPMC settings structure passed. The GPMC settings
+ * structure is initialised to zero by this function and so any
+ * previously stored settings will be cleared.
+ */
+static void gpmc_read_settings_dt(struct device_node *np,
+				  struct gpmc_settings *p)
+{
+	memset(p, 0, sizeof(struct gpmc_settings));
+
+	p->sync_read = of_property_read_bool(np, "gpmc,sync-read");
+	p->sync_write = of_property_read_bool(np, "gpmc,sync-write");
+	of_property_read_u32(np, "gpmc,device-width", &p->device_width);
+	of_property_read_u32(np, "gpmc,mux-add-data", &p->mux_add_data);
+
+	if (!of_property_read_u32(np, "gpmc,burst-length", &p->burst_len)) {
+		p->burst_wrap = of_property_read_bool(np, "gpmc,burst-wrap");
+		p->burst_read = of_property_read_bool(np, "gpmc,burst-read");
+		p->burst_write = of_property_read_bool(np, "gpmc,burst-write");
+		if (!p->burst_read && !p->burst_write)
+			pr_warn("%s: page/burst-length set but not used!\n",
+				__func__);
+	}
+
+	if (!of_property_read_u32(np, "gpmc,wait-pin", &p->wait_pin)) {
+		p->wait_on_read = of_property_read_bool(np,
+							"gpmc,wait-on-read");
+		p->wait_on_write = of_property_read_bool(np,
+							 "gpmc,wait-on-write");
+		if (!p->wait_on_read && !p->wait_on_write)
+			pr_warn("%s: read/write wait monitoring not enabled!\n",
+				__func__);
+	}
+}
+
+static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
+						struct gpmc_timings *gpmc_t)
+{
+	struct gpmc_bool_timings *p;
+
+	if (!np || !gpmc_t)
+		return;
+
+	memset(gpmc_t, 0, sizeof(*gpmc_t));
+
+	/* minimum clock period for syncronous mode */
+	of_property_read_u32(np, "gpmc,sync-clk-ps", &gpmc_t->sync_clk);
+
+	/* chip select timtings */
+	of_property_read_u32(np, "gpmc,cs-on-ns", &gpmc_t->cs_on);
+	of_property_read_u32(np, "gpmc,cs-rd-off-ns", &gpmc_t->cs_rd_off);
+	of_property_read_u32(np, "gpmc,cs-wr-off-ns", &gpmc_t->cs_wr_off);
+
+	/* ADV signal timings */
+	of_property_read_u32(np, "gpmc,adv-on-ns", &gpmc_t->adv_on);
+	of_property_read_u32(np, "gpmc,adv-rd-off-ns", &gpmc_t->adv_rd_off);
+	of_property_read_u32(np, "gpmc,adv-wr-off-ns", &gpmc_t->adv_wr_off);
+
+	/* WE signal timings */
+	of_property_read_u32(np, "gpmc,we-on-ns", &gpmc_t->we_on);
+	of_property_read_u32(np, "gpmc,we-off-ns", &gpmc_t->we_off);
+
+	/* OE signal timings */
+	of_property_read_u32(np, "gpmc,oe-on-ns", &gpmc_t->oe_on);
+	of_property_read_u32(np, "gpmc,oe-off-ns", &gpmc_t->oe_off);
+
+	/* access and cycle timings */
+	of_property_read_u32(np, "gpmc,page-burst-access-ns",
+			     &gpmc_t->page_burst_access);
+	of_property_read_u32(np, "gpmc,access-ns", &gpmc_t->access);
+	of_property_read_u32(np, "gpmc,rd-cycle-ns", &gpmc_t->rd_cycle);
+	of_property_read_u32(np, "gpmc,wr-cycle-ns", &gpmc_t->wr_cycle);
+	of_property_read_u32(np, "gpmc,bus-turnaround-ns",
+			     &gpmc_t->bus_turnaround);
+	of_property_read_u32(np, "gpmc,cycle2cycle-delay-ns",
+			     &gpmc_t->cycle2cycle_delay);
+	of_property_read_u32(np, "gpmc,wait-monitoring-ns",
+			     &gpmc_t->wait_monitoring);
+	of_property_read_u32(np, "gpmc,clk-activation-ns",
+			     &gpmc_t->clk_activation);
+
+	/* only applicable to OMAP3+ */
+	of_property_read_u32(np, "gpmc,wr-access-ns", &gpmc_t->wr_access);
+	of_property_read_u32(np, "gpmc,wr-data-mux-bus-ns",
+			     &gpmc_t->wr_data_mux_bus);
+
+	/* bool timing parameters */
+	p = &gpmc_t->bool_timings;
+
+	p->cycle2cyclediffcsen =
+		of_property_read_bool(np, "gpmc,cycle2cycle-diffcsen");
+	p->cycle2cyclesamecsen =
+		of_property_read_bool(np, "gpmc,cycle2cycle-samecsen");
+	p->we_extra_delay = of_property_read_bool(np, "gpmc,we-extra-delay");
+	p->oe_extra_delay = of_property_read_bool(np, "gpmc,oe-extra-delay");
+	p->adv_extra_delay = of_property_read_bool(np, "gpmc,adv-extra-delay");
+	p->cs_extra_delay = of_property_read_bool(np, "gpmc,cs-extra-delay");
+	p->time_para_granularity =
+		of_property_read_bool(np, "gpmc,time-para-granularity");
+}
+
+/**
+ * gpmc_probe_generic_child - configures the gpmc for a child device
+ * @pdev:	pointer to gpmc platform device
+ * @child:	pointer to device-tree node for child device
+ *
+ * Allocates and configures a GPMC chip-select for a child device.
+ * Returns 0 on success and appropriate negative error code on failure.
+ */
+static int gpmc_probe_generic_child(struct platform_device *pdev,
+				    struct device_node *child)
+{
+	struct gpmc_settings gpmc_s;
+	struct gpmc_timings gpmc_t;
+	struct resource res;
+	unsigned long base;
+	int ret, cs;
+	struct device *dev = &pdev->dev;
+
+	if (of_property_read_u32(child, "reg", &cs) < 0) {
+		dev_err(&pdev->dev, "%s has no 'reg' property\n",
+			child->full_name);
+		return -ENODEV;
+	}
+
+	if (of_address_to_resource(child, 0, &res) < 0) {
+		dev_err(&pdev->dev, "%s has malformed 'reg' property\n",
+			child->full_name);
+		return -ENODEV;
+	}
+
+	ret = gpmc_cs_request(cs, resource_size(&res), &base);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "cannot request GPMC CS %d\n", cs);
+		return ret;
+	}
+
+	/*
+	 * For some GPMC devices we still need to rely on the bootloader
+	 * timings because the devices can be connected via FPGA. So far
+	 * the list is smc91x on the omap2 SDP boards, and 8250 on zooms.
+	 * REVISIT: Add timing support from slls644g.pdf and from the
+	 * lan91c96 manual.
+	 */
+	if (of_device_is_compatible(child, "ns16550a") ||
+	    of_device_is_compatible(child, "smsc,lan91c94") ||
+	    of_device_is_compatible(child, "smsc,lan91c111")) {
+		dev_warn(&pdev->dev,
+			 "%s using bootloader timings on CS%d\n",
+			 child->name, cs);
+		goto no_timings;
+	}
+
+	/*
+	 * FIXME: gpmc_cs_request() will map the CS to an arbitary
+	 * location in the gpmc address space. When booting with
+	 * device-tree we want the NOR flash to be mapped to the
+	 * location specified in the device-tree blob. So remap the
+	 * CS to this location. Once DT migration is complete should
+	 * just make gpmc_cs_request() map a specific address.
+	 */
+	ret = gpmc_cs_remap(cs, res.start);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "cannot remap GPMC CS %d to %pa\n",
+			cs, &res.start);
+		goto err;
+	}
+
+	gpmc_read_settings_dt(child, &gpmc_s);
+
+	if (of_node_cmp(child->name, "nand") == 0) {
+		/* NAND specific setup */
+		u32 val;
+
+		val = of_get_nand_bus_width(child);
+		switch (val) {
+		case 8:
+			gpmc_s.device_width = GPMC_DEVWIDTH_8BIT;
+			break;
+		case 16:
+			gpmc_s.device_width = GPMC_DEVWIDTH_16BIT;
+			break;
+		default:
+			dev_err(dev, "%s: invalid 'nand-bus-width'\n",
+				child->name);
+			ret = -EINVAL;
+			goto err;
+		}
+
+		gpmc_s.device_nand = true;
+
+	} else if (of_node_cmp(child->name, "onenand") == 0) {
+		/* DT incorrectly sets sync modes, onenand default is async */
+		gpmc_s.sync_read = false;
+		gpmc_s.sync_write = false;
+
+	} else {
+		if (of_property_read_u32(child, "bank-width",
+					 &gpmc_s.device_width)) {
+			dev_err(dev, "%s: no 'bank-width' property\n",
+				child->name);
+			goto err;
+		}
+
+		if (gpmc_s.device_width < 1 || gpmc_s.device_width > 2) {
+			dev_err(dev, "%s: invalid 'bank-width'\n",
+				child->name);
+			goto err;
+		}
+	}
+
+	ret = gpmc_cs_program_settings(cs, &gpmc_s);
+	if (ret < 0)
+		goto err;
+
+	gpmc_read_timings_dt(child, &gpmc_t);
+	gpmc_cs_set_timings(cs, &gpmc_t);
+
+no_timings:
+	if (of_platform_device_create(child, NULL, &pdev->dev))
+		return 0;
+
+	dev_err(&pdev->dev, "failed to create gpmc child %s\n", child->name);
+	ret = -ENODEV;
+
+err:
+	gpmc_cs_free(cs);
+
+	return ret;
+}
+
+static int gpmc_probe_dt(struct platform_device *pdev)
+{
+	int ret;
+	struct device_node *child;
+
+	ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-cs",
+				   &gpmc_cs_num);
+	if (ret < 0) {
+		pr_err("%s: number of chip-selects not defined\n", __func__);
+		return ret;
+	} else if (gpmc_cs_num < 1) {
+		pr_err("%s: all chip-selects are disabled\n", __func__);
+		return -EINVAL;
+	} else if (gpmc_cs_num > GPMC_CS_NUM) {
+		pr_err("%s: number of supported chip-selects cannot be > %d\n",
+		       __func__, GPMC_CS_NUM);
+		return -EINVAL;
+	}
+
+	ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-waitpins",
+				   &gpmc_nr_waitpins);
+	if (ret < 0) {
+		pr_err("%s: number of wait pins not found!\n", __func__);
+		return ret;
+	}
+
+	for_each_child_of_node(pdev->dev.of_node, child) {
+		if (!child->name)
+			continue;
+
+		if (of_node_cmp(child->name, "ethernet") == 0 ||
+		    of_node_cmp(child->name, "nor") == 0 ||
+		    of_node_cmp(child->name, "uart") == 0 ||
+		    of_node_cmp(child->name, "nand") == 0 ||
+		    of_node_cmp(child->name, "onenand") == 0)
+			ret = gpmc_probe_generic_child(pdev, child);
+
+		if (WARN(ret < 0, "%s: probing gpmc child %s failed\n",
+			 __func__, child->full_name))
+			of_node_put(child);
+	}
+
+	return 0;
+}
+#else
+static int gpmc_probe_dt(struct platform_device *pdev)
+{
+	return 0;
+}
+#endif
+
+static int gpmc_nand_setup(struct platform_device *parent_pdev,
+			   struct gpmc_omap_cs_data *cs)
+{
+	struct resource *res;
+	struct resource *res_gpmc;
+
+	if (!cs->pdev)
+		return -EINVAL;
+
+	res = cs->pdev->resource;
+
+	if (cs->pdev->num_resources < 3)
+		return -EINVAL;
+
+	if (resource_type(&res[1]) != IORESOURCE_MEM ||
+	    resource_type(&res[2]) != IORESOURCE_IRQ)
+		return -EINVAL;
+
+	if (!cs->settings)
+		return -EINVAL;
+
+	/* GPMC register space */
+	res_gpmc = platform_get_resource(parent_pdev, IORESOURCE_MEM, 0);
+	if (!res_gpmc)
+		return -EINVAL;
+
+	res[1] = *res_gpmc;
+
+	/* setup IRQ resources */
+	res[2].start = gpmc_irq;
+
+	cs->settings->device_nand = true;
+
+	return 0;
+}
+
+static void gpmc_probe_legacy(struct platform_device *pdev)
+{
+	int i, rc, j;
+	struct device *dev = &pdev->dev;
+	struct gpmc_omap_platform_data *gpmc_pdata;
+	struct resource *mem_res;
+	unsigned long cs_base;
+	resource_size_t size;
+	struct gpmc_timings gpmc_timings;
+	struct gpmc_omap_cs_data *cs;
+
+	gpmc_pdata = dev->platform_data;
+	gpmc_cs_num = GPMC_CS_NUM;
+	gpmc_nr_waitpins = GPMC_NR_WAITPINS;
+
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		cs = &gpmc_pdata->cs[i];
+		if (!cs->valid)
+			continue;
+
+		if (cs->settings) {
+			if (gpmc_cs_program_settings(i, cs->settings)) {
+				dev_err(dev,
+					"Couldn't program settings for CS %d\n",
+					i);
+				continue;
+			}
+		}
+
+		/* give device_timings priority over gpmc_timings */
+		if (cs->device_timings) {
+			gpmc_calc_timings(&gpmc_timings, cs->settings,
+					  cs->device_timings);
+
+			if (gpmc_cs_set_timings(i, &gpmc_timings)) {
+				dev_err(dev,
+					"Couldn't program timings for CS %d\n",
+					i);
+				continue;
+			}
+		} else if (cs->gpmc_timings) {
+			if (gpmc_cs_set_timings(i, cs->gpmc_timings)) {
+				dev_err(dev,
+					"Couldn't program timings for CS %d\n",
+					i);
+				continue;
+			}
+		}
+	}
+
+	/*
+	 * All Chip Selects must be configured before platform devices are
+	 * created as some devices (e.g. tusb6010) can use multiple
+	 * Chip selects.
+	 */
+
+	/* Fixup Memory resources */
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		int required_resources;
+
+		cs = &gpmc_pdata->cs[i];
+		if (!cs->valid)
+			continue;
+
+		if (!cs->pdev)
+			continue;
+
+		/* Customized NAND setup */
+		if (cs->is_nand) {
+			if (gpmc_nand_setup(pdev, cs)) {
+				dev_err(dev, "Error setting up NAND on CS %d\n",
+					i);
+				continue;
+			}
+		}
+
+		mem_res = cs->pdev->resource;
+
+		/*
+		 * If device is present multiple times, fix the subsequent
+		 * resources
+		 */
+		required_resources = 1;
+		for (j = 0; j < i; j++) {
+			if (gpmc_pdata->cs[j].pdev == cs->pdev) {
+				mem_res++;
+				required_resources++;
+			}
+		}
+
+		if (cs->pdev->num_resources < required_resources ||
+		    resource_type(mem_res) != IORESOURCE_MEM) {
+			dev_err(dev, "Invalid IOMEM resource for CS %d\n", i);
+			continue;
+		}
+
+		/*
+		 * Request a CS space. Use size from
+		 * platform device's MEM resource
+		 */
+		size = mem_res->end - mem_res->start + 1;
+		if (gpmc_cs_request(i, size, &cs_base)) {
+			dev_err(dev, "Couldn't request resource for CS %d\n",
+				i);
+			continue;
+		}
+
+		mem_res->start = cs_base;
+		mem_res->end = cs_base + size - 1;
+	}
+
+	/* create the platform devices */
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		bool registered;
+
+		cs = &gpmc_pdata->cs[i];
+		if (!cs->valid)
+			continue;
+
+		if (!cs->pdev)
+			continue;
+
+		/*
+		 * same device can be present on multiple CS, don't
+		 * register device more than once.
+		 */
+		registered = false;
+		for (j = 0; j < i; j++) {
+			if (gpmc_pdata->cs[j].pdev == cs->pdev) {
+				registered = true;
+				break;
+			}
+		}
+
+		if (registered)
+			continue;
+
+		cs->pdev->dev.parent = dev;
+		rc = platform_device_register(cs->pdev);
+		if (rc < 0) {
+			dev_err(dev,
+				"Failed to register device %s on CS %d\n",
+				cs->pdev->name, i);
+			continue;
+		}
+	}
+}
+
+static int gpmc_probe(struct platform_device *pdev)
+{
+	int rc;
+	u32 l;
+	struct resource *res;
+	struct device *dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL)
+		return -ENOENT;
+
+	phys_base = res->start;
+	mem_size = resource_size(res);
+
+	gpmc_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(gpmc_base))
+		return PTR_ERR(gpmc_base);
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get resource: irq\n");
+		return -EINVAL;
+	}
+
+	gpmc_irq = res->start;
+
+	gpmc_l3_clk = clk_get(&pdev->dev, "fck");
+	if (IS_ERR(gpmc_l3_clk)) {
+		dev_err(&pdev->dev, "error: clk_get\n");
+		gpmc_irq = 0;
+		return PTR_ERR(gpmc_l3_clk);
+	}
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
+
+	gpmc_dev = dev;
+
+	l = gpmc_read_reg(GPMC_REVISION);
+
+	/*
+	 * FIXME: Once device-tree migration is complete the below flags
+	 * should be populated based upon the device-tree compatible
+	 * string. For now just use the IP revision. OMAP3+ devices have
+	 * the wr_access and wr_data_mux_bus register fields. OMAP4+
+	 * devices support the addr-addr-data multiplex protocol.
+	 *
+	 * GPMC IP revisions:
+	 * - OMAP24xx			= 2.0
+	 * - OMAP3xxx			= 5.0
+	 * - OMAP44xx/54xx/AM335x	= 6.0
+	 */
+	if (GPMC_REVISION_MAJOR(l) > 0x4)
+		gpmc_capability = GPMC_HAS_WR_ACCESS | GPMC_HAS_WR_DATA_MUX_BUS;
+	if (GPMC_REVISION_MAJOR(l) > 0x5)
+		gpmc_capability |= GPMC_HAS_MUX_AAD;
+	dev_info(dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l),
+		 GPMC_REVISION_MINOR(l));
+
+	gpmc_mem_init();
+
+	/* Now the GPMC is initialised, unreserve the chip-selects */
+	gpmc_cs_map = 0;
+	gpmc_dev = dev;
+
+	if (dev->of_node) {
+		rc = gpmc_probe_dt(pdev);
+		if (rc) {
+			dev_err(dev, "gpmc_probe_dt() failed\n");
+			goto error;
+		}
+	} else {
+		/* Legacy probing based on platform data */
+		if (!dev->platform_data) {
+			dev_err(dev, "No platform data\n");
+			rc = -EINVAL;
+			goto error;
+		}
+
+		gpmc_probe_legacy(pdev);
+	}
+
+	return 0;
+
+error:
+	pm_runtime_put_sync(dev);
+	clk_put(gpmc_l3_clk);
+	return rc;
+}
+
+static int gpmc_remove(struct platform_device *pdev)
+{
+	gpmc_mem_exit();
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	gpmc_dev = NULL;
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+/* Structure to save gpmc cs context */
+struct gpmc_cs_config {
+	u32 config1;
+	u32 config2;
+	u32 config3;
+	u32 config4;
+	u32 config5;
+	u32 config6;
+	u32 config7;
+	int is_valid;
+};
+
+/*
+ * Structure to save/restore gpmc context
+ */
+struct omap_gpmc_regs {
+	u32 sysconfig;
+	u32 irqenable;
+	u32 timeout_ctrl;
+	u32 config;
+	u32 prefetch_config1;
+	u32 prefetch_config2;
+	u32 prefetch_control;
+	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
+};
+
+static struct omap_gpmc_regs gpmc_context;
+
+void omap_gpmc_save_context(void)
+{
+	int i;
+
+	gpmc_context.sysconfig = gpmc_read_reg(GPMC_SYSCONFIG);
+	gpmc_context.irqenable = gpmc_read_reg(GPMC_IRQENABLE);
+	gpmc_context.timeout_ctrl = gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
+	gpmc_context.config = gpmc_read_reg(GPMC_CONFIG);
+	gpmc_context.prefetch_config1 = gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
+	gpmc_context.prefetch_config2 = gpmc_read_reg(GPMC_PREFETCH_CONFIG2);
+	gpmc_context.prefetch_control = gpmc_read_reg(GPMC_PREFETCH_CONTROL);
+	for (i = 0; i < gpmc_cs_num; i++) {
+		gpmc_context.cs_context[i].is_valid = gpmc_cs_mem_enabled(i);
+		if (gpmc_context.cs_context[i].is_valid) {
+			gpmc_context.cs_context[i].config1 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG1);
+			gpmc_context.cs_context[i].config2 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG2);
+			gpmc_context.cs_context[i].config3 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG3);
+			gpmc_context.cs_context[i].config4 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG4);
+			gpmc_context.cs_context[i].config5 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG5);
+			gpmc_context.cs_context[i].config6 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG6);
+			gpmc_context.cs_context[i].config7 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
+		}
+	}
+}
+
+void omap_gpmc_restore_context(void)
+{
+	int i;
+
+	gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig);
+	gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable);
+	gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl);
+	gpmc_write_reg(GPMC_CONFIG, gpmc_context.config);
+	gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1);
+	gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2);
+	gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control);
+	for (i = 0; i < gpmc_cs_num; i++) {
+		if (gpmc_context.cs_context[i].is_valid) {
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG1,
+					  gpmc_context.cs_context[i].config1);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG2,
+					  gpmc_context.cs_context[i].config2);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG3,
+					  gpmc_context.cs_context[i].config3);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG4,
+					  gpmc_context.cs_context[i].config4);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG5,
+					  gpmc_context.cs_context[i].config5);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG6,
+					  gpmc_context.cs_context[i].config6);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG7,
+					  gpmc_context.cs_context[i].config7);
+		}
+	}
+}
+
+static int gpmc_suspend(struct device *dev)
+{
+	omap_gpmc_save_context();
+	pm_runtime_put_sync(dev);
+	return 0;
+}
+
+static int gpmc_resume(struct device *dev)
+{
+	pm_runtime_get_sync(dev);
+	omap_gpmc_restore_context();
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(gpmc_pm_ops, gpmc_suspend, gpmc_resume);
+
+static struct platform_driver gpmc_driver = {
+	.probe		= gpmc_probe,
+	.remove		= gpmc_remove,
+	.driver		= {
+		.name	= DEVICE_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(gpmc_dt_ids),
+		.pm	= &gpmc_pm_ops,
+	},
+};
+
+static __init int gpmc_init(void)
+{
+	return platform_driver_register(&gpmc_driver);
+}
+
+static __exit void gpmc_exit(void)
+{
+	platform_driver_unregister(&gpmc_driver);
+}
+
+module_init(gpmc_init);
+module_exit(gpmc_exit);
+
+/**
+ * omap_gpmc_retime - Reconfigre GPMC timings for the device
+ *
+ * @cs		Chip select number
+ * @gpmc_s	GPMC settings
+ * @dev_t	New device timings to set
+ */
+int omap_gpmc_retime(int cs, struct gpmc_settings *gpmc_s,
+		     struct gpmc_device_timings *dev_t)
+{
+	struct gpmc_timings gpmc_t;
+	struct device *dev = gpmc_dev;
+
+	if (!gpmc_dev)
+		return -ENODEV;
+
+	if (cs < 0 || cs >= gpmc_cs_num) {
+		dev_err(dev, "%s: Invalid find Chip Select\n", __func__);
+		return cs;
+	}
+
+	if (gpmc_cs_program_settings(cs, gpmc_s)) {
+		dev_err(dev, "%s: Failed to set GPMC settings\n", __func__);
+		return -EINVAL;
+	}
+
+	gpmc_calc_timings(&gpmc_t, gpmc_s, dev_t);
+	if (gpmc_cs_set_timings(cs, &gpmc_t)) {
+		dev_err(dev, "%s: Failed to set GPMC timings\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(omap_gpmc_retime);
+
+/**
+ * omap_gpmc_get_clk_period - Get the nearest possible (equal to or higer) GPMC
+ *				synchronous clock (GPMC_CLK) period.
+ *
+ * @cs		Chip select number
+ * @min_ps	Minimum synchronous clock period supporded by the device
+ *
+ * Returns the nearest possible GPMC clock period in picoseconds, equal to or
+ * higher than the requested period. 0 in case of error.
+ */
+unsigned long omap_gpmc_get_clk_period(int cs,
+				       unsigned long min_ps)
+{
+	int div;
+	unsigned long clk_ps;
+	struct device *dev = gpmc_dev;
+
+	if (!gpmc_dev)
+		return 0;
+
+	if (cs < 0 || cs >= gpmc_cs_num) {
+		dev_err(dev, "%s: Invalid Chip Select\n", __func__);
+		return cs;
+	}
+
+	div = gpmc_calc_divider(min_ps);
+	if (div < 0) {
+		dev_err(dev, "%s: Can't support requested clock period %lu ps\n",
+			__func__, min_ps);
+		return 0;
+	}
+
+	clk_ps = gpmc_get_fclk_period() * div;
+
+	return clk_ps;
+}
+EXPORT_SYMBOL_GPL(omap_gpmc_get_clk_period);
+
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index f1cf503..e1db2c1 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -89,7 +89,7 @@ config MTD_NAND_AMS_DELTA
 
 config MTD_NAND_OMAP2
 	tristate "NAND Flash device on OMAP2, OMAP3 and OMAP4"
-	depends on ARCH_OMAP2PLUS
+	depends on TI_GPMC
 	help
           Support for NAND flash on Texas Instruments OMAP2, OMAP3 and OMAP4
 	  platforms.
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig
index ab260727..272c16c 100644
--- a/drivers/mtd/onenand/Kconfig
+++ b/drivers/mtd/onenand/Kconfig
@@ -24,10 +24,10 @@ config MTD_ONENAND_GENERIC
 	  Support for OneNAND flash via platform device driver.
 
 config MTD_ONENAND_OMAP2
-	tristate "OneNAND on OMAP2/OMAP3 support"
-	depends on ARCH_OMAP2 || ARCH_OMAP3
+	tristate "OneNAND on OMAP2+ support"
+	depends on TI_GPMC
 	help
-	  Support for a OneNAND flash device connected to an OMAP2/OMAP3 CPU
+	  Support for a OneNAND flash device connected to an OMAP2+ SoCs
 	  via the GPMC memory controller.
 
 config MTD_ONENAND_SAMSUNG
-- 
1.8.3.2


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

* [PATCH 35/36] ARM: OMAP2+: gpmc: move GPMC driver into drivers/memory
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

Move the GPMC driver out of mach-omap2. We leave behind only
the mach-omap2 specific bits in mach-omap2/gpmc_legacy.c
i.e. gpmc_generic_init() for use by board files to register
the GPMC configuration and omap3_gpmc_save/restore_context() for
use by OMAP3 OFF mode support.

The GPMC driver is now enabled by its own kernel config option
TI_GPMC. The other drivers that need GPMC to work i.e. MTD_ONENAND_OMAP2
and MTD_NAND_OMAP2 are made to depend on TI_GPMC.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/Makefile      |    2 +-
 arch/arm/mach-omap2/gpmc.c        | 1947 -------------------------------------
 arch/arm/mach-omap2/gpmc_legacy.c |  296 ++++++
 drivers/memory/Kconfig            |   10 +
 drivers/memory/Makefile           |    1 +
 drivers/memory/ti-gpmc.c          | 1829 ++++++++++++++++++++++++++++++++++
 drivers/mtd/nand/Kconfig          |    2 +-
 drivers/mtd/onenand/Kconfig       |    6 +-
 8 files changed, 2141 insertions(+), 1952 deletions(-)
 delete mode 100644 arch/arm/mach-omap2/gpmc.c
 create mode 100644 arch/arm/mach-omap2/gpmc_legacy.c
 create mode 100644 drivers/memory/ti-gpmc.c

diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 8421f38..a2e7426 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -6,7 +6,7 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
 	-I$(srctree)/arch/arm/plat-omap/include
 
 # Common support
-obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o gpmc.o timer.o pm.o \
+obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o gpmc_legacy.o timer.o pm.o \
 	 common.o gpio.o dma.o wd_timer.o display.o i2c.o hdq1w.o omap_hwmod.o \
 	 omap_device.o sram.o drm.o
 
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
deleted file mode 100644
index 9173f71..0000000
--- a/arch/arm/mach-omap2/gpmc.c
+++ /dev/null
@@ -1,1947 +0,0 @@
-/*
- * GPMC support functions
- *
- * Copyright (C) 2005-2006 Nokia Corporation
- *
- * Author: Juha Yrjola
- *
- * Copyright (C) 2009 Texas Instruments
- * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.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.
- */
-#undef DEBUG
-
-#include <linux/irq.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/ioport.h>
-#include <linux/spinlock.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_mtd.h>
-#include <linux/of_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/slab.h>
-
-#include <linux/platform_data/mtd-nand-omap2.h>
-
-#include <asm/mach-types.h>
-
-#include "soc.h"
-#include "common.h"
-#include "omap_device.h"
-#include "gpmc.h"
-
-#define	DEVICE_NAME		"omap-gpmc"
-
-/* GPMC register offsets */
-#define GPMC_REVISION		0x00
-#define GPMC_SYSCONFIG		0x10
-#define GPMC_SYSSTATUS		0x14
-#define GPMC_IRQSTATUS		0x18
-#define GPMC_IRQENABLE		0x1c
-#define GPMC_TIMEOUT_CONTROL	0x40
-#define GPMC_ERR_ADDRESS	0x44
-#define GPMC_ERR_TYPE		0x48
-#define GPMC_CONFIG		0x50
-#define GPMC_STATUS		0x54
-#define GPMC_PREFETCH_CONFIG1	0x1e0
-#define GPMC_PREFETCH_CONFIG2	0x1e4
-#define GPMC_PREFETCH_CONTROL	0x1ec
-#define GPMC_PREFETCH_STATUS	0x1f0
-#define GPMC_ECC_CONFIG		0x1f4
-#define GPMC_ECC_CONTROL	0x1f8
-#define GPMC_ECC_SIZE_CONFIG	0x1fc
-#define GPMC_ECC1_RESULT        0x200
-#define GPMC_ECC_BCH_RESULT_0   0x240   /* not available on OMAP2 */
-#define	GPMC_ECC_BCH_RESULT_1	0x244	/* not available on OMAP2 */
-#define	GPMC_ECC_BCH_RESULT_2	0x248	/* not available on OMAP2 */
-#define	GPMC_ECC_BCH_RESULT_3	0x24c	/* not available on OMAP2 */
-
-/* GPMC ECC control settings */
-#define GPMC_ECC_CTRL_ECCCLEAR		0x100
-#define GPMC_ECC_CTRL_ECCDISABLE	0x000
-#define GPMC_ECC_CTRL_ECCREG1		0x001
-#define GPMC_ECC_CTRL_ECCREG2		0x002
-#define GPMC_ECC_CTRL_ECCREG3		0x003
-#define GPMC_ECC_CTRL_ECCREG4		0x004
-#define GPMC_ECC_CTRL_ECCREG5		0x005
-#define GPMC_ECC_CTRL_ECCREG6		0x006
-#define GPMC_ECC_CTRL_ECCREG7		0x007
-#define GPMC_ECC_CTRL_ECCREG8		0x008
-#define GPMC_ECC_CTRL_ECCREG9		0x009
-
-/* ECC commands */
-#define GPMC_ECC_READ		0 /* Reset Hardware ECC for read */
-#define GPMC_ECC_WRITE		1 /* Reset Hardware ECC for write */
-#define GPMC_ECC_READSYN	2 /* Reset before syndrom is read back */
-
-/* CS CONFIG registers */
-#define GPMC_CS_CONFIG1		0x00
-#define GPMC_CS_CONFIG2		0x04
-#define GPMC_CS_CONFIG3		0x08
-#define GPMC_CS_CONFIG4		0x0c
-#define GPMC_CS_CONFIG5		0x10
-#define GPMC_CS_CONFIG6		0x14
-#define GPMC_CS_CONFIG7		0x18
-
-#define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
-#define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
-#define GPMC_CONFIG1_READTYPE_ASYNC     (0 << 29)
-#define GPMC_CONFIG1_READTYPE_SYNC      (1 << 29)
-#define GPMC_CONFIG1_WRITEMULTIPLE_SUPP (1 << 28)
-#define GPMC_CONFIG1_WRITETYPE_ASYNC    (0 << 27)
-#define GPMC_CONFIG1_WRITETYPE_SYNC     (1 << 27)
-#define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val & 3) << 25)
-#define GPMC_CONFIG1_PAGE_LEN(val)      ((val & 3) << 23)
-#define GPMC_CONFIG1_WAIT_READ_MON      (1 << 22)
-#define GPMC_CONFIG1_WAIT_WRITE_MON     (1 << 21)
-#define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18)
-#define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val & 3) << 16)
-#define GPMC_CONFIG1_DEVICESIZE(val)    ((val & 3) << 12)
-#define GPMC_CONFIG1_DEVICESIZE_16      GPMC_CONFIG1_DEVICESIZE(1)
-#define GPMC_CONFIG1_DEVICETYPE(val)    ((val & 3) << 10)
-#define GPMC_CONFIG1_DEVICETYPE_NOR     GPMC_CONFIG1_DEVICETYPE(0)
-#define GPMC_CONFIG1_MUXTYPE(val)       ((val & 3) << 8)
-#define GPMC_CONFIG1_TIME_PARA_GRAN     (1 << 4)
-#define GPMC_CONFIG1_FCLK_DIV(val)      (val & 3)
-#define GPMC_CONFIG1_FCLK_DIV2          (GPMC_CONFIG1_FCLK_DIV(1))
-#define GPMC_CONFIG1_FCLK_DIV3          (GPMC_CONFIG1_FCLK_DIV(2))
-#define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
-#define GPMC_CONFIG7_CSVALID		(1 << 6)
-
-#define	GPMC_CONFIG2_CSEXTRADELAY		BIT(7)
-#define	GPMC_CONFIG3_ADVEXTRADELAY		BIT(7)
-#define	GPMC_CONFIG4_OEEXTRADELAY		BIT(7)
-#define	GPMC_CONFIG4_WEEXTRADELAY		BIT(23)
-#define	GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN	BIT(6)
-#define	GPMC_CONFIG6_CYCLE2CYCLESAMECSEN	BIT(7)
-
-#define GPMC_DEVICETYPE_NOR		0
-#define GPMC_DEVICETYPE_NAND		2
-#define WR_RD_PIN_MONITORING		0x00600000
-#define GPMC_IRQ_FIFOEVENTENABLE	0x01
-#define GPMC_IRQ_COUNT_EVENT		0x02
-
-#define GPMC_CS0_OFFSET		0x60
-#define GPMC_CS_SIZE		0x30
-#define	GPMC_BCH_SIZE		0x10
-
-#define GPMC_MEM_END		0x3FFFFFFF
-
-#define GPMC_CHUNK_SHIFT	24		/* 16 MB */
-#define GPMC_SECTION_SHIFT	28		/* 128 MB */
-
-#define CS_NUM_SHIFT		24
-#define ENABLE_PREFETCH		(0x1 << 7)
-#define DMA_MPU_MODE		2
-
-#define	GPMC_REVISION_MAJOR(l)		((l >> 4) & 0xf)
-#define	GPMC_REVISION_MINOR(l)		(l & 0xf)
-
-#define	GPMC_HAS_WR_ACCESS		0x1
-#define	GPMC_HAS_WR_DATA_MUX_BUS	0x2
-#define	GPMC_HAS_MUX_AAD		0x4
-
-#define GPMC_NR_WAITPINS		4
-
-static struct gpmc_omap_platform_data gpmc_pdata;
-
-/* Structure to save gpmc cs context */
-struct gpmc_cs_config {
-	u32 config1;
-	u32 config2;
-	u32 config3;
-	u32 config4;
-	u32 config5;
-	u32 config6;
-	u32 config7;
-	int is_valid;
-};
-
-/*
- * Structure to save/restore gpmc context
- * to support core off on OMAP3
- */
-struct omap3_gpmc_regs {
-	u32 sysconfig;
-	u32 irqenable;
-	u32 timeout_ctrl;
-	u32 config;
-	u32 prefetch_config1;
-	u32 prefetch_config2;
-	u32 prefetch_control;
-	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
-};
-
-static struct resource	gpmc_mem_root;
-static struct resource	gpmc_cs_mem[GPMC_CS_NUM];
-static DEFINE_SPINLOCK(gpmc_mem_lock);
-/* Define chip-selects as reserved by default until probe completes */
-static unsigned int gpmc_cs_map = ((1 << GPMC_CS_NUM) - 1);
-static unsigned int gpmc_cs_num = GPMC_CS_NUM;
-static unsigned int gpmc_nr_waitpins;
-static struct device *gpmc_dev;
-static int gpmc_irq = -EINVAL;
-static resource_size_t phys_base, mem_size;
-static unsigned gpmc_capability;
-static void __iomem *gpmc_base;
-
-static struct clk *gpmc_l3_clk;
-
-static void gpmc_write_reg(int idx, u32 val)
-{
-	__raw_writel(val, gpmc_base + idx);
-}
-
-static u32 gpmc_read_reg(int idx)
-{
-	return __raw_readl(gpmc_base + idx);
-}
-
-static void gpmc_cs_write_reg(int cs, int idx, u32 val)
-{
-	void __iomem *reg_addr;
-
-	reg_addr = gpmc_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
-	__raw_writel(val, reg_addr);
-}
-
-static u32 gpmc_cs_read_reg(int cs, int idx)
-{
-	void __iomem *reg_addr;
-
-	reg_addr = gpmc_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
-	return __raw_readl(reg_addr);
-}
-
-/* TODO: Add support for gpmc_fck to clock framework and use it */
-static unsigned long gpmc_get_fclk_period(void)
-{
-	unsigned long rate = clk_get_rate(gpmc_l3_clk);
-
-	if (rate == 0) {
-		printk(KERN_WARNING "gpmc_l3_clk not enabled\n");
-		return 0;
-	}
-
-	rate /= 1000;
-	rate = 1000000000 / rate;	/* In picoseconds */
-
-	return rate;
-}
-
-static unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
-{
-	unsigned long tick_ps;
-
-	/* Calculate in picosecs to yield more exact results */
-	tick_ps = gpmc_get_fclk_period();
-
-	return (time_ns * 1000 + tick_ps - 1) / tick_ps;
-}
-
-static unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
-{
-	unsigned long tick_ps;
-
-	/* Calculate in picosecs to yield more exact results */
-	tick_ps = gpmc_get_fclk_period();
-
-	return (time_ps + tick_ps - 1) / tick_ps;
-}
-
-static unsigned int gpmc_ticks_to_ps(unsigned int ticks)
-{
-	return ticks * gpmc_get_fclk_period();
-}
-
-static unsigned int gpmc_round_ps_to_ticks(unsigned int time_ps)
-{
-	unsigned long ticks = gpmc_ps_to_ticks(time_ps);
-
-	return ticks * gpmc_get_fclk_period();
-}
-
-static inline void gpmc_cs_modify_reg(int cs, int reg, u32 mask, bool value)
-{
-	u32 l;
-
-	l = gpmc_cs_read_reg(cs, reg);
-	if (value)
-		l |= mask;
-	else
-		l &= ~mask;
-	gpmc_cs_write_reg(cs, reg, l);
-}
-
-static void gpmc_cs_bool_timings(int cs, const struct gpmc_bool_timings *p)
-{
-	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG1,
-			   GPMC_CONFIG1_TIME_PARA_GRAN,
-			   p->time_para_granularity);
-	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG2,
-			   GPMC_CONFIG2_CSEXTRADELAY, p->cs_extra_delay);
-	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG3,
-			   GPMC_CONFIG3_ADVEXTRADELAY, p->adv_extra_delay);
-	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG4,
-			   GPMC_CONFIG4_OEEXTRADELAY, p->oe_extra_delay);
-	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG4,
-			   GPMC_CONFIG4_OEEXTRADELAY, p->we_extra_delay);
-	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG6,
-			   GPMC_CONFIG6_CYCLE2CYCLESAMECSEN,
-			   p->cycle2cyclesamecsen);
-	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG6,
-			   GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN,
-			   p->cycle2cyclediffcsen);
-}
-
-#ifdef DEBUG
-static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
-			       int time, const char *name)
-#else
-static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
-			       int time)
-#endif
-{
-	u32 l;
-	int ticks, mask, nr_bits;
-
-	if (time == 0)
-		ticks = 0;
-	else
-		ticks = gpmc_ns_to_ticks(time);
-	nr_bits = end_bit - st_bit + 1;
-	if (ticks >= 1 << nr_bits) {
-#ifdef DEBUG
-		printk(KERN_INFO "GPMC CS%d: %-10s* %3d ns, %3d ticks >= %d\n",
-				cs, name, time, ticks, 1 << nr_bits);
-#endif
-		return -1;
-	}
-
-	mask = (1 << nr_bits) - 1;
-	l = gpmc_cs_read_reg(cs, reg);
-#ifdef DEBUG
-	printk(KERN_INFO
-		"GPMC CS%d: %-10s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n",
-	       cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000,
-			(l >> st_bit) & mask, time);
-#endif
-	l &= ~(mask << st_bit);
-	l |= ticks << st_bit;
-	gpmc_cs_write_reg(cs, reg, l);
-
-	return 0;
-}
-
-#ifdef DEBUG
-#define GPMC_SET_ONE(reg, st, end, field) \
-	if (set_gpmc_timing_reg(cs, (reg), (st), (end),		\
-			t->field, #field) < 0)			\
-		return -1
-#else
-#define GPMC_SET_ONE(reg, st, end, field) \
-	if (set_gpmc_timing_reg(cs, (reg), (st), (end), t->field) < 0) \
-		return -1
-#endif
-
-static int gpmc_calc_divider(unsigned int sync_clk)
-{
-	int div;
-	u32 l;
-
-	l = sync_clk + (gpmc_get_fclk_period() - 1);
-	div = l / gpmc_get_fclk_period();
-	if (div > 4)
-		return -1;
-	if (div <= 0)
-		div = 1;
-
-	return div;
-}
-
-static int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
-{
-	int div;
-	u32 l;
-
-	div = gpmc_calc_divider(t->sync_clk);
-	if (div < 0)
-		return div;
-
-	GPMC_SET_ONE(GPMC_CS_CONFIG2,  0,  3, cs_on);
-	GPMC_SET_ONE(GPMC_CS_CONFIG2,  8, 12, cs_rd_off);
-	GPMC_SET_ONE(GPMC_CS_CONFIG2, 16, 20, cs_wr_off);
-
-	GPMC_SET_ONE(GPMC_CS_CONFIG3,  0,  3, adv_on);
-	GPMC_SET_ONE(GPMC_CS_CONFIG3,  8, 12, adv_rd_off);
-	GPMC_SET_ONE(GPMC_CS_CONFIG3, 16, 20, adv_wr_off);
-
-	GPMC_SET_ONE(GPMC_CS_CONFIG4,  0,  3, oe_on);
-	GPMC_SET_ONE(GPMC_CS_CONFIG4,  8, 12, oe_off);
-	GPMC_SET_ONE(GPMC_CS_CONFIG4, 16, 19, we_on);
-	GPMC_SET_ONE(GPMC_CS_CONFIG4, 24, 28, we_off);
-
-	GPMC_SET_ONE(GPMC_CS_CONFIG5,  0,  4, rd_cycle);
-	GPMC_SET_ONE(GPMC_CS_CONFIG5,  8, 12, wr_cycle);
-	GPMC_SET_ONE(GPMC_CS_CONFIG5, 16, 20, access);
-
-	GPMC_SET_ONE(GPMC_CS_CONFIG5, 24, 27, page_burst_access);
-
-	GPMC_SET_ONE(GPMC_CS_CONFIG6, 0, 3, bus_turnaround);
-	GPMC_SET_ONE(GPMC_CS_CONFIG6, 8, 11, cycle2cycle_delay);
-
-	GPMC_SET_ONE(GPMC_CS_CONFIG1, 18, 19, wait_monitoring);
-	GPMC_SET_ONE(GPMC_CS_CONFIG1, 25, 26, clk_activation);
-
-	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
-		GPMC_SET_ONE(GPMC_CS_CONFIG6, 16, 19, wr_data_mux_bus);
-	if (gpmc_capability & GPMC_HAS_WR_ACCESS)
-		GPMC_SET_ONE(GPMC_CS_CONFIG6, 24, 28, wr_access);
-
-	/* caller is expected to have initialized CONFIG1 to cover
-	 * at least sync vs async
-	 */
-	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
-	if (l & (GPMC_CONFIG1_READTYPE_SYNC | GPMC_CONFIG1_WRITETYPE_SYNC)) {
-#ifdef DEBUG
-		printk(KERN_INFO "GPMC CS%d CLK period is %lu ns (div %d)\n",
-				cs, (div * gpmc_get_fclk_period()) / 1000, div);
-#endif
-		l &= ~0x03;
-		l |= (div - 1);
-		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
-	}
-
-	gpmc_cs_bool_timings(cs, &t->bool_timings);
-
-	return 0;
-}
-
-static int gpmc_cs_enable_mem(int cs, u32 base, u32 size)
-{
-	u32 l;
-	u32 mask;
-
-	/*
-	 * Ensure that base address is aligned on a
-	 * boundary equal to or greater than size.
-	 */
-	if (base & (size - 1))
-		return -EINVAL;
-
-	mask = (1 << GPMC_SECTION_SHIFT) - size;
-	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
-	l &= ~0x3f;
-	l = (base >> GPMC_CHUNK_SHIFT) & 0x3f;
-	l &= ~(0x0f << 8);
-	l |= ((mask >> GPMC_CHUNK_SHIFT) & 0x0f) << 8;
-	l |= GPMC_CONFIG7_CSVALID;
-	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
-
-	return 0;
-}
-
-static void gpmc_cs_disable_mem(int cs)
-{
-	u32 l;
-
-	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
-	l &= ~GPMC_CONFIG7_CSVALID;
-	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
-}
-
-static void gpmc_cs_get_memconf(int cs, u32 *base, u32 *size)
-{
-	u32 l;
-	u32 mask;
-
-	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
-	*base = (l & 0x3f) << GPMC_CHUNK_SHIFT;
-	mask = (l >> 8) & 0x0f;
-	*size = (1 << GPMC_SECTION_SHIFT) - (mask << GPMC_CHUNK_SHIFT);
-}
-
-static int gpmc_cs_mem_enabled(int cs)
-{
-	u32 l;
-
-	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
-	return l & GPMC_CONFIG7_CSVALID;
-}
-
-static void gpmc_cs_set_reserved(int cs, int reserved)
-{
-	gpmc_cs_map &= ~(1 << cs);
-	gpmc_cs_map |= (reserved ? 1 : 0) << cs;
-}
-
-static bool gpmc_cs_reserved(int cs)
-{
-	return gpmc_cs_map & (1 << cs);
-}
-
-static unsigned long gpmc_mem_align(unsigned long size)
-{
-	int order;
-
-	size = (size - 1) >> (GPMC_CHUNK_SHIFT - 1);
-	order = GPMC_CHUNK_SHIFT - 1;
-	do {
-		size >>= 1;
-		order++;
-	} while (size);
-	size = 1 << order;
-	return size;
-}
-
-static int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size)
-{
-	struct resource	*res = &gpmc_cs_mem[cs];
-	int r;
-
-	size = gpmc_mem_align(size);
-	spin_lock(&gpmc_mem_lock);
-	res->start = base;
-	res->end = base + size - 1;
-	r = request_resource(&gpmc_mem_root, res);
-	spin_unlock(&gpmc_mem_lock);
-
-	return r;
-}
-
-static int gpmc_cs_delete_mem(int cs)
-{
-	struct resource	*res = &gpmc_cs_mem[cs];
-	int r;
-
-	spin_lock(&gpmc_mem_lock);
-	r = release_resource(res);
-	res->start = 0;
-	res->end = 0;
-	spin_unlock(&gpmc_mem_lock);
-
-	return r;
-}
-
-/**
- * gpmc_cs_remap - remaps a chip-select physical base address
- * @cs:		chip-select to remap
- * @base:	physical base address to re-map chip-select to
- *
- * Re-maps a chip-select to a new physical base address specified by
- * "base". Returns 0 on success and appropriate negative error code
- * on failure.
- */
-static int gpmc_cs_remap(int cs, u32 base)
-{
-	int ret;
-	u32 old_base, size;
-
-	if (cs > gpmc_cs_num) {
-		pr_err("%s: requested chip-select is disabled\n", __func__);
-		return -ENODEV;
-	}
-
-	/*
-	 * Make sure we ignore any device offsets from the GPMC partition
-	 * allocated for the chip select and that the new base confirms
-	 * to the GPMC 16MB minimum granularity.
-	 */ 
-	base &= ~(SZ_16M - 1);
-
-	gpmc_cs_get_memconf(cs, &old_base, &size);
-	if (base == old_base)
-		return 0;
-	gpmc_cs_disable_mem(cs);
-	ret = gpmc_cs_delete_mem(cs);
-	if (ret < 0)
-		return ret;
-	ret = gpmc_cs_insert_mem(cs, base, size);
-	if (ret < 0)
-		return ret;
-	ret = gpmc_cs_enable_mem(cs, base, size);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
-static int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
-{
-	struct resource *res = &gpmc_cs_mem[cs];
-	int r = -1;
-
-	if (cs > gpmc_cs_num) {
-		pr_err("%s: requested chip-select is disabled\n", __func__);
-		return -ENODEV;
-	}
-	size = gpmc_mem_align(size);
-	if (size > (1 << GPMC_SECTION_SHIFT))
-		return -ENOMEM;
-
-	spin_lock(&gpmc_mem_lock);
-	if (gpmc_cs_reserved(cs)) {
-		r = -EBUSY;
-		goto out;
-	}
-	if (gpmc_cs_mem_enabled(cs))
-		r = adjust_resource(res, res->start & ~(size - 1), size);
-	if (r < 0)
-		r = allocate_resource(&gpmc_mem_root, res, size, 0, ~0,
-				      size, NULL, NULL);
-	if (r < 0)
-		goto out;
-
-	r = gpmc_cs_enable_mem(cs, res->start, resource_size(res));
-	if (r < 0) {
-		release_resource(res);
-		goto out;
-	}
-
-	*base = res->start;
-	gpmc_cs_set_reserved(cs, 1);
-out:
-	spin_unlock(&gpmc_mem_lock);
-	return r;
-}
-
-static void gpmc_cs_free(int cs)
-{
-	struct resource	*res = &gpmc_cs_mem[cs];
-
-	spin_lock(&gpmc_mem_lock);
-	if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) {
-		printk(KERN_ERR "Trying to free non-reserved GPMC CS%d\n", cs);
-		BUG();
-		spin_unlock(&gpmc_mem_lock);
-		return;
-	}
-	gpmc_cs_disable_mem(cs);
-	if (res->flags)
-		release_resource(res);
-	gpmc_cs_set_reserved(cs, 0);
-	spin_unlock(&gpmc_mem_lock);
-}
-
-static void gpmc_mem_exit(void)
-{
-	int cs;
-
-	for (cs = 0; cs < gpmc_cs_num; cs++) {
-		if (!gpmc_cs_mem_enabled(cs))
-			continue;
-		gpmc_cs_delete_mem(cs);
-	}
-
-}
-
-static void gpmc_mem_init(void)
-{
-	int cs;
-
-	/*
-	 * The first 1MB of GPMC address space is typically mapped to
-	 * the internal ROM. Never allocate the first page, to
-	 * facilitate bug detection; even if we didn't boot from ROM.
-	 */
-	gpmc_mem_root.start = SZ_1M;
-	gpmc_mem_root.end = GPMC_MEM_END;
-
-	/* Reserve all regions that has been set up by bootloader */
-	for (cs = 0; cs < gpmc_cs_num; cs++) {
-		u32 base, size;
-
-		if (!gpmc_cs_mem_enabled(cs))
-			continue;
-		gpmc_cs_get_memconf(cs, &base, &size);
-		if (gpmc_cs_insert_mem(cs, base, size)) {
-			pr_warn("%s: disabling cs %d mapped at 0x%x-0x%x\n",
-				__func__, cs, base, base + size);
-			gpmc_cs_disable_mem(cs);
-		}
-	}
-}
-
-static u32 gpmc_round_ps_to_sync_clk(u32 time_ps, u32 sync_clk)
-{
-	u32 temp;
-	int div;
-
-	div = gpmc_calc_divider(sync_clk);
-	temp = gpmc_ps_to_ticks(time_ps);
-	temp = (temp + div - 1) / div;
-	return gpmc_ticks_to_ps(temp * div);
-}
-
-/* XXX: can the cycles be avoided ? */
-static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t,
-				       struct gpmc_device_timings *dev_t,
-				       bool mux)
-{
-	u32 temp;
-
-	/* adv_rd_off */
-	temp = dev_t->t_avdp_r;
-	/* XXX: mux check required ? */
-	if (mux) {
-		/* XXX: t_avdp not to be required for sync, only added for tusb
-		 * this indirectly necessitates requirement of t_avdp_r and
-		 * t_avdp_w instead of having a single t_avdp
-		 */
-		temp = max_t(u32, temp,	gpmc_t->clk_activation + dev_t->t_avdh);
-		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
-	}
-	gpmc_t->adv_rd_off = gpmc_round_ps_to_ticks(temp);
-
-	/* oe_on */
-	temp = dev_t->t_oeasu; /* XXX: remove this ? */
-	if (mux) {
-		temp = max_t(u32, temp,	gpmc_t->clk_activation + dev_t->t_ach);
-		temp = max_t(u32, temp, gpmc_t->adv_rd_off +
-				gpmc_ticks_to_ps(dev_t->cyc_aavdh_oe));
-	}
-	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
-
-	/* access */
-	/* XXX: any scope for improvement ?, by combining oe_on
-	 * and clk_activation, need to check whether
-	 * access = clk_activation + round to sync clk ?
-	 */
-	temp = max_t(u32, dev_t->t_iaa,	dev_t->cyc_iaa * gpmc_t->sync_clk);
-	temp += gpmc_t->clk_activation;
-	if (dev_t->cyc_oe)
-		temp = max_t(u32, temp, gpmc_t->oe_on +
-				gpmc_ticks_to_ps(dev_t->cyc_oe));
-	gpmc_t->access = gpmc_round_ps_to_ticks(temp);
-
-	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ps(1);
-	gpmc_t->cs_rd_off = gpmc_t->oe_off;
-
-	/* rd_cycle */
-	temp = max_t(u32, dev_t->t_cez_r, dev_t->t_oez);
-	temp = gpmc_round_ps_to_sync_clk(temp, gpmc_t->sync_clk) +
-							gpmc_t->access;
-	/* XXX: barter t_ce_rdyz with t_cez_r ? */
-	if (dev_t->t_ce_rdyz)
-		temp = max_t(u32, temp,	gpmc_t->cs_rd_off + dev_t->t_ce_rdyz);
-	gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp);
-
-	return 0;
-}
-
-static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t,
-					struct gpmc_device_timings *dev_t,
-					bool mux)
-{
-	u32 temp;
-
-	/* adv_wr_off */
-	temp = dev_t->t_avdp_w;
-	if (mux) {
-		temp = max_t(u32, temp,
-			gpmc_t->clk_activation + dev_t->t_avdh);
-		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
-	}
-	gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp);
-
-	/* wr_data_mux_bus */
-	temp = max_t(u32, dev_t->t_weasu,
-			gpmc_t->clk_activation + dev_t->t_rdyo);
-	/* XXX: shouldn't mux be kept as a whole for wr_data_mux_bus ?,
-	 * and in that case remember to handle we_on properly
-	 */
-	if (mux) {
-		temp = max_t(u32, temp,
-			gpmc_t->adv_wr_off + dev_t->t_aavdh);
-		temp = max_t(u32, temp, gpmc_t->adv_wr_off +
-				gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
-	}
-	gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp);
-
-	/* we_on */
-	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
-		gpmc_t->we_on = gpmc_round_ps_to_ticks(dev_t->t_weasu);
-	else
-		gpmc_t->we_on = gpmc_t->wr_data_mux_bus;
-
-	/* wr_access */
-	/* XXX: gpmc_capability check reqd ? , even if not, will not harm */
-	gpmc_t->wr_access = gpmc_t->access;
-
-	/* we_off */
-	temp = gpmc_t->we_on + dev_t->t_wpl;
-	temp = max_t(u32, temp,
-			gpmc_t->wr_access + gpmc_ticks_to_ps(1));
-	temp = max_t(u32, temp,
-		gpmc_t->we_on + gpmc_ticks_to_ps(dev_t->cyc_wpl));
-	gpmc_t->we_off = gpmc_round_ps_to_ticks(temp);
-
-	gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off +
-							dev_t->t_wph);
-
-	/* wr_cycle */
-	temp = gpmc_round_ps_to_sync_clk(dev_t->t_cez_w, gpmc_t->sync_clk);
-	temp += gpmc_t->wr_access;
-	/* XXX: barter t_ce_rdyz with t_cez_w ? */
-	if (dev_t->t_ce_rdyz)
-		temp = max_t(u32, temp,
-				 gpmc_t->cs_wr_off + dev_t->t_ce_rdyz);
-	gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp);
-
-	return 0;
-}
-
-static int gpmc_calc_async_read_timings(struct gpmc_timings *gpmc_t,
-					struct gpmc_device_timings *dev_t,
-					bool mux)
-{
-	u32 temp;
-
-	/* adv_rd_off */
-	temp = dev_t->t_avdp_r;
-	if (mux)
-		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
-	gpmc_t->adv_rd_off = gpmc_round_ps_to_ticks(temp);
-
-	/* oe_on */
-	temp = dev_t->t_oeasu;
-	if (mux)
-		temp = max_t(u32, temp,
-			gpmc_t->adv_rd_off + dev_t->t_aavdh);
-	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
-
-	/* access */
-	temp = max_t(u32, dev_t->t_iaa, /* XXX: remove t_iaa in async ? */
-				gpmc_t->oe_on + dev_t->t_oe);
-	temp = max_t(u32, temp,
-				gpmc_t->cs_on + dev_t->t_ce);
-	temp = max_t(u32, temp,
-				gpmc_t->adv_on + dev_t->t_aa);
-	gpmc_t->access = gpmc_round_ps_to_ticks(temp);
-
-	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ps(1);
-	gpmc_t->cs_rd_off = gpmc_t->oe_off;
-
-	/* rd_cycle */
-	temp = max_t(u32, dev_t->t_rd_cycle,
-			gpmc_t->cs_rd_off + dev_t->t_cez_r);
-	temp = max_t(u32, temp, gpmc_t->oe_off + dev_t->t_oez);
-	gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp);
-
-	return 0;
-}
-
-static int gpmc_calc_async_write_timings(struct gpmc_timings *gpmc_t,
-					 struct gpmc_device_timings *dev_t,
-					 bool mux)
-{
-	u32 temp;
-
-	/* adv_wr_off */
-	temp = dev_t->t_avdp_w;
-	if (mux)
-		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
-	gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp);
-
-	/* wr_data_mux_bus */
-	temp = dev_t->t_weasu;
-	if (mux) {
-		temp = max_t(u32, temp,	gpmc_t->adv_wr_off + dev_t->t_aavdh);
-		temp = max_t(u32, temp, gpmc_t->adv_wr_off +
-				gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
-	}
-	gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp);
-
-	/* we_on */
-	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
-		gpmc_t->we_on = gpmc_round_ps_to_ticks(dev_t->t_weasu);
-	else
-		gpmc_t->we_on = gpmc_t->wr_data_mux_bus;
-
-	/* we_off */
-	temp = gpmc_t->we_on + dev_t->t_wpl;
-	gpmc_t->we_off = gpmc_round_ps_to_ticks(temp);
-
-	gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off +
-							dev_t->t_wph);
-
-	/* wr_cycle */
-	temp = max_t(u32, dev_t->t_wr_cycle,
-				gpmc_t->cs_wr_off + dev_t->t_cez_w);
-	gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp);
-
-	return 0;
-}
-
-static int gpmc_calc_sync_common_timings(struct gpmc_timings *gpmc_t,
-			struct gpmc_device_timings *dev_t)
-{
-	u32 temp;
-
-	gpmc_t->sync_clk = gpmc_calc_divider(dev_t->clk) *
-						gpmc_get_fclk_period();
-
-	gpmc_t->page_burst_access = gpmc_round_ps_to_sync_clk(
-					dev_t->t_bacc,
-					gpmc_t->sync_clk);
-
-	temp = max_t(u32, dev_t->t_ces, dev_t->t_avds);
-	gpmc_t->clk_activation = gpmc_round_ps_to_ticks(temp);
-
-	if (gpmc_calc_divider(gpmc_t->sync_clk) != 1)
-		return 0;
-
-	if (dev_t->ce_xdelay)
-		gpmc_t->bool_timings.cs_extra_delay = true;
-	if (dev_t->avd_xdelay)
-		gpmc_t->bool_timings.adv_extra_delay = true;
-	if (dev_t->oe_xdelay)
-		gpmc_t->bool_timings.oe_extra_delay = true;
-	if (dev_t->we_xdelay)
-		gpmc_t->bool_timings.we_extra_delay = true;
-
-	return 0;
-}
-
-static int gpmc_calc_common_timings(struct gpmc_timings *gpmc_t,
-				    struct gpmc_device_timings *dev_t,
-				    bool sync)
-{
-	u32 temp;
-
-	/* cs_on */
-	gpmc_t->cs_on = gpmc_round_ps_to_ticks(dev_t->t_ceasu);
-
-	/* adv_on */
-	temp = dev_t->t_avdasu;
-	if (dev_t->t_ce_avd)
-		temp = max_t(u32, temp,
-				gpmc_t->cs_on + dev_t->t_ce_avd);
-	gpmc_t->adv_on = gpmc_round_ps_to_ticks(temp);
-
-	if (sync)
-		gpmc_calc_sync_common_timings(gpmc_t, dev_t);
-
-	return 0;
-}
-
-/* TODO: remove this function once all peripherals are confirmed to
- * work with generic timing. Simultaneously gpmc_cs_set_timings()
- * has to be modified to handle timings in ps instead of ns
-*/
-static void gpmc_convert_ps_to_ns(struct gpmc_timings *t)
-{
-	t->cs_on /= 1000;
-	t->cs_rd_off /= 1000;
-	t->cs_wr_off /= 1000;
-	t->adv_on /= 1000;
-	t->adv_rd_off /= 1000;
-	t->adv_wr_off /= 1000;
-	t->we_on /= 1000;
-	t->we_off /= 1000;
-	t->oe_on /= 1000;
-	t->oe_off /= 1000;
-	t->page_burst_access /= 1000;
-	t->access /= 1000;
-	t->rd_cycle /= 1000;
-	t->wr_cycle /= 1000;
-	t->bus_turnaround /= 1000;
-	t->cycle2cycle_delay /= 1000;
-	t->wait_monitoring /= 1000;
-	t->clk_activation /= 1000;
-	t->wr_access /= 1000;
-	t->wr_data_mux_bus /= 1000;
-}
-
-static int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
-			     struct gpmc_settings *gpmc_s,
-			     struct gpmc_device_timings *dev_t)
-{
-	bool mux = false, sync = false;
-
-	if (gpmc_s) {
-		mux = gpmc_s->mux_add_data ? true : false;
-		sync = (gpmc_s->sync_read || gpmc_s->sync_write);
-	}
-
-	memset(gpmc_t, 0, sizeof(*gpmc_t));
-
-	gpmc_calc_common_timings(gpmc_t, dev_t, sync);
-
-	if (gpmc_s && gpmc_s->sync_read)
-		gpmc_calc_sync_read_timings(gpmc_t, dev_t, mux);
-	else
-		gpmc_calc_async_read_timings(gpmc_t, dev_t, mux);
-
-	if (gpmc_s && gpmc_s->sync_write)
-		gpmc_calc_sync_write_timings(gpmc_t, dev_t, mux);
-	else
-		gpmc_calc_async_write_timings(gpmc_t, dev_t, mux);
-
-	/* TODO: remove, see function definition */
-	gpmc_convert_ps_to_ns(gpmc_t);
-
-	return 0;
-}
-
-/**
- * gpmc_cs_program_settings - programs non-timing related settings
- * @cs:		GPMC chip-select to program
- * @p:		pointer to GPMC settings structure
- *
- * Programs non-timing related settings for a GPMC chip-select, such as
- * bus-width, burst configuration, etc. Function should be called once
- * for each chip-select that is being used and must be called before
- * calling gpmc_cs_set_timings() as timing parameters in the CONFIG1
- * register will be initialised to zero by this function. Returns 0 on
- * success and appropriate negative error code on failure.
- */
-static int gpmc_cs_program_settings(int cs, struct gpmc_settings *p)
-{
-	u32 config1;
-
-	if ((!p->device_width) || (p->device_width > GPMC_DEVWIDTH_16BIT)) {
-		pr_err("%s: invalid width %d!", __func__, p->device_width);
-		return -EINVAL;
-	}
-
-	/* Address-data multiplexing not supported for NAND devices */
-	if (p->device_nand && p->mux_add_data) {
-		pr_err("%s: invalid configuration!\n", __func__);
-		return -EINVAL;
-	}
-
-	if ((p->mux_add_data > GPMC_MUX_AD) ||
-	    ((p->mux_add_data == GPMC_MUX_AAD) &&
-	     !(gpmc_capability & GPMC_HAS_MUX_AAD))) {
-		pr_err("%s: invalid multiplex configuration!\n", __func__);
-		return -EINVAL;
-	}
-
-	/* Page/burst mode supports lengths of 4, 8 and 16 bytes */
-	if (p->burst_read || p->burst_write) {
-		switch (p->burst_len) {
-		case GPMC_BURST_4:
-		case GPMC_BURST_8:
-		case GPMC_BURST_16:
-			break;
-		default:
-			pr_err("%s: invalid page/burst-length (%d)\n",
-			       __func__, p->burst_len);
-			return -EINVAL;
-		}
-	}
-
-	if ((p->wait_on_read || p->wait_on_write) &&
-	    (p->wait_pin > gpmc_nr_waitpins)) {
-		pr_err("%s: invalid wait-pin (%d)\n", __func__, p->wait_pin);
-		return -EINVAL;
-	}
-
-	config1 = GPMC_CONFIG1_DEVICESIZE((p->device_width - 1));
-
-	if (p->sync_read)
-		config1 |= GPMC_CONFIG1_READTYPE_SYNC;
-	if (p->sync_write)
-		config1 |= GPMC_CONFIG1_WRITETYPE_SYNC;
-	if (p->wait_on_read)
-		config1 |= GPMC_CONFIG1_WAIT_READ_MON;
-	if (p->wait_on_write)
-		config1 |= GPMC_CONFIG1_WAIT_WRITE_MON;
-	if (p->wait_on_read || p->wait_on_write)
-		config1 |= GPMC_CONFIG1_WAIT_PIN_SEL(p->wait_pin);
-	if (p->device_nand)
-		config1	|= GPMC_CONFIG1_DEVICETYPE(GPMC_DEVICETYPE_NAND);
-	if (p->mux_add_data)
-		config1	|= GPMC_CONFIG1_MUXTYPE(p->mux_add_data);
-	if (p->burst_read)
-		config1 |= GPMC_CONFIG1_READMULTIPLE_SUPP;
-	if (p->burst_write)
-		config1 |= GPMC_CONFIG1_WRITEMULTIPLE_SUPP;
-	if (p->burst_read || p->burst_write) {
-		config1 |= GPMC_CONFIG1_PAGE_LEN(p->burst_len >> 3);
-		config1 |= p->burst_wrap ? GPMC_CONFIG1_WRAPBURST_SUPP : 0;
-	}
-
-	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, config1);
-
-	return 0;
-}
-
-#ifdef CONFIG_OF
-static struct of_device_id gpmc_dt_ids[] = {
-	{ .compatible = "ti,omap2420-gpmc" },
-	{ .compatible = "ti,omap2430-gpmc" },
-	{ .compatible = "ti,omap3430-gpmc" },	/* omap3430 & omap3630 */
-	{ .compatible = "ti,omap4430-gpmc" },	/* omap4430 & omap4460 & omap543x */
-	{ .compatible = "ti,am3352-gpmc" },	/* am335x devices */
-	{ }
-};
-MODULE_DEVICE_TABLE(of, gpmc_dt_ids);
-
-/**
- * gpmc_read_settings_dt - read gpmc settings from device-tree
- * @np:		pointer to device-tree node for a gpmc child device
- * @p:		pointer to gpmc settings structure
- *
- * Reads the GPMC settings for a GPMC child device from device-tree and
- * stores them in the GPMC settings structure passed. The GPMC settings
- * structure is initialised to zero by this function and so any
- * previously stored settings will be cleared.
- */
-static void gpmc_read_settings_dt(struct device_node *np,
-				  struct gpmc_settings *p)
-{
-	memset(p, 0, sizeof(struct gpmc_settings));
-
-	p->sync_read = of_property_read_bool(np, "gpmc,sync-read");
-	p->sync_write = of_property_read_bool(np, "gpmc,sync-write");
-	of_property_read_u32(np, "gpmc,device-width", &p->device_width);
-	of_property_read_u32(np, "gpmc,mux-add-data", &p->mux_add_data);
-
-	if (!of_property_read_u32(np, "gpmc,burst-length", &p->burst_len)) {
-		p->burst_wrap = of_property_read_bool(np, "gpmc,burst-wrap");
-		p->burst_read = of_property_read_bool(np, "gpmc,burst-read");
-		p->burst_write = of_property_read_bool(np, "gpmc,burst-write");
-		if (!p->burst_read && !p->burst_write)
-			pr_warn("%s: page/burst-length set but not used!\n",
-				__func__);
-	}
-
-	if (!of_property_read_u32(np, "gpmc,wait-pin", &p->wait_pin)) {
-		p->wait_on_read = of_property_read_bool(np,
-							"gpmc,wait-on-read");
-		p->wait_on_write = of_property_read_bool(np,
-							 "gpmc,wait-on-write");
-		if (!p->wait_on_read && !p->wait_on_write)
-			pr_warn("%s: read/write wait monitoring not enabled!\n",
-				__func__);
-	}
-}
-
-static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
-						struct gpmc_timings *gpmc_t)
-{
-	struct gpmc_bool_timings *p;
-
-	if (!np || !gpmc_t)
-		return;
-
-	memset(gpmc_t, 0, sizeof(*gpmc_t));
-
-	/* minimum clock period for syncronous mode */
-	of_property_read_u32(np, "gpmc,sync-clk-ps", &gpmc_t->sync_clk);
-
-	/* chip select timtings */
-	of_property_read_u32(np, "gpmc,cs-on-ns", &gpmc_t->cs_on);
-	of_property_read_u32(np, "gpmc,cs-rd-off-ns", &gpmc_t->cs_rd_off);
-	of_property_read_u32(np, "gpmc,cs-wr-off-ns", &gpmc_t->cs_wr_off);
-
-	/* ADV signal timings */
-	of_property_read_u32(np, "gpmc,adv-on-ns", &gpmc_t->adv_on);
-	of_property_read_u32(np, "gpmc,adv-rd-off-ns", &gpmc_t->adv_rd_off);
-	of_property_read_u32(np, "gpmc,adv-wr-off-ns", &gpmc_t->adv_wr_off);
-
-	/* WE signal timings */
-	of_property_read_u32(np, "gpmc,we-on-ns", &gpmc_t->we_on);
-	of_property_read_u32(np, "gpmc,we-off-ns", &gpmc_t->we_off);
-
-	/* OE signal timings */
-	of_property_read_u32(np, "gpmc,oe-on-ns", &gpmc_t->oe_on);
-	of_property_read_u32(np, "gpmc,oe-off-ns", &gpmc_t->oe_off);
-
-	/* access and cycle timings */
-	of_property_read_u32(np, "gpmc,page-burst-access-ns",
-			     &gpmc_t->page_burst_access);
-	of_property_read_u32(np, "gpmc,access-ns", &gpmc_t->access);
-	of_property_read_u32(np, "gpmc,rd-cycle-ns", &gpmc_t->rd_cycle);
-	of_property_read_u32(np, "gpmc,wr-cycle-ns", &gpmc_t->wr_cycle);
-	of_property_read_u32(np, "gpmc,bus-turnaround-ns",
-			     &gpmc_t->bus_turnaround);
-	of_property_read_u32(np, "gpmc,cycle2cycle-delay-ns",
-			     &gpmc_t->cycle2cycle_delay);
-	of_property_read_u32(np, "gpmc,wait-monitoring-ns",
-			     &gpmc_t->wait_monitoring);
-	of_property_read_u32(np, "gpmc,clk-activation-ns",
-			     &gpmc_t->clk_activation);
-
-	/* only applicable to OMAP3+ */
-	of_property_read_u32(np, "gpmc,wr-access-ns", &gpmc_t->wr_access);
-	of_property_read_u32(np, "gpmc,wr-data-mux-bus-ns",
-			     &gpmc_t->wr_data_mux_bus);
-
-	/* bool timing parameters */
-	p = &gpmc_t->bool_timings;
-
-	p->cycle2cyclediffcsen =
-		of_property_read_bool(np, "gpmc,cycle2cycle-diffcsen");
-	p->cycle2cyclesamecsen =
-		of_property_read_bool(np, "gpmc,cycle2cycle-samecsen");
-	p->we_extra_delay = of_property_read_bool(np, "gpmc,we-extra-delay");
-	p->oe_extra_delay = of_property_read_bool(np, "gpmc,oe-extra-delay");
-	p->adv_extra_delay = of_property_read_bool(np, "gpmc,adv-extra-delay");
-	p->cs_extra_delay = of_property_read_bool(np, "gpmc,cs-extra-delay");
-	p->time_para_granularity =
-		of_property_read_bool(np, "gpmc,time-para-granularity");
-}
-
-/**
- * gpmc_probe_generic_child - configures the gpmc for a child device
- * @pdev:	pointer to gpmc platform device
- * @child:	pointer to device-tree node for child device
- *
- * Allocates and configures a GPMC chip-select for a child device.
- * Returns 0 on success and appropriate negative error code on failure.
- */
-static int gpmc_probe_generic_child(struct platform_device *pdev,
-				struct device_node *child)
-{
-	struct gpmc_settings gpmc_s;
-	struct gpmc_timings gpmc_t;
-	struct resource res;
-	unsigned long base;
-	int ret, cs;
-	struct device *dev = &pdev->dev;
-
-	if (of_property_read_u32(child, "reg", &cs) < 0) {
-		dev_err(&pdev->dev, "%s has no 'reg' property\n",
-			child->full_name);
-		return -ENODEV;
-	}
-
-	if (of_address_to_resource(child, 0, &res) < 0) {
-		dev_err(&pdev->dev, "%s has malformed 'reg' property\n",
-			child->full_name);
-		return -ENODEV;
-	}
-
-	ret = gpmc_cs_request(cs, resource_size(&res), &base);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "cannot request GPMC CS %d\n", cs);
-		return ret;
-	}
-
-	/*
-	 * For some GPMC devices we still need to rely on the bootloader
-	 * timings because the devices can be connected via FPGA. So far
-	 * the list is smc91x on the omap2 SDP boards, and 8250 on zooms.
-	 * REVISIT: Add timing support from slls644g.pdf and from the
-	 * lan91c96 manual.
-	 */
-	if (of_device_is_compatible(child, "ns16550a") ||
-	    of_device_is_compatible(child, "smsc,lan91c94") ||
-	    of_device_is_compatible(child, "smsc,lan91c111")) {
-		dev_warn(&pdev->dev,
-			 "%s using bootloader timings on CS%d\n",
-			 child->name, cs);
-		goto no_timings;
-	}
-
-	/*
-	 * FIXME: gpmc_cs_request() will map the CS to an arbitary
-	 * location in the gpmc address space. When booting with
-	 * device-tree we want the NOR flash to be mapped to the
-	 * location specified in the device-tree blob. So remap the
-	 * CS to this location. Once DT migration is complete should
-	 * just make gpmc_cs_request() map a specific address.
-	 */
-	ret = gpmc_cs_remap(cs, res.start);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "cannot remap GPMC CS %d to %pa\n",
-			cs, &res.start);
-		goto err;
-	}
-
-	gpmc_read_settings_dt(child, &gpmc_s);
-
-	if (of_node_cmp(child->name, "nand") == 0) {
-		/* NAND specific setup */
-		u32 val;
-
-		val = of_get_nand_bus_width(child);
-		switch (val) {
-		case 8:
-			gpmc_s.device_width = GPMC_DEVWIDTH_8BIT;
-			break;
-		case 16:
-			gpmc_s.device_width = GPMC_DEVWIDTH_16BIT;
-			break;
-		default:
-			dev_err(dev, "%s: invalid 'nand-bus-width'\n",
-				child->name);
-			ret = -EINVAL;
-			goto err;
-		}
-
-		gpmc_s.device_nand = true;
-
-	} else if (of_node_cmp(child->name, "onenand") == 0) {
-		/* DT incorrectly sets sync modes, onenand default is async */
-		gpmc_s.sync_read = false;
-		gpmc_s.sync_write = false;
-
-	} else {
-		if (of_property_read_u32(child, "bank-width",
-					 &gpmc_s.device_width)) {
-			dev_err(dev, "%s: no 'bank-width' property\n",
-				child->name);
-			goto err;
-		}
-
-		if (gpmc_s.device_width < 1 || gpmc_s.device_width > 2) {
-			dev_err(dev, "%s: invalid 'bank-width'\n",
-				child->name);
-			goto err;
-		}
-	}
-
-	ret = gpmc_cs_program_settings(cs, &gpmc_s);
-	if (ret < 0)
-		goto err;
-
-	gpmc_read_timings_dt(child, &gpmc_t);
-	gpmc_cs_set_timings(cs, &gpmc_t);
-
-no_timings:
-	if (of_platform_device_create(child, NULL, &pdev->dev))
-		return 0;
-
-	dev_err(&pdev->dev, "failed to create gpmc child %s\n", child->name);
-	ret = -ENODEV;
-
-err:
-	gpmc_cs_free(cs);
-
-	return ret;
-}
-
-static int gpmc_probe_dt(struct platform_device *pdev)
-{
-	int ret;
-	struct device_node *child;
-
-	ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-cs",
-				   &gpmc_cs_num);
-	if (ret < 0) {
-		pr_err("%s: number of chip-selects not defined\n", __func__);
-		return ret;
-	} else if (gpmc_cs_num < 1) {
-		pr_err("%s: all chip-selects are disabled\n", __func__);
-		return -EINVAL;
-	} else if (gpmc_cs_num > GPMC_CS_NUM) {
-		pr_err("%s: number of supported chip-selects cannot be > %d\n",
-					 __func__, GPMC_CS_NUM);
-		return -EINVAL;
-	}
-
-	ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-waitpins",
-				   &gpmc_nr_waitpins);
-	if (ret < 0) {
-		pr_err("%s: number of wait pins not found!\n", __func__);
-		return ret;
-	}
-
-	for_each_child_of_node(pdev->dev.of_node, child) {
-
-		if (!child->name)
-			continue;
-
-		if (of_node_cmp(child->name, "ethernet") == 0 ||
-		    of_node_cmp(child->name, "nor") == 0 ||
-		    of_node_cmp(child->name, "uart") == 0 ||
-		    of_node_cmp(child->name, "nand") == 0 ||
-		    of_node_cmp(child->name, "onenand") == 0)
-			ret = gpmc_probe_generic_child(pdev, child);
-
-		if (WARN(ret < 0, "%s: probing gpmc child %s failed\n",
-			 __func__, child->full_name))
-			of_node_put(child);
-	}
-
-	return 0;
-}
-#else
-static int gpmc_probe_dt(struct platform_device *pdev)
-{
-	return 0;
-}
-#endif
-
-static int gpmc_nand_setup(struct platform_device *parent_pdev,
-			   struct gpmc_omap_cs_data *cs)
-{
-	struct resource *res;
-	struct resource *res_gpmc;
-
-	if (!cs->pdev)
-		return -EINVAL;
-
-	res = cs->pdev->resource;
-
-	if (cs->pdev->num_resources < 3)
-		return -EINVAL;
-
-	if (resource_type(&res[1]) != IORESOURCE_MEM ||
-	    resource_type(&res[2]) != IORESOURCE_IRQ)
-		return -EINVAL;
-
-	if (!cs->settings)
-		return -EINVAL;
-
-	/* GPMC register space */
-	res_gpmc = platform_get_resource(parent_pdev, IORESOURCE_MEM, 0);
-	if (!res_gpmc)
-		return -EINVAL;
-
-	res[1] = *res_gpmc;
-
-	/* setup IRQ resources */
-	res[2].start = gpmc_irq;
-
-	cs->settings->device_nand = true;
-
-	return 0;
-}
-
-static void gpmc_probe_legacy(struct platform_device *pdev)
-{
-	int i, rc, j;
-	struct device *dev = &pdev->dev;
-	struct gpmc_omap_platform_data *gpmc_pdata;
-	struct resource *mem_res;
-	unsigned long cs_base;
-	resource_size_t size;
-	struct gpmc_timings gpmc_timings;
-	struct gpmc_omap_cs_data *cs;
-
-	gpmc_pdata = dev->platform_data;
-	gpmc_cs_num = GPMC_CS_NUM;
-	gpmc_nr_waitpins = GPMC_NR_WAITPINS;
-
-	for (i = 0; i < GPMC_CS_NUM; i++) {
-		cs = &gpmc_pdata->cs[i];
-		if (!cs->valid)
-			continue;
-
-		if (cs->settings) {
-			if (gpmc_cs_program_settings(i, cs->settings)) {
-				dev_err(dev,
-					"Couldn't program settings for CS %d\n",
-					i);
-				continue;
-			}
-		}
-
-		/* give device_timings priority over gpmc_timings */
-		if (cs->device_timings) {
-			gpmc_calc_timings(&gpmc_timings, cs->settings,
-					  cs->device_timings);
-
-			if (gpmc_cs_set_timings(i, &gpmc_timings)) {
-				dev_err(dev,
-					"Couldn't program timings for CS %d\n",
-					i);
-				continue;
-			}
-		} else if (cs->gpmc_timings) {
-			if (gpmc_cs_set_timings(i, cs->gpmc_timings)) {
-				dev_err(dev,
-					"Couldn't program timings for CS %d\n",
-					i);
-				continue;
-			}
-		}
-	}
-
-	/*
-	 * All Chip Selects must be configured before platform devices are
-	 * created as some devices (e.g. tusb6010) can use multiple
-	 * Chip selects.
-	 */
-
-	/* Fixup Memory resources */
-	for (i = 0; i < GPMC_CS_NUM; i++) {
-		int required_resources;
-
-		cs = &gpmc_pdata->cs[i];
-		if (!cs->valid)
-			continue;
-
-		if (!cs->pdev)
-			continue;
-
-		/* Customized NAND setup */
-		if (cs->is_nand) {
-			if (gpmc_nand_setup(pdev, cs)) {
-				dev_err(dev, "Error setting up NAND on CS %d\n",
-					i);
-				continue;
-			}
-		}
-
-		mem_res = cs->pdev->resource;
-
-		/*
-		 * If device is present multiple times, fix the subsequent
-		 * resources
-		 */
-		required_resources = 1;
-		for (j = 0; j < i; j++) {
-			if (gpmc_pdata->cs[j].pdev == cs->pdev) {
-				mem_res++;
-				required_resources++;
-			}
-		}
-
-		if (cs->pdev->num_resources < required_resources ||
-		    resource_type(mem_res) != IORESOURCE_MEM) {
-			dev_err(dev, "Invalid IOMEM resource for CS %d\n", i);
-			continue;
-		}
-
-		/*
-		 * Request a CS space. Use size from
-		 * platform device's MEM resource
-		 */
-		size = mem_res->end - mem_res->start + 1;
-		if (gpmc_cs_request(i, size, &cs_base)) {
-			dev_err(dev, "Couldn't request resource for CS %d\n",
-				i);
-			continue;
-		}
-
-		mem_res->start = cs_base;
-		mem_res->end = cs_base + size - 1;
-	}
-
-	/* create the platform devices */
-	for (i = 0; i < GPMC_CS_NUM; i++) {
-		bool registered;
-
-		cs = &gpmc_pdata->cs[i];
-		if (!cs->valid)
-			continue;
-
-		if (!cs->pdev)
-			continue;
-
-		/*
-		 * same device can be present on multiple CS, don't
-		 * register device more than once.
-		 */
-		registered = false;
-		for (j = 0; j < i; j++) {
-			if (gpmc_pdata->cs[j].pdev == cs->pdev) {
-				registered = true;
-				break;
-			}
-		}
-
-		if (registered)
-			continue;
-
-		cs->pdev->dev.parent = dev;
-		rc = platform_device_register(cs->pdev);
-		if (rc < 0) {
-			dev_err(dev,
-				"Failed to register device %s on CS %d\n",
-				cs->pdev->name, i);
-			continue;
-		}
-	}
-}
-
-static int gpmc_probe(struct platform_device *pdev)
-{
-	int rc;
-	u32 l;
-	struct resource *res;
-	struct device *dev = &pdev->dev;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res == NULL)
-		return -ENOENT;
-
-	phys_base = res->start;
-	mem_size = resource_size(res);
-
-	gpmc_base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(gpmc_base))
-		return PTR_ERR(gpmc_base);
-
-	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "Failed to get resource: irq\n");
-		return -EINVAL;
-	}
-
-	gpmc_irq = res->start;
-
-	gpmc_l3_clk = clk_get(&pdev->dev, "fck");
-	if (IS_ERR(gpmc_l3_clk)) {
-		dev_err(&pdev->dev, "error: clk_get\n");
-		gpmc_irq = 0;
-		return PTR_ERR(gpmc_l3_clk);
-	}
-
-	pm_runtime_enable(&pdev->dev);
-	pm_runtime_get_sync(&pdev->dev);
-
-	gpmc_dev = dev;
-
-	l = gpmc_read_reg(GPMC_REVISION);
-
-	/*
-	 * FIXME: Once device-tree migration is complete the below flags
-	 * should be populated based upon the device-tree compatible
-	 * string. For now just use the IP revision. OMAP3+ devices have
-	 * the wr_access and wr_data_mux_bus register fields. OMAP4+
-	 * devices support the addr-addr-data multiplex protocol.
-	 *
-	 * GPMC IP revisions:
-	 * - OMAP24xx			= 2.0
-	 * - OMAP3xxx			= 5.0
-	 * - OMAP44xx/54xx/AM335x	= 6.0
-	 */
-	if (GPMC_REVISION_MAJOR(l) > 0x4)
-		gpmc_capability = GPMC_HAS_WR_ACCESS | GPMC_HAS_WR_DATA_MUX_BUS;
-	if (GPMC_REVISION_MAJOR(l) > 0x5)
-		gpmc_capability |= GPMC_HAS_MUX_AAD;
-	dev_info(dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l),
-		 GPMC_REVISION_MINOR(l));
-
-	gpmc_mem_init();
-
-	/* Now the GPMC is initialised, unreserve the chip-selects */
-	gpmc_cs_map = 0;
-
-	if (dev->of_node) {
-		rc = gpmc_probe_dt(pdev);
-		if (rc) {
-			dev_err(dev, "gpmc_probe_dt() failed\n");
-			goto error;
-		}
-	} else {
-		/* Legacy probing based on platform data */
-		if (!dev->platform_data) {
-			dev_err(dev, "No platform data\n");
-			rc = -EINVAL;
-			goto error;
-		}
-
-		gpmc_probe_legacy(pdev);
-	}
-
-	return 0;
-
-error:
-	pm_runtime_put_sync(dev);
-	clk_put(gpmc_l3_clk);
-	return rc;
-}
-
-static int gpmc_remove(struct platform_device *pdev)
-{
-	gpmc_mem_exit();
-	pm_runtime_put_sync(&pdev->dev);
-	pm_runtime_disable(&pdev->dev);
-	gpmc_dev = NULL;
-	return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int gpmc_suspend(struct device *dev)
-{
-	omap3_gpmc_save_context();
-	pm_runtime_put_sync(dev);
-	return 0;
-}
-
-static int gpmc_resume(struct device *dev)
-{
-	pm_runtime_get_sync(dev);
-	omap3_gpmc_restore_context();
-	return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(gpmc_pm_ops, gpmc_suspend, gpmc_resume);
-
-static struct platform_driver gpmc_driver = {
-	.probe		= gpmc_probe,
-	.remove		= gpmc_remove,
-	.driver		= {
-		.name	= DEVICE_NAME,
-		.owner	= THIS_MODULE,
-		.of_match_table = of_match_ptr(gpmc_dt_ids),
-		.pm	= &gpmc_pm_ops,
-	},
-};
-
-static __init int gpmc_init(void)
-{
-	return platform_driver_register(&gpmc_driver);
-}
-
-static __exit void gpmc_exit(void)
-{
-	platform_driver_unregister(&gpmc_driver);
-
-}
-
-module_init(gpmc_init);
-module_exit(gpmc_exit);
-
-static int __init omap_gpmc_init(void)
-{
-	struct omap_hwmod *oh;
-	struct platform_device *pdev;
-	char *oh_name = "gpmc";
-
-	/*
-	 * if the board boots up with a populated DT, do not
-	 * manually add the device from this initcall
-	 */
-	if (of_have_populated_dt())
-		return -ENODEV;
-
-	oh = omap_hwmod_lookup(oh_name);
-	if (!oh) {
-		pr_err("Could not look up %s\n", oh_name);
-		return -ENODEV;
-	}
-
-	pdev = omap_device_build(DEVICE_NAME, -1, oh, (void *)&gpmc_pdata,
-				 sizeof(gpmc_pdata));
-	WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
-
-	return PTR_RET(pdev);
-}
-/* must run after machine_init code. i.e. arch_init */
-omap_subsys_initcall(omap_gpmc_init);
-
-/**
- * gpmc_generic_init - Initialize platform data for a Chip Select
- *
- * @cs		chip select number
- * @is_nand	true if device is NAND flash.
- * @settings	GPMC settings
- * @device_timings	device timings for device on this CS
- * @gpmc_timings	GPMC timings
- * @pdev	platform device for the device on this CS
- * @pdata_size	platform data size for the platform device
- */
-int gpmc_generic_init(int cs, bool is_nand,
-		      struct gpmc_settings *settings,
-		      struct gpmc_device_timings *device_timings,
-		      struct gpmc_timings *gpmc_timings,
-		      struct platform_device *pdev, unsigned pdata_size)
-{
-	struct gpmc_settings *gpmc_s = NULL;
-	struct gpmc_device_timings *gpmc_dev_t = NULL;
-	struct gpmc_timings *gpmc_t;
-
-	if (cs >= GPMC_CS_NUM) {
-		pr_err("%s: Invalid cs specified. Max CS = %d\n",
-		       __func__, GPMC_CS_NUM);
-		return -EINVAL;
-	}
-
-	if (gpmc_pdata.cs[cs].valid) {
-		pr_err("%s: cs %d already requested, ignoring new request\n",
-		       __func__, cs);
-		return -EINVAL;
-	}
-
-	if (settings) {
-		gpmc_s = kmemdup(settings, sizeof(*settings), GFP_KERNEL);
-		if (!gpmc_s)
-			return -ENOMEM;
-
-		gpmc_pdata.cs[cs].settings = gpmc_s;
-	}
-
-	if (device_timings) {
-		gpmc_dev_t = kmemdup(device_timings, sizeof(*device_timings),
-				     GFP_KERNEL);
-		if (!gpmc_dev_t)
-			goto dev_t_fail;
-
-		gpmc_pdata.cs[cs].device_timings = gpmc_dev_t;
-	}
-
-	if (gpmc_timings) {
-		gpmc_t = kmemdup(gpmc_timings, sizeof(*gpmc_timings),
-				 GFP_KERNEL);
-		if (!gpmc_t)
-			goto gpmc_t_fail;
-
-		gpmc_pdata.cs[cs].gpmc_timings = gpmc_t;
-	}
-
-	gpmc_pdata.cs[cs].is_nand = is_nand;
-	gpmc_pdata.cs[cs].pdev = pdev;
-	gpmc_pdata.cs[cs].pdata_size = pdata_size;
-	gpmc_pdata.cs[cs].valid = true;
-
-	return 0;
-
-gpmc_t_fail:
-	if (device_timings)
-		kfree(gpmc_dev_t);
-dev_t_fail:
-	if (settings)
-		kfree(gpmc_s);
-
-	return -ENOMEM;
-}
-
-/**
- * omap_gpmc_retime - Reconfigre GPMC timings for the device
- *
- * @cs		Chip select number
- * @gpmc_s	GPMC settings
- * @dev_t	New device timings to set
- */
-int omap_gpmc_retime(int cs, struct gpmc_settings *gpmc_s,
-		     struct gpmc_device_timings *dev_t)
-{
-	struct gpmc_timings gpmc_t;
-	struct device *dev = gpmc_dev;
-
-	if (!gpmc_dev)
-		return -ENODEV;
-
-	if (cs < 0 || cs >= gpmc_cs_num) {
-		dev_err(dev, "%s: Invalid find Chip Select\n", __func__);
-		return cs;
-	}
-
-	if (gpmc_cs_program_settings(cs, gpmc_s)) {
-		dev_err(dev, "%s: Failed to set GPMC settings\n", __func__);
-		return -EINVAL;
-	}
-
-	gpmc_calc_timings(&gpmc_t, gpmc_s, dev_t);
-	if (gpmc_cs_set_timings(cs, &gpmc_t)) {
-		dev_err(dev, "%s: Failed to set GPMC timings\n", __func__);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(omap_gpmc_retime);
-
-/**
- * omap_gpmc_get_clk_period - Get the nearest possible (equal to or higer) GPMC
- *				synchronous clock (GPMC_CLK) period.
- *
- * @cs		Chip select number
- * @min_ps	Minimum synchronous clock period supporded by the device
- *
- * Returns the nearest possible GPMC clock period in picoseconds, equal to or
- * higher than the requested period. 0 in case of error.
- */
-unsigned long omap_gpmc_get_clk_period(int cs,
-				       unsigned long min_ps)
-{
-	int div;
-	unsigned long clk_ps;
-	struct device *dev = gpmc_dev;
-
-	if (!gpmc_dev)
-		return 0;
-
-	if (cs < 0 || cs >= gpmc_cs_num) {
-		dev_err(dev, "%s: Invalid Chip Select\n", __func__);
-		return cs;
-	}
-
-	div = gpmc_calc_divider(min_ps);
-	if (div < 0) {
-		dev_err(dev, "%s: Can't support requested clock period %lu ps\n",
-			__func__, min_ps);
-		return 0;
-	}
-
-	clk_ps = gpmc_get_fclk_period() * div;
-
-	return clk_ps;
-}
-EXPORT_SYMBOL_GPL(omap_gpmc_get_clk_period);
-
-static struct omap3_gpmc_regs gpmc_context;
-
-void omap3_gpmc_save_context(void)
-{
-	int i;
-
-	gpmc_context.sysconfig = gpmc_read_reg(GPMC_SYSCONFIG);
-	gpmc_context.irqenable = gpmc_read_reg(GPMC_IRQENABLE);
-	gpmc_context.timeout_ctrl = gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
-	gpmc_context.config = gpmc_read_reg(GPMC_CONFIG);
-	gpmc_context.prefetch_config1 = gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
-	gpmc_context.prefetch_config2 = gpmc_read_reg(GPMC_PREFETCH_CONFIG2);
-	gpmc_context.prefetch_control = gpmc_read_reg(GPMC_PREFETCH_CONTROL);
-	for (i = 0; i < gpmc_cs_num; i++) {
-		gpmc_context.cs_context[i].is_valid = gpmc_cs_mem_enabled(i);
-		if (gpmc_context.cs_context[i].is_valid) {
-			gpmc_context.cs_context[i].config1 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG1);
-			gpmc_context.cs_context[i].config2 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG2);
-			gpmc_context.cs_context[i].config3 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG3);
-			gpmc_context.cs_context[i].config4 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG4);
-			gpmc_context.cs_context[i].config5 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG5);
-			gpmc_context.cs_context[i].config6 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG6);
-			gpmc_context.cs_context[i].config7 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
-		}
-	}
-}
-
-void omap3_gpmc_restore_context(void)
-{
-	int i;
-
-	gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig);
-	gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable);
-	gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl);
-	gpmc_write_reg(GPMC_CONFIG, gpmc_context.config);
-	gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1);
-	gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2);
-	gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control);
-	for (i = 0; i < gpmc_cs_num; i++) {
-		if (gpmc_context.cs_context[i].is_valid) {
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG1,
-				gpmc_context.cs_context[i].config1);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG2,
-				gpmc_context.cs_context[i].config2);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG3,
-				gpmc_context.cs_context[i].config3);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG4,
-				gpmc_context.cs_context[i].config4);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG5,
-				gpmc_context.cs_context[i].config5);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG6,
-				gpmc_context.cs_context[i].config6);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG7,
-				gpmc_context.cs_context[i].config7);
-		}
-	}
-}
diff --git a/arch/arm/mach-omap2/gpmc_legacy.c b/arch/arm/mach-omap2/gpmc_legacy.c
new file mode 100644
index 0000000..3b3f86e
--- /dev/null
+++ b/arch/arm/mach-omap2/gpmc_legacy.c
@@ -0,0 +1,296 @@
+/*
+ * GPMC support functions
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation
+ *
+ * Author: Juha Yrjola
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#include "soc.h"
+#include "gpmc.h"
+#include "omap_device.h"
+
+#define	DEVICE_NAME		"omap-gpmc"
+
+/* CS CONFIG registers */
+#define GPMC_CS_CONFIG1		0x00
+#define GPMC_CS_CONFIG2		0x04
+#define GPMC_CS_CONFIG3		0x08
+#define GPMC_CS_CONFIG4		0x0c
+#define GPMC_CS_CONFIG5		0x10
+#define GPMC_CS_CONFIG6		0x14
+#define GPMC_CS_CONFIG7		0x18
+
+#define GPMC_CS0_OFFSET		0x60
+#define GPMC_CS_SIZE		0x30
+
+/* GPMC register offsets */
+#define GPMC_SYSCONFIG		0x10
+#define GPMC_IRQENABLE		0x1c
+#define GPMC_TIMEOUT_CONTROL	0x40
+#define GPMC_CONFIG		0x50
+#define GPMC_PREFETCH_CONFIG1	0x1e0
+#define GPMC_PREFETCH_CONFIG2	0x1e4
+#define GPMC_PREFETCH_CONTROL	0x1ec
+
+#define GPMC_CONFIG7_CSVALID		(1 << 6)
+
+static struct gpmc_omap_platform_data gpmc_pdata;
+
+/* Structure to save gpmc cs context */
+struct gpmc_cs_config {
+	u32 config1;
+	u32 config2;
+	u32 config3;
+	u32 config4;
+	u32 config5;
+	u32 config6;
+	u32 config7;
+	int is_valid;
+};
+
+/*
+ * Structure to save/restore gpmc context
+ * to support core off on OMAP3
+ */
+struct omap3_gpmc_regs {
+	u32 sysconfig;
+	u32 irqenable;
+	u32 timeout_ctrl;
+	u32 config;
+	u32 prefetch_config1;
+	u32 prefetch_config2;
+	u32 prefetch_control;
+	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
+};
+
+static int __init omap_gpmc_init(void)
+{
+	struct omap_hwmod *oh;
+	struct platform_device *pdev;
+	char *oh_name = "gpmc";
+
+	/*
+	 * if the board boots up with a populated DT, do not
+	 * manually add the device from this initcall
+	 */
+	if (of_have_populated_dt())
+		return -ENODEV;
+
+	oh = omap_hwmod_lookup(oh_name);
+	if (!oh) {
+		pr_err("Could not look up %s\n", oh_name);
+		return -ENODEV;
+	}
+
+	pdev = omap_device_build(DEVICE_NAME, -1, oh, (void *)&gpmc_pdata,
+				 sizeof(gpmc_pdata));
+	WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
+
+	return PTR_RET(pdev);
+}
+/* must run after machine_init code. i.e. arch_init */
+omap_subsys_initcall(omap_gpmc_init);
+
+/**
+ * gpmc_generic_init - Initialize platform data for a Chip Select
+ *
+ * @cs		chip select number
+ * @type	GPMC_OMAP_TYPE
+ * @settings	GPMC settings
+ * @device_timings	device timings for device on this CS
+ * @gpmc_timings	GPMC timings
+ * @pdev	platform device for the device on this CS
+ * @pdata_size	platform data size for the platform device
+ */
+int gpmc_generic_init(int cs, bool is_nand,
+		      struct gpmc_settings *settings,
+		      struct gpmc_device_timings *device_timings,
+		      struct gpmc_timings *gpmc_timings,
+		      struct platform_device *pdev, unsigned pdata_size)
+{
+	struct gpmc_settings *gpmc_s = NULL;
+	struct gpmc_device_timings *gpmc_dev_t = NULL;
+	struct gpmc_timings *gpmc_t;
+
+	if (cs >= GPMC_CS_NUM) {
+		pr_err("%s: Invalid cs specified. Max CS = %d\n",
+		       __func__, GPMC_CS_NUM);
+		return -EINVAL;
+	}
+
+	if (gpmc_pdata.cs[cs].valid) {
+		pr_err("%s: cs %d already requested, ignoring new request\n",
+		       __func__, cs);
+		return -EINVAL;
+	}
+
+	if (settings) {
+		gpmc_s = kmemdup(settings, sizeof(*settings), GFP_KERNEL);
+		if (!gpmc_s)
+			return -ENOMEM;
+
+		gpmc_pdata.cs[cs].settings = gpmc_s;
+	}
+
+	if (device_timings) {
+		gpmc_dev_t = kmemdup(device_timings, sizeof(*device_timings),
+				     GFP_KERNEL);
+		if (!gpmc_dev_t)
+			goto dev_t_fail;
+
+		gpmc_pdata.cs[cs].device_timings = gpmc_dev_t;
+	}
+
+	if (gpmc_timings) {
+		gpmc_t = kmemdup(gpmc_timings, sizeof(*gpmc_timings),
+				 GFP_KERNEL);
+		if (!gpmc_t)
+			goto gpmc_t_fail;
+
+		gpmc_pdata.cs[cs].gpmc_timings = gpmc_t;
+	}
+
+	gpmc_pdata.cs[cs].is_nand = is_nand;
+	gpmc_pdata.cs[cs].pdev = pdev;
+	gpmc_pdata.cs[cs].pdata_size = pdata_size;
+	gpmc_pdata.cs[cs].valid = true;
+
+	return 0;
+
+gpmc_t_fail:
+	if (device_timings)
+		kfree(gpmc_dev_t);
+dev_t_fail:
+	if (settings)
+		kfree(gpmc_s);
+
+	return -ENOMEM;
+}
+
+
+static struct omap3_gpmc_regs gpmc_context;
+
+/*
+ * Below code only for OMAP3 OFF mode support.
+ * This code must be left back in mach-omap2.
+ */
+void __iomem *omap2_gpmc_base;
+
+void __init omap2_set_globals_gpmc(void __iomem *gpmc)
+{
+	omap2_gpmc_base = gpmc;
+}
+
+static u32 _gpmc_read_reg(u16 reg)
+{
+	return __raw_readl(omap2_gpmc_base + reg);
+}
+
+static void _gpmc_write_reg(u32 val, u16 reg)
+{
+	__raw_readl(omap2_gpmc_base + reg);
+}
+
+static u32 _gpmc_cs_read_reg(int cs, int idx)
+{
+	u16 reg;
+
+	reg = GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
+
+	return _gpmc_read_reg(reg);
+}
+
+static void _gpmc_cs_write_reg(int cs, int idx, u32 val)
+{
+	u16 reg;
+
+	reg = GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
+	_gpmc_write_reg(val, reg);
+}
+
+void omap3_gpmc_save_context(void)
+{
+	int i;
+	u32 val;
+
+	if (!omap2_gpmc_base)
+		return;
+
+	gpmc_context.sysconfig = _gpmc_read_reg(GPMC_SYSCONFIG);
+	gpmc_context.irqenable = _gpmc_read_reg(GPMC_IRQENABLE);
+	gpmc_context.timeout_ctrl = _gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
+	gpmc_context.config = _gpmc_read_reg(GPMC_CONFIG);
+	gpmc_context.prefetch_config1 = _gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
+	gpmc_context.prefetch_config2 = _gpmc_read_reg(GPMC_PREFETCH_CONFIG2);
+	gpmc_context.prefetch_control = _gpmc_read_reg(GPMC_PREFETCH_CONTROL);
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		/* check if valid */
+		val = _gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
+		gpmc_context.cs_context[i].is_valid =
+						val & GPMC_CONFIG7_CSVALID;
+
+		if (gpmc_context.cs_context[i].is_valid) {
+			gpmc_context.cs_context[i].config1 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG1);
+			gpmc_context.cs_context[i].config2 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG2);
+			gpmc_context.cs_context[i].config3 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG3);
+			gpmc_context.cs_context[i].config4 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG4);
+			gpmc_context.cs_context[i].config5 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG5);
+			gpmc_context.cs_context[i].config6 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG6);
+			gpmc_context.cs_context[i].config7 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
+		}
+	}
+}
+
+void omap3_gpmc_restore_context(void)
+{
+	int i;
+
+	if (!omap2_gpmc_base)
+		return;
+
+	_gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig);
+	_gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable);
+	_gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl);
+	_gpmc_write_reg(GPMC_CONFIG, gpmc_context.config);
+	_gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1);
+	_gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2);
+	_gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control);
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		if (gpmc_context.cs_context[i].is_valid) {
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG1,
+					   gpmc_context.cs_context[i].config1);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG2,
+					   gpmc_context.cs_context[i].config2);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG3,
+					   gpmc_context.cs_context[i].config3);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG4,
+					   gpmc_context.cs_context[i].config4);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG5,
+					   gpmc_context.cs_context[i].config5);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG6,
+					   gpmc_context.cs_context[i].config6);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG7,
+					   gpmc_context.cs_context[i].config7);
+		}
+	}
+}
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index c59e9c9..ce611b0 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -31,6 +31,16 @@ config TI_EMIF
 	  parameters and other settings during frequency, voltage and
 	  temperature changes
 
+config TI_GPMC
+	bool "Texas Instruments GPMC driver"
+	depends on ARCH_OMAP2PLUS
+	default y
+	help
+	 This driver is for the General Purpose Memory Controller (GPMC)
+	 present on Texas Instruments SoCs (e.g. OMAP2+). GPMC allows
+	 interfacing to a variety of asynchronous as well as synchronous
+	 memory drives like NOR, NAND, OneNAND, SRAM.
+
 config MVEBU_DEVBUS
 	bool "Marvell EBU Device Bus Controller"
 	default y
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index 71160a2..329b7b6 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_OF)		+= of_memory.o
 endif
 obj-$(CONFIG_TI_AEMIF)		+= ti-aemif.o
 obj-$(CONFIG_TI_EMIF)		+= emif.o
+obj-$(CONFIG_TI_GPMC)		+= ti-gpmc.o
 obj-$(CONFIG_FSL_IFC)		+= fsl_ifc.o
 obj-$(CONFIG_MVEBU_DEVBUS)	+= mvebu-devbus.o
 obj-$(CONFIG_TEGRA20_MC)	+= tegra20-mc.o
diff --git a/drivers/memory/ti-gpmc.c b/drivers/memory/ti-gpmc.c
new file mode 100644
index 0000000..3bb2fd6
--- /dev/null
+++ b/drivers/memory/ti-gpmc.c
@@ -0,0 +1,1829 @@
+/*
+ * GPMC support functions
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation
+ *
+ * Author: Juha Yrjola
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.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.
+ */
+#undef DEBUG
+
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_mtd.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+
+#include <linux/platform_data/mtd-nand-omap2.h>
+#include <linux/platform_data/gpmc-omap.h>
+
+#define	DEVICE_NAME		"omap-gpmc"
+
+/* GPMC register offsets */
+#define GPMC_REVISION		0x00
+#define GPMC_SYSCONFIG		0x10
+#define GPMC_SYSSTATUS		0x14
+#define GPMC_IRQSTATUS		0x18
+#define GPMC_IRQENABLE		0x1c
+#define GPMC_TIMEOUT_CONTROL	0x40
+#define GPMC_ERR_ADDRESS	0x44
+#define GPMC_ERR_TYPE		0x48
+#define GPMC_CONFIG		0x50
+#define GPMC_STATUS		0x54
+#define GPMC_PREFETCH_CONFIG1	0x1e0
+#define GPMC_PREFETCH_CONFIG2	0x1e4
+#define GPMC_PREFETCH_CONTROL	0x1ec
+#define GPMC_PREFETCH_STATUS	0x1f0
+#define GPMC_ECC_CONFIG		0x1f4
+#define GPMC_ECC_CONTROL	0x1f8
+#define GPMC_ECC_SIZE_CONFIG	0x1fc
+#define GPMC_ECC1_RESULT        0x200
+#define GPMC_ECC_BCH_RESULT_0   0x240   /* not available on OMAP2 */
+#define	GPMC_ECC_BCH_RESULT_1	0x244	/* not available on OMAP2 */
+#define	GPMC_ECC_BCH_RESULT_2	0x248	/* not available on OMAP2 */
+#define	GPMC_ECC_BCH_RESULT_3	0x24c	/* not available on OMAP2 */
+
+/* GPMC ECC control settings */
+#define GPMC_ECC_CTRL_ECCCLEAR		0x100
+#define GPMC_ECC_CTRL_ECCDISABLE	0x000
+#define GPMC_ECC_CTRL_ECCREG1		0x001
+#define GPMC_ECC_CTRL_ECCREG2		0x002
+#define GPMC_ECC_CTRL_ECCREG3		0x003
+#define GPMC_ECC_CTRL_ECCREG4		0x004
+#define GPMC_ECC_CTRL_ECCREG5		0x005
+#define GPMC_ECC_CTRL_ECCREG6		0x006
+#define GPMC_ECC_CTRL_ECCREG7		0x007
+#define GPMC_ECC_CTRL_ECCREG8		0x008
+#define GPMC_ECC_CTRL_ECCREG9		0x009
+
+/* ECC commands */
+#define GPMC_ECC_READ		0 /* Reset Hardware ECC for read */
+#define GPMC_ECC_WRITE		1 /* Reset Hardware ECC for write */
+#define GPMC_ECC_READSYN	2 /* Reset before syndrom is read back */
+
+/* CS CONFIG registers */
+#define GPMC_CS_CONFIG1		0x00
+#define GPMC_CS_CONFIG2		0x04
+#define GPMC_CS_CONFIG3		0x08
+#define GPMC_CS_CONFIG4		0x0c
+#define GPMC_CS_CONFIG5		0x10
+#define GPMC_CS_CONFIG6		0x14
+#define GPMC_CS_CONFIG7		0x18
+
+#define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
+#define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
+#define GPMC_CONFIG1_READTYPE_ASYNC     (0 << 29)
+#define GPMC_CONFIG1_READTYPE_SYNC      (1 << 29)
+#define GPMC_CONFIG1_WRITEMULTIPLE_SUPP (1 << 28)
+#define GPMC_CONFIG1_WRITETYPE_ASYNC    (0 << 27)
+#define GPMC_CONFIG1_WRITETYPE_SYNC     (1 << 27)
+#define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val & 3) << 25)
+#define GPMC_CONFIG1_PAGE_LEN(val)      ((val & 3) << 23)
+#define GPMC_CONFIG1_WAIT_READ_MON      (1 << 22)
+#define GPMC_CONFIG1_WAIT_WRITE_MON     (1 << 21)
+#define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18)
+#define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val & 3) << 16)
+#define GPMC_CONFIG1_DEVICESIZE(val)    ((val & 3) << 12)
+#define GPMC_CONFIG1_DEVICESIZE_16      GPMC_CONFIG1_DEVICESIZE(1)
+#define GPMC_CONFIG1_DEVICETYPE(val)    ((val & 3) << 10)
+#define GPMC_CONFIG1_DEVICETYPE_NOR     GPMC_CONFIG1_DEVICETYPE(0)
+#define GPMC_CONFIG1_MUXTYPE(val)       ((val & 3) << 8)
+#define GPMC_CONFIG1_TIME_PARA_GRAN     (1 << 4)
+#define GPMC_CONFIG1_FCLK_DIV(val)      (val & 3)
+#define GPMC_CONFIG1_FCLK_DIV2          (GPMC_CONFIG1_FCLK_DIV(1))
+#define GPMC_CONFIG1_FCLK_DIV3          (GPMC_CONFIG1_FCLK_DIV(2))
+#define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
+#define GPMC_CONFIG7_CSVALID		(1 << 6)
+
+#define	GPMC_CONFIG2_CSEXTRADELAY		BIT(7)
+#define	GPMC_CONFIG3_ADVEXTRADELAY		BIT(7)
+#define	GPMC_CONFIG4_OEEXTRADELAY		BIT(7)
+#define	GPMC_CONFIG4_WEEXTRADELAY		BIT(23)
+#define	GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN	BIT(6)
+#define	GPMC_CONFIG6_CYCLE2CYCLESAMECSEN	BIT(7)
+
+#define GPMC_DEVICETYPE_NOR		0
+#define GPMC_DEVICETYPE_NAND		2
+#define WR_RD_PIN_MONITORING		0x00600000
+#define GPMC_IRQ_FIFOEVENTENABLE	0x01
+#define GPMC_IRQ_COUNT_EVENT		0x02
+
+#define GPMC_CS0_OFFSET		0x60
+#define GPMC_CS_SIZE		0x30
+#define	GPMC_BCH_SIZE		0x10
+
+#define GPMC_MEM_END		0x3FFFFFFF
+
+#define GPMC_CHUNK_SHIFT	24		/* 16 MB */
+#define GPMC_SECTION_SHIFT	28		/* 128 MB */
+
+#define CS_NUM_SHIFT		24
+#define ENABLE_PREFETCH		(0x1 << 7)
+#define DMA_MPU_MODE		2
+
+#define	GPMC_REVISION_MAJOR(l)		((l >> 4) & 0xf)
+#define	GPMC_REVISION_MINOR(l)		(l & 0xf)
+
+#define	GPMC_HAS_WR_ACCESS		0x1
+#define	GPMC_HAS_WR_DATA_MUX_BUS	0x2
+#define	GPMC_HAS_MUX_AAD		0x4
+
+#define GPMC_NR_WAITPINS		4
+
+static struct resource	gpmc_mem_root;
+static struct resource	gpmc_cs_mem[GPMC_CS_NUM];
+static DEFINE_SPINLOCK(gpmc_mem_lock);
+/* Define chip-selects as reserved by default until probe completes */
+static unsigned int gpmc_cs_map = ((1 << GPMC_CS_NUM) - 1);
+static unsigned int gpmc_cs_num = GPMC_CS_NUM;
+static unsigned int gpmc_nr_waitpins;
+static struct device *gpmc_dev;
+static int gpmc_irq = -EINVAL;
+static resource_size_t phys_base, mem_size;
+static unsigned gpmc_capability;
+static void __iomem *gpmc_base;
+
+static struct clk *gpmc_l3_clk;
+
+static void gpmc_write_reg(int idx, u32 val)
+{
+	__raw_writel(val, gpmc_base + idx);
+}
+
+static u32 gpmc_read_reg(int idx)
+{
+	return __raw_readl(gpmc_base + idx);
+}
+
+static void gpmc_cs_write_reg(int cs, int idx, u32 val)
+{
+	void __iomem *reg_addr;
+
+	reg_addr = gpmc_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
+	__raw_writel(val, reg_addr);
+}
+
+static u32 gpmc_cs_read_reg(int cs, int idx)
+{
+	void __iomem *reg_addr;
+
+	reg_addr = gpmc_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
+	return __raw_readl(reg_addr);
+}
+
+/* TODO: Add support for gpmc_fck to clock framework and use it */
+static unsigned long gpmc_get_fclk_period(void)
+{
+	unsigned long rate = clk_get_rate(gpmc_l3_clk);
+
+	if (rate == 0) {
+		pr_warn("%s: gpmc_l3_clk not enabled\n", __func__);
+		return 0;
+	}
+
+	rate /= 1000;
+	rate = 1000000000 / rate;	/* In picoseconds */
+
+	return rate;
+}
+
+static unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
+{
+	unsigned long tick_ps;
+
+	/* Calculate in picosecs to yield more exact results */
+	tick_ps = gpmc_get_fclk_period();
+
+	return (time_ns * 1000 + tick_ps - 1) / tick_ps;
+}
+
+static unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
+{
+	unsigned long tick_ps;
+
+	/* Calculate in picosecs to yield more exact results */
+	tick_ps = gpmc_get_fclk_period();
+
+	return (time_ps + tick_ps - 1) / tick_ps;
+}
+
+static unsigned int gpmc_ticks_to_ps(unsigned int ticks)
+{
+	return ticks * gpmc_get_fclk_period();
+}
+
+static unsigned int gpmc_round_ps_to_ticks(unsigned int time_ps)
+{
+	unsigned long ticks = gpmc_ps_to_ticks(time_ps);
+
+	return ticks * gpmc_get_fclk_period();
+}
+
+static inline void gpmc_cs_modify_reg(int cs, int reg, u32 mask, bool value)
+{
+	u32 l;
+
+	l = gpmc_cs_read_reg(cs, reg);
+	if (value)
+		l |= mask;
+	else
+		l &= ~mask;
+	gpmc_cs_write_reg(cs, reg, l);
+}
+
+static void gpmc_cs_bool_timings(int cs, const struct gpmc_bool_timings *p)
+{
+	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG1,
+			   GPMC_CONFIG1_TIME_PARA_GRAN,
+			   p->time_para_granularity);
+	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG2,
+			   GPMC_CONFIG2_CSEXTRADELAY, p->cs_extra_delay);
+	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG3,
+			   GPMC_CONFIG3_ADVEXTRADELAY, p->adv_extra_delay);
+	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG4,
+			   GPMC_CONFIG4_OEEXTRADELAY, p->oe_extra_delay);
+	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG4,
+			   GPMC_CONFIG4_OEEXTRADELAY, p->we_extra_delay);
+	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG6,
+			   GPMC_CONFIG6_CYCLE2CYCLESAMECSEN,
+			   p->cycle2cyclesamecsen);
+	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG6,
+			   GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN,
+			   p->cycle2cyclediffcsen);
+}
+
+#ifdef DEBUG
+static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
+			       int time, const char *name)
+#else
+static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
+			       int time)
+#endif
+{
+	u32 l;
+	int ticks, mask, nr_bits;
+
+	if (time == 0)
+		ticks = 0;
+	else
+		ticks = gpmc_ns_to_ticks(time);
+	nr_bits = end_bit - st_bit + 1;
+	if (ticks >= 1 << nr_bits) {
+#ifdef DEBUG
+		pr_info("GPMC CS%d: %-10s* %3d ns, %3d ticks >= %d\n",
+			cs, name, time, ticks, 1 << nr_bits);
+#endif
+		return -1;
+	}
+
+	mask = (1 << nr_bits) - 1;
+	l = gpmc_cs_read_reg(cs, reg);
+#ifdef DEBUG
+	pr_info("GPMC CS%d: %-10s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n",
+		cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000,
+		(l >> st_bit) & mask, time);
+#endif
+	l &= ~(mask << st_bit);
+	l |= ticks << st_bit;
+	gpmc_cs_write_reg(cs, reg, l);
+
+	return 0;
+}
+
+#ifdef DEBUG
+#define GPMC_SET_ONE(reg, st, end, field) \
+	set_gpmc_timing_reg(cs, (reg), (st), (end),		\
+			t->field, #field)
+#else
+#define GPMC_SET_ONE(reg, st, end, field) \
+	set_gpmc_timing_reg(cs, (reg), (st), (end), t->field)
+#endif
+
+static int gpmc_calc_divider(unsigned int sync_clk)
+{
+	int div;
+	u32 l;
+
+	l = sync_clk + (gpmc_get_fclk_period() - 1);
+	div = l / gpmc_get_fclk_period();
+	if (div > 4)
+		return -1;
+	if (div <= 0)
+		div = 1;
+
+	return div;
+}
+
+static int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
+{
+	int div;
+	u32 l;
+
+	div = gpmc_calc_divider(t->sync_clk);
+	if (div < 0)
+		return div;
+
+	GPMC_SET_ONE(GPMC_CS_CONFIG2,  0,  3, cs_on);
+	GPMC_SET_ONE(GPMC_CS_CONFIG2,  8, 12, cs_rd_off);
+	GPMC_SET_ONE(GPMC_CS_CONFIG2, 16, 20, cs_wr_off);
+
+	GPMC_SET_ONE(GPMC_CS_CONFIG3,  0,  3, adv_on);
+	GPMC_SET_ONE(GPMC_CS_CONFIG3,  8, 12, adv_rd_off);
+	GPMC_SET_ONE(GPMC_CS_CONFIG3, 16, 20, adv_wr_off);
+
+	GPMC_SET_ONE(GPMC_CS_CONFIG4,  0,  3, oe_on);
+	GPMC_SET_ONE(GPMC_CS_CONFIG4,  8, 12, oe_off);
+	GPMC_SET_ONE(GPMC_CS_CONFIG4, 16, 19, we_on);
+	GPMC_SET_ONE(GPMC_CS_CONFIG4, 24, 28, we_off);
+
+	GPMC_SET_ONE(GPMC_CS_CONFIG5,  0,  4, rd_cycle);
+	GPMC_SET_ONE(GPMC_CS_CONFIG5,  8, 12, wr_cycle);
+	GPMC_SET_ONE(GPMC_CS_CONFIG5, 16, 20, access);
+
+	GPMC_SET_ONE(GPMC_CS_CONFIG5, 24, 27, page_burst_access);
+
+	GPMC_SET_ONE(GPMC_CS_CONFIG6, 0, 3, bus_turnaround);
+	GPMC_SET_ONE(GPMC_CS_CONFIG6, 8, 11, cycle2cycle_delay);
+
+	GPMC_SET_ONE(GPMC_CS_CONFIG1, 18, 19, wait_monitoring);
+	GPMC_SET_ONE(GPMC_CS_CONFIG1, 25, 26, clk_activation);
+
+	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
+		GPMC_SET_ONE(GPMC_CS_CONFIG6, 16, 19, wr_data_mux_bus);
+	if (gpmc_capability & GPMC_HAS_WR_ACCESS)
+		GPMC_SET_ONE(GPMC_CS_CONFIG6, 24, 28, wr_access);
+
+	/* caller is expected to have initialized CONFIG1 to cover
+	 * at least sync vs async
+	 */
+	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+	if (l & (GPMC_CONFIG1_READTYPE_SYNC | GPMC_CONFIG1_WRITETYPE_SYNC)) {
+#ifdef DEBUG
+		pr_info("GPMC CS%d CLK period is %lu ns (div %d)\n",
+			cs, (div * gpmc_get_fclk_period()) / 1000, div);
+#endif
+		l &= ~0x03;
+		l |= (div - 1);
+		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
+	}
+
+	gpmc_cs_bool_timings(cs, &t->bool_timings);
+
+	return 0;
+}
+
+static int gpmc_cs_enable_mem(int cs, u32 base, u32 size)
+{
+	u32 l;
+	u32 mask;
+
+	/*
+	 * Ensure that base address is aligned on a
+	 * boundary equal to or greater than size.
+	 */
+	if (base & (size - 1))
+		return -EINVAL;
+
+	mask = (1 << GPMC_SECTION_SHIFT) - size;
+	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+	l &= ~0x3f;
+	l = (base >> GPMC_CHUNK_SHIFT) & 0x3f;
+	l &= ~(0x0f << 8);
+	l |= ((mask >> GPMC_CHUNK_SHIFT) & 0x0f) << 8;
+	l |= GPMC_CONFIG7_CSVALID;
+	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
+
+	return 0;
+}
+
+static void gpmc_cs_disable_mem(int cs)
+{
+	u32 l;
+
+	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+	l &= ~GPMC_CONFIG7_CSVALID;
+	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
+}
+
+static void gpmc_cs_get_memconf(int cs, u32 *base, u32 *size)
+{
+	u32 l;
+	u32 mask;
+
+	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+	*base = (l & 0x3f) << GPMC_CHUNK_SHIFT;
+	mask = (l >> 8) & 0x0f;
+	*size = (1 << GPMC_SECTION_SHIFT) - (mask << GPMC_CHUNK_SHIFT);
+}
+
+static int gpmc_cs_mem_enabled(int cs)
+{
+	u32 l;
+
+	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+	return l & GPMC_CONFIG7_CSVALID;
+}
+
+static void gpmc_cs_set_reserved(int cs, int reserved)
+{
+	gpmc_cs_map &= ~(1 << cs);
+	gpmc_cs_map |= (reserved ? 1 : 0) << cs;
+}
+
+static bool gpmc_cs_reserved(int cs)
+{
+	return gpmc_cs_map & (1 << cs);
+}
+
+static unsigned long gpmc_mem_align(unsigned long size)
+{
+	int order;
+
+	size = (size - 1) >> (GPMC_CHUNK_SHIFT - 1);
+	order = GPMC_CHUNK_SHIFT - 1;
+	do {
+		size >>= 1;
+		order++;
+	} while (size);
+	size = 1 << order;
+	return size;
+}
+
+static int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size)
+{
+	struct resource	*res = &gpmc_cs_mem[cs];
+	int r;
+
+	size = gpmc_mem_align(size);
+	spin_lock(&gpmc_mem_lock);
+	res->start = base;
+	res->end = base + size - 1;
+	r = request_resource(&gpmc_mem_root, res);
+	spin_unlock(&gpmc_mem_lock);
+
+	return r;
+}
+
+static int gpmc_cs_delete_mem(int cs)
+{
+	struct resource	*res = &gpmc_cs_mem[cs];
+	int r;
+
+	spin_lock(&gpmc_mem_lock);
+	r = release_resource(res);
+	res->start = 0;
+	res->end = 0;
+	spin_unlock(&gpmc_mem_lock);
+
+	return r;
+}
+
+/**
+ * gpmc_cs_remap - remaps a chip-select physical base address
+ * @cs:		chip-select to remap
+ * @base:	physical base address to re-map chip-select to
+ *
+ * Re-maps a chip-select to a new physical base address specified by
+ * "base". Returns 0 on success and appropriate negative error code
+ * on failure.
+ */
+static int gpmc_cs_remap(int cs, u32 base)
+{
+	int ret;
+	u32 old_base, size;
+
+	if (cs > gpmc_cs_num) {
+		pr_err("%s: requested chip-select is disabled\n", __func__);
+		return -ENODEV;
+	}
+
+	/*
+	 * Make sure we ignore any device offsets from the GPMC partition
+	 * allocated for the chip select and that the new base confirms
+	 * to the GPMC 16MB minimum granularity.
+	 */
+	base &= ~(SZ_16M - 1);
+
+	gpmc_cs_get_memconf(cs, &old_base, &size);
+	if (base == old_base)
+		return 0;
+	gpmc_cs_disable_mem(cs);
+	ret = gpmc_cs_delete_mem(cs);
+	if (ret < 0)
+		return ret;
+	ret = gpmc_cs_insert_mem(cs, base, size);
+	if (ret < 0)
+		return ret;
+	ret = gpmc_cs_enable_mem(cs, base, size);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
+{
+	struct resource *res = &gpmc_cs_mem[cs];
+	int r = -1;
+
+	if (cs > gpmc_cs_num) {
+		pr_err("%s: requested chip-select is disabled\n", __func__);
+		return -ENODEV;
+	}
+	size = gpmc_mem_align(size);
+	if (size > (1 << GPMC_SECTION_SHIFT))
+		return -ENOMEM;
+
+	spin_lock(&gpmc_mem_lock);
+	if (gpmc_cs_reserved(cs)) {
+		r = -EBUSY;
+		goto out;
+	}
+	if (gpmc_cs_mem_enabled(cs))
+		r = adjust_resource(res, res->start & ~(size - 1), size);
+	if (r < 0)
+		r = allocate_resource(&gpmc_mem_root, res, size, 0, ~0,
+				      size, NULL, NULL);
+	if (r < 0)
+		goto out;
+
+	r = gpmc_cs_enable_mem(cs, res->start, resource_size(res));
+	if (r < 0) {
+		release_resource(res);
+		goto out;
+	}
+
+	*base = res->start;
+	gpmc_cs_set_reserved(cs, 1);
+out:
+	spin_unlock(&gpmc_mem_lock);
+	return r;
+}
+
+static void gpmc_cs_free(int cs)
+{
+	struct resource	*res = &gpmc_cs_mem[cs];
+
+	spin_lock(&gpmc_mem_lock);
+	if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) {
+		pr_err("Trying to free non-reserved GPMC CS%d\n", cs);
+		BUG();
+		spin_unlock(&gpmc_mem_lock);
+		return;
+	}
+	gpmc_cs_disable_mem(cs);
+	if (res->flags)
+		release_resource(res);
+	gpmc_cs_set_reserved(cs, 0);
+	spin_unlock(&gpmc_mem_lock);
+}
+
+static void gpmc_mem_exit(void)
+{
+	int cs;
+
+	for (cs = 0; cs < gpmc_cs_num; cs++) {
+		if (!gpmc_cs_mem_enabled(cs))
+			continue;
+		gpmc_cs_delete_mem(cs);
+	}
+}
+
+static void gpmc_mem_init(void)
+{
+	int cs;
+
+	/*
+	 * The first 1MB of GPMC address space is typically mapped to
+	 * the internal ROM. Never allocate the first page, to
+	 * facilitate bug detection; even if we didn't boot from ROM.
+	 */
+	gpmc_mem_root.start = SZ_1M;
+	gpmc_mem_root.end = GPMC_MEM_END;
+
+	/* Reserve all regions that has been set up by bootloader */
+	for (cs = 0; cs < gpmc_cs_num; cs++) {
+		u32 base, size;
+
+		if (!gpmc_cs_mem_enabled(cs))
+			continue;
+		gpmc_cs_get_memconf(cs, &base, &size);
+		if (gpmc_cs_insert_mem(cs, base, size)) {
+			pr_warn("%s: disabling cs %d mapped at 0x%x-0x%x\n",
+				__func__, cs, base, base + size);
+			gpmc_cs_disable_mem(cs);
+		}
+	}
+}
+
+static u32 gpmc_round_ps_to_sync_clk(u32 time_ps, u32 sync_clk)
+{
+	u32 temp;
+	int div;
+
+	div = gpmc_calc_divider(sync_clk);
+	temp = gpmc_ps_to_ticks(time_ps);
+	temp = (temp + div - 1) / div;
+	return gpmc_ticks_to_ps(temp * div);
+}
+
+/* XXX: can the cycles be avoided ? */
+static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t,
+				       struct gpmc_device_timings *dev_t,
+				       bool mux)
+{
+	u32 temp;
+
+	/* adv_rd_off */
+	temp = dev_t->t_avdp_r;
+	/* XXX: mux check required ? */
+	if (mux) {
+		/* XXX: t_avdp not to be required for sync, only added for tusb
+		 * this indirectly necessitates requirement of t_avdp_r and
+		 * t_avdp_w instead of having a single t_avdp
+		 */
+		temp = max_t(u32, temp,	gpmc_t->clk_activation + dev_t->t_avdh);
+		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
+	}
+	gpmc_t->adv_rd_off = gpmc_round_ps_to_ticks(temp);
+
+	/* oe_on */
+	temp = dev_t->t_oeasu; /* XXX: remove this ? */
+	if (mux) {
+		temp = max_t(u32, temp,	gpmc_t->clk_activation + dev_t->t_ach);
+		temp = max_t(u32, temp, gpmc_t->adv_rd_off +
+			     gpmc_ticks_to_ps(dev_t->cyc_aavdh_oe));
+	}
+	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
+
+	/* access */
+	/* XXX: any scope for improvement ?, by combining oe_on
+	 * and clk_activation, need to check whether
+	 * access = clk_activation + round to sync clk ?
+	 */
+	temp = max_t(u32, dev_t->t_iaa,	dev_t->cyc_iaa * gpmc_t->sync_clk);
+	temp += gpmc_t->clk_activation;
+	if (dev_t->cyc_oe)
+		temp = max_t(u32, temp, gpmc_t->oe_on +
+			     gpmc_ticks_to_ps(dev_t->cyc_oe));
+	gpmc_t->access = gpmc_round_ps_to_ticks(temp);
+
+	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ps(1);
+	gpmc_t->cs_rd_off = gpmc_t->oe_off;
+
+	/* rd_cycle */
+	temp = max_t(u32, dev_t->t_cez_r, dev_t->t_oez);
+	temp = gpmc_round_ps_to_sync_clk(temp, gpmc_t->sync_clk) +
+					 gpmc_t->access;
+	/* XXX: barter t_ce_rdyz with t_cez_r ? */
+	if (dev_t->t_ce_rdyz)
+		temp = max_t(u32, temp,	gpmc_t->cs_rd_off + dev_t->t_ce_rdyz);
+	gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp);
+
+	return 0;
+}
+
+static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t,
+					struct gpmc_device_timings *dev_t,
+					bool mux)
+{
+	u32 temp;
+
+	/* adv_wr_off */
+	temp = dev_t->t_avdp_w;
+	if (mux) {
+		temp = max_t(u32, temp,
+			     gpmc_t->clk_activation + dev_t->t_avdh);
+		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
+	}
+	gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp);
+
+	/* wr_data_mux_bus */
+	temp = max_t(u32, dev_t->t_weasu,
+		     gpmc_t->clk_activation + dev_t->t_rdyo);
+	/* XXX: shouldn't mux be kept as a whole for wr_data_mux_bus ?,
+	 * and in that case remember to handle we_on properly
+	 */
+	if (mux) {
+		temp = max_t(u32, temp,
+			     gpmc_t->adv_wr_off + dev_t->t_aavdh);
+		temp = max_t(u32, temp, gpmc_t->adv_wr_off +
+			     gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
+	}
+	gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp);
+
+	/* we_on */
+	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
+		gpmc_t->we_on = gpmc_round_ps_to_ticks(dev_t->t_weasu);
+	else
+		gpmc_t->we_on = gpmc_t->wr_data_mux_bus;
+
+	/* wr_access */
+	/* XXX: gpmc_capability check reqd ? , even if not, will not harm */
+	gpmc_t->wr_access = gpmc_t->access;
+
+	/* we_off */
+	temp = gpmc_t->we_on + dev_t->t_wpl;
+	temp = max_t(u32, temp,
+		     gpmc_t->wr_access + gpmc_ticks_to_ps(1));
+	temp = max_t(u32, temp,
+		     gpmc_t->we_on + gpmc_ticks_to_ps(dev_t->cyc_wpl));
+	gpmc_t->we_off = gpmc_round_ps_to_ticks(temp);
+
+	gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off +
+						   dev_t->t_wph);
+
+	/* wr_cycle */
+	temp = gpmc_round_ps_to_sync_clk(dev_t->t_cez_w, gpmc_t->sync_clk);
+	temp += gpmc_t->wr_access;
+	/* XXX: barter t_ce_rdyz with t_cez_w ? */
+	if (dev_t->t_ce_rdyz)
+		temp = max_t(u32, temp,
+			     gpmc_t->cs_wr_off + dev_t->t_ce_rdyz);
+	gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp);
+
+	return 0;
+}
+
+static int gpmc_calc_async_read_timings(struct gpmc_timings *gpmc_t,
+					struct gpmc_device_timings *dev_t,
+					bool mux)
+{
+	u32 temp;
+
+	/* adv_rd_off */
+	temp = dev_t->t_avdp_r;
+	if (mux)
+		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
+	gpmc_t->adv_rd_off = gpmc_round_ps_to_ticks(temp);
+
+	/* oe_on */
+	temp = dev_t->t_oeasu;
+	if (mux)
+		temp = max_t(u32, temp,
+			     gpmc_t->adv_rd_off + dev_t->t_aavdh);
+	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
+
+	/* access */
+	temp = max_t(u32, dev_t->t_iaa, /* XXX: remove t_iaa in async ? */
+		     gpmc_t->oe_on + dev_t->t_oe);
+	temp = max_t(u32, temp,
+		     gpmc_t->cs_on + dev_t->t_ce);
+	temp = max_t(u32, temp,
+		     gpmc_t->adv_on + dev_t->t_aa);
+	gpmc_t->access = gpmc_round_ps_to_ticks(temp);
+
+	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ps(1);
+	gpmc_t->cs_rd_off = gpmc_t->oe_off;
+
+	/* rd_cycle */
+	temp = max_t(u32, dev_t->t_rd_cycle,
+		     gpmc_t->cs_rd_off + dev_t->t_cez_r);
+	temp = max_t(u32, temp, gpmc_t->oe_off + dev_t->t_oez);
+	gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp);
+
+	return 0;
+}
+
+static int gpmc_calc_async_write_timings(struct gpmc_timings *gpmc_t,
+					 struct gpmc_device_timings *dev_t,
+					 bool mux)
+{
+	u32 temp;
+
+	/* adv_wr_off */
+	temp = dev_t->t_avdp_w;
+	if (mux)
+		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
+	gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp);
+
+	/* wr_data_mux_bus */
+	temp = dev_t->t_weasu;
+	if (mux) {
+		temp = max_t(u32, temp,	gpmc_t->adv_wr_off + dev_t->t_aavdh);
+		temp = max_t(u32, temp, gpmc_t->adv_wr_off +
+			     gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
+	}
+	gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp);
+
+	/* we_on */
+	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
+		gpmc_t->we_on = gpmc_round_ps_to_ticks(dev_t->t_weasu);
+	else
+		gpmc_t->we_on = gpmc_t->wr_data_mux_bus;
+
+	/* we_off */
+	temp = gpmc_t->we_on + dev_t->t_wpl;
+	gpmc_t->we_off = gpmc_round_ps_to_ticks(temp);
+
+	gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off +
+						   dev_t->t_wph);
+
+	/* wr_cycle */
+	temp = max_t(u32, dev_t->t_wr_cycle,
+		     gpmc_t->cs_wr_off + dev_t->t_cez_w);
+	gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp);
+
+	return 0;
+}
+
+static int gpmc_calc_sync_common_timings(struct gpmc_timings *gpmc_t,
+					 struct gpmc_device_timings *dev_t)
+{
+	u32 temp;
+
+	gpmc_t->sync_clk = gpmc_calc_divider(dev_t->clk) *
+					     gpmc_get_fclk_period();
+
+	gpmc_t->page_burst_access = gpmc_round_ps_to_sync_clk(dev_t->t_bacc,
+							      gpmc_t->sync_clk);
+
+	temp = max_t(u32, dev_t->t_ces, dev_t->t_avds);
+	gpmc_t->clk_activation = gpmc_round_ps_to_ticks(temp);
+
+	if (gpmc_calc_divider(gpmc_t->sync_clk) != 1)
+		return 0;
+
+	if (dev_t->ce_xdelay)
+		gpmc_t->bool_timings.cs_extra_delay = true;
+	if (dev_t->avd_xdelay)
+		gpmc_t->bool_timings.adv_extra_delay = true;
+	if (dev_t->oe_xdelay)
+		gpmc_t->bool_timings.oe_extra_delay = true;
+	if (dev_t->we_xdelay)
+		gpmc_t->bool_timings.we_extra_delay = true;
+
+	return 0;
+}
+
+static int gpmc_calc_common_timings(struct gpmc_timings *gpmc_t,
+				    struct gpmc_device_timings *dev_t,
+				    bool sync)
+{
+	u32 temp;
+
+	/* cs_on */
+	gpmc_t->cs_on = gpmc_round_ps_to_ticks(dev_t->t_ceasu);
+
+	/* adv_on */
+	temp = dev_t->t_avdasu;
+	if (dev_t->t_ce_avd)
+		temp = max_t(u32, temp,
+			     gpmc_t->cs_on + dev_t->t_ce_avd);
+	gpmc_t->adv_on = gpmc_round_ps_to_ticks(temp);
+
+	if (sync)
+		gpmc_calc_sync_common_timings(gpmc_t, dev_t);
+
+	return 0;
+}
+
+/* TODO: remove this function once all peripherals are confirmed to
+ * work with generic timing. Simultaneously gpmc_cs_set_timings()
+ * has to be modified to handle timings in ps instead of ns
+*/
+static void gpmc_convert_ps_to_ns(struct gpmc_timings *t)
+{
+	t->cs_on /= 1000;
+	t->cs_rd_off /= 1000;
+	t->cs_wr_off /= 1000;
+	t->adv_on /= 1000;
+	t->adv_rd_off /= 1000;
+	t->adv_wr_off /= 1000;
+	t->we_on /= 1000;
+	t->we_off /= 1000;
+	t->oe_on /= 1000;
+	t->oe_off /= 1000;
+	t->page_burst_access /= 1000;
+	t->access /= 1000;
+	t->rd_cycle /= 1000;
+	t->wr_cycle /= 1000;
+	t->bus_turnaround /= 1000;
+	t->cycle2cycle_delay /= 1000;
+	t->wait_monitoring /= 1000;
+	t->clk_activation /= 1000;
+	t->wr_access /= 1000;
+	t->wr_data_mux_bus /= 1000;
+}
+
+static int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
+			     struct gpmc_settings *gpmc_s,
+			     struct gpmc_device_timings *dev_t)
+{
+	bool mux = false, sync = false;
+
+	if (gpmc_s) {
+		mux = gpmc_s->mux_add_data ? true : false;
+		sync = (gpmc_s->sync_read || gpmc_s->sync_write);
+	}
+
+	memset(gpmc_t, 0, sizeof(*gpmc_t));
+
+	gpmc_calc_common_timings(gpmc_t, dev_t, sync);
+
+	if (gpmc_s && gpmc_s->sync_read)
+		gpmc_calc_sync_read_timings(gpmc_t, dev_t, mux);
+	else
+		gpmc_calc_async_read_timings(gpmc_t, dev_t, mux);
+
+	if (gpmc_s && gpmc_s->sync_write)
+		gpmc_calc_sync_write_timings(gpmc_t, dev_t, mux);
+	else
+		gpmc_calc_async_write_timings(gpmc_t, dev_t, mux);
+
+	/* TODO: remove, see function definition */
+	gpmc_convert_ps_to_ns(gpmc_t);
+
+	return 0;
+}
+
+/**
+ * gpmc_cs_program_settings - programs non-timing related settings
+ * @cs:		GPMC chip-select to program
+ * @p:		pointer to GPMC settings structure
+ *
+ * Programs non-timing related settings for a GPMC chip-select, such as
+ * bus-width, burst configuration, etc. Function should be called once
+ * for each chip-select that is being used and must be called before
+ * calling gpmc_cs_set_timings() as timing parameters in the CONFIG1
+ * register will be initialised to zero by this function. Returns 0 on
+ * success and appropriate negative error code on failure.
+ */
+static int gpmc_cs_program_settings(int cs, struct gpmc_settings *p)
+{
+	u32 config1;
+
+	if ((!p->device_width) || (p->device_width > GPMC_DEVWIDTH_16BIT)) {
+		pr_err("%s: invalid width %d!", __func__, p->device_width);
+		return -EINVAL;
+	}
+
+	/* Address-data multiplexing not supported for NAND devices */
+	if (p->device_nand && p->mux_add_data) {
+		pr_err("%s: invalid configuration!\n", __func__);
+		return -EINVAL;
+	}
+
+	if ((p->mux_add_data > GPMC_MUX_AD) ||
+	    ((p->mux_add_data == GPMC_MUX_AAD) &&
+	     !(gpmc_capability & GPMC_HAS_MUX_AAD))) {
+		pr_err("%s: invalid multiplex configuration!\n", __func__);
+		return -EINVAL;
+	}
+
+	/* Page/burst mode supports lengths of 4, 8 and 16 bytes */
+	if (p->burst_read || p->burst_write) {
+		switch (p->burst_len) {
+		case GPMC_BURST_4:
+		case GPMC_BURST_8:
+		case GPMC_BURST_16:
+			break;
+		default:
+			pr_err("%s: invalid page/burst-length (%d)\n",
+			       __func__, p->burst_len);
+			return -EINVAL;
+		}
+	}
+
+	if ((p->wait_on_read || p->wait_on_write) &&
+	    (p->wait_pin > gpmc_nr_waitpins)) {
+		pr_err("%s: invalid wait-pin (%d)\n", __func__, p->wait_pin);
+		return -EINVAL;
+	}
+
+	config1 = GPMC_CONFIG1_DEVICESIZE((p->device_width - 1));
+
+	if (p->sync_read)
+		config1 |= GPMC_CONFIG1_READTYPE_SYNC;
+	if (p->sync_write)
+		config1 |= GPMC_CONFIG1_WRITETYPE_SYNC;
+	if (p->wait_on_read)
+		config1 |= GPMC_CONFIG1_WAIT_READ_MON;
+	if (p->wait_on_write)
+		config1 |= GPMC_CONFIG1_WAIT_WRITE_MON;
+	if (p->wait_on_read || p->wait_on_write)
+		config1 |= GPMC_CONFIG1_WAIT_PIN_SEL(p->wait_pin);
+	if (p->device_nand)
+		config1	|= GPMC_CONFIG1_DEVICETYPE(GPMC_DEVICETYPE_NAND);
+	if (p->mux_add_data)
+		config1	|= GPMC_CONFIG1_MUXTYPE(p->mux_add_data);
+	if (p->burst_read)
+		config1 |= GPMC_CONFIG1_READMULTIPLE_SUPP;
+	if (p->burst_write)
+		config1 |= GPMC_CONFIG1_WRITEMULTIPLE_SUPP;
+	if (p->burst_read || p->burst_write) {
+		config1 |= GPMC_CONFIG1_PAGE_LEN(p->burst_len >> 3);
+		config1 |= p->burst_wrap ? GPMC_CONFIG1_WRAPBURST_SUPP : 0;
+	}
+
+	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, config1);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id gpmc_dt_ids[] = {
+	{ .compatible = "ti,omap2420-gpmc" },
+	{ .compatible = "ti,omap2430-gpmc" },
+	{ .compatible = "ti,omap3430-gpmc" },	/* omap3430 & omap3630 */
+	{ .compatible = "ti,omap4430-gpmc" },	/* omap4 & omap543x */
+	{ .compatible = "ti,am3352-gpmc" },	/* am335x devices */
+	{ }
+};
+MODULE_DEVICE_TABLE(of, gpmc_dt_ids);
+
+/**
+ * gpmc_read_settings_dt - read gpmc settings from device-tree
+ * @np:		pointer to device-tree node for a gpmc child device
+ * @p:		pointer to gpmc settings structure
+ *
+ * Reads the GPMC settings for a GPMC child device from device-tree and
+ * stores them in the GPMC settings structure passed. The GPMC settings
+ * structure is initialised to zero by this function and so any
+ * previously stored settings will be cleared.
+ */
+static void gpmc_read_settings_dt(struct device_node *np,
+				  struct gpmc_settings *p)
+{
+	memset(p, 0, sizeof(struct gpmc_settings));
+
+	p->sync_read = of_property_read_bool(np, "gpmc,sync-read");
+	p->sync_write = of_property_read_bool(np, "gpmc,sync-write");
+	of_property_read_u32(np, "gpmc,device-width", &p->device_width);
+	of_property_read_u32(np, "gpmc,mux-add-data", &p->mux_add_data);
+
+	if (!of_property_read_u32(np, "gpmc,burst-length", &p->burst_len)) {
+		p->burst_wrap = of_property_read_bool(np, "gpmc,burst-wrap");
+		p->burst_read = of_property_read_bool(np, "gpmc,burst-read");
+		p->burst_write = of_property_read_bool(np, "gpmc,burst-write");
+		if (!p->burst_read && !p->burst_write)
+			pr_warn("%s: page/burst-length set but not used!\n",
+				__func__);
+	}
+
+	if (!of_property_read_u32(np, "gpmc,wait-pin", &p->wait_pin)) {
+		p->wait_on_read = of_property_read_bool(np,
+							"gpmc,wait-on-read");
+		p->wait_on_write = of_property_read_bool(np,
+							 "gpmc,wait-on-write");
+		if (!p->wait_on_read && !p->wait_on_write)
+			pr_warn("%s: read/write wait monitoring not enabled!\n",
+				__func__);
+	}
+}
+
+static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
+						struct gpmc_timings *gpmc_t)
+{
+	struct gpmc_bool_timings *p;
+
+	if (!np || !gpmc_t)
+		return;
+
+	memset(gpmc_t, 0, sizeof(*gpmc_t));
+
+	/* minimum clock period for syncronous mode */
+	of_property_read_u32(np, "gpmc,sync-clk-ps", &gpmc_t->sync_clk);
+
+	/* chip select timtings */
+	of_property_read_u32(np, "gpmc,cs-on-ns", &gpmc_t->cs_on);
+	of_property_read_u32(np, "gpmc,cs-rd-off-ns", &gpmc_t->cs_rd_off);
+	of_property_read_u32(np, "gpmc,cs-wr-off-ns", &gpmc_t->cs_wr_off);
+
+	/* ADV signal timings */
+	of_property_read_u32(np, "gpmc,adv-on-ns", &gpmc_t->adv_on);
+	of_property_read_u32(np, "gpmc,adv-rd-off-ns", &gpmc_t->adv_rd_off);
+	of_property_read_u32(np, "gpmc,adv-wr-off-ns", &gpmc_t->adv_wr_off);
+
+	/* WE signal timings */
+	of_property_read_u32(np, "gpmc,we-on-ns", &gpmc_t->we_on);
+	of_property_read_u32(np, "gpmc,we-off-ns", &gpmc_t->we_off);
+
+	/* OE signal timings */
+	of_property_read_u32(np, "gpmc,oe-on-ns", &gpmc_t->oe_on);
+	of_property_read_u32(np, "gpmc,oe-off-ns", &gpmc_t->oe_off);
+
+	/* access and cycle timings */
+	of_property_read_u32(np, "gpmc,page-burst-access-ns",
+			     &gpmc_t->page_burst_access);
+	of_property_read_u32(np, "gpmc,access-ns", &gpmc_t->access);
+	of_property_read_u32(np, "gpmc,rd-cycle-ns", &gpmc_t->rd_cycle);
+	of_property_read_u32(np, "gpmc,wr-cycle-ns", &gpmc_t->wr_cycle);
+	of_property_read_u32(np, "gpmc,bus-turnaround-ns",
+			     &gpmc_t->bus_turnaround);
+	of_property_read_u32(np, "gpmc,cycle2cycle-delay-ns",
+			     &gpmc_t->cycle2cycle_delay);
+	of_property_read_u32(np, "gpmc,wait-monitoring-ns",
+			     &gpmc_t->wait_monitoring);
+	of_property_read_u32(np, "gpmc,clk-activation-ns",
+			     &gpmc_t->clk_activation);
+
+	/* only applicable to OMAP3+ */
+	of_property_read_u32(np, "gpmc,wr-access-ns", &gpmc_t->wr_access);
+	of_property_read_u32(np, "gpmc,wr-data-mux-bus-ns",
+			     &gpmc_t->wr_data_mux_bus);
+
+	/* bool timing parameters */
+	p = &gpmc_t->bool_timings;
+
+	p->cycle2cyclediffcsen =
+		of_property_read_bool(np, "gpmc,cycle2cycle-diffcsen");
+	p->cycle2cyclesamecsen =
+		of_property_read_bool(np, "gpmc,cycle2cycle-samecsen");
+	p->we_extra_delay = of_property_read_bool(np, "gpmc,we-extra-delay");
+	p->oe_extra_delay = of_property_read_bool(np, "gpmc,oe-extra-delay");
+	p->adv_extra_delay = of_property_read_bool(np, "gpmc,adv-extra-delay");
+	p->cs_extra_delay = of_property_read_bool(np, "gpmc,cs-extra-delay");
+	p->time_para_granularity =
+		of_property_read_bool(np, "gpmc,time-para-granularity");
+}
+
+/**
+ * gpmc_probe_generic_child - configures the gpmc for a child device
+ * @pdev:	pointer to gpmc platform device
+ * @child:	pointer to device-tree node for child device
+ *
+ * Allocates and configures a GPMC chip-select for a child device.
+ * Returns 0 on success and appropriate negative error code on failure.
+ */
+static int gpmc_probe_generic_child(struct platform_device *pdev,
+				    struct device_node *child)
+{
+	struct gpmc_settings gpmc_s;
+	struct gpmc_timings gpmc_t;
+	struct resource res;
+	unsigned long base;
+	int ret, cs;
+	struct device *dev = &pdev->dev;
+
+	if (of_property_read_u32(child, "reg", &cs) < 0) {
+		dev_err(&pdev->dev, "%s has no 'reg' property\n",
+			child->full_name);
+		return -ENODEV;
+	}
+
+	if (of_address_to_resource(child, 0, &res) < 0) {
+		dev_err(&pdev->dev, "%s has malformed 'reg' property\n",
+			child->full_name);
+		return -ENODEV;
+	}
+
+	ret = gpmc_cs_request(cs, resource_size(&res), &base);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "cannot request GPMC CS %d\n", cs);
+		return ret;
+	}
+
+	/*
+	 * For some GPMC devices we still need to rely on the bootloader
+	 * timings because the devices can be connected via FPGA. So far
+	 * the list is smc91x on the omap2 SDP boards, and 8250 on zooms.
+	 * REVISIT: Add timing support from slls644g.pdf and from the
+	 * lan91c96 manual.
+	 */
+	if (of_device_is_compatible(child, "ns16550a") ||
+	    of_device_is_compatible(child, "smsc,lan91c94") ||
+	    of_device_is_compatible(child, "smsc,lan91c111")) {
+		dev_warn(&pdev->dev,
+			 "%s using bootloader timings on CS%d\n",
+			 child->name, cs);
+		goto no_timings;
+	}
+
+	/*
+	 * FIXME: gpmc_cs_request() will map the CS to an arbitary
+	 * location in the gpmc address space. When booting with
+	 * device-tree we want the NOR flash to be mapped to the
+	 * location specified in the device-tree blob. So remap the
+	 * CS to this location. Once DT migration is complete should
+	 * just make gpmc_cs_request() map a specific address.
+	 */
+	ret = gpmc_cs_remap(cs, res.start);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "cannot remap GPMC CS %d to %pa\n",
+			cs, &res.start);
+		goto err;
+	}
+
+	gpmc_read_settings_dt(child, &gpmc_s);
+
+	if (of_node_cmp(child->name, "nand") == 0) {
+		/* NAND specific setup */
+		u32 val;
+
+		val = of_get_nand_bus_width(child);
+		switch (val) {
+		case 8:
+			gpmc_s.device_width = GPMC_DEVWIDTH_8BIT;
+			break;
+		case 16:
+			gpmc_s.device_width = GPMC_DEVWIDTH_16BIT;
+			break;
+		default:
+			dev_err(dev, "%s: invalid 'nand-bus-width'\n",
+				child->name);
+			ret = -EINVAL;
+			goto err;
+		}
+
+		gpmc_s.device_nand = true;
+
+	} else if (of_node_cmp(child->name, "onenand") == 0) {
+		/* DT incorrectly sets sync modes, onenand default is async */
+		gpmc_s.sync_read = false;
+		gpmc_s.sync_write = false;
+
+	} else {
+		if (of_property_read_u32(child, "bank-width",
+					 &gpmc_s.device_width)) {
+			dev_err(dev, "%s: no 'bank-width' property\n",
+				child->name);
+			goto err;
+		}
+
+		if (gpmc_s.device_width < 1 || gpmc_s.device_width > 2) {
+			dev_err(dev, "%s: invalid 'bank-width'\n",
+				child->name);
+			goto err;
+		}
+	}
+
+	ret = gpmc_cs_program_settings(cs, &gpmc_s);
+	if (ret < 0)
+		goto err;
+
+	gpmc_read_timings_dt(child, &gpmc_t);
+	gpmc_cs_set_timings(cs, &gpmc_t);
+
+no_timings:
+	if (of_platform_device_create(child, NULL, &pdev->dev))
+		return 0;
+
+	dev_err(&pdev->dev, "failed to create gpmc child %s\n", child->name);
+	ret = -ENODEV;
+
+err:
+	gpmc_cs_free(cs);
+
+	return ret;
+}
+
+static int gpmc_probe_dt(struct platform_device *pdev)
+{
+	int ret;
+	struct device_node *child;
+
+	ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-cs",
+				   &gpmc_cs_num);
+	if (ret < 0) {
+		pr_err("%s: number of chip-selects not defined\n", __func__);
+		return ret;
+	} else if (gpmc_cs_num < 1) {
+		pr_err("%s: all chip-selects are disabled\n", __func__);
+		return -EINVAL;
+	} else if (gpmc_cs_num > GPMC_CS_NUM) {
+		pr_err("%s: number of supported chip-selects cannot be > %d\n",
+		       __func__, GPMC_CS_NUM);
+		return -EINVAL;
+	}
+
+	ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-waitpins",
+				   &gpmc_nr_waitpins);
+	if (ret < 0) {
+		pr_err("%s: number of wait pins not found!\n", __func__);
+		return ret;
+	}
+
+	for_each_child_of_node(pdev->dev.of_node, child) {
+		if (!child->name)
+			continue;
+
+		if (of_node_cmp(child->name, "ethernet") == 0 ||
+		    of_node_cmp(child->name, "nor") == 0 ||
+		    of_node_cmp(child->name, "uart") == 0 ||
+		    of_node_cmp(child->name, "nand") == 0 ||
+		    of_node_cmp(child->name, "onenand") == 0)
+			ret = gpmc_probe_generic_child(pdev, child);
+
+		if (WARN(ret < 0, "%s: probing gpmc child %s failed\n",
+			 __func__, child->full_name))
+			of_node_put(child);
+	}
+
+	return 0;
+}
+#else
+static int gpmc_probe_dt(struct platform_device *pdev)
+{
+	return 0;
+}
+#endif
+
+static int gpmc_nand_setup(struct platform_device *parent_pdev,
+			   struct gpmc_omap_cs_data *cs)
+{
+	struct resource *res;
+	struct resource *res_gpmc;
+
+	if (!cs->pdev)
+		return -EINVAL;
+
+	res = cs->pdev->resource;
+
+	if (cs->pdev->num_resources < 3)
+		return -EINVAL;
+
+	if (resource_type(&res[1]) != IORESOURCE_MEM ||
+	    resource_type(&res[2]) != IORESOURCE_IRQ)
+		return -EINVAL;
+
+	if (!cs->settings)
+		return -EINVAL;
+
+	/* GPMC register space */
+	res_gpmc = platform_get_resource(parent_pdev, IORESOURCE_MEM, 0);
+	if (!res_gpmc)
+		return -EINVAL;
+
+	res[1] = *res_gpmc;
+
+	/* setup IRQ resources */
+	res[2].start = gpmc_irq;
+
+	cs->settings->device_nand = true;
+
+	return 0;
+}
+
+static void gpmc_probe_legacy(struct platform_device *pdev)
+{
+	int i, rc, j;
+	struct device *dev = &pdev->dev;
+	struct gpmc_omap_platform_data *gpmc_pdata;
+	struct resource *mem_res;
+	unsigned long cs_base;
+	resource_size_t size;
+	struct gpmc_timings gpmc_timings;
+	struct gpmc_omap_cs_data *cs;
+
+	gpmc_pdata = dev->platform_data;
+	gpmc_cs_num = GPMC_CS_NUM;
+	gpmc_nr_waitpins = GPMC_NR_WAITPINS;
+
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		cs = &gpmc_pdata->cs[i];
+		if (!cs->valid)
+			continue;
+
+		if (cs->settings) {
+			if (gpmc_cs_program_settings(i, cs->settings)) {
+				dev_err(dev,
+					"Couldn't program settings for CS %d\n",
+					i);
+				continue;
+			}
+		}
+
+		/* give device_timings priority over gpmc_timings */
+		if (cs->device_timings) {
+			gpmc_calc_timings(&gpmc_timings, cs->settings,
+					  cs->device_timings);
+
+			if (gpmc_cs_set_timings(i, &gpmc_timings)) {
+				dev_err(dev,
+					"Couldn't program timings for CS %d\n",
+					i);
+				continue;
+			}
+		} else if (cs->gpmc_timings) {
+			if (gpmc_cs_set_timings(i, cs->gpmc_timings)) {
+				dev_err(dev,
+					"Couldn't program timings for CS %d\n",
+					i);
+				continue;
+			}
+		}
+	}
+
+	/*
+	 * All Chip Selects must be configured before platform devices are
+	 * created as some devices (e.g. tusb6010) can use multiple
+	 * Chip selects.
+	 */
+
+	/* Fixup Memory resources */
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		int required_resources;
+
+		cs = &gpmc_pdata->cs[i];
+		if (!cs->valid)
+			continue;
+
+		if (!cs->pdev)
+			continue;
+
+		/* Customized NAND setup */
+		if (cs->is_nand) {
+			if (gpmc_nand_setup(pdev, cs)) {
+				dev_err(dev, "Error setting up NAND on CS %d\n",
+					i);
+				continue;
+			}
+		}
+
+		mem_res = cs->pdev->resource;
+
+		/*
+		 * If device is present multiple times, fix the subsequent
+		 * resources
+		 */
+		required_resources = 1;
+		for (j = 0; j < i; j++) {
+			if (gpmc_pdata->cs[j].pdev == cs->pdev) {
+				mem_res++;
+				required_resources++;
+			}
+		}
+
+		if (cs->pdev->num_resources < required_resources ||
+		    resource_type(mem_res) != IORESOURCE_MEM) {
+			dev_err(dev, "Invalid IOMEM resource for CS %d\n", i);
+			continue;
+		}
+
+		/*
+		 * Request a CS space. Use size from
+		 * platform device's MEM resource
+		 */
+		size = mem_res->end - mem_res->start + 1;
+		if (gpmc_cs_request(i, size, &cs_base)) {
+			dev_err(dev, "Couldn't request resource for CS %d\n",
+				i);
+			continue;
+		}
+
+		mem_res->start = cs_base;
+		mem_res->end = cs_base + size - 1;
+	}
+
+	/* create the platform devices */
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		bool registered;
+
+		cs = &gpmc_pdata->cs[i];
+		if (!cs->valid)
+			continue;
+
+		if (!cs->pdev)
+			continue;
+
+		/*
+		 * same device can be present on multiple CS, don't
+		 * register device more than once.
+		 */
+		registered = false;
+		for (j = 0; j < i; j++) {
+			if (gpmc_pdata->cs[j].pdev == cs->pdev) {
+				registered = true;
+				break;
+			}
+		}
+
+		if (registered)
+			continue;
+
+		cs->pdev->dev.parent = dev;
+		rc = platform_device_register(cs->pdev);
+		if (rc < 0) {
+			dev_err(dev,
+				"Failed to register device %s on CS %d\n",
+				cs->pdev->name, i);
+			continue;
+		}
+	}
+}
+
+static int gpmc_probe(struct platform_device *pdev)
+{
+	int rc;
+	u32 l;
+	struct resource *res;
+	struct device *dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL)
+		return -ENOENT;
+
+	phys_base = res->start;
+	mem_size = resource_size(res);
+
+	gpmc_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(gpmc_base))
+		return PTR_ERR(gpmc_base);
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get resource: irq\n");
+		return -EINVAL;
+	}
+
+	gpmc_irq = res->start;
+
+	gpmc_l3_clk = clk_get(&pdev->dev, "fck");
+	if (IS_ERR(gpmc_l3_clk)) {
+		dev_err(&pdev->dev, "error: clk_get\n");
+		gpmc_irq = 0;
+		return PTR_ERR(gpmc_l3_clk);
+	}
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
+
+	gpmc_dev = dev;
+
+	l = gpmc_read_reg(GPMC_REVISION);
+
+	/*
+	 * FIXME: Once device-tree migration is complete the below flags
+	 * should be populated based upon the device-tree compatible
+	 * string. For now just use the IP revision. OMAP3+ devices have
+	 * the wr_access and wr_data_mux_bus register fields. OMAP4+
+	 * devices support the addr-addr-data multiplex protocol.
+	 *
+	 * GPMC IP revisions:
+	 * - OMAP24xx			= 2.0
+	 * - OMAP3xxx			= 5.0
+	 * - OMAP44xx/54xx/AM335x	= 6.0
+	 */
+	if (GPMC_REVISION_MAJOR(l) > 0x4)
+		gpmc_capability = GPMC_HAS_WR_ACCESS | GPMC_HAS_WR_DATA_MUX_BUS;
+	if (GPMC_REVISION_MAJOR(l) > 0x5)
+		gpmc_capability |= GPMC_HAS_MUX_AAD;
+	dev_info(dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l),
+		 GPMC_REVISION_MINOR(l));
+
+	gpmc_mem_init();
+
+	/* Now the GPMC is initialised, unreserve the chip-selects */
+	gpmc_cs_map = 0;
+	gpmc_dev = dev;
+
+	if (dev->of_node) {
+		rc = gpmc_probe_dt(pdev);
+		if (rc) {
+			dev_err(dev, "gpmc_probe_dt() failed\n");
+			goto error;
+		}
+	} else {
+		/* Legacy probing based on platform data */
+		if (!dev->platform_data) {
+			dev_err(dev, "No platform data\n");
+			rc = -EINVAL;
+			goto error;
+		}
+
+		gpmc_probe_legacy(pdev);
+	}
+
+	return 0;
+
+error:
+	pm_runtime_put_sync(dev);
+	clk_put(gpmc_l3_clk);
+	return rc;
+}
+
+static int gpmc_remove(struct platform_device *pdev)
+{
+	gpmc_mem_exit();
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	gpmc_dev = NULL;
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+/* Structure to save gpmc cs context */
+struct gpmc_cs_config {
+	u32 config1;
+	u32 config2;
+	u32 config3;
+	u32 config4;
+	u32 config5;
+	u32 config6;
+	u32 config7;
+	int is_valid;
+};
+
+/*
+ * Structure to save/restore gpmc context
+ */
+struct omap_gpmc_regs {
+	u32 sysconfig;
+	u32 irqenable;
+	u32 timeout_ctrl;
+	u32 config;
+	u32 prefetch_config1;
+	u32 prefetch_config2;
+	u32 prefetch_control;
+	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
+};
+
+static struct omap_gpmc_regs gpmc_context;
+
+void omap_gpmc_save_context(void)
+{
+	int i;
+
+	gpmc_context.sysconfig = gpmc_read_reg(GPMC_SYSCONFIG);
+	gpmc_context.irqenable = gpmc_read_reg(GPMC_IRQENABLE);
+	gpmc_context.timeout_ctrl = gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
+	gpmc_context.config = gpmc_read_reg(GPMC_CONFIG);
+	gpmc_context.prefetch_config1 = gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
+	gpmc_context.prefetch_config2 = gpmc_read_reg(GPMC_PREFETCH_CONFIG2);
+	gpmc_context.prefetch_control = gpmc_read_reg(GPMC_PREFETCH_CONTROL);
+	for (i = 0; i < gpmc_cs_num; i++) {
+		gpmc_context.cs_context[i].is_valid = gpmc_cs_mem_enabled(i);
+		if (gpmc_context.cs_context[i].is_valid) {
+			gpmc_context.cs_context[i].config1 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG1);
+			gpmc_context.cs_context[i].config2 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG2);
+			gpmc_context.cs_context[i].config3 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG3);
+			gpmc_context.cs_context[i].config4 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG4);
+			gpmc_context.cs_context[i].config5 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG5);
+			gpmc_context.cs_context[i].config6 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG6);
+			gpmc_context.cs_context[i].config7 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
+		}
+	}
+}
+
+void omap_gpmc_restore_context(void)
+{
+	int i;
+
+	gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig);
+	gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable);
+	gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl);
+	gpmc_write_reg(GPMC_CONFIG, gpmc_context.config);
+	gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1);
+	gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2);
+	gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control);
+	for (i = 0; i < gpmc_cs_num; i++) {
+		if (gpmc_context.cs_context[i].is_valid) {
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG1,
+					  gpmc_context.cs_context[i].config1);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG2,
+					  gpmc_context.cs_context[i].config2);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG3,
+					  gpmc_context.cs_context[i].config3);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG4,
+					  gpmc_context.cs_context[i].config4);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG5,
+					  gpmc_context.cs_context[i].config5);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG6,
+					  gpmc_context.cs_context[i].config6);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG7,
+					  gpmc_context.cs_context[i].config7);
+		}
+	}
+}
+
+static int gpmc_suspend(struct device *dev)
+{
+	omap_gpmc_save_context();
+	pm_runtime_put_sync(dev);
+	return 0;
+}
+
+static int gpmc_resume(struct device *dev)
+{
+	pm_runtime_get_sync(dev);
+	omap_gpmc_restore_context();
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(gpmc_pm_ops, gpmc_suspend, gpmc_resume);
+
+static struct platform_driver gpmc_driver = {
+	.probe		= gpmc_probe,
+	.remove		= gpmc_remove,
+	.driver		= {
+		.name	= DEVICE_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(gpmc_dt_ids),
+		.pm	= &gpmc_pm_ops,
+	},
+};
+
+static __init int gpmc_init(void)
+{
+	return platform_driver_register(&gpmc_driver);
+}
+
+static __exit void gpmc_exit(void)
+{
+	platform_driver_unregister(&gpmc_driver);
+}
+
+module_init(gpmc_init);
+module_exit(gpmc_exit);
+
+/**
+ * omap_gpmc_retime - Reconfigre GPMC timings for the device
+ *
+ * @cs		Chip select number
+ * @gpmc_s	GPMC settings
+ * @dev_t	New device timings to set
+ */
+int omap_gpmc_retime(int cs, struct gpmc_settings *gpmc_s,
+		     struct gpmc_device_timings *dev_t)
+{
+	struct gpmc_timings gpmc_t;
+	struct device *dev = gpmc_dev;
+
+	if (!gpmc_dev)
+		return -ENODEV;
+
+	if (cs < 0 || cs >= gpmc_cs_num) {
+		dev_err(dev, "%s: Invalid find Chip Select\n", __func__);
+		return cs;
+	}
+
+	if (gpmc_cs_program_settings(cs, gpmc_s)) {
+		dev_err(dev, "%s: Failed to set GPMC settings\n", __func__);
+		return -EINVAL;
+	}
+
+	gpmc_calc_timings(&gpmc_t, gpmc_s, dev_t);
+	if (gpmc_cs_set_timings(cs, &gpmc_t)) {
+		dev_err(dev, "%s: Failed to set GPMC timings\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(omap_gpmc_retime);
+
+/**
+ * omap_gpmc_get_clk_period - Get the nearest possible (equal to or higer) GPMC
+ *				synchronous clock (GPMC_CLK) period.
+ *
+ * @cs		Chip select number
+ * @min_ps	Minimum synchronous clock period supporded by the device
+ *
+ * Returns the nearest possible GPMC clock period in picoseconds, equal to or
+ * higher than the requested period. 0 in case of error.
+ */
+unsigned long omap_gpmc_get_clk_period(int cs,
+				       unsigned long min_ps)
+{
+	int div;
+	unsigned long clk_ps;
+	struct device *dev = gpmc_dev;
+
+	if (!gpmc_dev)
+		return 0;
+
+	if (cs < 0 || cs >= gpmc_cs_num) {
+		dev_err(dev, "%s: Invalid Chip Select\n", __func__);
+		return cs;
+	}
+
+	div = gpmc_calc_divider(min_ps);
+	if (div < 0) {
+		dev_err(dev, "%s: Can't support requested clock period %lu ps\n",
+			__func__, min_ps);
+		return 0;
+	}
+
+	clk_ps = gpmc_get_fclk_period() * div;
+
+	return clk_ps;
+}
+EXPORT_SYMBOL_GPL(omap_gpmc_get_clk_period);
+
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index f1cf503..e1db2c1 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -89,7 +89,7 @@ config MTD_NAND_AMS_DELTA
 
 config MTD_NAND_OMAP2
 	tristate "NAND Flash device on OMAP2, OMAP3 and OMAP4"
-	depends on ARCH_OMAP2PLUS
+	depends on TI_GPMC
 	help
           Support for NAND flash on Texas Instruments OMAP2, OMAP3 and OMAP4
 	  platforms.
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig
index ab260727..272c16c 100644
--- a/drivers/mtd/onenand/Kconfig
+++ b/drivers/mtd/onenand/Kconfig
@@ -24,10 +24,10 @@ config MTD_ONENAND_GENERIC
 	  Support for OneNAND flash via platform device driver.
 
 config MTD_ONENAND_OMAP2
-	tristate "OneNAND on OMAP2/OMAP3 support"
-	depends on ARCH_OMAP2 || ARCH_OMAP3
+	tristate "OneNAND on OMAP2+ support"
+	depends on TI_GPMC
 	help
-	  Support for a OneNAND flash device connected to an OMAP2/OMAP3 CPU
+	  Support for a OneNAND flash device connected to an OMAP2+ SoCs
 	  via the GPMC memory controller.
 
 config MTD_ONENAND_SAMSUNG
-- 
1.8.3.2

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

* [PATCH 35/36] ARM: OMAP2+: gpmc: move GPMC driver into drivers/memory
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

Move the GPMC driver out of mach-omap2. We leave behind only
the mach-omap2 specific bits in mach-omap2/gpmc_legacy.c
i.e. gpmc_generic_init() for use by board files to register
the GPMC configuration and omap3_gpmc_save/restore_context() for
use by OMAP3 OFF mode support.

The GPMC driver is now enabled by its own kernel config option
TI_GPMC. The other drivers that need GPMC to work i.e. MTD_ONENAND_OMAP2
and MTD_NAND_OMAP2 are made to depend on TI_GPMC.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/Makefile      |    2 +-
 arch/arm/mach-omap2/gpmc.c        | 1947 -------------------------------------
 arch/arm/mach-omap2/gpmc_legacy.c |  296 ++++++
 drivers/memory/Kconfig            |   10 +
 drivers/memory/Makefile           |    1 +
 drivers/memory/ti-gpmc.c          | 1829 ++++++++++++++++++++++++++++++++++
 drivers/mtd/nand/Kconfig          |    2 +-
 drivers/mtd/onenand/Kconfig       |    6 +-
 8 files changed, 2141 insertions(+), 1952 deletions(-)
 delete mode 100644 arch/arm/mach-omap2/gpmc.c
 create mode 100644 arch/arm/mach-omap2/gpmc_legacy.c
 create mode 100644 drivers/memory/ti-gpmc.c

diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 8421f38..a2e7426 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -6,7 +6,7 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
 	-I$(srctree)/arch/arm/plat-omap/include
 
 # Common support
-obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o gpmc.o timer.o pm.o \
+obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o gpmc_legacy.o timer.o pm.o \
 	 common.o gpio.o dma.o wd_timer.o display.o i2c.o hdq1w.o omap_hwmod.o \
 	 omap_device.o sram.o drm.o
 
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
deleted file mode 100644
index 9173f71..0000000
--- a/arch/arm/mach-omap2/gpmc.c
+++ /dev/null
@@ -1,1947 +0,0 @@
-/*
- * GPMC support functions
- *
- * Copyright (C) 2005-2006 Nokia Corporation
- *
- * Author: Juha Yrjola
- *
- * Copyright (C) 2009 Texas Instruments
- * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.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.
- */
-#undef DEBUG
-
-#include <linux/irq.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/ioport.h>
-#include <linux/spinlock.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_mtd.h>
-#include <linux/of_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/slab.h>
-
-#include <linux/platform_data/mtd-nand-omap2.h>
-
-#include <asm/mach-types.h>
-
-#include "soc.h"
-#include "common.h"
-#include "omap_device.h"
-#include "gpmc.h"
-
-#define	DEVICE_NAME		"omap-gpmc"
-
-/* GPMC register offsets */
-#define GPMC_REVISION		0x00
-#define GPMC_SYSCONFIG		0x10
-#define GPMC_SYSSTATUS		0x14
-#define GPMC_IRQSTATUS		0x18
-#define GPMC_IRQENABLE		0x1c
-#define GPMC_TIMEOUT_CONTROL	0x40
-#define GPMC_ERR_ADDRESS	0x44
-#define GPMC_ERR_TYPE		0x48
-#define GPMC_CONFIG		0x50
-#define GPMC_STATUS		0x54
-#define GPMC_PREFETCH_CONFIG1	0x1e0
-#define GPMC_PREFETCH_CONFIG2	0x1e4
-#define GPMC_PREFETCH_CONTROL	0x1ec
-#define GPMC_PREFETCH_STATUS	0x1f0
-#define GPMC_ECC_CONFIG		0x1f4
-#define GPMC_ECC_CONTROL	0x1f8
-#define GPMC_ECC_SIZE_CONFIG	0x1fc
-#define GPMC_ECC1_RESULT        0x200
-#define GPMC_ECC_BCH_RESULT_0   0x240   /* not available on OMAP2 */
-#define	GPMC_ECC_BCH_RESULT_1	0x244	/* not available on OMAP2 */
-#define	GPMC_ECC_BCH_RESULT_2	0x248	/* not available on OMAP2 */
-#define	GPMC_ECC_BCH_RESULT_3	0x24c	/* not available on OMAP2 */
-
-/* GPMC ECC control settings */
-#define GPMC_ECC_CTRL_ECCCLEAR		0x100
-#define GPMC_ECC_CTRL_ECCDISABLE	0x000
-#define GPMC_ECC_CTRL_ECCREG1		0x001
-#define GPMC_ECC_CTRL_ECCREG2		0x002
-#define GPMC_ECC_CTRL_ECCREG3		0x003
-#define GPMC_ECC_CTRL_ECCREG4		0x004
-#define GPMC_ECC_CTRL_ECCREG5		0x005
-#define GPMC_ECC_CTRL_ECCREG6		0x006
-#define GPMC_ECC_CTRL_ECCREG7		0x007
-#define GPMC_ECC_CTRL_ECCREG8		0x008
-#define GPMC_ECC_CTRL_ECCREG9		0x009
-
-/* ECC commands */
-#define GPMC_ECC_READ		0 /* Reset Hardware ECC for read */
-#define GPMC_ECC_WRITE		1 /* Reset Hardware ECC for write */
-#define GPMC_ECC_READSYN	2 /* Reset before syndrom is read back */
-
-/* CS CONFIG registers */
-#define GPMC_CS_CONFIG1		0x00
-#define GPMC_CS_CONFIG2		0x04
-#define GPMC_CS_CONFIG3		0x08
-#define GPMC_CS_CONFIG4		0x0c
-#define GPMC_CS_CONFIG5		0x10
-#define GPMC_CS_CONFIG6		0x14
-#define GPMC_CS_CONFIG7		0x18
-
-#define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
-#define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
-#define GPMC_CONFIG1_READTYPE_ASYNC     (0 << 29)
-#define GPMC_CONFIG1_READTYPE_SYNC      (1 << 29)
-#define GPMC_CONFIG1_WRITEMULTIPLE_SUPP (1 << 28)
-#define GPMC_CONFIG1_WRITETYPE_ASYNC    (0 << 27)
-#define GPMC_CONFIG1_WRITETYPE_SYNC     (1 << 27)
-#define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val & 3) << 25)
-#define GPMC_CONFIG1_PAGE_LEN(val)      ((val & 3) << 23)
-#define GPMC_CONFIG1_WAIT_READ_MON      (1 << 22)
-#define GPMC_CONFIG1_WAIT_WRITE_MON     (1 << 21)
-#define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18)
-#define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val & 3) << 16)
-#define GPMC_CONFIG1_DEVICESIZE(val)    ((val & 3) << 12)
-#define GPMC_CONFIG1_DEVICESIZE_16      GPMC_CONFIG1_DEVICESIZE(1)
-#define GPMC_CONFIG1_DEVICETYPE(val)    ((val & 3) << 10)
-#define GPMC_CONFIG1_DEVICETYPE_NOR     GPMC_CONFIG1_DEVICETYPE(0)
-#define GPMC_CONFIG1_MUXTYPE(val)       ((val & 3) << 8)
-#define GPMC_CONFIG1_TIME_PARA_GRAN     (1 << 4)
-#define GPMC_CONFIG1_FCLK_DIV(val)      (val & 3)
-#define GPMC_CONFIG1_FCLK_DIV2          (GPMC_CONFIG1_FCLK_DIV(1))
-#define GPMC_CONFIG1_FCLK_DIV3          (GPMC_CONFIG1_FCLK_DIV(2))
-#define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
-#define GPMC_CONFIG7_CSVALID		(1 << 6)
-
-#define	GPMC_CONFIG2_CSEXTRADELAY		BIT(7)
-#define	GPMC_CONFIG3_ADVEXTRADELAY		BIT(7)
-#define	GPMC_CONFIG4_OEEXTRADELAY		BIT(7)
-#define	GPMC_CONFIG4_WEEXTRADELAY		BIT(23)
-#define	GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN	BIT(6)
-#define	GPMC_CONFIG6_CYCLE2CYCLESAMECSEN	BIT(7)
-
-#define GPMC_DEVICETYPE_NOR		0
-#define GPMC_DEVICETYPE_NAND		2
-#define WR_RD_PIN_MONITORING		0x00600000
-#define GPMC_IRQ_FIFOEVENTENABLE	0x01
-#define GPMC_IRQ_COUNT_EVENT		0x02
-
-#define GPMC_CS0_OFFSET		0x60
-#define GPMC_CS_SIZE		0x30
-#define	GPMC_BCH_SIZE		0x10
-
-#define GPMC_MEM_END		0x3FFFFFFF
-
-#define GPMC_CHUNK_SHIFT	24		/* 16 MB */
-#define GPMC_SECTION_SHIFT	28		/* 128 MB */
-
-#define CS_NUM_SHIFT		24
-#define ENABLE_PREFETCH		(0x1 << 7)
-#define DMA_MPU_MODE		2
-
-#define	GPMC_REVISION_MAJOR(l)		((l >> 4) & 0xf)
-#define	GPMC_REVISION_MINOR(l)		(l & 0xf)
-
-#define	GPMC_HAS_WR_ACCESS		0x1
-#define	GPMC_HAS_WR_DATA_MUX_BUS	0x2
-#define	GPMC_HAS_MUX_AAD		0x4
-
-#define GPMC_NR_WAITPINS		4
-
-static struct gpmc_omap_platform_data gpmc_pdata;
-
-/* Structure to save gpmc cs context */
-struct gpmc_cs_config {
-	u32 config1;
-	u32 config2;
-	u32 config3;
-	u32 config4;
-	u32 config5;
-	u32 config6;
-	u32 config7;
-	int is_valid;
-};
-
-/*
- * Structure to save/restore gpmc context
- * to support core off on OMAP3
- */
-struct omap3_gpmc_regs {
-	u32 sysconfig;
-	u32 irqenable;
-	u32 timeout_ctrl;
-	u32 config;
-	u32 prefetch_config1;
-	u32 prefetch_config2;
-	u32 prefetch_control;
-	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
-};
-
-static struct resource	gpmc_mem_root;
-static struct resource	gpmc_cs_mem[GPMC_CS_NUM];
-static DEFINE_SPINLOCK(gpmc_mem_lock);
-/* Define chip-selects as reserved by default until probe completes */
-static unsigned int gpmc_cs_map = ((1 << GPMC_CS_NUM) - 1);
-static unsigned int gpmc_cs_num = GPMC_CS_NUM;
-static unsigned int gpmc_nr_waitpins;
-static struct device *gpmc_dev;
-static int gpmc_irq = -EINVAL;
-static resource_size_t phys_base, mem_size;
-static unsigned gpmc_capability;
-static void __iomem *gpmc_base;
-
-static struct clk *gpmc_l3_clk;
-
-static void gpmc_write_reg(int idx, u32 val)
-{
-	__raw_writel(val, gpmc_base + idx);
-}
-
-static u32 gpmc_read_reg(int idx)
-{
-	return __raw_readl(gpmc_base + idx);
-}
-
-static void gpmc_cs_write_reg(int cs, int idx, u32 val)
-{
-	void __iomem *reg_addr;
-
-	reg_addr = gpmc_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
-	__raw_writel(val, reg_addr);
-}
-
-static u32 gpmc_cs_read_reg(int cs, int idx)
-{
-	void __iomem *reg_addr;
-
-	reg_addr = gpmc_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
-	return __raw_readl(reg_addr);
-}
-
-/* TODO: Add support for gpmc_fck to clock framework and use it */
-static unsigned long gpmc_get_fclk_period(void)
-{
-	unsigned long rate = clk_get_rate(gpmc_l3_clk);
-
-	if (rate == 0) {
-		printk(KERN_WARNING "gpmc_l3_clk not enabled\n");
-		return 0;
-	}
-
-	rate /= 1000;
-	rate = 1000000000 / rate;	/* In picoseconds */
-
-	return rate;
-}
-
-static unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
-{
-	unsigned long tick_ps;
-
-	/* Calculate in picosecs to yield more exact results */
-	tick_ps = gpmc_get_fclk_period();
-
-	return (time_ns * 1000 + tick_ps - 1) / tick_ps;
-}
-
-static unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
-{
-	unsigned long tick_ps;
-
-	/* Calculate in picosecs to yield more exact results */
-	tick_ps = gpmc_get_fclk_period();
-
-	return (time_ps + tick_ps - 1) / tick_ps;
-}
-
-static unsigned int gpmc_ticks_to_ps(unsigned int ticks)
-{
-	return ticks * gpmc_get_fclk_period();
-}
-
-static unsigned int gpmc_round_ps_to_ticks(unsigned int time_ps)
-{
-	unsigned long ticks = gpmc_ps_to_ticks(time_ps);
-
-	return ticks * gpmc_get_fclk_period();
-}
-
-static inline void gpmc_cs_modify_reg(int cs, int reg, u32 mask, bool value)
-{
-	u32 l;
-
-	l = gpmc_cs_read_reg(cs, reg);
-	if (value)
-		l |= mask;
-	else
-		l &= ~mask;
-	gpmc_cs_write_reg(cs, reg, l);
-}
-
-static void gpmc_cs_bool_timings(int cs, const struct gpmc_bool_timings *p)
-{
-	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG1,
-			   GPMC_CONFIG1_TIME_PARA_GRAN,
-			   p->time_para_granularity);
-	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG2,
-			   GPMC_CONFIG2_CSEXTRADELAY, p->cs_extra_delay);
-	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG3,
-			   GPMC_CONFIG3_ADVEXTRADELAY, p->adv_extra_delay);
-	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG4,
-			   GPMC_CONFIG4_OEEXTRADELAY, p->oe_extra_delay);
-	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG4,
-			   GPMC_CONFIG4_OEEXTRADELAY, p->we_extra_delay);
-	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG6,
-			   GPMC_CONFIG6_CYCLE2CYCLESAMECSEN,
-			   p->cycle2cyclesamecsen);
-	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG6,
-			   GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN,
-			   p->cycle2cyclediffcsen);
-}
-
-#ifdef DEBUG
-static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
-			       int time, const char *name)
-#else
-static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
-			       int time)
-#endif
-{
-	u32 l;
-	int ticks, mask, nr_bits;
-
-	if (time == 0)
-		ticks = 0;
-	else
-		ticks = gpmc_ns_to_ticks(time);
-	nr_bits = end_bit - st_bit + 1;
-	if (ticks >= 1 << nr_bits) {
-#ifdef DEBUG
-		printk(KERN_INFO "GPMC CS%d: %-10s* %3d ns, %3d ticks >= %d\n",
-				cs, name, time, ticks, 1 << nr_bits);
-#endif
-		return -1;
-	}
-
-	mask = (1 << nr_bits) - 1;
-	l = gpmc_cs_read_reg(cs, reg);
-#ifdef DEBUG
-	printk(KERN_INFO
-		"GPMC CS%d: %-10s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n",
-	       cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000,
-			(l >> st_bit) & mask, time);
-#endif
-	l &= ~(mask << st_bit);
-	l |= ticks << st_bit;
-	gpmc_cs_write_reg(cs, reg, l);
-
-	return 0;
-}
-
-#ifdef DEBUG
-#define GPMC_SET_ONE(reg, st, end, field) \
-	if (set_gpmc_timing_reg(cs, (reg), (st), (end),		\
-			t->field, #field) < 0)			\
-		return -1
-#else
-#define GPMC_SET_ONE(reg, st, end, field) \
-	if (set_gpmc_timing_reg(cs, (reg), (st), (end), t->field) < 0) \
-		return -1
-#endif
-
-static int gpmc_calc_divider(unsigned int sync_clk)
-{
-	int div;
-	u32 l;
-
-	l = sync_clk + (gpmc_get_fclk_period() - 1);
-	div = l / gpmc_get_fclk_period();
-	if (div > 4)
-		return -1;
-	if (div <= 0)
-		div = 1;
-
-	return div;
-}
-
-static int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
-{
-	int div;
-	u32 l;
-
-	div = gpmc_calc_divider(t->sync_clk);
-	if (div < 0)
-		return div;
-
-	GPMC_SET_ONE(GPMC_CS_CONFIG2,  0,  3, cs_on);
-	GPMC_SET_ONE(GPMC_CS_CONFIG2,  8, 12, cs_rd_off);
-	GPMC_SET_ONE(GPMC_CS_CONFIG2, 16, 20, cs_wr_off);
-
-	GPMC_SET_ONE(GPMC_CS_CONFIG3,  0,  3, adv_on);
-	GPMC_SET_ONE(GPMC_CS_CONFIG3,  8, 12, adv_rd_off);
-	GPMC_SET_ONE(GPMC_CS_CONFIG3, 16, 20, adv_wr_off);
-
-	GPMC_SET_ONE(GPMC_CS_CONFIG4,  0,  3, oe_on);
-	GPMC_SET_ONE(GPMC_CS_CONFIG4,  8, 12, oe_off);
-	GPMC_SET_ONE(GPMC_CS_CONFIG4, 16, 19, we_on);
-	GPMC_SET_ONE(GPMC_CS_CONFIG4, 24, 28, we_off);
-
-	GPMC_SET_ONE(GPMC_CS_CONFIG5,  0,  4, rd_cycle);
-	GPMC_SET_ONE(GPMC_CS_CONFIG5,  8, 12, wr_cycle);
-	GPMC_SET_ONE(GPMC_CS_CONFIG5, 16, 20, access);
-
-	GPMC_SET_ONE(GPMC_CS_CONFIG5, 24, 27, page_burst_access);
-
-	GPMC_SET_ONE(GPMC_CS_CONFIG6, 0, 3, bus_turnaround);
-	GPMC_SET_ONE(GPMC_CS_CONFIG6, 8, 11, cycle2cycle_delay);
-
-	GPMC_SET_ONE(GPMC_CS_CONFIG1, 18, 19, wait_monitoring);
-	GPMC_SET_ONE(GPMC_CS_CONFIG1, 25, 26, clk_activation);
-
-	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
-		GPMC_SET_ONE(GPMC_CS_CONFIG6, 16, 19, wr_data_mux_bus);
-	if (gpmc_capability & GPMC_HAS_WR_ACCESS)
-		GPMC_SET_ONE(GPMC_CS_CONFIG6, 24, 28, wr_access);
-
-	/* caller is expected to have initialized CONFIG1 to cover
-	 * at least sync vs async
-	 */
-	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
-	if (l & (GPMC_CONFIG1_READTYPE_SYNC | GPMC_CONFIG1_WRITETYPE_SYNC)) {
-#ifdef DEBUG
-		printk(KERN_INFO "GPMC CS%d CLK period is %lu ns (div %d)\n",
-				cs, (div * gpmc_get_fclk_period()) / 1000, div);
-#endif
-		l &= ~0x03;
-		l |= (div - 1);
-		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
-	}
-
-	gpmc_cs_bool_timings(cs, &t->bool_timings);
-
-	return 0;
-}
-
-static int gpmc_cs_enable_mem(int cs, u32 base, u32 size)
-{
-	u32 l;
-	u32 mask;
-
-	/*
-	 * Ensure that base address is aligned on a
-	 * boundary equal to or greater than size.
-	 */
-	if (base & (size - 1))
-		return -EINVAL;
-
-	mask = (1 << GPMC_SECTION_SHIFT) - size;
-	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
-	l &= ~0x3f;
-	l = (base >> GPMC_CHUNK_SHIFT) & 0x3f;
-	l &= ~(0x0f << 8);
-	l |= ((mask >> GPMC_CHUNK_SHIFT) & 0x0f) << 8;
-	l |= GPMC_CONFIG7_CSVALID;
-	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
-
-	return 0;
-}
-
-static void gpmc_cs_disable_mem(int cs)
-{
-	u32 l;
-
-	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
-	l &= ~GPMC_CONFIG7_CSVALID;
-	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
-}
-
-static void gpmc_cs_get_memconf(int cs, u32 *base, u32 *size)
-{
-	u32 l;
-	u32 mask;
-
-	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
-	*base = (l & 0x3f) << GPMC_CHUNK_SHIFT;
-	mask = (l >> 8) & 0x0f;
-	*size = (1 << GPMC_SECTION_SHIFT) - (mask << GPMC_CHUNK_SHIFT);
-}
-
-static int gpmc_cs_mem_enabled(int cs)
-{
-	u32 l;
-
-	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
-	return l & GPMC_CONFIG7_CSVALID;
-}
-
-static void gpmc_cs_set_reserved(int cs, int reserved)
-{
-	gpmc_cs_map &= ~(1 << cs);
-	gpmc_cs_map |= (reserved ? 1 : 0) << cs;
-}
-
-static bool gpmc_cs_reserved(int cs)
-{
-	return gpmc_cs_map & (1 << cs);
-}
-
-static unsigned long gpmc_mem_align(unsigned long size)
-{
-	int order;
-
-	size = (size - 1) >> (GPMC_CHUNK_SHIFT - 1);
-	order = GPMC_CHUNK_SHIFT - 1;
-	do {
-		size >>= 1;
-		order++;
-	} while (size);
-	size = 1 << order;
-	return size;
-}
-
-static int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size)
-{
-	struct resource	*res = &gpmc_cs_mem[cs];
-	int r;
-
-	size = gpmc_mem_align(size);
-	spin_lock(&gpmc_mem_lock);
-	res->start = base;
-	res->end = base + size - 1;
-	r = request_resource(&gpmc_mem_root, res);
-	spin_unlock(&gpmc_mem_lock);
-
-	return r;
-}
-
-static int gpmc_cs_delete_mem(int cs)
-{
-	struct resource	*res = &gpmc_cs_mem[cs];
-	int r;
-
-	spin_lock(&gpmc_mem_lock);
-	r = release_resource(res);
-	res->start = 0;
-	res->end = 0;
-	spin_unlock(&gpmc_mem_lock);
-
-	return r;
-}
-
-/**
- * gpmc_cs_remap - remaps a chip-select physical base address
- * @cs:		chip-select to remap
- * @base:	physical base address to re-map chip-select to
- *
- * Re-maps a chip-select to a new physical base address specified by
- * "base". Returns 0 on success and appropriate negative error code
- * on failure.
- */
-static int gpmc_cs_remap(int cs, u32 base)
-{
-	int ret;
-	u32 old_base, size;
-
-	if (cs > gpmc_cs_num) {
-		pr_err("%s: requested chip-select is disabled\n", __func__);
-		return -ENODEV;
-	}
-
-	/*
-	 * Make sure we ignore any device offsets from the GPMC partition
-	 * allocated for the chip select and that the new base confirms
-	 * to the GPMC 16MB minimum granularity.
-	 */ 
-	base &= ~(SZ_16M - 1);
-
-	gpmc_cs_get_memconf(cs, &old_base, &size);
-	if (base == old_base)
-		return 0;
-	gpmc_cs_disable_mem(cs);
-	ret = gpmc_cs_delete_mem(cs);
-	if (ret < 0)
-		return ret;
-	ret = gpmc_cs_insert_mem(cs, base, size);
-	if (ret < 0)
-		return ret;
-	ret = gpmc_cs_enable_mem(cs, base, size);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
-static int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
-{
-	struct resource *res = &gpmc_cs_mem[cs];
-	int r = -1;
-
-	if (cs > gpmc_cs_num) {
-		pr_err("%s: requested chip-select is disabled\n", __func__);
-		return -ENODEV;
-	}
-	size = gpmc_mem_align(size);
-	if (size > (1 << GPMC_SECTION_SHIFT))
-		return -ENOMEM;
-
-	spin_lock(&gpmc_mem_lock);
-	if (gpmc_cs_reserved(cs)) {
-		r = -EBUSY;
-		goto out;
-	}
-	if (gpmc_cs_mem_enabled(cs))
-		r = adjust_resource(res, res->start & ~(size - 1), size);
-	if (r < 0)
-		r = allocate_resource(&gpmc_mem_root, res, size, 0, ~0,
-				      size, NULL, NULL);
-	if (r < 0)
-		goto out;
-
-	r = gpmc_cs_enable_mem(cs, res->start, resource_size(res));
-	if (r < 0) {
-		release_resource(res);
-		goto out;
-	}
-
-	*base = res->start;
-	gpmc_cs_set_reserved(cs, 1);
-out:
-	spin_unlock(&gpmc_mem_lock);
-	return r;
-}
-
-static void gpmc_cs_free(int cs)
-{
-	struct resource	*res = &gpmc_cs_mem[cs];
-
-	spin_lock(&gpmc_mem_lock);
-	if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) {
-		printk(KERN_ERR "Trying to free non-reserved GPMC CS%d\n", cs);
-		BUG();
-		spin_unlock(&gpmc_mem_lock);
-		return;
-	}
-	gpmc_cs_disable_mem(cs);
-	if (res->flags)
-		release_resource(res);
-	gpmc_cs_set_reserved(cs, 0);
-	spin_unlock(&gpmc_mem_lock);
-}
-
-static void gpmc_mem_exit(void)
-{
-	int cs;
-
-	for (cs = 0; cs < gpmc_cs_num; cs++) {
-		if (!gpmc_cs_mem_enabled(cs))
-			continue;
-		gpmc_cs_delete_mem(cs);
-	}
-
-}
-
-static void gpmc_mem_init(void)
-{
-	int cs;
-
-	/*
-	 * The first 1MB of GPMC address space is typically mapped to
-	 * the internal ROM. Never allocate the first page, to
-	 * facilitate bug detection; even if we didn't boot from ROM.
-	 */
-	gpmc_mem_root.start = SZ_1M;
-	gpmc_mem_root.end = GPMC_MEM_END;
-
-	/* Reserve all regions that has been set up by bootloader */
-	for (cs = 0; cs < gpmc_cs_num; cs++) {
-		u32 base, size;
-
-		if (!gpmc_cs_mem_enabled(cs))
-			continue;
-		gpmc_cs_get_memconf(cs, &base, &size);
-		if (gpmc_cs_insert_mem(cs, base, size)) {
-			pr_warn("%s: disabling cs %d mapped at 0x%x-0x%x\n",
-				__func__, cs, base, base + size);
-			gpmc_cs_disable_mem(cs);
-		}
-	}
-}
-
-static u32 gpmc_round_ps_to_sync_clk(u32 time_ps, u32 sync_clk)
-{
-	u32 temp;
-	int div;
-
-	div = gpmc_calc_divider(sync_clk);
-	temp = gpmc_ps_to_ticks(time_ps);
-	temp = (temp + div - 1) / div;
-	return gpmc_ticks_to_ps(temp * div);
-}
-
-/* XXX: can the cycles be avoided ? */
-static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t,
-				       struct gpmc_device_timings *dev_t,
-				       bool mux)
-{
-	u32 temp;
-
-	/* adv_rd_off */
-	temp = dev_t->t_avdp_r;
-	/* XXX: mux check required ? */
-	if (mux) {
-		/* XXX: t_avdp not to be required for sync, only added for tusb
-		 * this indirectly necessitates requirement of t_avdp_r and
-		 * t_avdp_w instead of having a single t_avdp
-		 */
-		temp = max_t(u32, temp,	gpmc_t->clk_activation + dev_t->t_avdh);
-		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
-	}
-	gpmc_t->adv_rd_off = gpmc_round_ps_to_ticks(temp);
-
-	/* oe_on */
-	temp = dev_t->t_oeasu; /* XXX: remove this ? */
-	if (mux) {
-		temp = max_t(u32, temp,	gpmc_t->clk_activation + dev_t->t_ach);
-		temp = max_t(u32, temp, gpmc_t->adv_rd_off +
-				gpmc_ticks_to_ps(dev_t->cyc_aavdh_oe));
-	}
-	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
-
-	/* access */
-	/* XXX: any scope for improvement ?, by combining oe_on
-	 * and clk_activation, need to check whether
-	 * access = clk_activation + round to sync clk ?
-	 */
-	temp = max_t(u32, dev_t->t_iaa,	dev_t->cyc_iaa * gpmc_t->sync_clk);
-	temp += gpmc_t->clk_activation;
-	if (dev_t->cyc_oe)
-		temp = max_t(u32, temp, gpmc_t->oe_on +
-				gpmc_ticks_to_ps(dev_t->cyc_oe));
-	gpmc_t->access = gpmc_round_ps_to_ticks(temp);
-
-	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ps(1);
-	gpmc_t->cs_rd_off = gpmc_t->oe_off;
-
-	/* rd_cycle */
-	temp = max_t(u32, dev_t->t_cez_r, dev_t->t_oez);
-	temp = gpmc_round_ps_to_sync_clk(temp, gpmc_t->sync_clk) +
-							gpmc_t->access;
-	/* XXX: barter t_ce_rdyz with t_cez_r ? */
-	if (dev_t->t_ce_rdyz)
-		temp = max_t(u32, temp,	gpmc_t->cs_rd_off + dev_t->t_ce_rdyz);
-	gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp);
-
-	return 0;
-}
-
-static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t,
-					struct gpmc_device_timings *dev_t,
-					bool mux)
-{
-	u32 temp;
-
-	/* adv_wr_off */
-	temp = dev_t->t_avdp_w;
-	if (mux) {
-		temp = max_t(u32, temp,
-			gpmc_t->clk_activation + dev_t->t_avdh);
-		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
-	}
-	gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp);
-
-	/* wr_data_mux_bus */
-	temp = max_t(u32, dev_t->t_weasu,
-			gpmc_t->clk_activation + dev_t->t_rdyo);
-	/* XXX: shouldn't mux be kept as a whole for wr_data_mux_bus ?,
-	 * and in that case remember to handle we_on properly
-	 */
-	if (mux) {
-		temp = max_t(u32, temp,
-			gpmc_t->adv_wr_off + dev_t->t_aavdh);
-		temp = max_t(u32, temp, gpmc_t->adv_wr_off +
-				gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
-	}
-	gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp);
-
-	/* we_on */
-	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
-		gpmc_t->we_on = gpmc_round_ps_to_ticks(dev_t->t_weasu);
-	else
-		gpmc_t->we_on = gpmc_t->wr_data_mux_bus;
-
-	/* wr_access */
-	/* XXX: gpmc_capability check reqd ? , even if not, will not harm */
-	gpmc_t->wr_access = gpmc_t->access;
-
-	/* we_off */
-	temp = gpmc_t->we_on + dev_t->t_wpl;
-	temp = max_t(u32, temp,
-			gpmc_t->wr_access + gpmc_ticks_to_ps(1));
-	temp = max_t(u32, temp,
-		gpmc_t->we_on + gpmc_ticks_to_ps(dev_t->cyc_wpl));
-	gpmc_t->we_off = gpmc_round_ps_to_ticks(temp);
-
-	gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off +
-							dev_t->t_wph);
-
-	/* wr_cycle */
-	temp = gpmc_round_ps_to_sync_clk(dev_t->t_cez_w, gpmc_t->sync_clk);
-	temp += gpmc_t->wr_access;
-	/* XXX: barter t_ce_rdyz with t_cez_w ? */
-	if (dev_t->t_ce_rdyz)
-		temp = max_t(u32, temp,
-				 gpmc_t->cs_wr_off + dev_t->t_ce_rdyz);
-	gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp);
-
-	return 0;
-}
-
-static int gpmc_calc_async_read_timings(struct gpmc_timings *gpmc_t,
-					struct gpmc_device_timings *dev_t,
-					bool mux)
-{
-	u32 temp;
-
-	/* adv_rd_off */
-	temp = dev_t->t_avdp_r;
-	if (mux)
-		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
-	gpmc_t->adv_rd_off = gpmc_round_ps_to_ticks(temp);
-
-	/* oe_on */
-	temp = dev_t->t_oeasu;
-	if (mux)
-		temp = max_t(u32, temp,
-			gpmc_t->adv_rd_off + dev_t->t_aavdh);
-	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
-
-	/* access */
-	temp = max_t(u32, dev_t->t_iaa, /* XXX: remove t_iaa in async ? */
-				gpmc_t->oe_on + dev_t->t_oe);
-	temp = max_t(u32, temp,
-				gpmc_t->cs_on + dev_t->t_ce);
-	temp = max_t(u32, temp,
-				gpmc_t->adv_on + dev_t->t_aa);
-	gpmc_t->access = gpmc_round_ps_to_ticks(temp);
-
-	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ps(1);
-	gpmc_t->cs_rd_off = gpmc_t->oe_off;
-
-	/* rd_cycle */
-	temp = max_t(u32, dev_t->t_rd_cycle,
-			gpmc_t->cs_rd_off + dev_t->t_cez_r);
-	temp = max_t(u32, temp, gpmc_t->oe_off + dev_t->t_oez);
-	gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp);
-
-	return 0;
-}
-
-static int gpmc_calc_async_write_timings(struct gpmc_timings *gpmc_t,
-					 struct gpmc_device_timings *dev_t,
-					 bool mux)
-{
-	u32 temp;
-
-	/* adv_wr_off */
-	temp = dev_t->t_avdp_w;
-	if (mux)
-		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
-	gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp);
-
-	/* wr_data_mux_bus */
-	temp = dev_t->t_weasu;
-	if (mux) {
-		temp = max_t(u32, temp,	gpmc_t->adv_wr_off + dev_t->t_aavdh);
-		temp = max_t(u32, temp, gpmc_t->adv_wr_off +
-				gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
-	}
-	gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp);
-
-	/* we_on */
-	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
-		gpmc_t->we_on = gpmc_round_ps_to_ticks(dev_t->t_weasu);
-	else
-		gpmc_t->we_on = gpmc_t->wr_data_mux_bus;
-
-	/* we_off */
-	temp = gpmc_t->we_on + dev_t->t_wpl;
-	gpmc_t->we_off = gpmc_round_ps_to_ticks(temp);
-
-	gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off +
-							dev_t->t_wph);
-
-	/* wr_cycle */
-	temp = max_t(u32, dev_t->t_wr_cycle,
-				gpmc_t->cs_wr_off + dev_t->t_cez_w);
-	gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp);
-
-	return 0;
-}
-
-static int gpmc_calc_sync_common_timings(struct gpmc_timings *gpmc_t,
-			struct gpmc_device_timings *dev_t)
-{
-	u32 temp;
-
-	gpmc_t->sync_clk = gpmc_calc_divider(dev_t->clk) *
-						gpmc_get_fclk_period();
-
-	gpmc_t->page_burst_access = gpmc_round_ps_to_sync_clk(
-					dev_t->t_bacc,
-					gpmc_t->sync_clk);
-
-	temp = max_t(u32, dev_t->t_ces, dev_t->t_avds);
-	gpmc_t->clk_activation = gpmc_round_ps_to_ticks(temp);
-
-	if (gpmc_calc_divider(gpmc_t->sync_clk) != 1)
-		return 0;
-
-	if (dev_t->ce_xdelay)
-		gpmc_t->bool_timings.cs_extra_delay = true;
-	if (dev_t->avd_xdelay)
-		gpmc_t->bool_timings.adv_extra_delay = true;
-	if (dev_t->oe_xdelay)
-		gpmc_t->bool_timings.oe_extra_delay = true;
-	if (dev_t->we_xdelay)
-		gpmc_t->bool_timings.we_extra_delay = true;
-
-	return 0;
-}
-
-static int gpmc_calc_common_timings(struct gpmc_timings *gpmc_t,
-				    struct gpmc_device_timings *dev_t,
-				    bool sync)
-{
-	u32 temp;
-
-	/* cs_on */
-	gpmc_t->cs_on = gpmc_round_ps_to_ticks(dev_t->t_ceasu);
-
-	/* adv_on */
-	temp = dev_t->t_avdasu;
-	if (dev_t->t_ce_avd)
-		temp = max_t(u32, temp,
-				gpmc_t->cs_on + dev_t->t_ce_avd);
-	gpmc_t->adv_on = gpmc_round_ps_to_ticks(temp);
-
-	if (sync)
-		gpmc_calc_sync_common_timings(gpmc_t, dev_t);
-
-	return 0;
-}
-
-/* TODO: remove this function once all peripherals are confirmed to
- * work with generic timing. Simultaneously gpmc_cs_set_timings()
- * has to be modified to handle timings in ps instead of ns
-*/
-static void gpmc_convert_ps_to_ns(struct gpmc_timings *t)
-{
-	t->cs_on /= 1000;
-	t->cs_rd_off /= 1000;
-	t->cs_wr_off /= 1000;
-	t->adv_on /= 1000;
-	t->adv_rd_off /= 1000;
-	t->adv_wr_off /= 1000;
-	t->we_on /= 1000;
-	t->we_off /= 1000;
-	t->oe_on /= 1000;
-	t->oe_off /= 1000;
-	t->page_burst_access /= 1000;
-	t->access /= 1000;
-	t->rd_cycle /= 1000;
-	t->wr_cycle /= 1000;
-	t->bus_turnaround /= 1000;
-	t->cycle2cycle_delay /= 1000;
-	t->wait_monitoring /= 1000;
-	t->clk_activation /= 1000;
-	t->wr_access /= 1000;
-	t->wr_data_mux_bus /= 1000;
-}
-
-static int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
-			     struct gpmc_settings *gpmc_s,
-			     struct gpmc_device_timings *dev_t)
-{
-	bool mux = false, sync = false;
-
-	if (gpmc_s) {
-		mux = gpmc_s->mux_add_data ? true : false;
-		sync = (gpmc_s->sync_read || gpmc_s->sync_write);
-	}
-
-	memset(gpmc_t, 0, sizeof(*gpmc_t));
-
-	gpmc_calc_common_timings(gpmc_t, dev_t, sync);
-
-	if (gpmc_s && gpmc_s->sync_read)
-		gpmc_calc_sync_read_timings(gpmc_t, dev_t, mux);
-	else
-		gpmc_calc_async_read_timings(gpmc_t, dev_t, mux);
-
-	if (gpmc_s && gpmc_s->sync_write)
-		gpmc_calc_sync_write_timings(gpmc_t, dev_t, mux);
-	else
-		gpmc_calc_async_write_timings(gpmc_t, dev_t, mux);
-
-	/* TODO: remove, see function definition */
-	gpmc_convert_ps_to_ns(gpmc_t);
-
-	return 0;
-}
-
-/**
- * gpmc_cs_program_settings - programs non-timing related settings
- * @cs:		GPMC chip-select to program
- * @p:		pointer to GPMC settings structure
- *
- * Programs non-timing related settings for a GPMC chip-select, such as
- * bus-width, burst configuration, etc. Function should be called once
- * for each chip-select that is being used and must be called before
- * calling gpmc_cs_set_timings() as timing parameters in the CONFIG1
- * register will be initialised to zero by this function. Returns 0 on
- * success and appropriate negative error code on failure.
- */
-static int gpmc_cs_program_settings(int cs, struct gpmc_settings *p)
-{
-	u32 config1;
-
-	if ((!p->device_width) || (p->device_width > GPMC_DEVWIDTH_16BIT)) {
-		pr_err("%s: invalid width %d!", __func__, p->device_width);
-		return -EINVAL;
-	}
-
-	/* Address-data multiplexing not supported for NAND devices */
-	if (p->device_nand && p->mux_add_data) {
-		pr_err("%s: invalid configuration!\n", __func__);
-		return -EINVAL;
-	}
-
-	if ((p->mux_add_data > GPMC_MUX_AD) ||
-	    ((p->mux_add_data == GPMC_MUX_AAD) &&
-	     !(gpmc_capability & GPMC_HAS_MUX_AAD))) {
-		pr_err("%s: invalid multiplex configuration!\n", __func__);
-		return -EINVAL;
-	}
-
-	/* Page/burst mode supports lengths of 4, 8 and 16 bytes */
-	if (p->burst_read || p->burst_write) {
-		switch (p->burst_len) {
-		case GPMC_BURST_4:
-		case GPMC_BURST_8:
-		case GPMC_BURST_16:
-			break;
-		default:
-			pr_err("%s: invalid page/burst-length (%d)\n",
-			       __func__, p->burst_len);
-			return -EINVAL;
-		}
-	}
-
-	if ((p->wait_on_read || p->wait_on_write) &&
-	    (p->wait_pin > gpmc_nr_waitpins)) {
-		pr_err("%s: invalid wait-pin (%d)\n", __func__, p->wait_pin);
-		return -EINVAL;
-	}
-
-	config1 = GPMC_CONFIG1_DEVICESIZE((p->device_width - 1));
-
-	if (p->sync_read)
-		config1 |= GPMC_CONFIG1_READTYPE_SYNC;
-	if (p->sync_write)
-		config1 |= GPMC_CONFIG1_WRITETYPE_SYNC;
-	if (p->wait_on_read)
-		config1 |= GPMC_CONFIG1_WAIT_READ_MON;
-	if (p->wait_on_write)
-		config1 |= GPMC_CONFIG1_WAIT_WRITE_MON;
-	if (p->wait_on_read || p->wait_on_write)
-		config1 |= GPMC_CONFIG1_WAIT_PIN_SEL(p->wait_pin);
-	if (p->device_nand)
-		config1	|= GPMC_CONFIG1_DEVICETYPE(GPMC_DEVICETYPE_NAND);
-	if (p->mux_add_data)
-		config1	|= GPMC_CONFIG1_MUXTYPE(p->mux_add_data);
-	if (p->burst_read)
-		config1 |= GPMC_CONFIG1_READMULTIPLE_SUPP;
-	if (p->burst_write)
-		config1 |= GPMC_CONFIG1_WRITEMULTIPLE_SUPP;
-	if (p->burst_read || p->burst_write) {
-		config1 |= GPMC_CONFIG1_PAGE_LEN(p->burst_len >> 3);
-		config1 |= p->burst_wrap ? GPMC_CONFIG1_WRAPBURST_SUPP : 0;
-	}
-
-	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, config1);
-
-	return 0;
-}
-
-#ifdef CONFIG_OF
-static struct of_device_id gpmc_dt_ids[] = {
-	{ .compatible = "ti,omap2420-gpmc" },
-	{ .compatible = "ti,omap2430-gpmc" },
-	{ .compatible = "ti,omap3430-gpmc" },	/* omap3430 & omap3630 */
-	{ .compatible = "ti,omap4430-gpmc" },	/* omap4430 & omap4460 & omap543x */
-	{ .compatible = "ti,am3352-gpmc" },	/* am335x devices */
-	{ }
-};
-MODULE_DEVICE_TABLE(of, gpmc_dt_ids);
-
-/**
- * gpmc_read_settings_dt - read gpmc settings from device-tree
- * @np:		pointer to device-tree node for a gpmc child device
- * @p:		pointer to gpmc settings structure
- *
- * Reads the GPMC settings for a GPMC child device from device-tree and
- * stores them in the GPMC settings structure passed. The GPMC settings
- * structure is initialised to zero by this function and so any
- * previously stored settings will be cleared.
- */
-static void gpmc_read_settings_dt(struct device_node *np,
-				  struct gpmc_settings *p)
-{
-	memset(p, 0, sizeof(struct gpmc_settings));
-
-	p->sync_read = of_property_read_bool(np, "gpmc,sync-read");
-	p->sync_write = of_property_read_bool(np, "gpmc,sync-write");
-	of_property_read_u32(np, "gpmc,device-width", &p->device_width);
-	of_property_read_u32(np, "gpmc,mux-add-data", &p->mux_add_data);
-
-	if (!of_property_read_u32(np, "gpmc,burst-length", &p->burst_len)) {
-		p->burst_wrap = of_property_read_bool(np, "gpmc,burst-wrap");
-		p->burst_read = of_property_read_bool(np, "gpmc,burst-read");
-		p->burst_write = of_property_read_bool(np, "gpmc,burst-write");
-		if (!p->burst_read && !p->burst_write)
-			pr_warn("%s: page/burst-length set but not used!\n",
-				__func__);
-	}
-
-	if (!of_property_read_u32(np, "gpmc,wait-pin", &p->wait_pin)) {
-		p->wait_on_read = of_property_read_bool(np,
-							"gpmc,wait-on-read");
-		p->wait_on_write = of_property_read_bool(np,
-							 "gpmc,wait-on-write");
-		if (!p->wait_on_read && !p->wait_on_write)
-			pr_warn("%s: read/write wait monitoring not enabled!\n",
-				__func__);
-	}
-}
-
-static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
-						struct gpmc_timings *gpmc_t)
-{
-	struct gpmc_bool_timings *p;
-
-	if (!np || !gpmc_t)
-		return;
-
-	memset(gpmc_t, 0, sizeof(*gpmc_t));
-
-	/* minimum clock period for syncronous mode */
-	of_property_read_u32(np, "gpmc,sync-clk-ps", &gpmc_t->sync_clk);
-
-	/* chip select timtings */
-	of_property_read_u32(np, "gpmc,cs-on-ns", &gpmc_t->cs_on);
-	of_property_read_u32(np, "gpmc,cs-rd-off-ns", &gpmc_t->cs_rd_off);
-	of_property_read_u32(np, "gpmc,cs-wr-off-ns", &gpmc_t->cs_wr_off);
-
-	/* ADV signal timings */
-	of_property_read_u32(np, "gpmc,adv-on-ns", &gpmc_t->adv_on);
-	of_property_read_u32(np, "gpmc,adv-rd-off-ns", &gpmc_t->adv_rd_off);
-	of_property_read_u32(np, "gpmc,adv-wr-off-ns", &gpmc_t->adv_wr_off);
-
-	/* WE signal timings */
-	of_property_read_u32(np, "gpmc,we-on-ns", &gpmc_t->we_on);
-	of_property_read_u32(np, "gpmc,we-off-ns", &gpmc_t->we_off);
-
-	/* OE signal timings */
-	of_property_read_u32(np, "gpmc,oe-on-ns", &gpmc_t->oe_on);
-	of_property_read_u32(np, "gpmc,oe-off-ns", &gpmc_t->oe_off);
-
-	/* access and cycle timings */
-	of_property_read_u32(np, "gpmc,page-burst-access-ns",
-			     &gpmc_t->page_burst_access);
-	of_property_read_u32(np, "gpmc,access-ns", &gpmc_t->access);
-	of_property_read_u32(np, "gpmc,rd-cycle-ns", &gpmc_t->rd_cycle);
-	of_property_read_u32(np, "gpmc,wr-cycle-ns", &gpmc_t->wr_cycle);
-	of_property_read_u32(np, "gpmc,bus-turnaround-ns",
-			     &gpmc_t->bus_turnaround);
-	of_property_read_u32(np, "gpmc,cycle2cycle-delay-ns",
-			     &gpmc_t->cycle2cycle_delay);
-	of_property_read_u32(np, "gpmc,wait-monitoring-ns",
-			     &gpmc_t->wait_monitoring);
-	of_property_read_u32(np, "gpmc,clk-activation-ns",
-			     &gpmc_t->clk_activation);
-
-	/* only applicable to OMAP3+ */
-	of_property_read_u32(np, "gpmc,wr-access-ns", &gpmc_t->wr_access);
-	of_property_read_u32(np, "gpmc,wr-data-mux-bus-ns",
-			     &gpmc_t->wr_data_mux_bus);
-
-	/* bool timing parameters */
-	p = &gpmc_t->bool_timings;
-
-	p->cycle2cyclediffcsen =
-		of_property_read_bool(np, "gpmc,cycle2cycle-diffcsen");
-	p->cycle2cyclesamecsen =
-		of_property_read_bool(np, "gpmc,cycle2cycle-samecsen");
-	p->we_extra_delay = of_property_read_bool(np, "gpmc,we-extra-delay");
-	p->oe_extra_delay = of_property_read_bool(np, "gpmc,oe-extra-delay");
-	p->adv_extra_delay = of_property_read_bool(np, "gpmc,adv-extra-delay");
-	p->cs_extra_delay = of_property_read_bool(np, "gpmc,cs-extra-delay");
-	p->time_para_granularity =
-		of_property_read_bool(np, "gpmc,time-para-granularity");
-}
-
-/**
- * gpmc_probe_generic_child - configures the gpmc for a child device
- * @pdev:	pointer to gpmc platform device
- * @child:	pointer to device-tree node for child device
- *
- * Allocates and configures a GPMC chip-select for a child device.
- * Returns 0 on success and appropriate negative error code on failure.
- */
-static int gpmc_probe_generic_child(struct platform_device *pdev,
-				struct device_node *child)
-{
-	struct gpmc_settings gpmc_s;
-	struct gpmc_timings gpmc_t;
-	struct resource res;
-	unsigned long base;
-	int ret, cs;
-	struct device *dev = &pdev->dev;
-
-	if (of_property_read_u32(child, "reg", &cs) < 0) {
-		dev_err(&pdev->dev, "%s has no 'reg' property\n",
-			child->full_name);
-		return -ENODEV;
-	}
-
-	if (of_address_to_resource(child, 0, &res) < 0) {
-		dev_err(&pdev->dev, "%s has malformed 'reg' property\n",
-			child->full_name);
-		return -ENODEV;
-	}
-
-	ret = gpmc_cs_request(cs, resource_size(&res), &base);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "cannot request GPMC CS %d\n", cs);
-		return ret;
-	}
-
-	/*
-	 * For some GPMC devices we still need to rely on the bootloader
-	 * timings because the devices can be connected via FPGA. So far
-	 * the list is smc91x on the omap2 SDP boards, and 8250 on zooms.
-	 * REVISIT: Add timing support from slls644g.pdf and from the
-	 * lan91c96 manual.
-	 */
-	if (of_device_is_compatible(child, "ns16550a") ||
-	    of_device_is_compatible(child, "smsc,lan91c94") ||
-	    of_device_is_compatible(child, "smsc,lan91c111")) {
-		dev_warn(&pdev->dev,
-			 "%s using bootloader timings on CS%d\n",
-			 child->name, cs);
-		goto no_timings;
-	}
-
-	/*
-	 * FIXME: gpmc_cs_request() will map the CS to an arbitary
-	 * location in the gpmc address space. When booting with
-	 * device-tree we want the NOR flash to be mapped to the
-	 * location specified in the device-tree blob. So remap the
-	 * CS to this location. Once DT migration is complete should
-	 * just make gpmc_cs_request() map a specific address.
-	 */
-	ret = gpmc_cs_remap(cs, res.start);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "cannot remap GPMC CS %d to %pa\n",
-			cs, &res.start);
-		goto err;
-	}
-
-	gpmc_read_settings_dt(child, &gpmc_s);
-
-	if (of_node_cmp(child->name, "nand") == 0) {
-		/* NAND specific setup */
-		u32 val;
-
-		val = of_get_nand_bus_width(child);
-		switch (val) {
-		case 8:
-			gpmc_s.device_width = GPMC_DEVWIDTH_8BIT;
-			break;
-		case 16:
-			gpmc_s.device_width = GPMC_DEVWIDTH_16BIT;
-			break;
-		default:
-			dev_err(dev, "%s: invalid 'nand-bus-width'\n",
-				child->name);
-			ret = -EINVAL;
-			goto err;
-		}
-
-		gpmc_s.device_nand = true;
-
-	} else if (of_node_cmp(child->name, "onenand") == 0) {
-		/* DT incorrectly sets sync modes, onenand default is async */
-		gpmc_s.sync_read = false;
-		gpmc_s.sync_write = false;
-
-	} else {
-		if (of_property_read_u32(child, "bank-width",
-					 &gpmc_s.device_width)) {
-			dev_err(dev, "%s: no 'bank-width' property\n",
-				child->name);
-			goto err;
-		}
-
-		if (gpmc_s.device_width < 1 || gpmc_s.device_width > 2) {
-			dev_err(dev, "%s: invalid 'bank-width'\n",
-				child->name);
-			goto err;
-		}
-	}
-
-	ret = gpmc_cs_program_settings(cs, &gpmc_s);
-	if (ret < 0)
-		goto err;
-
-	gpmc_read_timings_dt(child, &gpmc_t);
-	gpmc_cs_set_timings(cs, &gpmc_t);
-
-no_timings:
-	if (of_platform_device_create(child, NULL, &pdev->dev))
-		return 0;
-
-	dev_err(&pdev->dev, "failed to create gpmc child %s\n", child->name);
-	ret = -ENODEV;
-
-err:
-	gpmc_cs_free(cs);
-
-	return ret;
-}
-
-static int gpmc_probe_dt(struct platform_device *pdev)
-{
-	int ret;
-	struct device_node *child;
-
-	ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-cs",
-				   &gpmc_cs_num);
-	if (ret < 0) {
-		pr_err("%s: number of chip-selects not defined\n", __func__);
-		return ret;
-	} else if (gpmc_cs_num < 1) {
-		pr_err("%s: all chip-selects are disabled\n", __func__);
-		return -EINVAL;
-	} else if (gpmc_cs_num > GPMC_CS_NUM) {
-		pr_err("%s: number of supported chip-selects cannot be > %d\n",
-					 __func__, GPMC_CS_NUM);
-		return -EINVAL;
-	}
-
-	ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-waitpins",
-				   &gpmc_nr_waitpins);
-	if (ret < 0) {
-		pr_err("%s: number of wait pins not found!\n", __func__);
-		return ret;
-	}
-
-	for_each_child_of_node(pdev->dev.of_node, child) {
-
-		if (!child->name)
-			continue;
-
-		if (of_node_cmp(child->name, "ethernet") == 0 ||
-		    of_node_cmp(child->name, "nor") == 0 ||
-		    of_node_cmp(child->name, "uart") == 0 ||
-		    of_node_cmp(child->name, "nand") == 0 ||
-		    of_node_cmp(child->name, "onenand") == 0)
-			ret = gpmc_probe_generic_child(pdev, child);
-
-		if (WARN(ret < 0, "%s: probing gpmc child %s failed\n",
-			 __func__, child->full_name))
-			of_node_put(child);
-	}
-
-	return 0;
-}
-#else
-static int gpmc_probe_dt(struct platform_device *pdev)
-{
-	return 0;
-}
-#endif
-
-static int gpmc_nand_setup(struct platform_device *parent_pdev,
-			   struct gpmc_omap_cs_data *cs)
-{
-	struct resource *res;
-	struct resource *res_gpmc;
-
-	if (!cs->pdev)
-		return -EINVAL;
-
-	res = cs->pdev->resource;
-
-	if (cs->pdev->num_resources < 3)
-		return -EINVAL;
-
-	if (resource_type(&res[1]) != IORESOURCE_MEM ||
-	    resource_type(&res[2]) != IORESOURCE_IRQ)
-		return -EINVAL;
-
-	if (!cs->settings)
-		return -EINVAL;
-
-	/* GPMC register space */
-	res_gpmc = platform_get_resource(parent_pdev, IORESOURCE_MEM, 0);
-	if (!res_gpmc)
-		return -EINVAL;
-
-	res[1] = *res_gpmc;
-
-	/* setup IRQ resources */
-	res[2].start = gpmc_irq;
-
-	cs->settings->device_nand = true;
-
-	return 0;
-}
-
-static void gpmc_probe_legacy(struct platform_device *pdev)
-{
-	int i, rc, j;
-	struct device *dev = &pdev->dev;
-	struct gpmc_omap_platform_data *gpmc_pdata;
-	struct resource *mem_res;
-	unsigned long cs_base;
-	resource_size_t size;
-	struct gpmc_timings gpmc_timings;
-	struct gpmc_omap_cs_data *cs;
-
-	gpmc_pdata = dev->platform_data;
-	gpmc_cs_num = GPMC_CS_NUM;
-	gpmc_nr_waitpins = GPMC_NR_WAITPINS;
-
-	for (i = 0; i < GPMC_CS_NUM; i++) {
-		cs = &gpmc_pdata->cs[i];
-		if (!cs->valid)
-			continue;
-
-		if (cs->settings) {
-			if (gpmc_cs_program_settings(i, cs->settings)) {
-				dev_err(dev,
-					"Couldn't program settings for CS %d\n",
-					i);
-				continue;
-			}
-		}
-
-		/* give device_timings priority over gpmc_timings */
-		if (cs->device_timings) {
-			gpmc_calc_timings(&gpmc_timings, cs->settings,
-					  cs->device_timings);
-
-			if (gpmc_cs_set_timings(i, &gpmc_timings)) {
-				dev_err(dev,
-					"Couldn't program timings for CS %d\n",
-					i);
-				continue;
-			}
-		} else if (cs->gpmc_timings) {
-			if (gpmc_cs_set_timings(i, cs->gpmc_timings)) {
-				dev_err(dev,
-					"Couldn't program timings for CS %d\n",
-					i);
-				continue;
-			}
-		}
-	}
-
-	/*
-	 * All Chip Selects must be configured before platform devices are
-	 * created as some devices (e.g. tusb6010) can use multiple
-	 * Chip selects.
-	 */
-
-	/* Fixup Memory resources */
-	for (i = 0; i < GPMC_CS_NUM; i++) {
-		int required_resources;
-
-		cs = &gpmc_pdata->cs[i];
-		if (!cs->valid)
-			continue;
-
-		if (!cs->pdev)
-			continue;
-
-		/* Customized NAND setup */
-		if (cs->is_nand) {
-			if (gpmc_nand_setup(pdev, cs)) {
-				dev_err(dev, "Error setting up NAND on CS %d\n",
-					i);
-				continue;
-			}
-		}
-
-		mem_res = cs->pdev->resource;
-
-		/*
-		 * If device is present multiple times, fix the subsequent
-		 * resources
-		 */
-		required_resources = 1;
-		for (j = 0; j < i; j++) {
-			if (gpmc_pdata->cs[j].pdev == cs->pdev) {
-				mem_res++;
-				required_resources++;
-			}
-		}
-
-		if (cs->pdev->num_resources < required_resources ||
-		    resource_type(mem_res) != IORESOURCE_MEM) {
-			dev_err(dev, "Invalid IOMEM resource for CS %d\n", i);
-			continue;
-		}
-
-		/*
-		 * Request a CS space. Use size from
-		 * platform device's MEM resource
-		 */
-		size = mem_res->end - mem_res->start + 1;
-		if (gpmc_cs_request(i, size, &cs_base)) {
-			dev_err(dev, "Couldn't request resource for CS %d\n",
-				i);
-			continue;
-		}
-
-		mem_res->start = cs_base;
-		mem_res->end = cs_base + size - 1;
-	}
-
-	/* create the platform devices */
-	for (i = 0; i < GPMC_CS_NUM; i++) {
-		bool registered;
-
-		cs = &gpmc_pdata->cs[i];
-		if (!cs->valid)
-			continue;
-
-		if (!cs->pdev)
-			continue;
-
-		/*
-		 * same device can be present on multiple CS, don't
-		 * register device more than once.
-		 */
-		registered = false;
-		for (j = 0; j < i; j++) {
-			if (gpmc_pdata->cs[j].pdev == cs->pdev) {
-				registered = true;
-				break;
-			}
-		}
-
-		if (registered)
-			continue;
-
-		cs->pdev->dev.parent = dev;
-		rc = platform_device_register(cs->pdev);
-		if (rc < 0) {
-			dev_err(dev,
-				"Failed to register device %s on CS %d\n",
-				cs->pdev->name, i);
-			continue;
-		}
-	}
-}
-
-static int gpmc_probe(struct platform_device *pdev)
-{
-	int rc;
-	u32 l;
-	struct resource *res;
-	struct device *dev = &pdev->dev;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res == NULL)
-		return -ENOENT;
-
-	phys_base = res->start;
-	mem_size = resource_size(res);
-
-	gpmc_base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(gpmc_base))
-		return PTR_ERR(gpmc_base);
-
-	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "Failed to get resource: irq\n");
-		return -EINVAL;
-	}
-
-	gpmc_irq = res->start;
-
-	gpmc_l3_clk = clk_get(&pdev->dev, "fck");
-	if (IS_ERR(gpmc_l3_clk)) {
-		dev_err(&pdev->dev, "error: clk_get\n");
-		gpmc_irq = 0;
-		return PTR_ERR(gpmc_l3_clk);
-	}
-
-	pm_runtime_enable(&pdev->dev);
-	pm_runtime_get_sync(&pdev->dev);
-
-	gpmc_dev = dev;
-
-	l = gpmc_read_reg(GPMC_REVISION);
-
-	/*
-	 * FIXME: Once device-tree migration is complete the below flags
-	 * should be populated based upon the device-tree compatible
-	 * string. For now just use the IP revision. OMAP3+ devices have
-	 * the wr_access and wr_data_mux_bus register fields. OMAP4+
-	 * devices support the addr-addr-data multiplex protocol.
-	 *
-	 * GPMC IP revisions:
-	 * - OMAP24xx			= 2.0
-	 * - OMAP3xxx			= 5.0
-	 * - OMAP44xx/54xx/AM335x	= 6.0
-	 */
-	if (GPMC_REVISION_MAJOR(l) > 0x4)
-		gpmc_capability = GPMC_HAS_WR_ACCESS | GPMC_HAS_WR_DATA_MUX_BUS;
-	if (GPMC_REVISION_MAJOR(l) > 0x5)
-		gpmc_capability |= GPMC_HAS_MUX_AAD;
-	dev_info(dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l),
-		 GPMC_REVISION_MINOR(l));
-
-	gpmc_mem_init();
-
-	/* Now the GPMC is initialised, unreserve the chip-selects */
-	gpmc_cs_map = 0;
-
-	if (dev->of_node) {
-		rc = gpmc_probe_dt(pdev);
-		if (rc) {
-			dev_err(dev, "gpmc_probe_dt() failed\n");
-			goto error;
-		}
-	} else {
-		/* Legacy probing based on platform data */
-		if (!dev->platform_data) {
-			dev_err(dev, "No platform data\n");
-			rc = -EINVAL;
-			goto error;
-		}
-
-		gpmc_probe_legacy(pdev);
-	}
-
-	return 0;
-
-error:
-	pm_runtime_put_sync(dev);
-	clk_put(gpmc_l3_clk);
-	return rc;
-}
-
-static int gpmc_remove(struct platform_device *pdev)
-{
-	gpmc_mem_exit();
-	pm_runtime_put_sync(&pdev->dev);
-	pm_runtime_disable(&pdev->dev);
-	gpmc_dev = NULL;
-	return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int gpmc_suspend(struct device *dev)
-{
-	omap3_gpmc_save_context();
-	pm_runtime_put_sync(dev);
-	return 0;
-}
-
-static int gpmc_resume(struct device *dev)
-{
-	pm_runtime_get_sync(dev);
-	omap3_gpmc_restore_context();
-	return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(gpmc_pm_ops, gpmc_suspend, gpmc_resume);
-
-static struct platform_driver gpmc_driver = {
-	.probe		= gpmc_probe,
-	.remove		= gpmc_remove,
-	.driver		= {
-		.name	= DEVICE_NAME,
-		.owner	= THIS_MODULE,
-		.of_match_table = of_match_ptr(gpmc_dt_ids),
-		.pm	= &gpmc_pm_ops,
-	},
-};
-
-static __init int gpmc_init(void)
-{
-	return platform_driver_register(&gpmc_driver);
-}
-
-static __exit void gpmc_exit(void)
-{
-	platform_driver_unregister(&gpmc_driver);
-
-}
-
-module_init(gpmc_init);
-module_exit(gpmc_exit);
-
-static int __init omap_gpmc_init(void)
-{
-	struct omap_hwmod *oh;
-	struct platform_device *pdev;
-	char *oh_name = "gpmc";
-
-	/*
-	 * if the board boots up with a populated DT, do not
-	 * manually add the device from this initcall
-	 */
-	if (of_have_populated_dt())
-		return -ENODEV;
-
-	oh = omap_hwmod_lookup(oh_name);
-	if (!oh) {
-		pr_err("Could not look up %s\n", oh_name);
-		return -ENODEV;
-	}
-
-	pdev = omap_device_build(DEVICE_NAME, -1, oh, (void *)&gpmc_pdata,
-				 sizeof(gpmc_pdata));
-	WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
-
-	return PTR_RET(pdev);
-}
-/* must run after machine_init code. i.e. arch_init */
-omap_subsys_initcall(omap_gpmc_init);
-
-/**
- * gpmc_generic_init - Initialize platform data for a Chip Select
- *
- * @cs		chip select number
- * @is_nand	true if device is NAND flash.
- * @settings	GPMC settings
- * @device_timings	device timings for device on this CS
- * @gpmc_timings	GPMC timings
- * @pdev	platform device for the device on this CS
- * @pdata_size	platform data size for the platform device
- */
-int gpmc_generic_init(int cs, bool is_nand,
-		      struct gpmc_settings *settings,
-		      struct gpmc_device_timings *device_timings,
-		      struct gpmc_timings *gpmc_timings,
-		      struct platform_device *pdev, unsigned pdata_size)
-{
-	struct gpmc_settings *gpmc_s = NULL;
-	struct gpmc_device_timings *gpmc_dev_t = NULL;
-	struct gpmc_timings *gpmc_t;
-
-	if (cs >= GPMC_CS_NUM) {
-		pr_err("%s: Invalid cs specified. Max CS = %d\n",
-		       __func__, GPMC_CS_NUM);
-		return -EINVAL;
-	}
-
-	if (gpmc_pdata.cs[cs].valid) {
-		pr_err("%s: cs %d already requested, ignoring new request\n",
-		       __func__, cs);
-		return -EINVAL;
-	}
-
-	if (settings) {
-		gpmc_s = kmemdup(settings, sizeof(*settings), GFP_KERNEL);
-		if (!gpmc_s)
-			return -ENOMEM;
-
-		gpmc_pdata.cs[cs].settings = gpmc_s;
-	}
-
-	if (device_timings) {
-		gpmc_dev_t = kmemdup(device_timings, sizeof(*device_timings),
-				     GFP_KERNEL);
-		if (!gpmc_dev_t)
-			goto dev_t_fail;
-
-		gpmc_pdata.cs[cs].device_timings = gpmc_dev_t;
-	}
-
-	if (gpmc_timings) {
-		gpmc_t = kmemdup(gpmc_timings, sizeof(*gpmc_timings),
-				 GFP_KERNEL);
-		if (!gpmc_t)
-			goto gpmc_t_fail;
-
-		gpmc_pdata.cs[cs].gpmc_timings = gpmc_t;
-	}
-
-	gpmc_pdata.cs[cs].is_nand = is_nand;
-	gpmc_pdata.cs[cs].pdev = pdev;
-	gpmc_pdata.cs[cs].pdata_size = pdata_size;
-	gpmc_pdata.cs[cs].valid = true;
-
-	return 0;
-
-gpmc_t_fail:
-	if (device_timings)
-		kfree(gpmc_dev_t);
-dev_t_fail:
-	if (settings)
-		kfree(gpmc_s);
-
-	return -ENOMEM;
-}
-
-/**
- * omap_gpmc_retime - Reconfigre GPMC timings for the device
- *
- * @cs		Chip select number
- * @gpmc_s	GPMC settings
- * @dev_t	New device timings to set
- */
-int omap_gpmc_retime(int cs, struct gpmc_settings *gpmc_s,
-		     struct gpmc_device_timings *dev_t)
-{
-	struct gpmc_timings gpmc_t;
-	struct device *dev = gpmc_dev;
-
-	if (!gpmc_dev)
-		return -ENODEV;
-
-	if (cs < 0 || cs >= gpmc_cs_num) {
-		dev_err(dev, "%s: Invalid find Chip Select\n", __func__);
-		return cs;
-	}
-
-	if (gpmc_cs_program_settings(cs, gpmc_s)) {
-		dev_err(dev, "%s: Failed to set GPMC settings\n", __func__);
-		return -EINVAL;
-	}
-
-	gpmc_calc_timings(&gpmc_t, gpmc_s, dev_t);
-	if (gpmc_cs_set_timings(cs, &gpmc_t)) {
-		dev_err(dev, "%s: Failed to set GPMC timings\n", __func__);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(omap_gpmc_retime);
-
-/**
- * omap_gpmc_get_clk_period - Get the nearest possible (equal to or higer) GPMC
- *				synchronous clock (GPMC_CLK) period.
- *
- * @cs		Chip select number
- * @min_ps	Minimum synchronous clock period supporded by the device
- *
- * Returns the nearest possible GPMC clock period in picoseconds, equal to or
- * higher than the requested period. 0 in case of error.
- */
-unsigned long omap_gpmc_get_clk_period(int cs,
-				       unsigned long min_ps)
-{
-	int div;
-	unsigned long clk_ps;
-	struct device *dev = gpmc_dev;
-
-	if (!gpmc_dev)
-		return 0;
-
-	if (cs < 0 || cs >= gpmc_cs_num) {
-		dev_err(dev, "%s: Invalid Chip Select\n", __func__);
-		return cs;
-	}
-
-	div = gpmc_calc_divider(min_ps);
-	if (div < 0) {
-		dev_err(dev, "%s: Can't support requested clock period %lu ps\n",
-			__func__, min_ps);
-		return 0;
-	}
-
-	clk_ps = gpmc_get_fclk_period() * div;
-
-	return clk_ps;
-}
-EXPORT_SYMBOL_GPL(omap_gpmc_get_clk_period);
-
-static struct omap3_gpmc_regs gpmc_context;
-
-void omap3_gpmc_save_context(void)
-{
-	int i;
-
-	gpmc_context.sysconfig = gpmc_read_reg(GPMC_SYSCONFIG);
-	gpmc_context.irqenable = gpmc_read_reg(GPMC_IRQENABLE);
-	gpmc_context.timeout_ctrl = gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
-	gpmc_context.config = gpmc_read_reg(GPMC_CONFIG);
-	gpmc_context.prefetch_config1 = gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
-	gpmc_context.prefetch_config2 = gpmc_read_reg(GPMC_PREFETCH_CONFIG2);
-	gpmc_context.prefetch_control = gpmc_read_reg(GPMC_PREFETCH_CONTROL);
-	for (i = 0; i < gpmc_cs_num; i++) {
-		gpmc_context.cs_context[i].is_valid = gpmc_cs_mem_enabled(i);
-		if (gpmc_context.cs_context[i].is_valid) {
-			gpmc_context.cs_context[i].config1 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG1);
-			gpmc_context.cs_context[i].config2 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG2);
-			gpmc_context.cs_context[i].config3 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG3);
-			gpmc_context.cs_context[i].config4 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG4);
-			gpmc_context.cs_context[i].config5 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG5);
-			gpmc_context.cs_context[i].config6 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG6);
-			gpmc_context.cs_context[i].config7 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
-		}
-	}
-}
-
-void omap3_gpmc_restore_context(void)
-{
-	int i;
-
-	gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig);
-	gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable);
-	gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl);
-	gpmc_write_reg(GPMC_CONFIG, gpmc_context.config);
-	gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1);
-	gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2);
-	gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control);
-	for (i = 0; i < gpmc_cs_num; i++) {
-		if (gpmc_context.cs_context[i].is_valid) {
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG1,
-				gpmc_context.cs_context[i].config1);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG2,
-				gpmc_context.cs_context[i].config2);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG3,
-				gpmc_context.cs_context[i].config3);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG4,
-				gpmc_context.cs_context[i].config4);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG5,
-				gpmc_context.cs_context[i].config5);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG6,
-				gpmc_context.cs_context[i].config6);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG7,
-				gpmc_context.cs_context[i].config7);
-		}
-	}
-}
diff --git a/arch/arm/mach-omap2/gpmc_legacy.c b/arch/arm/mach-omap2/gpmc_legacy.c
new file mode 100644
index 0000000..3b3f86e
--- /dev/null
+++ b/arch/arm/mach-omap2/gpmc_legacy.c
@@ -0,0 +1,296 @@
+/*
+ * GPMC support functions
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation
+ *
+ * Author: Juha Yrjola
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#include "soc.h"
+#include "gpmc.h"
+#include "omap_device.h"
+
+#define	DEVICE_NAME		"omap-gpmc"
+
+/* CS CONFIG registers */
+#define GPMC_CS_CONFIG1		0x00
+#define GPMC_CS_CONFIG2		0x04
+#define GPMC_CS_CONFIG3		0x08
+#define GPMC_CS_CONFIG4		0x0c
+#define GPMC_CS_CONFIG5		0x10
+#define GPMC_CS_CONFIG6		0x14
+#define GPMC_CS_CONFIG7		0x18
+
+#define GPMC_CS0_OFFSET		0x60
+#define GPMC_CS_SIZE		0x30
+
+/* GPMC register offsets */
+#define GPMC_SYSCONFIG		0x10
+#define GPMC_IRQENABLE		0x1c
+#define GPMC_TIMEOUT_CONTROL	0x40
+#define GPMC_CONFIG		0x50
+#define GPMC_PREFETCH_CONFIG1	0x1e0
+#define GPMC_PREFETCH_CONFIG2	0x1e4
+#define GPMC_PREFETCH_CONTROL	0x1ec
+
+#define GPMC_CONFIG7_CSVALID		(1 << 6)
+
+static struct gpmc_omap_platform_data gpmc_pdata;
+
+/* Structure to save gpmc cs context */
+struct gpmc_cs_config {
+	u32 config1;
+	u32 config2;
+	u32 config3;
+	u32 config4;
+	u32 config5;
+	u32 config6;
+	u32 config7;
+	int is_valid;
+};
+
+/*
+ * Structure to save/restore gpmc context
+ * to support core off on OMAP3
+ */
+struct omap3_gpmc_regs {
+	u32 sysconfig;
+	u32 irqenable;
+	u32 timeout_ctrl;
+	u32 config;
+	u32 prefetch_config1;
+	u32 prefetch_config2;
+	u32 prefetch_control;
+	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
+};
+
+static int __init omap_gpmc_init(void)
+{
+	struct omap_hwmod *oh;
+	struct platform_device *pdev;
+	char *oh_name = "gpmc";
+
+	/*
+	 * if the board boots up with a populated DT, do not
+	 * manually add the device from this initcall
+	 */
+	if (of_have_populated_dt())
+		return -ENODEV;
+
+	oh = omap_hwmod_lookup(oh_name);
+	if (!oh) {
+		pr_err("Could not look up %s\n", oh_name);
+		return -ENODEV;
+	}
+
+	pdev = omap_device_build(DEVICE_NAME, -1, oh, (void *)&gpmc_pdata,
+				 sizeof(gpmc_pdata));
+	WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
+
+	return PTR_RET(pdev);
+}
+/* must run after machine_init code. i.e. arch_init */
+omap_subsys_initcall(omap_gpmc_init);
+
+/**
+ * gpmc_generic_init - Initialize platform data for a Chip Select
+ *
+ * @cs		chip select number
+ * @type	GPMC_OMAP_TYPE
+ * @settings	GPMC settings
+ * @device_timings	device timings for device on this CS
+ * @gpmc_timings	GPMC timings
+ * @pdev	platform device for the device on this CS
+ * @pdata_size	platform data size for the platform device
+ */
+int gpmc_generic_init(int cs, bool is_nand,
+		      struct gpmc_settings *settings,
+		      struct gpmc_device_timings *device_timings,
+		      struct gpmc_timings *gpmc_timings,
+		      struct platform_device *pdev, unsigned pdata_size)
+{
+	struct gpmc_settings *gpmc_s = NULL;
+	struct gpmc_device_timings *gpmc_dev_t = NULL;
+	struct gpmc_timings *gpmc_t;
+
+	if (cs >= GPMC_CS_NUM) {
+		pr_err("%s: Invalid cs specified. Max CS = %d\n",
+		       __func__, GPMC_CS_NUM);
+		return -EINVAL;
+	}
+
+	if (gpmc_pdata.cs[cs].valid) {
+		pr_err("%s: cs %d already requested, ignoring new request\n",
+		       __func__, cs);
+		return -EINVAL;
+	}
+
+	if (settings) {
+		gpmc_s = kmemdup(settings, sizeof(*settings), GFP_KERNEL);
+		if (!gpmc_s)
+			return -ENOMEM;
+
+		gpmc_pdata.cs[cs].settings = gpmc_s;
+	}
+
+	if (device_timings) {
+		gpmc_dev_t = kmemdup(device_timings, sizeof(*device_timings),
+				     GFP_KERNEL);
+		if (!gpmc_dev_t)
+			goto dev_t_fail;
+
+		gpmc_pdata.cs[cs].device_timings = gpmc_dev_t;
+	}
+
+	if (gpmc_timings) {
+		gpmc_t = kmemdup(gpmc_timings, sizeof(*gpmc_timings),
+				 GFP_KERNEL);
+		if (!gpmc_t)
+			goto gpmc_t_fail;
+
+		gpmc_pdata.cs[cs].gpmc_timings = gpmc_t;
+	}
+
+	gpmc_pdata.cs[cs].is_nand = is_nand;
+	gpmc_pdata.cs[cs].pdev = pdev;
+	gpmc_pdata.cs[cs].pdata_size = pdata_size;
+	gpmc_pdata.cs[cs].valid = true;
+
+	return 0;
+
+gpmc_t_fail:
+	if (device_timings)
+		kfree(gpmc_dev_t);
+dev_t_fail:
+	if (settings)
+		kfree(gpmc_s);
+
+	return -ENOMEM;
+}
+
+
+static struct omap3_gpmc_regs gpmc_context;
+
+/*
+ * Below code only for OMAP3 OFF mode support.
+ * This code must be left back in mach-omap2.
+ */
+void __iomem *omap2_gpmc_base;
+
+void __init omap2_set_globals_gpmc(void __iomem *gpmc)
+{
+	omap2_gpmc_base = gpmc;
+}
+
+static u32 _gpmc_read_reg(u16 reg)
+{
+	return __raw_readl(omap2_gpmc_base + reg);
+}
+
+static void _gpmc_write_reg(u32 val, u16 reg)
+{
+	__raw_readl(omap2_gpmc_base + reg);
+}
+
+static u32 _gpmc_cs_read_reg(int cs, int idx)
+{
+	u16 reg;
+
+	reg = GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
+
+	return _gpmc_read_reg(reg);
+}
+
+static void _gpmc_cs_write_reg(int cs, int idx, u32 val)
+{
+	u16 reg;
+
+	reg = GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
+	_gpmc_write_reg(val, reg);
+}
+
+void omap3_gpmc_save_context(void)
+{
+	int i;
+	u32 val;
+
+	if (!omap2_gpmc_base)
+		return;
+
+	gpmc_context.sysconfig = _gpmc_read_reg(GPMC_SYSCONFIG);
+	gpmc_context.irqenable = _gpmc_read_reg(GPMC_IRQENABLE);
+	gpmc_context.timeout_ctrl = _gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
+	gpmc_context.config = _gpmc_read_reg(GPMC_CONFIG);
+	gpmc_context.prefetch_config1 = _gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
+	gpmc_context.prefetch_config2 = _gpmc_read_reg(GPMC_PREFETCH_CONFIG2);
+	gpmc_context.prefetch_control = _gpmc_read_reg(GPMC_PREFETCH_CONTROL);
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		/* check if valid */
+		val = _gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
+		gpmc_context.cs_context[i].is_valid =
+						val & GPMC_CONFIG7_CSVALID;
+
+		if (gpmc_context.cs_context[i].is_valid) {
+			gpmc_context.cs_context[i].config1 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG1);
+			gpmc_context.cs_context[i].config2 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG2);
+			gpmc_context.cs_context[i].config3 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG3);
+			gpmc_context.cs_context[i].config4 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG4);
+			gpmc_context.cs_context[i].config5 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG5);
+			gpmc_context.cs_context[i].config6 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG6);
+			gpmc_context.cs_context[i].config7 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
+		}
+	}
+}
+
+void omap3_gpmc_restore_context(void)
+{
+	int i;
+
+	if (!omap2_gpmc_base)
+		return;
+
+	_gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig);
+	_gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable);
+	_gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl);
+	_gpmc_write_reg(GPMC_CONFIG, gpmc_context.config);
+	_gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1);
+	_gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2);
+	_gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control);
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		if (gpmc_context.cs_context[i].is_valid) {
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG1,
+					   gpmc_context.cs_context[i].config1);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG2,
+					   gpmc_context.cs_context[i].config2);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG3,
+					   gpmc_context.cs_context[i].config3);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG4,
+					   gpmc_context.cs_context[i].config4);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG5,
+					   gpmc_context.cs_context[i].config5);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG6,
+					   gpmc_context.cs_context[i].config6);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG7,
+					   gpmc_context.cs_context[i].config7);
+		}
+	}
+}
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index c59e9c9..ce611b0 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -31,6 +31,16 @@ config TI_EMIF
 	  parameters and other settings during frequency, voltage and
 	  temperature changes
 
+config TI_GPMC
+	bool "Texas Instruments GPMC driver"
+	depends on ARCH_OMAP2PLUS
+	default y
+	help
+	 This driver is for the General Purpose Memory Controller (GPMC)
+	 present on Texas Instruments SoCs (e.g. OMAP2+). GPMC allows
+	 interfacing to a variety of asynchronous as well as synchronous
+	 memory drives like NOR, NAND, OneNAND, SRAM.
+
 config MVEBU_DEVBUS
 	bool "Marvell EBU Device Bus Controller"
 	default y
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index 71160a2..329b7b6 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_OF)		+= of_memory.o
 endif
 obj-$(CONFIG_TI_AEMIF)		+= ti-aemif.o
 obj-$(CONFIG_TI_EMIF)		+= emif.o
+obj-$(CONFIG_TI_GPMC)		+= ti-gpmc.o
 obj-$(CONFIG_FSL_IFC)		+= fsl_ifc.o
 obj-$(CONFIG_MVEBU_DEVBUS)	+= mvebu-devbus.o
 obj-$(CONFIG_TEGRA20_MC)	+= tegra20-mc.o
diff --git a/drivers/memory/ti-gpmc.c b/drivers/memory/ti-gpmc.c
new file mode 100644
index 0000000..3bb2fd6
--- /dev/null
+++ b/drivers/memory/ti-gpmc.c
@@ -0,0 +1,1829 @@
+/*
+ * GPMC support functions
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation
+ *
+ * Author: Juha Yrjola
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.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.
+ */
+#undef DEBUG
+
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_mtd.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+
+#include <linux/platform_data/mtd-nand-omap2.h>
+#include <linux/platform_data/gpmc-omap.h>
+
+#define	DEVICE_NAME		"omap-gpmc"
+
+/* GPMC register offsets */
+#define GPMC_REVISION		0x00
+#define GPMC_SYSCONFIG		0x10
+#define GPMC_SYSSTATUS		0x14
+#define GPMC_IRQSTATUS		0x18
+#define GPMC_IRQENABLE		0x1c
+#define GPMC_TIMEOUT_CONTROL	0x40
+#define GPMC_ERR_ADDRESS	0x44
+#define GPMC_ERR_TYPE		0x48
+#define GPMC_CONFIG		0x50
+#define GPMC_STATUS		0x54
+#define GPMC_PREFETCH_CONFIG1	0x1e0
+#define GPMC_PREFETCH_CONFIG2	0x1e4
+#define GPMC_PREFETCH_CONTROL	0x1ec
+#define GPMC_PREFETCH_STATUS	0x1f0
+#define GPMC_ECC_CONFIG		0x1f4
+#define GPMC_ECC_CONTROL	0x1f8
+#define GPMC_ECC_SIZE_CONFIG	0x1fc
+#define GPMC_ECC1_RESULT        0x200
+#define GPMC_ECC_BCH_RESULT_0   0x240   /* not available on OMAP2 */
+#define	GPMC_ECC_BCH_RESULT_1	0x244	/* not available on OMAP2 */
+#define	GPMC_ECC_BCH_RESULT_2	0x248	/* not available on OMAP2 */
+#define	GPMC_ECC_BCH_RESULT_3	0x24c	/* not available on OMAP2 */
+
+/* GPMC ECC control settings */
+#define GPMC_ECC_CTRL_ECCCLEAR		0x100
+#define GPMC_ECC_CTRL_ECCDISABLE	0x000
+#define GPMC_ECC_CTRL_ECCREG1		0x001
+#define GPMC_ECC_CTRL_ECCREG2		0x002
+#define GPMC_ECC_CTRL_ECCREG3		0x003
+#define GPMC_ECC_CTRL_ECCREG4		0x004
+#define GPMC_ECC_CTRL_ECCREG5		0x005
+#define GPMC_ECC_CTRL_ECCREG6		0x006
+#define GPMC_ECC_CTRL_ECCREG7		0x007
+#define GPMC_ECC_CTRL_ECCREG8		0x008
+#define GPMC_ECC_CTRL_ECCREG9		0x009
+
+/* ECC commands */
+#define GPMC_ECC_READ		0 /* Reset Hardware ECC for read */
+#define GPMC_ECC_WRITE		1 /* Reset Hardware ECC for write */
+#define GPMC_ECC_READSYN	2 /* Reset before syndrom is read back */
+
+/* CS CONFIG registers */
+#define GPMC_CS_CONFIG1		0x00
+#define GPMC_CS_CONFIG2		0x04
+#define GPMC_CS_CONFIG3		0x08
+#define GPMC_CS_CONFIG4		0x0c
+#define GPMC_CS_CONFIG5		0x10
+#define GPMC_CS_CONFIG6		0x14
+#define GPMC_CS_CONFIG7		0x18
+
+#define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
+#define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
+#define GPMC_CONFIG1_READTYPE_ASYNC     (0 << 29)
+#define GPMC_CONFIG1_READTYPE_SYNC      (1 << 29)
+#define GPMC_CONFIG1_WRITEMULTIPLE_SUPP (1 << 28)
+#define GPMC_CONFIG1_WRITETYPE_ASYNC    (0 << 27)
+#define GPMC_CONFIG1_WRITETYPE_SYNC     (1 << 27)
+#define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val & 3) << 25)
+#define GPMC_CONFIG1_PAGE_LEN(val)      ((val & 3) << 23)
+#define GPMC_CONFIG1_WAIT_READ_MON      (1 << 22)
+#define GPMC_CONFIG1_WAIT_WRITE_MON     (1 << 21)
+#define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18)
+#define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val & 3) << 16)
+#define GPMC_CONFIG1_DEVICESIZE(val)    ((val & 3) << 12)
+#define GPMC_CONFIG1_DEVICESIZE_16      GPMC_CONFIG1_DEVICESIZE(1)
+#define GPMC_CONFIG1_DEVICETYPE(val)    ((val & 3) << 10)
+#define GPMC_CONFIG1_DEVICETYPE_NOR     GPMC_CONFIG1_DEVICETYPE(0)
+#define GPMC_CONFIG1_MUXTYPE(val)       ((val & 3) << 8)
+#define GPMC_CONFIG1_TIME_PARA_GRAN     (1 << 4)
+#define GPMC_CONFIG1_FCLK_DIV(val)      (val & 3)
+#define GPMC_CONFIG1_FCLK_DIV2          (GPMC_CONFIG1_FCLK_DIV(1))
+#define GPMC_CONFIG1_FCLK_DIV3          (GPMC_CONFIG1_FCLK_DIV(2))
+#define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
+#define GPMC_CONFIG7_CSVALID		(1 << 6)
+
+#define	GPMC_CONFIG2_CSEXTRADELAY		BIT(7)
+#define	GPMC_CONFIG3_ADVEXTRADELAY		BIT(7)
+#define	GPMC_CONFIG4_OEEXTRADELAY		BIT(7)
+#define	GPMC_CONFIG4_WEEXTRADELAY		BIT(23)
+#define	GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN	BIT(6)
+#define	GPMC_CONFIG6_CYCLE2CYCLESAMECSEN	BIT(7)
+
+#define GPMC_DEVICETYPE_NOR		0
+#define GPMC_DEVICETYPE_NAND		2
+#define WR_RD_PIN_MONITORING		0x00600000
+#define GPMC_IRQ_FIFOEVENTENABLE	0x01
+#define GPMC_IRQ_COUNT_EVENT		0x02
+
+#define GPMC_CS0_OFFSET		0x60
+#define GPMC_CS_SIZE		0x30
+#define	GPMC_BCH_SIZE		0x10
+
+#define GPMC_MEM_END		0x3FFFFFFF
+
+#define GPMC_CHUNK_SHIFT	24		/* 16 MB */
+#define GPMC_SECTION_SHIFT	28		/* 128 MB */
+
+#define CS_NUM_SHIFT		24
+#define ENABLE_PREFETCH		(0x1 << 7)
+#define DMA_MPU_MODE		2
+
+#define	GPMC_REVISION_MAJOR(l)		((l >> 4) & 0xf)
+#define	GPMC_REVISION_MINOR(l)		(l & 0xf)
+
+#define	GPMC_HAS_WR_ACCESS		0x1
+#define	GPMC_HAS_WR_DATA_MUX_BUS	0x2
+#define	GPMC_HAS_MUX_AAD		0x4
+
+#define GPMC_NR_WAITPINS		4
+
+static struct resource	gpmc_mem_root;
+static struct resource	gpmc_cs_mem[GPMC_CS_NUM];
+static DEFINE_SPINLOCK(gpmc_mem_lock);
+/* Define chip-selects as reserved by default until probe completes */
+static unsigned int gpmc_cs_map = ((1 << GPMC_CS_NUM) - 1);
+static unsigned int gpmc_cs_num = GPMC_CS_NUM;
+static unsigned int gpmc_nr_waitpins;
+static struct device *gpmc_dev;
+static int gpmc_irq = -EINVAL;
+static resource_size_t phys_base, mem_size;
+static unsigned gpmc_capability;
+static void __iomem *gpmc_base;
+
+static struct clk *gpmc_l3_clk;
+
+static void gpmc_write_reg(int idx, u32 val)
+{
+	__raw_writel(val, gpmc_base + idx);
+}
+
+static u32 gpmc_read_reg(int idx)
+{
+	return __raw_readl(gpmc_base + idx);
+}
+
+static void gpmc_cs_write_reg(int cs, int idx, u32 val)
+{
+	void __iomem *reg_addr;
+
+	reg_addr = gpmc_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
+	__raw_writel(val, reg_addr);
+}
+
+static u32 gpmc_cs_read_reg(int cs, int idx)
+{
+	void __iomem *reg_addr;
+
+	reg_addr = gpmc_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
+	return __raw_readl(reg_addr);
+}
+
+/* TODO: Add support for gpmc_fck to clock framework and use it */
+static unsigned long gpmc_get_fclk_period(void)
+{
+	unsigned long rate = clk_get_rate(gpmc_l3_clk);
+
+	if (rate == 0) {
+		pr_warn("%s: gpmc_l3_clk not enabled\n", __func__);
+		return 0;
+	}
+
+	rate /= 1000;
+	rate = 1000000000 / rate;	/* In picoseconds */
+
+	return rate;
+}
+
+static unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
+{
+	unsigned long tick_ps;
+
+	/* Calculate in picosecs to yield more exact results */
+	tick_ps = gpmc_get_fclk_period();
+
+	return (time_ns * 1000 + tick_ps - 1) / tick_ps;
+}
+
+static unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
+{
+	unsigned long tick_ps;
+
+	/* Calculate in picosecs to yield more exact results */
+	tick_ps = gpmc_get_fclk_period();
+
+	return (time_ps + tick_ps - 1) / tick_ps;
+}
+
+static unsigned int gpmc_ticks_to_ps(unsigned int ticks)
+{
+	return ticks * gpmc_get_fclk_period();
+}
+
+static unsigned int gpmc_round_ps_to_ticks(unsigned int time_ps)
+{
+	unsigned long ticks = gpmc_ps_to_ticks(time_ps);
+
+	return ticks * gpmc_get_fclk_period();
+}
+
+static inline void gpmc_cs_modify_reg(int cs, int reg, u32 mask, bool value)
+{
+	u32 l;
+
+	l = gpmc_cs_read_reg(cs, reg);
+	if (value)
+		l |= mask;
+	else
+		l &= ~mask;
+	gpmc_cs_write_reg(cs, reg, l);
+}
+
+static void gpmc_cs_bool_timings(int cs, const struct gpmc_bool_timings *p)
+{
+	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG1,
+			   GPMC_CONFIG1_TIME_PARA_GRAN,
+			   p->time_para_granularity);
+	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG2,
+			   GPMC_CONFIG2_CSEXTRADELAY, p->cs_extra_delay);
+	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG3,
+			   GPMC_CONFIG3_ADVEXTRADELAY, p->adv_extra_delay);
+	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG4,
+			   GPMC_CONFIG4_OEEXTRADELAY, p->oe_extra_delay);
+	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG4,
+			   GPMC_CONFIG4_OEEXTRADELAY, p->we_extra_delay);
+	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG6,
+			   GPMC_CONFIG6_CYCLE2CYCLESAMECSEN,
+			   p->cycle2cyclesamecsen);
+	gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG6,
+			   GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN,
+			   p->cycle2cyclediffcsen);
+}
+
+#ifdef DEBUG
+static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
+			       int time, const char *name)
+#else
+static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
+			       int time)
+#endif
+{
+	u32 l;
+	int ticks, mask, nr_bits;
+
+	if (time == 0)
+		ticks = 0;
+	else
+		ticks = gpmc_ns_to_ticks(time);
+	nr_bits = end_bit - st_bit + 1;
+	if (ticks >= 1 << nr_bits) {
+#ifdef DEBUG
+		pr_info("GPMC CS%d: %-10s* %3d ns, %3d ticks >= %d\n",
+			cs, name, time, ticks, 1 << nr_bits);
+#endif
+		return -1;
+	}
+
+	mask = (1 << nr_bits) - 1;
+	l = gpmc_cs_read_reg(cs, reg);
+#ifdef DEBUG
+	pr_info("GPMC CS%d: %-10s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n",
+		cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000,
+		(l >> st_bit) & mask, time);
+#endif
+	l &= ~(mask << st_bit);
+	l |= ticks << st_bit;
+	gpmc_cs_write_reg(cs, reg, l);
+
+	return 0;
+}
+
+#ifdef DEBUG
+#define GPMC_SET_ONE(reg, st, end, field) \
+	set_gpmc_timing_reg(cs, (reg), (st), (end),		\
+			t->field, #field)
+#else
+#define GPMC_SET_ONE(reg, st, end, field) \
+	set_gpmc_timing_reg(cs, (reg), (st), (end), t->field)
+#endif
+
+static int gpmc_calc_divider(unsigned int sync_clk)
+{
+	int div;
+	u32 l;
+
+	l = sync_clk + (gpmc_get_fclk_period() - 1);
+	div = l / gpmc_get_fclk_period();
+	if (div > 4)
+		return -1;
+	if (div <= 0)
+		div = 1;
+
+	return div;
+}
+
+static int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
+{
+	int div;
+	u32 l;
+
+	div = gpmc_calc_divider(t->sync_clk);
+	if (div < 0)
+		return div;
+
+	GPMC_SET_ONE(GPMC_CS_CONFIG2,  0,  3, cs_on);
+	GPMC_SET_ONE(GPMC_CS_CONFIG2,  8, 12, cs_rd_off);
+	GPMC_SET_ONE(GPMC_CS_CONFIG2, 16, 20, cs_wr_off);
+
+	GPMC_SET_ONE(GPMC_CS_CONFIG3,  0,  3, adv_on);
+	GPMC_SET_ONE(GPMC_CS_CONFIG3,  8, 12, adv_rd_off);
+	GPMC_SET_ONE(GPMC_CS_CONFIG3, 16, 20, adv_wr_off);
+
+	GPMC_SET_ONE(GPMC_CS_CONFIG4,  0,  3, oe_on);
+	GPMC_SET_ONE(GPMC_CS_CONFIG4,  8, 12, oe_off);
+	GPMC_SET_ONE(GPMC_CS_CONFIG4, 16, 19, we_on);
+	GPMC_SET_ONE(GPMC_CS_CONFIG4, 24, 28, we_off);
+
+	GPMC_SET_ONE(GPMC_CS_CONFIG5,  0,  4, rd_cycle);
+	GPMC_SET_ONE(GPMC_CS_CONFIG5,  8, 12, wr_cycle);
+	GPMC_SET_ONE(GPMC_CS_CONFIG5, 16, 20, access);
+
+	GPMC_SET_ONE(GPMC_CS_CONFIG5, 24, 27, page_burst_access);
+
+	GPMC_SET_ONE(GPMC_CS_CONFIG6, 0, 3, bus_turnaround);
+	GPMC_SET_ONE(GPMC_CS_CONFIG6, 8, 11, cycle2cycle_delay);
+
+	GPMC_SET_ONE(GPMC_CS_CONFIG1, 18, 19, wait_monitoring);
+	GPMC_SET_ONE(GPMC_CS_CONFIG1, 25, 26, clk_activation);
+
+	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
+		GPMC_SET_ONE(GPMC_CS_CONFIG6, 16, 19, wr_data_mux_bus);
+	if (gpmc_capability & GPMC_HAS_WR_ACCESS)
+		GPMC_SET_ONE(GPMC_CS_CONFIG6, 24, 28, wr_access);
+
+	/* caller is expected to have initialized CONFIG1 to cover
+	 * at least sync vs async
+	 */
+	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+	if (l & (GPMC_CONFIG1_READTYPE_SYNC | GPMC_CONFIG1_WRITETYPE_SYNC)) {
+#ifdef DEBUG
+		pr_info("GPMC CS%d CLK period is %lu ns (div %d)\n",
+			cs, (div * gpmc_get_fclk_period()) / 1000, div);
+#endif
+		l &= ~0x03;
+		l |= (div - 1);
+		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
+	}
+
+	gpmc_cs_bool_timings(cs, &t->bool_timings);
+
+	return 0;
+}
+
+static int gpmc_cs_enable_mem(int cs, u32 base, u32 size)
+{
+	u32 l;
+	u32 mask;
+
+	/*
+	 * Ensure that base address is aligned on a
+	 * boundary equal to or greater than size.
+	 */
+	if (base & (size - 1))
+		return -EINVAL;
+
+	mask = (1 << GPMC_SECTION_SHIFT) - size;
+	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+	l &= ~0x3f;
+	l = (base >> GPMC_CHUNK_SHIFT) & 0x3f;
+	l &= ~(0x0f << 8);
+	l |= ((mask >> GPMC_CHUNK_SHIFT) & 0x0f) << 8;
+	l |= GPMC_CONFIG7_CSVALID;
+	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
+
+	return 0;
+}
+
+static void gpmc_cs_disable_mem(int cs)
+{
+	u32 l;
+
+	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+	l &= ~GPMC_CONFIG7_CSVALID;
+	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
+}
+
+static void gpmc_cs_get_memconf(int cs, u32 *base, u32 *size)
+{
+	u32 l;
+	u32 mask;
+
+	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+	*base = (l & 0x3f) << GPMC_CHUNK_SHIFT;
+	mask = (l >> 8) & 0x0f;
+	*size = (1 << GPMC_SECTION_SHIFT) - (mask << GPMC_CHUNK_SHIFT);
+}
+
+static int gpmc_cs_mem_enabled(int cs)
+{
+	u32 l;
+
+	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+	return l & GPMC_CONFIG7_CSVALID;
+}
+
+static void gpmc_cs_set_reserved(int cs, int reserved)
+{
+	gpmc_cs_map &= ~(1 << cs);
+	gpmc_cs_map |= (reserved ? 1 : 0) << cs;
+}
+
+static bool gpmc_cs_reserved(int cs)
+{
+	return gpmc_cs_map & (1 << cs);
+}
+
+static unsigned long gpmc_mem_align(unsigned long size)
+{
+	int order;
+
+	size = (size - 1) >> (GPMC_CHUNK_SHIFT - 1);
+	order = GPMC_CHUNK_SHIFT - 1;
+	do {
+		size >>= 1;
+		order++;
+	} while (size);
+	size = 1 << order;
+	return size;
+}
+
+static int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size)
+{
+	struct resource	*res = &gpmc_cs_mem[cs];
+	int r;
+
+	size = gpmc_mem_align(size);
+	spin_lock(&gpmc_mem_lock);
+	res->start = base;
+	res->end = base + size - 1;
+	r = request_resource(&gpmc_mem_root, res);
+	spin_unlock(&gpmc_mem_lock);
+
+	return r;
+}
+
+static int gpmc_cs_delete_mem(int cs)
+{
+	struct resource	*res = &gpmc_cs_mem[cs];
+	int r;
+
+	spin_lock(&gpmc_mem_lock);
+	r = release_resource(res);
+	res->start = 0;
+	res->end = 0;
+	spin_unlock(&gpmc_mem_lock);
+
+	return r;
+}
+
+/**
+ * gpmc_cs_remap - remaps a chip-select physical base address
+ * @cs:		chip-select to remap
+ * @base:	physical base address to re-map chip-select to
+ *
+ * Re-maps a chip-select to a new physical base address specified by
+ * "base". Returns 0 on success and appropriate negative error code
+ * on failure.
+ */
+static int gpmc_cs_remap(int cs, u32 base)
+{
+	int ret;
+	u32 old_base, size;
+
+	if (cs > gpmc_cs_num) {
+		pr_err("%s: requested chip-select is disabled\n", __func__);
+		return -ENODEV;
+	}
+
+	/*
+	 * Make sure we ignore any device offsets from the GPMC partition
+	 * allocated for the chip select and that the new base confirms
+	 * to the GPMC 16MB minimum granularity.
+	 */
+	base &= ~(SZ_16M - 1);
+
+	gpmc_cs_get_memconf(cs, &old_base, &size);
+	if (base == old_base)
+		return 0;
+	gpmc_cs_disable_mem(cs);
+	ret = gpmc_cs_delete_mem(cs);
+	if (ret < 0)
+		return ret;
+	ret = gpmc_cs_insert_mem(cs, base, size);
+	if (ret < 0)
+		return ret;
+	ret = gpmc_cs_enable_mem(cs, base, size);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
+{
+	struct resource *res = &gpmc_cs_mem[cs];
+	int r = -1;
+
+	if (cs > gpmc_cs_num) {
+		pr_err("%s: requested chip-select is disabled\n", __func__);
+		return -ENODEV;
+	}
+	size = gpmc_mem_align(size);
+	if (size > (1 << GPMC_SECTION_SHIFT))
+		return -ENOMEM;
+
+	spin_lock(&gpmc_mem_lock);
+	if (gpmc_cs_reserved(cs)) {
+		r = -EBUSY;
+		goto out;
+	}
+	if (gpmc_cs_mem_enabled(cs))
+		r = adjust_resource(res, res->start & ~(size - 1), size);
+	if (r < 0)
+		r = allocate_resource(&gpmc_mem_root, res, size, 0, ~0,
+				      size, NULL, NULL);
+	if (r < 0)
+		goto out;
+
+	r = gpmc_cs_enable_mem(cs, res->start, resource_size(res));
+	if (r < 0) {
+		release_resource(res);
+		goto out;
+	}
+
+	*base = res->start;
+	gpmc_cs_set_reserved(cs, 1);
+out:
+	spin_unlock(&gpmc_mem_lock);
+	return r;
+}
+
+static void gpmc_cs_free(int cs)
+{
+	struct resource	*res = &gpmc_cs_mem[cs];
+
+	spin_lock(&gpmc_mem_lock);
+	if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) {
+		pr_err("Trying to free non-reserved GPMC CS%d\n", cs);
+		BUG();
+		spin_unlock(&gpmc_mem_lock);
+		return;
+	}
+	gpmc_cs_disable_mem(cs);
+	if (res->flags)
+		release_resource(res);
+	gpmc_cs_set_reserved(cs, 0);
+	spin_unlock(&gpmc_mem_lock);
+}
+
+static void gpmc_mem_exit(void)
+{
+	int cs;
+
+	for (cs = 0; cs < gpmc_cs_num; cs++) {
+		if (!gpmc_cs_mem_enabled(cs))
+			continue;
+		gpmc_cs_delete_mem(cs);
+	}
+}
+
+static void gpmc_mem_init(void)
+{
+	int cs;
+
+	/*
+	 * The first 1MB of GPMC address space is typically mapped to
+	 * the internal ROM. Never allocate the first page, to
+	 * facilitate bug detection; even if we didn't boot from ROM.
+	 */
+	gpmc_mem_root.start = SZ_1M;
+	gpmc_mem_root.end = GPMC_MEM_END;
+
+	/* Reserve all regions that has been set up by bootloader */
+	for (cs = 0; cs < gpmc_cs_num; cs++) {
+		u32 base, size;
+
+		if (!gpmc_cs_mem_enabled(cs))
+			continue;
+		gpmc_cs_get_memconf(cs, &base, &size);
+		if (gpmc_cs_insert_mem(cs, base, size)) {
+			pr_warn("%s: disabling cs %d mapped at 0x%x-0x%x\n",
+				__func__, cs, base, base + size);
+			gpmc_cs_disable_mem(cs);
+		}
+	}
+}
+
+static u32 gpmc_round_ps_to_sync_clk(u32 time_ps, u32 sync_clk)
+{
+	u32 temp;
+	int div;
+
+	div = gpmc_calc_divider(sync_clk);
+	temp = gpmc_ps_to_ticks(time_ps);
+	temp = (temp + div - 1) / div;
+	return gpmc_ticks_to_ps(temp * div);
+}
+
+/* XXX: can the cycles be avoided ? */
+static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t,
+				       struct gpmc_device_timings *dev_t,
+				       bool mux)
+{
+	u32 temp;
+
+	/* adv_rd_off */
+	temp = dev_t->t_avdp_r;
+	/* XXX: mux check required ? */
+	if (mux) {
+		/* XXX: t_avdp not to be required for sync, only added for tusb
+		 * this indirectly necessitates requirement of t_avdp_r and
+		 * t_avdp_w instead of having a single t_avdp
+		 */
+		temp = max_t(u32, temp,	gpmc_t->clk_activation + dev_t->t_avdh);
+		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
+	}
+	gpmc_t->adv_rd_off = gpmc_round_ps_to_ticks(temp);
+
+	/* oe_on */
+	temp = dev_t->t_oeasu; /* XXX: remove this ? */
+	if (mux) {
+		temp = max_t(u32, temp,	gpmc_t->clk_activation + dev_t->t_ach);
+		temp = max_t(u32, temp, gpmc_t->adv_rd_off +
+			     gpmc_ticks_to_ps(dev_t->cyc_aavdh_oe));
+	}
+	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
+
+	/* access */
+	/* XXX: any scope for improvement ?, by combining oe_on
+	 * and clk_activation, need to check whether
+	 * access = clk_activation + round to sync clk ?
+	 */
+	temp = max_t(u32, dev_t->t_iaa,	dev_t->cyc_iaa * gpmc_t->sync_clk);
+	temp += gpmc_t->clk_activation;
+	if (dev_t->cyc_oe)
+		temp = max_t(u32, temp, gpmc_t->oe_on +
+			     gpmc_ticks_to_ps(dev_t->cyc_oe));
+	gpmc_t->access = gpmc_round_ps_to_ticks(temp);
+
+	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ps(1);
+	gpmc_t->cs_rd_off = gpmc_t->oe_off;
+
+	/* rd_cycle */
+	temp = max_t(u32, dev_t->t_cez_r, dev_t->t_oez);
+	temp = gpmc_round_ps_to_sync_clk(temp, gpmc_t->sync_clk) +
+					 gpmc_t->access;
+	/* XXX: barter t_ce_rdyz with t_cez_r ? */
+	if (dev_t->t_ce_rdyz)
+		temp = max_t(u32, temp,	gpmc_t->cs_rd_off + dev_t->t_ce_rdyz);
+	gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp);
+
+	return 0;
+}
+
+static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t,
+					struct gpmc_device_timings *dev_t,
+					bool mux)
+{
+	u32 temp;
+
+	/* adv_wr_off */
+	temp = dev_t->t_avdp_w;
+	if (mux) {
+		temp = max_t(u32, temp,
+			     gpmc_t->clk_activation + dev_t->t_avdh);
+		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
+	}
+	gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp);
+
+	/* wr_data_mux_bus */
+	temp = max_t(u32, dev_t->t_weasu,
+		     gpmc_t->clk_activation + dev_t->t_rdyo);
+	/* XXX: shouldn't mux be kept as a whole for wr_data_mux_bus ?,
+	 * and in that case remember to handle we_on properly
+	 */
+	if (mux) {
+		temp = max_t(u32, temp,
+			     gpmc_t->adv_wr_off + dev_t->t_aavdh);
+		temp = max_t(u32, temp, gpmc_t->adv_wr_off +
+			     gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
+	}
+	gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp);
+
+	/* we_on */
+	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
+		gpmc_t->we_on = gpmc_round_ps_to_ticks(dev_t->t_weasu);
+	else
+		gpmc_t->we_on = gpmc_t->wr_data_mux_bus;
+
+	/* wr_access */
+	/* XXX: gpmc_capability check reqd ? , even if not, will not harm */
+	gpmc_t->wr_access = gpmc_t->access;
+
+	/* we_off */
+	temp = gpmc_t->we_on + dev_t->t_wpl;
+	temp = max_t(u32, temp,
+		     gpmc_t->wr_access + gpmc_ticks_to_ps(1));
+	temp = max_t(u32, temp,
+		     gpmc_t->we_on + gpmc_ticks_to_ps(dev_t->cyc_wpl));
+	gpmc_t->we_off = gpmc_round_ps_to_ticks(temp);
+
+	gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off +
+						   dev_t->t_wph);
+
+	/* wr_cycle */
+	temp = gpmc_round_ps_to_sync_clk(dev_t->t_cez_w, gpmc_t->sync_clk);
+	temp += gpmc_t->wr_access;
+	/* XXX: barter t_ce_rdyz with t_cez_w ? */
+	if (dev_t->t_ce_rdyz)
+		temp = max_t(u32, temp,
+			     gpmc_t->cs_wr_off + dev_t->t_ce_rdyz);
+	gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp);
+
+	return 0;
+}
+
+static int gpmc_calc_async_read_timings(struct gpmc_timings *gpmc_t,
+					struct gpmc_device_timings *dev_t,
+					bool mux)
+{
+	u32 temp;
+
+	/* adv_rd_off */
+	temp = dev_t->t_avdp_r;
+	if (mux)
+		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
+	gpmc_t->adv_rd_off = gpmc_round_ps_to_ticks(temp);
+
+	/* oe_on */
+	temp = dev_t->t_oeasu;
+	if (mux)
+		temp = max_t(u32, temp,
+			     gpmc_t->adv_rd_off + dev_t->t_aavdh);
+	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
+
+	/* access */
+	temp = max_t(u32, dev_t->t_iaa, /* XXX: remove t_iaa in async ? */
+		     gpmc_t->oe_on + dev_t->t_oe);
+	temp = max_t(u32, temp,
+		     gpmc_t->cs_on + dev_t->t_ce);
+	temp = max_t(u32, temp,
+		     gpmc_t->adv_on + dev_t->t_aa);
+	gpmc_t->access = gpmc_round_ps_to_ticks(temp);
+
+	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ps(1);
+	gpmc_t->cs_rd_off = gpmc_t->oe_off;
+
+	/* rd_cycle */
+	temp = max_t(u32, dev_t->t_rd_cycle,
+		     gpmc_t->cs_rd_off + dev_t->t_cez_r);
+	temp = max_t(u32, temp, gpmc_t->oe_off + dev_t->t_oez);
+	gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp);
+
+	return 0;
+}
+
+static int gpmc_calc_async_write_timings(struct gpmc_timings *gpmc_t,
+					 struct gpmc_device_timings *dev_t,
+					 bool mux)
+{
+	u32 temp;
+
+	/* adv_wr_off */
+	temp = dev_t->t_avdp_w;
+	if (mux)
+		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
+	gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp);
+
+	/* wr_data_mux_bus */
+	temp = dev_t->t_weasu;
+	if (mux) {
+		temp = max_t(u32, temp,	gpmc_t->adv_wr_off + dev_t->t_aavdh);
+		temp = max_t(u32, temp, gpmc_t->adv_wr_off +
+			     gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
+	}
+	gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp);
+
+	/* we_on */
+	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
+		gpmc_t->we_on = gpmc_round_ps_to_ticks(dev_t->t_weasu);
+	else
+		gpmc_t->we_on = gpmc_t->wr_data_mux_bus;
+
+	/* we_off */
+	temp = gpmc_t->we_on + dev_t->t_wpl;
+	gpmc_t->we_off = gpmc_round_ps_to_ticks(temp);
+
+	gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off +
+						   dev_t->t_wph);
+
+	/* wr_cycle */
+	temp = max_t(u32, dev_t->t_wr_cycle,
+		     gpmc_t->cs_wr_off + dev_t->t_cez_w);
+	gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp);
+
+	return 0;
+}
+
+static int gpmc_calc_sync_common_timings(struct gpmc_timings *gpmc_t,
+					 struct gpmc_device_timings *dev_t)
+{
+	u32 temp;
+
+	gpmc_t->sync_clk = gpmc_calc_divider(dev_t->clk) *
+					     gpmc_get_fclk_period();
+
+	gpmc_t->page_burst_access = gpmc_round_ps_to_sync_clk(dev_t->t_bacc,
+							      gpmc_t->sync_clk);
+
+	temp = max_t(u32, dev_t->t_ces, dev_t->t_avds);
+	gpmc_t->clk_activation = gpmc_round_ps_to_ticks(temp);
+
+	if (gpmc_calc_divider(gpmc_t->sync_clk) != 1)
+		return 0;
+
+	if (dev_t->ce_xdelay)
+		gpmc_t->bool_timings.cs_extra_delay = true;
+	if (dev_t->avd_xdelay)
+		gpmc_t->bool_timings.adv_extra_delay = true;
+	if (dev_t->oe_xdelay)
+		gpmc_t->bool_timings.oe_extra_delay = true;
+	if (dev_t->we_xdelay)
+		gpmc_t->bool_timings.we_extra_delay = true;
+
+	return 0;
+}
+
+static int gpmc_calc_common_timings(struct gpmc_timings *gpmc_t,
+				    struct gpmc_device_timings *dev_t,
+				    bool sync)
+{
+	u32 temp;
+
+	/* cs_on */
+	gpmc_t->cs_on = gpmc_round_ps_to_ticks(dev_t->t_ceasu);
+
+	/* adv_on */
+	temp = dev_t->t_avdasu;
+	if (dev_t->t_ce_avd)
+		temp = max_t(u32, temp,
+			     gpmc_t->cs_on + dev_t->t_ce_avd);
+	gpmc_t->adv_on = gpmc_round_ps_to_ticks(temp);
+
+	if (sync)
+		gpmc_calc_sync_common_timings(gpmc_t, dev_t);
+
+	return 0;
+}
+
+/* TODO: remove this function once all peripherals are confirmed to
+ * work with generic timing. Simultaneously gpmc_cs_set_timings()
+ * has to be modified to handle timings in ps instead of ns
+*/
+static void gpmc_convert_ps_to_ns(struct gpmc_timings *t)
+{
+	t->cs_on /= 1000;
+	t->cs_rd_off /= 1000;
+	t->cs_wr_off /= 1000;
+	t->adv_on /= 1000;
+	t->adv_rd_off /= 1000;
+	t->adv_wr_off /= 1000;
+	t->we_on /= 1000;
+	t->we_off /= 1000;
+	t->oe_on /= 1000;
+	t->oe_off /= 1000;
+	t->page_burst_access /= 1000;
+	t->access /= 1000;
+	t->rd_cycle /= 1000;
+	t->wr_cycle /= 1000;
+	t->bus_turnaround /= 1000;
+	t->cycle2cycle_delay /= 1000;
+	t->wait_monitoring /= 1000;
+	t->clk_activation /= 1000;
+	t->wr_access /= 1000;
+	t->wr_data_mux_bus /= 1000;
+}
+
+static int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
+			     struct gpmc_settings *gpmc_s,
+			     struct gpmc_device_timings *dev_t)
+{
+	bool mux = false, sync = false;
+
+	if (gpmc_s) {
+		mux = gpmc_s->mux_add_data ? true : false;
+		sync = (gpmc_s->sync_read || gpmc_s->sync_write);
+	}
+
+	memset(gpmc_t, 0, sizeof(*gpmc_t));
+
+	gpmc_calc_common_timings(gpmc_t, dev_t, sync);
+
+	if (gpmc_s && gpmc_s->sync_read)
+		gpmc_calc_sync_read_timings(gpmc_t, dev_t, mux);
+	else
+		gpmc_calc_async_read_timings(gpmc_t, dev_t, mux);
+
+	if (gpmc_s && gpmc_s->sync_write)
+		gpmc_calc_sync_write_timings(gpmc_t, dev_t, mux);
+	else
+		gpmc_calc_async_write_timings(gpmc_t, dev_t, mux);
+
+	/* TODO: remove, see function definition */
+	gpmc_convert_ps_to_ns(gpmc_t);
+
+	return 0;
+}
+
+/**
+ * gpmc_cs_program_settings - programs non-timing related settings
+ * @cs:		GPMC chip-select to program
+ * @p:		pointer to GPMC settings structure
+ *
+ * Programs non-timing related settings for a GPMC chip-select, such as
+ * bus-width, burst configuration, etc. Function should be called once
+ * for each chip-select that is being used and must be called before
+ * calling gpmc_cs_set_timings() as timing parameters in the CONFIG1
+ * register will be initialised to zero by this function. Returns 0 on
+ * success and appropriate negative error code on failure.
+ */
+static int gpmc_cs_program_settings(int cs, struct gpmc_settings *p)
+{
+	u32 config1;
+
+	if ((!p->device_width) || (p->device_width > GPMC_DEVWIDTH_16BIT)) {
+		pr_err("%s: invalid width %d!", __func__, p->device_width);
+		return -EINVAL;
+	}
+
+	/* Address-data multiplexing not supported for NAND devices */
+	if (p->device_nand && p->mux_add_data) {
+		pr_err("%s: invalid configuration!\n", __func__);
+		return -EINVAL;
+	}
+
+	if ((p->mux_add_data > GPMC_MUX_AD) ||
+	    ((p->mux_add_data == GPMC_MUX_AAD) &&
+	     !(gpmc_capability & GPMC_HAS_MUX_AAD))) {
+		pr_err("%s: invalid multiplex configuration!\n", __func__);
+		return -EINVAL;
+	}
+
+	/* Page/burst mode supports lengths of 4, 8 and 16 bytes */
+	if (p->burst_read || p->burst_write) {
+		switch (p->burst_len) {
+		case GPMC_BURST_4:
+		case GPMC_BURST_8:
+		case GPMC_BURST_16:
+			break;
+		default:
+			pr_err("%s: invalid page/burst-length (%d)\n",
+			       __func__, p->burst_len);
+			return -EINVAL;
+		}
+	}
+
+	if ((p->wait_on_read || p->wait_on_write) &&
+	    (p->wait_pin > gpmc_nr_waitpins)) {
+		pr_err("%s: invalid wait-pin (%d)\n", __func__, p->wait_pin);
+		return -EINVAL;
+	}
+
+	config1 = GPMC_CONFIG1_DEVICESIZE((p->device_width - 1));
+
+	if (p->sync_read)
+		config1 |= GPMC_CONFIG1_READTYPE_SYNC;
+	if (p->sync_write)
+		config1 |= GPMC_CONFIG1_WRITETYPE_SYNC;
+	if (p->wait_on_read)
+		config1 |= GPMC_CONFIG1_WAIT_READ_MON;
+	if (p->wait_on_write)
+		config1 |= GPMC_CONFIG1_WAIT_WRITE_MON;
+	if (p->wait_on_read || p->wait_on_write)
+		config1 |= GPMC_CONFIG1_WAIT_PIN_SEL(p->wait_pin);
+	if (p->device_nand)
+		config1	|= GPMC_CONFIG1_DEVICETYPE(GPMC_DEVICETYPE_NAND);
+	if (p->mux_add_data)
+		config1	|= GPMC_CONFIG1_MUXTYPE(p->mux_add_data);
+	if (p->burst_read)
+		config1 |= GPMC_CONFIG1_READMULTIPLE_SUPP;
+	if (p->burst_write)
+		config1 |= GPMC_CONFIG1_WRITEMULTIPLE_SUPP;
+	if (p->burst_read || p->burst_write) {
+		config1 |= GPMC_CONFIG1_PAGE_LEN(p->burst_len >> 3);
+		config1 |= p->burst_wrap ? GPMC_CONFIG1_WRAPBURST_SUPP : 0;
+	}
+
+	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, config1);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id gpmc_dt_ids[] = {
+	{ .compatible = "ti,omap2420-gpmc" },
+	{ .compatible = "ti,omap2430-gpmc" },
+	{ .compatible = "ti,omap3430-gpmc" },	/* omap3430 & omap3630 */
+	{ .compatible = "ti,omap4430-gpmc" },	/* omap4 & omap543x */
+	{ .compatible = "ti,am3352-gpmc" },	/* am335x devices */
+	{ }
+};
+MODULE_DEVICE_TABLE(of, gpmc_dt_ids);
+
+/**
+ * gpmc_read_settings_dt - read gpmc settings from device-tree
+ * @np:		pointer to device-tree node for a gpmc child device
+ * @p:		pointer to gpmc settings structure
+ *
+ * Reads the GPMC settings for a GPMC child device from device-tree and
+ * stores them in the GPMC settings structure passed. The GPMC settings
+ * structure is initialised to zero by this function and so any
+ * previously stored settings will be cleared.
+ */
+static void gpmc_read_settings_dt(struct device_node *np,
+				  struct gpmc_settings *p)
+{
+	memset(p, 0, sizeof(struct gpmc_settings));
+
+	p->sync_read = of_property_read_bool(np, "gpmc,sync-read");
+	p->sync_write = of_property_read_bool(np, "gpmc,sync-write");
+	of_property_read_u32(np, "gpmc,device-width", &p->device_width);
+	of_property_read_u32(np, "gpmc,mux-add-data", &p->mux_add_data);
+
+	if (!of_property_read_u32(np, "gpmc,burst-length", &p->burst_len)) {
+		p->burst_wrap = of_property_read_bool(np, "gpmc,burst-wrap");
+		p->burst_read = of_property_read_bool(np, "gpmc,burst-read");
+		p->burst_write = of_property_read_bool(np, "gpmc,burst-write");
+		if (!p->burst_read && !p->burst_write)
+			pr_warn("%s: page/burst-length set but not used!\n",
+				__func__);
+	}
+
+	if (!of_property_read_u32(np, "gpmc,wait-pin", &p->wait_pin)) {
+		p->wait_on_read = of_property_read_bool(np,
+							"gpmc,wait-on-read");
+		p->wait_on_write = of_property_read_bool(np,
+							 "gpmc,wait-on-write");
+		if (!p->wait_on_read && !p->wait_on_write)
+			pr_warn("%s: read/write wait monitoring not enabled!\n",
+				__func__);
+	}
+}
+
+static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
+						struct gpmc_timings *gpmc_t)
+{
+	struct gpmc_bool_timings *p;
+
+	if (!np || !gpmc_t)
+		return;
+
+	memset(gpmc_t, 0, sizeof(*gpmc_t));
+
+	/* minimum clock period for syncronous mode */
+	of_property_read_u32(np, "gpmc,sync-clk-ps", &gpmc_t->sync_clk);
+
+	/* chip select timtings */
+	of_property_read_u32(np, "gpmc,cs-on-ns", &gpmc_t->cs_on);
+	of_property_read_u32(np, "gpmc,cs-rd-off-ns", &gpmc_t->cs_rd_off);
+	of_property_read_u32(np, "gpmc,cs-wr-off-ns", &gpmc_t->cs_wr_off);
+
+	/* ADV signal timings */
+	of_property_read_u32(np, "gpmc,adv-on-ns", &gpmc_t->adv_on);
+	of_property_read_u32(np, "gpmc,adv-rd-off-ns", &gpmc_t->adv_rd_off);
+	of_property_read_u32(np, "gpmc,adv-wr-off-ns", &gpmc_t->adv_wr_off);
+
+	/* WE signal timings */
+	of_property_read_u32(np, "gpmc,we-on-ns", &gpmc_t->we_on);
+	of_property_read_u32(np, "gpmc,we-off-ns", &gpmc_t->we_off);
+
+	/* OE signal timings */
+	of_property_read_u32(np, "gpmc,oe-on-ns", &gpmc_t->oe_on);
+	of_property_read_u32(np, "gpmc,oe-off-ns", &gpmc_t->oe_off);
+
+	/* access and cycle timings */
+	of_property_read_u32(np, "gpmc,page-burst-access-ns",
+			     &gpmc_t->page_burst_access);
+	of_property_read_u32(np, "gpmc,access-ns", &gpmc_t->access);
+	of_property_read_u32(np, "gpmc,rd-cycle-ns", &gpmc_t->rd_cycle);
+	of_property_read_u32(np, "gpmc,wr-cycle-ns", &gpmc_t->wr_cycle);
+	of_property_read_u32(np, "gpmc,bus-turnaround-ns",
+			     &gpmc_t->bus_turnaround);
+	of_property_read_u32(np, "gpmc,cycle2cycle-delay-ns",
+			     &gpmc_t->cycle2cycle_delay);
+	of_property_read_u32(np, "gpmc,wait-monitoring-ns",
+			     &gpmc_t->wait_monitoring);
+	of_property_read_u32(np, "gpmc,clk-activation-ns",
+			     &gpmc_t->clk_activation);
+
+	/* only applicable to OMAP3+ */
+	of_property_read_u32(np, "gpmc,wr-access-ns", &gpmc_t->wr_access);
+	of_property_read_u32(np, "gpmc,wr-data-mux-bus-ns",
+			     &gpmc_t->wr_data_mux_bus);
+
+	/* bool timing parameters */
+	p = &gpmc_t->bool_timings;
+
+	p->cycle2cyclediffcsen =
+		of_property_read_bool(np, "gpmc,cycle2cycle-diffcsen");
+	p->cycle2cyclesamecsen =
+		of_property_read_bool(np, "gpmc,cycle2cycle-samecsen");
+	p->we_extra_delay = of_property_read_bool(np, "gpmc,we-extra-delay");
+	p->oe_extra_delay = of_property_read_bool(np, "gpmc,oe-extra-delay");
+	p->adv_extra_delay = of_property_read_bool(np, "gpmc,adv-extra-delay");
+	p->cs_extra_delay = of_property_read_bool(np, "gpmc,cs-extra-delay");
+	p->time_para_granularity =
+		of_property_read_bool(np, "gpmc,time-para-granularity");
+}
+
+/**
+ * gpmc_probe_generic_child - configures the gpmc for a child device
+ * @pdev:	pointer to gpmc platform device
+ * @child:	pointer to device-tree node for child device
+ *
+ * Allocates and configures a GPMC chip-select for a child device.
+ * Returns 0 on success and appropriate negative error code on failure.
+ */
+static int gpmc_probe_generic_child(struct platform_device *pdev,
+				    struct device_node *child)
+{
+	struct gpmc_settings gpmc_s;
+	struct gpmc_timings gpmc_t;
+	struct resource res;
+	unsigned long base;
+	int ret, cs;
+	struct device *dev = &pdev->dev;
+
+	if (of_property_read_u32(child, "reg", &cs) < 0) {
+		dev_err(&pdev->dev, "%s has no 'reg' property\n",
+			child->full_name);
+		return -ENODEV;
+	}
+
+	if (of_address_to_resource(child, 0, &res) < 0) {
+		dev_err(&pdev->dev, "%s has malformed 'reg' property\n",
+			child->full_name);
+		return -ENODEV;
+	}
+
+	ret = gpmc_cs_request(cs, resource_size(&res), &base);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "cannot request GPMC CS %d\n", cs);
+		return ret;
+	}
+
+	/*
+	 * For some GPMC devices we still need to rely on the bootloader
+	 * timings because the devices can be connected via FPGA. So far
+	 * the list is smc91x on the omap2 SDP boards, and 8250 on zooms.
+	 * REVISIT: Add timing support from slls644g.pdf and from the
+	 * lan91c96 manual.
+	 */
+	if (of_device_is_compatible(child, "ns16550a") ||
+	    of_device_is_compatible(child, "smsc,lan91c94") ||
+	    of_device_is_compatible(child, "smsc,lan91c111")) {
+		dev_warn(&pdev->dev,
+			 "%s using bootloader timings on CS%d\n",
+			 child->name, cs);
+		goto no_timings;
+	}
+
+	/*
+	 * FIXME: gpmc_cs_request() will map the CS to an arbitary
+	 * location in the gpmc address space. When booting with
+	 * device-tree we want the NOR flash to be mapped to the
+	 * location specified in the device-tree blob. So remap the
+	 * CS to this location. Once DT migration is complete should
+	 * just make gpmc_cs_request() map a specific address.
+	 */
+	ret = gpmc_cs_remap(cs, res.start);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "cannot remap GPMC CS %d to %pa\n",
+			cs, &res.start);
+		goto err;
+	}
+
+	gpmc_read_settings_dt(child, &gpmc_s);
+
+	if (of_node_cmp(child->name, "nand") == 0) {
+		/* NAND specific setup */
+		u32 val;
+
+		val = of_get_nand_bus_width(child);
+		switch (val) {
+		case 8:
+			gpmc_s.device_width = GPMC_DEVWIDTH_8BIT;
+			break;
+		case 16:
+			gpmc_s.device_width = GPMC_DEVWIDTH_16BIT;
+			break;
+		default:
+			dev_err(dev, "%s: invalid 'nand-bus-width'\n",
+				child->name);
+			ret = -EINVAL;
+			goto err;
+		}
+
+		gpmc_s.device_nand = true;
+
+	} else if (of_node_cmp(child->name, "onenand") == 0) {
+		/* DT incorrectly sets sync modes, onenand default is async */
+		gpmc_s.sync_read = false;
+		gpmc_s.sync_write = false;
+
+	} else {
+		if (of_property_read_u32(child, "bank-width",
+					 &gpmc_s.device_width)) {
+			dev_err(dev, "%s: no 'bank-width' property\n",
+				child->name);
+			goto err;
+		}
+
+		if (gpmc_s.device_width < 1 || gpmc_s.device_width > 2) {
+			dev_err(dev, "%s: invalid 'bank-width'\n",
+				child->name);
+			goto err;
+		}
+	}
+
+	ret = gpmc_cs_program_settings(cs, &gpmc_s);
+	if (ret < 0)
+		goto err;
+
+	gpmc_read_timings_dt(child, &gpmc_t);
+	gpmc_cs_set_timings(cs, &gpmc_t);
+
+no_timings:
+	if (of_platform_device_create(child, NULL, &pdev->dev))
+		return 0;
+
+	dev_err(&pdev->dev, "failed to create gpmc child %s\n", child->name);
+	ret = -ENODEV;
+
+err:
+	gpmc_cs_free(cs);
+
+	return ret;
+}
+
+static int gpmc_probe_dt(struct platform_device *pdev)
+{
+	int ret;
+	struct device_node *child;
+
+	ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-cs",
+				   &gpmc_cs_num);
+	if (ret < 0) {
+		pr_err("%s: number of chip-selects not defined\n", __func__);
+		return ret;
+	} else if (gpmc_cs_num < 1) {
+		pr_err("%s: all chip-selects are disabled\n", __func__);
+		return -EINVAL;
+	} else if (gpmc_cs_num > GPMC_CS_NUM) {
+		pr_err("%s: number of supported chip-selects cannot be > %d\n",
+		       __func__, GPMC_CS_NUM);
+		return -EINVAL;
+	}
+
+	ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-waitpins",
+				   &gpmc_nr_waitpins);
+	if (ret < 0) {
+		pr_err("%s: number of wait pins not found!\n", __func__);
+		return ret;
+	}
+
+	for_each_child_of_node(pdev->dev.of_node, child) {
+		if (!child->name)
+			continue;
+
+		if (of_node_cmp(child->name, "ethernet") == 0 ||
+		    of_node_cmp(child->name, "nor") == 0 ||
+		    of_node_cmp(child->name, "uart") == 0 ||
+		    of_node_cmp(child->name, "nand") == 0 ||
+		    of_node_cmp(child->name, "onenand") == 0)
+			ret = gpmc_probe_generic_child(pdev, child);
+
+		if (WARN(ret < 0, "%s: probing gpmc child %s failed\n",
+			 __func__, child->full_name))
+			of_node_put(child);
+	}
+
+	return 0;
+}
+#else
+static int gpmc_probe_dt(struct platform_device *pdev)
+{
+	return 0;
+}
+#endif
+
+static int gpmc_nand_setup(struct platform_device *parent_pdev,
+			   struct gpmc_omap_cs_data *cs)
+{
+	struct resource *res;
+	struct resource *res_gpmc;
+
+	if (!cs->pdev)
+		return -EINVAL;
+
+	res = cs->pdev->resource;
+
+	if (cs->pdev->num_resources < 3)
+		return -EINVAL;
+
+	if (resource_type(&res[1]) != IORESOURCE_MEM ||
+	    resource_type(&res[2]) != IORESOURCE_IRQ)
+		return -EINVAL;
+
+	if (!cs->settings)
+		return -EINVAL;
+
+	/* GPMC register space */
+	res_gpmc = platform_get_resource(parent_pdev, IORESOURCE_MEM, 0);
+	if (!res_gpmc)
+		return -EINVAL;
+
+	res[1] = *res_gpmc;
+
+	/* setup IRQ resources */
+	res[2].start = gpmc_irq;
+
+	cs->settings->device_nand = true;
+
+	return 0;
+}
+
+static void gpmc_probe_legacy(struct platform_device *pdev)
+{
+	int i, rc, j;
+	struct device *dev = &pdev->dev;
+	struct gpmc_omap_platform_data *gpmc_pdata;
+	struct resource *mem_res;
+	unsigned long cs_base;
+	resource_size_t size;
+	struct gpmc_timings gpmc_timings;
+	struct gpmc_omap_cs_data *cs;
+
+	gpmc_pdata = dev->platform_data;
+	gpmc_cs_num = GPMC_CS_NUM;
+	gpmc_nr_waitpins = GPMC_NR_WAITPINS;
+
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		cs = &gpmc_pdata->cs[i];
+		if (!cs->valid)
+			continue;
+
+		if (cs->settings) {
+			if (gpmc_cs_program_settings(i, cs->settings)) {
+				dev_err(dev,
+					"Couldn't program settings for CS %d\n",
+					i);
+				continue;
+			}
+		}
+
+		/* give device_timings priority over gpmc_timings */
+		if (cs->device_timings) {
+			gpmc_calc_timings(&gpmc_timings, cs->settings,
+					  cs->device_timings);
+
+			if (gpmc_cs_set_timings(i, &gpmc_timings)) {
+				dev_err(dev,
+					"Couldn't program timings for CS %d\n",
+					i);
+				continue;
+			}
+		} else if (cs->gpmc_timings) {
+			if (gpmc_cs_set_timings(i, cs->gpmc_timings)) {
+				dev_err(dev,
+					"Couldn't program timings for CS %d\n",
+					i);
+				continue;
+			}
+		}
+	}
+
+	/*
+	 * All Chip Selects must be configured before platform devices are
+	 * created as some devices (e.g. tusb6010) can use multiple
+	 * Chip selects.
+	 */
+
+	/* Fixup Memory resources */
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		int required_resources;
+
+		cs = &gpmc_pdata->cs[i];
+		if (!cs->valid)
+			continue;
+
+		if (!cs->pdev)
+			continue;
+
+		/* Customized NAND setup */
+		if (cs->is_nand) {
+			if (gpmc_nand_setup(pdev, cs)) {
+				dev_err(dev, "Error setting up NAND on CS %d\n",
+					i);
+				continue;
+			}
+		}
+
+		mem_res = cs->pdev->resource;
+
+		/*
+		 * If device is present multiple times, fix the subsequent
+		 * resources
+		 */
+		required_resources = 1;
+		for (j = 0; j < i; j++) {
+			if (gpmc_pdata->cs[j].pdev == cs->pdev) {
+				mem_res++;
+				required_resources++;
+			}
+		}
+
+		if (cs->pdev->num_resources < required_resources ||
+		    resource_type(mem_res) != IORESOURCE_MEM) {
+			dev_err(dev, "Invalid IOMEM resource for CS %d\n", i);
+			continue;
+		}
+
+		/*
+		 * Request a CS space. Use size from
+		 * platform device's MEM resource
+		 */
+		size = mem_res->end - mem_res->start + 1;
+		if (gpmc_cs_request(i, size, &cs_base)) {
+			dev_err(dev, "Couldn't request resource for CS %d\n",
+				i);
+			continue;
+		}
+
+		mem_res->start = cs_base;
+		mem_res->end = cs_base + size - 1;
+	}
+
+	/* create the platform devices */
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		bool registered;
+
+		cs = &gpmc_pdata->cs[i];
+		if (!cs->valid)
+			continue;
+
+		if (!cs->pdev)
+			continue;
+
+		/*
+		 * same device can be present on multiple CS, don't
+		 * register device more than once.
+		 */
+		registered = false;
+		for (j = 0; j < i; j++) {
+			if (gpmc_pdata->cs[j].pdev == cs->pdev) {
+				registered = true;
+				break;
+			}
+		}
+
+		if (registered)
+			continue;
+
+		cs->pdev->dev.parent = dev;
+		rc = platform_device_register(cs->pdev);
+		if (rc < 0) {
+			dev_err(dev,
+				"Failed to register device %s on CS %d\n",
+				cs->pdev->name, i);
+			continue;
+		}
+	}
+}
+
+static int gpmc_probe(struct platform_device *pdev)
+{
+	int rc;
+	u32 l;
+	struct resource *res;
+	struct device *dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL)
+		return -ENOENT;
+
+	phys_base = res->start;
+	mem_size = resource_size(res);
+
+	gpmc_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(gpmc_base))
+		return PTR_ERR(gpmc_base);
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get resource: irq\n");
+		return -EINVAL;
+	}
+
+	gpmc_irq = res->start;
+
+	gpmc_l3_clk = clk_get(&pdev->dev, "fck");
+	if (IS_ERR(gpmc_l3_clk)) {
+		dev_err(&pdev->dev, "error: clk_get\n");
+		gpmc_irq = 0;
+		return PTR_ERR(gpmc_l3_clk);
+	}
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
+
+	gpmc_dev = dev;
+
+	l = gpmc_read_reg(GPMC_REVISION);
+
+	/*
+	 * FIXME: Once device-tree migration is complete the below flags
+	 * should be populated based upon the device-tree compatible
+	 * string. For now just use the IP revision. OMAP3+ devices have
+	 * the wr_access and wr_data_mux_bus register fields. OMAP4+
+	 * devices support the addr-addr-data multiplex protocol.
+	 *
+	 * GPMC IP revisions:
+	 * - OMAP24xx			= 2.0
+	 * - OMAP3xxx			= 5.0
+	 * - OMAP44xx/54xx/AM335x	= 6.0
+	 */
+	if (GPMC_REVISION_MAJOR(l) > 0x4)
+		gpmc_capability = GPMC_HAS_WR_ACCESS | GPMC_HAS_WR_DATA_MUX_BUS;
+	if (GPMC_REVISION_MAJOR(l) > 0x5)
+		gpmc_capability |= GPMC_HAS_MUX_AAD;
+	dev_info(dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l),
+		 GPMC_REVISION_MINOR(l));
+
+	gpmc_mem_init();
+
+	/* Now the GPMC is initialised, unreserve the chip-selects */
+	gpmc_cs_map = 0;
+	gpmc_dev = dev;
+
+	if (dev->of_node) {
+		rc = gpmc_probe_dt(pdev);
+		if (rc) {
+			dev_err(dev, "gpmc_probe_dt() failed\n");
+			goto error;
+		}
+	} else {
+		/* Legacy probing based on platform data */
+		if (!dev->platform_data) {
+			dev_err(dev, "No platform data\n");
+			rc = -EINVAL;
+			goto error;
+		}
+
+		gpmc_probe_legacy(pdev);
+	}
+
+	return 0;
+
+error:
+	pm_runtime_put_sync(dev);
+	clk_put(gpmc_l3_clk);
+	return rc;
+}
+
+static int gpmc_remove(struct platform_device *pdev)
+{
+	gpmc_mem_exit();
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	gpmc_dev = NULL;
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+/* Structure to save gpmc cs context */
+struct gpmc_cs_config {
+	u32 config1;
+	u32 config2;
+	u32 config3;
+	u32 config4;
+	u32 config5;
+	u32 config6;
+	u32 config7;
+	int is_valid;
+};
+
+/*
+ * Structure to save/restore gpmc context
+ */
+struct omap_gpmc_regs {
+	u32 sysconfig;
+	u32 irqenable;
+	u32 timeout_ctrl;
+	u32 config;
+	u32 prefetch_config1;
+	u32 prefetch_config2;
+	u32 prefetch_control;
+	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
+};
+
+static struct omap_gpmc_regs gpmc_context;
+
+void omap_gpmc_save_context(void)
+{
+	int i;
+
+	gpmc_context.sysconfig = gpmc_read_reg(GPMC_SYSCONFIG);
+	gpmc_context.irqenable = gpmc_read_reg(GPMC_IRQENABLE);
+	gpmc_context.timeout_ctrl = gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
+	gpmc_context.config = gpmc_read_reg(GPMC_CONFIG);
+	gpmc_context.prefetch_config1 = gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
+	gpmc_context.prefetch_config2 = gpmc_read_reg(GPMC_PREFETCH_CONFIG2);
+	gpmc_context.prefetch_control = gpmc_read_reg(GPMC_PREFETCH_CONTROL);
+	for (i = 0; i < gpmc_cs_num; i++) {
+		gpmc_context.cs_context[i].is_valid = gpmc_cs_mem_enabled(i);
+		if (gpmc_context.cs_context[i].is_valid) {
+			gpmc_context.cs_context[i].config1 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG1);
+			gpmc_context.cs_context[i].config2 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG2);
+			gpmc_context.cs_context[i].config3 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG3);
+			gpmc_context.cs_context[i].config4 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG4);
+			gpmc_context.cs_context[i].config5 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG5);
+			gpmc_context.cs_context[i].config6 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG6);
+			gpmc_context.cs_context[i].config7 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
+		}
+	}
+}
+
+void omap_gpmc_restore_context(void)
+{
+	int i;
+
+	gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig);
+	gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable);
+	gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl);
+	gpmc_write_reg(GPMC_CONFIG, gpmc_context.config);
+	gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1);
+	gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2);
+	gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control);
+	for (i = 0; i < gpmc_cs_num; i++) {
+		if (gpmc_context.cs_context[i].is_valid) {
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG1,
+					  gpmc_context.cs_context[i].config1);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG2,
+					  gpmc_context.cs_context[i].config2);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG3,
+					  gpmc_context.cs_context[i].config3);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG4,
+					  gpmc_context.cs_context[i].config4);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG5,
+					  gpmc_context.cs_context[i].config5);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG6,
+					  gpmc_context.cs_context[i].config6);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG7,
+					  gpmc_context.cs_context[i].config7);
+		}
+	}
+}
+
+static int gpmc_suspend(struct device *dev)
+{
+	omap_gpmc_save_context();
+	pm_runtime_put_sync(dev);
+	return 0;
+}
+
+static int gpmc_resume(struct device *dev)
+{
+	pm_runtime_get_sync(dev);
+	omap_gpmc_restore_context();
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(gpmc_pm_ops, gpmc_suspend, gpmc_resume);
+
+static struct platform_driver gpmc_driver = {
+	.probe		= gpmc_probe,
+	.remove		= gpmc_remove,
+	.driver		= {
+		.name	= DEVICE_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(gpmc_dt_ids),
+		.pm	= &gpmc_pm_ops,
+	},
+};
+
+static __init int gpmc_init(void)
+{
+	return platform_driver_register(&gpmc_driver);
+}
+
+static __exit void gpmc_exit(void)
+{
+	platform_driver_unregister(&gpmc_driver);
+}
+
+module_init(gpmc_init);
+module_exit(gpmc_exit);
+
+/**
+ * omap_gpmc_retime - Reconfigre GPMC timings for the device
+ *
+ * @cs		Chip select number
+ * @gpmc_s	GPMC settings
+ * @dev_t	New device timings to set
+ */
+int omap_gpmc_retime(int cs, struct gpmc_settings *gpmc_s,
+		     struct gpmc_device_timings *dev_t)
+{
+	struct gpmc_timings gpmc_t;
+	struct device *dev = gpmc_dev;
+
+	if (!gpmc_dev)
+		return -ENODEV;
+
+	if (cs < 0 || cs >= gpmc_cs_num) {
+		dev_err(dev, "%s: Invalid find Chip Select\n", __func__);
+		return cs;
+	}
+
+	if (gpmc_cs_program_settings(cs, gpmc_s)) {
+		dev_err(dev, "%s: Failed to set GPMC settings\n", __func__);
+		return -EINVAL;
+	}
+
+	gpmc_calc_timings(&gpmc_t, gpmc_s, dev_t);
+	if (gpmc_cs_set_timings(cs, &gpmc_t)) {
+		dev_err(dev, "%s: Failed to set GPMC timings\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(omap_gpmc_retime);
+
+/**
+ * omap_gpmc_get_clk_period - Get the nearest possible (equal to or higer) GPMC
+ *				synchronous clock (GPMC_CLK) period.
+ *
+ * @cs		Chip select number
+ * @min_ps	Minimum synchronous clock period supporded by the device
+ *
+ * Returns the nearest possible GPMC clock period in picoseconds, equal to or
+ * higher than the requested period. 0 in case of error.
+ */
+unsigned long omap_gpmc_get_clk_period(int cs,
+				       unsigned long min_ps)
+{
+	int div;
+	unsigned long clk_ps;
+	struct device *dev = gpmc_dev;
+
+	if (!gpmc_dev)
+		return 0;
+
+	if (cs < 0 || cs >= gpmc_cs_num) {
+		dev_err(dev, "%s: Invalid Chip Select\n", __func__);
+		return cs;
+	}
+
+	div = gpmc_calc_divider(min_ps);
+	if (div < 0) {
+		dev_err(dev, "%s: Can't support requested clock period %lu ps\n",
+			__func__, min_ps);
+		return 0;
+	}
+
+	clk_ps = gpmc_get_fclk_period() * div;
+
+	return clk_ps;
+}
+EXPORT_SYMBOL_GPL(omap_gpmc_get_clk_period);
+
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index f1cf503..e1db2c1 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -89,7 +89,7 @@ config MTD_NAND_AMS_DELTA
 
 config MTD_NAND_OMAP2
 	tristate "NAND Flash device on OMAP2, OMAP3 and OMAP4"
-	depends on ARCH_OMAP2PLUS
+	depends on TI_GPMC
 	help
           Support for NAND flash on Texas Instruments OMAP2, OMAP3 and OMAP4
 	  platforms.
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig
index ab260727..272c16c 100644
--- a/drivers/mtd/onenand/Kconfig
+++ b/drivers/mtd/onenand/Kconfig
@@ -24,10 +24,10 @@ config MTD_ONENAND_GENERIC
 	  Support for OneNAND flash via platform device driver.
 
 config MTD_ONENAND_OMAP2
-	tristate "OneNAND on OMAP2/OMAP3 support"
-	depends on ARCH_OMAP2 || ARCH_OMAP3
+	tristate "OneNAND on OMAP2+ support"
+	depends on TI_GPMC
 	help
-	  Support for a OneNAND flash device connected to an OMAP2/OMAP3 CPU
+	  Support for a OneNAND flash device connected to an OMAP2+ SoCs
 	  via the GPMC memory controller.
 
 config MTD_ONENAND_SAMSUNG
-- 
1.8.3.2

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

* [PATCH 36/36] ARM: OMAP2+: defconfig: Enable TI GPMC driver
  2014-06-11  8:56 ` Roger Quadros
  (?)
@ 2014-06-11  8:56   ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

This is needed for NAND and OneNAND to work.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/configs/omap2plus_defconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig
index a4e8d01..98dad6c 100644
--- a/arch/arm/configs/omap2plus_defconfig
+++ b/arch/arm/configs/omap2plus_defconfig
@@ -79,6 +79,8 @@ CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_DMA_CMA=y
 CONFIG_OMAP_OCP2SCP=y
 CONFIG_CONNECTOR=y
+CONFIG_MEMORY=y
+CONFIG_TI_GPMC=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
-- 
1.8.3.2


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

* [PATCH 36/36] ARM: OMAP2+: defconfig: Enable TI GPMC driver
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel, Roger Quadros

This is needed for NAND and OneNAND to work.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/configs/omap2plus_defconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig
index a4e8d01..98dad6c 100644
--- a/arch/arm/configs/omap2plus_defconfig
+++ b/arch/arm/configs/omap2plus_defconfig
@@ -79,6 +79,8 @@ CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_DMA_CMA=y
 CONFIG_OMAP_OCP2SCP=y
 CONFIG_CONNECTOR=y
+CONFIG_MEMORY=y
+CONFIG_TI_GPMC=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
-- 
1.8.3.2

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

* [PATCH 36/36] ARM: OMAP2+: defconfig: Enable TI GPMC driver
@ 2014-06-11  8:56   ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11  8:56 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap, Roger Quadros

This is needed for NAND and OneNAND to work.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/configs/omap2plus_defconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig
index a4e8d01..98dad6c 100644
--- a/arch/arm/configs/omap2plus_defconfig
+++ b/arch/arm/configs/omap2plus_defconfig
@@ -79,6 +79,8 @@ CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_DMA_CMA=y
 CONFIG_OMAP_OCP2SCP=y
 CONFIG_CONNECTOR=y
+CONFIG_MEMORY=y
+CONFIG_TI_GPMC=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
-- 
1.8.3.2

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

* [resend][PATCH 35/36] ARM: OMAP2+: gpmc: move GPMC driver into drivers/memory
@ 2014-06-11 11:45     ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11 11:45 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: kyungmin.park, pekon, ezequiel.garcia, javier, nsekhar,
	linux-omap, linux-mtd, devicetree, linux-kernel

Resending with rename detection option to git-format-patch
for easier review.

From: Roger Quadros <rogerq@ti.com>

Move the GPMC driver out of mach-omap2. We leave behind only
the mach-omap2 specific bits in mach-omap2/gpmc_legacy.c
i.e. gpmc_generic_init() for use by board files to register
the GPMC configuration and omap3_gpmc_save/restore_context() for
use by OMAP3 OFF mode support.

The GPMC driver is now enabled by its own kernel config option
TI_GPMC. The other drivers that need GPMC to work i.e. MTD_ONENAND_OMAP2
and MTD_NAND_OMAP2 are made to depend on TI_GPMC.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/Makefile                       |   2 +-
 arch/arm/mach-omap2/gpmc_legacy.c                  | 296 ++++++++++++++++
 drivers/memory/Kconfig                             |  10 +
 drivers/memory/Makefile                            |   1 +
 .../mach-omap2/gpmc.c => drivers/memory/ti-gpmc.c  | 388 +++++++--------------
 drivers/mtd/nand/Kconfig                           |   2 +-
 drivers/mtd/onenand/Kconfig                        |   6 +-
 7 files changed, 447 insertions(+), 258 deletions(-)
 create mode 100644 arch/arm/mach-omap2/gpmc_legacy.c
 rename arch/arm/mach-omap2/gpmc.c => drivers/memory/ti-gpmc.c (90%)

diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 8421f38..a2e7426 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -6,7 +6,7 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
 	-I$(srctree)/arch/arm/plat-omap/include
 
 # Common support
-obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o gpmc.o timer.o pm.o \
+obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o gpmc_legacy.o timer.o pm.o \
 	 common.o gpio.o dma.o wd_timer.o display.o i2c.o hdq1w.o omap_hwmod.o \
 	 omap_device.o sram.o drm.o
 
diff --git a/arch/arm/mach-omap2/gpmc_legacy.c b/arch/arm/mach-omap2/gpmc_legacy.c
new file mode 100644
index 0000000..3b3f86e
--- /dev/null
+++ b/arch/arm/mach-omap2/gpmc_legacy.c
@@ -0,0 +1,296 @@
+/*
+ * GPMC support functions
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation
+ *
+ * Author: Juha Yrjola
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#include "soc.h"
+#include "gpmc.h"
+#include "omap_device.h"
+
+#define	DEVICE_NAME		"omap-gpmc"
+
+/* CS CONFIG registers */
+#define GPMC_CS_CONFIG1		0x00
+#define GPMC_CS_CONFIG2		0x04
+#define GPMC_CS_CONFIG3		0x08
+#define GPMC_CS_CONFIG4		0x0c
+#define GPMC_CS_CONFIG5		0x10
+#define GPMC_CS_CONFIG6		0x14
+#define GPMC_CS_CONFIG7		0x18
+
+#define GPMC_CS0_OFFSET		0x60
+#define GPMC_CS_SIZE		0x30
+
+/* GPMC register offsets */
+#define GPMC_SYSCONFIG		0x10
+#define GPMC_IRQENABLE		0x1c
+#define GPMC_TIMEOUT_CONTROL	0x40
+#define GPMC_CONFIG		0x50
+#define GPMC_PREFETCH_CONFIG1	0x1e0
+#define GPMC_PREFETCH_CONFIG2	0x1e4
+#define GPMC_PREFETCH_CONTROL	0x1ec
+
+#define GPMC_CONFIG7_CSVALID		(1 << 6)
+
+static struct gpmc_omap_platform_data gpmc_pdata;
+
+/* Structure to save gpmc cs context */
+struct gpmc_cs_config {
+	u32 config1;
+	u32 config2;
+	u32 config3;
+	u32 config4;
+	u32 config5;
+	u32 config6;
+	u32 config7;
+	int is_valid;
+};
+
+/*
+ * Structure to save/restore gpmc context
+ * to support core off on OMAP3
+ */
+struct omap3_gpmc_regs {
+	u32 sysconfig;
+	u32 irqenable;
+	u32 timeout_ctrl;
+	u32 config;
+	u32 prefetch_config1;
+	u32 prefetch_config2;
+	u32 prefetch_control;
+	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
+};
+
+static int __init omap_gpmc_init(void)
+{
+	struct omap_hwmod *oh;
+	struct platform_device *pdev;
+	char *oh_name = "gpmc";
+
+	/*
+	 * if the board boots up with a populated DT, do not
+	 * manually add the device from this initcall
+	 */
+	if (of_have_populated_dt())
+		return -ENODEV;
+
+	oh = omap_hwmod_lookup(oh_name);
+	if (!oh) {
+		pr_err("Could not look up %s\n", oh_name);
+		return -ENODEV;
+	}
+
+	pdev = omap_device_build(DEVICE_NAME, -1, oh, (void *)&gpmc_pdata,
+				 sizeof(gpmc_pdata));
+	WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
+
+	return PTR_RET(pdev);
+}
+/* must run after machine_init code. i.e. arch_init */
+omap_subsys_initcall(omap_gpmc_init);
+
+/**
+ * gpmc_generic_init - Initialize platform data for a Chip Select
+ *
+ * @cs		chip select number
+ * @type	GPMC_OMAP_TYPE
+ * @settings	GPMC settings
+ * @device_timings	device timings for device on this CS
+ * @gpmc_timings	GPMC timings
+ * @pdev	platform device for the device on this CS
+ * @pdata_size	platform data size for the platform device
+ */
+int gpmc_generic_init(int cs, bool is_nand,
+		      struct gpmc_settings *settings,
+		      struct gpmc_device_timings *device_timings,
+		      struct gpmc_timings *gpmc_timings,
+		      struct platform_device *pdev, unsigned pdata_size)
+{
+	struct gpmc_settings *gpmc_s = NULL;
+	struct gpmc_device_timings *gpmc_dev_t = NULL;
+	struct gpmc_timings *gpmc_t;
+
+	if (cs >= GPMC_CS_NUM) {
+		pr_err("%s: Invalid cs specified. Max CS = %d\n",
+		       __func__, GPMC_CS_NUM);
+		return -EINVAL;
+	}
+
+	if (gpmc_pdata.cs[cs].valid) {
+		pr_err("%s: cs %d already requested, ignoring new request\n",
+		       __func__, cs);
+		return -EINVAL;
+	}
+
+	if (settings) {
+		gpmc_s = kmemdup(settings, sizeof(*settings), GFP_KERNEL);
+		if (!gpmc_s)
+			return -ENOMEM;
+
+		gpmc_pdata.cs[cs].settings = gpmc_s;
+	}
+
+	if (device_timings) {
+		gpmc_dev_t = kmemdup(device_timings, sizeof(*device_timings),
+				     GFP_KERNEL);
+		if (!gpmc_dev_t)
+			goto dev_t_fail;
+
+		gpmc_pdata.cs[cs].device_timings = gpmc_dev_t;
+	}
+
+	if (gpmc_timings) {
+		gpmc_t = kmemdup(gpmc_timings, sizeof(*gpmc_timings),
+				 GFP_KERNEL);
+		if (!gpmc_t)
+			goto gpmc_t_fail;
+
+		gpmc_pdata.cs[cs].gpmc_timings = gpmc_t;
+	}
+
+	gpmc_pdata.cs[cs].is_nand = is_nand;
+	gpmc_pdata.cs[cs].pdev = pdev;
+	gpmc_pdata.cs[cs].pdata_size = pdata_size;
+	gpmc_pdata.cs[cs].valid = true;
+
+	return 0;
+
+gpmc_t_fail:
+	if (device_timings)
+		kfree(gpmc_dev_t);
+dev_t_fail:
+	if (settings)
+		kfree(gpmc_s);
+
+	return -ENOMEM;
+}
+
+
+static struct omap3_gpmc_regs gpmc_context;
+
+/*
+ * Below code only for OMAP3 OFF mode support.
+ * This code must be left back in mach-omap2.
+ */
+void __iomem *omap2_gpmc_base;
+
+void __init omap2_set_globals_gpmc(void __iomem *gpmc)
+{
+	omap2_gpmc_base = gpmc;
+}
+
+static u32 _gpmc_read_reg(u16 reg)
+{
+	return __raw_readl(omap2_gpmc_base + reg);
+}
+
+static void _gpmc_write_reg(u32 val, u16 reg)
+{
+	__raw_readl(omap2_gpmc_base + reg);
+}
+
+static u32 _gpmc_cs_read_reg(int cs, int idx)
+{
+	u16 reg;
+
+	reg = GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
+
+	return _gpmc_read_reg(reg);
+}
+
+static void _gpmc_cs_write_reg(int cs, int idx, u32 val)
+{
+	u16 reg;
+
+	reg = GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
+	_gpmc_write_reg(val, reg);
+}
+
+void omap3_gpmc_save_context(void)
+{
+	int i;
+	u32 val;
+
+	if (!omap2_gpmc_base)
+		return;
+
+	gpmc_context.sysconfig = _gpmc_read_reg(GPMC_SYSCONFIG);
+	gpmc_context.irqenable = _gpmc_read_reg(GPMC_IRQENABLE);
+	gpmc_context.timeout_ctrl = _gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
+	gpmc_context.config = _gpmc_read_reg(GPMC_CONFIG);
+	gpmc_context.prefetch_config1 = _gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
+	gpmc_context.prefetch_config2 = _gpmc_read_reg(GPMC_PREFETCH_CONFIG2);
+	gpmc_context.prefetch_control = _gpmc_read_reg(GPMC_PREFETCH_CONTROL);
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		/* check if valid */
+		val = _gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
+		gpmc_context.cs_context[i].is_valid =
+						val & GPMC_CONFIG7_CSVALID;
+
+		if (gpmc_context.cs_context[i].is_valid) {
+			gpmc_context.cs_context[i].config1 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG1);
+			gpmc_context.cs_context[i].config2 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG2);
+			gpmc_context.cs_context[i].config3 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG3);
+			gpmc_context.cs_context[i].config4 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG4);
+			gpmc_context.cs_context[i].config5 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG5);
+			gpmc_context.cs_context[i].config6 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG6);
+			gpmc_context.cs_context[i].config7 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
+		}
+	}
+}
+
+void omap3_gpmc_restore_context(void)
+{
+	int i;
+
+	if (!omap2_gpmc_base)
+		return;
+
+	_gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig);
+	_gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable);
+	_gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl);
+	_gpmc_write_reg(GPMC_CONFIG, gpmc_context.config);
+	_gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1);
+	_gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2);
+	_gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control);
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		if (gpmc_context.cs_context[i].is_valid) {
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG1,
+					   gpmc_context.cs_context[i].config1);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG2,
+					   gpmc_context.cs_context[i].config2);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG3,
+					   gpmc_context.cs_context[i].config3);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG4,
+					   gpmc_context.cs_context[i].config4);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG5,
+					   gpmc_context.cs_context[i].config5);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG6,
+					   gpmc_context.cs_context[i].config6);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG7,
+					   gpmc_context.cs_context[i].config7);
+		}
+	}
+}
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index c59e9c9..ce611b0 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -31,6 +31,16 @@ config TI_EMIF
 	  parameters and other settings during frequency, voltage and
 	  temperature changes
 
+config TI_GPMC
+	bool "Texas Instruments GPMC driver"
+	depends on ARCH_OMAP2PLUS
+	default y
+	help
+	 This driver is for the General Purpose Memory Controller (GPMC)
+	 present on Texas Instruments SoCs (e.g. OMAP2+). GPMC allows
+	 interfacing to a variety of asynchronous as well as synchronous
+	 memory drives like NOR, NAND, OneNAND, SRAM.
+
 config MVEBU_DEVBUS
 	bool "Marvell EBU Device Bus Controller"
 	default y
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index 71160a2..329b7b6 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_OF)		+= of_memory.o
 endif
 obj-$(CONFIG_TI_AEMIF)		+= ti-aemif.o
 obj-$(CONFIG_TI_EMIF)		+= emif.o
+obj-$(CONFIG_TI_GPMC)		+= ti-gpmc.o
 obj-$(CONFIG_FSL_IFC)		+= fsl_ifc.o
 obj-$(CONFIG_MVEBU_DEVBUS)	+= mvebu-devbus.o
 obj-$(CONFIG_TEGRA20_MC)	+= tegra20-mc.o
diff --git a/arch/arm/mach-omap2/gpmc.c b/drivers/memory/ti-gpmc.c
similarity index 90%
rename from arch/arm/mach-omap2/gpmc.c
rename to drivers/memory/ti-gpmc.c
index 9173f71..3bb2fd6 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/drivers/memory/ti-gpmc.c
@@ -33,13 +33,7 @@
 #include <linux/slab.h>
 
 #include <linux/platform_data/mtd-nand-omap2.h>
-
-#include <asm/mach-types.h>
-
-#include "soc.h"
-#include "common.h"
-#include "omap_device.h"
-#include "gpmc.h"
+#include <linux/platform_data/gpmc-omap.h>
 
 #define	DEVICE_NAME		"omap-gpmc"
 
@@ -154,35 +148,6 @@
 
 #define GPMC_NR_WAITPINS		4
 
-static struct gpmc_omap_platform_data gpmc_pdata;
-
-/* Structure to save gpmc cs context */
-struct gpmc_cs_config {
-	u32 config1;
-	u32 config2;
-	u32 config3;
-	u32 config4;
-	u32 config5;
-	u32 config6;
-	u32 config7;
-	int is_valid;
-};
-
-/*
- * Structure to save/restore gpmc context
- * to support core off on OMAP3
- */
-struct omap3_gpmc_regs {
-	u32 sysconfig;
-	u32 irqenable;
-	u32 timeout_ctrl;
-	u32 config;
-	u32 prefetch_config1;
-	u32 prefetch_config2;
-	u32 prefetch_control;
-	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
-};
-
 static struct resource	gpmc_mem_root;
 static struct resource	gpmc_cs_mem[GPMC_CS_NUM];
 static DEFINE_SPINLOCK(gpmc_mem_lock);
@@ -230,7 +195,7 @@ static unsigned long gpmc_get_fclk_period(void)
 	unsigned long rate = clk_get_rate(gpmc_l3_clk);
 
 	if (rate == 0) {
-		printk(KERN_WARNING "gpmc_l3_clk not enabled\n");
+		pr_warn("%s: gpmc_l3_clk not enabled\n", __func__);
 		return 0;
 	}
 
@@ -323,8 +288,8 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
 	nr_bits = end_bit - st_bit + 1;
 	if (ticks >= 1 << nr_bits) {
 #ifdef DEBUG
-		printk(KERN_INFO "GPMC CS%d: %-10s* %3d ns, %3d ticks >= %d\n",
-				cs, name, time, ticks, 1 << nr_bits);
+		pr_info("GPMC CS%d: %-10s* %3d ns, %3d ticks >= %d\n",
+			cs, name, time, ticks, 1 << nr_bits);
 #endif
 		return -1;
 	}
@@ -332,10 +297,9 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
 	mask = (1 << nr_bits) - 1;
 	l = gpmc_cs_read_reg(cs, reg);
 #ifdef DEBUG
-	printk(KERN_INFO
-		"GPMC CS%d: %-10s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n",
-	       cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000,
-			(l >> st_bit) & mask, time);
+	pr_info("GPMC CS%d: %-10s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n",
+		cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000,
+		(l >> st_bit) & mask, time);
 #endif
 	l &= ~(mask << st_bit);
 	l |= ticks << st_bit;
@@ -346,13 +310,11 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
 
 #ifdef DEBUG
 #define GPMC_SET_ONE(reg, st, end, field) \
-	if (set_gpmc_timing_reg(cs, (reg), (st), (end),		\
-			t->field, #field) < 0)			\
-		return -1
+	set_gpmc_timing_reg(cs, (reg), (st), (end),		\
+			t->field, #field)
 #else
 #define GPMC_SET_ONE(reg, st, end, field) \
-	if (set_gpmc_timing_reg(cs, (reg), (st), (end), t->field) < 0) \
-		return -1
+	set_gpmc_timing_reg(cs, (reg), (st), (end), t->field)
 #endif
 
 static int gpmc_calc_divider(unsigned int sync_clk)
@@ -415,8 +377,8 @@ static int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
 	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
 	if (l & (GPMC_CONFIG1_READTYPE_SYNC | GPMC_CONFIG1_WRITETYPE_SYNC)) {
 #ifdef DEBUG
-		printk(KERN_INFO "GPMC CS%d CLK period is %lu ns (div %d)\n",
-				cs, (div * gpmc_get_fclk_period()) / 1000, div);
+		pr_info("GPMC CS%d CLK period is %lu ns (div %d)\n",
+			cs, (div * gpmc_get_fclk_period()) / 1000, div);
 #endif
 		l &= ~0x03;
 		l |= (div - 1);
@@ -557,7 +519,7 @@ static int gpmc_cs_remap(int cs, u32 base)
 	 * Make sure we ignore any device offsets from the GPMC partition
 	 * allocated for the chip select and that the new base confirms
 	 * to the GPMC 16MB minimum granularity.
-	 */ 
+	 */
 	base &= ~(SZ_16M - 1);
 
 	gpmc_cs_get_memconf(cs, &old_base, &size);
@@ -622,7 +584,7 @@ static void gpmc_cs_free(int cs)
 
 	spin_lock(&gpmc_mem_lock);
 	if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) {
-		printk(KERN_ERR "Trying to free non-reserved GPMC CS%d\n", cs);
+		pr_err("Trying to free non-reserved GPMC CS%d\n", cs);
 		BUG();
 		spin_unlock(&gpmc_mem_lock);
 		return;
@@ -643,7 +605,6 @@ static void gpmc_mem_exit(void)
 			continue;
 		gpmc_cs_delete_mem(cs);
 	}
-
 }
 
 static void gpmc_mem_init(void)
@@ -709,7 +670,7 @@ static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t,
 	if (mux) {
 		temp = max_t(u32, temp,	gpmc_t->clk_activation + dev_t->t_ach);
 		temp = max_t(u32, temp, gpmc_t->adv_rd_off +
-				gpmc_ticks_to_ps(dev_t->cyc_aavdh_oe));
+			     gpmc_ticks_to_ps(dev_t->cyc_aavdh_oe));
 	}
 	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
 
@@ -722,7 +683,7 @@ static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t,
 	temp += gpmc_t->clk_activation;
 	if (dev_t->cyc_oe)
 		temp = max_t(u32, temp, gpmc_t->oe_on +
-				gpmc_ticks_to_ps(dev_t->cyc_oe));
+			     gpmc_ticks_to_ps(dev_t->cyc_oe));
 	gpmc_t->access = gpmc_round_ps_to_ticks(temp);
 
 	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ps(1);
@@ -731,7 +692,7 @@ static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t,
 	/* rd_cycle */
 	temp = max_t(u32, dev_t->t_cez_r, dev_t->t_oez);
 	temp = gpmc_round_ps_to_sync_clk(temp, gpmc_t->sync_clk) +
-							gpmc_t->access;
+					 gpmc_t->access;
 	/* XXX: barter t_ce_rdyz with t_cez_r ? */
 	if (dev_t->t_ce_rdyz)
 		temp = max_t(u32, temp,	gpmc_t->cs_rd_off + dev_t->t_ce_rdyz);
@@ -750,22 +711,22 @@ static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t,
 	temp = dev_t->t_avdp_w;
 	if (mux) {
 		temp = max_t(u32, temp,
-			gpmc_t->clk_activation + dev_t->t_avdh);
+			     gpmc_t->clk_activation + dev_t->t_avdh);
 		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
 	}
 	gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp);
 
 	/* wr_data_mux_bus */
 	temp = max_t(u32, dev_t->t_weasu,
-			gpmc_t->clk_activation + dev_t->t_rdyo);
+		     gpmc_t->clk_activation + dev_t->t_rdyo);
 	/* XXX: shouldn't mux be kept as a whole for wr_data_mux_bus ?,
 	 * and in that case remember to handle we_on properly
 	 */
 	if (mux) {
 		temp = max_t(u32, temp,
-			gpmc_t->adv_wr_off + dev_t->t_aavdh);
+			     gpmc_t->adv_wr_off + dev_t->t_aavdh);
 		temp = max_t(u32, temp, gpmc_t->adv_wr_off +
-				gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
+			     gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
 	}
 	gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp);
 
@@ -782,13 +743,13 @@ static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t,
 	/* we_off */
 	temp = gpmc_t->we_on + dev_t->t_wpl;
 	temp = max_t(u32, temp,
-			gpmc_t->wr_access + gpmc_ticks_to_ps(1));
+		     gpmc_t->wr_access + gpmc_ticks_to_ps(1));
 	temp = max_t(u32, temp,
-		gpmc_t->we_on + gpmc_ticks_to_ps(dev_t->cyc_wpl));
+		     gpmc_t->we_on + gpmc_ticks_to_ps(dev_t->cyc_wpl));
 	gpmc_t->we_off = gpmc_round_ps_to_ticks(temp);
 
 	gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off +
-							dev_t->t_wph);
+						   dev_t->t_wph);
 
 	/* wr_cycle */
 	temp = gpmc_round_ps_to_sync_clk(dev_t->t_cez_w, gpmc_t->sync_clk);
@@ -796,7 +757,7 @@ static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t,
 	/* XXX: barter t_ce_rdyz with t_cez_w ? */
 	if (dev_t->t_ce_rdyz)
 		temp = max_t(u32, temp,
-				 gpmc_t->cs_wr_off + dev_t->t_ce_rdyz);
+			     gpmc_t->cs_wr_off + dev_t->t_ce_rdyz);
 	gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp);
 
 	return 0;
@@ -818,16 +779,16 @@ static int gpmc_calc_async_read_timings(struct gpmc_timings *gpmc_t,
 	temp = dev_t->t_oeasu;
 	if (mux)
 		temp = max_t(u32, temp,
-			gpmc_t->adv_rd_off + dev_t->t_aavdh);
+			     gpmc_t->adv_rd_off + dev_t->t_aavdh);
 	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
 
 	/* access */
 	temp = max_t(u32, dev_t->t_iaa, /* XXX: remove t_iaa in async ? */
-				gpmc_t->oe_on + dev_t->t_oe);
+		     gpmc_t->oe_on + dev_t->t_oe);
 	temp = max_t(u32, temp,
-				gpmc_t->cs_on + dev_t->t_ce);
+		     gpmc_t->cs_on + dev_t->t_ce);
 	temp = max_t(u32, temp,
-				gpmc_t->adv_on + dev_t->t_aa);
+		     gpmc_t->adv_on + dev_t->t_aa);
 	gpmc_t->access = gpmc_round_ps_to_ticks(temp);
 
 	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ps(1);
@@ -835,7 +796,7 @@ static int gpmc_calc_async_read_timings(struct gpmc_timings *gpmc_t,
 
 	/* rd_cycle */
 	temp = max_t(u32, dev_t->t_rd_cycle,
-			gpmc_t->cs_rd_off + dev_t->t_cez_r);
+		     gpmc_t->cs_rd_off + dev_t->t_cez_r);
 	temp = max_t(u32, temp, gpmc_t->oe_off + dev_t->t_oez);
 	gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp);
 
@@ -859,7 +820,7 @@ static int gpmc_calc_async_write_timings(struct gpmc_timings *gpmc_t,
 	if (mux) {
 		temp = max_t(u32, temp,	gpmc_t->adv_wr_off + dev_t->t_aavdh);
 		temp = max_t(u32, temp, gpmc_t->adv_wr_off +
-				gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
+			     gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
 	}
 	gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp);
 
@@ -874,27 +835,26 @@ static int gpmc_calc_async_write_timings(struct gpmc_timings *gpmc_t,
 	gpmc_t->we_off = gpmc_round_ps_to_ticks(temp);
 
 	gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off +
-							dev_t->t_wph);
+						   dev_t->t_wph);
 
 	/* wr_cycle */
 	temp = max_t(u32, dev_t->t_wr_cycle,
-				gpmc_t->cs_wr_off + dev_t->t_cez_w);
+		     gpmc_t->cs_wr_off + dev_t->t_cez_w);
 	gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp);
 
 	return 0;
 }
 
 static int gpmc_calc_sync_common_timings(struct gpmc_timings *gpmc_t,
-			struct gpmc_device_timings *dev_t)
+					 struct gpmc_device_timings *dev_t)
 {
 	u32 temp;
 
 	gpmc_t->sync_clk = gpmc_calc_divider(dev_t->clk) *
-						gpmc_get_fclk_period();
+					     gpmc_get_fclk_period();
 
-	gpmc_t->page_burst_access = gpmc_round_ps_to_sync_clk(
-					dev_t->t_bacc,
-					gpmc_t->sync_clk);
+	gpmc_t->page_burst_access = gpmc_round_ps_to_sync_clk(dev_t->t_bacc,
+							      gpmc_t->sync_clk);
 
 	temp = max_t(u32, dev_t->t_ces, dev_t->t_avds);
 	gpmc_t->clk_activation = gpmc_round_ps_to_ticks(temp);
@@ -927,7 +887,7 @@ static int gpmc_calc_common_timings(struct gpmc_timings *gpmc_t,
 	temp = dev_t->t_avdasu;
 	if (dev_t->t_ce_avd)
 		temp = max_t(u32, temp,
-				gpmc_t->cs_on + dev_t->t_ce_avd);
+			     gpmc_t->cs_on + dev_t->t_ce_avd);
 	gpmc_t->adv_on = gpmc_round_ps_to_ticks(temp);
 
 	if (sync)
@@ -1084,7 +1044,7 @@ static struct of_device_id gpmc_dt_ids[] = {
 	{ .compatible = "ti,omap2420-gpmc" },
 	{ .compatible = "ti,omap2430-gpmc" },
 	{ .compatible = "ti,omap3430-gpmc" },	/* omap3430 & omap3630 */
-	{ .compatible = "ti,omap4430-gpmc" },	/* omap4430 & omap4460 & omap543x */
+	{ .compatible = "ti,omap4430-gpmc" },	/* omap4 & omap543x */
 	{ .compatible = "ti,am3352-gpmc" },	/* am335x devices */
 	{ }
 };
@@ -1205,7 +1165,7 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
  * Returns 0 on success and appropriate negative error code on failure.
  */
 static int gpmc_probe_generic_child(struct platform_device *pdev,
-				struct device_node *child)
+				    struct device_node *child)
 {
 	struct gpmc_settings gpmc_s;
 	struct gpmc_timings gpmc_t;
@@ -1341,7 +1301,7 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 		return -EINVAL;
 	} else if (gpmc_cs_num > GPMC_CS_NUM) {
 		pr_err("%s: number of supported chip-selects cannot be > %d\n",
-					 __func__, GPMC_CS_NUM);
+		       __func__, GPMC_CS_NUM);
 		return -EINVAL;
 	}
 
@@ -1353,7 +1313,6 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 	}
 
 	for_each_child_of_node(pdev->dev.of_node, child) {
-
 		if (!child->name)
 			continue;
 
@@ -1625,6 +1584,7 @@ static int gpmc_probe(struct platform_device *pdev)
 
 	/* Now the GPMC is initialised, unreserve the chip-selects */
 	gpmc_cs_map = 0;
+	gpmc_dev = dev;
 
 	if (dev->of_node) {
 		rc = gpmc_probe_dt(pdev);
@@ -1661,9 +1621,100 @@ static int gpmc_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM_SLEEP
+/* Structure to save gpmc cs context */
+struct gpmc_cs_config {
+	u32 config1;
+	u32 config2;
+	u32 config3;
+	u32 config4;
+	u32 config5;
+	u32 config6;
+	u32 config7;
+	int is_valid;
+};
+
+/*
+ * Structure to save/restore gpmc context
+ */
+struct omap_gpmc_regs {
+	u32 sysconfig;
+	u32 irqenable;
+	u32 timeout_ctrl;
+	u32 config;
+	u32 prefetch_config1;
+	u32 prefetch_config2;
+	u32 prefetch_control;
+	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
+};
+
+static struct omap_gpmc_regs gpmc_context;
+
+void omap_gpmc_save_context(void)
+{
+	int i;
+
+	gpmc_context.sysconfig = gpmc_read_reg(GPMC_SYSCONFIG);
+	gpmc_context.irqenable = gpmc_read_reg(GPMC_IRQENABLE);
+	gpmc_context.timeout_ctrl = gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
+	gpmc_context.config = gpmc_read_reg(GPMC_CONFIG);
+	gpmc_context.prefetch_config1 = gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
+	gpmc_context.prefetch_config2 = gpmc_read_reg(GPMC_PREFETCH_CONFIG2);
+	gpmc_context.prefetch_control = gpmc_read_reg(GPMC_PREFETCH_CONTROL);
+	for (i = 0; i < gpmc_cs_num; i++) {
+		gpmc_context.cs_context[i].is_valid = gpmc_cs_mem_enabled(i);
+		if (gpmc_context.cs_context[i].is_valid) {
+			gpmc_context.cs_context[i].config1 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG1);
+			gpmc_context.cs_context[i].config2 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG2);
+			gpmc_context.cs_context[i].config3 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG3);
+			gpmc_context.cs_context[i].config4 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG4);
+			gpmc_context.cs_context[i].config5 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG5);
+			gpmc_context.cs_context[i].config6 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG6);
+			gpmc_context.cs_context[i].config7 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
+		}
+	}
+}
+
+void omap_gpmc_restore_context(void)
+{
+	int i;
+
+	gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig);
+	gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable);
+	gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl);
+	gpmc_write_reg(GPMC_CONFIG, gpmc_context.config);
+	gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1);
+	gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2);
+	gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control);
+	for (i = 0; i < gpmc_cs_num; i++) {
+		if (gpmc_context.cs_context[i].is_valid) {
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG1,
+					  gpmc_context.cs_context[i].config1);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG2,
+					  gpmc_context.cs_context[i].config2);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG3,
+					  gpmc_context.cs_context[i].config3);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG4,
+					  gpmc_context.cs_context[i].config4);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG5,
+					  gpmc_context.cs_context[i].config5);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG6,
+					  gpmc_context.cs_context[i].config6);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG7,
+					  gpmc_context.cs_context[i].config7);
+		}
+	}
+}
+
 static int gpmc_suspend(struct device *dev)
 {
-	omap3_gpmc_save_context();
+	omap_gpmc_save_context();
 	pm_runtime_put_sync(dev);
 	return 0;
 }
@@ -1671,7 +1722,7 @@ static int gpmc_suspend(struct device *dev)
 static int gpmc_resume(struct device *dev)
 {
 	pm_runtime_get_sync(dev);
-	omap3_gpmc_restore_context();
+	omap_gpmc_restore_context();
 	return 0;
 }
 #endif
@@ -1697,116 +1748,11 @@ static __init int gpmc_init(void)
 static __exit void gpmc_exit(void)
 {
 	platform_driver_unregister(&gpmc_driver);
-
 }
 
 module_init(gpmc_init);
 module_exit(gpmc_exit);
 
-static int __init omap_gpmc_init(void)
-{
-	struct omap_hwmod *oh;
-	struct platform_device *pdev;
-	char *oh_name = "gpmc";
-
-	/*
-	 * if the board boots up with a populated DT, do not
-	 * manually add the device from this initcall
-	 */
-	if (of_have_populated_dt())
-		return -ENODEV;
-
-	oh = omap_hwmod_lookup(oh_name);
-	if (!oh) {
-		pr_err("Could not look up %s\n", oh_name);
-		return -ENODEV;
-	}
-
-	pdev = omap_device_build(DEVICE_NAME, -1, oh, (void *)&gpmc_pdata,
-				 sizeof(gpmc_pdata));
-	WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
-
-	return PTR_RET(pdev);
-}
-/* must run after machine_init code. i.e. arch_init */
-omap_subsys_initcall(omap_gpmc_init);
-
-/**
- * gpmc_generic_init - Initialize platform data for a Chip Select
- *
- * @cs		chip select number
- * @is_nand	true if device is NAND flash.
- * @settings	GPMC settings
- * @device_timings	device timings for device on this CS
- * @gpmc_timings	GPMC timings
- * @pdev	platform device for the device on this CS
- * @pdata_size	platform data size for the platform device
- */
-int gpmc_generic_init(int cs, bool is_nand,
-		      struct gpmc_settings *settings,
-		      struct gpmc_device_timings *device_timings,
-		      struct gpmc_timings *gpmc_timings,
-		      struct platform_device *pdev, unsigned pdata_size)
-{
-	struct gpmc_settings *gpmc_s = NULL;
-	struct gpmc_device_timings *gpmc_dev_t = NULL;
-	struct gpmc_timings *gpmc_t;
-
-	if (cs >= GPMC_CS_NUM) {
-		pr_err("%s: Invalid cs specified. Max CS = %d\n",
-		       __func__, GPMC_CS_NUM);
-		return -EINVAL;
-	}
-
-	if (gpmc_pdata.cs[cs].valid) {
-		pr_err("%s: cs %d already requested, ignoring new request\n",
-		       __func__, cs);
-		return -EINVAL;
-	}
-
-	if (settings) {
-		gpmc_s = kmemdup(settings, sizeof(*settings), GFP_KERNEL);
-		if (!gpmc_s)
-			return -ENOMEM;
-
-		gpmc_pdata.cs[cs].settings = gpmc_s;
-	}
-
-	if (device_timings) {
-		gpmc_dev_t = kmemdup(device_timings, sizeof(*device_timings),
-				     GFP_KERNEL);
-		if (!gpmc_dev_t)
-			goto dev_t_fail;
-
-		gpmc_pdata.cs[cs].device_timings = gpmc_dev_t;
-	}
-
-	if (gpmc_timings) {
-		gpmc_t = kmemdup(gpmc_timings, sizeof(*gpmc_timings),
-				 GFP_KERNEL);
-		if (!gpmc_t)
-			goto gpmc_t_fail;
-
-		gpmc_pdata.cs[cs].gpmc_timings = gpmc_t;
-	}
-
-	gpmc_pdata.cs[cs].is_nand = is_nand;
-	gpmc_pdata.cs[cs].pdev = pdev;
-	gpmc_pdata.cs[cs].pdata_size = pdata_size;
-	gpmc_pdata.cs[cs].valid = true;
-
-	return 0;
-
-gpmc_t_fail:
-	if (device_timings)
-		kfree(gpmc_dev_t);
-dev_t_fail:
-	if (settings)
-		kfree(gpmc_s);
-
-	return -ENOMEM;
-}
-
 /**
  * omap_gpmc_retime - Reconfigre GPMC timings for the device
  *
@@ -1881,67 +1827,3 @@ unsigned long omap_gpmc_get_clk_period(int cs,
 }
 EXPORT_SYMBOL_GPL(omap_gpmc_get_clk_period);
 
-static struct omap3_gpmc_regs gpmc_context;
-
-void omap3_gpmc_save_context(void)
-{
-	int i;
-
-	gpmc_context.sysconfig = gpmc_read_reg(GPMC_SYSCONFIG);
-	gpmc_context.irqenable = gpmc_read_reg(GPMC_IRQENABLE);
-	gpmc_context.timeout_ctrl = gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
-	gpmc_context.config = gpmc_read_reg(GPMC_CONFIG);
-	gpmc_context.prefetch_config1 = gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
-	gpmc_context.prefetch_config2 = gpmc_read_reg(GPMC_PREFETCH_CONFIG2);
-	gpmc_context.prefetch_control = gpmc_read_reg(GPMC_PREFETCH_CONTROL);
-	for (i = 0; i < gpmc_cs_num; i++) {
-		gpmc_context.cs_context[i].is_valid = gpmc_cs_mem_enabled(i);
-		if (gpmc_context.cs_context[i].is_valid) {
-			gpmc_context.cs_context[i].config1 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG1);
-			gpmc_context.cs_context[i].config2 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG2);
-			gpmc_context.cs_context[i].config3 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG3);
-			gpmc_context.cs_context[i].config4 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG4);
-			gpmc_context.cs_context[i].config5 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG5);
-			gpmc_context.cs_context[i].config6 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG6);
-			gpmc_context.cs_context[i].config7 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
-		}
-	}
-}
-
-void omap3_gpmc_restore_context(void)
-{
-	int i;
-
-	gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig);
-	gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable);
-	gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl);
-	gpmc_write_reg(GPMC_CONFIG, gpmc_context.config);
-	gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1);
-	gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2);
-	gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control);
-	for (i = 0; i < gpmc_cs_num; i++) {
-		if (gpmc_context.cs_context[i].is_valid) {
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG1,
-				gpmc_context.cs_context[i].config1);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG2,
-				gpmc_context.cs_context[i].config2);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG3,
-				gpmc_context.cs_context[i].config3);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG4,
-				gpmc_context.cs_context[i].config4);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG5,
-				gpmc_context.cs_context[i].config5);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG6,
-				gpmc_context.cs_context[i].config6);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG7,
-				gpmc_context.cs_context[i].config7);
-		}
-	}
-}
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index f1cf503..e1db2c1 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -89,7 +89,7 @@ config MTD_NAND_AMS_DELTA
 
 config MTD_NAND_OMAP2
 	tristate "NAND Flash device on OMAP2, OMAP3 and OMAP4"
-	depends on ARCH_OMAP2PLUS
+	depends on TI_GPMC
 	help
           Support for NAND flash on Texas Instruments OMAP2, OMAP3 and OMAP4
 	  platforms.
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig
index ab260727..272c16c 100644
--- a/drivers/mtd/onenand/Kconfig
+++ b/drivers/mtd/onenand/Kconfig
@@ -24,10 +24,10 @@ config MTD_ONENAND_GENERIC
 	  Support for OneNAND flash via platform device driver.
 
 config MTD_ONENAND_OMAP2
-	tristate "OneNAND on OMAP2/OMAP3 support"
-	depends on ARCH_OMAP2 || ARCH_OMAP3
+	tristate "OneNAND on OMAP2+ support"
+	depends on TI_GPMC
 	help
-	  Support for a OneNAND flash device connected to an OMAP2/OMAP3 CPU
+	  Support for a OneNAND flash device connected to an OMAP2+ SoCs
 	  via the GPMC memory controller.
 
 config MTD_ONENAND_SAMSUNG
-- 
1.8.3.2



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

* [resend][PATCH 35/36] ARM: OMAP2+: gpmc: move GPMC driver into drivers/memory
@ 2014-06-11 11:45     ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11 11:45 UTC (permalink / raw)
  To: tony-4v6yS6AI5VpBDgjK7y7TUQ, dwmw2-wEGCiKHe2LqWVfeAwA7xHQ,
	computersforpeace-Re5JQEeQqe8AvxtiuMwx3w
  Cc: kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ, pekon-l0cyMroinI0,
	ezequiel.garcia-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	javier-0uQlZySMnqxg9hUCZPvPmw, nsekhar-l0cyMroinI0,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

Resending with rename detection option to git-format-patch
for easier review.

From: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>

Move the GPMC driver out of mach-omap2. We leave behind only
the mach-omap2 specific bits in mach-omap2/gpmc_legacy.c
i.e. gpmc_generic_init() for use by board files to register
the GPMC configuration and omap3_gpmc_save/restore_context() for
use by OMAP3 OFF mode support.

The GPMC driver is now enabled by its own kernel config option
TI_GPMC. The other drivers that need GPMC to work i.e. MTD_ONENAND_OMAP2
and MTD_NAND_OMAP2 are made to depend on TI_GPMC.

Signed-off-by: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
---
 arch/arm/mach-omap2/Makefile                       |   2 +-
 arch/arm/mach-omap2/gpmc_legacy.c                  | 296 ++++++++++++++++
 drivers/memory/Kconfig                             |  10 +
 drivers/memory/Makefile                            |   1 +
 .../mach-omap2/gpmc.c => drivers/memory/ti-gpmc.c  | 388 +++++++--------------
 drivers/mtd/nand/Kconfig                           |   2 +-
 drivers/mtd/onenand/Kconfig                        |   6 +-
 7 files changed, 447 insertions(+), 258 deletions(-)
 create mode 100644 arch/arm/mach-omap2/gpmc_legacy.c
 rename arch/arm/mach-omap2/gpmc.c => drivers/memory/ti-gpmc.c (90%)

diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 8421f38..a2e7426 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -6,7 +6,7 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
 	-I$(srctree)/arch/arm/plat-omap/include
 
 # Common support
-obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o gpmc.o timer.o pm.o \
+obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o gpmc_legacy.o timer.o pm.o \
 	 common.o gpio.o dma.o wd_timer.o display.o i2c.o hdq1w.o omap_hwmod.o \
 	 omap_device.o sram.o drm.o
 
diff --git a/arch/arm/mach-omap2/gpmc_legacy.c b/arch/arm/mach-omap2/gpmc_legacy.c
new file mode 100644
index 0000000..3b3f86e
--- /dev/null
+++ b/arch/arm/mach-omap2/gpmc_legacy.c
@@ -0,0 +1,296 @@
+/*
+ * GPMC support functions
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation
+ *
+ * Author: Juha Yrjola
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar-l0cyMroinI0@public.gmane.org>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#include "soc.h"
+#include "gpmc.h"
+#include "omap_device.h"
+
+#define	DEVICE_NAME		"omap-gpmc"
+
+/* CS CONFIG registers */
+#define GPMC_CS_CONFIG1		0x00
+#define GPMC_CS_CONFIG2		0x04
+#define GPMC_CS_CONFIG3		0x08
+#define GPMC_CS_CONFIG4		0x0c
+#define GPMC_CS_CONFIG5		0x10
+#define GPMC_CS_CONFIG6		0x14
+#define GPMC_CS_CONFIG7		0x18
+
+#define GPMC_CS0_OFFSET		0x60
+#define GPMC_CS_SIZE		0x30
+
+/* GPMC register offsets */
+#define GPMC_SYSCONFIG		0x10
+#define GPMC_IRQENABLE		0x1c
+#define GPMC_TIMEOUT_CONTROL	0x40
+#define GPMC_CONFIG		0x50
+#define GPMC_PREFETCH_CONFIG1	0x1e0
+#define GPMC_PREFETCH_CONFIG2	0x1e4
+#define GPMC_PREFETCH_CONTROL	0x1ec
+
+#define GPMC_CONFIG7_CSVALID		(1 << 6)
+
+static struct gpmc_omap_platform_data gpmc_pdata;
+
+/* Structure to save gpmc cs context */
+struct gpmc_cs_config {
+	u32 config1;
+	u32 config2;
+	u32 config3;
+	u32 config4;
+	u32 config5;
+	u32 config6;
+	u32 config7;
+	int is_valid;
+};
+
+/*
+ * Structure to save/restore gpmc context
+ * to support core off on OMAP3
+ */
+struct omap3_gpmc_regs {
+	u32 sysconfig;
+	u32 irqenable;
+	u32 timeout_ctrl;
+	u32 config;
+	u32 prefetch_config1;
+	u32 prefetch_config2;
+	u32 prefetch_control;
+	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
+};
+
+static int __init omap_gpmc_init(void)
+{
+	struct omap_hwmod *oh;
+	struct platform_device *pdev;
+	char *oh_name = "gpmc";
+
+	/*
+	 * if the board boots up with a populated DT, do not
+	 * manually add the device from this initcall
+	 */
+	if (of_have_populated_dt())
+		return -ENODEV;
+
+	oh = omap_hwmod_lookup(oh_name);
+	if (!oh) {
+		pr_err("Could not look up %s\n", oh_name);
+		return -ENODEV;
+	}
+
+	pdev = omap_device_build(DEVICE_NAME, -1, oh, (void *)&gpmc_pdata,
+				 sizeof(gpmc_pdata));
+	WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
+
+	return PTR_RET(pdev);
+}
+/* must run after machine_init code. i.e. arch_init */
+omap_subsys_initcall(omap_gpmc_init);
+
+/**
+ * gpmc_generic_init - Initialize platform data for a Chip Select
+ *
+ * @cs		chip select number
+ * @type	GPMC_OMAP_TYPE
+ * @settings	GPMC settings
+ * @device_timings	device timings for device on this CS
+ * @gpmc_timings	GPMC timings
+ * @pdev	platform device for the device on this CS
+ * @pdata_size	platform data size for the platform device
+ */
+int gpmc_generic_init(int cs, bool is_nand,
+		      struct gpmc_settings *settings,
+		      struct gpmc_device_timings *device_timings,
+		      struct gpmc_timings *gpmc_timings,
+		      struct platform_device *pdev, unsigned pdata_size)
+{
+	struct gpmc_settings *gpmc_s = NULL;
+	struct gpmc_device_timings *gpmc_dev_t = NULL;
+	struct gpmc_timings *gpmc_t;
+
+	if (cs >= GPMC_CS_NUM) {
+		pr_err("%s: Invalid cs specified. Max CS = %d\n",
+		       __func__, GPMC_CS_NUM);
+		return -EINVAL;
+	}
+
+	if (gpmc_pdata.cs[cs].valid) {
+		pr_err("%s: cs %d already requested, ignoring new request\n",
+		       __func__, cs);
+		return -EINVAL;
+	}
+
+	if (settings) {
+		gpmc_s = kmemdup(settings, sizeof(*settings), GFP_KERNEL);
+		if (!gpmc_s)
+			return -ENOMEM;
+
+		gpmc_pdata.cs[cs].settings = gpmc_s;
+	}
+
+	if (device_timings) {
+		gpmc_dev_t = kmemdup(device_timings, sizeof(*device_timings),
+				     GFP_KERNEL);
+		if (!gpmc_dev_t)
+			goto dev_t_fail;
+
+		gpmc_pdata.cs[cs].device_timings = gpmc_dev_t;
+	}
+
+	if (gpmc_timings) {
+		gpmc_t = kmemdup(gpmc_timings, sizeof(*gpmc_timings),
+				 GFP_KERNEL);
+		if (!gpmc_t)
+			goto gpmc_t_fail;
+
+		gpmc_pdata.cs[cs].gpmc_timings = gpmc_t;
+	}
+
+	gpmc_pdata.cs[cs].is_nand = is_nand;
+	gpmc_pdata.cs[cs].pdev = pdev;
+	gpmc_pdata.cs[cs].pdata_size = pdata_size;
+	gpmc_pdata.cs[cs].valid = true;
+
+	return 0;
+
+gpmc_t_fail:
+	if (device_timings)
+		kfree(gpmc_dev_t);
+dev_t_fail:
+	if (settings)
+		kfree(gpmc_s);
+
+	return -ENOMEM;
+}
+
+
+static struct omap3_gpmc_regs gpmc_context;
+
+/*
+ * Below code only for OMAP3 OFF mode support.
+ * This code must be left back in mach-omap2.
+ */
+void __iomem *omap2_gpmc_base;
+
+void __init omap2_set_globals_gpmc(void __iomem *gpmc)
+{
+	omap2_gpmc_base = gpmc;
+}
+
+static u32 _gpmc_read_reg(u16 reg)
+{
+	return __raw_readl(omap2_gpmc_base + reg);
+}
+
+static void _gpmc_write_reg(u32 val, u16 reg)
+{
+	__raw_readl(omap2_gpmc_base + reg);
+}
+
+static u32 _gpmc_cs_read_reg(int cs, int idx)
+{
+	u16 reg;
+
+	reg = GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
+
+	return _gpmc_read_reg(reg);
+}
+
+static void _gpmc_cs_write_reg(int cs, int idx, u32 val)
+{
+	u16 reg;
+
+	reg = GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
+	_gpmc_write_reg(val, reg);
+}
+
+void omap3_gpmc_save_context(void)
+{
+	int i;
+	u32 val;
+
+	if (!omap2_gpmc_base)
+		return;
+
+	gpmc_context.sysconfig = _gpmc_read_reg(GPMC_SYSCONFIG);
+	gpmc_context.irqenable = _gpmc_read_reg(GPMC_IRQENABLE);
+	gpmc_context.timeout_ctrl = _gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
+	gpmc_context.config = _gpmc_read_reg(GPMC_CONFIG);
+	gpmc_context.prefetch_config1 = _gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
+	gpmc_context.prefetch_config2 = _gpmc_read_reg(GPMC_PREFETCH_CONFIG2);
+	gpmc_context.prefetch_control = _gpmc_read_reg(GPMC_PREFETCH_CONTROL);
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		/* check if valid */
+		val = _gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
+		gpmc_context.cs_context[i].is_valid =
+						val & GPMC_CONFIG7_CSVALID;
+
+		if (gpmc_context.cs_context[i].is_valid) {
+			gpmc_context.cs_context[i].config1 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG1);
+			gpmc_context.cs_context[i].config2 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG2);
+			gpmc_context.cs_context[i].config3 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG3);
+			gpmc_context.cs_context[i].config4 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG4);
+			gpmc_context.cs_context[i].config5 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG5);
+			gpmc_context.cs_context[i].config6 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG6);
+			gpmc_context.cs_context[i].config7 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
+		}
+	}
+}
+
+void omap3_gpmc_restore_context(void)
+{
+	int i;
+
+	if (!omap2_gpmc_base)
+		return;
+
+	_gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig);
+	_gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable);
+	_gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl);
+	_gpmc_write_reg(GPMC_CONFIG, gpmc_context.config);
+	_gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1);
+	_gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2);
+	_gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control);
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		if (gpmc_context.cs_context[i].is_valid) {
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG1,
+					   gpmc_context.cs_context[i].config1);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG2,
+					   gpmc_context.cs_context[i].config2);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG3,
+					   gpmc_context.cs_context[i].config3);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG4,
+					   gpmc_context.cs_context[i].config4);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG5,
+					   gpmc_context.cs_context[i].config5);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG6,
+					   gpmc_context.cs_context[i].config6);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG7,
+					   gpmc_context.cs_context[i].config7);
+		}
+	}
+}
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index c59e9c9..ce611b0 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -31,6 +31,16 @@ config TI_EMIF
 	  parameters and other settings during frequency, voltage and
 	  temperature changes
 
+config TI_GPMC
+	bool "Texas Instruments GPMC driver"
+	depends on ARCH_OMAP2PLUS
+	default y
+	help
+	 This driver is for the General Purpose Memory Controller (GPMC)
+	 present on Texas Instruments SoCs (e.g. OMAP2+). GPMC allows
+	 interfacing to a variety of asynchronous as well as synchronous
+	 memory drives like NOR, NAND, OneNAND, SRAM.
+
 config MVEBU_DEVBUS
 	bool "Marvell EBU Device Bus Controller"
 	default y
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index 71160a2..329b7b6 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_OF)		+= of_memory.o
 endif
 obj-$(CONFIG_TI_AEMIF)		+= ti-aemif.o
 obj-$(CONFIG_TI_EMIF)		+= emif.o
+obj-$(CONFIG_TI_GPMC)		+= ti-gpmc.o
 obj-$(CONFIG_FSL_IFC)		+= fsl_ifc.o
 obj-$(CONFIG_MVEBU_DEVBUS)	+= mvebu-devbus.o
 obj-$(CONFIG_TEGRA20_MC)	+= tegra20-mc.o
diff --git a/arch/arm/mach-omap2/gpmc.c b/drivers/memory/ti-gpmc.c
similarity index 90%
rename from arch/arm/mach-omap2/gpmc.c
rename to drivers/memory/ti-gpmc.c
index 9173f71..3bb2fd6 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/drivers/memory/ti-gpmc.c
@@ -33,13 +33,7 @@
 #include <linux/slab.h>
 
 #include <linux/platform_data/mtd-nand-omap2.h>
-
-#include <asm/mach-types.h>
-
-#include "soc.h"
-#include "common.h"
-#include "omap_device.h"
-#include "gpmc.h"
+#include <linux/platform_data/gpmc-omap.h>
 
 #define	DEVICE_NAME		"omap-gpmc"
 
@@ -154,35 +148,6 @@
 
 #define GPMC_NR_WAITPINS		4
 
-static struct gpmc_omap_platform_data gpmc_pdata;
-
-/* Structure to save gpmc cs context */
-struct gpmc_cs_config {
-	u32 config1;
-	u32 config2;
-	u32 config3;
-	u32 config4;
-	u32 config5;
-	u32 config6;
-	u32 config7;
-	int is_valid;
-};
-
-/*
- * Structure to save/restore gpmc context
- * to support core off on OMAP3
- */
-struct omap3_gpmc_regs {
-	u32 sysconfig;
-	u32 irqenable;
-	u32 timeout_ctrl;
-	u32 config;
-	u32 prefetch_config1;
-	u32 prefetch_config2;
-	u32 prefetch_control;
-	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
-};
-
 static struct resource	gpmc_mem_root;
 static struct resource	gpmc_cs_mem[GPMC_CS_NUM];
 static DEFINE_SPINLOCK(gpmc_mem_lock);
@@ -230,7 +195,7 @@ static unsigned long gpmc_get_fclk_period(void)
 	unsigned long rate = clk_get_rate(gpmc_l3_clk);
 
 	if (rate == 0) {
-		printk(KERN_WARNING "gpmc_l3_clk not enabled\n");
+		pr_warn("%s: gpmc_l3_clk not enabled\n", __func__);
 		return 0;
 	}
 
@@ -323,8 +288,8 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
 	nr_bits = end_bit - st_bit + 1;
 	if (ticks >= 1 << nr_bits) {
 #ifdef DEBUG
-		printk(KERN_INFO "GPMC CS%d: %-10s* %3d ns, %3d ticks >= %d\n",
-				cs, name, time, ticks, 1 << nr_bits);
+		pr_info("GPMC CS%d: %-10s* %3d ns, %3d ticks >= %d\n",
+			cs, name, time, ticks, 1 << nr_bits);
 #endif
 		return -1;
 	}
@@ -332,10 +297,9 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
 	mask = (1 << nr_bits) - 1;
 	l = gpmc_cs_read_reg(cs, reg);
 #ifdef DEBUG
-	printk(KERN_INFO
-		"GPMC CS%d: %-10s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n",
-	       cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000,
-			(l >> st_bit) & mask, time);
+	pr_info("GPMC CS%d: %-10s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n",
+		cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000,
+		(l >> st_bit) & mask, time);
 #endif
 	l &= ~(mask << st_bit);
 	l |= ticks << st_bit;
@@ -346,13 +310,11 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
 
 #ifdef DEBUG
 #define GPMC_SET_ONE(reg, st, end, field) \
-	if (set_gpmc_timing_reg(cs, (reg), (st), (end),		\
-			t->field, #field) < 0)			\
-		return -1
+	set_gpmc_timing_reg(cs, (reg), (st), (end),		\
+			t->field, #field)
 #else
 #define GPMC_SET_ONE(reg, st, end, field) \
-	if (set_gpmc_timing_reg(cs, (reg), (st), (end), t->field) < 0) \
-		return -1
+	set_gpmc_timing_reg(cs, (reg), (st), (end), t->field)
 #endif
 
 static int gpmc_calc_divider(unsigned int sync_clk)
@@ -415,8 +377,8 @@ static int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
 	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
 	if (l & (GPMC_CONFIG1_READTYPE_SYNC | GPMC_CONFIG1_WRITETYPE_SYNC)) {
 #ifdef DEBUG
-		printk(KERN_INFO "GPMC CS%d CLK period is %lu ns (div %d)\n",
-				cs, (div * gpmc_get_fclk_period()) / 1000, div);
+		pr_info("GPMC CS%d CLK period is %lu ns (div %d)\n",
+			cs, (div * gpmc_get_fclk_period()) / 1000, div);
 #endif
 		l &= ~0x03;
 		l |= (div - 1);
@@ -557,7 +519,7 @@ static int gpmc_cs_remap(int cs, u32 base)
 	 * Make sure we ignore any device offsets from the GPMC partition
 	 * allocated for the chip select and that the new base confirms
 	 * to the GPMC 16MB minimum granularity.
-	 */ 
+	 */
 	base &= ~(SZ_16M - 1);
 
 	gpmc_cs_get_memconf(cs, &old_base, &size);
@@ -622,7 +584,7 @@ static void gpmc_cs_free(int cs)
 
 	spin_lock(&gpmc_mem_lock);
 	if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) {
-		printk(KERN_ERR "Trying to free non-reserved GPMC CS%d\n", cs);
+		pr_err("Trying to free non-reserved GPMC CS%d\n", cs);
 		BUG();
 		spin_unlock(&gpmc_mem_lock);
 		return;
@@ -643,7 +605,6 @@ static void gpmc_mem_exit(void)
 			continue;
 		gpmc_cs_delete_mem(cs);
 	}
-
 }
 
 static void gpmc_mem_init(void)
@@ -709,7 +670,7 @@ static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t,
 	if (mux) {
 		temp = max_t(u32, temp,	gpmc_t->clk_activation + dev_t->t_ach);
 		temp = max_t(u32, temp, gpmc_t->adv_rd_off +
-				gpmc_ticks_to_ps(dev_t->cyc_aavdh_oe));
+			     gpmc_ticks_to_ps(dev_t->cyc_aavdh_oe));
 	}
 	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
 
@@ -722,7 +683,7 @@ static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t,
 	temp += gpmc_t->clk_activation;
 	if (dev_t->cyc_oe)
 		temp = max_t(u32, temp, gpmc_t->oe_on +
-				gpmc_ticks_to_ps(dev_t->cyc_oe));
+			     gpmc_ticks_to_ps(dev_t->cyc_oe));
 	gpmc_t->access = gpmc_round_ps_to_ticks(temp);
 
 	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ps(1);
@@ -731,7 +692,7 @@ static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t,
 	/* rd_cycle */
 	temp = max_t(u32, dev_t->t_cez_r, dev_t->t_oez);
 	temp = gpmc_round_ps_to_sync_clk(temp, gpmc_t->sync_clk) +
-							gpmc_t->access;
+					 gpmc_t->access;
 	/* XXX: barter t_ce_rdyz with t_cez_r ? */
 	if (dev_t->t_ce_rdyz)
 		temp = max_t(u32, temp,	gpmc_t->cs_rd_off + dev_t->t_ce_rdyz);
@@ -750,22 +711,22 @@ static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t,
 	temp = dev_t->t_avdp_w;
 	if (mux) {
 		temp = max_t(u32, temp,
-			gpmc_t->clk_activation + dev_t->t_avdh);
+			     gpmc_t->clk_activation + dev_t->t_avdh);
 		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
 	}
 	gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp);
 
 	/* wr_data_mux_bus */
 	temp = max_t(u32, dev_t->t_weasu,
-			gpmc_t->clk_activation + dev_t->t_rdyo);
+		     gpmc_t->clk_activation + dev_t->t_rdyo);
 	/* XXX: shouldn't mux be kept as a whole for wr_data_mux_bus ?,
 	 * and in that case remember to handle we_on properly
 	 */
 	if (mux) {
 		temp = max_t(u32, temp,
-			gpmc_t->adv_wr_off + dev_t->t_aavdh);
+			     gpmc_t->adv_wr_off + dev_t->t_aavdh);
 		temp = max_t(u32, temp, gpmc_t->adv_wr_off +
-				gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
+			     gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
 	}
 	gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp);
 
@@ -782,13 +743,13 @@ static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t,
 	/* we_off */
 	temp = gpmc_t->we_on + dev_t->t_wpl;
 	temp = max_t(u32, temp,
-			gpmc_t->wr_access + gpmc_ticks_to_ps(1));
+		     gpmc_t->wr_access + gpmc_ticks_to_ps(1));
 	temp = max_t(u32, temp,
-		gpmc_t->we_on + gpmc_ticks_to_ps(dev_t->cyc_wpl));
+		     gpmc_t->we_on + gpmc_ticks_to_ps(dev_t->cyc_wpl));
 	gpmc_t->we_off = gpmc_round_ps_to_ticks(temp);
 
 	gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off +
-							dev_t->t_wph);
+						   dev_t->t_wph);
 
 	/* wr_cycle */
 	temp = gpmc_round_ps_to_sync_clk(dev_t->t_cez_w, gpmc_t->sync_clk);
@@ -796,7 +757,7 @@ static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t,
 	/* XXX: barter t_ce_rdyz with t_cez_w ? */
 	if (dev_t->t_ce_rdyz)
 		temp = max_t(u32, temp,
-				 gpmc_t->cs_wr_off + dev_t->t_ce_rdyz);
+			     gpmc_t->cs_wr_off + dev_t->t_ce_rdyz);
 	gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp);
 
 	return 0;
@@ -818,16 +779,16 @@ static int gpmc_calc_async_read_timings(struct gpmc_timings *gpmc_t,
 	temp = dev_t->t_oeasu;
 	if (mux)
 		temp = max_t(u32, temp,
-			gpmc_t->adv_rd_off + dev_t->t_aavdh);
+			     gpmc_t->adv_rd_off + dev_t->t_aavdh);
 	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
 
 	/* access */
 	temp = max_t(u32, dev_t->t_iaa, /* XXX: remove t_iaa in async ? */
-				gpmc_t->oe_on + dev_t->t_oe);
+		     gpmc_t->oe_on + dev_t->t_oe);
 	temp = max_t(u32, temp,
-				gpmc_t->cs_on + dev_t->t_ce);
+		     gpmc_t->cs_on + dev_t->t_ce);
 	temp = max_t(u32, temp,
-				gpmc_t->adv_on + dev_t->t_aa);
+		     gpmc_t->adv_on + dev_t->t_aa);
 	gpmc_t->access = gpmc_round_ps_to_ticks(temp);
 
 	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ps(1);
@@ -835,7 +796,7 @@ static int gpmc_calc_async_read_timings(struct gpmc_timings *gpmc_t,
 
 	/* rd_cycle */
 	temp = max_t(u32, dev_t->t_rd_cycle,
-			gpmc_t->cs_rd_off + dev_t->t_cez_r);
+		     gpmc_t->cs_rd_off + dev_t->t_cez_r);
 	temp = max_t(u32, temp, gpmc_t->oe_off + dev_t->t_oez);
 	gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp);
 
@@ -859,7 +820,7 @@ static int gpmc_calc_async_write_timings(struct gpmc_timings *gpmc_t,
 	if (mux) {
 		temp = max_t(u32, temp,	gpmc_t->adv_wr_off + dev_t->t_aavdh);
 		temp = max_t(u32, temp, gpmc_t->adv_wr_off +
-				gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
+			     gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
 	}
 	gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp);
 
@@ -874,27 +835,26 @@ static int gpmc_calc_async_write_timings(struct gpmc_timings *gpmc_t,
 	gpmc_t->we_off = gpmc_round_ps_to_ticks(temp);
 
 	gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off +
-							dev_t->t_wph);
+						   dev_t->t_wph);
 
 	/* wr_cycle */
 	temp = max_t(u32, dev_t->t_wr_cycle,
-				gpmc_t->cs_wr_off + dev_t->t_cez_w);
+		     gpmc_t->cs_wr_off + dev_t->t_cez_w);
 	gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp);
 
 	return 0;
 }
 
 static int gpmc_calc_sync_common_timings(struct gpmc_timings *gpmc_t,
-			struct gpmc_device_timings *dev_t)
+					 struct gpmc_device_timings *dev_t)
 {
 	u32 temp;
 
 	gpmc_t->sync_clk = gpmc_calc_divider(dev_t->clk) *
-						gpmc_get_fclk_period();
+					     gpmc_get_fclk_period();
 
-	gpmc_t->page_burst_access = gpmc_round_ps_to_sync_clk(
-					dev_t->t_bacc,
-					gpmc_t->sync_clk);
+	gpmc_t->page_burst_access = gpmc_round_ps_to_sync_clk(dev_t->t_bacc,
+							      gpmc_t->sync_clk);
 
 	temp = max_t(u32, dev_t->t_ces, dev_t->t_avds);
 	gpmc_t->clk_activation = gpmc_round_ps_to_ticks(temp);
@@ -927,7 +887,7 @@ static int gpmc_calc_common_timings(struct gpmc_timings *gpmc_t,
 	temp = dev_t->t_avdasu;
 	if (dev_t->t_ce_avd)
 		temp = max_t(u32, temp,
-				gpmc_t->cs_on + dev_t->t_ce_avd);
+			     gpmc_t->cs_on + dev_t->t_ce_avd);
 	gpmc_t->adv_on = gpmc_round_ps_to_ticks(temp);
 
 	if (sync)
@@ -1084,7 +1044,7 @@ static struct of_device_id gpmc_dt_ids[] = {
 	{ .compatible = "ti,omap2420-gpmc" },
 	{ .compatible = "ti,omap2430-gpmc" },
 	{ .compatible = "ti,omap3430-gpmc" },	/* omap3430 & omap3630 */
-	{ .compatible = "ti,omap4430-gpmc" },	/* omap4430 & omap4460 & omap543x */
+	{ .compatible = "ti,omap4430-gpmc" },	/* omap4 & omap543x */
 	{ .compatible = "ti,am3352-gpmc" },	/* am335x devices */
 	{ }
 };
@@ -1205,7 +1165,7 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
  * Returns 0 on success and appropriate negative error code on failure.
  */
 static int gpmc_probe_generic_child(struct platform_device *pdev,
-				struct device_node *child)
+				    struct device_node *child)
 {
 	struct gpmc_settings gpmc_s;
 	struct gpmc_timings gpmc_t;
@@ -1341,7 +1301,7 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 		return -EINVAL;
 	} else if (gpmc_cs_num > GPMC_CS_NUM) {
 		pr_err("%s: number of supported chip-selects cannot be > %d\n",
-					 __func__, GPMC_CS_NUM);
+		       __func__, GPMC_CS_NUM);
 		return -EINVAL;
 	}
 
@@ -1353,7 +1313,6 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 	}
 
 	for_each_child_of_node(pdev->dev.of_node, child) {
-
 		if (!child->name)
 			continue;
 
@@ -1625,6 +1584,7 @@ static int gpmc_probe(struct platform_device *pdev)
 
 	/* Now the GPMC is initialised, unreserve the chip-selects */
 	gpmc_cs_map = 0;
+	gpmc_dev = dev;
 
 	if (dev->of_node) {
 		rc = gpmc_probe_dt(pdev);
@@ -1661,9 +1621,100 @@ static int gpmc_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM_SLEEP
+/* Structure to save gpmc cs context */
+struct gpmc_cs_config {
+	u32 config1;
+	u32 config2;
+	u32 config3;
+	u32 config4;
+	u32 config5;
+	u32 config6;
+	u32 config7;
+	int is_valid;
+};
+
+/*
+ * Structure to save/restore gpmc context
+ */
+struct omap_gpmc_regs {
+	u32 sysconfig;
+	u32 irqenable;
+	u32 timeout_ctrl;
+	u32 config;
+	u32 prefetch_config1;
+	u32 prefetch_config2;
+	u32 prefetch_control;
+	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
+};
+
+static struct omap_gpmc_regs gpmc_context;
+
+void omap_gpmc_save_context(void)
+{
+	int i;
+
+	gpmc_context.sysconfig = gpmc_read_reg(GPMC_SYSCONFIG);
+	gpmc_context.irqenable = gpmc_read_reg(GPMC_IRQENABLE);
+	gpmc_context.timeout_ctrl = gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
+	gpmc_context.config = gpmc_read_reg(GPMC_CONFIG);
+	gpmc_context.prefetch_config1 = gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
+	gpmc_context.prefetch_config2 = gpmc_read_reg(GPMC_PREFETCH_CONFIG2);
+	gpmc_context.prefetch_control = gpmc_read_reg(GPMC_PREFETCH_CONTROL);
+	for (i = 0; i < gpmc_cs_num; i++) {
+		gpmc_context.cs_context[i].is_valid = gpmc_cs_mem_enabled(i);
+		if (gpmc_context.cs_context[i].is_valid) {
+			gpmc_context.cs_context[i].config1 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG1);
+			gpmc_context.cs_context[i].config2 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG2);
+			gpmc_context.cs_context[i].config3 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG3);
+			gpmc_context.cs_context[i].config4 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG4);
+			gpmc_context.cs_context[i].config5 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG5);
+			gpmc_context.cs_context[i].config6 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG6);
+			gpmc_context.cs_context[i].config7 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
+		}
+	}
+}
+
+void omap_gpmc_restore_context(void)
+{
+	int i;
+
+	gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig);
+	gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable);
+	gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl);
+	gpmc_write_reg(GPMC_CONFIG, gpmc_context.config);
+	gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1);
+	gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2);
+	gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control);
+	for (i = 0; i < gpmc_cs_num; i++) {
+		if (gpmc_context.cs_context[i].is_valid) {
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG1,
+					  gpmc_context.cs_context[i].config1);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG2,
+					  gpmc_context.cs_context[i].config2);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG3,
+					  gpmc_context.cs_context[i].config3);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG4,
+					  gpmc_context.cs_context[i].config4);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG5,
+					  gpmc_context.cs_context[i].config5);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG6,
+					  gpmc_context.cs_context[i].config6);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG7,
+					  gpmc_context.cs_context[i].config7);
+		}
+	}
+}
+
 static int gpmc_suspend(struct device *dev)
 {
-	omap3_gpmc_save_context();
+	omap_gpmc_save_context();
 	pm_runtime_put_sync(dev);
 	return 0;
 }
@@ -1671,7 +1722,7 @@ static int gpmc_suspend(struct device *dev)
 static int gpmc_resume(struct device *dev)
 {
 	pm_runtime_get_sync(dev);
-	omap3_gpmc_restore_context();
+	omap_gpmc_restore_context();
 	return 0;
 }
 #endif
@@ -1697,116 +1748,11 @@ static __init int gpmc_init(void)
 static __exit void gpmc_exit(void)
 {
 	platform_driver_unregister(&gpmc_driver);
-
 }
 
 module_init(gpmc_init);
 module_exit(gpmc_exit);
 
-static int __init omap_gpmc_init(void)
-{
-	struct omap_hwmod *oh;
-	struct platform_device *pdev;
-	char *oh_name = "gpmc";
-
-	/*
-	 * if the board boots up with a populated DT, do not
-	 * manually add the device from this initcall
-	 */
-	if (of_have_populated_dt())
-		return -ENODEV;
-
-	oh = omap_hwmod_lookup(oh_name);
-	if (!oh) {
-		pr_err("Could not look up %s\n", oh_name);
-		return -ENODEV;
-	}
-
-	pdev = omap_device_build(DEVICE_NAME, -1, oh, (void *)&gpmc_pdata,
-				 sizeof(gpmc_pdata));
-	WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
-
-	return PTR_RET(pdev);
-}
-/* must run after machine_init code. i.e. arch_init */
-omap_subsys_initcall(omap_gpmc_init);
-
-/**
- * gpmc_generic_init - Initialize platform data for a Chip Select
- *
- * @cs		chip select number
- * @is_nand	true if device is NAND flash.
- * @settings	GPMC settings
- * @device_timings	device timings for device on this CS
- * @gpmc_timings	GPMC timings
- * @pdev	platform device for the device on this CS
- * @pdata_size	platform data size for the platform device
- */
-int gpmc_generic_init(int cs, bool is_nand,
-		      struct gpmc_settings *settings,
-		      struct gpmc_device_timings *device_timings,
-		      struct gpmc_timings *gpmc_timings,
-		      struct platform_device *pdev, unsigned pdata_size)
-{
-	struct gpmc_settings *gpmc_s = NULL;
-	struct gpmc_device_timings *gpmc_dev_t = NULL;
-	struct gpmc_timings *gpmc_t;
-
-	if (cs >= GPMC_CS_NUM) {
-		pr_err("%s: Invalid cs specified. Max CS = %d\n",
-		       __func__, GPMC_CS_NUM);
-		return -EINVAL;
-	}
-
-	if (gpmc_pdata.cs[cs].valid) {
-		pr_err("%s: cs %d already requested, ignoring new request\n",
-		       __func__, cs);
-		return -EINVAL;
-	}
-
-	if (settings) {
-		gpmc_s = kmemdup(settings, sizeof(*settings), GFP_KERNEL);
-		if (!gpmc_s)
-			return -ENOMEM;
-
-		gpmc_pdata.cs[cs].settings = gpmc_s;
-	}
-
-	if (device_timings) {
-		gpmc_dev_t = kmemdup(device_timings, sizeof(*device_timings),
-				     GFP_KERNEL);
-		if (!gpmc_dev_t)
-			goto dev_t_fail;
-
-		gpmc_pdata.cs[cs].device_timings = gpmc_dev_t;
-	}
-
-	if (gpmc_timings) {
-		gpmc_t = kmemdup(gpmc_timings, sizeof(*gpmc_timings),
-				 GFP_KERNEL);
-		if (!gpmc_t)
-			goto gpmc_t_fail;
-
-		gpmc_pdata.cs[cs].gpmc_timings = gpmc_t;
-	}
-
-	gpmc_pdata.cs[cs].is_nand = is_nand;
-	gpmc_pdata.cs[cs].pdev = pdev;
-	gpmc_pdata.cs[cs].pdata_size = pdata_size;
-	gpmc_pdata.cs[cs].valid = true;
-
-	return 0;
-
-gpmc_t_fail:
-	if (device_timings)
-		kfree(gpmc_dev_t);
-dev_t_fail:
-	if (settings)
-		kfree(gpmc_s);
-
-	return -ENOMEM;
-}
-
 /**
  * omap_gpmc_retime - Reconfigre GPMC timings for the device
  *
@@ -1881,67 +1827,3 @@ unsigned long omap_gpmc_get_clk_period(int cs,
 }
 EXPORT_SYMBOL_GPL(omap_gpmc_get_clk_period);
 
-static struct omap3_gpmc_regs gpmc_context;
-
-void omap3_gpmc_save_context(void)
-{
-	int i;
-
-	gpmc_context.sysconfig = gpmc_read_reg(GPMC_SYSCONFIG);
-	gpmc_context.irqenable = gpmc_read_reg(GPMC_IRQENABLE);
-	gpmc_context.timeout_ctrl = gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
-	gpmc_context.config = gpmc_read_reg(GPMC_CONFIG);
-	gpmc_context.prefetch_config1 = gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
-	gpmc_context.prefetch_config2 = gpmc_read_reg(GPMC_PREFETCH_CONFIG2);
-	gpmc_context.prefetch_control = gpmc_read_reg(GPMC_PREFETCH_CONTROL);
-	for (i = 0; i < gpmc_cs_num; i++) {
-		gpmc_context.cs_context[i].is_valid = gpmc_cs_mem_enabled(i);
-		if (gpmc_context.cs_context[i].is_valid) {
-			gpmc_context.cs_context[i].config1 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG1);
-			gpmc_context.cs_context[i].config2 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG2);
-			gpmc_context.cs_context[i].config3 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG3);
-			gpmc_context.cs_context[i].config4 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG4);
-			gpmc_context.cs_context[i].config5 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG5);
-			gpmc_context.cs_context[i].config6 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG6);
-			gpmc_context.cs_context[i].config7 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
-		}
-	}
-}
-
-void omap3_gpmc_restore_context(void)
-{
-	int i;
-
-	gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig);
-	gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable);
-	gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl);
-	gpmc_write_reg(GPMC_CONFIG, gpmc_context.config);
-	gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1);
-	gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2);
-	gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control);
-	for (i = 0; i < gpmc_cs_num; i++) {
-		if (gpmc_context.cs_context[i].is_valid) {
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG1,
-				gpmc_context.cs_context[i].config1);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG2,
-				gpmc_context.cs_context[i].config2);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG3,
-				gpmc_context.cs_context[i].config3);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG4,
-				gpmc_context.cs_context[i].config4);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG5,
-				gpmc_context.cs_context[i].config5);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG6,
-				gpmc_context.cs_context[i].config6);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG7,
-				gpmc_context.cs_context[i].config7);
-		}
-	}
-}
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index f1cf503..e1db2c1 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -89,7 +89,7 @@ config MTD_NAND_AMS_DELTA
 
 config MTD_NAND_OMAP2
 	tristate "NAND Flash device on OMAP2, OMAP3 and OMAP4"
-	depends on ARCH_OMAP2PLUS
+	depends on TI_GPMC
 	help
           Support for NAND flash on Texas Instruments OMAP2, OMAP3 and OMAP4
 	  platforms.
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig
index ab260727..272c16c 100644
--- a/drivers/mtd/onenand/Kconfig
+++ b/drivers/mtd/onenand/Kconfig
@@ -24,10 +24,10 @@ config MTD_ONENAND_GENERIC
 	  Support for OneNAND flash via platform device driver.
 
 config MTD_ONENAND_OMAP2
-	tristate "OneNAND on OMAP2/OMAP3 support"
-	depends on ARCH_OMAP2 || ARCH_OMAP3
+	tristate "OneNAND on OMAP2+ support"
+	depends on TI_GPMC
 	help
-	  Support for a OneNAND flash device connected to an OMAP2/OMAP3 CPU
+	  Support for a OneNAND flash device connected to an OMAP2+ SoCs
 	  via the GPMC memory controller.
 
 config MTD_ONENAND_SAMSUNG
-- 
1.8.3.2


--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [resend][PATCH 35/36] ARM: OMAP2+: gpmc: move GPMC driver into drivers/memory
@ 2014-06-11 11:45     ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11 11:45 UTC (permalink / raw)
  To: tony, dwmw2, computersforpeace
  Cc: devicetree, nsekhar, linux-kernel, kyungmin.park, linux-mtd,
	pekon, ezequiel.garcia, javier, linux-omap

Resending with rename detection option to git-format-patch
for easier review.

From: Roger Quadros <rogerq@ti.com>

Move the GPMC driver out of mach-omap2. We leave behind only
the mach-omap2 specific bits in mach-omap2/gpmc_legacy.c
i.e. gpmc_generic_init() for use by board files to register
the GPMC configuration and omap3_gpmc_save/restore_context() for
use by OMAP3 OFF mode support.

The GPMC driver is now enabled by its own kernel config option
TI_GPMC. The other drivers that need GPMC to work i.e. MTD_ONENAND_OMAP2
and MTD_NAND_OMAP2 are made to depend on TI_GPMC.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/Makefile                       |   2 +-
 arch/arm/mach-omap2/gpmc_legacy.c                  | 296 ++++++++++++++++
 drivers/memory/Kconfig                             |  10 +
 drivers/memory/Makefile                            |   1 +
 .../mach-omap2/gpmc.c => drivers/memory/ti-gpmc.c  | 388 +++++++--------------
 drivers/mtd/nand/Kconfig                           |   2 +-
 drivers/mtd/onenand/Kconfig                        |   6 +-
 7 files changed, 447 insertions(+), 258 deletions(-)
 create mode 100644 arch/arm/mach-omap2/gpmc_legacy.c
 rename arch/arm/mach-omap2/gpmc.c => drivers/memory/ti-gpmc.c (90%)

diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 8421f38..a2e7426 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -6,7 +6,7 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
 	-I$(srctree)/arch/arm/plat-omap/include
 
 # Common support
-obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o gpmc.o timer.o pm.o \
+obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o gpmc_legacy.o timer.o pm.o \
 	 common.o gpio.o dma.o wd_timer.o display.o i2c.o hdq1w.o omap_hwmod.o \
 	 omap_device.o sram.o drm.o
 
diff --git a/arch/arm/mach-omap2/gpmc_legacy.c b/arch/arm/mach-omap2/gpmc_legacy.c
new file mode 100644
index 0000000..3b3f86e
--- /dev/null
+++ b/arch/arm/mach-omap2/gpmc_legacy.c
@@ -0,0 +1,296 @@
+/*
+ * GPMC support functions
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation
+ *
+ * Author: Juha Yrjola
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#include "soc.h"
+#include "gpmc.h"
+#include "omap_device.h"
+
+#define	DEVICE_NAME		"omap-gpmc"
+
+/* CS CONFIG registers */
+#define GPMC_CS_CONFIG1		0x00
+#define GPMC_CS_CONFIG2		0x04
+#define GPMC_CS_CONFIG3		0x08
+#define GPMC_CS_CONFIG4		0x0c
+#define GPMC_CS_CONFIG5		0x10
+#define GPMC_CS_CONFIG6		0x14
+#define GPMC_CS_CONFIG7		0x18
+
+#define GPMC_CS0_OFFSET		0x60
+#define GPMC_CS_SIZE		0x30
+
+/* GPMC register offsets */
+#define GPMC_SYSCONFIG		0x10
+#define GPMC_IRQENABLE		0x1c
+#define GPMC_TIMEOUT_CONTROL	0x40
+#define GPMC_CONFIG		0x50
+#define GPMC_PREFETCH_CONFIG1	0x1e0
+#define GPMC_PREFETCH_CONFIG2	0x1e4
+#define GPMC_PREFETCH_CONTROL	0x1ec
+
+#define GPMC_CONFIG7_CSVALID		(1 << 6)
+
+static struct gpmc_omap_platform_data gpmc_pdata;
+
+/* Structure to save gpmc cs context */
+struct gpmc_cs_config {
+	u32 config1;
+	u32 config2;
+	u32 config3;
+	u32 config4;
+	u32 config5;
+	u32 config6;
+	u32 config7;
+	int is_valid;
+};
+
+/*
+ * Structure to save/restore gpmc context
+ * to support core off on OMAP3
+ */
+struct omap3_gpmc_regs {
+	u32 sysconfig;
+	u32 irqenable;
+	u32 timeout_ctrl;
+	u32 config;
+	u32 prefetch_config1;
+	u32 prefetch_config2;
+	u32 prefetch_control;
+	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
+};
+
+static int __init omap_gpmc_init(void)
+{
+	struct omap_hwmod *oh;
+	struct platform_device *pdev;
+	char *oh_name = "gpmc";
+
+	/*
+	 * if the board boots up with a populated DT, do not
+	 * manually add the device from this initcall
+	 */
+	if (of_have_populated_dt())
+		return -ENODEV;
+
+	oh = omap_hwmod_lookup(oh_name);
+	if (!oh) {
+		pr_err("Could not look up %s\n", oh_name);
+		return -ENODEV;
+	}
+
+	pdev = omap_device_build(DEVICE_NAME, -1, oh, (void *)&gpmc_pdata,
+				 sizeof(gpmc_pdata));
+	WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
+
+	return PTR_RET(pdev);
+}
+/* must run after machine_init code. i.e. arch_init */
+omap_subsys_initcall(omap_gpmc_init);
+
+/**
+ * gpmc_generic_init - Initialize platform data for a Chip Select
+ *
+ * @cs		chip select number
+ * @type	GPMC_OMAP_TYPE
+ * @settings	GPMC settings
+ * @device_timings	device timings for device on this CS
+ * @gpmc_timings	GPMC timings
+ * @pdev	platform device for the device on this CS
+ * @pdata_size	platform data size for the platform device
+ */
+int gpmc_generic_init(int cs, bool is_nand,
+		      struct gpmc_settings *settings,
+		      struct gpmc_device_timings *device_timings,
+		      struct gpmc_timings *gpmc_timings,
+		      struct platform_device *pdev, unsigned pdata_size)
+{
+	struct gpmc_settings *gpmc_s = NULL;
+	struct gpmc_device_timings *gpmc_dev_t = NULL;
+	struct gpmc_timings *gpmc_t;
+
+	if (cs >= GPMC_CS_NUM) {
+		pr_err("%s: Invalid cs specified. Max CS = %d\n",
+		       __func__, GPMC_CS_NUM);
+		return -EINVAL;
+	}
+
+	if (gpmc_pdata.cs[cs].valid) {
+		pr_err("%s: cs %d already requested, ignoring new request\n",
+		       __func__, cs);
+		return -EINVAL;
+	}
+
+	if (settings) {
+		gpmc_s = kmemdup(settings, sizeof(*settings), GFP_KERNEL);
+		if (!gpmc_s)
+			return -ENOMEM;
+
+		gpmc_pdata.cs[cs].settings = gpmc_s;
+	}
+
+	if (device_timings) {
+		gpmc_dev_t = kmemdup(device_timings, sizeof(*device_timings),
+				     GFP_KERNEL);
+		if (!gpmc_dev_t)
+			goto dev_t_fail;
+
+		gpmc_pdata.cs[cs].device_timings = gpmc_dev_t;
+	}
+
+	if (gpmc_timings) {
+		gpmc_t = kmemdup(gpmc_timings, sizeof(*gpmc_timings),
+				 GFP_KERNEL);
+		if (!gpmc_t)
+			goto gpmc_t_fail;
+
+		gpmc_pdata.cs[cs].gpmc_timings = gpmc_t;
+	}
+
+	gpmc_pdata.cs[cs].is_nand = is_nand;
+	gpmc_pdata.cs[cs].pdev = pdev;
+	gpmc_pdata.cs[cs].pdata_size = pdata_size;
+	gpmc_pdata.cs[cs].valid = true;
+
+	return 0;
+
+gpmc_t_fail:
+	if (device_timings)
+		kfree(gpmc_dev_t);
+dev_t_fail:
+	if (settings)
+		kfree(gpmc_s);
+
+	return -ENOMEM;
+}
+
+
+static struct omap3_gpmc_regs gpmc_context;
+
+/*
+ * Below code only for OMAP3 OFF mode support.
+ * This code must be left back in mach-omap2.
+ */
+void __iomem *omap2_gpmc_base;
+
+void __init omap2_set_globals_gpmc(void __iomem *gpmc)
+{
+	omap2_gpmc_base = gpmc;
+}
+
+static u32 _gpmc_read_reg(u16 reg)
+{
+	return __raw_readl(omap2_gpmc_base + reg);
+}
+
+static void _gpmc_write_reg(u32 val, u16 reg)
+{
+	__raw_readl(omap2_gpmc_base + reg);
+}
+
+static u32 _gpmc_cs_read_reg(int cs, int idx)
+{
+	u16 reg;
+
+	reg = GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
+
+	return _gpmc_read_reg(reg);
+}
+
+static void _gpmc_cs_write_reg(int cs, int idx, u32 val)
+{
+	u16 reg;
+
+	reg = GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
+	_gpmc_write_reg(val, reg);
+}
+
+void omap3_gpmc_save_context(void)
+{
+	int i;
+	u32 val;
+
+	if (!omap2_gpmc_base)
+		return;
+
+	gpmc_context.sysconfig = _gpmc_read_reg(GPMC_SYSCONFIG);
+	gpmc_context.irqenable = _gpmc_read_reg(GPMC_IRQENABLE);
+	gpmc_context.timeout_ctrl = _gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
+	gpmc_context.config = _gpmc_read_reg(GPMC_CONFIG);
+	gpmc_context.prefetch_config1 = _gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
+	gpmc_context.prefetch_config2 = _gpmc_read_reg(GPMC_PREFETCH_CONFIG2);
+	gpmc_context.prefetch_control = _gpmc_read_reg(GPMC_PREFETCH_CONTROL);
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		/* check if valid */
+		val = _gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
+		gpmc_context.cs_context[i].is_valid =
+						val & GPMC_CONFIG7_CSVALID;
+
+		if (gpmc_context.cs_context[i].is_valid) {
+			gpmc_context.cs_context[i].config1 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG1);
+			gpmc_context.cs_context[i].config2 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG2);
+			gpmc_context.cs_context[i].config3 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG3);
+			gpmc_context.cs_context[i].config4 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG4);
+			gpmc_context.cs_context[i].config5 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG5);
+			gpmc_context.cs_context[i].config6 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG6);
+			gpmc_context.cs_context[i].config7 =
+				_gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
+		}
+	}
+}
+
+void omap3_gpmc_restore_context(void)
+{
+	int i;
+
+	if (!omap2_gpmc_base)
+		return;
+
+	_gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig);
+	_gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable);
+	_gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl);
+	_gpmc_write_reg(GPMC_CONFIG, gpmc_context.config);
+	_gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1);
+	_gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2);
+	_gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control);
+	for (i = 0; i < GPMC_CS_NUM; i++) {
+		if (gpmc_context.cs_context[i].is_valid) {
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG1,
+					   gpmc_context.cs_context[i].config1);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG2,
+					   gpmc_context.cs_context[i].config2);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG3,
+					   gpmc_context.cs_context[i].config3);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG4,
+					   gpmc_context.cs_context[i].config4);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG5,
+					   gpmc_context.cs_context[i].config5);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG6,
+					   gpmc_context.cs_context[i].config6);
+			_gpmc_cs_write_reg(i, GPMC_CS_CONFIG7,
+					   gpmc_context.cs_context[i].config7);
+		}
+	}
+}
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index c59e9c9..ce611b0 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -31,6 +31,16 @@ config TI_EMIF
 	  parameters and other settings during frequency, voltage and
 	  temperature changes
 
+config TI_GPMC
+	bool "Texas Instruments GPMC driver"
+	depends on ARCH_OMAP2PLUS
+	default y
+	help
+	 This driver is for the General Purpose Memory Controller (GPMC)
+	 present on Texas Instruments SoCs (e.g. OMAP2+). GPMC allows
+	 interfacing to a variety of asynchronous as well as synchronous
+	 memory drives like NOR, NAND, OneNAND, SRAM.
+
 config MVEBU_DEVBUS
 	bool "Marvell EBU Device Bus Controller"
 	default y
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index 71160a2..329b7b6 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_OF)		+= of_memory.o
 endif
 obj-$(CONFIG_TI_AEMIF)		+= ti-aemif.o
 obj-$(CONFIG_TI_EMIF)		+= emif.o
+obj-$(CONFIG_TI_GPMC)		+= ti-gpmc.o
 obj-$(CONFIG_FSL_IFC)		+= fsl_ifc.o
 obj-$(CONFIG_MVEBU_DEVBUS)	+= mvebu-devbus.o
 obj-$(CONFIG_TEGRA20_MC)	+= tegra20-mc.o
diff --git a/arch/arm/mach-omap2/gpmc.c b/drivers/memory/ti-gpmc.c
similarity index 90%
rename from arch/arm/mach-omap2/gpmc.c
rename to drivers/memory/ti-gpmc.c
index 9173f71..3bb2fd6 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/drivers/memory/ti-gpmc.c
@@ -33,13 +33,7 @@
 #include <linux/slab.h>
 
 #include <linux/platform_data/mtd-nand-omap2.h>
-
-#include <asm/mach-types.h>
-
-#include "soc.h"
-#include "common.h"
-#include "omap_device.h"
-#include "gpmc.h"
+#include <linux/platform_data/gpmc-omap.h>
 
 #define	DEVICE_NAME		"omap-gpmc"
 
@@ -154,35 +148,6 @@
 
 #define GPMC_NR_WAITPINS		4
 
-static struct gpmc_omap_platform_data gpmc_pdata;
-
-/* Structure to save gpmc cs context */
-struct gpmc_cs_config {
-	u32 config1;
-	u32 config2;
-	u32 config3;
-	u32 config4;
-	u32 config5;
-	u32 config6;
-	u32 config7;
-	int is_valid;
-};
-
-/*
- * Structure to save/restore gpmc context
- * to support core off on OMAP3
- */
-struct omap3_gpmc_regs {
-	u32 sysconfig;
-	u32 irqenable;
-	u32 timeout_ctrl;
-	u32 config;
-	u32 prefetch_config1;
-	u32 prefetch_config2;
-	u32 prefetch_control;
-	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
-};
-
 static struct resource	gpmc_mem_root;
 static struct resource	gpmc_cs_mem[GPMC_CS_NUM];
 static DEFINE_SPINLOCK(gpmc_mem_lock);
@@ -230,7 +195,7 @@ static unsigned long gpmc_get_fclk_period(void)
 	unsigned long rate = clk_get_rate(gpmc_l3_clk);
 
 	if (rate == 0) {
-		printk(KERN_WARNING "gpmc_l3_clk not enabled\n");
+		pr_warn("%s: gpmc_l3_clk not enabled\n", __func__);
 		return 0;
 	}
 
@@ -323,8 +288,8 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
 	nr_bits = end_bit - st_bit + 1;
 	if (ticks >= 1 << nr_bits) {
 #ifdef DEBUG
-		printk(KERN_INFO "GPMC CS%d: %-10s* %3d ns, %3d ticks >= %d\n",
-				cs, name, time, ticks, 1 << nr_bits);
+		pr_info("GPMC CS%d: %-10s* %3d ns, %3d ticks >= %d\n",
+			cs, name, time, ticks, 1 << nr_bits);
 #endif
 		return -1;
 	}
@@ -332,10 +297,9 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
 	mask = (1 << nr_bits) - 1;
 	l = gpmc_cs_read_reg(cs, reg);
 #ifdef DEBUG
-	printk(KERN_INFO
-		"GPMC CS%d: %-10s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n",
-	       cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000,
-			(l >> st_bit) & mask, time);
+	pr_info("GPMC CS%d: %-10s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n",
+		cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000,
+		(l >> st_bit) & mask, time);
 #endif
 	l &= ~(mask << st_bit);
 	l |= ticks << st_bit;
@@ -346,13 +310,11 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
 
 #ifdef DEBUG
 #define GPMC_SET_ONE(reg, st, end, field) \
-	if (set_gpmc_timing_reg(cs, (reg), (st), (end),		\
-			t->field, #field) < 0)			\
-		return -1
+	set_gpmc_timing_reg(cs, (reg), (st), (end),		\
+			t->field, #field)
 #else
 #define GPMC_SET_ONE(reg, st, end, field) \
-	if (set_gpmc_timing_reg(cs, (reg), (st), (end), t->field) < 0) \
-		return -1
+	set_gpmc_timing_reg(cs, (reg), (st), (end), t->field)
 #endif
 
 static int gpmc_calc_divider(unsigned int sync_clk)
@@ -415,8 +377,8 @@ static int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
 	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
 	if (l & (GPMC_CONFIG1_READTYPE_SYNC | GPMC_CONFIG1_WRITETYPE_SYNC)) {
 #ifdef DEBUG
-		printk(KERN_INFO "GPMC CS%d CLK period is %lu ns (div %d)\n",
-				cs, (div * gpmc_get_fclk_period()) / 1000, div);
+		pr_info("GPMC CS%d CLK period is %lu ns (div %d)\n",
+			cs, (div * gpmc_get_fclk_period()) / 1000, div);
 #endif
 		l &= ~0x03;
 		l |= (div - 1);
@@ -557,7 +519,7 @@ static int gpmc_cs_remap(int cs, u32 base)
 	 * Make sure we ignore any device offsets from the GPMC partition
 	 * allocated for the chip select and that the new base confirms
 	 * to the GPMC 16MB minimum granularity.
-	 */ 
+	 */
 	base &= ~(SZ_16M - 1);
 
 	gpmc_cs_get_memconf(cs, &old_base, &size);
@@ -622,7 +584,7 @@ static void gpmc_cs_free(int cs)
 
 	spin_lock(&gpmc_mem_lock);
 	if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) {
-		printk(KERN_ERR "Trying to free non-reserved GPMC CS%d\n", cs);
+		pr_err("Trying to free non-reserved GPMC CS%d\n", cs);
 		BUG();
 		spin_unlock(&gpmc_mem_lock);
 		return;
@@ -643,7 +605,6 @@ static void gpmc_mem_exit(void)
 			continue;
 		gpmc_cs_delete_mem(cs);
 	}
-
 }
 
 static void gpmc_mem_init(void)
@@ -709,7 +670,7 @@ static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t,
 	if (mux) {
 		temp = max_t(u32, temp,	gpmc_t->clk_activation + dev_t->t_ach);
 		temp = max_t(u32, temp, gpmc_t->adv_rd_off +
-				gpmc_ticks_to_ps(dev_t->cyc_aavdh_oe));
+			     gpmc_ticks_to_ps(dev_t->cyc_aavdh_oe));
 	}
 	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
 
@@ -722,7 +683,7 @@ static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t,
 	temp += gpmc_t->clk_activation;
 	if (dev_t->cyc_oe)
 		temp = max_t(u32, temp, gpmc_t->oe_on +
-				gpmc_ticks_to_ps(dev_t->cyc_oe));
+			     gpmc_ticks_to_ps(dev_t->cyc_oe));
 	gpmc_t->access = gpmc_round_ps_to_ticks(temp);
 
 	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ps(1);
@@ -731,7 +692,7 @@ static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t,
 	/* rd_cycle */
 	temp = max_t(u32, dev_t->t_cez_r, dev_t->t_oez);
 	temp = gpmc_round_ps_to_sync_clk(temp, gpmc_t->sync_clk) +
-							gpmc_t->access;
+					 gpmc_t->access;
 	/* XXX: barter t_ce_rdyz with t_cez_r ? */
 	if (dev_t->t_ce_rdyz)
 		temp = max_t(u32, temp,	gpmc_t->cs_rd_off + dev_t->t_ce_rdyz);
@@ -750,22 +711,22 @@ static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t,
 	temp = dev_t->t_avdp_w;
 	if (mux) {
 		temp = max_t(u32, temp,
-			gpmc_t->clk_activation + dev_t->t_avdh);
+			     gpmc_t->clk_activation + dev_t->t_avdh);
 		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
 	}
 	gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp);
 
 	/* wr_data_mux_bus */
 	temp = max_t(u32, dev_t->t_weasu,
-			gpmc_t->clk_activation + dev_t->t_rdyo);
+		     gpmc_t->clk_activation + dev_t->t_rdyo);
 	/* XXX: shouldn't mux be kept as a whole for wr_data_mux_bus ?,
 	 * and in that case remember to handle we_on properly
 	 */
 	if (mux) {
 		temp = max_t(u32, temp,
-			gpmc_t->adv_wr_off + dev_t->t_aavdh);
+			     gpmc_t->adv_wr_off + dev_t->t_aavdh);
 		temp = max_t(u32, temp, gpmc_t->adv_wr_off +
-				gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
+			     gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
 	}
 	gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp);
 
@@ -782,13 +743,13 @@ static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t,
 	/* we_off */
 	temp = gpmc_t->we_on + dev_t->t_wpl;
 	temp = max_t(u32, temp,
-			gpmc_t->wr_access + gpmc_ticks_to_ps(1));
+		     gpmc_t->wr_access + gpmc_ticks_to_ps(1));
 	temp = max_t(u32, temp,
-		gpmc_t->we_on + gpmc_ticks_to_ps(dev_t->cyc_wpl));
+		     gpmc_t->we_on + gpmc_ticks_to_ps(dev_t->cyc_wpl));
 	gpmc_t->we_off = gpmc_round_ps_to_ticks(temp);
 
 	gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off +
-							dev_t->t_wph);
+						   dev_t->t_wph);
 
 	/* wr_cycle */
 	temp = gpmc_round_ps_to_sync_clk(dev_t->t_cez_w, gpmc_t->sync_clk);
@@ -796,7 +757,7 @@ static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t,
 	/* XXX: barter t_ce_rdyz with t_cez_w ? */
 	if (dev_t->t_ce_rdyz)
 		temp = max_t(u32, temp,
-				 gpmc_t->cs_wr_off + dev_t->t_ce_rdyz);
+			     gpmc_t->cs_wr_off + dev_t->t_ce_rdyz);
 	gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp);
 
 	return 0;
@@ -818,16 +779,16 @@ static int gpmc_calc_async_read_timings(struct gpmc_timings *gpmc_t,
 	temp = dev_t->t_oeasu;
 	if (mux)
 		temp = max_t(u32, temp,
-			gpmc_t->adv_rd_off + dev_t->t_aavdh);
+			     gpmc_t->adv_rd_off + dev_t->t_aavdh);
 	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
 
 	/* access */
 	temp = max_t(u32, dev_t->t_iaa, /* XXX: remove t_iaa in async ? */
-				gpmc_t->oe_on + dev_t->t_oe);
+		     gpmc_t->oe_on + dev_t->t_oe);
 	temp = max_t(u32, temp,
-				gpmc_t->cs_on + dev_t->t_ce);
+		     gpmc_t->cs_on + dev_t->t_ce);
 	temp = max_t(u32, temp,
-				gpmc_t->adv_on + dev_t->t_aa);
+		     gpmc_t->adv_on + dev_t->t_aa);
 	gpmc_t->access = gpmc_round_ps_to_ticks(temp);
 
 	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ps(1);
@@ -835,7 +796,7 @@ static int gpmc_calc_async_read_timings(struct gpmc_timings *gpmc_t,
 
 	/* rd_cycle */
 	temp = max_t(u32, dev_t->t_rd_cycle,
-			gpmc_t->cs_rd_off + dev_t->t_cez_r);
+		     gpmc_t->cs_rd_off + dev_t->t_cez_r);
 	temp = max_t(u32, temp, gpmc_t->oe_off + dev_t->t_oez);
 	gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp);
 
@@ -859,7 +820,7 @@ static int gpmc_calc_async_write_timings(struct gpmc_timings *gpmc_t,
 	if (mux) {
 		temp = max_t(u32, temp,	gpmc_t->adv_wr_off + dev_t->t_aavdh);
 		temp = max_t(u32, temp, gpmc_t->adv_wr_off +
-				gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
+			     gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
 	}
 	gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp);
 
@@ -874,27 +835,26 @@ static int gpmc_calc_async_write_timings(struct gpmc_timings *gpmc_t,
 	gpmc_t->we_off = gpmc_round_ps_to_ticks(temp);
 
 	gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off +
-							dev_t->t_wph);
+						   dev_t->t_wph);
 
 	/* wr_cycle */
 	temp = max_t(u32, dev_t->t_wr_cycle,
-				gpmc_t->cs_wr_off + dev_t->t_cez_w);
+		     gpmc_t->cs_wr_off + dev_t->t_cez_w);
 	gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp);
 
 	return 0;
 }
 
 static int gpmc_calc_sync_common_timings(struct gpmc_timings *gpmc_t,
-			struct gpmc_device_timings *dev_t)
+					 struct gpmc_device_timings *dev_t)
 {
 	u32 temp;
 
 	gpmc_t->sync_clk = gpmc_calc_divider(dev_t->clk) *
-						gpmc_get_fclk_period();
+					     gpmc_get_fclk_period();
 
-	gpmc_t->page_burst_access = gpmc_round_ps_to_sync_clk(
-					dev_t->t_bacc,
-					gpmc_t->sync_clk);
+	gpmc_t->page_burst_access = gpmc_round_ps_to_sync_clk(dev_t->t_bacc,
+							      gpmc_t->sync_clk);
 
 	temp = max_t(u32, dev_t->t_ces, dev_t->t_avds);
 	gpmc_t->clk_activation = gpmc_round_ps_to_ticks(temp);
@@ -927,7 +887,7 @@ static int gpmc_calc_common_timings(struct gpmc_timings *gpmc_t,
 	temp = dev_t->t_avdasu;
 	if (dev_t->t_ce_avd)
 		temp = max_t(u32, temp,
-				gpmc_t->cs_on + dev_t->t_ce_avd);
+			     gpmc_t->cs_on + dev_t->t_ce_avd);
 	gpmc_t->adv_on = gpmc_round_ps_to_ticks(temp);
 
 	if (sync)
@@ -1084,7 +1044,7 @@ static struct of_device_id gpmc_dt_ids[] = {
 	{ .compatible = "ti,omap2420-gpmc" },
 	{ .compatible = "ti,omap2430-gpmc" },
 	{ .compatible = "ti,omap3430-gpmc" },	/* omap3430 & omap3630 */
-	{ .compatible = "ti,omap4430-gpmc" },	/* omap4430 & omap4460 & omap543x */
+	{ .compatible = "ti,omap4430-gpmc" },	/* omap4 & omap543x */
 	{ .compatible = "ti,am3352-gpmc" },	/* am335x devices */
 	{ }
 };
@@ -1205,7 +1165,7 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
  * Returns 0 on success and appropriate negative error code on failure.
  */
 static int gpmc_probe_generic_child(struct platform_device *pdev,
-				struct device_node *child)
+				    struct device_node *child)
 {
 	struct gpmc_settings gpmc_s;
 	struct gpmc_timings gpmc_t;
@@ -1341,7 +1301,7 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 		return -EINVAL;
 	} else if (gpmc_cs_num > GPMC_CS_NUM) {
 		pr_err("%s: number of supported chip-selects cannot be > %d\n",
-					 __func__, GPMC_CS_NUM);
+		       __func__, GPMC_CS_NUM);
 		return -EINVAL;
 	}
 
@@ -1353,7 +1313,6 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 	}
 
 	for_each_child_of_node(pdev->dev.of_node, child) {
-
 		if (!child->name)
 			continue;
 
@@ -1625,6 +1584,7 @@ static int gpmc_probe(struct platform_device *pdev)
 
 	/* Now the GPMC is initialised, unreserve the chip-selects */
 	gpmc_cs_map = 0;
+	gpmc_dev = dev;
 
 	if (dev->of_node) {
 		rc = gpmc_probe_dt(pdev);
@@ -1661,9 +1621,100 @@ static int gpmc_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM_SLEEP
+/* Structure to save gpmc cs context */
+struct gpmc_cs_config {
+	u32 config1;
+	u32 config2;
+	u32 config3;
+	u32 config4;
+	u32 config5;
+	u32 config6;
+	u32 config7;
+	int is_valid;
+};
+
+/*
+ * Structure to save/restore gpmc context
+ */
+struct omap_gpmc_regs {
+	u32 sysconfig;
+	u32 irqenable;
+	u32 timeout_ctrl;
+	u32 config;
+	u32 prefetch_config1;
+	u32 prefetch_config2;
+	u32 prefetch_control;
+	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
+};
+
+static struct omap_gpmc_regs gpmc_context;
+
+void omap_gpmc_save_context(void)
+{
+	int i;
+
+	gpmc_context.sysconfig = gpmc_read_reg(GPMC_SYSCONFIG);
+	gpmc_context.irqenable = gpmc_read_reg(GPMC_IRQENABLE);
+	gpmc_context.timeout_ctrl = gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
+	gpmc_context.config = gpmc_read_reg(GPMC_CONFIG);
+	gpmc_context.prefetch_config1 = gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
+	gpmc_context.prefetch_config2 = gpmc_read_reg(GPMC_PREFETCH_CONFIG2);
+	gpmc_context.prefetch_control = gpmc_read_reg(GPMC_PREFETCH_CONTROL);
+	for (i = 0; i < gpmc_cs_num; i++) {
+		gpmc_context.cs_context[i].is_valid = gpmc_cs_mem_enabled(i);
+		if (gpmc_context.cs_context[i].is_valid) {
+			gpmc_context.cs_context[i].config1 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG1);
+			gpmc_context.cs_context[i].config2 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG2);
+			gpmc_context.cs_context[i].config3 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG3);
+			gpmc_context.cs_context[i].config4 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG4);
+			gpmc_context.cs_context[i].config5 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG5);
+			gpmc_context.cs_context[i].config6 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG6);
+			gpmc_context.cs_context[i].config7 =
+				gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
+		}
+	}
+}
+
+void omap_gpmc_restore_context(void)
+{
+	int i;
+
+	gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig);
+	gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable);
+	gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl);
+	gpmc_write_reg(GPMC_CONFIG, gpmc_context.config);
+	gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1);
+	gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2);
+	gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control);
+	for (i = 0; i < gpmc_cs_num; i++) {
+		if (gpmc_context.cs_context[i].is_valid) {
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG1,
+					  gpmc_context.cs_context[i].config1);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG2,
+					  gpmc_context.cs_context[i].config2);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG3,
+					  gpmc_context.cs_context[i].config3);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG4,
+					  gpmc_context.cs_context[i].config4);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG5,
+					  gpmc_context.cs_context[i].config5);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG6,
+					  gpmc_context.cs_context[i].config6);
+			gpmc_cs_write_reg(i, GPMC_CS_CONFIG7,
+					  gpmc_context.cs_context[i].config7);
+		}
+	}
+}
+
 static int gpmc_suspend(struct device *dev)
 {
-	omap3_gpmc_save_context();
+	omap_gpmc_save_context();
 	pm_runtime_put_sync(dev);
 	return 0;
 }
@@ -1671,7 +1722,7 @@ static int gpmc_suspend(struct device *dev)
 static int gpmc_resume(struct device *dev)
 {
 	pm_runtime_get_sync(dev);
-	omap3_gpmc_restore_context();
+	omap_gpmc_restore_context();
 	return 0;
 }
 #endif
@@ -1697,116 +1748,11 @@ static __init int gpmc_init(void)
 static __exit void gpmc_exit(void)
 {
 	platform_driver_unregister(&gpmc_driver);
-
 }
 
 module_init(gpmc_init);
 module_exit(gpmc_exit);
 
-static int __init omap_gpmc_init(void)
-{
-	struct omap_hwmod *oh;
-	struct platform_device *pdev;
-	char *oh_name = "gpmc";
-
-	/*
-	 * if the board boots up with a populated DT, do not
-	 * manually add the device from this initcall
-	 */
-	if (of_have_populated_dt())
-		return -ENODEV;
-
-	oh = omap_hwmod_lookup(oh_name);
-	if (!oh) {
-		pr_err("Could not look up %s\n", oh_name);
-		return -ENODEV;
-	}
-
-	pdev = omap_device_build(DEVICE_NAME, -1, oh, (void *)&gpmc_pdata,
-				 sizeof(gpmc_pdata));
-	WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
-
-	return PTR_RET(pdev);
-}
-/* must run after machine_init code. i.e. arch_init */
-omap_subsys_initcall(omap_gpmc_init);
-
-/**
- * gpmc_generic_init - Initialize platform data for a Chip Select
- *
- * @cs		chip select number
- * @is_nand	true if device is NAND flash.
- * @settings	GPMC settings
- * @device_timings	device timings for device on this CS
- * @gpmc_timings	GPMC timings
- * @pdev	platform device for the device on this CS
- * @pdata_size	platform data size for the platform device
- */
-int gpmc_generic_init(int cs, bool is_nand,
-		      struct gpmc_settings *settings,
-		      struct gpmc_device_timings *device_timings,
-		      struct gpmc_timings *gpmc_timings,
-		      struct platform_device *pdev, unsigned pdata_size)
-{
-	struct gpmc_settings *gpmc_s = NULL;
-	struct gpmc_device_timings *gpmc_dev_t = NULL;
-	struct gpmc_timings *gpmc_t;
-
-	if (cs >= GPMC_CS_NUM) {
-		pr_err("%s: Invalid cs specified. Max CS = %d\n",
-		       __func__, GPMC_CS_NUM);
-		return -EINVAL;
-	}
-
-	if (gpmc_pdata.cs[cs].valid) {
-		pr_err("%s: cs %d already requested, ignoring new request\n",
-		       __func__, cs);
-		return -EINVAL;
-	}
-
-	if (settings) {
-		gpmc_s = kmemdup(settings, sizeof(*settings), GFP_KERNEL);
-		if (!gpmc_s)
-			return -ENOMEM;
-
-		gpmc_pdata.cs[cs].settings = gpmc_s;
-	}
-
-	if (device_timings) {
-		gpmc_dev_t = kmemdup(device_timings, sizeof(*device_timings),
-				     GFP_KERNEL);
-		if (!gpmc_dev_t)
-			goto dev_t_fail;
-
-		gpmc_pdata.cs[cs].device_timings = gpmc_dev_t;
-	}
-
-	if (gpmc_timings) {
-		gpmc_t = kmemdup(gpmc_timings, sizeof(*gpmc_timings),
-				 GFP_KERNEL);
-		if (!gpmc_t)
-			goto gpmc_t_fail;
-
-		gpmc_pdata.cs[cs].gpmc_timings = gpmc_t;
-	}
-
-	gpmc_pdata.cs[cs].is_nand = is_nand;
-	gpmc_pdata.cs[cs].pdev = pdev;
-	gpmc_pdata.cs[cs].pdata_size = pdata_size;
-	gpmc_pdata.cs[cs].valid = true;
-
-	return 0;
-
-gpmc_t_fail:
-	if (device_timings)
-		kfree(gpmc_dev_t);
-dev_t_fail:
-	if (settings)
-		kfree(gpmc_s);
-
-	return -ENOMEM;
-}
-
 /**
  * omap_gpmc_retime - Reconfigre GPMC timings for the device
  *
@@ -1881,67 +1827,3 @@ unsigned long omap_gpmc_get_clk_period(int cs,
 }
 EXPORT_SYMBOL_GPL(omap_gpmc_get_clk_period);
 
-static struct omap3_gpmc_regs gpmc_context;
-
-void omap3_gpmc_save_context(void)
-{
-	int i;
-
-	gpmc_context.sysconfig = gpmc_read_reg(GPMC_SYSCONFIG);
-	gpmc_context.irqenable = gpmc_read_reg(GPMC_IRQENABLE);
-	gpmc_context.timeout_ctrl = gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
-	gpmc_context.config = gpmc_read_reg(GPMC_CONFIG);
-	gpmc_context.prefetch_config1 = gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
-	gpmc_context.prefetch_config2 = gpmc_read_reg(GPMC_PREFETCH_CONFIG2);
-	gpmc_context.prefetch_control = gpmc_read_reg(GPMC_PREFETCH_CONTROL);
-	for (i = 0; i < gpmc_cs_num; i++) {
-		gpmc_context.cs_context[i].is_valid = gpmc_cs_mem_enabled(i);
-		if (gpmc_context.cs_context[i].is_valid) {
-			gpmc_context.cs_context[i].config1 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG1);
-			gpmc_context.cs_context[i].config2 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG2);
-			gpmc_context.cs_context[i].config3 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG3);
-			gpmc_context.cs_context[i].config4 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG4);
-			gpmc_context.cs_context[i].config5 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG5);
-			gpmc_context.cs_context[i].config6 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG6);
-			gpmc_context.cs_context[i].config7 =
-				gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
-		}
-	}
-}
-
-void omap3_gpmc_restore_context(void)
-{
-	int i;
-
-	gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig);
-	gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable);
-	gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl);
-	gpmc_write_reg(GPMC_CONFIG, gpmc_context.config);
-	gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1);
-	gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2);
-	gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control);
-	for (i = 0; i < gpmc_cs_num; i++) {
-		if (gpmc_context.cs_context[i].is_valid) {
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG1,
-				gpmc_context.cs_context[i].config1);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG2,
-				gpmc_context.cs_context[i].config2);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG3,
-				gpmc_context.cs_context[i].config3);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG4,
-				gpmc_context.cs_context[i].config4);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG5,
-				gpmc_context.cs_context[i].config5);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG6,
-				gpmc_context.cs_context[i].config6);
-			gpmc_cs_write_reg(i, GPMC_CS_CONFIG7,
-				gpmc_context.cs_context[i].config7);
-		}
-	}
-}
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index f1cf503..e1db2c1 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -89,7 +89,7 @@ config MTD_NAND_AMS_DELTA
 
 config MTD_NAND_OMAP2
 	tristate "NAND Flash device on OMAP2, OMAP3 and OMAP4"
-	depends on ARCH_OMAP2PLUS
+	depends on TI_GPMC
 	help
           Support for NAND flash on Texas Instruments OMAP2, OMAP3 and OMAP4
 	  platforms.
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig
index ab260727..272c16c 100644
--- a/drivers/mtd/onenand/Kconfig
+++ b/drivers/mtd/onenand/Kconfig
@@ -24,10 +24,10 @@ config MTD_ONENAND_GENERIC
 	  Support for OneNAND flash via platform device driver.
 
 config MTD_ONENAND_OMAP2
-	tristate "OneNAND on OMAP2/OMAP3 support"
-	depends on ARCH_OMAP2 || ARCH_OMAP3
+	tristate "OneNAND on OMAP2+ support"
+	depends on TI_GPMC
 	help
-	  Support for a OneNAND flash device connected to an OMAP2/OMAP3 CPU
+	  Support for a OneNAND flash device connected to an OMAP2+ SoCs
 	  via the GPMC memory controller.
 
 config MTD_ONENAND_SAMSUNG
-- 
1.8.3.2

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

* Re: [PATCH 00/36] OMAP: GPMC: Restructure and move OMAP GPMC driver out of mach-omap2
@ 2014-06-11 11:52   ` Javier Martinez Canillas
  0 siblings, 0 replies; 181+ messages in thread
From: Javier Martinez Canillas @ 2014-06-11 11:52 UTC (permalink / raw)
  To: Roger Quadros
  Cc: Tony Lindgren, David Woodhouse, Brian Norris, kyungmin.park,
	Gupta, Pekon, Ezequiel Garcia, nsekhar, linux-omap, linux-mtd,
	devicetree, Linux Kernel

Hello Roger,

What a great series!!

On Wed, Jun 11, 2014 at 10:56 AM, Roger Quadros <rogerq@ti.com> wrote:
> Hi,
>
> This is a complete functional set to get the gpmc driver out of mach-omap2
> and into drivers/memory. The DT binding remains the same except for the
> following minor changes

I probably won't have time to do a proper review until at least next
week but doing a quick glance it looks very good to me.

> - compatible property is required for NAND & OneNAND nodes

This is a minor ABI breakage but I agree with you that it is wrong
that these were not introduced in the first place and relied on the
dev node so I think is not that bad to break it in this case.

> - Second register space and interrupts properties are required for
>   NAND controller node
> - ti,onenand-sync-rw property added for OneNAND node.
>
> The series does the following changes
> - Move GPMC IRQ and NAND register handling to NAND driver.
>   The entire GPMC register space is made available to the NAND driver.
> - Clean up NAND device tree handling. Don't rely on legacy platform device
>   i.e. don't call gpmc_nand_init()
> - Add 2 public APIs omap_gpmc_retime() and omap_gpmc_get_clk_period()
>   omap_gpmc_retime() allows to reconfigure the GPMC settings and timings
>   for the specified Chip select region.
>   omap_gpmc_get_clk_period() allows to query the GPMC_CLK (external clock)
>   period, to perform timing calculations.
>   Both functions will be needed by the OneNAND driver since it calculates
>   device timings on the fly and needs to change from Asynchronous mode
>   to Synchronous mode.
> - Setup OneNAND in Asynchronous mode by default and move Synchronous
>   setting code into OneNAND driver.
> - Clean up OneNAND device tree handling. Don't rely on legacy platform device
>   i.e. don't call gpmc_onenand_init()
> - Introduce gpmc_generic_init() that should be used by board files to specify
>   GPMC chip select setting/timing and platform device within that Chip Select.
> - Stop using all gpmc*() that are meant to be private to GPMC driver.
> - Move GPMC driver into drivers/memory
>
> Tested on:
>
> - beagleboard C4: NAND
> - Nokia N900: OneNAND
>

Do you have a tree somewhere that I can use it to test on the boards I
maintain and post patches to update the DTS according the new binding?

> Changelog:
>
> [1] RFC patch - https://lkml.org/lkml/2014/5/21/218
>
> cheers,
> -roger
>
> ---
> Roger Quadros (36):
>   ARM: OMAP3: hwmod: Fix gpmc memory resource space
>   ARM: dts: OMAP2+: Fix GPMC register space size
>   ARM: OMAP2+: gpmc: Add platform data
>   ARM: OMAP2+: gpmc: Add gpmc timings and settings to platform data
>   mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
>   mtd: nand: omap: Move gpmc_update_nand_reg to nand driver
>   mtd: nand: omap: Move NAND write protect code from GPMC to NAND driver
>   mtd: nand: omap: Copy platform data parameters to omap_nand_info data
>   mtd: nand: omap: Clean up device tree support
>   ARM: dts: OMAP2+: Fix NAND device nodes
>   mtd: nand: omap: Update DT binding documentation
>   ARM: dts: omap3-beagle: Add NAND device
>   ARM: OMAP2+: gpmc.c: sanity check bank-width DT property
>   ARM: OMAP2+: gpmc: Allow drivers to reconfigure GPMC settings &
>     timings
>   ARM: OMAP2+: gpmc: Allow drivers to query GPMC_CLK period
>   mtd: onenand: omap: Remove regulator management code
>   ARM: OMAP2+: gpmc-onenand: Use Async settings/timings by default
>   ARM: OMAP2+: gpmc-onenand: Move Synchronous setting code to drivers/
>   mtd: onenand: omap: Use devres managed resources
>   mtd: onenand: omap: Clean up device tree support
>   ARM: dts: OMAP2+: Fix OneNAND device nodes
>   ARM: OMAP2+: gmpc: add gpmc_generic_init()
>   ARM: OMAP2+: gpmc: use platform data to configure CS space and
>     poplulate device
>   ARM: OMAP2+: gpmc: add NAND specific setup
>   ARM: OMAP2+: gpmc: Support multiple Chip Selects per device
>   ARM: OMAP2+: gpmc-smc91x: Get rid of retime() from
>     omap_smc91x_platform_data
>   ARM: OMAP2+: usb-tusb6010: Use omap_gpmc_retime()
>   ARM: OMAP2+: nand: Update gpmc_nand_init() to use generic_gpmc_init()
>   ARM: OMAP2+: gpmc-smc91x: Use gpmc_generic_init()
>   ARM: OMAP2+: gpmc-smsc911x: Use gpmc_generic_init()
>   ARM: OMAP2: usb-tusb6010: Use gpmc_generic_init()
>   ARM: OMAP2+: onenand: Use gpmc_generic_init()
>   ARM: OMAP2+: board-flash: Use gpmc_generic_init() for NOR
>   ARM: OMAP2+: gpmc: Make externally unused functions/defines private
>   ARM: OMAP2+: gpmc: move GPMC driver into drivers/memory
>   ARM: OMAP2+: defconfig: Enable TI GPMC driver
>
>  .../devicetree/bindings/mtd/gpmc-nand.txt          |   16 +-
>  .../devicetree/bindings/mtd/gpmc-onenand.txt       |    4 +
>  arch/arm/boot/dts/am335x-evm.dts                   |    8 +-
>  arch/arm/boot/dts/am335x-igep0033.dtsi             |    8 +-
>  arch/arm/boot/dts/am33xx.dtsi                      |    2 +-
>  arch/arm/boot/dts/am4372.dtsi                      |    2 +-
>  arch/arm/boot/dts/am43x-epos-evm.dts               |    8 +-
>  arch/arm/boot/dts/omap2420-n8x0-common.dtsi        |    5 +-
>  arch/arm/boot/dts/omap2420.dtsi                    |    2 +-
>  arch/arm/boot/dts/omap2430.dtsi                    |    2 +-
>  arch/arm/boot/dts/omap3-beagle.dts                 |   53 +
>  arch/arm/boot/dts/omap3-devkit8000.dts             |    9 +-
>  arch/arm/boot/dts/omap3-evm-37xx.dts               |   10 +-
>  arch/arm/boot/dts/omap3-igep0020.dts               |   10 +-
>  arch/arm/boot/dts/omap3-igep0030.dts               |    8 +-
>  arch/arm/boot/dts/omap3-ldp.dts                    |   10 +-
>  arch/arm/boot/dts/omap3-lilly-a83x.dtsi            |   10 +-
>  arch/arm/boot/dts/omap3-lilly-dbb056.dts           |    7 +-
>  arch/arm/boot/dts/omap3-n900.dts                   |    6 +-
>  arch/arm/boot/dts/omap3-n950-n9.dtsi               |    6 +-
>  arch/arm/boot/dts/omap3.dtsi                       |    2 +-
>  arch/arm/boot/dts/omap3430-sdp.dts                 |   14 +-
>  arch/arm/boot/dts/omap4.dtsi                       |    2 +-
>  arch/arm/boot/dts/omap5.dtsi                       |    2 +-
>  arch/arm/configs/omap2plus_defconfig               |    2 +
>  arch/arm/mach-omap2/Makefile                       |    2 +-
>  arch/arm/mach-omap2/board-3430sdp.c                |    8 +-
>  arch/arm/mach-omap2/board-flash.c                  |   28 +-
>  arch/arm/mach-omap2/gpmc-nand.c                    |   66 +-
>  arch/arm/mach-omap2/gpmc-onenand.c                 |  351 +---
>  arch/arm/mach-omap2/gpmc-smc91x.c                  |   91 +-
>  arch/arm/mach-omap2/gpmc-smc91x.h                  |    1 -
>  arch/arm/mach-omap2/gpmc-smsc911x.c                |   76 +-
>  arch/arm/mach-omap2/gpmc.c                         | 1872 --------------------
>  arch/arm/mach-omap2/gpmc.h                         |  221 +--
>  arch/arm/mach-omap2/gpmc_legacy.c                  |  296 ++++
>  arch/arm/mach-omap2/omap_hwmod_3xxx_data.c         |    2 +-
>  arch/arm/mach-omap2/usb-tusb6010.c                 |  172 +-
>  drivers/memory/Kconfig                             |   10 +
>  drivers/memory/Makefile                            |    1 +
>  drivers/memory/ti-gpmc.c                           | 1829 +++++++++++++++++++
>  drivers/mtd/nand/Kconfig                           |    2 +-
>  drivers/mtd/nand/omap2.c                           |  364 +++-
>  drivers/mtd/onenand/Kconfig                        |    6 +-
>  drivers/mtd/onenand/omap2.c                        |  456 +++--
>  include/linux/platform_data/gpmc-omap.h            |  189 ++
>  include/linux/platform_data/mtd-nand-omap2.h       |   10 +-
>  include/linux/platform_data/mtd-onenand-omap2.h    |    7 +-
>  48 files changed, 3361 insertions(+), 2907 deletions(-)
>  delete mode 100644 arch/arm/mach-omap2/gpmc.c
>  create mode 100644 arch/arm/mach-omap2/gpmc_legacy.c
>  create mode 100644 drivers/memory/ti-gpmc.c
>  create mode 100644 include/linux/platform_data/gpmc-omap.h
>
> --
> 1.8.3.2
>

Best regards,
Javier

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

* Re: [PATCH 00/36] OMAP: GPMC: Restructure and move OMAP GPMC driver out of mach-omap2
@ 2014-06-11 11:52   ` Javier Martinez Canillas
  0 siblings, 0 replies; 181+ messages in thread
From: Javier Martinez Canillas @ 2014-06-11 11:52 UTC (permalink / raw)
  To: Roger Quadros
  Cc: Tony Lindgren, David Woodhouse, Brian Norris,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ, Gupta, Pekon,
	Ezequiel Garcia, nsekhar-l0cyMroinI0,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Linux Kernel

Hello Roger,

What a great series!!

On Wed, Jun 11, 2014 at 10:56 AM, Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> wrote:
> Hi,
>
> This is a complete functional set to get the gpmc driver out of mach-omap2
> and into drivers/memory. The DT binding remains the same except for the
> following minor changes

I probably won't have time to do a proper review until at least next
week but doing a quick glance it looks very good to me.

> - compatible property is required for NAND & OneNAND nodes

This is a minor ABI breakage but I agree with you that it is wrong
that these were not introduced in the first place and relied on the
dev node so I think is not that bad to break it in this case.

> - Second register space and interrupts properties are required for
>   NAND controller node
> - ti,onenand-sync-rw property added for OneNAND node.
>
> The series does the following changes
> - Move GPMC IRQ and NAND register handling to NAND driver.
>   The entire GPMC register space is made available to the NAND driver.
> - Clean up NAND device tree handling. Don't rely on legacy platform device
>   i.e. don't call gpmc_nand_init()
> - Add 2 public APIs omap_gpmc_retime() and omap_gpmc_get_clk_period()
>   omap_gpmc_retime() allows to reconfigure the GPMC settings and timings
>   for the specified Chip select region.
>   omap_gpmc_get_clk_period() allows to query the GPMC_CLK (external clock)
>   period, to perform timing calculations.
>   Both functions will be needed by the OneNAND driver since it calculates
>   device timings on the fly and needs to change from Asynchronous mode
>   to Synchronous mode.
> - Setup OneNAND in Asynchronous mode by default and move Synchronous
>   setting code into OneNAND driver.
> - Clean up OneNAND device tree handling. Don't rely on legacy platform device
>   i.e. don't call gpmc_onenand_init()
> - Introduce gpmc_generic_init() that should be used by board files to specify
>   GPMC chip select setting/timing and platform device within that Chip Select.
> - Stop using all gpmc*() that are meant to be private to GPMC driver.
> - Move GPMC driver into drivers/memory
>
> Tested on:
>
> - beagleboard C4: NAND
> - Nokia N900: OneNAND
>

Do you have a tree somewhere that I can use it to test on the boards I
maintain and post patches to update the DTS according the new binding?

> Changelog:
>
> [1] RFC patch - https://lkml.org/lkml/2014/5/21/218
>
> cheers,
> -roger
>
> ---
> Roger Quadros (36):
>   ARM: OMAP3: hwmod: Fix gpmc memory resource space
>   ARM: dts: OMAP2+: Fix GPMC register space size
>   ARM: OMAP2+: gpmc: Add platform data
>   ARM: OMAP2+: gpmc: Add gpmc timings and settings to platform data
>   mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
>   mtd: nand: omap: Move gpmc_update_nand_reg to nand driver
>   mtd: nand: omap: Move NAND write protect code from GPMC to NAND driver
>   mtd: nand: omap: Copy platform data parameters to omap_nand_info data
>   mtd: nand: omap: Clean up device tree support
>   ARM: dts: OMAP2+: Fix NAND device nodes
>   mtd: nand: omap: Update DT binding documentation
>   ARM: dts: omap3-beagle: Add NAND device
>   ARM: OMAP2+: gpmc.c: sanity check bank-width DT property
>   ARM: OMAP2+: gpmc: Allow drivers to reconfigure GPMC settings &
>     timings
>   ARM: OMAP2+: gpmc: Allow drivers to query GPMC_CLK period
>   mtd: onenand: omap: Remove regulator management code
>   ARM: OMAP2+: gpmc-onenand: Use Async settings/timings by default
>   ARM: OMAP2+: gpmc-onenand: Move Synchronous setting code to drivers/
>   mtd: onenand: omap: Use devres managed resources
>   mtd: onenand: omap: Clean up device tree support
>   ARM: dts: OMAP2+: Fix OneNAND device nodes
>   ARM: OMAP2+: gmpc: add gpmc_generic_init()
>   ARM: OMAP2+: gpmc: use platform data to configure CS space and
>     poplulate device
>   ARM: OMAP2+: gpmc: add NAND specific setup
>   ARM: OMAP2+: gpmc: Support multiple Chip Selects per device
>   ARM: OMAP2+: gpmc-smc91x: Get rid of retime() from
>     omap_smc91x_platform_data
>   ARM: OMAP2+: usb-tusb6010: Use omap_gpmc_retime()
>   ARM: OMAP2+: nand: Update gpmc_nand_init() to use generic_gpmc_init()
>   ARM: OMAP2+: gpmc-smc91x: Use gpmc_generic_init()
>   ARM: OMAP2+: gpmc-smsc911x: Use gpmc_generic_init()
>   ARM: OMAP2: usb-tusb6010: Use gpmc_generic_init()
>   ARM: OMAP2+: onenand: Use gpmc_generic_init()
>   ARM: OMAP2+: board-flash: Use gpmc_generic_init() for NOR
>   ARM: OMAP2+: gpmc: Make externally unused functions/defines private
>   ARM: OMAP2+: gpmc: move GPMC driver into drivers/memory
>   ARM: OMAP2+: defconfig: Enable TI GPMC driver
>
>  .../devicetree/bindings/mtd/gpmc-nand.txt          |   16 +-
>  .../devicetree/bindings/mtd/gpmc-onenand.txt       |    4 +
>  arch/arm/boot/dts/am335x-evm.dts                   |    8 +-
>  arch/arm/boot/dts/am335x-igep0033.dtsi             |    8 +-
>  arch/arm/boot/dts/am33xx.dtsi                      |    2 +-
>  arch/arm/boot/dts/am4372.dtsi                      |    2 +-
>  arch/arm/boot/dts/am43x-epos-evm.dts               |    8 +-
>  arch/arm/boot/dts/omap2420-n8x0-common.dtsi        |    5 +-
>  arch/arm/boot/dts/omap2420.dtsi                    |    2 +-
>  arch/arm/boot/dts/omap2430.dtsi                    |    2 +-
>  arch/arm/boot/dts/omap3-beagle.dts                 |   53 +
>  arch/arm/boot/dts/omap3-devkit8000.dts             |    9 +-
>  arch/arm/boot/dts/omap3-evm-37xx.dts               |   10 +-
>  arch/arm/boot/dts/omap3-igep0020.dts               |   10 +-
>  arch/arm/boot/dts/omap3-igep0030.dts               |    8 +-
>  arch/arm/boot/dts/omap3-ldp.dts                    |   10 +-
>  arch/arm/boot/dts/omap3-lilly-a83x.dtsi            |   10 +-
>  arch/arm/boot/dts/omap3-lilly-dbb056.dts           |    7 +-
>  arch/arm/boot/dts/omap3-n900.dts                   |    6 +-
>  arch/arm/boot/dts/omap3-n950-n9.dtsi               |    6 +-
>  arch/arm/boot/dts/omap3.dtsi                       |    2 +-
>  arch/arm/boot/dts/omap3430-sdp.dts                 |   14 +-
>  arch/arm/boot/dts/omap4.dtsi                       |    2 +-
>  arch/arm/boot/dts/omap5.dtsi                       |    2 +-
>  arch/arm/configs/omap2plus_defconfig               |    2 +
>  arch/arm/mach-omap2/Makefile                       |    2 +-
>  arch/arm/mach-omap2/board-3430sdp.c                |    8 +-
>  arch/arm/mach-omap2/board-flash.c                  |   28 +-
>  arch/arm/mach-omap2/gpmc-nand.c                    |   66 +-
>  arch/arm/mach-omap2/gpmc-onenand.c                 |  351 +---
>  arch/arm/mach-omap2/gpmc-smc91x.c                  |   91 +-
>  arch/arm/mach-omap2/gpmc-smc91x.h                  |    1 -
>  arch/arm/mach-omap2/gpmc-smsc911x.c                |   76 +-
>  arch/arm/mach-omap2/gpmc.c                         | 1872 --------------------
>  arch/arm/mach-omap2/gpmc.h                         |  221 +--
>  arch/arm/mach-omap2/gpmc_legacy.c                  |  296 ++++
>  arch/arm/mach-omap2/omap_hwmod_3xxx_data.c         |    2 +-
>  arch/arm/mach-omap2/usb-tusb6010.c                 |  172 +-
>  drivers/memory/Kconfig                             |   10 +
>  drivers/memory/Makefile                            |    1 +
>  drivers/memory/ti-gpmc.c                           | 1829 +++++++++++++++++++
>  drivers/mtd/nand/Kconfig                           |    2 +-
>  drivers/mtd/nand/omap2.c                           |  364 +++-
>  drivers/mtd/onenand/Kconfig                        |    6 +-
>  drivers/mtd/onenand/omap2.c                        |  456 +++--
>  include/linux/platform_data/gpmc-omap.h            |  189 ++
>  include/linux/platform_data/mtd-nand-omap2.h       |   10 +-
>  include/linux/platform_data/mtd-onenand-omap2.h    |    7 +-
>  48 files changed, 3361 insertions(+), 2907 deletions(-)
>  delete mode 100644 arch/arm/mach-omap2/gpmc.c
>  create mode 100644 arch/arm/mach-omap2/gpmc_legacy.c
>  create mode 100644 drivers/memory/ti-gpmc.c
>  create mode 100644 include/linux/platform_data/gpmc-omap.h
>
> --
> 1.8.3.2
>

Best regards,
Javier
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 00/36] OMAP: GPMC: Restructure and move OMAP GPMC driver out of mach-omap2
@ 2014-06-11 11:52   ` Javier Martinez Canillas
  0 siblings, 0 replies; 181+ messages in thread
From: Javier Martinez Canillas @ 2014-06-11 11:52 UTC (permalink / raw)
  To: Roger Quadros
  Cc: devicetree, linux-omap, Tony Lindgren, nsekhar, Linux Kernel,
	kyungmin.park, linux-mtd, Gupta, Pekon, Ezequiel Garcia,
	Brian Norris, David Woodhouse

Hello Roger,

What a great series!!

On Wed, Jun 11, 2014 at 10:56 AM, Roger Quadros <rogerq@ti.com> wrote:
> Hi,
>
> This is a complete functional set to get the gpmc driver out of mach-omap2
> and into drivers/memory. The DT binding remains the same except for the
> following minor changes

I probably won't have time to do a proper review until at least next
week but doing a quick glance it looks very good to me.

> - compatible property is required for NAND & OneNAND nodes

This is a minor ABI breakage but I agree with you that it is wrong
that these were not introduced in the first place and relied on the
dev node so I think is not that bad to break it in this case.

> - Second register space and interrupts properties are required for
>   NAND controller node
> - ti,onenand-sync-rw property added for OneNAND node.
>
> The series does the following changes
> - Move GPMC IRQ and NAND register handling to NAND driver.
>   The entire GPMC register space is made available to the NAND driver.
> - Clean up NAND device tree handling. Don't rely on legacy platform device
>   i.e. don't call gpmc_nand_init()
> - Add 2 public APIs omap_gpmc_retime() and omap_gpmc_get_clk_period()
>   omap_gpmc_retime() allows to reconfigure the GPMC settings and timings
>   for the specified Chip select region.
>   omap_gpmc_get_clk_period() allows to query the GPMC_CLK (external clock)
>   period, to perform timing calculations.
>   Both functions will be needed by the OneNAND driver since it calculates
>   device timings on the fly and needs to change from Asynchronous mode
>   to Synchronous mode.
> - Setup OneNAND in Asynchronous mode by default and move Synchronous
>   setting code into OneNAND driver.
> - Clean up OneNAND device tree handling. Don't rely on legacy platform device
>   i.e. don't call gpmc_onenand_init()
> - Introduce gpmc_generic_init() that should be used by board files to specify
>   GPMC chip select setting/timing and platform device within that Chip Select.
> - Stop using all gpmc*() that are meant to be private to GPMC driver.
> - Move GPMC driver into drivers/memory
>
> Tested on:
>
> - beagleboard C4: NAND
> - Nokia N900: OneNAND
>

Do you have a tree somewhere that I can use it to test on the boards I
maintain and post patches to update the DTS according the new binding?

> Changelog:
>
> [1] RFC patch - https://lkml.org/lkml/2014/5/21/218
>
> cheers,
> -roger
>
> ---
> Roger Quadros (36):
>   ARM: OMAP3: hwmod: Fix gpmc memory resource space
>   ARM: dts: OMAP2+: Fix GPMC register space size
>   ARM: OMAP2+: gpmc: Add platform data
>   ARM: OMAP2+: gpmc: Add gpmc timings and settings to platform data
>   mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
>   mtd: nand: omap: Move gpmc_update_nand_reg to nand driver
>   mtd: nand: omap: Move NAND write protect code from GPMC to NAND driver
>   mtd: nand: omap: Copy platform data parameters to omap_nand_info data
>   mtd: nand: omap: Clean up device tree support
>   ARM: dts: OMAP2+: Fix NAND device nodes
>   mtd: nand: omap: Update DT binding documentation
>   ARM: dts: omap3-beagle: Add NAND device
>   ARM: OMAP2+: gpmc.c: sanity check bank-width DT property
>   ARM: OMAP2+: gpmc: Allow drivers to reconfigure GPMC settings &
>     timings
>   ARM: OMAP2+: gpmc: Allow drivers to query GPMC_CLK period
>   mtd: onenand: omap: Remove regulator management code
>   ARM: OMAP2+: gpmc-onenand: Use Async settings/timings by default
>   ARM: OMAP2+: gpmc-onenand: Move Synchronous setting code to drivers/
>   mtd: onenand: omap: Use devres managed resources
>   mtd: onenand: omap: Clean up device tree support
>   ARM: dts: OMAP2+: Fix OneNAND device nodes
>   ARM: OMAP2+: gmpc: add gpmc_generic_init()
>   ARM: OMAP2+: gpmc: use platform data to configure CS space and
>     poplulate device
>   ARM: OMAP2+: gpmc: add NAND specific setup
>   ARM: OMAP2+: gpmc: Support multiple Chip Selects per device
>   ARM: OMAP2+: gpmc-smc91x: Get rid of retime() from
>     omap_smc91x_platform_data
>   ARM: OMAP2+: usb-tusb6010: Use omap_gpmc_retime()
>   ARM: OMAP2+: nand: Update gpmc_nand_init() to use generic_gpmc_init()
>   ARM: OMAP2+: gpmc-smc91x: Use gpmc_generic_init()
>   ARM: OMAP2+: gpmc-smsc911x: Use gpmc_generic_init()
>   ARM: OMAP2: usb-tusb6010: Use gpmc_generic_init()
>   ARM: OMAP2+: onenand: Use gpmc_generic_init()
>   ARM: OMAP2+: board-flash: Use gpmc_generic_init() for NOR
>   ARM: OMAP2+: gpmc: Make externally unused functions/defines private
>   ARM: OMAP2+: gpmc: move GPMC driver into drivers/memory
>   ARM: OMAP2+: defconfig: Enable TI GPMC driver
>
>  .../devicetree/bindings/mtd/gpmc-nand.txt          |   16 +-
>  .../devicetree/bindings/mtd/gpmc-onenand.txt       |    4 +
>  arch/arm/boot/dts/am335x-evm.dts                   |    8 +-
>  arch/arm/boot/dts/am335x-igep0033.dtsi             |    8 +-
>  arch/arm/boot/dts/am33xx.dtsi                      |    2 +-
>  arch/arm/boot/dts/am4372.dtsi                      |    2 +-
>  arch/arm/boot/dts/am43x-epos-evm.dts               |    8 +-
>  arch/arm/boot/dts/omap2420-n8x0-common.dtsi        |    5 +-
>  arch/arm/boot/dts/omap2420.dtsi                    |    2 +-
>  arch/arm/boot/dts/omap2430.dtsi                    |    2 +-
>  arch/arm/boot/dts/omap3-beagle.dts                 |   53 +
>  arch/arm/boot/dts/omap3-devkit8000.dts             |    9 +-
>  arch/arm/boot/dts/omap3-evm-37xx.dts               |   10 +-
>  arch/arm/boot/dts/omap3-igep0020.dts               |   10 +-
>  arch/arm/boot/dts/omap3-igep0030.dts               |    8 +-
>  arch/arm/boot/dts/omap3-ldp.dts                    |   10 +-
>  arch/arm/boot/dts/omap3-lilly-a83x.dtsi            |   10 +-
>  arch/arm/boot/dts/omap3-lilly-dbb056.dts           |    7 +-
>  arch/arm/boot/dts/omap3-n900.dts                   |    6 +-
>  arch/arm/boot/dts/omap3-n950-n9.dtsi               |    6 +-
>  arch/arm/boot/dts/omap3.dtsi                       |    2 +-
>  arch/arm/boot/dts/omap3430-sdp.dts                 |   14 +-
>  arch/arm/boot/dts/omap4.dtsi                       |    2 +-
>  arch/arm/boot/dts/omap5.dtsi                       |    2 +-
>  arch/arm/configs/omap2plus_defconfig               |    2 +
>  arch/arm/mach-omap2/Makefile                       |    2 +-
>  arch/arm/mach-omap2/board-3430sdp.c                |    8 +-
>  arch/arm/mach-omap2/board-flash.c                  |   28 +-
>  arch/arm/mach-omap2/gpmc-nand.c                    |   66 +-
>  arch/arm/mach-omap2/gpmc-onenand.c                 |  351 +---
>  arch/arm/mach-omap2/gpmc-smc91x.c                  |   91 +-
>  arch/arm/mach-omap2/gpmc-smc91x.h                  |    1 -
>  arch/arm/mach-omap2/gpmc-smsc911x.c                |   76 +-
>  arch/arm/mach-omap2/gpmc.c                         | 1872 --------------------
>  arch/arm/mach-omap2/gpmc.h                         |  221 +--
>  arch/arm/mach-omap2/gpmc_legacy.c                  |  296 ++++
>  arch/arm/mach-omap2/omap_hwmod_3xxx_data.c         |    2 +-
>  arch/arm/mach-omap2/usb-tusb6010.c                 |  172 +-
>  drivers/memory/Kconfig                             |   10 +
>  drivers/memory/Makefile                            |    1 +
>  drivers/memory/ti-gpmc.c                           | 1829 +++++++++++++++++++
>  drivers/mtd/nand/Kconfig                           |    2 +-
>  drivers/mtd/nand/omap2.c                           |  364 +++-
>  drivers/mtd/onenand/Kconfig                        |    6 +-
>  drivers/mtd/onenand/omap2.c                        |  456 +++--
>  include/linux/platform_data/gpmc-omap.h            |  189 ++
>  include/linux/platform_data/mtd-nand-omap2.h       |   10 +-
>  include/linux/platform_data/mtd-onenand-omap2.h    |    7 +-
>  48 files changed, 3361 insertions(+), 2907 deletions(-)
>  delete mode 100644 arch/arm/mach-omap2/gpmc.c
>  create mode 100644 arch/arm/mach-omap2/gpmc_legacy.c
>  create mode 100644 drivers/memory/ti-gpmc.c
>  create mode 100644 include/linux/platform_data/gpmc-omap.h
>
> --
> 1.8.3.2
>

Best regards,
Javier

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

* Re: [PATCH 00/36] OMAP: GPMC: Restructure and move OMAP GPMC driver out of mach-omap2
  2014-06-11 11:52   ` Javier Martinez Canillas
  (?)
@ 2014-06-11 11:54     ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11 11:54 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: Tony Lindgren, David Woodhouse, Brian Norris, kyungmin.park,
	Gupta, Pekon, Ezequiel Garcia, nsekhar, linux-omap, linux-mtd,
	devicetree, Linux Kernel

Hi Javier,

On 06/11/2014 02:52 PM, Javier Martinez Canillas wrote:
> Hello Roger,
> 
> What a great series!!

Thanks :)

> 
> On Wed, Jun 11, 2014 at 10:56 AM, Roger Quadros <rogerq@ti.com> wrote:
>> Hi,
>>
>> This is a complete functional set to get the gpmc driver out of mach-omap2
>> and into drivers/memory. The DT binding remains the same except for the
>> following minor changes
> 
> I probably won't have time to do a proper review until at least next
> week but doing a quick glance it looks very good to me.
> 
>> - compatible property is required for NAND & OneNAND nodes
> 
> This is a minor ABI breakage but I agree with you that it is wrong
> that these were not introduced in the first place and relied on the
> dev node so I think is not that bad to break it in this case.
> 
>> - Second register space and interrupts properties are required for
>>   NAND controller node
>> - ti,onenand-sync-rw property added for OneNAND node.
>>
>> The series does the following changes
>> - Move GPMC IRQ and NAND register handling to NAND driver.
>>   The entire GPMC register space is made available to the NAND driver.
>> - Clean up NAND device tree handling. Don't rely on legacy platform device
>>   i.e. don't call gpmc_nand_init()
>> - Add 2 public APIs omap_gpmc_retime() and omap_gpmc_get_clk_period()
>>   omap_gpmc_retime() allows to reconfigure the GPMC settings and timings
>>   for the specified Chip select region.
>>   omap_gpmc_get_clk_period() allows to query the GPMC_CLK (external clock)
>>   period, to perform timing calculations.
>>   Both functions will be needed by the OneNAND driver since it calculates
>>   device timings on the fly and needs to change from Asynchronous mode
>>   to Synchronous mode.
>> - Setup OneNAND in Asynchronous mode by default and move Synchronous
>>   setting code into OneNAND driver.
>> - Clean up OneNAND device tree handling. Don't rely on legacy platform device
>>   i.e. don't call gpmc_onenand_init()
>> - Introduce gpmc_generic_init() that should be used by board files to specify
>>   GPMC chip select setting/timing and platform device within that Chip Select.
>> - Stop using all gpmc*() that are meant to be private to GPMC driver.
>> - Move GPMC driver into drivers/memory
>>
>> Tested on:
>>
>> - beagleboard C4: NAND
>> - Nokia N900: OneNAND
>>
> 
> Do you have a tree somewhere that I can use it to test on the boards I
> maintain and post patches to update the DTS according the new binding?

You can find the series at
git@github.com:rogerq/linux.git
gpmc-3.16-v1

cheers,
-roger


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

* Re: [PATCH 00/36] OMAP: GPMC: Restructure and move OMAP GPMC driver out of mach-omap2
@ 2014-06-11 11:54     ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11 11:54 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: Tony Lindgren, David Woodhouse, Brian Norris, kyungmin.park,
	Gupta, Pekon, Ezequiel Garcia, nsekhar, linux-omap, linux-mtd,
	devicetree, Linux Kernel

Hi Javier,

On 06/11/2014 02:52 PM, Javier Martinez Canillas wrote:
> Hello Roger,
> 
> What a great series!!

Thanks :)

> 
> On Wed, Jun 11, 2014 at 10:56 AM, Roger Quadros <rogerq@ti.com> wrote:
>> Hi,
>>
>> This is a complete functional set to get the gpmc driver out of mach-omap2
>> and into drivers/memory. The DT binding remains the same except for the
>> following minor changes
> 
> I probably won't have time to do a proper review until at least next
> week but doing a quick glance it looks very good to me.
> 
>> - compatible property is required for NAND & OneNAND nodes
> 
> This is a minor ABI breakage but I agree with you that it is wrong
> that these were not introduced in the first place and relied on the
> dev node so I think is not that bad to break it in this case.
> 
>> - Second register space and interrupts properties are required for
>>   NAND controller node
>> - ti,onenand-sync-rw property added for OneNAND node.
>>
>> The series does the following changes
>> - Move GPMC IRQ and NAND register handling to NAND driver.
>>   The entire GPMC register space is made available to the NAND driver.
>> - Clean up NAND device tree handling. Don't rely on legacy platform device
>>   i.e. don't call gpmc_nand_init()
>> - Add 2 public APIs omap_gpmc_retime() and omap_gpmc_get_clk_period()
>>   omap_gpmc_retime() allows to reconfigure the GPMC settings and timings
>>   for the specified Chip select region.
>>   omap_gpmc_get_clk_period() allows to query the GPMC_CLK (external clock)
>>   period, to perform timing calculations.
>>   Both functions will be needed by the OneNAND driver since it calculates
>>   device timings on the fly and needs to change from Asynchronous mode
>>   to Synchronous mode.
>> - Setup OneNAND in Asynchronous mode by default and move Synchronous
>>   setting code into OneNAND driver.
>> - Clean up OneNAND device tree handling. Don't rely on legacy platform device
>>   i.e. don't call gpmc_onenand_init()
>> - Introduce gpmc_generic_init() that should be used by board files to specify
>>   GPMC chip select setting/timing and platform device within that Chip Select.
>> - Stop using all gpmc*() that are meant to be private to GPMC driver.
>> - Move GPMC driver into drivers/memory
>>
>> Tested on:
>>
>> - beagleboard C4: NAND
>> - Nokia N900: OneNAND
>>
> 
> Do you have a tree somewhere that I can use it to test on the boards I
> maintain and post patches to update the DTS according the new binding?

You can find the series at
git@github.com:rogerq/linux.git
gpmc-3.16-v1

cheers,
-roger

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

* Re: [PATCH 00/36] OMAP: GPMC: Restructure and move OMAP GPMC driver out of mach-omap2
@ 2014-06-11 11:54     ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-11 11:54 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: devicetree, linux-omap, Tony Lindgren, nsekhar, Linux Kernel,
	kyungmin.park, linux-mtd, Gupta, Pekon, Ezequiel Garcia,
	Brian Norris, David Woodhouse

Hi Javier,

On 06/11/2014 02:52 PM, Javier Martinez Canillas wrote:
> Hello Roger,
> 
> What a great series!!

Thanks :)

> 
> On Wed, Jun 11, 2014 at 10:56 AM, Roger Quadros <rogerq@ti.com> wrote:
>> Hi,
>>
>> This is a complete functional set to get the gpmc driver out of mach-omap2
>> and into drivers/memory. The DT binding remains the same except for the
>> following minor changes
> 
> I probably won't have time to do a proper review until at least next
> week but doing a quick glance it looks very good to me.
> 
>> - compatible property is required for NAND & OneNAND nodes
> 
> This is a minor ABI breakage but I agree with you that it is wrong
> that these were not introduced in the first place and relied on the
> dev node so I think is not that bad to break it in this case.
> 
>> - Second register space and interrupts properties are required for
>>   NAND controller node
>> - ti,onenand-sync-rw property added for OneNAND node.
>>
>> The series does the following changes
>> - Move GPMC IRQ and NAND register handling to NAND driver.
>>   The entire GPMC register space is made available to the NAND driver.
>> - Clean up NAND device tree handling. Don't rely on legacy platform device
>>   i.e. don't call gpmc_nand_init()
>> - Add 2 public APIs omap_gpmc_retime() and omap_gpmc_get_clk_period()
>>   omap_gpmc_retime() allows to reconfigure the GPMC settings and timings
>>   for the specified Chip select region.
>>   omap_gpmc_get_clk_period() allows to query the GPMC_CLK (external clock)
>>   period, to perform timing calculations.
>>   Both functions will be needed by the OneNAND driver since it calculates
>>   device timings on the fly and needs to change from Asynchronous mode
>>   to Synchronous mode.
>> - Setup OneNAND in Asynchronous mode by default and move Synchronous
>>   setting code into OneNAND driver.
>> - Clean up OneNAND device tree handling. Don't rely on legacy platform device
>>   i.e. don't call gpmc_onenand_init()
>> - Introduce gpmc_generic_init() that should be used by board files to specify
>>   GPMC chip select setting/timing and platform device within that Chip Select.
>> - Stop using all gpmc*() that are meant to be private to GPMC driver.
>> - Move GPMC driver into drivers/memory
>>
>> Tested on:
>>
>> - beagleboard C4: NAND
>> - Nokia N900: OneNAND
>>
> 
> Do you have a tree somewhere that I can use it to test on the boards I
> maintain and post patches to update the DTS according the new binding?

You can find the series at
git@github.com:rogerq/linux.git
gpmc-3.16-v1

cheers,
-roger

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

* Re: [PATCH 01/36] ARM: OMAP3: hwmod: Fix gpmc memory resource space
  2014-06-11  8:56   ` Roger Quadros
@ 2014-06-13  7:13     ` Tony Lindgren
  -1 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  7:13 UTC (permalink / raw)
  To: Roger Quadros
  Cc: dwmw2, computersforpeace, kyungmin.park, pekon, ezequiel.garcia,
	javier, nsekhar, linux-omap, linux-mtd, devicetree, linux-kernel

* Roger Quadros <rogerq@ti.com> [140611 01:58]:

Missing description? Probably not an urgent fix or does
this fix something?

Regards,

Tony

> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
>  arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
> index 71ac7d5..f2848a8 100644
> --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
> +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
> @@ -3426,7 +3426,7 @@ static struct omap_hwmod_addr_space omap3xxx_counter_32k_addrs[] = {
>  static struct omap_hwmod_addr_space omap3xxx_gpmc_addrs[] = {
>  	{
>  		.pa_start	= 0x6e000000,
> -		.pa_end		= 0x6e000fff,
> +		.pa_end		= 0x6e0002d4,
>  		.flags		= ADDR_TYPE_RT
>  	},
>  	{ }
> -- 
> 1.8.3.2
> 

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

* Re: [PATCH 01/36] ARM: OMAP3: hwmod: Fix gpmc memory resource space
@ 2014-06-13  7:13     ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  7:13 UTC (permalink / raw)
  To: Roger Quadros
  Cc: devicetree, linux-omap, nsekhar, linux-kernel, kyungmin.park,
	linux-mtd, pekon, ezequiel.garcia, javier, computersforpeace,
	dwmw2

* Roger Quadros <rogerq@ti.com> [140611 01:58]:

Missing description? Probably not an urgent fix or does
this fix something?

Regards,

Tony

> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
>  arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
> index 71ac7d5..f2848a8 100644
> --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
> +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
> @@ -3426,7 +3426,7 @@ static struct omap_hwmod_addr_space omap3xxx_counter_32k_addrs[] = {
>  static struct omap_hwmod_addr_space omap3xxx_gpmc_addrs[] = {
>  	{
>  		.pa_start	= 0x6e000000,
> -		.pa_end		= 0x6e000fff,
> +		.pa_end		= 0x6e0002d4,
>  		.flags		= ADDR_TYPE_RT
>  	},
>  	{ }
> -- 
> 1.8.3.2
> 

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

* Re: [PATCH 01/36] ARM: OMAP3: hwmod: Fix gpmc memory resource space
  2014-06-13  7:13     ` Tony Lindgren
  (?)
@ 2014-06-13  7:15       ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-13  7:15 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: dwmw2, computersforpeace, kyungmin.park, pekon, ezequiel.garcia,
	javier, nsekhar, linux-omap, linux-mtd, devicetree, linux-kernel

On 06/13/2014 10:13 AM, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [140611 01:58]:
> 
> Missing description? Probably not an urgent fix or does
> this fix something?

Doesn't fix anything. It is just for correctness. I'll add the description.

cheers,
-roger

> 
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> ---
>>  arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
>> index 71ac7d5..f2848a8 100644
>> --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
>> +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
>> @@ -3426,7 +3426,7 @@ static struct omap_hwmod_addr_space omap3xxx_counter_32k_addrs[] = {
>>  static struct omap_hwmod_addr_space omap3xxx_gpmc_addrs[] = {
>>  	{
>>  		.pa_start	= 0x6e000000,
>> -		.pa_end		= 0x6e000fff,
>> +		.pa_end		= 0x6e0002d4,
>>  		.flags		= ADDR_TYPE_RT
>>  	},
>>  	{ }
>> -- 
>> 1.8.3.2
>>


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

* Re: [PATCH 01/36] ARM: OMAP3: hwmod: Fix gpmc memory resource space
@ 2014-06-13  7:15       ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-13  7:15 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: dwmw2, computersforpeace, kyungmin.park, pekon, ezequiel.garcia,
	javier, nsekhar, linux-omap, linux-mtd, devicetree, linux-kernel

On 06/13/2014 10:13 AM, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [140611 01:58]:
> 
> Missing description? Probably not an urgent fix or does
> this fix something?

Doesn't fix anything. It is just for correctness. I'll add the description.

cheers,
-roger

> 
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> ---
>>  arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
>> index 71ac7d5..f2848a8 100644
>> --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
>> +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
>> @@ -3426,7 +3426,7 @@ static struct omap_hwmod_addr_space omap3xxx_counter_32k_addrs[] = {
>>  static struct omap_hwmod_addr_space omap3xxx_gpmc_addrs[] = {
>>  	{
>>  		.pa_start	= 0x6e000000,
>> -		.pa_end		= 0x6e000fff,
>> +		.pa_end		= 0x6e0002d4,
>>  		.flags		= ADDR_TYPE_RT
>>  	},
>>  	{ }
>> -- 
>> 1.8.3.2
>>


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

* Re: [PATCH 01/36] ARM: OMAP3: hwmod: Fix gpmc memory resource space
@ 2014-06-13  7:15       ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-13  7:15 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: devicetree, linux-omap, nsekhar, linux-kernel, kyungmin.park,
	linux-mtd, pekon, ezequiel.garcia, javier, computersforpeace,
	dwmw2

On 06/13/2014 10:13 AM, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [140611 01:58]:
> 
> Missing description? Probably not an urgent fix or does
> this fix something?

Doesn't fix anything. It is just for correctness. I'll add the description.

cheers,
-roger

> 
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> ---
>>  arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
>> index 71ac7d5..f2848a8 100644
>> --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
>> +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
>> @@ -3426,7 +3426,7 @@ static struct omap_hwmod_addr_space omap3xxx_counter_32k_addrs[] = {
>>  static struct omap_hwmod_addr_space omap3xxx_gpmc_addrs[] = {
>>  	{
>>  		.pa_start	= 0x6e000000,
>> -		.pa_end		= 0x6e000fff,
>> +		.pa_end		= 0x6e0002d4,
>>  		.flags		= ADDR_TYPE_RT
>>  	},
>>  	{ }
>> -- 
>> 1.8.3.2
>>

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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
  2014-06-11  8:56   ` Roger Quadros
@ 2014-06-13  7:18     ` Tony Lindgren
  -1 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  7:18 UTC (permalink / raw)
  To: Roger Quadros
  Cc: dwmw2, computersforpeace, kyungmin.park, pekon, ezequiel.garcia,
	javier, nsekhar, linux-omap, linux-mtd, devicetree, linux-kernel

* Roger Quadros <rogerq@ti.com> [140611 01:58]:
> Since the Interrupt Events are used only by the NAND driver,
> there is no point in managing the Interrupt registers
> in the GPMC driver and complicating it with irqchip modeling.
> 
> Let's manage the interrupt registers directly in the NAND driver
> and get rid of irqchip model from GPMC driver.
> 
> Get rid of IRQ commands and unused commands from gpmc_configure() in
> the GPMC driver.

This seems like a step backward to me. The GPMC interrupt enable
register can do edge detection on the wait pins, how is that
limited to NAND?

Further, let's not start mixing GPMC hardware module register
access with the NAND driver register access. They can be clocked
separately. And bugs in the NAND driver can cause issues in other
GPMC using drivers.

Regards,

Tony

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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-06-13  7:18     ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  7:18 UTC (permalink / raw)
  To: Roger Quadros
  Cc: devicetree, linux-omap, nsekhar, linux-kernel, kyungmin.park,
	linux-mtd, pekon, ezequiel.garcia, javier, computersforpeace,
	dwmw2

* Roger Quadros <rogerq@ti.com> [140611 01:58]:
> Since the Interrupt Events are used only by the NAND driver,
> there is no point in managing the Interrupt registers
> in the GPMC driver and complicating it with irqchip modeling.
> 
> Let's manage the interrupt registers directly in the NAND driver
> and get rid of irqchip model from GPMC driver.
> 
> Get rid of IRQ commands and unused commands from gpmc_configure() in
> the GPMC driver.

This seems like a step backward to me. The GPMC interrupt enable
register can do edge detection on the wait pins, how is that
limited to NAND?

Further, let's not start mixing GPMC hardware module register
access with the NAND driver register access. They can be clocked
separately. And bugs in the NAND driver can cause issues in other
GPMC using drivers.

Regards,

Tony

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

* Re: [PATCH 06/36] mtd: nand: omap: Move gpmc_update_nand_reg to nand driver
@ 2014-06-13  7:19     ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  7:19 UTC (permalink / raw)
  To: Roger Quadros
  Cc: dwmw2, computersforpeace, kyungmin.park, pekon, ezequiel.garcia,
	javier, nsekhar, linux-omap, linux-mtd, devicetree, linux-kernel

* Roger Quadros <rogerq@ti.com> [140611 01:58]:
> GPMC and NAND drivers share the same register space but never use the
> same registers. As there is no clear address seperation between the
> registers for GPMC and NAND, we can't easily split it up into 2 regions
> i.e. one for GPMC and other for NAND. Instead, we simply remap the entire
> register space in both the drivers. The NAND driver doesn't re-request
> the region as it is already requested by the GPMC driver (parent).

Oh now, let's not do this. It's best to limit GPMC register access
to the GPMC driver. Even if we need to export few NAND specific
functions from the GPMC driver.

Regards,

Tony

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

* Re: [PATCH 06/36] mtd: nand: omap: Move gpmc_update_nand_reg to nand driver
@ 2014-06-13  7:19     ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  7:19 UTC (permalink / raw)
  To: Roger Quadros
  Cc: dwmw2-wEGCiKHe2LqWVfeAwA7xHQ,
	computersforpeace-Re5JQEeQqe8AvxtiuMwx3w,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ, pekon-l0cyMroinI0,
	ezequiel.garcia-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	javier-0uQlZySMnqxg9hUCZPvPmw, nsekhar-l0cyMroinI0,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

* Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> [140611 01:58]:
> GPMC and NAND drivers share the same register space but never use the
> same registers. As there is no clear address seperation between the
> registers for GPMC and NAND, we can't easily split it up into 2 regions
> i.e. one for GPMC and other for NAND. Instead, we simply remap the entire
> register space in both the drivers. The NAND driver doesn't re-request
> the region as it is already requested by the GPMC driver (parent).

Oh now, let's not do this. It's best to limit GPMC register access
to the GPMC driver. Even if we need to export few NAND specific
functions from the GPMC driver.

Regards,

Tony
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 06/36] mtd: nand: omap: Move gpmc_update_nand_reg to nand driver
@ 2014-06-13  7:19     ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  7:19 UTC (permalink / raw)
  To: Roger Quadros
  Cc: devicetree, linux-omap, nsekhar, linux-kernel, kyungmin.park,
	linux-mtd, pekon, ezequiel.garcia, javier, computersforpeace,
	dwmw2

* Roger Quadros <rogerq@ti.com> [140611 01:58]:
> GPMC and NAND drivers share the same register space but never use the
> same registers. As there is no clear address seperation between the
> registers for GPMC and NAND, we can't easily split it up into 2 regions
> i.e. one for GPMC and other for NAND. Instead, we simply remap the entire
> register space in both the drivers. The NAND driver doesn't re-request
> the region as it is already requested by the GPMC driver (parent).

Oh now, let's not do this. It's best to limit GPMC register access
to the GPMC driver. Even if we need to export few NAND specific
functions from the GPMC driver.

Regards,

Tony

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

* Re: [PATCH 07/36] mtd: nand: omap: Move NAND write protect code from GPMC to NAND driver
  2014-06-11  8:56   ` Roger Quadros
@ 2014-06-13  7:20     ` Tony Lindgren
  -1 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  7:20 UTC (permalink / raw)
  To: Roger Quadros
  Cc: dwmw2, computersforpeace, kyungmin.park, pekon, ezequiel.garcia,
	javier, nsekhar, linux-omap, linux-mtd, devicetree, linux-kernel

* Roger Quadros <rogerq@ti.com> [140611 01:58]:
> The write protect (WP) pin is only used for NAND devices. So move
> the code into the NAND driver.

Eek, noooo!

Tony

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

* Re: [PATCH 07/36] mtd: nand: omap: Move NAND write protect code from GPMC to NAND driver
@ 2014-06-13  7:20     ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  7:20 UTC (permalink / raw)
  To: Roger Quadros
  Cc: devicetree, linux-omap, nsekhar, linux-kernel, kyungmin.park,
	linux-mtd, pekon, ezequiel.garcia, javier, computersforpeace,
	dwmw2

* Roger Quadros <rogerq@ti.com> [140611 01:58]:
> The write protect (WP) pin is only used for NAND devices. So move
> the code into the NAND driver.

Eek, noooo!

Tony

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

* Re: [PATCH 10/36] ARM: dts: OMAP2+: Fix NAND device nodes
@ 2014-06-13  7:21     ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  7:21 UTC (permalink / raw)
  To: Roger Quadros
  Cc: dwmw2, computersforpeace, kyungmin.park, pekon, ezequiel.garcia,
	javier, nsekhar, linux-omap, linux-mtd, devicetree, linux-kernel

* Roger Quadros <rogerq@ti.com> [140611 01:58]:
> Add compatible id, GPMC register resource and interrupt
> resource to NAND controller nodes.
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
>  arch/arm/boot/dts/am335x-evm.dts         |  8 ++++++--
>  arch/arm/boot/dts/am335x-igep0033.dtsi   |  8 ++++++--
>  arch/arm/boot/dts/am43x-epos-evm.dts     |  8 ++++++--
>  arch/arm/boot/dts/omap3-devkit8000.dts   |  9 +++++++--
>  arch/arm/boot/dts/omap3-evm-37xx.dts     | 10 +++++++---
>  arch/arm/boot/dts/omap3-igep0020.dts     | 10 +++++++---
>  arch/arm/boot/dts/omap3-igep0030.dts     |  8 ++++++--
>  arch/arm/boot/dts/omap3-ldp.dts          | 10 +++++++---
>  arch/arm/boot/dts/omap3-lilly-a83x.dtsi  | 10 +++++++---
>  arch/arm/boot/dts/omap3-lilly-dbb056.dts |  7 ++++---
>  arch/arm/boot/dts/omap3430-sdp.dts       |  8 ++++++--
>  11 files changed, 69 insertions(+), 27 deletions(-)
> 
> diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
> index 6028217..fa25f2b 100644
> --- a/arch/arm/boot/dts/am335x-evm.dts
> +++ b/arch/arm/boot/dts/am335x-evm.dts
> @@ -437,9 +437,13 @@
>  	status = "okay";
>  	pinctrl-names = "default";
>  	pinctrl-0 = <&nandflash_pins_s0>;
> -	ranges = <0 0 0x08000000 0x10000000>;	/* CS0: NAND */
> +	ranges = <0 0 0x08000000 0x10000000	/* CS0 space, 16MB */
> +		  255 0 0x50000000 0x36c>;	/* GPMC reg */

And here too let's not let the NAND driver tinker with the GPMC
registers.

Tony

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

* Re: [PATCH 10/36] ARM: dts: OMAP2+: Fix NAND device nodes
@ 2014-06-13  7:21     ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  7:21 UTC (permalink / raw)
  To: Roger Quadros
  Cc: dwmw2-wEGCiKHe2LqWVfeAwA7xHQ,
	computersforpeace-Re5JQEeQqe8AvxtiuMwx3w,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ, pekon-l0cyMroinI0,
	ezequiel.garcia-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	javier-0uQlZySMnqxg9hUCZPvPmw, nsekhar-l0cyMroinI0,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

* Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> [140611 01:58]:
> Add compatible id, GPMC register resource and interrupt
> resource to NAND controller nodes.
> 
> Signed-off-by: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
> ---
>  arch/arm/boot/dts/am335x-evm.dts         |  8 ++++++--
>  arch/arm/boot/dts/am335x-igep0033.dtsi   |  8 ++++++--
>  arch/arm/boot/dts/am43x-epos-evm.dts     |  8 ++++++--
>  arch/arm/boot/dts/omap3-devkit8000.dts   |  9 +++++++--
>  arch/arm/boot/dts/omap3-evm-37xx.dts     | 10 +++++++---
>  arch/arm/boot/dts/omap3-igep0020.dts     | 10 +++++++---
>  arch/arm/boot/dts/omap3-igep0030.dts     |  8 ++++++--
>  arch/arm/boot/dts/omap3-ldp.dts          | 10 +++++++---
>  arch/arm/boot/dts/omap3-lilly-a83x.dtsi  | 10 +++++++---
>  arch/arm/boot/dts/omap3-lilly-dbb056.dts |  7 ++++---
>  arch/arm/boot/dts/omap3430-sdp.dts       |  8 ++++++--
>  11 files changed, 69 insertions(+), 27 deletions(-)
> 
> diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
> index 6028217..fa25f2b 100644
> --- a/arch/arm/boot/dts/am335x-evm.dts
> +++ b/arch/arm/boot/dts/am335x-evm.dts
> @@ -437,9 +437,13 @@
>  	status = "okay";
>  	pinctrl-names = "default";
>  	pinctrl-0 = <&nandflash_pins_s0>;
> -	ranges = <0 0 0x08000000 0x10000000>;	/* CS0: NAND */
> +	ranges = <0 0 0x08000000 0x10000000	/* CS0 space, 16MB */
> +		  255 0 0x50000000 0x36c>;	/* GPMC reg */

And here too let's not let the NAND driver tinker with the GPMC
registers.

Tony
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 10/36] ARM: dts: OMAP2+: Fix NAND device nodes
@ 2014-06-13  7:21     ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  7:21 UTC (permalink / raw)
  To: Roger Quadros
  Cc: devicetree, linux-omap, nsekhar, linux-kernel, kyungmin.park,
	linux-mtd, pekon, ezequiel.garcia, javier, computersforpeace,
	dwmw2

* Roger Quadros <rogerq@ti.com> [140611 01:58]:
> Add compatible id, GPMC register resource and interrupt
> resource to NAND controller nodes.
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
>  arch/arm/boot/dts/am335x-evm.dts         |  8 ++++++--
>  arch/arm/boot/dts/am335x-igep0033.dtsi   |  8 ++++++--
>  arch/arm/boot/dts/am43x-epos-evm.dts     |  8 ++++++--
>  arch/arm/boot/dts/omap3-devkit8000.dts   |  9 +++++++--
>  arch/arm/boot/dts/omap3-evm-37xx.dts     | 10 +++++++---
>  arch/arm/boot/dts/omap3-igep0020.dts     | 10 +++++++---
>  arch/arm/boot/dts/omap3-igep0030.dts     |  8 ++++++--
>  arch/arm/boot/dts/omap3-ldp.dts          | 10 +++++++---
>  arch/arm/boot/dts/omap3-lilly-a83x.dtsi  | 10 +++++++---
>  arch/arm/boot/dts/omap3-lilly-dbb056.dts |  7 ++++---
>  arch/arm/boot/dts/omap3430-sdp.dts       |  8 ++++++--
>  11 files changed, 69 insertions(+), 27 deletions(-)
> 
> diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
> index 6028217..fa25f2b 100644
> --- a/arch/arm/boot/dts/am335x-evm.dts
> +++ b/arch/arm/boot/dts/am335x-evm.dts
> @@ -437,9 +437,13 @@
>  	status = "okay";
>  	pinctrl-names = "default";
>  	pinctrl-0 = <&nandflash_pins_s0>;
> -	ranges = <0 0 0x08000000 0x10000000>;	/* CS0: NAND */
> +	ranges = <0 0 0x08000000 0x10000000	/* CS0 space, 16MB */
> +		  255 0 0x50000000 0x36c>;	/* GPMC reg */

And here too let's not let the NAND driver tinker with the GPMC
registers.

Tony

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

* Re: [PATCH 14/36] ARM: OMAP2+: gpmc: Allow drivers to reconfigure GPMC settings & timings
  2014-06-11  8:56   ` Roger Quadros
@ 2014-06-13  7:25     ` Tony Lindgren
  -1 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  7:25 UTC (permalink / raw)
  To: Roger Quadros
  Cc: dwmw2, computersforpeace, kyungmin.park, pekon, ezequiel.garcia,
	javier, nsekhar, linux-omap, linux-mtd, devicetree, linux-kernel

* Roger Quadros <rogerq@ti.com> [140611 01:58]:
> Some devices (e.g. TUSB6010, omap-onenand) need to reconfigure the GPMC
> timings in order to operate with different peripheral clock frequencies.
> Introduce omap_gpmc_retime() to allow them to do that. The driver
> needs to pass the chips select number, GPMC settings and Device timings to
> omap_gpmc_retime().
> 
> NOTE: Device tree and board code must still pass the most conservative
> timings to GPMC so that the device can be probed by the respective driver.
> e.g. Onenand must operate in asynchronous mode at bootup. The device driver
> can then request for more optimal timings via omap_gpmc_retime().

Hmm but many of the devices are Linux generic like sms91x and 8250 so it's
not nice to start stuffing omap bus specific data there.

I wonder if we should just keep device specific gpmc-smc91x.c etc
in drivers/memory?

Regards,

Tony

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

* Re: [PATCH 14/36] ARM: OMAP2+: gpmc: Allow drivers to reconfigure GPMC settings & timings
@ 2014-06-13  7:25     ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  7:25 UTC (permalink / raw)
  To: Roger Quadros
  Cc: devicetree, linux-omap, nsekhar, linux-kernel, kyungmin.park,
	linux-mtd, pekon, ezequiel.garcia, javier, computersforpeace,
	dwmw2

* Roger Quadros <rogerq@ti.com> [140611 01:58]:
> Some devices (e.g. TUSB6010, omap-onenand) need to reconfigure the GPMC
> timings in order to operate with different peripheral clock frequencies.
> Introduce omap_gpmc_retime() to allow them to do that. The driver
> needs to pass the chips select number, GPMC settings and Device timings to
> omap_gpmc_retime().
> 
> NOTE: Device tree and board code must still pass the most conservative
> timings to GPMC so that the device can be probed by the respective driver.
> e.g. Onenand must operate in asynchronous mode at bootup. The device driver
> can then request for more optimal timings via omap_gpmc_retime().

Hmm but many of the devices are Linux generic like sms91x and 8250 so it's
not nice to start stuffing omap bus specific data there.

I wonder if we should just keep device specific gpmc-smc91x.c etc
in drivers/memory?

Regards,

Tony

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

* Re: [PATCH 15/36] ARM: OMAP2+: gpmc: Allow drivers to query GPMC_CLK period
  2014-06-11  8:56   ` Roger Quadros
@ 2014-06-13  7:26     ` Tony Lindgren
  -1 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  7:26 UTC (permalink / raw)
  To: Roger Quadros
  Cc: dwmw2, computersforpeace, kyungmin.park, pekon, ezequiel.garcia,
	javier, nsekhar, linux-omap, linux-mtd, devicetree, linux-kernel

* Roger Quadros <rogerq@ti.com> [140611 01:59]:
> GPMC_CLK is the external clock output pin that is used for syncronous
> accesses.
> 
> Device drivers need to know the fastest possible GPMC_CLK period in order
> to calculate the most optimal device timings. Add the function
> omap_gpmc_get_clk_period() to allow drivers to get the nearset possible
> (equal to or greater than) GPMC_CLK period given the minimum
> clock period supported by the attached device.
> 
> This is especially needed by the onenand driver as it calculates
> device timings on the fly for various onenand speed grades.

Here too this should probably still be done by the gpmc to driver
glue layer, not by the actual driver that shoud be Linux generic.

Regards,

Tony

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

* Re: [PATCH 15/36] ARM: OMAP2+: gpmc: Allow drivers to query GPMC_CLK period
@ 2014-06-13  7:26     ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  7:26 UTC (permalink / raw)
  To: Roger Quadros
  Cc: devicetree, linux-omap, nsekhar, linux-kernel, kyungmin.park,
	linux-mtd, pekon, ezequiel.garcia, javier, computersforpeace,
	dwmw2

* Roger Quadros <rogerq@ti.com> [140611 01:59]:
> GPMC_CLK is the external clock output pin that is used for syncronous
> accesses.
> 
> Device drivers need to know the fastest possible GPMC_CLK period in order
> to calculate the most optimal device timings. Add the function
> omap_gpmc_get_clk_period() to allow drivers to get the nearset possible
> (equal to or greater than) GPMC_CLK period given the minimum
> clock period supported by the attached device.
> 
> This is especially needed by the onenand driver as it calculates
> device timings on the fly for various onenand speed grades.

Here too this should probably still be done by the gpmc to driver
glue layer, not by the actual driver that shoud be Linux generic.

Regards,

Tony

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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-06-13  7:38       ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-13  7:38 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: dwmw2, computersforpeace, kyungmin.park, pekon, ezequiel.garcia,
	javier, nsekhar, linux-omap, linux-mtd, devicetree, linux-kernel

On 06/13/2014 10:18 AM, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [140611 01:58]:
>> Since the Interrupt Events are used only by the NAND driver,
>> there is no point in managing the Interrupt registers
>> in the GPMC driver and complicating it with irqchip modeling.
>>
>> Let's manage the interrupt registers directly in the NAND driver
>> and get rid of irqchip model from GPMC driver.
>>
>> Get rid of IRQ commands and unused commands from gpmc_configure() in
>> the GPMC driver.
> 
> This seems like a step backward to me. The GPMC interrupt enable
> register can do edge detection on the wait pins, how is that
> limited to NAND?

OK. But wait pin edge detection was not yet being used and I couldn't
think of how it would ever be used. Any ideas?

> 
> Further, let's not start mixing GPMC hardware module register
> access with the NAND driver register access. They can be clocked
> separately. And bugs in the NAND driver can cause issues in other
> GPMC using drivers.

I understood that NAND controller is integrated into the GPMC module and they are clocked
the same. Not sure why the hardware designers would keep the registers so closely knit.

FYI. memory/ti-amif.c and mtd/nand/davinci_nand.c share the AMIF register space in the
same way. I thought it'd be nice to be consistent across TI drivers.

cheers,
-roger

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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-06-13  7:38       ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-13  7:38 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: dwmw2-wEGCiKHe2LqWVfeAwA7xHQ,
	computersforpeace-Re5JQEeQqe8AvxtiuMwx3w,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ, pekon-l0cyMroinI0,
	ezequiel.garcia-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	javier-0uQlZySMnqxg9hUCZPvPmw, nsekhar-l0cyMroinI0,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

On 06/13/2014 10:18 AM, Tony Lindgren wrote:
> * Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> [140611 01:58]:
>> Since the Interrupt Events are used only by the NAND driver,
>> there is no point in managing the Interrupt registers
>> in the GPMC driver and complicating it with irqchip modeling.
>>
>> Let's manage the interrupt registers directly in the NAND driver
>> and get rid of irqchip model from GPMC driver.
>>
>> Get rid of IRQ commands and unused commands from gpmc_configure() in
>> the GPMC driver.
> 
> This seems like a step backward to me. The GPMC interrupt enable
> register can do edge detection on the wait pins, how is that
> limited to NAND?

OK. But wait pin edge detection was not yet being used and I couldn't
think of how it would ever be used. Any ideas?

> 
> Further, let's not start mixing GPMC hardware module register
> access with the NAND driver register access. They can be clocked
> separately. And bugs in the NAND driver can cause issues in other
> GPMC using drivers.

I understood that NAND controller is integrated into the GPMC module and they are clocked
the same. Not sure why the hardware designers would keep the registers so closely knit.

FYI. memory/ti-amif.c and mtd/nand/davinci_nand.c share the AMIF register space in the
same way. I thought it'd be nice to be consistent across TI drivers.

cheers,
-roger
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-06-13  7:38       ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-13  7:38 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: devicetree, linux-omap, nsekhar, linux-kernel, kyungmin.park,
	linux-mtd, pekon, ezequiel.garcia, javier, computersforpeace,
	dwmw2

On 06/13/2014 10:18 AM, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [140611 01:58]:
>> Since the Interrupt Events are used only by the NAND driver,
>> there is no point in managing the Interrupt registers
>> in the GPMC driver and complicating it with irqchip modeling.
>>
>> Let's manage the interrupt registers directly in the NAND driver
>> and get rid of irqchip model from GPMC driver.
>>
>> Get rid of IRQ commands and unused commands from gpmc_configure() in
>> the GPMC driver.
> 
> This seems like a step backward to me. The GPMC interrupt enable
> register can do edge detection on the wait pins, how is that
> limited to NAND?

OK. But wait pin edge detection was not yet being used and I couldn't
think of how it would ever be used. Any ideas?

> 
> Further, let's not start mixing GPMC hardware module register
> access with the NAND driver register access. They can be clocked
> separately. And bugs in the NAND driver can cause issues in other
> GPMC using drivers.

I understood that NAND controller is integrated into the GPMC module and they are clocked
the same. Not sure why the hardware designers would keep the registers so closely knit.

FYI. memory/ti-amif.c and mtd/nand/davinci_nand.c share the AMIF register space in the
same way. I thought it'd be nice to be consistent across TI drivers.

cheers,
-roger

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

* Re: [PATCH 14/36] ARM: OMAP2+: gpmc: Allow drivers to reconfigure GPMC settings & timings
  2014-06-13  7:25     ` Tony Lindgren
  (?)
@ 2014-06-13  7:44       ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-13  7:44 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: dwmw2, computersforpeace, kyungmin.park, pekon, ezequiel.garcia,
	javier, nsekhar, linux-omap, linux-mtd, devicetree, linux-kernel

On 06/13/2014 10:25 AM, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [140611 01:58]:
>> Some devices (e.g. TUSB6010, omap-onenand) need to reconfigure the GPMC
>> timings in order to operate with different peripheral clock frequencies.
>> Introduce omap_gpmc_retime() to allow them to do that. The driver
>> needs to pass the chips select number, GPMC settings and Device timings to
>> omap_gpmc_retime().
>>
>> NOTE: Device tree and board code must still pass the most conservative
>> timings to GPMC so that the device can be probed by the respective driver.
>> e.g. Onenand must operate in asynchronous mode at bootup. The device driver
>> can then request for more optimal timings via omap_gpmc_retime().
> 
> Hmm but many of the devices are Linux generic like sms91x and 8250 so it's
> not nice to start stuffing omap bus specific data there.

Those drivers should never need to use this function. Hopefully they will work with a one time setup where we specify the timings in the DT. This function is primarily for use by omap-onenand and tusb6010, which are both OMAP specific.

cheers,
-roger

> 
> I wonder if we should just keep device specific gpmc-smc91x.c etc
> in drivers/memory?
> 
> Regards,
> 
> Tony
> 


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

* Re: [PATCH 14/36] ARM: OMAP2+: gpmc: Allow drivers to reconfigure GPMC settings & timings
@ 2014-06-13  7:44       ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-13  7:44 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: dwmw2, computersforpeace, kyungmin.park, pekon, ezequiel.garcia,
	javier, nsekhar, linux-omap, linux-mtd, devicetree, linux-kernel

On 06/13/2014 10:25 AM, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [140611 01:58]:
>> Some devices (e.g. TUSB6010, omap-onenand) need to reconfigure the GPMC
>> timings in order to operate with different peripheral clock frequencies.
>> Introduce omap_gpmc_retime() to allow them to do that. The driver
>> needs to pass the chips select number, GPMC settings and Device timings to
>> omap_gpmc_retime().
>>
>> NOTE: Device tree and board code must still pass the most conservative
>> timings to GPMC so that the device can be probed by the respective driver.
>> e.g. Onenand must operate in asynchronous mode at bootup. The device driver
>> can then request for more optimal timings via omap_gpmc_retime().
> 
> Hmm but many of the devices are Linux generic like sms91x and 8250 so it's
> not nice to start stuffing omap bus specific data there.

Those drivers should never need to use this function. Hopefully they will work with a one time setup where we specify the timings in the DT. This function is primarily for use by omap-onenand and tusb6010, which are both OMAP specific.

cheers,
-roger

> 
> I wonder if we should just keep device specific gpmc-smc91x.c etc
> in drivers/memory?
> 
> Regards,
> 
> Tony
> 

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

* Re: [PATCH 14/36] ARM: OMAP2+: gpmc: Allow drivers to reconfigure GPMC settings & timings
@ 2014-06-13  7:44       ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-13  7:44 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: devicetree, linux-omap, nsekhar, linux-kernel, kyungmin.park,
	linux-mtd, pekon, ezequiel.garcia, javier, computersforpeace,
	dwmw2

On 06/13/2014 10:25 AM, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [140611 01:58]:
>> Some devices (e.g. TUSB6010, omap-onenand) need to reconfigure the GPMC
>> timings in order to operate with different peripheral clock frequencies.
>> Introduce omap_gpmc_retime() to allow them to do that. The driver
>> needs to pass the chips select number, GPMC settings and Device timings to
>> omap_gpmc_retime().
>>
>> NOTE: Device tree and board code must still pass the most conservative
>> timings to GPMC so that the device can be probed by the respective driver.
>> e.g. Onenand must operate in asynchronous mode at bootup. The device driver
>> can then request for more optimal timings via omap_gpmc_retime().
> 
> Hmm but many of the devices are Linux generic like sms91x and 8250 so it's
> not nice to start stuffing omap bus specific data there.

Those drivers should never need to use this function. Hopefully they will work with a one time setup where we specify the timings in the DT. This function is primarily for use by omap-onenand and tusb6010, which are both OMAP specific.

cheers,
-roger

> 
> I wonder if we should just keep device specific gpmc-smc91x.c etc
> in drivers/memory?
> 
> Regards,
> 
> Tony
> 

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

* Re: [PATCH 15/36] ARM: OMAP2+: gpmc: Allow drivers to query GPMC_CLK period
  2014-06-13  7:26     ` Tony Lindgren
  (?)
@ 2014-06-13  7:48       ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-13  7:48 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: dwmw2, computersforpeace, kyungmin.park, pekon, ezequiel.garcia,
	javier, nsekhar, linux-omap, linux-mtd, devicetree, linux-kernel

On 06/13/2014 10:26 AM, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [140611 01:59]:
>> GPMC_CLK is the external clock output pin that is used for syncronous
>> accesses.
>>
>> Device drivers need to know the fastest possible GPMC_CLK period in order
>> to calculate the most optimal device timings. Add the function
>> omap_gpmc_get_clk_period() to allow drivers to get the nearset possible
>> (equal to or greater than) GPMC_CLK period given the minimum
>> clock period supported by the attached device.
>>
>> This is especially needed by the onenand driver as it calculates
>> device timings on the fly for various onenand speed grades.
> 
> Here too this should probably still be done by the gpmc to driver
> glue layer, not by the actual driver that shoud be Linux generic.

Well, this is only needed by the omap-onenand driver to perform the timing calculations at run-time.
Other option is to model the GPMC_CLK (external) as a clock and request the rate using the clock framework.
But since this and the retime() is only used by 2 OMAP specific drivers, I'm not sure if it is worth the effort.

cheers,
-roger


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

* Re: [PATCH 15/36] ARM: OMAP2+: gpmc: Allow drivers to query GPMC_CLK period
@ 2014-06-13  7:48       ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-13  7:48 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: dwmw2, computersforpeace, kyungmin.park, pekon, ezequiel.garcia,
	javier, nsekhar, linux-omap, linux-mtd, devicetree, linux-kernel

On 06/13/2014 10:26 AM, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [140611 01:59]:
>> GPMC_CLK is the external clock output pin that is used for syncronous
>> accesses.
>>
>> Device drivers need to know the fastest possible GPMC_CLK period in order
>> to calculate the most optimal device timings. Add the function
>> omap_gpmc_get_clk_period() to allow drivers to get the nearset possible
>> (equal to or greater than) GPMC_CLK period given the minimum
>> clock period supported by the attached device.
>>
>> This is especially needed by the onenand driver as it calculates
>> device timings on the fly for various onenand speed grades.
> 
> Here too this should probably still be done by the gpmc to driver
> glue layer, not by the actual driver that shoud be Linux generic.

Well, this is only needed by the omap-onenand driver to perform the timing calculations at run-time.
Other option is to model the GPMC_CLK (external) as a clock and request the rate using the clock framework.
But since this and the retime() is only used by 2 OMAP specific drivers, I'm not sure if it is worth the effort.

cheers,
-roger

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

* Re: [PATCH 15/36] ARM: OMAP2+: gpmc: Allow drivers to query GPMC_CLK period
@ 2014-06-13  7:48       ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-13  7:48 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: devicetree, linux-omap, nsekhar, linux-kernel, kyungmin.park,
	linux-mtd, pekon, ezequiel.garcia, javier, computersforpeace,
	dwmw2

On 06/13/2014 10:26 AM, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [140611 01:59]:
>> GPMC_CLK is the external clock output pin that is used for syncronous
>> accesses.
>>
>> Device drivers need to know the fastest possible GPMC_CLK period in order
>> to calculate the most optimal device timings. Add the function
>> omap_gpmc_get_clk_period() to allow drivers to get the nearset possible
>> (equal to or greater than) GPMC_CLK period given the minimum
>> clock period supported by the attached device.
>>
>> This is especially needed by the onenand driver as it calculates
>> device timings on the fly for various onenand speed grades.
> 
> Here too this should probably still be done by the gpmc to driver
> glue layer, not by the actual driver that shoud be Linux generic.

Well, this is only needed by the omap-onenand driver to perform the timing calculations at run-time.
Other option is to model the GPMC_CLK (external) as a clock and request the rate using the clock framework.
But since this and the retime() is only used by 2 OMAP specific drivers, I'm not sure if it is worth the effort.

cheers,
-roger

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

* Re: [PATCH 18/36] ARM: OMAP2+: gpmc-onenand: Move Synchronous setting code to drivers/
@ 2014-06-13  7:55     ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  7:55 UTC (permalink / raw)
  To: Roger Quadros
  Cc: dwmw2, computersforpeace, kyungmin.park, pekon, ezequiel.garcia,
	javier, nsekhar, linux-omap, linux-mtd, devicetree, linux-kernel

* Roger Quadros <rogerq@ti.com> [140611 01:59]:
> Move the code that puts the onenand in synchronous mode
> into the appropriate place i.e. drivers/mtd/onenand/omap2.c.
> 
> Make use of omap_gpmc_get_clk_period() and omap_gpmc_retime()
> to calculate the necessary timings and configure the GPMC
> parent's timings.

Ideally we would just use the drivers/mtd/onenand/generic.c
and get rid of drivers/mtd/onenand/omap2.c. We still need
the bus glue, which should probably be in drivers/memory?

Regards,

Tony

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

* Re: [PATCH 18/36] ARM: OMAP2+: gpmc-onenand: Move Synchronous setting code to drivers/
@ 2014-06-13  7:55     ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  7:55 UTC (permalink / raw)
  To: Roger Quadros
  Cc: dwmw2-wEGCiKHe2LqWVfeAwA7xHQ,
	computersforpeace-Re5JQEeQqe8AvxtiuMwx3w,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ, pekon-l0cyMroinI0,
	ezequiel.garcia-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	javier-0uQlZySMnqxg9hUCZPvPmw, nsekhar-l0cyMroinI0,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

* Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> [140611 01:59]:
> Move the code that puts the onenand in synchronous mode
> into the appropriate place i.e. drivers/mtd/onenand/omap2.c.
> 
> Make use of omap_gpmc_get_clk_period() and omap_gpmc_retime()
> to calculate the necessary timings and configure the GPMC
> parent's timings.

Ideally we would just use the drivers/mtd/onenand/generic.c
and get rid of drivers/mtd/onenand/omap2.c. We still need
the bus glue, which should probably be in drivers/memory?

Regards,

Tony
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 18/36] ARM: OMAP2+: gpmc-onenand: Move Synchronous setting code to drivers/
@ 2014-06-13  7:55     ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  7:55 UTC (permalink / raw)
  To: Roger Quadros
  Cc: devicetree, linux-omap, nsekhar, linux-kernel, kyungmin.park,
	linux-mtd, pekon, ezequiel.garcia, javier, computersforpeace,
	dwmw2

* Roger Quadros <rogerq@ti.com> [140611 01:59]:
> Move the code that puts the onenand in synchronous mode
> into the appropriate place i.e. drivers/mtd/onenand/omap2.c.
> 
> Make use of omap_gpmc_get_clk_period() and omap_gpmc_retime()
> to calculate the necessary timings and configure the GPMC
> parent's timings.

Ideally we would just use the drivers/mtd/onenand/generic.c
and get rid of drivers/mtd/onenand/omap2.c. We still need
the bus glue, which should probably be in drivers/memory?

Regards,

Tony

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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-06-13  7:58         ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  7:58 UTC (permalink / raw)
  To: Roger Quadros
  Cc: dwmw2, computersforpeace, kyungmin.park, pekon, ezequiel.garcia,
	javier, nsekhar, linux-omap, linux-mtd, devicetree, linux-kernel

* Roger Quadros <rogerq@ti.com> [140613 00:40]:
> On 06/13/2014 10:18 AM, Tony Lindgren wrote:
> > * Roger Quadros <rogerq@ti.com> [140611 01:58]:
> >> Since the Interrupt Events are used only by the NAND driver,
> >> there is no point in managing the Interrupt registers
> >> in the GPMC driver and complicating it with irqchip modeling.
> >>
> >> Let's manage the interrupt registers directly in the NAND driver
> >> and get rid of irqchip model from GPMC driver.
> >>
> >> Get rid of IRQ commands and unused commands from gpmc_configure() in
> >> the GPMC driver.
> > 
> > This seems like a step backward to me. The GPMC interrupt enable
> > register can do edge detection on the wait pins, how is that
> > limited to NAND?
> 
> OK. But wait pin edge detection was not yet being used and I couldn't
> think of how it would ever be used. Any ideas?

Maybe to wake-up the system on bus activity or something? 

> > Further, let's not start mixing GPMC hardware module register
> > access with the NAND driver register access. They can be clocked
> > separately. And bugs in the NAND driver can cause issues in other
> > GPMC using drivers.
> 
> I understood that NAND controller is integrated into the GPMC module and they are clocked
> the same. Not sure why the hardware designers would keep the registers so closely knit.

Yeah. Maybe regmap could provide some abstraction to the the
NAND registers.
 
> FYI. memory/ti-amif.c and mtd/nand/davinci_nand.c share the AMIF register space in the
> same way. I thought it'd be nice to be consistent across TI drivers.

Probably they did not yet learn the problems caused by it :)

Regards,

Tony

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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-06-13  7:58         ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  7:58 UTC (permalink / raw)
  To: Roger Quadros
  Cc: dwmw2-wEGCiKHe2LqWVfeAwA7xHQ,
	computersforpeace-Re5JQEeQqe8AvxtiuMwx3w,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ, pekon-l0cyMroinI0,
	ezequiel.garcia-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	javier-0uQlZySMnqxg9hUCZPvPmw, nsekhar-l0cyMroinI0,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

* Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> [140613 00:40]:
> On 06/13/2014 10:18 AM, Tony Lindgren wrote:
> > * Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> [140611 01:58]:
> >> Since the Interrupt Events are used only by the NAND driver,
> >> there is no point in managing the Interrupt registers
> >> in the GPMC driver and complicating it with irqchip modeling.
> >>
> >> Let's manage the interrupt registers directly in the NAND driver
> >> and get rid of irqchip model from GPMC driver.
> >>
> >> Get rid of IRQ commands and unused commands from gpmc_configure() in
> >> the GPMC driver.
> > 
> > This seems like a step backward to me. The GPMC interrupt enable
> > register can do edge detection on the wait pins, how is that
> > limited to NAND?
> 
> OK. But wait pin edge detection was not yet being used and I couldn't
> think of how it would ever be used. Any ideas?

Maybe to wake-up the system on bus activity or something? 

> > Further, let's not start mixing GPMC hardware module register
> > access with the NAND driver register access. They can be clocked
> > separately. And bugs in the NAND driver can cause issues in other
> > GPMC using drivers.
> 
> I understood that NAND controller is integrated into the GPMC module and they are clocked
> the same. Not sure why the hardware designers would keep the registers so closely knit.

Yeah. Maybe regmap could provide some abstraction to the the
NAND registers.
 
> FYI. memory/ti-amif.c and mtd/nand/davinci_nand.c share the AMIF register space in the
> same way. I thought it'd be nice to be consistent across TI drivers.

Probably they did not yet learn the problems caused by it :)

Regards,

Tony
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-06-13  7:58         ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  7:58 UTC (permalink / raw)
  To: Roger Quadros
  Cc: devicetree, linux-omap, nsekhar, linux-kernel, kyungmin.park,
	linux-mtd, pekon, ezequiel.garcia, javier, computersforpeace,
	dwmw2

* Roger Quadros <rogerq@ti.com> [140613 00:40]:
> On 06/13/2014 10:18 AM, Tony Lindgren wrote:
> > * Roger Quadros <rogerq@ti.com> [140611 01:58]:
> >> Since the Interrupt Events are used only by the NAND driver,
> >> there is no point in managing the Interrupt registers
> >> in the GPMC driver and complicating it with irqchip modeling.
> >>
> >> Let's manage the interrupt registers directly in the NAND driver
> >> and get rid of irqchip model from GPMC driver.
> >>
> >> Get rid of IRQ commands and unused commands from gpmc_configure() in
> >> the GPMC driver.
> > 
> > This seems like a step backward to me. The GPMC interrupt enable
> > register can do edge detection on the wait pins, how is that
> > limited to NAND?
> 
> OK. But wait pin edge detection was not yet being used and I couldn't
> think of how it would ever be used. Any ideas?

Maybe to wake-up the system on bus activity or something? 

> > Further, let's not start mixing GPMC hardware module register
> > access with the NAND driver register access. They can be clocked
> > separately. And bugs in the NAND driver can cause issues in other
> > GPMC using drivers.
> 
> I understood that NAND controller is integrated into the GPMC module and they are clocked
> the same. Not sure why the hardware designers would keep the registers so closely knit.

Yeah. Maybe regmap could provide some abstraction to the the
NAND registers.
 
> FYI. memory/ti-amif.c and mtd/nand/davinci_nand.c share the AMIF register space in the
> same way. I thought it'd be nice to be consistent across TI drivers.

Probably they did not yet learn the problems caused by it :)

Regards,

Tony

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

* Re: [PATCH 14/36] ARM: OMAP2+: gpmc: Allow drivers to reconfigure GPMC settings & timings
@ 2014-06-13  8:04         ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  8:04 UTC (permalink / raw)
  To: Roger Quadros
  Cc: dwmw2, computersforpeace, kyungmin.park, pekon, ezequiel.garcia,
	javier, nsekhar, linux-omap, linux-mtd, devicetree, linux-kernel

* Roger Quadros <rogerq@ti.com> [140613 00:46]:
> On 06/13/2014 10:25 AM, Tony Lindgren wrote:
> > * Roger Quadros <rogerq@ti.com> [140611 01:58]:
> >> Some devices (e.g. TUSB6010, omap-onenand) need to reconfigure the GPMC
> >> timings in order to operate with different peripheral clock frequencies.
> >> Introduce omap_gpmc_retime() to allow them to do that. The driver
> >> needs to pass the chips select number, GPMC settings and Device timings to
> >> omap_gpmc_retime().
> >>
> >> NOTE: Device tree and board code must still pass the most conservative
> >> timings to GPMC so that the device can be probed by the respective driver.
> >> e.g. Onenand must operate in asynchronous mode at bootup. The device driver
> >> can then request for more optimal timings via omap_gpmc_retime().
> > 
> > Hmm but many of the devices are Linux generic like sms91x and 8250 so it's
> > not nice to start stuffing omap bus specific data there.
> 
> Those drivers should never need to use this function. Hopefully they will work with a one time setup where we specify the timings in the DT. This function is primarily for use by omap-onenand and tusb6010, which are both OMAP specific.

Well those were the only ones so far that had to tolerate with L3
speed changes at some point, so others may need it potentially too.
And we could get rid of the omap specific onenand driver at some
point..

But yeah, I'm fine keeping those recalc functions in the device
drivers if it makes things simpler. Just something to consider in
any case.

Regards,

Tony

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

* Re: [PATCH 14/36] ARM: OMAP2+: gpmc: Allow drivers to reconfigure GPMC settings & timings
@ 2014-06-13  8:04         ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  8:04 UTC (permalink / raw)
  To: Roger Quadros
  Cc: dwmw2-wEGCiKHe2LqWVfeAwA7xHQ,
	computersforpeace-Re5JQEeQqe8AvxtiuMwx3w,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ, pekon-l0cyMroinI0,
	ezequiel.garcia-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	javier-0uQlZySMnqxg9hUCZPvPmw, nsekhar-l0cyMroinI0,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

* Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> [140613 00:46]:
> On 06/13/2014 10:25 AM, Tony Lindgren wrote:
> > * Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> [140611 01:58]:
> >> Some devices (e.g. TUSB6010, omap-onenand) need to reconfigure the GPMC
> >> timings in order to operate with different peripheral clock frequencies.
> >> Introduce omap_gpmc_retime() to allow them to do that. The driver
> >> needs to pass the chips select number, GPMC settings and Device timings to
> >> omap_gpmc_retime().
> >>
> >> NOTE: Device tree and board code must still pass the most conservative
> >> timings to GPMC so that the device can be probed by the respective driver.
> >> e.g. Onenand must operate in asynchronous mode at bootup. The device driver
> >> can then request for more optimal timings via omap_gpmc_retime().
> > 
> > Hmm but many of the devices are Linux generic like sms91x and 8250 so it's
> > not nice to start stuffing omap bus specific data there.
> 
> Those drivers should never need to use this function. Hopefully they will work with a one time setup where we specify the timings in the DT. This function is primarily for use by omap-onenand and tusb6010, which are both OMAP specific.

Well those were the only ones so far that had to tolerate with L3
speed changes at some point, so others may need it potentially too.
And we could get rid of the omap specific onenand driver at some
point..

But yeah, I'm fine keeping those recalc functions in the device
drivers if it makes things simpler. Just something to consider in
any case.

Regards,

Tony
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 14/36] ARM: OMAP2+: gpmc: Allow drivers to reconfigure GPMC settings & timings
@ 2014-06-13  8:04         ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13  8:04 UTC (permalink / raw)
  To: Roger Quadros
  Cc: devicetree, linux-omap, nsekhar, linux-kernel, kyungmin.park,
	linux-mtd, pekon, ezequiel.garcia, javier, computersforpeace,
	dwmw2

* Roger Quadros <rogerq@ti.com> [140613 00:46]:
> On 06/13/2014 10:25 AM, Tony Lindgren wrote:
> > * Roger Quadros <rogerq@ti.com> [140611 01:58]:
> >> Some devices (e.g. TUSB6010, omap-onenand) need to reconfigure the GPMC
> >> timings in order to operate with different peripheral clock frequencies.
> >> Introduce omap_gpmc_retime() to allow them to do that. The driver
> >> needs to pass the chips select number, GPMC settings and Device timings to
> >> omap_gpmc_retime().
> >>
> >> NOTE: Device tree and board code must still pass the most conservative
> >> timings to GPMC so that the device can be probed by the respective driver.
> >> e.g. Onenand must operate in asynchronous mode at bootup. The device driver
> >> can then request for more optimal timings via omap_gpmc_retime().
> > 
> > Hmm but many of the devices are Linux generic like sms91x and 8250 so it's
> > not nice to start stuffing omap bus specific data there.
> 
> Those drivers should never need to use this function. Hopefully they will work with a one time setup where we specify the timings in the DT. This function is primarily for use by omap-onenand and tusb6010, which are both OMAP specific.

Well those were the only ones so far that had to tolerate with L3
speed changes at some point, so others may need it potentially too.
And we could get rid of the omap specific onenand driver at some
point..

But yeah, I'm fine keeping those recalc functions in the device
drivers if it makes things simpler. Just something to consider in
any case.

Regards,

Tony

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

* RE: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
  2014-06-13  7:58         ` Tony Lindgren
  (?)
@ 2014-06-13  8:13           ` Gupta, Pekon
  -1 siblings, 0 replies; 181+ messages in thread
From: Gupta, Pekon @ 2014-06-13  8:13 UTC (permalink / raw)
  To: Tony Lindgren, Quadros, Roger
  Cc: dwmw2, computersforpeace, kyungmin.park, ezequiel.garcia, javier,
	Nori, Sekhar, linux-omap, linux-mtd, devicetree, linux-kernel


>From: Tony Lindgren [mailto:tony@atomide.com]
>>* Roger Quadros <rogerq@ti.com> [140613 00:40]:
>>> On 06/13/2014 10:18 AM, Tony Lindgren wrote:
>> >> * Roger Quadros <rogerq@ti.com> [140611 01:58]:
>> >> Since the Interrupt Events are used only by the NAND driver,
>> >> there is no point in managing the Interrupt registers
>> >> in the GPMC driver and complicating it with irqchip modeling.
>> >>
>> >> Let's manage the interrupt registers directly in the NAND driver
>> >> and get rid of irqchip model from GPMC driver.
>> >>
>> >> Get rid of IRQ commands and unused commands from gpmc_configure() in
>> >> the GPMC driver.
>> >
>> > This seems like a step backward to me. The GPMC interrupt enable
>> > register can do edge detection on the wait pins, how is that
>> > limited to NAND?
>>
>> OK. But wait pin edge detection was not yet being used and I couldn't
>> think of how it would ever be used. Any ideas?
>
>Maybe to wake-up the system on bus activity or something?
>
Sorry, I wasn't able to review this series.
But just as pointer, GPMC driver was used for interfacing many
non-memory devices like Ethernet (smc91x) and in past GPMC has been
proved to work with camera devices too, but that's wasn't mainlined.
So keeping IRQ and few other things in GPMC driver is helpful.




>> > Further, let's not start mixing GPMC hardware module register
>> > access with the NAND driver register access. They can be clocked
>> > separately. And bugs in the NAND driver can cause issues in other
>> > GPMC using drivers.
>>
>> I understood that NAND controller is integrated into the GPMC module and they are clocked
>> the same. Not sure why the hardware designers would keep the registers so closely knit.
>
>Yeah. Maybe regmap could provide some abstraction to the the
>NAND registers.
>
As you mentioned, GPMC has two set of registers:
(a) Chip-select registers (CONFIGx_cs) for device specific parameters
 (like device-width, signal-timings, etc) which are statically programmed
during probe or via DT.
(b) ECC registers which are continuously reconfigured based on
 ECC engine.

*Ideal Scenario*
NAND driver should be considered equivalent to protocol driver,
Therefore ideally it should use only those registers which are
specific to NAND (b).

*Actual Scenario*
But most NAND device today are ONFI compliant and they have
almost all device parameters like device-width, signal-timings
burned on-die in an ONFI page. These values are read back from
NAND device during device_probe() and then re-configured back
Chip-select registers (a).
Hence NAND driver needs access of both (a) and (b), which is why
You need to export complete GPMC register set to NAND driver.
However this is not the case and has been discussed earlier too..

http://lists.infradead.org/pipermail/linux-mtd/2013-October/049284.html
http://lists.infradead.org/pipermail/linux-mtd/2013-October/049347.html
(Just pointing out my version of history, would be good to read the
entire discussion. But the summary was that we need to re-configure
some GPMC chip-select registers (a) based on probe done in
NAND driver. So we need all GPMC registers exposed to NAND driver).




>> FYI. memory/ti-amif.c and mtd/nand/davinci_nand.c share the AMIF register space in the
>> same way. I thought it'd be nice to be consistent across TI drivers.
>
>Probably they did not yet learn the problems caused by it :)
>
I havn't reviewed the ti-amif.c driver completely but I think they too
configure device signal timing statically based on DT. But as per
today this is frowned upon because:

(1) Its difficult for layman user to decipher NAND signal timings
from datasheet and then convert it into controller understandable DT

(2) ONFI parameter page on NAND has these timings specified
on-die itself, and these timings are characterized for best performance
so NAND driver should re-configure these timings after probe.
Refer below mail from '<Rob Herring> robherring2@gmail.com'
http://lists.infradead.org/pipermail/linux-mtd/2014-April/053488.html


Considering all these details, please re-review the changes you plan
for GPMC driver.

with regards, pekon

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

* RE: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-06-13  8:13           ` Gupta, Pekon
  0 siblings, 0 replies; 181+ messages in thread
From: Gupta, Pekon @ 2014-06-13  8:13 UTC (permalink / raw)
  To: Tony Lindgren, Quadros, Roger
  Cc: dwmw2, computersforpeace, kyungmin.park, ezequiel.garcia, javier,
	Nori, Sekhar, linux-omap, linux-mtd, devicetree, linux-kernel


>From: Tony Lindgren [mailto:tony@atomide.com]
>>* Roger Quadros <rogerq@ti.com> [140613 00:40]:
>>> On 06/13/2014 10:18 AM, Tony Lindgren wrote:
>> >> * Roger Quadros <rogerq@ti.com> [140611 01:58]:
>> >> Since the Interrupt Events are used only by the NAND driver,
>> >> there is no point in managing the Interrupt registers
>> >> in the GPMC driver and complicating it with irqchip modeling.
>> >>
>> >> Let's manage the interrupt registers directly in the NAND driver
>> >> and get rid of irqchip model from GPMC driver.
>> >>
>> >> Get rid of IRQ commands and unused commands from gpmc_configure() in
>> >> the GPMC driver.
>> >
>> > This seems like a step backward to me. The GPMC interrupt enable
>> > register can do edge detection on the wait pins, how is that
>> > limited to NAND?
>>
>> OK. But wait pin edge detection was not yet being used and I couldn't
>> think of how it would ever be used. Any ideas?
>
>Maybe to wake-up the system on bus activity or something?
>
Sorry, I wasn't able to review this series.
But just as pointer, GPMC driver was used for interfacing many
non-memory devices like Ethernet (smc91x) and in past GPMC has been
proved to work with camera devices too, but that's wasn't mainlined.
So keeping IRQ and few other things in GPMC driver is helpful.




>> > Further, let's not start mixing GPMC hardware module register
>> > access with the NAND driver register access. They can be clocked
>> > separately. And bugs in the NAND driver can cause issues in other
>> > GPMC using drivers.
>>
>> I understood that NAND controller is integrated into the GPMC module and they are clocked
>> the same. Not sure why the hardware designers would keep the registers so closely knit.
>
>Yeah. Maybe regmap could provide some abstraction to the the
>NAND registers.
>
As you mentioned, GPMC has two set of registers:
(a) Chip-select registers (CONFIGx_cs) for device specific parameters
 (like device-width, signal-timings, etc) which are statically programmed
during probe or via DT.
(b) ECC registers which are continuously reconfigured based on
 ECC engine.

*Ideal Scenario*
NAND driver should be considered equivalent to protocol driver,
Therefore ideally it should use only those registers which are
specific to NAND (b).

*Actual Scenario*
But most NAND device today are ONFI compliant and they have
almost all device parameters like device-width, signal-timings
burned on-die in an ONFI page. These values are read back from
NAND device during device_probe() and then re-configured back
Chip-select registers (a).
Hence NAND driver needs access of both (a) and (b), which is why
You need to export complete GPMC register set to NAND driver.
However this is not the case and has been discussed earlier too..

http://lists.infradead.org/pipermail/linux-mtd/2013-October/049284.html
http://lists.infradead.org/pipermail/linux-mtd/2013-October/049347.html
(Just pointing out my version of history, would be good to read the
entire discussion. But the summary was that we need to re-configure
some GPMC chip-select registers (a) based on probe done in
NAND driver. So we need all GPMC registers exposed to NAND driver).




>> FYI. memory/ti-amif.c and mtd/nand/davinci_nand.c share the AMIF register space in the
>> same way. I thought it'd be nice to be consistent across TI drivers.
>
>Probably they did not yet learn the problems caused by it :)
>
I havn't reviewed the ti-amif.c driver completely but I think they too
configure device signal timing statically based on DT. But as per
today this is frowned upon because:

(1) Its difficult for layman user to decipher NAND signal timings
from datasheet and then convert it into controller understandable DT

(2) ONFI parameter page on NAND has these timings specified
on-die itself, and these timings are characterized for best performance
so NAND driver should re-configure these timings after probe.
Refer below mail from '<Rob Herring> robherring2@gmail.com'
http://lists.infradead.org/pipermail/linux-mtd/2014-April/053488.html


Considering all these details, please re-review the changes you plan
for GPMC driver.

with regards, pekon

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

* RE: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-06-13  8:13           ` Gupta, Pekon
  0 siblings, 0 replies; 181+ messages in thread
From: Gupta, Pekon @ 2014-06-13  8:13 UTC (permalink / raw)
  To: Tony Lindgren, Quadros, Roger
  Cc: devicetree, linux-omap, Nori, Sekhar, linux-kernel,
	kyungmin.park, linux-mtd, ezequiel.garcia, javier,
	computersforpeace, dwmw2


>From: Tony Lindgren [mailto:tony@atomide.com]
>>* Roger Quadros <rogerq@ti.com> [140613 00:40]:
>>> On 06/13/2014 10:18 AM, Tony Lindgren wrote:
>> >> * Roger Quadros <rogerq@ti.com> [140611 01:58]:
>> >> Since the Interrupt Events are used only by the NAND driver,
>> >> there is no point in managing the Interrupt registers
>> >> in the GPMC driver and complicating it with irqchip modeling.
>> >>
>> >> Let's manage the interrupt registers directly in the NAND driver
>> >> and get rid of irqchip model from GPMC driver.
>> >>
>> >> Get rid of IRQ commands and unused commands from gpmc_configure() in
>> >> the GPMC driver.
>> >
>> > This seems like a step backward to me. The GPMC interrupt enable
>> > register can do edge detection on the wait pins, how is that
>> > limited to NAND?
>>
>> OK. But wait pin edge detection was not yet being used and I couldn't
>> think of how it would ever be used. Any ideas?
>
>Maybe to wake-up the system on bus activity or something?
>
Sorry, I wasn't able to review this series.
But just as pointer, GPMC driver was used for interfacing many
non-memory devices like Ethernet (smc91x) and in past GPMC has been
proved to work with camera devices too, but that's wasn't mainlined.
So keeping IRQ and few other things in GPMC driver is helpful.




>> > Further, let's not start mixing GPMC hardware module register
>> > access with the NAND driver register access. They can be clocked
>> > separately. And bugs in the NAND driver can cause issues in other
>> > GPMC using drivers.
>>
>> I understood that NAND controller is integrated into the GPMC module and they are clocked
>> the same. Not sure why the hardware designers would keep the registers so closely knit.
>
>Yeah. Maybe regmap could provide some abstraction to the the
>NAND registers.
>
As you mentioned, GPMC has two set of registers:
(a) Chip-select registers (CONFIGx_cs) for device specific parameters
 (like device-width, signal-timings, etc) which are statically programmed
during probe or via DT.
(b) ECC registers which are continuously reconfigured based on
 ECC engine.

*Ideal Scenario*
NAND driver should be considered equivalent to protocol driver,
Therefore ideally it should use only those registers which are
specific to NAND (b).

*Actual Scenario*
But most NAND device today are ONFI compliant and they have
almost all device parameters like device-width, signal-timings
burned on-die in an ONFI page. These values are read back from
NAND device during device_probe() and then re-configured back
Chip-select registers (a).
Hence NAND driver needs access of both (a) and (b), which is why
You need to export complete GPMC register set to NAND driver.
However this is not the case and has been discussed earlier too..

http://lists.infradead.org/pipermail/linux-mtd/2013-October/049284.html
http://lists.infradead.org/pipermail/linux-mtd/2013-October/049347.html
(Just pointing out my version of history, would be good to read the
entire discussion. But the summary was that we need to re-configure
some GPMC chip-select registers (a) based on probe done in
NAND driver. So we need all GPMC registers exposed to NAND driver).




>> FYI. memory/ti-amif.c and mtd/nand/davinci_nand.c share the AMIF register space in the
>> same way. I thought it'd be nice to be consistent across TI drivers.
>
>Probably they did not yet learn the problems caused by it :)
>
I havn't reviewed the ti-amif.c driver completely but I think they too
configure device signal timing statically based on DT. But as per
today this is frowned upon because:

(1) Its difficult for layman user to decipher NAND signal timings
from datasheet and then convert it into controller understandable DT

(2) ONFI parameter page on NAND has these timings specified
on-die itself, and these timings are characterized for best performance
so NAND driver should re-configure these timings after probe.
Refer below mail from '<Rob Herring> robherring2@gmail.com'
http://lists.infradead.org/pipermail/linux-mtd/2014-April/053488.html


Considering all these details, please re-review the changes you plan
for GPMC driver.

with regards, pekon

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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
  2014-06-13  8:13           ` Gupta, Pekon
  (?)
@ 2014-06-13  8:23             ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-13  8:23 UTC (permalink / raw)
  To: Gupta, Pekon, Tony Lindgren
  Cc: dwmw2, computersforpeace, kyungmin.park, ezequiel.garcia, javier,
	Nori, Sekhar, linux-omap, linux-mtd, devicetree, linux-kernel

On 06/13/2014 11:13 AM, Gupta, Pekon wrote:
> 
>> From: Tony Lindgren [mailto:tony@atomide.com]
>>> * Roger Quadros <rogerq@ti.com> [140613 00:40]:
>>>> On 06/13/2014 10:18 AM, Tony Lindgren wrote:
>>>>> * Roger Quadros <rogerq@ti.com> [140611 01:58]:
>>>>> Since the Interrupt Events are used only by the NAND driver,
>>>>> there is no point in managing the Interrupt registers
>>>>> in the GPMC driver and complicating it with irqchip modeling.
>>>>>
>>>>> Let's manage the interrupt registers directly in the NAND driver
>>>>> and get rid of irqchip model from GPMC driver.
>>>>>
>>>>> Get rid of IRQ commands and unused commands from gpmc_configure() in
>>>>> the GPMC driver.
>>>>
>>>> This seems like a step backward to me. The GPMC interrupt enable
>>>> register can do edge detection on the wait pins, how is that
>>>> limited to NAND?
>>>
>>> OK. But wait pin edge detection was not yet being used and I couldn't
>>> think of how it would ever be used. Any ideas?
>>
>> Maybe to wake-up the system on bus activity or something?
>>
> Sorry, I wasn't able to review this series.
> But just as pointer, GPMC driver was used for interfacing many
> non-memory devices like Ethernet (smc91x) and in past GPMC has been
> proved to work with camera devices too, but that's wasn't mainlined.
> So keeping IRQ and few other things in GPMC driver is helpful.
> 

On further study it seems that the wait pin edge detection is only used in the NAND controller use case.
see section 10.1.5.14.2.2 Ready Pin Monitored by Hardware Interrupt

For memory devices, no software wait pin intervention is necessary and doesn't even make sense.

So I don't agree on managing the IRQSTATUS and IRQENABLE register in the GPMC driver. It is adding unnecessary complexity. I don't mind having a wrapper around it though like the other nand registers.

To be frank, I think it is cleaner if the NAND driver directly accesses the NAND registers.
I don't see why we should make things complicated just because the hardware designers didn't create a clear register split between GPMC and NAND.

Only the GPMC_CONFIG register needs to remain with the GPMC driver.

cheers,
-roger

> 
> 
> 
>>>> Further, let's not start mixing GPMC hardware module register
>>>> access with the NAND driver register access. They can be clocked
>>>> separately. And bugs in the NAND driver can cause issues in other
>>>> GPMC using drivers.
>>>
>>> I understood that NAND controller is integrated into the GPMC module and they are clocked
>>> the same. Not sure why the hardware designers would keep the registers so closely knit.
>>
>> Yeah. Maybe regmap could provide some abstraction to the the
>> NAND registers.
>>
> As you mentioned, GPMC has two set of registers:
> (a) Chip-select registers (CONFIGx_cs) for device specific parameters
>  (like device-width, signal-timings, etc) which are statically programmed
> during probe or via DT.
> (b) ECC registers which are continuously reconfigured based on
>  ECC engine.
> 
> *Ideal Scenario*
> NAND driver should be considered equivalent to protocol driver,
> Therefore ideally it should use only those registers which are
> specific to NAND (b).
> 
> *Actual Scenario*
> But most NAND device today are ONFI compliant and they have
> almost all device parameters like device-width, signal-timings
> burned on-die in an ONFI page. These values are read back from
> NAND device during device_probe() and then re-configured back
> Chip-select registers (a).
> Hence NAND driver needs access of both (a) and (b), which is why
> You need to export complete GPMC register set to NAND driver.
> However this is not the case and has been discussed earlier too..
> 
> http://lists.infradead.org/pipermail/linux-mtd/2013-October/049284.html
> http://lists.infradead.org/pipermail/linux-mtd/2013-October/049347.html
> (Just pointing out my version of history, would be good to read the
> entire discussion. But the summary was that we need to re-configure
> some GPMC chip-select registers (a) based on probe done in
> NAND driver. So we need all GPMC registers exposed to NAND driver).
> 
> 
> 
> 
>>> FYI. memory/ti-amif.c and mtd/nand/davinci_nand.c share the AMIF register space in the
>>> same way. I thought it'd be nice to be consistent across TI drivers.
>>
>> Probably they did not yet learn the problems caused by it :)
>>
> I havn't reviewed the ti-amif.c driver completely but I think they too
> configure device signal timing statically based on DT. But as per
> today this is frowned upon because:
> 
> (1) Its difficult for layman user to decipher NAND signal timings
> from datasheet and then convert it into controller understandable DT
> 
> (2) ONFI parameter page on NAND has these timings specified
> on-die itself, and these timings are characterized for best performance
> so NAND driver should re-configure these timings after probe.
> Refer below mail from '<Rob Herring> robherring2@gmail.com'
> http://lists.infradead.org/pipermail/linux-mtd/2014-April/053488.html
> 
> 
> Considering all these details, please re-review the changes you plan
> for GPMC driver.
> 
> with regards, pekon
> 


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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-06-13  8:23             ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-13  8:23 UTC (permalink / raw)
  To: Gupta, Pekon, Tony Lindgren
  Cc: dwmw2, computersforpeace, kyungmin.park, ezequiel.garcia, javier,
	Nori, Sekhar, linux-omap, linux-mtd, devicetree, linux-kernel

On 06/13/2014 11:13 AM, Gupta, Pekon wrote:
> 
>> From: Tony Lindgren [mailto:tony@atomide.com]
>>> * Roger Quadros <rogerq@ti.com> [140613 00:40]:
>>>> On 06/13/2014 10:18 AM, Tony Lindgren wrote:
>>>>> * Roger Quadros <rogerq@ti.com> [140611 01:58]:
>>>>> Since the Interrupt Events are used only by the NAND driver,
>>>>> there is no point in managing the Interrupt registers
>>>>> in the GPMC driver and complicating it with irqchip modeling.
>>>>>
>>>>> Let's manage the interrupt registers directly in the NAND driver
>>>>> and get rid of irqchip model from GPMC driver.
>>>>>
>>>>> Get rid of IRQ commands and unused commands from gpmc_configure() in
>>>>> the GPMC driver.
>>>>
>>>> This seems like a step backward to me. The GPMC interrupt enable
>>>> register can do edge detection on the wait pins, how is that
>>>> limited to NAND?
>>>
>>> OK. But wait pin edge detection was not yet being used and I couldn't
>>> think of how it would ever be used. Any ideas?
>>
>> Maybe to wake-up the system on bus activity or something?
>>
> Sorry, I wasn't able to review this series.
> But just as pointer, GPMC driver was used for interfacing many
> non-memory devices like Ethernet (smc91x) and in past GPMC has been
> proved to work with camera devices too, but that's wasn't mainlined.
> So keeping IRQ and few other things in GPMC driver is helpful.
> 

On further study it seems that the wait pin edge detection is only used in the NAND controller use case.
see section 10.1.5.14.2.2 Ready Pin Monitored by Hardware Interrupt

For memory devices, no software wait pin intervention is necessary and doesn't even make sense.

So I don't agree on managing the IRQSTATUS and IRQENABLE register in the GPMC driver. It is adding unnecessary complexity. I don't mind having a wrapper around it though like the other nand registers.

To be frank, I think it is cleaner if the NAND driver directly accesses the NAND registers.
I don't see why we should make things complicated just because the hardware designers didn't create a clear register split between GPMC and NAND.

Only the GPMC_CONFIG register needs to remain with the GPMC driver.

cheers,
-roger

> 
> 
> 
>>>> Further, let's not start mixing GPMC hardware module register
>>>> access with the NAND driver register access. They can be clocked
>>>> separately. And bugs in the NAND driver can cause issues in other
>>>> GPMC using drivers.
>>>
>>> I understood that NAND controller is integrated into the GPMC module and they are clocked
>>> the same. Not sure why the hardware designers would keep the registers so closely knit.
>>
>> Yeah. Maybe regmap could provide some abstraction to the the
>> NAND registers.
>>
> As you mentioned, GPMC has two set of registers:
> (a) Chip-select registers (CONFIGx_cs) for device specific parameters
>  (like device-width, signal-timings, etc) which are statically programmed
> during probe or via DT.
> (b) ECC registers which are continuously reconfigured based on
>  ECC engine.
> 
> *Ideal Scenario*
> NAND driver should be considered equivalent to protocol driver,
> Therefore ideally it should use only those registers which are
> specific to NAND (b).
> 
> *Actual Scenario*
> But most NAND device today are ONFI compliant and they have
> almost all device parameters like device-width, signal-timings
> burned on-die in an ONFI page. These values are read back from
> NAND device during device_probe() and then re-configured back
> Chip-select registers (a).
> Hence NAND driver needs access of both (a) and (b), which is why
> You need to export complete GPMC register set to NAND driver.
> However this is not the case and has been discussed earlier too..
> 
> http://lists.infradead.org/pipermail/linux-mtd/2013-October/049284.html
> http://lists.infradead.org/pipermail/linux-mtd/2013-October/049347.html
> (Just pointing out my version of history, would be good to read the
> entire discussion. But the summary was that we need to re-configure
> some GPMC chip-select registers (a) based on probe done in
> NAND driver. So we need all GPMC registers exposed to NAND driver).
> 
> 
> 
> 
>>> FYI. memory/ti-amif.c and mtd/nand/davinci_nand.c share the AMIF register space in the
>>> same way. I thought it'd be nice to be consistent across TI drivers.
>>
>> Probably they did not yet learn the problems caused by it :)
>>
> I havn't reviewed the ti-amif.c driver completely but I think they too
> configure device signal timing statically based on DT. But as per
> today this is frowned upon because:
> 
> (1) Its difficult for layman user to decipher NAND signal timings
> from datasheet and then convert it into controller understandable DT
> 
> (2) ONFI parameter page on NAND has these timings specified
> on-die itself, and these timings are characterized for best performance
> so NAND driver should re-configure these timings after probe.
> Refer below mail from '<Rob Herring> robherring2@gmail.com'
> http://lists.infradead.org/pipermail/linux-mtd/2014-April/053488.html
> 
> 
> Considering all these details, please re-review the changes you plan
> for GPMC driver.
> 
> with regards, pekon
> 

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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-06-13  8:23             ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-13  8:23 UTC (permalink / raw)
  To: Gupta, Pekon, Tony Lindgren
  Cc: devicetree, linux-omap, Nori, Sekhar, linux-kernel,
	kyungmin.park, linux-mtd, ezequiel.garcia, javier,
	computersforpeace, dwmw2

On 06/13/2014 11:13 AM, Gupta, Pekon wrote:
> 
>> From: Tony Lindgren [mailto:tony@atomide.com]
>>> * Roger Quadros <rogerq@ti.com> [140613 00:40]:
>>>> On 06/13/2014 10:18 AM, Tony Lindgren wrote:
>>>>> * Roger Quadros <rogerq@ti.com> [140611 01:58]:
>>>>> Since the Interrupt Events are used only by the NAND driver,
>>>>> there is no point in managing the Interrupt registers
>>>>> in the GPMC driver and complicating it with irqchip modeling.
>>>>>
>>>>> Let's manage the interrupt registers directly in the NAND driver
>>>>> and get rid of irqchip model from GPMC driver.
>>>>>
>>>>> Get rid of IRQ commands and unused commands from gpmc_configure() in
>>>>> the GPMC driver.
>>>>
>>>> This seems like a step backward to me. The GPMC interrupt enable
>>>> register can do edge detection on the wait pins, how is that
>>>> limited to NAND?
>>>
>>> OK. But wait pin edge detection was not yet being used and I couldn't
>>> think of how it would ever be used. Any ideas?
>>
>> Maybe to wake-up the system on bus activity or something?
>>
> Sorry, I wasn't able to review this series.
> But just as pointer, GPMC driver was used for interfacing many
> non-memory devices like Ethernet (smc91x) and in past GPMC has been
> proved to work with camera devices too, but that's wasn't mainlined.
> So keeping IRQ and few other things in GPMC driver is helpful.
> 

On further study it seems that the wait pin edge detection is only used in the NAND controller use case.
see section 10.1.5.14.2.2 Ready Pin Monitored by Hardware Interrupt

For memory devices, no software wait pin intervention is necessary and doesn't even make sense.

So I don't agree on managing the IRQSTATUS and IRQENABLE register in the GPMC driver. It is adding unnecessary complexity. I don't mind having a wrapper around it though like the other nand registers.

To be frank, I think it is cleaner if the NAND driver directly accesses the NAND registers.
I don't see why we should make things complicated just because the hardware designers didn't create a clear register split between GPMC and NAND.

Only the GPMC_CONFIG register needs to remain with the GPMC driver.

cheers,
-roger

> 
> 
> 
>>>> Further, let's not start mixing GPMC hardware module register
>>>> access with the NAND driver register access. They can be clocked
>>>> separately. And bugs in the NAND driver can cause issues in other
>>>> GPMC using drivers.
>>>
>>> I understood that NAND controller is integrated into the GPMC module and they are clocked
>>> the same. Not sure why the hardware designers would keep the registers so closely knit.
>>
>> Yeah. Maybe regmap could provide some abstraction to the the
>> NAND registers.
>>
> As you mentioned, GPMC has two set of registers:
> (a) Chip-select registers (CONFIGx_cs) for device specific parameters
>  (like device-width, signal-timings, etc) which are statically programmed
> during probe or via DT.
> (b) ECC registers which are continuously reconfigured based on
>  ECC engine.
> 
> *Ideal Scenario*
> NAND driver should be considered equivalent to protocol driver,
> Therefore ideally it should use only those registers which are
> specific to NAND (b).
> 
> *Actual Scenario*
> But most NAND device today are ONFI compliant and they have
> almost all device parameters like device-width, signal-timings
> burned on-die in an ONFI page. These values are read back from
> NAND device during device_probe() and then re-configured back
> Chip-select registers (a).
> Hence NAND driver needs access of both (a) and (b), which is why
> You need to export complete GPMC register set to NAND driver.
> However this is not the case and has been discussed earlier too..
> 
> http://lists.infradead.org/pipermail/linux-mtd/2013-October/049284.html
> http://lists.infradead.org/pipermail/linux-mtd/2013-October/049347.html
> (Just pointing out my version of history, would be good to read the
> entire discussion. But the summary was that we need to re-configure
> some GPMC chip-select registers (a) based on probe done in
> NAND driver. So we need all GPMC registers exposed to NAND driver).
> 
> 
> 
> 
>>> FYI. memory/ti-amif.c and mtd/nand/davinci_nand.c share the AMIF register space in the
>>> same way. I thought it'd be nice to be consistent across TI drivers.
>>
>> Probably they did not yet learn the problems caused by it :)
>>
> I havn't reviewed the ti-amif.c driver completely but I think they too
> configure device signal timing statically based on DT. But as per
> today this is frowned upon because:
> 
> (1) Its difficult for layman user to decipher NAND signal timings
> from datasheet and then convert it into controller understandable DT
> 
> (2) ONFI parameter page on NAND has these timings specified
> on-die itself, and these timings are characterized for best performance
> so NAND driver should re-configure these timings after probe.
> Refer below mail from '<Rob Herring> robherring2@gmail.com'
> http://lists.infradead.org/pipermail/linux-mtd/2014-April/053488.html
> 
> 
> Considering all these details, please re-review the changes you plan
> for GPMC driver.
> 
> with regards, pekon
> 

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

* Re: [PATCH 18/36] ARM: OMAP2+: gpmc-onenand: Move Synchronous setting code to drivers/
@ 2014-06-13  8:30       ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-13  8:30 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: dwmw2, computersforpeace, kyungmin.park, pekon, ezequiel.garcia,
	javier, nsekhar, linux-omap, linux-mtd, devicetree, linux-kernel

On 06/13/2014 10:55 AM, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [140611 01:59]:
>> Move the code that puts the onenand in synchronous mode
>> into the appropriate place i.e. drivers/mtd/onenand/omap2.c.
>>
>> Make use of omap_gpmc_get_clk_period() and omap_gpmc_retime()
>> to calculate the necessary timings and configure the GPMC
>> parent's timings.
> 
> Ideally we would just use the drivers/mtd/onenand/generic.c
> and get rid of drivers/mtd/onenand/omap2.c. We still need
> the bus glue, which should probably be in drivers/memory?
> 

But what about the runtime synchronous timing calculations onenand/omap2.c?
There is also OMAP2 and OMAP3 specific dma handling done there, which should probably be done generically using dmaengine.

cheers,
-roger



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

* Re: [PATCH 18/36] ARM: OMAP2+: gpmc-onenand: Move Synchronous setting code to drivers/
@ 2014-06-13  8:30       ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-13  8:30 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: dwmw2-wEGCiKHe2LqWVfeAwA7xHQ,
	computersforpeace-Re5JQEeQqe8AvxtiuMwx3w,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ, pekon-l0cyMroinI0,
	ezequiel.garcia-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	javier-0uQlZySMnqxg9hUCZPvPmw, nsekhar-l0cyMroinI0,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

On 06/13/2014 10:55 AM, Tony Lindgren wrote:
> * Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> [140611 01:59]:
>> Move the code that puts the onenand in synchronous mode
>> into the appropriate place i.e. drivers/mtd/onenand/omap2.c.
>>
>> Make use of omap_gpmc_get_clk_period() and omap_gpmc_retime()
>> to calculate the necessary timings and configure the GPMC
>> parent's timings.
> 
> Ideally we would just use the drivers/mtd/onenand/generic.c
> and get rid of drivers/mtd/onenand/omap2.c. We still need
> the bus glue, which should probably be in drivers/memory?
> 

But what about the runtime synchronous timing calculations onenand/omap2.c?
There is also OMAP2 and OMAP3 specific dma handling done there, which should probably be done generically using dmaengine.

cheers,
-roger


--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 18/36] ARM: OMAP2+: gpmc-onenand: Move Synchronous setting code to drivers/
@ 2014-06-13  8:30       ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-13  8:30 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: devicetree, linux-omap, nsekhar, linux-kernel, kyungmin.park,
	linux-mtd, pekon, ezequiel.garcia, javier, computersforpeace,
	dwmw2

On 06/13/2014 10:55 AM, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [140611 01:59]:
>> Move the code that puts the onenand in synchronous mode
>> into the appropriate place i.e. drivers/mtd/onenand/omap2.c.
>>
>> Make use of omap_gpmc_get_clk_period() and omap_gpmc_retime()
>> to calculate the necessary timings and configure the GPMC
>> parent's timings.
> 
> Ideally we would just use the drivers/mtd/onenand/generic.c
> and get rid of drivers/mtd/onenand/omap2.c. We still need
> the bus glue, which should probably be in drivers/memory?
> 

But what about the runtime synchronous timing calculations onenand/omap2.c?
There is also OMAP2 and OMAP3 specific dma handling done there, which should probably be done generically using dmaengine.

cheers,
-roger

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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
  2014-06-13  8:23             ` Roger Quadros
  (?)
@ 2014-06-13 10:46               ` Tony Lindgren
  -1 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13 10:46 UTC (permalink / raw)
  To: Roger Quadros
  Cc: Gupta, Pekon, dwmw2, computersforpeace, kyungmin.park,
	ezequiel.garcia, javier, Nori, Sekhar, linux-omap, linux-mtd,
	devicetree, linux-kernel

* Roger Quadros <rogerq@ti.com> [140613 01:24]:
> On 06/13/2014 11:13 AM, Gupta, Pekon wrote:
> >> From: Tony Lindgren [mailto:tony@atomide.com]
> >>> * Roger Quadros <rogerq@ti.com> [140613 00:40]:
> >>>> On 06/13/2014 10:18 AM, Tony Lindgren wrote:
> >>>>> * Roger Quadros <rogerq@ti.com> [140611 01:58]:
> >>>
> >>> OK. But wait pin edge detection was not yet being used and I couldn't
> >>> think of how it would ever be used. Any ideas?
> >>
> >> Maybe to wake-up the system on bus activity or something?
> >>
> > Sorry, I wasn't able to review this series.
> > But just as pointer, GPMC driver was used for interfacing many
> > non-memory devices like Ethernet (smc91x) and in past GPMC has been
> > proved to work with camera devices too, but that's wasn't mainlined.
> > So keeping IRQ and few other things in GPMC driver is helpful.
> > 
> 
> On further study it seems that the wait pin edge detection is only used in the NAND controller use case.
> see section 10.1.5.14.2.2 Ready Pin Monitored by Hardware Interrupt

It seems they can be used for anything slow like NOR and NAND.
 
> For memory devices, no software wait pin intervention is necessary and doesn't even make sense.

Still seems that it's use can be generic though, not limited
to NAND.
 
> So I don't agree on managing the IRQSTATUS and IRQENABLE register in the GPMC driver. It is adding unnecessary complexity. I don't mind having a wrapper around it though like the other nand registers.

But all the consumer driver should need to do is request_irq()
on it? That's pretty much the most common interface we have
for drivers :)
 
> To be frank, I think it is cleaner if the NAND driver directly accesses the NAND registers.
> I don't see why we should make things complicated just because the hardware designers didn't create a clear register split between GPMC and NAND.

Because they are in separate hardware modules :)

Who knows why it was set up this way. Maybe the plan was to have
the common features in GPMC that then can be used by various MTD
devices.
 
> Only the GPMC_CONFIG register needs to remain with the GPMC driver.

And managing clocks and runtime PM in general. In any case, let's
not let drivers tinker with the GPMC registers directly though.
Some kind of abstraction via existing frameworks or with regmap
is needed.

Regards,

Tony

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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-06-13 10:46               ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13 10:46 UTC (permalink / raw)
  To: Roger Quadros
  Cc: Gupta, Pekon, dwmw2, computersforpeace, kyungmin.park,
	ezequiel.garcia, javier, Nori, Sekhar, linux-omap, linux-mtd,
	devicetree, linux-kernel

* Roger Quadros <rogerq@ti.com> [140613 01:24]:
> On 06/13/2014 11:13 AM, Gupta, Pekon wrote:
> >> From: Tony Lindgren [mailto:tony@atomide.com]
> >>> * Roger Quadros <rogerq@ti.com> [140613 00:40]:
> >>>> On 06/13/2014 10:18 AM, Tony Lindgren wrote:
> >>>>> * Roger Quadros <rogerq@ti.com> [140611 01:58]:
> >>>
> >>> OK. But wait pin edge detection was not yet being used and I couldn't
> >>> think of how it would ever be used. Any ideas?
> >>
> >> Maybe to wake-up the system on bus activity or something?
> >>
> > Sorry, I wasn't able to review this series.
> > But just as pointer, GPMC driver was used for interfacing many
> > non-memory devices like Ethernet (smc91x) and in past GPMC has been
> > proved to work with camera devices too, but that's wasn't mainlined.
> > So keeping IRQ and few other things in GPMC driver is helpful.
> > 
> 
> On further study it seems that the wait pin edge detection is only used in the NAND controller use case.
> see section 10.1.5.14.2.2 Ready Pin Monitored by Hardware Interrupt

It seems they can be used for anything slow like NOR and NAND.
 
> For memory devices, no software wait pin intervention is necessary and doesn't even make sense.

Still seems that it's use can be generic though, not limited
to NAND.
 
> So I don't agree on managing the IRQSTATUS and IRQENABLE register in the GPMC driver. It is adding unnecessary complexity. I don't mind having a wrapper around it though like the other nand registers.

But all the consumer driver should need to do is request_irq()
on it? That's pretty much the most common interface we have
for drivers :)
 
> To be frank, I think it is cleaner if the NAND driver directly accesses the NAND registers.
> I don't see why we should make things complicated just because the hardware designers didn't create a clear register split between GPMC and NAND.

Because they are in separate hardware modules :)

Who knows why it was set up this way. Maybe the plan was to have
the common features in GPMC that then can be used by various MTD
devices.
 
> Only the GPMC_CONFIG register needs to remain with the GPMC driver.

And managing clocks and runtime PM in general. In any case, let's
not let drivers tinker with the GPMC registers directly though.
Some kind of abstraction via existing frameworks or with regmap
is needed.

Regards,

Tony

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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-06-13 10:46               ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13 10:46 UTC (permalink / raw)
  To: Roger Quadros
  Cc: devicetree, linux-omap, Nori, Sekhar, linux-kernel,
	kyungmin.park, linux-mtd, Gupta, Pekon, ezequiel.garcia, javier,
	computersforpeace, dwmw2

* Roger Quadros <rogerq@ti.com> [140613 01:24]:
> On 06/13/2014 11:13 AM, Gupta, Pekon wrote:
> >> From: Tony Lindgren [mailto:tony@atomide.com]
> >>> * Roger Quadros <rogerq@ti.com> [140613 00:40]:
> >>>> On 06/13/2014 10:18 AM, Tony Lindgren wrote:
> >>>>> * Roger Quadros <rogerq@ti.com> [140611 01:58]:
> >>>
> >>> OK. But wait pin edge detection was not yet being used and I couldn't
> >>> think of how it would ever be used. Any ideas?
> >>
> >> Maybe to wake-up the system on bus activity or something?
> >>
> > Sorry, I wasn't able to review this series.
> > But just as pointer, GPMC driver was used for interfacing many
> > non-memory devices like Ethernet (smc91x) and in past GPMC has been
> > proved to work with camera devices too, but that's wasn't mainlined.
> > So keeping IRQ and few other things in GPMC driver is helpful.
> > 
> 
> On further study it seems that the wait pin edge detection is only used in the NAND controller use case.
> see section 10.1.5.14.2.2 Ready Pin Monitored by Hardware Interrupt

It seems they can be used for anything slow like NOR and NAND.
 
> For memory devices, no software wait pin intervention is necessary and doesn't even make sense.

Still seems that it's use can be generic though, not limited
to NAND.
 
> So I don't agree on managing the IRQSTATUS and IRQENABLE register in the GPMC driver. It is adding unnecessary complexity. I don't mind having a wrapper around it though like the other nand registers.

But all the consumer driver should need to do is request_irq()
on it? That's pretty much the most common interface we have
for drivers :)
 
> To be frank, I think it is cleaner if the NAND driver directly accesses the NAND registers.
> I don't see why we should make things complicated just because the hardware designers didn't create a clear register split between GPMC and NAND.

Because they are in separate hardware modules :)

Who knows why it was set up this way. Maybe the plan was to have
the common features in GPMC that then can be used by various MTD
devices.
 
> Only the GPMC_CONFIG register needs to remain with the GPMC driver.

And managing clocks and runtime PM in general. In any case, let's
not let drivers tinker with the GPMC registers directly though.
Some kind of abstraction via existing frameworks or with regmap
is needed.

Regards,

Tony

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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-06-13 11:42                 ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-13 11:42 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: Gupta, Pekon, dwmw2, computersforpeace, kyungmin.park,
	ezequiel.garcia, javier, Nori, Sekhar, linux-omap, linux-mtd,
	devicetree, linux-kernel

On 06/13/2014 01:46 PM, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [140613 01:24]:
>> On 06/13/2014 11:13 AM, Gupta, Pekon wrote:
>>>> From: Tony Lindgren [mailto:tony@atomide.com]
>>>>> * Roger Quadros <rogerq@ti.com> [140613 00:40]:
>>>>>> On 06/13/2014 10:18 AM, Tony Lindgren wrote:
>>>>>>> * Roger Quadros <rogerq@ti.com> [140611 01:58]:
>>>>>
>>>>> OK. But wait pin edge detection was not yet being used and I couldn't
>>>>> think of how it would ever be used. Any ideas?
>>>>
>>>> Maybe to wake-up the system on bus activity or something?
>>>>
>>> Sorry, I wasn't able to review this series.
>>> But just as pointer, GPMC driver was used for interfacing many
>>> non-memory devices like Ethernet (smc91x) and in past GPMC has been
>>> proved to work with camera devices too, but that's wasn't mainlined.
>>> So keeping IRQ and few other things in GPMC driver is helpful.
>>>
>>
>> On further study it seems that the wait pin edge detection is only used in the NAND controller use case.
>> see section 10.1.5.14.2.2 Ready Pin Monitored by Hardware Interrupt
> 
> It seems they can be used for anything slow like NOR and NAND.

But NOR driver never requests for any IRQ.

We should not confuse this wait pin edge interrupt with NOR bus cycle WAIT pin mechanism.
That is configured using GPMC_CONFIG1 register via WAITPINSELECT and WAITREAD/WRITEMONITORING bits.
That wait pin handling is done completely in hardware and doesn't need any software intervention.
Imagine using it for interrupt for every bus cycle wait. It will be dead slow and unusable.

The WAIT edge interrupt mechanism is exclusively for NAND use case to notify the status of READY pin after a block/page operation.

>  
>> For memory devices, no software wait pin intervention is necessary and doesn't even make sense.
> 
> Still seems that it's use can be generic though, not limited
> to NAND.
>  
>> So I don't agree on managing the IRQSTATUS and IRQENABLE register in the GPMC driver. It is adding unnecessary complexity. I don't mind having a wrapper around it though like the other nand registers.
> 
> But all the consumer driver should need to do is request_irq()
> on it? That's pretty much the most common interface we have
> for drivers :)

the client driver side is easy, but it adds unnecessary complication to model it as IRQ chip and assign a line for each event. Since it is going to be used exclusively by NAND we should avoid IRQ chip modeling.

>  
>> To be frank, I think it is cleaner if the NAND driver directly accesses the NAND registers.
>> I don't see why we should make things complicated just because the hardware designers didn't create a clear register split between GPMC and NAND.
> 
> Because they are in separate hardware modules :)
> 
> Who knows why it was set up this way. Maybe the plan was to have
> the common features in GPMC that then can be used by various MTD
> devices.
>  
>> Only the GPMC_CONFIG register needs to remain with the GPMC driver.
> 
> And managing clocks and runtime PM in general. In any case, let's
> not let drivers tinker with the GPMC registers directly though.
> Some kind of abstraction via existing frameworks or with regmap
> is needed.

OK. I agree about using some kind of abstraction instead of direct access.

cheers,
-roger

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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-06-13 11:42                 ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-13 11:42 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: Gupta, Pekon, dwmw2-wEGCiKHe2LqWVfeAwA7xHQ,
	computersforpeace-Re5JQEeQqe8AvxtiuMwx3w,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ,
	ezequiel.garcia-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	javier-0uQlZySMnqxg9hUCZPvPmw, Nori, Sekhar,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

On 06/13/2014 01:46 PM, Tony Lindgren wrote:
> * Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> [140613 01:24]:
>> On 06/13/2014 11:13 AM, Gupta, Pekon wrote:
>>>> From: Tony Lindgren [mailto:tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org]
>>>>> * Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> [140613 00:40]:
>>>>>> On 06/13/2014 10:18 AM, Tony Lindgren wrote:
>>>>>>> * Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> [140611 01:58]:
>>>>>
>>>>> OK. But wait pin edge detection was not yet being used and I couldn't
>>>>> think of how it would ever be used. Any ideas?
>>>>
>>>> Maybe to wake-up the system on bus activity or something?
>>>>
>>> Sorry, I wasn't able to review this series.
>>> But just as pointer, GPMC driver was used for interfacing many
>>> non-memory devices like Ethernet (smc91x) and in past GPMC has been
>>> proved to work with camera devices too, but that's wasn't mainlined.
>>> So keeping IRQ and few other things in GPMC driver is helpful.
>>>
>>
>> On further study it seems that the wait pin edge detection is only used in the NAND controller use case.
>> see section 10.1.5.14.2.2 Ready Pin Monitored by Hardware Interrupt
> 
> It seems they can be used for anything slow like NOR and NAND.

But NOR driver never requests for any IRQ.

We should not confuse this wait pin edge interrupt with NOR bus cycle WAIT pin mechanism.
That is configured using GPMC_CONFIG1 register via WAITPINSELECT and WAITREAD/WRITEMONITORING bits.
That wait pin handling is done completely in hardware and doesn't need any software intervention.
Imagine using it for interrupt for every bus cycle wait. It will be dead slow and unusable.

The WAIT edge interrupt mechanism is exclusively for NAND use case to notify the status of READY pin after a block/page operation.

>  
>> For memory devices, no software wait pin intervention is necessary and doesn't even make sense.
> 
> Still seems that it's use can be generic though, not limited
> to NAND.
>  
>> So I don't agree on managing the IRQSTATUS and IRQENABLE register in the GPMC driver. It is adding unnecessary complexity. I don't mind having a wrapper around it though like the other nand registers.
> 
> But all the consumer driver should need to do is request_irq()
> on it? That's pretty much the most common interface we have
> for drivers :)

the client driver side is easy, but it adds unnecessary complication to model it as IRQ chip and assign a line for each event. Since it is going to be used exclusively by NAND we should avoid IRQ chip modeling.

>  
>> To be frank, I think it is cleaner if the NAND driver directly accesses the NAND registers.
>> I don't see why we should make things complicated just because the hardware designers didn't create a clear register split between GPMC and NAND.
> 
> Because they are in separate hardware modules :)
> 
> Who knows why it was set up this way. Maybe the plan was to have
> the common features in GPMC that then can be used by various MTD
> devices.
>  
>> Only the GPMC_CONFIG register needs to remain with the GPMC driver.
> 
> And managing clocks and runtime PM in general. In any case, let's
> not let drivers tinker with the GPMC registers directly though.
> Some kind of abstraction via existing frameworks or with regmap
> is needed.

OK. I agree about using some kind of abstraction instead of direct access.

cheers,
-roger
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-06-13 11:42                 ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-06-13 11:42 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: devicetree, linux-omap, Nori, Sekhar, linux-kernel,
	kyungmin.park, linux-mtd, Gupta, Pekon, ezequiel.garcia, javier,
	computersforpeace, dwmw2

On 06/13/2014 01:46 PM, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [140613 01:24]:
>> On 06/13/2014 11:13 AM, Gupta, Pekon wrote:
>>>> From: Tony Lindgren [mailto:tony@atomide.com]
>>>>> * Roger Quadros <rogerq@ti.com> [140613 00:40]:
>>>>>> On 06/13/2014 10:18 AM, Tony Lindgren wrote:
>>>>>>> * Roger Quadros <rogerq@ti.com> [140611 01:58]:
>>>>>
>>>>> OK. But wait pin edge detection was not yet being used and I couldn't
>>>>> think of how it would ever be used. Any ideas?
>>>>
>>>> Maybe to wake-up the system on bus activity or something?
>>>>
>>> Sorry, I wasn't able to review this series.
>>> But just as pointer, GPMC driver was used for interfacing many
>>> non-memory devices like Ethernet (smc91x) and in past GPMC has been
>>> proved to work with camera devices too, but that's wasn't mainlined.
>>> So keeping IRQ and few other things in GPMC driver is helpful.
>>>
>>
>> On further study it seems that the wait pin edge detection is only used in the NAND controller use case.
>> see section 10.1.5.14.2.2 Ready Pin Monitored by Hardware Interrupt
> 
> It seems they can be used for anything slow like NOR and NAND.

But NOR driver never requests for any IRQ.

We should not confuse this wait pin edge interrupt with NOR bus cycle WAIT pin mechanism.
That is configured using GPMC_CONFIG1 register via WAITPINSELECT and WAITREAD/WRITEMONITORING bits.
That wait pin handling is done completely in hardware and doesn't need any software intervention.
Imagine using it for interrupt for every bus cycle wait. It will be dead slow and unusable.

The WAIT edge interrupt mechanism is exclusively for NAND use case to notify the status of READY pin after a block/page operation.

>  
>> For memory devices, no software wait pin intervention is necessary and doesn't even make sense.
> 
> Still seems that it's use can be generic though, not limited
> to NAND.
>  
>> So I don't agree on managing the IRQSTATUS and IRQENABLE register in the GPMC driver. It is adding unnecessary complexity. I don't mind having a wrapper around it though like the other nand registers.
> 
> But all the consumer driver should need to do is request_irq()
> on it? That's pretty much the most common interface we have
> for drivers :)

the client driver side is easy, but it adds unnecessary complication to model it as IRQ chip and assign a line for each event. Since it is going to be used exclusively by NAND we should avoid IRQ chip modeling.

>  
>> To be frank, I think it is cleaner if the NAND driver directly accesses the NAND registers.
>> I don't see why we should make things complicated just because the hardware designers didn't create a clear register split between GPMC and NAND.
> 
> Because they are in separate hardware modules :)
> 
> Who knows why it was set up this way. Maybe the plan was to have
> the common features in GPMC that then can be used by various MTD
> devices.
>  
>> Only the GPMC_CONFIG register needs to remain with the GPMC driver.
> 
> And managing clocks and runtime PM in general. In any case, let's
> not let drivers tinker with the GPMC registers directly though.
> Some kind of abstraction via existing frameworks or with regmap
> is needed.

OK. I agree about using some kind of abstraction instead of direct access.

cheers,
-roger

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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-06-13 12:08                   ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13 12:08 UTC (permalink / raw)
  To: Roger Quadros
  Cc: Gupta, Pekon, dwmw2, computersforpeace, kyungmin.park,
	ezequiel.garcia, javier, Nori, Sekhar, linux-omap, linux-mtd,
	devicetree, linux-kernel

* Roger Quadros <rogerq@ti.com> [140613 04:43]:
> On 06/13/2014 01:46 PM, Tony Lindgren wrote:
> > * Roger Quadros <rogerq@ti.com> [140613 01:24]:
> >> On 06/13/2014 11:13 AM, Gupta, Pekon wrote:
> >>>> From: Tony Lindgren [mailto:tony@atomide.com]
> >>>>> * Roger Quadros <rogerq@ti.com> [140613 00:40]:
> >>>>>> On 06/13/2014 10:18 AM, Tony Lindgren wrote:
> >>>>>>> * Roger Quadros <rogerq@ti.com> [140611 01:58]:
> >>>>>
> >>>>> OK. But wait pin edge detection was not yet being used and I couldn't
> >>>>> think of how it would ever be used. Any ideas?
> >>>>
> >>>> Maybe to wake-up the system on bus activity or something?
> >>>>
> >>> Sorry, I wasn't able to review this series.
> >>> But just as pointer, GPMC driver was used for interfacing many
> >>> non-memory devices like Ethernet (smc91x) and in past GPMC has been
> >>> proved to work with camera devices too, but that's wasn't mainlined.
> >>> So keeping IRQ and few other things in GPMC driver is helpful.
> >>>
> >>
> >> On further study it seems that the wait pin edge detection is only used in the NAND controller use case.
> >> see section 10.1.5.14.2.2 Ready Pin Monitored by Hardware Interrupt
> > 
> > It seems they can be used for anything slow like NOR and NAND.
> 
> But NOR driver never requests for any IRQ.
> 
> We should not confuse this wait pin edge interrupt with NOR bus cycle WAIT pin mechanism.
> That is configured using GPMC_CONFIG1 register via WAITPINSELECT and WAITREAD/WRITEMONITORING bits.
> That wait pin handling is done completely in hardware and doesn't need any software intervention.
> Imagine using it for interrupt for every bus cycle wait. It will be dead slow and unusable.
> 
> The WAIT edge interrupt mechanism is exclusively for NAND use case to notify the status of READY pin after a block/page operation.

OK thanks for clarifying it. 
 
> >> For memory devices, no software wait pin intervention is necessary and doesn't even make sense.
> > 
> > Still seems that it's use can be generic though, not limited
> > to NAND.
> >  
> >> So I don't agree on managing the IRQSTATUS and IRQENABLE register in the GPMC driver. It is adding unnecessary complexity. I don't mind having a wrapper around it though like the other nand registers.
> > 
> > But all the consumer driver should need to do is request_irq()
> > on it? That's pretty much the most common interface we have
> > for drivers :)
> 
> the client driver side is easy, but it adds unnecessary complication to model it as IRQ chip and assign a line for each event. Since it is going to be used exclusively by NAND we should avoid IRQ chip modeling.

OK up to you if there are no other users for it. 
 
> >> To be frank, I think it is cleaner if the NAND driver directly accesses the NAND registers.
> >> I don't see why we should make things complicated just because the hardware designers didn't create a clear register split between GPMC and NAND.
> > 
> > Because they are in separate hardware modules :)
> > 
> > Who knows why it was set up this way. Maybe the plan was to have
> > the common features in GPMC that then can be used by various MTD
> > devices.
> >  
> >> Only the GPMC_CONFIG register needs to remain with the GPMC driver.
> > 
> > And managing clocks and runtime PM in general. In any case, let's
> > not let drivers tinker with the GPMC registers directly though.
> > Some kind of abstraction via existing frameworks or with regmap
> > is needed.
> 
> OK. I agree about using some kind of abstraction instead of direct access.

Yes and like we chatted on irc, adding a syscon mapping for for
the NAND specific registers might do the trick here.

Regards,

Tony

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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-06-13 12:08                   ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13 12:08 UTC (permalink / raw)
  To: Roger Quadros
  Cc: Gupta, Pekon, dwmw2-wEGCiKHe2LqWVfeAwA7xHQ,
	computersforpeace-Re5JQEeQqe8AvxtiuMwx3w,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ,
	ezequiel.garcia-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	javier-0uQlZySMnqxg9hUCZPvPmw, Nori, Sekhar,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

* Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> [140613 04:43]:
> On 06/13/2014 01:46 PM, Tony Lindgren wrote:
> > * Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> [140613 01:24]:
> >> On 06/13/2014 11:13 AM, Gupta, Pekon wrote:
> >>>> From: Tony Lindgren [mailto:tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org]
> >>>>> * Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> [140613 00:40]:
> >>>>>> On 06/13/2014 10:18 AM, Tony Lindgren wrote:
> >>>>>>> * Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> [140611 01:58]:
> >>>>>
> >>>>> OK. But wait pin edge detection was not yet being used and I couldn't
> >>>>> think of how it would ever be used. Any ideas?
> >>>>
> >>>> Maybe to wake-up the system on bus activity or something?
> >>>>
> >>> Sorry, I wasn't able to review this series.
> >>> But just as pointer, GPMC driver was used for interfacing many
> >>> non-memory devices like Ethernet (smc91x) and in past GPMC has been
> >>> proved to work with camera devices too, but that's wasn't mainlined.
> >>> So keeping IRQ and few other things in GPMC driver is helpful.
> >>>
> >>
> >> On further study it seems that the wait pin edge detection is only used in the NAND controller use case.
> >> see section 10.1.5.14.2.2 Ready Pin Monitored by Hardware Interrupt
> > 
> > It seems they can be used for anything slow like NOR and NAND.
> 
> But NOR driver never requests for any IRQ.
> 
> We should not confuse this wait pin edge interrupt with NOR bus cycle WAIT pin mechanism.
> That is configured using GPMC_CONFIG1 register via WAITPINSELECT and WAITREAD/WRITEMONITORING bits.
> That wait pin handling is done completely in hardware and doesn't need any software intervention.
> Imagine using it for interrupt for every bus cycle wait. It will be dead slow and unusable.
> 
> The WAIT edge interrupt mechanism is exclusively for NAND use case to notify the status of READY pin after a block/page operation.

OK thanks for clarifying it. 
 
> >> For memory devices, no software wait pin intervention is necessary and doesn't even make sense.
> > 
> > Still seems that it's use can be generic though, not limited
> > to NAND.
> >  
> >> So I don't agree on managing the IRQSTATUS and IRQENABLE register in the GPMC driver. It is adding unnecessary complexity. I don't mind having a wrapper around it though like the other nand registers.
> > 
> > But all the consumer driver should need to do is request_irq()
> > on it? That's pretty much the most common interface we have
> > for drivers :)
> 
> the client driver side is easy, but it adds unnecessary complication to model it as IRQ chip and assign a line for each event. Since it is going to be used exclusively by NAND we should avoid IRQ chip modeling.

OK up to you if there are no other users for it. 
 
> >> To be frank, I think it is cleaner if the NAND driver directly accesses the NAND registers.
> >> I don't see why we should make things complicated just because the hardware designers didn't create a clear register split between GPMC and NAND.
> > 
> > Because they are in separate hardware modules :)
> > 
> > Who knows why it was set up this way. Maybe the plan was to have
> > the common features in GPMC that then can be used by various MTD
> > devices.
> >  
> >> Only the GPMC_CONFIG register needs to remain with the GPMC driver.
> > 
> > And managing clocks and runtime PM in general. In any case, let's
> > not let drivers tinker with the GPMC registers directly though.
> > Some kind of abstraction via existing frameworks or with regmap
> > is needed.
> 
> OK. I agree about using some kind of abstraction instead of direct access.

Yes and like we chatted on irc, adding a syscon mapping for for
the NAND specific registers might do the trick here.

Regards,

Tony
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-06-13 12:08                   ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-06-13 12:08 UTC (permalink / raw)
  To: Roger Quadros
  Cc: devicetree, linux-omap, Nori, Sekhar, linux-kernel,
	kyungmin.park, linux-mtd, Gupta, Pekon, ezequiel.garcia, javier,
	computersforpeace, dwmw2

* Roger Quadros <rogerq@ti.com> [140613 04:43]:
> On 06/13/2014 01:46 PM, Tony Lindgren wrote:
> > * Roger Quadros <rogerq@ti.com> [140613 01:24]:
> >> On 06/13/2014 11:13 AM, Gupta, Pekon wrote:
> >>>> From: Tony Lindgren [mailto:tony@atomide.com]
> >>>>> * Roger Quadros <rogerq@ti.com> [140613 00:40]:
> >>>>>> On 06/13/2014 10:18 AM, Tony Lindgren wrote:
> >>>>>>> * Roger Quadros <rogerq@ti.com> [140611 01:58]:
> >>>>>
> >>>>> OK. But wait pin edge detection was not yet being used and I couldn't
> >>>>> think of how it would ever be used. Any ideas?
> >>>>
> >>>> Maybe to wake-up the system on bus activity or something?
> >>>>
> >>> Sorry, I wasn't able to review this series.
> >>> But just as pointer, GPMC driver was used for interfacing many
> >>> non-memory devices like Ethernet (smc91x) and in past GPMC has been
> >>> proved to work with camera devices too, but that's wasn't mainlined.
> >>> So keeping IRQ and few other things in GPMC driver is helpful.
> >>>
> >>
> >> On further study it seems that the wait pin edge detection is only used in the NAND controller use case.
> >> see section 10.1.5.14.2.2 Ready Pin Monitored by Hardware Interrupt
> > 
> > It seems they can be used for anything slow like NOR and NAND.
> 
> But NOR driver never requests for any IRQ.
> 
> We should not confuse this wait pin edge interrupt with NOR bus cycle WAIT pin mechanism.
> That is configured using GPMC_CONFIG1 register via WAITPINSELECT and WAITREAD/WRITEMONITORING bits.
> That wait pin handling is done completely in hardware and doesn't need any software intervention.
> Imagine using it for interrupt for every bus cycle wait. It will be dead slow and unusable.
> 
> The WAIT edge interrupt mechanism is exclusively for NAND use case to notify the status of READY pin after a block/page operation.

OK thanks for clarifying it. 
 
> >> For memory devices, no software wait pin intervention is necessary and doesn't even make sense.
> > 
> > Still seems that it's use can be generic though, not limited
> > to NAND.
> >  
> >> So I don't agree on managing the IRQSTATUS and IRQENABLE register in the GPMC driver. It is adding unnecessary complexity. I don't mind having a wrapper around it though like the other nand registers.
> > 
> > But all the consumer driver should need to do is request_irq()
> > on it? That's pretty much the most common interface we have
> > for drivers :)
> 
> the client driver side is easy, but it adds unnecessary complication to model it as IRQ chip and assign a line for each event. Since it is going to be used exclusively by NAND we should avoid IRQ chip modeling.

OK up to you if there are no other users for it. 
 
> >> To be frank, I think it is cleaner if the NAND driver directly accesses the NAND registers.
> >> I don't see why we should make things complicated just because the hardware designers didn't create a clear register split between GPMC and NAND.
> > 
> > Because they are in separate hardware modules :)
> > 
> > Who knows why it was set up this way. Maybe the plan was to have
> > the common features in GPMC that then can be used by various MTD
> > devices.
> >  
> >> Only the GPMC_CONFIG register needs to remain with the GPMC driver.
> > 
> > And managing clocks and runtime PM in general. In any case, let's
> > not let drivers tinker with the GPMC registers directly though.
> > Some kind of abstraction via existing frameworks or with regmap
> > is needed.
> 
> OK. I agree about using some kind of abstraction instead of direct access.

Yes and like we chatted on irc, adding a syscon mapping for for
the NAND specific registers might do the trick here.

Regards,

Tony

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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
  2014-06-13 12:08                   ` Tony Lindgren
  (?)
@ 2014-07-01 10:11                     ` Roger Quadros
  -1 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-07-01 10:11 UTC (permalink / raw)
  To: Tony Lindgren, Mark Brown
  Cc: Gupta, Pekon, dwmw2, computersforpeace, kyungmin.park,
	ezequiel.garcia, javier, Nori, Sekhar, linux-omap, linux-mtd,
	devicetree, linux-kernel, ivan.khoronzhuk, Alexander Shiyan

+Mark, Alexander, Ivan

Hi Tony,

On 06/13/2014 03:08 PM, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [140613 04:43]:
>> On 06/13/2014 01:46 PM, Tony Lindgren wrote:
>>> * Roger Quadros <rogerq@ti.com> [140613 01:24]:
>>>> On 06/13/2014 11:13 AM, Gupta, Pekon wrote:
>>>>>> From: Tony Lindgren [mailto:tony@atomide.com]
>>>>>>> * Roger Quadros <rogerq@ti.com> [140613 00:40]:
>>>>>>>> On 06/13/2014 10:18 AM, Tony Lindgren wrote:
>>>>>>>>> * Roger Quadros <rogerq@ti.com> [140611 01:58]:
>>>>>>>
>>>>>>> OK. But wait pin edge detection was not yet being used and I couldn't
>>>>>>> think of how it would ever be used. Any ideas?
>>>>>>
>>>>>> Maybe to wake-up the system on bus activity or something?
>>>>>>
>>>>> Sorry, I wasn't able to review this series.
>>>>> But just as pointer, GPMC driver was used for interfacing many
>>>>> non-memory devices like Ethernet (smc91x) and in past GPMC has been
>>>>> proved to work with camera devices too, but that's wasn't mainlined.
>>>>> So keeping IRQ and few other things in GPMC driver is helpful.
>>>>>
>>>>
>>>> On further study it seems that the wait pin edge detection is only used in the NAND controller use case.
>>>> see section 10.1.5.14.2.2 Ready Pin Monitored by Hardware Interrupt
>>>
>>> It seems they can be used for anything slow like NOR and NAND.
>>
>> But NOR driver never requests for any IRQ.
>>
>> We should not confuse this wait pin edge interrupt with NOR bus cycle WAIT pin mechanism.
>> That is configured using GPMC_CONFIG1 register via WAITPINSELECT and WAITREAD/WRITEMONITORING bits.
>> That wait pin handling is done completely in hardware and doesn't need any software intervention.
>> Imagine using it for interrupt for every bus cycle wait. It will be dead slow and unusable.
>>
>> The WAIT edge interrupt mechanism is exclusively for NAND use case to notify the status of READY pin after a block/page operation.
> 
> OK thanks for clarifying it. 
>  
>>>> For memory devices, no software wait pin intervention is necessary and doesn't even make sense.
>>>
>>> Still seems that it's use can be generic though, not limited
>>> to NAND.
>>>  
>>>> So I don't agree on managing the IRQSTATUS and IRQENABLE register in the GPMC driver. It is adding unnecessary complexity. I don't mind having a wrapper around it though like the other nand registers.
>>>
>>> But all the consumer driver should need to do is request_irq()
>>> on it? That's pretty much the most common interface we have
>>> for drivers :)
>>
>> the client driver side is easy, but it adds unnecessary complication to model it as IRQ chip and assign a line for each event. Since it is going to be used exclusively by NAND we should avoid IRQ chip modeling.
> 
> OK up to you if there are no other users for it. 
>  
>>>> To be frank, I think it is cleaner if the NAND driver directly accesses the NAND registers.
>>>> I don't see why we should make things complicated just because the hardware designers didn't create a clear register split between GPMC and NAND.
>>>
>>> Because they are in separate hardware modules :)
>>>
>>> Who knows why it was set up this way. Maybe the plan was to have
>>> the common features in GPMC that then can be used by various MTD
>>> devices.
>>>  
>>>> Only the GPMC_CONFIG register needs to remain with the GPMC driver.
>>>
>>> And managing clocks and runtime PM in general. In any case, let's
>>> not let drivers tinker with the GPMC registers directly though.
>>> Some kind of abstraction via existing frameworks or with regmap
>>> is needed.
>>
>> OK. I agree about using some kind of abstraction instead of direct access.
> 
> Yes and like we chatted on irc, adding a syscon mapping for for
> the NAND specific registers might do the trick here.

After looking at the syscon driver, which relies on regmap, it seems that regmap was designed for slow control busses like I2C/SPI and using it for NAND controller register access will have a significant negative impact on performance. In the NAND case the register writes are used for each NAND command cycle and the reads for ECC checks (every page).

See how much code regmap_read and regmap_mmio_read() translates to for a simple register read i.e. readl().
http://lxr.free-electrons.com/source/drivers/base/regmap/regmap.c#L1944
http://lxr.free-electrons.com/source/drivers/base/regmap/regmap-mmio.c#L129

So I'm not so sure of using regmap/syscon for NAND controller register access.

Could there be any other abstraction method of sharing the register space between GPMC and NAND driver?
I've also added Ivan to the thread, the author of memory/ti-aemif.c driver, to check if he faced any issues with shared register access of the AEMIF/NAND registers.

cheers,
-roger


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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-07-01 10:11                     ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-07-01 10:11 UTC (permalink / raw)
  To: Tony Lindgren, Mark Brown
  Cc: Gupta, Pekon, dwmw2, computersforpeace, kyungmin.park,
	ezequiel.garcia, javier, Nori, Sekhar, linux-omap, linux-mtd,
	devicetree, linux-kernel, ivan.khoronzhuk, Alexander Shiyan

+Mark, Alexander, Ivan

Hi Tony,

On 06/13/2014 03:08 PM, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [140613 04:43]:
>> On 06/13/2014 01:46 PM, Tony Lindgren wrote:
>>> * Roger Quadros <rogerq@ti.com> [140613 01:24]:
>>>> On 06/13/2014 11:13 AM, Gupta, Pekon wrote:
>>>>>> From: Tony Lindgren [mailto:tony@atomide.com]
>>>>>>> * Roger Quadros <rogerq@ti.com> [140613 00:40]:
>>>>>>>> On 06/13/2014 10:18 AM, Tony Lindgren wrote:
>>>>>>>>> * Roger Quadros <rogerq@ti.com> [140611 01:58]:
>>>>>>>
>>>>>>> OK. But wait pin edge detection was not yet being used and I couldn't
>>>>>>> think of how it would ever be used. Any ideas?
>>>>>>
>>>>>> Maybe to wake-up the system on bus activity or something?
>>>>>>
>>>>> Sorry, I wasn't able to review this series.
>>>>> But just as pointer, GPMC driver was used for interfacing many
>>>>> non-memory devices like Ethernet (smc91x) and in past GPMC has been
>>>>> proved to work with camera devices too, but that's wasn't mainlined.
>>>>> So keeping IRQ and few other things in GPMC driver is helpful.
>>>>>
>>>>
>>>> On further study it seems that the wait pin edge detection is only used in the NAND controller use case.
>>>> see section 10.1.5.14.2.2 Ready Pin Monitored by Hardware Interrupt
>>>
>>> It seems they can be used for anything slow like NOR and NAND.
>>
>> But NOR driver never requests for any IRQ.
>>
>> We should not confuse this wait pin edge interrupt with NOR bus cycle WAIT pin mechanism.
>> That is configured using GPMC_CONFIG1 register via WAITPINSELECT and WAITREAD/WRITEMONITORING bits.
>> That wait pin handling is done completely in hardware and doesn't need any software intervention.
>> Imagine using it for interrupt for every bus cycle wait. It will be dead slow and unusable.
>>
>> The WAIT edge interrupt mechanism is exclusively for NAND use case to notify the status of READY pin after a block/page operation.
> 
> OK thanks for clarifying it. 
>  
>>>> For memory devices, no software wait pin intervention is necessary and doesn't even make sense.
>>>
>>> Still seems that it's use can be generic though, not limited
>>> to NAND.
>>>  
>>>> So I don't agree on managing the IRQSTATUS and IRQENABLE register in the GPMC driver. It is adding unnecessary complexity. I don't mind having a wrapper around it though like the other nand registers.
>>>
>>> But all the consumer driver should need to do is request_irq()
>>> on it? That's pretty much the most common interface we have
>>> for drivers :)
>>
>> the client driver side is easy, but it adds unnecessary complication to model it as IRQ chip and assign a line for each event. Since it is going to be used exclusively by NAND we should avoid IRQ chip modeling.
> 
> OK up to you if there are no other users for it. 
>  
>>>> To be frank, I think it is cleaner if the NAND driver directly accesses the NAND registers.
>>>> I don't see why we should make things complicated just because the hardware designers didn't create a clear register split between GPMC and NAND.
>>>
>>> Because they are in separate hardware modules :)
>>>
>>> Who knows why it was set up this way. Maybe the plan was to have
>>> the common features in GPMC that then can be used by various MTD
>>> devices.
>>>  
>>>> Only the GPMC_CONFIG register needs to remain with the GPMC driver.
>>>
>>> And managing clocks and runtime PM in general. In any case, let's
>>> not let drivers tinker with the GPMC registers directly though.
>>> Some kind of abstraction via existing frameworks or with regmap
>>> is needed.
>>
>> OK. I agree about using some kind of abstraction instead of direct access.
> 
> Yes and like we chatted on irc, adding a syscon mapping for for
> the NAND specific registers might do the trick here.

After looking at the syscon driver, which relies on regmap, it seems that regmap was designed for slow control busses like I2C/SPI and using it for NAND controller register access will have a significant negative impact on performance. In the NAND case the register writes are used for each NAND command cycle and the reads for ECC checks (every page).

See how much code regmap_read and regmap_mmio_read() translates to for a simple register read i.e. readl().
http://lxr.free-electrons.com/source/drivers/base/regmap/regmap.c#L1944
http://lxr.free-electrons.com/source/drivers/base/regmap/regmap-mmio.c#L129

So I'm not so sure of using regmap/syscon for NAND controller register access.

Could there be any other abstraction method of sharing the register space between GPMC and NAND driver?
I've also added Ivan to the thread, the author of memory/ti-aemif.c driver, to check if he faced any issues with shared register access of the AEMIF/NAND registers.

cheers,
-roger


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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-07-01 10:11                     ` Roger Quadros
  0 siblings, 0 replies; 181+ messages in thread
From: Roger Quadros @ 2014-07-01 10:11 UTC (permalink / raw)
  To: Tony Lindgren, Mark Brown
  Cc: devicetree, linux-omap, Alexander Shiyan, Nori, Sekhar,
	linux-kernel, kyungmin.park, linux-mtd, Gupta, Pekon,
	ezequiel.garcia, ivan.khoronzhuk, javier, computersforpeace,
	dwmw2

+Mark, Alexander, Ivan

Hi Tony,

On 06/13/2014 03:08 PM, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [140613 04:43]:
>> On 06/13/2014 01:46 PM, Tony Lindgren wrote:
>>> * Roger Quadros <rogerq@ti.com> [140613 01:24]:
>>>> On 06/13/2014 11:13 AM, Gupta, Pekon wrote:
>>>>>> From: Tony Lindgren [mailto:tony@atomide.com]
>>>>>>> * Roger Quadros <rogerq@ti.com> [140613 00:40]:
>>>>>>>> On 06/13/2014 10:18 AM, Tony Lindgren wrote:
>>>>>>>>> * Roger Quadros <rogerq@ti.com> [140611 01:58]:
>>>>>>>
>>>>>>> OK. But wait pin edge detection was not yet being used and I couldn't
>>>>>>> think of how it would ever be used. Any ideas?
>>>>>>
>>>>>> Maybe to wake-up the system on bus activity or something?
>>>>>>
>>>>> Sorry, I wasn't able to review this series.
>>>>> But just as pointer, GPMC driver was used for interfacing many
>>>>> non-memory devices like Ethernet (smc91x) and in past GPMC has been
>>>>> proved to work with camera devices too, but that's wasn't mainlined.
>>>>> So keeping IRQ and few other things in GPMC driver is helpful.
>>>>>
>>>>
>>>> On further study it seems that the wait pin edge detection is only used in the NAND controller use case.
>>>> see section 10.1.5.14.2.2 Ready Pin Monitored by Hardware Interrupt
>>>
>>> It seems they can be used for anything slow like NOR and NAND.
>>
>> But NOR driver never requests for any IRQ.
>>
>> We should not confuse this wait pin edge interrupt with NOR bus cycle WAIT pin mechanism.
>> That is configured using GPMC_CONFIG1 register via WAITPINSELECT and WAITREAD/WRITEMONITORING bits.
>> That wait pin handling is done completely in hardware and doesn't need any software intervention.
>> Imagine using it for interrupt for every bus cycle wait. It will be dead slow and unusable.
>>
>> The WAIT edge interrupt mechanism is exclusively for NAND use case to notify the status of READY pin after a block/page operation.
> 
> OK thanks for clarifying it. 
>  
>>>> For memory devices, no software wait pin intervention is necessary and doesn't even make sense.
>>>
>>> Still seems that it's use can be generic though, not limited
>>> to NAND.
>>>  
>>>> So I don't agree on managing the IRQSTATUS and IRQENABLE register in the GPMC driver. It is adding unnecessary complexity. I don't mind having a wrapper around it though like the other nand registers.
>>>
>>> But all the consumer driver should need to do is request_irq()
>>> on it? That's pretty much the most common interface we have
>>> for drivers :)
>>
>> the client driver side is easy, but it adds unnecessary complication to model it as IRQ chip and assign a line for each event. Since it is going to be used exclusively by NAND we should avoid IRQ chip modeling.
> 
> OK up to you if there are no other users for it. 
>  
>>>> To be frank, I think it is cleaner if the NAND driver directly accesses the NAND registers.
>>>> I don't see why we should make things complicated just because the hardware designers didn't create a clear register split between GPMC and NAND.
>>>
>>> Because they are in separate hardware modules :)
>>>
>>> Who knows why it was set up this way. Maybe the plan was to have
>>> the common features in GPMC that then can be used by various MTD
>>> devices.
>>>  
>>>> Only the GPMC_CONFIG register needs to remain with the GPMC driver.
>>>
>>> And managing clocks and runtime PM in general. In any case, let's
>>> not let drivers tinker with the GPMC registers directly though.
>>> Some kind of abstraction via existing frameworks or with regmap
>>> is needed.
>>
>> OK. I agree about using some kind of abstraction instead of direct access.
> 
> Yes and like we chatted on irc, adding a syscon mapping for for
> the NAND specific registers might do the trick here.

After looking at the syscon driver, which relies on regmap, it seems that regmap was designed for slow control busses like I2C/SPI and using it for NAND controller register access will have a significant negative impact on performance. In the NAND case the register writes are used for each NAND command cycle and the reads for ECC checks (every page).

See how much code regmap_read and regmap_mmio_read() translates to for a simple register read i.e. readl().
http://lxr.free-electrons.com/source/drivers/base/regmap/regmap.c#L1944
http://lxr.free-electrons.com/source/drivers/base/regmap/regmap-mmio.c#L129

So I'm not so sure of using regmap/syscon for NAND controller register access.

Could there be any other abstraction method of sharing the register space between GPMC and NAND driver?
I've also added Ivan to the thread, the author of memory/ti-aemif.c driver, to check if he faced any issues with shared register access of the AEMIF/NAND registers.

cheers,
-roger

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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
  2014-07-01 10:11                     ` Roger Quadros
  (?)
@ 2014-07-01 13:16                       ` Tony Lindgren
  -1 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-07-01 13:16 UTC (permalink / raw)
  To: Roger Quadros
  Cc: Mark Brown, Gupta, Pekon, dwmw2, computersforpeace,
	kyungmin.park, ezequiel.garcia, javier, Nori, Sekhar, linux-omap,
	linux-mtd, devicetree, linux-kernel, ivan.khoronzhuk,
	Alexander Shiyan

* Roger Quadros <rogerq@ti.com> [140701 03:13]:
> On 06/13/2014 03:08 PM, Tony Lindgren wrote:
> > * Roger Quadros <rogerq@ti.com> [140613 04:43]:
> >>
> >> OK. I agree about using some kind of abstraction instead of direct access.
> > 
> > Yes and like we chatted on irc, adding a syscon mapping for for
> > the NAND specific registers might do the trick here.
> 
> After looking at the syscon driver, which relies on regmap, it seems that regmap was designed for slow control busses like I2C/SPI and using it for NAND controller register access will have a significant negative impact on performance. In the NAND case the register writes are used for each NAND command cycle and the reads for ECC checks (every page).
> 
> See how much code regmap_read and regmap_mmio_read() translates to for a simple register read i.e. readl().
> http://lxr.free-electrons.com/source/drivers/base/regmap/regmap.c#L1944
> http://lxr.free-electrons.com/source/drivers/base/regmap/regmap-mmio.c#L129
> 
> So I'm not so sure of using regmap/syscon for NAND controller register access.

OK yes I agree, it's not a good solution for a constant
register access that's needed for the ECC registers.
 
> Could there be any other abstraction method of sharing the register space between GPMC and NAND driver?
> I've also added Ivan to the thread, the author of memory/ti-aemif.c driver, to check if he faced any issues with shared register access of the AEMIF/NAND registers.

If there's no common framework available for GPMC to implement,
it's best to just export few functions from gpmc.c for the ECC
calculations.

Regards,

Tony

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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-07-01 13:16                       ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-07-01 13:16 UTC (permalink / raw)
  To: Roger Quadros
  Cc: Mark Brown, Gupta, Pekon, dwmw2, computersforpeace,
	kyungmin.park, ezequiel.garcia, javier, Nori, Sekhar, linux-omap,
	linux-mtd, devicetree, linux-kernel, ivan.khoronzhuk,
	Alexander Shiyan

* Roger Quadros <rogerq@ti.com> [140701 03:13]:
> On 06/13/2014 03:08 PM, Tony Lindgren wrote:
> > * Roger Quadros <rogerq@ti.com> [140613 04:43]:
> >>
> >> OK. I agree about using some kind of abstraction instead of direct access.
> > 
> > Yes and like we chatted on irc, adding a syscon mapping for for
> > the NAND specific registers might do the trick here.
> 
> After looking at the syscon driver, which relies on regmap, it seems that regmap was designed for slow control busses like I2C/SPI and using it for NAND controller register access will have a significant negative impact on performance. In the NAND case the register writes are used for each NAND command cycle and the reads for ECC checks (every page).
> 
> See how much code regmap_read and regmap_mmio_read() translates to for a simple register read i.e. readl().
> http://lxr.free-electrons.com/source/drivers/base/regmap/regmap.c#L1944
> http://lxr.free-electrons.com/source/drivers/base/regmap/regmap-mmio.c#L129
> 
> So I'm not so sure of using regmap/syscon for NAND controller register access.

OK yes I agree, it's not a good solution for a constant
register access that's needed for the ECC registers.
 
> Could there be any other abstraction method of sharing the register space between GPMC and NAND driver?
> I've also added Ivan to the thread, the author of memory/ti-aemif.c driver, to check if he faced any issues with shared register access of the AEMIF/NAND registers.

If there's no common framework available for GPMC to implement,
it's best to just export few functions from gpmc.c for the ECC
calculations.

Regards,

Tony

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

* Re: [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver
@ 2014-07-01 13:16                       ` Tony Lindgren
  0 siblings, 0 replies; 181+ messages in thread
From: Tony Lindgren @ 2014-07-01 13:16 UTC (permalink / raw)
  To: Roger Quadros
  Cc: devicetree, linux-omap, Alexander Shiyan, Nori, Sekhar,
	linux-kernel, kyungmin.park, Mark Brown, linux-mtd, Gupta, Pekon,
	ezequiel.garcia, ivan.khoronzhuk, javier, computersforpeace,
	dwmw2

* Roger Quadros <rogerq@ti.com> [140701 03:13]:
> On 06/13/2014 03:08 PM, Tony Lindgren wrote:
> > * Roger Quadros <rogerq@ti.com> [140613 04:43]:
> >>
> >> OK. I agree about using some kind of abstraction instead of direct access.
> > 
> > Yes and like we chatted on irc, adding a syscon mapping for for
> > the NAND specific registers might do the trick here.
> 
> After looking at the syscon driver, which relies on regmap, it seems that regmap was designed for slow control busses like I2C/SPI and using it for NAND controller register access will have a significant negative impact on performance. In the NAND case the register writes are used for each NAND command cycle and the reads for ECC checks (every page).
> 
> See how much code regmap_read and regmap_mmio_read() translates to for a simple register read i.e. readl().
> http://lxr.free-electrons.com/source/drivers/base/regmap/regmap.c#L1944
> http://lxr.free-electrons.com/source/drivers/base/regmap/regmap-mmio.c#L129
> 
> So I'm not so sure of using regmap/syscon for NAND controller register access.

OK yes I agree, it's not a good solution for a constant
register access that's needed for the ECC registers.
 
> Could there be any other abstraction method of sharing the register space between GPMC and NAND driver?
> I've also added Ivan to the thread, the author of memory/ti-aemif.c driver, to check if he faced any issues with shared register access of the AEMIF/NAND registers.

If there's no common framework available for GPMC to implement,
it's best to just export few functions from gpmc.c for the ECC
calculations.

Regards,

Tony

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

end of thread, other threads:[~2014-07-01 13:17 UTC | newest]

Thread overview: 181+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-11  8:56 [PATCH 00/36] OMAP: GPMC: Restructure and move OMAP GPMC driver out of mach-omap2 Roger Quadros
2014-06-11  8:56 ` Roger Quadros
2014-06-11  8:56 ` Roger Quadros
2014-06-11  8:56 ` [PATCH 01/36] ARM: OMAP3: hwmod: Fix gpmc memory resource space Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-13  7:13   ` Tony Lindgren
2014-06-13  7:13     ` Tony Lindgren
2014-06-13  7:15     ` Roger Quadros
2014-06-13  7:15       ` Roger Quadros
2014-06-13  7:15       ` Roger Quadros
2014-06-11  8:56 ` [PATCH 02/36] ARM: dts: OMAP2+: Fix GPMC register space size Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 03/36] ARM: OMAP2+: gpmc: Add platform data Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 04/36] ARM: OMAP2+: gpmc: Add gpmc timings and settings to " Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 05/36] mtd: nand: omap: Move IRQ handling from GPMC to NAND driver Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-13  7:18   ` Tony Lindgren
2014-06-13  7:18     ` Tony Lindgren
2014-06-13  7:38     ` Roger Quadros
2014-06-13  7:38       ` Roger Quadros
2014-06-13  7:38       ` Roger Quadros
2014-06-13  7:58       ` Tony Lindgren
2014-06-13  7:58         ` Tony Lindgren
2014-06-13  7:58         ` Tony Lindgren
2014-06-13  8:13         ` Gupta, Pekon
2014-06-13  8:13           ` Gupta, Pekon
2014-06-13  8:13           ` Gupta, Pekon
2014-06-13  8:23           ` Roger Quadros
2014-06-13  8:23             ` Roger Quadros
2014-06-13  8:23             ` Roger Quadros
2014-06-13 10:46             ` Tony Lindgren
2014-06-13 10:46               ` Tony Lindgren
2014-06-13 10:46               ` Tony Lindgren
2014-06-13 11:42               ` Roger Quadros
2014-06-13 11:42                 ` Roger Quadros
2014-06-13 11:42                 ` Roger Quadros
2014-06-13 12:08                 ` Tony Lindgren
2014-06-13 12:08                   ` Tony Lindgren
2014-06-13 12:08                   ` Tony Lindgren
2014-07-01 10:11                   ` Roger Quadros
2014-07-01 10:11                     ` Roger Quadros
2014-07-01 10:11                     ` Roger Quadros
2014-07-01 13:16                     ` Tony Lindgren
2014-07-01 13:16                       ` Tony Lindgren
2014-07-01 13:16                       ` Tony Lindgren
2014-06-11  8:56 ` [PATCH 06/36] mtd: nand: omap: Move gpmc_update_nand_reg to nand driver Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-13  7:19   ` Tony Lindgren
2014-06-13  7:19     ` Tony Lindgren
2014-06-13  7:19     ` Tony Lindgren
2014-06-11  8:56 ` [PATCH 07/36] mtd: nand: omap: Move NAND write protect code from GPMC to NAND driver Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-13  7:20   ` Tony Lindgren
2014-06-13  7:20     ` Tony Lindgren
2014-06-11  8:56 ` [PATCH 08/36] mtd: nand: omap: Copy platform data parameters to omap_nand_info data Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 09/36] mtd: nand: omap: Clean up device tree support Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 10/36] ARM: dts: OMAP2+: Fix NAND device nodes Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-13  7:21   ` Tony Lindgren
2014-06-13  7:21     ` Tony Lindgren
2014-06-13  7:21     ` Tony Lindgren
2014-06-11  8:56 ` [PATCH 11/36] mtd: nand: omap: Update DT binding documentation Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 12/36] ARM: dts: omap3-beagle: Add NAND device Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 13/36] ARM: OMAP2+: gpmc.c: sanity check bank-width DT property Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 14/36] ARM: OMAP2+: gpmc: Allow drivers to reconfigure GPMC settings & timings Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-13  7:25   ` Tony Lindgren
2014-06-13  7:25     ` Tony Lindgren
2014-06-13  7:44     ` Roger Quadros
2014-06-13  7:44       ` Roger Quadros
2014-06-13  7:44       ` Roger Quadros
2014-06-13  8:04       ` Tony Lindgren
2014-06-13  8:04         ` Tony Lindgren
2014-06-13  8:04         ` Tony Lindgren
2014-06-11  8:56 ` [PATCH 15/36] ARM: OMAP2+: gpmc: Allow drivers to query GPMC_CLK period Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-13  7:26   ` Tony Lindgren
2014-06-13  7:26     ` Tony Lindgren
2014-06-13  7:48     ` Roger Quadros
2014-06-13  7:48       ` Roger Quadros
2014-06-13  7:48       ` Roger Quadros
2014-06-11  8:56 ` [PATCH 16/36] mtd: onenand: omap: Remove regulator management code Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 17/36] ARM: OMAP2+: gpmc-onenand: Use Async settings/timings by default Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 18/36] ARM: OMAP2+: gpmc-onenand: Move Synchronous setting code to drivers/ Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-13  7:55   ` Tony Lindgren
2014-06-13  7:55     ` Tony Lindgren
2014-06-13  7:55     ` Tony Lindgren
2014-06-13  8:30     ` Roger Quadros
2014-06-13  8:30       ` Roger Quadros
2014-06-13  8:30       ` Roger Quadros
2014-06-11  8:56 ` [PATCH 19/36] mtd: onenand: omap: Use devres managed resources Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 20/36] mtd: onenand: omap: Clean up device tree support Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 21/36] ARM: dts: OMAP2+: Fix OneNAND device nodes Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 22/36] ARM: OMAP2+: gmpc: add gpmc_generic_init() Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 23/36] ARM: OMAP2+: gpmc: use platform data to configure CS space and poplulate device Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 24/36] ARM: OMAP2+: gpmc: add NAND specific setup Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 25/36] ARM: OMAP2+: gpmc: Support multiple Chip Selects per device Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 26/36] ARM: OMAP2+: gpmc-smc91x: Get rid of retime() from omap_smc91x_platform_data Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 27/36] ARM: OMAP2+: usb-tusb6010: Use omap_gpmc_retime() Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 28/36] ARM: OMAP2+: nand: Update gpmc_nand_init() to use generic_gpmc_init() Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 29/36] ARM: OMAP2+: gpmc-smc91x: Use gpmc_generic_init() Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 30/36] ARM: OMAP2+: gpmc-smsc911x: " Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 31/36] ARM: OMAP2: usb-tusb6010: " Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 32/36] ARM: OMAP2+: onenand: " Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 33/36] ARM: OMAP2+: board-flash: Use gpmc_generic_init() for NOR Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 34/36] ARM: OMAP2+: gpmc: Make externally unused functions/defines private Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56 ` [PATCH 35/36] ARM: OMAP2+: gpmc: move GPMC driver into drivers/memory Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11 11:45   ` [resend][PATCH " Roger Quadros
2014-06-11 11:45     ` Roger Quadros
2014-06-11 11:45     ` Roger Quadros
2014-06-11  8:56 ` [PATCH 36/36] ARM: OMAP2+: defconfig: Enable TI GPMC driver Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11  8:56   ` Roger Quadros
2014-06-11 11:52 ` [PATCH 00/36] OMAP: GPMC: Restructure and move OMAP GPMC driver out of mach-omap2 Javier Martinez Canillas
2014-06-11 11:52   ` Javier Martinez Canillas
2014-06-11 11:52   ` Javier Martinez Canillas
2014-06-11 11:54   ` Roger Quadros
2014-06-11 11:54     ` Roger Quadros
2014-06-11 11:54     ` Roger Quadros

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.