mirror of
https://github.com/team-infusion-developers/android_kernel_samsung_msm8976.git
synced 2024-11-07 04:09:21 +00:00
OMAP GPMC (General Purpose Memory Controller) changes to add
device tree bindings. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJRD/qiAAoJEBvUPslcq6VzqDYQAI0L0cINi94HHr+PFHlqdmRk kbOSAZtGLBCOXKL5/hpQA+whCP2CRS56SUJhRzAqgD02oaNUCSYvwIuiF35eOfTN QLAQOucF/hSueNJew9IYqKs4rYmYNNQq4xF03QvVc/OOs6ASYSWDMi9e78GyDPXa gqYyAVQekUUGTW+az7SHn+c/0hsdsSKOUZ0KbVyuaP7b64MZdIqqYGwTkRv8dVqc 5un4DCslVIaAtDDqUs1RML/dLwsZ8XLHiEZnhmii+V8bSnVlOa0e0us+vhyBus9S fbU8bdLaFAi6OPzJ9nCoQw9YSqyKjg6fq7EcSq5CQ0KpCq6iw0VAYW3usxSWrzsu vZpzUvnC+5MJFY68vg7emrF2CcCOf0v6U172ypviU3nbSHaH1l0cSdPJugk3Z4mr 5jmNPFKhslB64PvOW406UGdUJ5PoZaIO/S6fjic0HF8aqpYYqCQWQaHVDieJf5GV DTtpPPGWe94ZGd67g7cqCO6ZWn+/kXGMze/CKQJERJUjoMpKr0/yrJICpHac4Gxa 8TuNi78YYpyor+IAWYRIrycjjO2GRiftFywccRZuN8eaDlZFC10K30Qp0SUqngrr sdNbTORbCEBPsM9mbMZ5I+UNiDB5kUaFw790BvxDyjAfkpc4xr5ZKk875WZ4nGEP PL+RCilq+3hk6weipnuk =bQWe -----END PGP SIGNATURE----- Merge tag 'omap-for-v3.9/gpmc-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into next/drivers From Tony Lindgren: OMAP GPMC (General Purpose Memory Controller) changes to add device tree bindings. * tag 'omap-for-v3.9/gpmc-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap: ARM: OMAP2+: gpmc: Add device tree documentation for elm handle ARM: OMAP2+: gpmc: add DT bindings for OneNAND ARM: OMAP2+: gpmc-onenand: drop __init annotation mtd: omap-onenand: pass device_node in platform data ARM: OMAP2+: Prevent potential crash if GPMC probe fails ARM: OMAP2+: gpmc: Remove unneeded of_node_put() ARM: OMAP: gpmc: add DT bindings for GPMC timings and NAND ARM: OMAP: gpmc: enable hwecc for AM33xx SoCs ARM: OMAP: gpmc-nand: drop __init annotation mtd: omap-nand: pass device_node in platform data ARM: OMAP: gpmc: don't create devices from initcall on DT Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
commit
b6a03d0492
10 changed files with 459 additions and 12 deletions
84
Documentation/devicetree/bindings/bus/ti-gpmc.txt
Normal file
84
Documentation/devicetree/bindings/bus/ti-gpmc.txt
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
Device tree bindings for OMAP general purpose memory controllers (GPMC)
|
||||||
|
|
||||||
|
The actual devices are instantiated from the child nodes of a GPMC node.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
|
||||||
|
- compatible: Should be set to one of the following:
|
||||||
|
|
||||||
|
ti,omap2420-gpmc (omap2420)
|
||||||
|
ti,omap2430-gpmc (omap2430)
|
||||||
|
ti,omap3430-gpmc (omap3430 & omap3630)
|
||||||
|
ti,omap4430-gpmc (omap4430 & omap4460 & omap543x)
|
||||||
|
ti,am3352-gpmc (am335x devices)
|
||||||
|
|
||||||
|
- reg: A resource specifier for the register space
|
||||||
|
(see the example below)
|
||||||
|
- ti,hwmods: Should be set to "ti,gpmc" until the DT transition is
|
||||||
|
completed.
|
||||||
|
- #address-cells: Must be set to 2 to allow memory address translation
|
||||||
|
- #size-cells: Must be set to 1 to allow CS address passing
|
||||||
|
- gpmc,num-cs: The maximum number of chip-select lines that controller
|
||||||
|
can support.
|
||||||
|
- gpmc,num-waitpins: The maximum number of wait pins that controller can
|
||||||
|
support.
|
||||||
|
- ranges: Must be set up to reflect the memory layout with four
|
||||||
|
integer values for each chip-select line in use:
|
||||||
|
|
||||||
|
<cs-number> 0 <physical address of mapping> <size>
|
||||||
|
|
||||||
|
Currently, calculated values derived from the contents
|
||||||
|
of the per-CS register GPMC_CONFIG7 (as set up by the
|
||||||
|
bootloader) are used for the physical address decoding.
|
||||||
|
As this will change in the future, filling correct
|
||||||
|
values here is a requirement.
|
||||||
|
|
||||||
|
Timing properties for child nodes. All are optional and default to 0.
|
||||||
|
|
||||||
|
- gpmc,sync-clk: Minimum clock period for synchronous mode, in picoseconds
|
||||||
|
|
||||||
|
Chip-select signal timings corresponding to GPMC_CONFIG2:
|
||||||
|
- gpmc,cs-on: Assertion time
|
||||||
|
- gpmc,cs-rd-off: Read deassertion time
|
||||||
|
- gpmc,cs-wr-off: Write deassertion time
|
||||||
|
|
||||||
|
ADV signal timings corresponding to GPMC_CONFIG3:
|
||||||
|
- gpmc,adv-on: Assertion time
|
||||||
|
- gpmc,adv-rd-off: Read deassertion time
|
||||||
|
- gpmc,adv-wr-off: Write deassertion time
|
||||||
|
|
||||||
|
WE signals timings corresponding to GPMC_CONFIG4:
|
||||||
|
- gpmc,we-on: Assertion time
|
||||||
|
- gpmc,we-off: Deassertion time
|
||||||
|
|
||||||
|
OE signals timings corresponding to GPMC_CONFIG4:
|
||||||
|
- gpmc,oe-on: Assertion time
|
||||||
|
- gpmc,oe-off: Deassertion time
|
||||||
|
|
||||||
|
Access time and cycle time timings corresponding to GPMC_CONFIG5:
|
||||||
|
- gpmc,page-burst-access: Multiple access word delay
|
||||||
|
- gpmc,access: Start-cycle to first data valid delay
|
||||||
|
- gpmc,rd-cycle: Total read cycle time
|
||||||
|
- gpmc,wr-cycle: Total write cycle time
|
||||||
|
|
||||||
|
The following are only applicable to OMAP3+ and AM335x:
|
||||||
|
- gpmc,wr-access
|
||||||
|
- gpmc,wr-data-mux-bus
|
||||||
|
|
||||||
|
|
||||||
|
Example for an AM33xx board:
|
||||||
|
|
||||||
|
gpmc: gpmc@50000000 {
|
||||||
|
compatible = "ti,am3352-gpmc";
|
||||||
|
ti,hwmods = "gpmc";
|
||||||
|
reg = <0x50000000 0x2000>;
|
||||||
|
interrupts = <100>;
|
||||||
|
|
||||||
|
gpmc,num-cs = <8>;
|
||||||
|
gpmc,num-waitpins = <2>;
|
||||||
|
#address-cells = <2>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
ranges = <0 0 0x08000000 0x10000000>; /* CS0 @addr 0x8000000, size 0x10000000 */
|
||||||
|
|
||||||
|
/* child nodes go here */
|
||||||
|
};
|
80
Documentation/devicetree/bindings/mtd/gpmc-nand.txt
Normal file
80
Documentation/devicetree/bindings/mtd/gpmc-nand.txt
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
Device tree bindings for GPMC connected NANDs
|
||||||
|
|
||||||
|
GPMC connected NAND (found on OMAP boards) are represented as child nodes of
|
||||||
|
the GPMC controller with a name of "nand".
|
||||||
|
|
||||||
|
All timing relevant properties as well as generic gpmc child properties are
|
||||||
|
explained in a separate documents - please refer to
|
||||||
|
Documentation/devicetree/bindings/bus/ti-gpmc.txt
|
||||||
|
|
||||||
|
For NAND specific properties such as ECC modes or bus width, please refer to
|
||||||
|
Documentation/devicetree/bindings/mtd/nand.txt
|
||||||
|
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
|
||||||
|
- reg: The CS line the peripheral is connected to
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
|
||||||
|
- nand-bus-width: Set this numeric value to 16 if the hardware
|
||||||
|
is wired that way. If not specified, a bus
|
||||||
|
width of 8 is assumed.
|
||||||
|
|
||||||
|
- ti,nand-ecc-opt: A string setting the ECC layout to use. One of:
|
||||||
|
|
||||||
|
"sw" Software method (default)
|
||||||
|
"hw" Hardware method
|
||||||
|
"hw-romcode" gpmc hamming mode method & romcode layout
|
||||||
|
"bch4" 4-bit BCH ecc code
|
||||||
|
"bch8" 8-bit BCH ecc code
|
||||||
|
|
||||||
|
- elm_id: Specifies elm device node. This is required to support BCH
|
||||||
|
error correction using ELM module.
|
||||||
|
|
||||||
|
For inline partiton table parsing (optional):
|
||||||
|
|
||||||
|
- #address-cells: should be set to 1
|
||||||
|
- #size-cells: should be set to 1
|
||||||
|
|
||||||
|
Example for an AM33xx board:
|
||||||
|
|
||||||
|
gpmc: gpmc@50000000 {
|
||||||
|
compatible = "ti,am3352-gpmc";
|
||||||
|
ti,hwmods = "gpmc";
|
||||||
|
reg = <0x50000000 0x1000000>;
|
||||||
|
interrupts = <100>;
|
||||||
|
gpmc,num-cs = <8>;
|
||||||
|
gpmc,num-waitpins = <2>;
|
||||||
|
#address-cells = <2>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
ranges = <0 0 0x08000000 0x2000>; /* CS0: NAND */
|
||||||
|
elm_id = <&elm>;
|
||||||
|
|
||||||
|
nand@0,0 {
|
||||||
|
reg = <0 0 0>; /* CS0, offset 0 */
|
||||||
|
nand-bus-width = <16>;
|
||||||
|
ti,nand-ecc-opt = "bch8";
|
||||||
|
|
||||||
|
gpmc,sync-clk = <0>;
|
||||||
|
gpmc,cs-on = <0>;
|
||||||
|
gpmc,cs-rd-off = <44>;
|
||||||
|
gpmc,cs-wr-off = <44>;
|
||||||
|
gpmc,adv-on = <6>;
|
||||||
|
gpmc,adv-rd-off = <34>;
|
||||||
|
gpmc,adv-wr-off = <44>;
|
||||||
|
gpmc,we-off = <40>;
|
||||||
|
gpmc,oe-off = <54>;
|
||||||
|
gpmc,access = <64>;
|
||||||
|
gpmc,rd-cycle = <82>;
|
||||||
|
gpmc,wr-cycle = <82>;
|
||||||
|
gpmc,wr-access = <40>;
|
||||||
|
gpmc,wr-data-mux-bus = <0>;
|
||||||
|
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
/* partitions go here */
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
43
Documentation/devicetree/bindings/mtd/gpmc-onenand.txt
Normal file
43
Documentation/devicetree/bindings/mtd/gpmc-onenand.txt
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
Device tree bindings for GPMC connected OneNANDs
|
||||||
|
|
||||||
|
GPMC connected OneNAND (found on OMAP boards) are represented as child nodes of
|
||||||
|
the GPMC controller with a name of "onenand".
|
||||||
|
|
||||||
|
All timing relevant properties as well as generic gpmc child properties are
|
||||||
|
explained in a separate documents - please refer to
|
||||||
|
Documentation/devicetree/bindings/bus/ti-gpmc.txt
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
|
||||||
|
- reg: The CS line the peripheral is connected to
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
|
||||||
|
- dma-channel: DMA Channel index
|
||||||
|
|
||||||
|
For inline partiton table parsing (optional):
|
||||||
|
|
||||||
|
- #address-cells: should be set to 1
|
||||||
|
- #size-cells: should be set to 1
|
||||||
|
|
||||||
|
Example for an OMAP3430 board:
|
||||||
|
|
||||||
|
gpmc: gpmc@6e000000 {
|
||||||
|
compatible = "ti,omap3430-gpmc";
|
||||||
|
ti,hwmods = "gpmc";
|
||||||
|
reg = <0x6e000000 0x1000000>;
|
||||||
|
interrupts = <20>;
|
||||||
|
gpmc,num-cs = <8>;
|
||||||
|
gpmc,num-waitpins = <4>;
|
||||||
|
#address-cells = <2>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
onenand@0 {
|
||||||
|
reg = <0 0 0>; /* CS0, offset 0 */
|
||||||
|
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
/* partitions go here */
|
||||||
|
};
|
||||||
|
};
|
|
@ -89,20 +89,21 @@ static int omap2_nand_gpmc_retime(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool __init gpmc_hwecc_bch_capable(enum omap_ecc ecc_opt)
|
static bool gpmc_hwecc_bch_capable(enum omap_ecc ecc_opt)
|
||||||
{
|
{
|
||||||
/* support only OMAP3 class */
|
/* support only OMAP3 class */
|
||||||
if (!cpu_is_omap34xx()) {
|
if (!cpu_is_omap34xx() && !soc_is_am33xx()) {
|
||||||
pr_err("BCH ecc is not supported on this CPU\n");
|
pr_err("BCH ecc is not supported on this CPU\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For now, assume 4-bit mode is only supported on OMAP3630 ES1.x, x>=1.
|
* For now, assume 4-bit mode is only supported on OMAP3630 ES1.x, x>=1
|
||||||
* Other chips may be added if confirmed to work.
|
* and AM33xx derivates. Other chips may be added if confirmed to work.
|
||||||
*/
|
*/
|
||||||
if ((ecc_opt == OMAP_ECC_BCH4_CODE_HW) &&
|
if ((ecc_opt == OMAP_ECC_BCH4_CODE_HW) &&
|
||||||
(!cpu_is_omap3630() || (GET_OMAP_REVISION() == 0))) {
|
(!cpu_is_omap3630() || (GET_OMAP_REVISION() == 0)) &&
|
||||||
|
(!soc_is_am33xx())) {
|
||||||
pr_err("BCH 4-bit mode is not supported on this CPU\n");
|
pr_err("BCH 4-bit mode is not supported on this CPU\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -110,8 +111,8 @@ static bool __init gpmc_hwecc_bch_capable(enum omap_ecc ecc_opt)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int __init gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
|
int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
|
||||||
struct gpmc_timings *gpmc_t)
|
struct gpmc_timings *gpmc_t)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
struct device *dev = &gpmc_nand_device.dev;
|
struct device *dev = &gpmc_nand_device.dev;
|
||||||
|
|
|
@ -356,7 +356,7 @@ static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
|
void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,10 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_mtd.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
|
#include <linux/mtd/nand.h>
|
||||||
|
|
||||||
#include <linux/platform_data/mtd-nand-omap2.h>
|
#include <linux/platform_data/mtd-nand-omap2.h>
|
||||||
|
|
||||||
|
@ -34,6 +38,8 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "omap_device.h"
|
#include "omap_device.h"
|
||||||
#include "gpmc.h"
|
#include "gpmc.h"
|
||||||
|
#include "gpmc-nand.h"
|
||||||
|
#include "gpmc-onenand.h"
|
||||||
|
|
||||||
#define DEVICE_NAME "omap-gpmc"
|
#define DEVICE_NAME "omap-gpmc"
|
||||||
|
|
||||||
|
@ -145,7 +151,8 @@ static unsigned gpmc_irq_start;
|
||||||
static struct resource gpmc_mem_root;
|
static struct resource gpmc_mem_root;
|
||||||
static struct resource gpmc_cs_mem[GPMC_CS_NUM];
|
static struct resource gpmc_cs_mem[GPMC_CS_NUM];
|
||||||
static DEFINE_SPINLOCK(gpmc_mem_lock);
|
static DEFINE_SPINLOCK(gpmc_mem_lock);
|
||||||
static unsigned int gpmc_cs_map; /* flag for cs which are initialized */
|
/* Define chip-selects as reserved by default until probe completes */
|
||||||
|
static unsigned int gpmc_cs_map = ((1 << GPMC_CS_NUM) - 1);
|
||||||
static struct device *gpmc_dev;
|
static struct device *gpmc_dev;
|
||||||
static int gpmc_irq;
|
static int gpmc_irq;
|
||||||
static resource_size_t phys_base, mem_size;
|
static resource_size_t phys_base, mem_size;
|
||||||
|
@ -1118,9 +1125,216 @@ int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
|
||||||
/* TODO: remove, see function definition */
|
/* TODO: remove, see function definition */
|
||||||
gpmc_convert_ps_to_ns(gpmc_t);
|
gpmc_convert_ps_to_ns(gpmc_t);
|
||||||
|
|
||||||
|
/* Now the GPMC is initialised, unreserve the chip-selects */
|
||||||
|
gpmc_cs_map = 0;
|
||||||
|
|
||||||
return 0;
|
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);
|
||||||
|
|
||||||
|
static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
|
||||||
|
struct gpmc_timings *gpmc_t)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
memset(gpmc_t, 0, sizeof(*gpmc_t));
|
||||||
|
|
||||||
|
/* minimum clock period for syncronous mode */
|
||||||
|
if (!of_property_read_u32(np, "gpmc,sync-clk", &val))
|
||||||
|
gpmc_t->sync_clk = val;
|
||||||
|
|
||||||
|
/* chip select timtings */
|
||||||
|
if (!of_property_read_u32(np, "gpmc,cs-on", &val))
|
||||||
|
gpmc_t->cs_on = val;
|
||||||
|
|
||||||
|
if (!of_property_read_u32(np, "gpmc,cs-rd-off", &val))
|
||||||
|
gpmc_t->cs_rd_off = val;
|
||||||
|
|
||||||
|
if (!of_property_read_u32(np, "gpmc,cs-wr-off", &val))
|
||||||
|
gpmc_t->cs_wr_off = val;
|
||||||
|
|
||||||
|
/* ADV signal timings */
|
||||||
|
if (!of_property_read_u32(np, "gpmc,adv-on", &val))
|
||||||
|
gpmc_t->adv_on = val;
|
||||||
|
|
||||||
|
if (!of_property_read_u32(np, "gpmc,adv-rd-off", &val))
|
||||||
|
gpmc_t->adv_rd_off = val;
|
||||||
|
|
||||||
|
if (!of_property_read_u32(np, "gpmc,adv-wr-off", &val))
|
||||||
|
gpmc_t->adv_wr_off = val;
|
||||||
|
|
||||||
|
/* WE signal timings */
|
||||||
|
if (!of_property_read_u32(np, "gpmc,we-on", &val))
|
||||||
|
gpmc_t->we_on = val;
|
||||||
|
|
||||||
|
if (!of_property_read_u32(np, "gpmc,we-off", &val))
|
||||||
|
gpmc_t->we_off = val;
|
||||||
|
|
||||||
|
/* OE signal timings */
|
||||||
|
if (!of_property_read_u32(np, "gpmc,oe-on", &val))
|
||||||
|
gpmc_t->oe_on = val;
|
||||||
|
|
||||||
|
if (!of_property_read_u32(np, "gpmc,oe-off", &val))
|
||||||
|
gpmc_t->oe_off = val;
|
||||||
|
|
||||||
|
/* access and cycle timings */
|
||||||
|
if (!of_property_read_u32(np, "gpmc,page-burst-access", &val))
|
||||||
|
gpmc_t->page_burst_access = val;
|
||||||
|
|
||||||
|
if (!of_property_read_u32(np, "gpmc,access", &val))
|
||||||
|
gpmc_t->access = val;
|
||||||
|
|
||||||
|
if (!of_property_read_u32(np, "gpmc,rd-cycle", &val))
|
||||||
|
gpmc_t->rd_cycle = val;
|
||||||
|
|
||||||
|
if (!of_property_read_u32(np, "gpmc,wr-cycle", &val))
|
||||||
|
gpmc_t->wr_cycle = val;
|
||||||
|
|
||||||
|
/* only for OMAP3430 */
|
||||||
|
if (!of_property_read_u32(np, "gpmc,wr-access", &val))
|
||||||
|
gpmc_t->wr_access = val;
|
||||||
|
|
||||||
|
if (!of_property_read_u32(np, "gpmc,wr-data-mux-bus", &val))
|
||||||
|
gpmc_t->wr_data_mux_bus = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_MTD_NAND
|
||||||
|
|
||||||
|
static const char * const nand_ecc_opts[] = {
|
||||||
|
[OMAP_ECC_HAMMING_CODE_DEFAULT] = "sw",
|
||||||
|
[OMAP_ECC_HAMMING_CODE_HW] = "hw",
|
||||||
|
[OMAP_ECC_HAMMING_CODE_HW_ROMCODE] = "hw-romcode",
|
||||||
|
[OMAP_ECC_BCH4_CODE_HW] = "bch4",
|
||||||
|
[OMAP_ECC_BCH8_CODE_HW] = "bch8",
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (!of_property_read_string(child, "ti,nand-ecc-opt", &s))
|
||||||
|
for (val = 0; val < ARRAY_SIZE(nand_ecc_opts); val++)
|
||||||
|
if (!strcasecmp(s, nand_ecc_opts[val])) {
|
||||||
|
gpmc_nand_data->ecc_opt = 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
|
||||||
|
|
||||||
|
#ifdef 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
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
for_each_node_by_name(child, "nand") {
|
||||||
|
ret = gpmc_probe_nand_child(pdev, child);
|
||||||
|
if (ret < 0) {
|
||||||
|
of_node_put(child);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_node_by_name(child, "onenand") {
|
||||||
|
ret = gpmc_probe_onenand_child(pdev, child);
|
||||||
|
if (ret < 0) {
|
||||||
|
of_node_put(child);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static int gpmc_probe_dt(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int gpmc_probe(struct platform_device *pdev)
|
static int gpmc_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -1174,6 +1388,14 @@ static int gpmc_probe(struct platform_device *pdev)
|
||||||
if (IS_ERR_VALUE(gpmc_setup_irq()))
|
if (IS_ERR_VALUE(gpmc_setup_irq()))
|
||||||
dev_warn(gpmc_dev, "gpmc_setup_irq failed\n");
|
dev_warn(gpmc_dev, "gpmc_setup_irq failed\n");
|
||||||
|
|
||||||
|
rc = gpmc_probe_dt(pdev);
|
||||||
|
if (rc < 0) {
|
||||||
|
clk_disable_unprepare(gpmc_l3_clk);
|
||||||
|
clk_put(gpmc_l3_clk);
|
||||||
|
dev_err(gpmc_dev, "failed to probe DT parameters\n");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1191,6 +1413,7 @@ static struct platform_driver gpmc_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = DEVICE_NAME,
|
.name = DEVICE_NAME,
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
.of_match_table = of_match_ptr(gpmc_dt_ids),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1214,6 +1437,13 @@ static int __init omap_gpmc_init(void)
|
||||||
struct platform_device *pdev;
|
struct platform_device *pdev;
|
||||||
char *oh_name = "gpmc";
|
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);
|
oh = omap_hwmod_lookup(oh_name);
|
||||||
if (!oh) {
|
if (!oh) {
|
||||||
pr_err("Could not look up %s\n", oh_name);
|
pr_err("Could not look up %s\n", oh_name);
|
||||||
|
|
|
@ -1332,6 +1332,7 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||||
dma_cap_mask_t mask;
|
dma_cap_mask_t mask;
|
||||||
unsigned sig;
|
unsigned sig;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
|
struct mtd_part_parser_data ppdata = {};
|
||||||
|
|
||||||
pdata = pdev->dev.platform_data;
|
pdata = pdev->dev.platform_data;
|
||||||
if (pdata == NULL) {
|
if (pdata == NULL) {
|
||||||
|
@ -1557,7 +1558,8 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||||
goto out_release_mem_region;
|
goto out_release_mem_region;
|
||||||
}
|
}
|
||||||
|
|
||||||
mtd_device_parse_register(&info->mtd, NULL, NULL, pdata->parts,
|
ppdata.of_node = pdata->of_node;
|
||||||
|
mtd_device_parse_register(&info->mtd, NULL, &ppdata, pdata->parts,
|
||||||
pdata->nr_parts);
|
pdata->nr_parts);
|
||||||
|
|
||||||
platform_set_drvdata(pdev, &info->mtd);
|
platform_set_drvdata(pdev, &info->mtd);
|
||||||
|
|
|
@ -637,6 +637,7 @@ static int omap2_onenand_probe(struct platform_device *pdev)
|
||||||
struct onenand_chip *this;
|
struct onenand_chip *this;
|
||||||
int r;
|
int r;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
|
struct mtd_part_parser_data ppdata = {};
|
||||||
|
|
||||||
pdata = pdev->dev.platform_data;
|
pdata = pdev->dev.platform_data;
|
||||||
if (pdata == NULL) {
|
if (pdata == NULL) {
|
||||||
|
@ -767,7 +768,8 @@ static int omap2_onenand_probe(struct platform_device *pdev)
|
||||||
if ((r = onenand_scan(&c->mtd, 1)) < 0)
|
if ((r = onenand_scan(&c->mtd, 1)) < 0)
|
||||||
goto err_release_regulator;
|
goto err_release_regulator;
|
||||||
|
|
||||||
r = mtd_device_parse_register(&c->mtd, NULL, NULL,
|
ppdata.of_node = pdata->of_node;
|
||||||
|
r = mtd_device_parse_register(&c->mtd, NULL, &ppdata,
|
||||||
pdata ? pdata->parts : NULL,
|
pdata ? pdata->parts : NULL,
|
||||||
pdata ? pdata->nr_parts : 0);
|
pdata ? pdata->nr_parts : 0);
|
||||||
if (r)
|
if (r)
|
||||||
|
|
|
@ -60,6 +60,8 @@ struct omap_nand_platform_data {
|
||||||
int devsize;
|
int devsize;
|
||||||
enum omap_ecc ecc_opt;
|
enum omap_ecc ecc_opt;
|
||||||
struct gpmc_nand_regs reg;
|
struct gpmc_nand_regs reg;
|
||||||
};
|
|
||||||
|
|
||||||
|
/* for passing the partitions */
|
||||||
|
struct device_node *of_node;
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -29,5 +29,8 @@ struct omap_onenand_platform_data {
|
||||||
u8 flags;
|
u8 flags;
|
||||||
u8 regulator_can_sleep;
|
u8 regulator_can_sleep;
|
||||||
u8 skip_initial_unlocking;
|
u8 skip_initial_unlocking;
|
||||||
|
|
||||||
|
/* for passing the partitions */
|
||||||
|
struct device_node *of_node;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue