-
Notifications
You must be signed in to change notification settings - Fork 63
/
0021-ARM-OMAP2-Add-device-tree-support-for-NOR-flash.patch
277 lines (268 loc) · 7.85 KB
/
0021-ARM-OMAP2-Add-device-tree-support-for-NOR-flash.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
From 6950d2cad88fe8670b9543d22e0a9cb40e20f3d0 Mon Sep 17 00:00:00 2001
From: Jon Hunter <jon-hunter@ti.com>
Date: Fri, 8 Feb 2013 16:46:13 -0600
Subject: [PATCH 21/39] ARM: OMAP2+: Add device-tree support for NOR flash
NOR flash is not currently supported when booting with device-tree
on OMAP2+ devices. Add support to detect and configure NOR devices
when booting with device-tree.
Add documentation for the TI GPMC NOR binding.
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
Tested-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
Documentation/devicetree/bindings/mtd/gpmc-nor.txt | 98 +++++++++++++++++
arch/arm/mach-omap2/gpmc.c | 119 +++++++++++++++++++++
2 files changed, 217 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mtd/gpmc-nor.txt
diff --git a/Documentation/devicetree/bindings/mtd/gpmc-nor.txt b/Documentation/devicetree/bindings/mtd/gpmc-nor.txt
new file mode 100644
index 0000000..420b3ab
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/gpmc-nor.txt
@@ -0,0 +1,98 @@
+Device tree bindings for NOR flash connect to TI GPMC
+
+NOR flash connected to the TI GPMC (found on OMAP boards) are represented as
+child nodes of the GPMC controller with a name of "nor".
+
+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:
+- bank-width: Width of NOR flash in bytes. GPMC supports 8-bit and
+ 16-bit devices and so must be either 1 or 2 bytes.
+- compatible: Documentation/devicetree/bindings/mtd/mtd-physmap.txt
+- gpmc,cs-on-ns: Chip-select assertion time
+- gpmc,cs-rd-off-ns: Chip-select de-assertion time for reads
+- gpmc,cs-wr-off-ns: Chip-select de-assertion time for writes
+- gpmc,oe-on-ns: Output-enable assertion time
+- gpmc,oe-off-ns: Output-enable de-assertion time
+- gpmc,we-on-ns Write-enable assertion time
+- gpmc,we-off-ns: Write-enable de-assertion time
+- gpmc,access-ns: Start cycle to first data capture (read access)
+- gpmc,rd-cycle-ns: Total read cycle time
+- gpmc,wr-cycle-ns: Total write cycle time
+- linux,mtd-name: Documentation/devicetree/bindings/mtd/mtd-physmap.txt
+- reg: Chip-select, base address (relative to chip-select)
+ and size of NOR flash. Note that base address will be
+ typically 0 as this is the start of the chip-select.
+
+Optional properties:
+- gpmc,XXX Additional GPMC timings and settings parameters. See
+ Documentation/devicetree/bindings/bus/ti-gpmc.txt
+
+Optional properties for partiton table parsing:
+- #address-cells: should be set to 1
+- #size-cells: should be set to 1
+
+Example:
+
+gpmc: gpmc@6e000000 {
+ compatible = "ti,omap3430-gpmc", "simple-bus";
+ ti,hwmods = "gpmc";
+ reg = <0x6e000000 0x1000>;
+ interrupts = <20>;
+ gpmc,num-cs = <8>;
+ gpmc,num-waitpins = <4>;
+ #address-cells = <2>;
+ #size-cells = <1>;
+
+ ranges = <0 0 0x10000000 0x08000000>;
+
+ nor@0,0 {
+ compatible = "cfi-flash";
+ linux,mtd-name= "intel,pf48f6000m0y1be";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0 0 0x08000000>;
+ bank-width = <2>;
+
+ gpmc,mux-add-data;
+ gpmc,cs-on-ns = <0>;
+ gpmc,cs-rd-off-ns = <186>;
+ gpmc,cs-wr-off-ns = <186>;
+ gpmc,adv-on-ns = <12>;
+ gpmc,adv-rd-off-ns = <48>;
+ gpmc,adv-wr-off-ns = <48>;
+ gpmc,oe-on-ns = <54>;
+ gpmc,oe-off-ns = <168>;
+ gpmc,we-on-ns = <54>;
+ gpmc,we-off-ns = <168>;
+ gpmc,rd-cycle-ns = <186>;
+ gpmc,wr-cycle-ns = <186>;
+ gpmc,access-ns = <114>;
+ gpmc,page-burst-access-ns = <6>;
+ gpmc,bus-turnaround-ns = <12>;
+ gpmc,cycle2cycle-delay-ns = <18>;
+ gpmc,wr-data-mux-bus-ns = <90>;
+ gpmc,wr-access-ns = <186>;
+ gpmc,cycle2cycle-samecsen;
+ gpmc,cycle2cycle-diffcsen;
+
+ partition@0 {
+ label = "bootloader-nor";
+ reg = <0 0x40000>;
+ };
+ partition@0x40000 {
+ label = "params-nor";
+ reg = <0x40000 0x40000>;
+ };
+ partition@0x80000 {
+ label = "kernel-nor";
+ reg = <0x80000 0x200000>;
+ };
+ partition@0x280000 {
+ label = "filesystem-nor";
+ reg = <0x240000 0x7d80000>;
+ };
+ };
+};
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index c127e75..80dd023 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -25,6 +25,11 @@
#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/mtd/nand.h>
#include <linux/platform_data/mtd-nand-omap2.h>
@@ -493,6 +498,37 @@ static int gpmc_cs_delete_mem(int cs)
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)
+ return -ENODEV;
+ 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;
+ gpmc_cs_enable_mem(cs, base, size);
+
+ return 0;
+}
+
int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
{
struct resource *res = &gpmc_cs_mem[cs];
@@ -1383,6 +1419,80 @@ static int gpmc_probe_onenand_child(struct platform_device *pdev,
}
#endif
+/**
+ * gpmc_probe_nor_child - configures the gpmc for a nor device
+ * @pdev: pointer to gpmc platform device
+ * @child: pointer to device-tree node for nor device
+ *
+ * Allocates and configures a GPMC chip-select for a NOR flash device.
+ * Returns 0 on success and appropriate negative error code on failure.
+ */
+static int gpmc_probe_nor_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;
+
+ 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;
+ }
+
+ /*
+ * 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 0x%x\n",
+ cs, res.start);
+ goto err;
+ }
+
+ gpmc_read_settings_dt(child, &gpmc_s);
+
+ 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)
+ goto err;
+
+ gpmc_read_timings_dt(child, &gpmc_t);
+ gpmc_cs_set_timings(cs, &gpmc_t);
+
+ if (of_platform_device_create(child, NULL, &pdev->dev))
+ return 0;
+
+ dev_err(&pdev->dev, "failed to create gpmc child %s\n", child->name);
+
+err:
+ gpmc_cs_free(cs);
+
+ return ret;
+}
+
static int gpmc_probe_dt(struct platform_device *pdev)
{
int ret;
@@ -1415,6 +1525,15 @@ static int gpmc_probe_dt(struct platform_device *pdev)
return ret;
}
}
+
+ for_each_node_by_name(child, "nor") {
+ ret = gpmc_probe_nor_child(pdev, child);
+ if (ret < 0) {
+ of_node_put(child);
+ return ret;
+ }
+ }
+
return 0;
}
#else
--
1.8.2.1