diff options
author | Olof Johansson <olof@lixom.net> | 2013-02-05 17:03:31 -0500 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2013-02-05 17:03:45 -0500 |
commit | b6a03d0492dedb5c10b8a5708ee92e04b0590c07 (patch) | |
tree | 21774ee93c50847fe1ea044f2cabae0746ac39d3 | |
parent | 3e93093ecd0c144e86a86cc1f165221b6cd3e7fb (diff) | |
parent | 97c794a1e37b1ca128ef38f17c069186bfa5fb1b (diff) |
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>
-rw-r--r-- | Documentation/devicetree/bindings/bus/ti-gpmc.txt | 84 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/mtd/gpmc-nand.txt | 80 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/mtd/gpmc-onenand.txt | 43 | ||||
-rw-r--r-- | arch/arm/mach-omap2/gpmc-nand.c | 15 | ||||
-rw-r--r-- | arch/arm/mach-omap2/gpmc-onenand.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-omap2/gpmc.c | 232 | ||||
-rw-r--r-- | drivers/mtd/nand/omap2.c | 4 | ||||
-rw-r--r-- | drivers/mtd/onenand/omap2.c | 4 | ||||
-rw-r--r-- | include/linux/platform_data/mtd-nand-omap2.h | 4 | ||||
-rw-r--r-- | include/linux/platform_data/mtd-onenand-omap2.h | 3 |
10 files changed, 459 insertions, 12 deletions
diff --git a/Documentation/devicetree/bindings/bus/ti-gpmc.txt b/Documentation/devicetree/bindings/bus/ti-gpmc.txt new file mode 100644 index 000000000000..5ddb2e9efaaa --- /dev/null +++ b/Documentation/devicetree/bindings/bus/ti-gpmc.txt | |||
@@ -0,0 +1,84 @@ | |||
1 | Device tree bindings for OMAP general purpose memory controllers (GPMC) | ||
2 | |||
3 | The actual devices are instantiated from the child nodes of a GPMC node. | ||
4 | |||
5 | Required properties: | ||
6 | |||
7 | - compatible: Should be set to one of the following: | ||
8 | |||
9 | ti,omap2420-gpmc (omap2420) | ||
10 | ti,omap2430-gpmc (omap2430) | ||
11 | ti,omap3430-gpmc (omap3430 & omap3630) | ||
12 | ti,omap4430-gpmc (omap4430 & omap4460 & omap543x) | ||
13 | ti,am3352-gpmc (am335x devices) | ||
14 | |||
15 | - reg: A resource specifier for the register space | ||
16 | (see the example below) | ||
17 | - ti,hwmods: Should be set to "ti,gpmc" until the DT transition is | ||
18 | completed. | ||
19 | - #address-cells: Must be set to 2 to allow memory address translation | ||
20 | - #size-cells: Must be set to 1 to allow CS address passing | ||
21 | - gpmc,num-cs: The maximum number of chip-select lines that controller | ||
22 | can support. | ||
23 | - gpmc,num-waitpins: The maximum number of wait pins that controller can | ||
24 | support. | ||
25 | - ranges: Must be set up to reflect the memory layout with four | ||
26 | integer values for each chip-select line in use: | ||
27 | |||
28 | <cs-number> 0 <physical address of mapping> <size> | ||
29 | |||
30 | Currently, calculated values derived from the contents | ||
31 | of the per-CS register GPMC_CONFIG7 (as set up by the | ||
32 | bootloader) are used for the physical address decoding. | ||
33 | As this will change in the future, filling correct | ||
34 | values here is a requirement. | ||
35 | |||
36 | Timing properties for child nodes. All are optional and default to 0. | ||
37 | |||
38 | - gpmc,sync-clk: Minimum clock period for synchronous mode, in picoseconds | ||
39 | |||
40 | Chip-select signal timings corresponding to GPMC_CONFIG2: | ||
41 | - gpmc,cs-on: Assertion time | ||
42 | - gpmc,cs-rd-off: Read deassertion time | ||
43 | - gpmc,cs-wr-off: Write deassertion time | ||
44 | |||
45 | ADV signal timings corresponding to GPMC_CONFIG3: | ||
46 | - gpmc,adv-on: Assertion time | ||
47 | - gpmc,adv-rd-off: Read deassertion time | ||
48 | - gpmc,adv-wr-off: Write deassertion time | ||
49 | |||
50 | WE signals timings corresponding to GPMC_CONFIG4: | ||
51 | - gpmc,we-on: Assertion time | ||
52 | - gpmc,we-off: Deassertion time | ||
53 | |||
54 | OE signals timings corresponding to GPMC_CONFIG4: | ||
55 | - gpmc,oe-on: Assertion time | ||
56 | - gpmc,oe-off: Deassertion time | ||
57 | |||
58 | Access time and cycle time timings corresponding to GPMC_CONFIG5: | ||
59 | - gpmc,page-burst-access: Multiple access word delay | ||
60 | - gpmc,access: Start-cycle to first data valid delay | ||
61 | - gpmc,rd-cycle: Total read cycle time | ||
62 | - gpmc,wr-cycle: Total write cycle time | ||
63 | |||
64 | The following are only applicable to OMAP3+ and AM335x: | ||
65 | - gpmc,wr-access | ||
66 | - gpmc,wr-data-mux-bus | ||
67 | |||
68 | |||
69 | Example for an AM33xx board: | ||
70 | |||
71 | gpmc: gpmc@50000000 { | ||
72 | compatible = "ti,am3352-gpmc"; | ||
73 | ti,hwmods = "gpmc"; | ||
74 | reg = <0x50000000 0x2000>; | ||
75 | interrupts = <100>; | ||
76 | |||
77 | gpmc,num-cs = <8>; | ||
78 | gpmc,num-waitpins = <2>; | ||
79 | #address-cells = <2>; | ||
80 | #size-cells = <1>; | ||
81 | ranges = <0 0 0x08000000 0x10000000>; /* CS0 @addr 0x8000000, size 0x10000000 */ | ||
82 | |||
83 | /* child nodes go here */ | ||
84 | }; | ||
diff --git a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt new file mode 100644 index 000000000000..e7f8d7ed47eb --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt | |||
@@ -0,0 +1,80 @@ | |||
1 | Device tree bindings for GPMC connected NANDs | ||
2 | |||
3 | GPMC connected NAND (found on OMAP boards) are represented as child nodes of | ||
4 | the GPMC controller with a name of "nand". | ||
5 | |||
6 | All timing relevant properties as well as generic gpmc child properties are | ||
7 | explained in a separate documents - please refer to | ||
8 | Documentation/devicetree/bindings/bus/ti-gpmc.txt | ||
9 | |||
10 | For NAND specific properties such as ECC modes or bus width, please refer to | ||
11 | Documentation/devicetree/bindings/mtd/nand.txt | ||
12 | |||
13 | |||
14 | Required properties: | ||
15 | |||
16 | - reg: The CS line the peripheral is connected to | ||
17 | |||
18 | Optional properties: | ||
19 | |||
20 | - nand-bus-width: Set this numeric value to 16 if the hardware | ||
21 | is wired that way. If not specified, a bus | ||
22 | width of 8 is assumed. | ||
23 | |||
24 | - ti,nand-ecc-opt: A string setting the ECC layout to use. One of: | ||
25 | |||
26 | "sw" Software method (default) | ||
27 | "hw" Hardware method | ||
28 | "hw-romcode" gpmc hamming mode method & romcode layout | ||
29 | "bch4" 4-bit BCH ecc code | ||
30 | "bch8" 8-bit BCH ecc code | ||
31 | |||
32 | - elm_id: Specifies elm device node. This is required to support BCH | ||
33 | error correction using ELM module. | ||
34 | |||
35 | For inline partiton table parsing (optional): | ||
36 | |||
37 | - #address-cells: should be set to 1 | ||
38 | - #size-cells: should be set to 1 | ||
39 | |||
40 | Example for an AM33xx board: | ||
41 | |||
42 | gpmc: gpmc@50000000 { | ||
43 | compatible = "ti,am3352-gpmc"; | ||
44 | ti,hwmods = "gpmc"; | ||
45 | reg = <0x50000000 0x1000000>; | ||
46 | interrupts = <100>; | ||
47 | gpmc,num-cs = <8>; | ||
48 | gpmc,num-waitpins = <2>; | ||
49 | #address-cells = <2>; | ||
50 | #size-cells = <1>; | ||
51 | ranges = <0 0 0x08000000 0x2000>; /* CS0: NAND */ | ||
52 | elm_id = <&elm>; | ||
53 | |||
54 | nand@0,0 { | ||
55 | reg = <0 0 0>; /* CS0, offset 0 */ | ||
56 | nand-bus-width = <16>; | ||
57 | ti,nand-ecc-opt = "bch8"; | ||
58 | |||
59 | gpmc,sync-clk = <0>; | ||
60 | gpmc,cs-on = <0>; | ||
61 | gpmc,cs-rd-off = <44>; | ||
62 | gpmc,cs-wr-off = <44>; | ||
63 | gpmc,adv-on = <6>; | ||
64 | gpmc,adv-rd-off = <34>; | ||
65 | gpmc,adv-wr-off = <44>; | ||
66 | gpmc,we-off = <40>; | ||
67 | gpmc,oe-off = <54>; | ||
68 | gpmc,access = <64>; | ||
69 | gpmc,rd-cycle = <82>; | ||
70 | gpmc,wr-cycle = <82>; | ||
71 | gpmc,wr-access = <40>; | ||
72 | gpmc,wr-data-mux-bus = <0>; | ||
73 | |||
74 | #address-cells = <1>; | ||
75 | #size-cells = <1>; | ||
76 | |||
77 | /* partitions go here */ | ||
78 | }; | ||
79 | }; | ||
80 | |||
diff --git a/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt b/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt new file mode 100644 index 000000000000..deec9da224a2 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt | |||
@@ -0,0 +1,43 @@ | |||
1 | Device tree bindings for GPMC connected OneNANDs | ||
2 | |||
3 | GPMC connected OneNAND (found on OMAP boards) are represented as child nodes of | ||
4 | the GPMC controller with a name of "onenand". | ||
5 | |||
6 | All timing relevant properties as well as generic gpmc child properties are | ||
7 | explained in a separate documents - please refer to | ||
8 | Documentation/devicetree/bindings/bus/ti-gpmc.txt | ||
9 | |||
10 | Required properties: | ||
11 | |||
12 | - reg: The CS line the peripheral is connected to | ||
13 | |||
14 | Optional properties: | ||
15 | |||
16 | - dma-channel: DMA Channel index | ||
17 | |||
18 | For inline partiton table parsing (optional): | ||
19 | |||
20 | - #address-cells: should be set to 1 | ||
21 | - #size-cells: should be set to 1 | ||
22 | |||
23 | Example for an OMAP3430 board: | ||
24 | |||
25 | gpmc: gpmc@6e000000 { | ||
26 | compatible = "ti,omap3430-gpmc"; | ||
27 | ti,hwmods = "gpmc"; | ||
28 | reg = <0x6e000000 0x1000000>; | ||
29 | interrupts = <20>; | ||
30 | gpmc,num-cs = <8>; | ||
31 | gpmc,num-waitpins = <4>; | ||
32 | #address-cells = <2>; | ||
33 | #size-cells = <1>; | ||
34 | |||
35 | onenand@0 { | ||
36 | reg = <0 0 0>; /* CS0, offset 0 */ | ||
37 | |||
38 | #address-cells = <1>; | ||
39 | #size-cells = <1>; | ||
40 | |||
41 | /* partitions go here */ | ||
42 | }; | ||
43 | }; | ||
diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c index db969a5c4998..afc1e8c32d6c 100644 --- a/arch/arm/mach-omap2/gpmc-nand.c +++ b/arch/arm/mach-omap2/gpmc-nand.c | |||
@@ -89,20 +89,21 @@ static int omap2_nand_gpmc_retime( | |||
89 | return 0; | 89 | return 0; |
90 | } | 90 | } |
91 | 91 | ||
92 | static bool __init gpmc_hwecc_bch_capable(enum omap_ecc ecc_opt) | 92 | static bool gpmc_hwecc_bch_capable(enum omap_ecc ecc_opt) |
93 | { | 93 | { |
94 | /* support only OMAP3 class */ | 94 | /* support only OMAP3 class */ |
95 | if (!cpu_is_omap34xx()) { | 95 | if (!cpu_is_omap34xx() && !soc_is_am33xx()) { |
96 | pr_err("BCH ecc is not supported on this CPU\n"); | 96 | pr_err("BCH ecc is not supported on this CPU\n"); |
97 | return 0; | 97 | return 0; |
98 | } | 98 | } |
99 | 99 | ||
100 | /* | 100 | /* |
101 | * For now, assume 4-bit mode is only supported on OMAP3630 ES1.x, x>=1. | 101 | * For now, assume 4-bit mode is only supported on OMAP3630 ES1.x, x>=1 |
102 | * Other chips may be added if confirmed to work. | 102 | * and AM33xx derivates. Other chips may be added if confirmed to work. |
103 | */ | 103 | */ |
104 | if ((ecc_opt == OMAP_ECC_BCH4_CODE_HW) && | 104 | if ((ecc_opt == OMAP_ECC_BCH4_CODE_HW) && |
105 | (!cpu_is_omap3630() || (GET_OMAP_REVISION() == 0))) { | 105 | (!cpu_is_omap3630() || (GET_OMAP_REVISION() == 0)) && |
106 | (!soc_is_am33xx())) { | ||
106 | pr_err("BCH 4-bit mode is not supported on this CPU\n"); | 107 | pr_err("BCH 4-bit mode is not supported on this CPU\n"); |
107 | return 0; | 108 | return 0; |
108 | } | 109 | } |
@@ -110,8 +111,8 @@ static bool __init gpmc_hwecc_bch_capable(enum omap_ecc ecc_opt) | |||
110 | return 1; | 111 | return 1; |
111 | } | 112 | } |
112 | 113 | ||
113 | int __init gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, | 114 | int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, |
114 | struct gpmc_timings *gpmc_t) | 115 | struct gpmc_timings *gpmc_t) |
115 | { | 116 | { |
116 | int err = 0; | 117 | int err = 0; |
117 | struct device *dev = &gpmc_nand_device.dev; | 118 | struct device *dev = &gpmc_nand_device.dev; |
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c index 94a349e4dc96..fadd87435cd0 100644 --- a/arch/arm/mach-omap2/gpmc-onenand.c +++ b/arch/arm/mach-omap2/gpmc-onenand.c | |||
@@ -356,7 +356,7 @@ static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr) | |||
356 | return ret; | 356 | return ret; |
357 | } | 357 | } |
358 | 358 | ||
359 | void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) | 359 | void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) |
360 | { | 360 | { |
361 | int err; | 361 | int err; |
362 | 362 | ||
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 8033cb747c86..1adb2d4496f6 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c | |||
@@ -25,6 +25,10 @@ | |||
25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
26 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
27 | #include <linux/platform_device.h> | 27 | #include <linux/platform_device.h> |
28 | #include <linux/of.h> | ||
29 | #include <linux/of_mtd.h> | ||
30 | #include <linux/of_device.h> | ||
31 | #include <linux/mtd/nand.h> | ||
28 | 32 | ||
29 | #include <linux/platform_data/mtd-nand-omap2.h> | 33 | #include <linux/platform_data/mtd-nand-omap2.h> |
30 | 34 | ||
@@ -34,6 +38,8 @@ | |||
34 | #include "common.h" | 38 | #include "common.h" |
35 | #include "omap_device.h" | 39 | #include "omap_device.h" |
36 | #include "gpmc.h" | 40 | #include "gpmc.h" |
41 | #include "gpmc-nand.h" | ||
42 | #include "gpmc-onenand.h" | ||
37 | 43 | ||
38 | #define DEVICE_NAME "omap-gpmc" | 44 | #define DEVICE_NAME "omap-gpmc" |
39 | 45 | ||
@@ -145,7 +151,8 @@ static unsigned gpmc_irq_start; | |||
145 | static struct resource gpmc_mem_root; | 151 | static struct resource gpmc_mem_root; |
146 | static struct resource gpmc_cs_mem[GPMC_CS_NUM]; | 152 | static struct resource gpmc_cs_mem[GPMC_CS_NUM]; |
147 | static DEFINE_SPINLOCK(gpmc_mem_lock); | 153 | static DEFINE_SPINLOCK(gpmc_mem_lock); |
148 | static unsigned int gpmc_cs_map; /* flag for cs which are initialized */ | 154 | /* Define chip-selects as reserved by default until probe completes */ |
155 | static unsigned int gpmc_cs_map = ((1 << GPMC_CS_NUM) - 1); | ||
149 | static struct device *gpmc_dev; | 156 | static struct device *gpmc_dev; |
150 | static int gpmc_irq; | 157 | static int gpmc_irq; |
151 | static resource_size_t phys_base, mem_size; | 158 | static resource_size_t phys_base, mem_size; |
@@ -1118,9 +1125,216 @@ int gpmc_calc_timings(struct gpmc_timings *gpmc_t, | |||
1118 | /* TODO: remove, see function definition */ | 1125 | /* TODO: remove, see function definition */ |
1119 | gpmc_convert_ps_to_ns(gpmc_t); | 1126 | gpmc_convert_ps_to_ns(gpmc_t); |
1120 | 1127 | ||
1128 | /* Now the GPMC is initialised, unreserve the chip-selects */ | ||
1129 | gpmc_cs_map = 0; | ||
1130 | |||
1121 | return 0; | 1131 | return 0; |
1122 | } | 1132 | } |
1123 | 1133 | ||
1134 | #ifdef CONFIG_OF | ||
1135 | static struct of_device_id gpmc_dt_ids[] = { | ||
1136 | { .compatible = "ti,omap2420-gpmc" }, | ||
1137 | { .compatible = "ti,omap2430-gpmc" }, | ||
1138 | { .compatible = "ti,omap3430-gpmc" }, /* omap3430 & omap3630 */ | ||
1139 | { .compatible = "ti,omap4430-gpmc" }, /* omap4430 & omap4460 & omap543x */ | ||
1140 | { .compatible = "ti,am3352-gpmc" }, /* am335x devices */ | ||
1141 | { } | ||
1142 | }; | ||
1143 | MODULE_DEVICE_TABLE(of, gpmc_dt_ids); | ||
1144 | |||
1145 | static void __maybe_unused gpmc_read_timings_dt(struct device_node *np, | ||
1146 | struct gpmc_timings *gpmc_t) | ||
1147 | { | ||
1148 | u32 val; | ||
1149 | |||
1150 | memset(gpmc_t, 0, sizeof(*gpmc_t)); | ||
1151 | |||
1152 | /* minimum clock period for syncronous mode */ | ||
1153 | if (!of_property_read_u32(np, "gpmc,sync-clk", &val)) | ||
1154 | gpmc_t->sync_clk = val; | ||
1155 | |||
1156 | /* chip select timtings */ | ||
1157 | if (!of_property_read_u32(np, "gpmc,cs-on", &val)) | ||
1158 | gpmc_t->cs_on = val; | ||
1159 | |||
1160 | if (!of_property_read_u32(np, "gpmc,cs-rd-off", &val)) | ||
1161 | gpmc_t->cs_rd_off = val; | ||
1162 | |||
1163 | if (!of_property_read_u32(np, "gpmc,cs-wr-off", &val)) | ||
1164 | gpmc_t->cs_wr_off = val; | ||
1165 | |||
1166 | /* ADV signal timings */ | ||
1167 | if (!of_property_read_u32(np, "gpmc,adv-on", &val)) | ||
1168 | gpmc_t->adv_on = val; | ||
1169 | |||
1170 | if (!of_property_read_u32(np, "gpmc,adv-rd-off", &val)) | ||
1171 | gpmc_t->adv_rd_off = val; | ||
1172 | |||
1173 | if (!of_property_read_u32(np, "gpmc,adv-wr-off", &val)) | ||
1174 | gpmc_t->adv_wr_off = val; | ||
1175 | |||
1176 | /* WE signal timings */ | ||
1177 | if (!of_property_read_u32(np, "gpmc,we-on", &val)) | ||
1178 | gpmc_t->we_on = val; | ||
1179 | |||
1180 | if (!of_property_read_u32(np, "gpmc,we-off", &val)) | ||
1181 | gpmc_t->we_off = val; | ||
1182 | |||
1183 | /* OE signal timings */ | ||
1184 | if (!of_property_read_u32(np, "gpmc,oe-on", &val)) | ||
1185 | gpmc_t->oe_on = val; | ||
1186 | |||
1187 | if (!of_property_read_u32(np, "gpmc,oe-off", &val)) | ||
1188 | gpmc_t->oe_off = val; | ||
1189 | |||
1190 | /* access and cycle timings */ | ||
1191 | if (!of_property_read_u32(np, "gpmc,page-burst-access", &val)) | ||
1192 | gpmc_t->page_burst_access = val; | ||
1193 | |||
1194 | if (!of_property_read_u32(np, "gpmc,access", &val)) | ||
1195 | gpmc_t->access = val; | ||
1196 | |||
1197 | if (!of_property_read_u32(np, "gpmc,rd-cycle", &val)) | ||
1198 | gpmc_t->rd_cycle = val; | ||
1199 | |||
1200 | if (!of_property_read_u32(np, "gpmc,wr-cycle", &val)) | ||
1201 | gpmc_t->wr_cycle = val; | ||
1202 | |||
1203 | /* only for OMAP3430 */ | ||
1204 | if (!of_property_read_u32(np, "gpmc,wr-access", &val)) | ||
1205 | gpmc_t->wr_access = val; | ||
1206 | |||
1207 | if (!of_property_read_u32(np, "gpmc,wr-data-mux-bus", &val)) | ||
1208 | gpmc_t->wr_data_mux_bus = val; | ||
1209 | } | ||
1210 | |||
1211 | #ifdef CONFIG_MTD_NAND | ||
1212 | |||
1213 | static const char * const nand_ecc_opts[] = { | ||
1214 | [OMAP_ECC_HAMMING_CODE_DEFAULT] = "sw", | ||
1215 | [OMAP_ECC_HAMMING_CODE_HW] = "hw", | ||
1216 | [OMAP_ECC_HAMMING_CODE_HW_ROMCODE] = "hw-romcode", | ||
1217 | [OMAP_ECC_BCH4_CODE_HW] = "bch4", | ||
1218 | [OMAP_ECC_BCH8_CODE_HW] = "bch8", | ||
1219 | }; | ||
1220 | |||
1221 | static int gpmc_probe_nand_child(struct platform_device *pdev, | ||
1222 | struct device_node *child) | ||
1223 | { | ||
1224 | u32 val; | ||
1225 | const char *s; | ||
1226 | struct gpmc_timings gpmc_t; | ||
1227 | struct omap_nand_platform_data *gpmc_nand_data; | ||
1228 | |||
1229 | if (of_property_read_u32(child, "reg", &val) < 0) { | ||
1230 | dev_err(&pdev->dev, "%s has no 'reg' property\n", | ||
1231 | child->full_name); | ||
1232 | return -ENODEV; | ||
1233 | } | ||
1234 | |||
1235 | gpmc_nand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_nand_data), | ||
1236 | GFP_KERNEL); | ||
1237 | if (!gpmc_nand_data) | ||
1238 | return -ENOMEM; | ||
1239 | |||
1240 | gpmc_nand_data->cs = val; | ||
1241 | gpmc_nand_data->of_node = child; | ||
1242 | |||
1243 | if (!of_property_read_string(child, "ti,nand-ecc-opt", &s)) | ||
1244 | for (val = 0; val < ARRAY_SIZE(nand_ecc_opts); val++) | ||
1245 | if (!strcasecmp(s, nand_ecc_opts[val])) { | ||
1246 | gpmc_nand_data->ecc_opt = val; | ||
1247 | break; | ||
1248 | } | ||
1249 | |||
1250 | val = of_get_nand_bus_width(child); | ||
1251 | if (val == 16) | ||
1252 | gpmc_nand_data->devsize = NAND_BUSWIDTH_16; | ||
1253 | |||
1254 | gpmc_read_timings_dt(child, &gpmc_t); | ||
1255 | gpmc_nand_init(gpmc_nand_data, &gpmc_t); | ||
1256 | |||
1257 | return 0; | ||
1258 | } | ||
1259 | #else | ||
1260 | static int gpmc_probe_nand_child(struct platform_device *pdev, | ||
1261 | struct device_node *child) | ||
1262 | { | ||
1263 | return 0; | ||
1264 | } | ||
1265 | #endif | ||
1266 | |||
1267 | #ifdef CONFIG_MTD_ONENAND | ||
1268 | static int gpmc_probe_onenand_child(struct platform_device *pdev, | ||
1269 | struct device_node *child) | ||
1270 | { | ||
1271 | u32 val; | ||
1272 | struct omap_onenand_platform_data *gpmc_onenand_data; | ||
1273 | |||
1274 | if (of_property_read_u32(child, "reg", &val) < 0) { | ||
1275 | dev_err(&pdev->dev, "%s has no 'reg' property\n", | ||
1276 | child->full_name); | ||
1277 | return -ENODEV; | ||
1278 | } | ||
1279 | |||
1280 | gpmc_onenand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_onenand_data), | ||
1281 | GFP_KERNEL); | ||
1282 | if (!gpmc_onenand_data) | ||
1283 | return -ENOMEM; | ||
1284 | |||
1285 | gpmc_onenand_data->cs = val; | ||
1286 | gpmc_onenand_data->of_node = child; | ||
1287 | gpmc_onenand_data->dma_channel = -1; | ||
1288 | |||
1289 | if (!of_property_read_u32(child, "dma-channel", &val)) | ||
1290 | gpmc_onenand_data->dma_channel = val; | ||
1291 | |||
1292 | gpmc_onenand_init(gpmc_onenand_data); | ||
1293 | |||
1294 | return 0; | ||
1295 | } | ||
1296 | #else | ||
1297 | static int gpmc_probe_onenand_child(struct platform_device *pdev, | ||
1298 | struct device_node *child) | ||
1299 | { | ||
1300 | return 0; | ||
1301 | } | ||
1302 | #endif | ||
1303 | |||
1304 | static int gpmc_probe_dt(struct platform_device *pdev) | ||
1305 | { | ||
1306 | int ret; | ||
1307 | struct device_node *child; | ||
1308 | const struct of_device_id *of_id = | ||
1309 | of_match_device(gpmc_dt_ids, &pdev->dev); | ||
1310 | |||
1311 | if (!of_id) | ||
1312 | return 0; | ||
1313 | |||
1314 | for_each_node_by_name(child, "nand") { | ||
1315 | ret = gpmc_probe_nand_child(pdev, child); | ||
1316 | if (ret < 0) { | ||
1317 | of_node_put(child); | ||
1318 | return ret; | ||
1319 | } | ||
1320 | } | ||
1321 | |||
1322 | for_each_node_by_name(child, "onenand") { | ||
1323 | ret = gpmc_probe_onenand_child(pdev, child); | ||
1324 | if (ret < 0) { | ||
1325 | of_node_put(child); | ||
1326 | return ret; | ||
1327 | } | ||
1328 | } | ||
1329 | return 0; | ||
1330 | } | ||
1331 | #else | ||
1332 | static int gpmc_probe_dt(struct platform_device *pdev) | ||
1333 | { | ||
1334 | return 0; | ||
1335 | } | ||
1336 | #endif | ||
1337 | |||
1124 | static int gpmc_probe(struct platform_device *pdev) | 1338 | static int gpmc_probe(struct platform_device *pdev) |
1125 | { | 1339 | { |
1126 | int rc; | 1340 | int rc; |
@@ -1174,6 +1388,14 @@ static int gpmc_probe(struct platform_device *pdev) | |||
1174 | if (IS_ERR_VALUE(gpmc_setup_irq())) | 1388 | if (IS_ERR_VALUE(gpmc_setup_irq())) |
1175 | dev_warn(gpmc_dev, "gpmc_setup_irq failed\n"); | 1389 | dev_warn(gpmc_dev, "gpmc_setup_irq failed\n"); |
1176 | 1390 | ||
1391 | rc = gpmc_probe_dt(pdev); | ||
1392 | if (rc < 0) { | ||
1393 | clk_disable_unprepare(gpmc_l3_clk); | ||
1394 | clk_put(gpmc_l3_clk); | ||
1395 | dev_err(gpmc_dev, "failed to probe DT parameters\n"); | ||
1396 | return rc; | ||
1397 | } | ||
1398 | |||
1177 | return 0; | 1399 | return 0; |
1178 | } | 1400 | } |
1179 | 1401 | ||
@@ -1191,6 +1413,7 @@ static struct platform_driver gpmc_driver = { | |||
1191 | .driver = { | 1413 | .driver = { |
1192 | .name = DEVICE_NAME, | 1414 | .name = DEVICE_NAME, |
1193 | .owner = THIS_MODULE, | 1415 | .owner = THIS_MODULE, |
1416 | .of_match_table = of_match_ptr(gpmc_dt_ids), | ||
1194 | }, | 1417 | }, |
1195 | }; | 1418 | }; |
1196 | 1419 | ||
@@ -1214,6 +1437,13 @@ static int __init omap_gpmc_init(void) | |||
1214 | struct platform_device *pdev; | 1437 | struct platform_device *pdev; |
1215 | char *oh_name = "gpmc"; | 1438 | char *oh_name = "gpmc"; |
1216 | 1439 | ||
1440 | /* | ||
1441 | * if the board boots up with a populated DT, do not | ||
1442 | * manually add the device from this initcall | ||
1443 | */ | ||
1444 | if (of_have_populated_dt()) | ||
1445 | return -ENODEV; | ||
1446 | |||
1217 | oh = omap_hwmod_lookup(oh_name); | 1447 | oh = omap_hwmod_lookup(oh_name); |
1218 | if (!oh) { | 1448 | if (!oh) { |
1219 | pr_err("Could not look up %s\n", oh_name); | 1449 | pr_err("Could not look up %s\n", oh_name); |
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 0002d5e94f0d..1d333497cfcb 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c | |||
@@ -1332,6 +1332,7 @@ static int omap_nand_probe(struct platform_device *pdev) | |||
1332 | dma_cap_mask_t mask; | 1332 | dma_cap_mask_t mask; |
1333 | unsigned sig; | 1333 | unsigned sig; |
1334 | struct resource *res; | 1334 | struct resource *res; |
1335 | struct mtd_part_parser_data ppdata = {}; | ||
1335 | 1336 | ||
1336 | pdata = pdev->dev.platform_data; | 1337 | pdata = pdev->dev.platform_data; |
1337 | if (pdata == NULL) { | 1338 | if (pdata == NULL) { |
@@ -1557,7 +1558,8 @@ static int omap_nand_probe(struct platform_device *pdev) | |||
1557 | goto out_release_mem_region; | 1558 | goto out_release_mem_region; |
1558 | } | 1559 | } |
1559 | 1560 | ||
1560 | mtd_device_parse_register(&info->mtd, NULL, NULL, pdata->parts, | 1561 | ppdata.of_node = pdata->of_node; |
1562 | mtd_device_parse_register(&info->mtd, NULL, &ppdata, pdata->parts, | ||
1561 | pdata->nr_parts); | 1563 | pdata->nr_parts); |
1562 | 1564 | ||
1563 | platform_set_drvdata(pdev, &info->mtd); | 1565 | platform_set_drvdata(pdev, &info->mtd); |
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index 065f3fe02a2f..eec2aedb4ab8 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c | |||
@@ -637,6 +637,7 @@ static int omap2_onenand_probe(struct platform_device *pdev) | |||
637 | struct onenand_chip *this; | 637 | struct onenand_chip *this; |
638 | int r; | 638 | int r; |
639 | struct resource *res; | 639 | struct resource *res; |
640 | struct mtd_part_parser_data ppdata = {}; | ||
640 | 641 | ||
641 | pdata = pdev->dev.platform_data; | 642 | pdata = pdev->dev.platform_data; |
642 | if (pdata == NULL) { | 643 | if (pdata == NULL) { |
@@ -767,7 +768,8 @@ static int omap2_onenand_probe(struct platform_device *pdev) | |||
767 | if ((r = onenand_scan(&c->mtd, 1)) < 0) | 768 | if ((r = onenand_scan(&c->mtd, 1)) < 0) |
768 | goto err_release_regulator; | 769 | goto err_release_regulator; |
769 | 770 | ||
770 | r = mtd_device_parse_register(&c->mtd, NULL, NULL, | 771 | ppdata.of_node = pdata->of_node; |
772 | r = mtd_device_parse_register(&c->mtd, NULL, &ppdata, | ||
771 | pdata ? pdata->parts : NULL, | 773 | pdata ? pdata->parts : NULL, |
772 | pdata ? pdata->nr_parts : 0); | 774 | pdata ? pdata->nr_parts : 0); |
773 | if (r) | 775 | if (r) |
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h index 24d32ca34bef..6bf9ef43ddb1 100644 --- a/include/linux/platform_data/mtd-nand-omap2.h +++ b/include/linux/platform_data/mtd-nand-omap2.h | |||
@@ -60,6 +60,8 @@ struct omap_nand_platform_data { | |||
60 | int devsize; | 60 | int devsize; |
61 | enum omap_ecc ecc_opt; | 61 | enum omap_ecc ecc_opt; |
62 | struct gpmc_nand_regs reg; | 62 | struct gpmc_nand_regs reg; |
63 | }; | ||
64 | 63 | ||
64 | /* for passing the partitions */ | ||
65 | struct device_node *of_node; | ||
66 | }; | ||
65 | #endif | 67 | #endif |
diff --git a/include/linux/platform_data/mtd-onenand-omap2.h b/include/linux/platform_data/mtd-onenand-omap2.h index 685af7e8b120..e9a9fb188f97 100644 --- a/include/linux/platform_data/mtd-onenand-omap2.h +++ b/include/linux/platform_data/mtd-onenand-omap2.h | |||
@@ -29,5 +29,8 @@ struct omap_onenand_platform_data { | |||
29 | u8 flags; | 29 | u8 flags; |
30 | u8 regulator_can_sleep; | 30 | u8 regulator_can_sleep; |
31 | u8 skip_initial_unlocking; | 31 | u8 skip_initial_unlocking; |
32 | |||
33 | /* for passing the partitions */ | ||
34 | struct device_node *of_node; | ||
32 | }; | 35 | }; |
33 | #endif | 36 | #endif |