[target/xburst] level up target xburst to linux kernel version 3.2.1
[openwrt.git] / target / linux / xburst / patches-3.2 / 0006-MTD-NAND-JZ4740-Multi-bank-support-with-autodetectio.patch
1 From d5814bdb661d3dac61422f8f69e459be884c9a9d Mon Sep 17 00:00:00 2001
2 From: Maarten ter Huurne <maarten@treewalker.org>
3 Date: Tue, 2 Aug 2011 10:49:28 +0200
4 Subject: [PATCH 06/21] MTD: NAND: JZ4740: Multi-bank support with
5 autodetection
6
7 The platform data can now specify which external memory banks to probe
8 for NAND chips, and in which order. Banks that contain a NAND are used
9 and the other banks are freed.
10
11 Squashed version of development done in jz-2.6.38 branch.
12 Original patch by Lars-Peter Clausen with some bug fixes from me.
13 Thanks to Paul Cercueil for the initial autodetection patch.
14 ---
15 arch/mips/include/asm/mach-jz4740/jz4740_nand.h | 4 +
16 arch/mips/jz4740/platform.c | 20 ++-
17 drivers/mtd/nand/jz4740_nand.c | 228 +++++++++++++++++++----
18 3 files changed, 215 insertions(+), 37 deletions(-)
19
20 diff --git a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
21 index bb5b9a4..986982d 100644
22 --- a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
23 +++ b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
24 @@ -19,6 +19,8 @@
25 #include <linux/mtd/nand.h>
26 #include <linux/mtd/partitions.h>
27
28 +#define JZ_NAND_NUM_BANKS 4
29 +
30 struct jz_nand_platform_data {
31 int num_partitions;
32 struct mtd_partition *partitions;
33 @@ -27,6 +29,8 @@ struct jz_nand_platform_data {
34
35 unsigned int busy_gpio;
36
37 + unsigned char banks[JZ_NAND_NUM_BANKS];
38 +
39 void (*ident_callback)(struct platform_device *, struct nand_chip *,
40 struct mtd_partition **, int *num_partitions);
41 };
42 diff --git a/arch/mips/jz4740/platform.c b/arch/mips/jz4740/platform.c
43 index 10929e2..e342ed4 100644
44 --- a/arch/mips/jz4740/platform.c
45 +++ b/arch/mips/jz4740/platform.c
46 @@ -157,11 +157,29 @@ static struct resource jz4740_nand_resources[] = {
47 .flags = IORESOURCE_MEM,
48 },
49 {
50 - .name = "bank",
51 + .name = "bank1",
52 .start = 0x18000000,
53 .end = 0x180C0000 - 1,
54 .flags = IORESOURCE_MEM,
55 },
56 + {
57 + .name = "bank2",
58 + .start = 0x14000000,
59 + .end = 0x140C0000 - 1,
60 + .flags = IORESOURCE_MEM,
61 + },
62 + {
63 + .name = "bank3",
64 + .start = 0x0C000000,
65 + .end = 0x0C0C0000 - 1,
66 + .flags = IORESOURCE_MEM,
67 + },
68 + {
69 + .name = "bank4",
70 + .start = 0x08000000,
71 + .end = 0x080C0000 - 1,
72 + .flags = IORESOURCE_MEM,
73 + },
74 };
75
76 struct platform_device jz4740_nand_device = {
77 diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
78 index e266407..b254b99 100644
79 --- a/drivers/mtd/nand/jz4740_nand.c
80 +++ b/drivers/mtd/nand/jz4740_nand.c
81 @@ -52,9 +52,10 @@
82
83 #define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT((x) << 1)
84 #define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT(((x) << 1) + 1)
85 +#define JZ_NAND_CTRL_ASSERT_CHIP_MASK 0xaa
86
87 -#define JZ_NAND_MEM_ADDR_OFFSET 0x10000
88 #define JZ_NAND_MEM_CMD_OFFSET 0x08000
89 +#define JZ_NAND_MEM_ADDR_OFFSET 0x10000
90
91 struct jz_nand {
92 struct mtd_info mtd;
93 @@ -62,8 +63,11 @@ struct jz_nand {
94 void __iomem *base;
95 struct resource *mem;
96
97 - void __iomem *bank_base;
98 - struct resource *bank_mem;
99 + unsigned char banks[JZ_NAND_NUM_BANKS];
100 + void __iomem *bank_base[JZ_NAND_NUM_BANKS];
101 + struct resource *bank_mem[JZ_NAND_NUM_BANKS];
102 +
103 + int selected_bank;
104
105 struct jz_nand_platform_data *pdata;
106 bool is_reading;
107 @@ -74,26 +78,50 @@ static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd)
108 return container_of(mtd, struct jz_nand, mtd);
109 }
110
111 +static void jz_nand_select_chip(struct mtd_info *mtd, int chipnr)
112 +{
113 + struct jz_nand *nand = mtd_to_jz_nand(mtd);
114 + struct nand_chip *chip = mtd->priv;
115 + uint32_t ctrl;
116 + int banknr;
117 +
118 + ctrl = readl(nand->base + JZ_REG_NAND_CTRL);
119 + ctrl &= ~JZ_NAND_CTRL_ASSERT_CHIP_MASK;
120 +
121 + if (chipnr == -1) {
122 + banknr = -1;
123 + } else {
124 + banknr = nand->banks[chipnr] - 1;
125 + chip->IO_ADDR_R = nand->bank_base[banknr];
126 + chip->IO_ADDR_W = nand->bank_base[banknr];
127 + }
128 + writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
129 +
130 + nand->selected_bank = banknr;
131 +}
132 +
133 static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
134 {
135 struct jz_nand *nand = mtd_to_jz_nand(mtd);
136 struct nand_chip *chip = mtd->priv;
137 uint32_t reg;
138 + void __iomem *bank_base = nand->bank_base[nand->selected_bank];
139 +
140 + BUG_ON(nand->selected_bank < 0);
141
142 if (ctrl & NAND_CTRL_CHANGE) {
143 BUG_ON((ctrl & NAND_ALE) && (ctrl & NAND_CLE));
144 if (ctrl & NAND_ALE)
145 - chip->IO_ADDR_W = nand->bank_base + JZ_NAND_MEM_ADDR_OFFSET;
146 + bank_base += JZ_NAND_MEM_ADDR_OFFSET;
147 else if (ctrl & NAND_CLE)
148 - chip->IO_ADDR_W = nand->bank_base + JZ_NAND_MEM_CMD_OFFSET;
149 - else
150 - chip->IO_ADDR_W = nand->bank_base;
151 + bank_base += JZ_NAND_MEM_CMD_OFFSET;
152 + chip->IO_ADDR_W = bank_base;
153
154 reg = readl(nand->base + JZ_REG_NAND_CTRL);
155 if (ctrl & NAND_NCE)
156 - reg |= JZ_NAND_CTRL_ASSERT_CHIP(0);
157 + reg |= JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank);
158 else
159 - reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(0);
160 + reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank);
161 writel(reg, nand->base + JZ_REG_NAND_CTRL);
162 }
163 if (dat != NAND_CMD_NONE)
164 @@ -252,7 +280,7 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
165 }
166
167 static int jz_nand_ioremap_resource(struct platform_device *pdev,
168 - const char *name, struct resource **res, void __iomem **base)
169 + const char *name, struct resource **res, void *__iomem *base)
170 {
171 int ret;
172
173 @@ -288,6 +316,90 @@ err:
174 return ret;
175 }
176
177 +static inline void jz_nand_iounmap_resource(struct resource *res, void __iomem *base)
178 +{
179 + iounmap(base);
180 + release_mem_region(res->start, resource_size(res));
181 +}
182 +
183 +static int __devinit jz_nand_detect_bank(struct platform_device *pdev, struct jz_nand *nand, unsigned char bank, size_t chipnr, uint8_t *nand_maf_id, uint8_t *nand_dev_id) {
184 + int ret;
185 + int gpio;
186 + char gpio_name[9];
187 + char res_name[6];
188 + uint32_t ctrl;
189 + struct mtd_info *mtd = &nand->mtd;
190 + struct nand_chip *chip = &nand->chip;
191 +
192 + /* Request GPIO port. */
193 + gpio = JZ_GPIO_MEM_CS0 + bank - 1;
194 + sprintf(gpio_name, "NAND CS%d", bank);
195 + ret = gpio_request(gpio, gpio_name);
196 + if (ret) {
197 + dev_warn(&pdev->dev,
198 + "Failed to request %s gpio %d: %d\n",
199 + gpio_name, gpio, ret);
200 + goto notfound_gpio;
201 + }
202 +
203 + /* Request I/O resource. */
204 + sprintf(res_name, "bank%d", bank);
205 + ret = jz_nand_ioremap_resource(pdev, res_name,
206 + &nand->bank_mem[bank - 1],
207 + &nand->bank_base[bank - 1]);
208 + if (ret)
209 + goto notfound_resource;
210 +
211 + /* Enable chip in bank. */
212 + jz_gpio_set_function(gpio, JZ_GPIO_FUNC_MEM_CS0);
213 + ctrl = readl(nand->base + JZ_REG_NAND_CTRL);
214 + ctrl |= JZ_NAND_CTRL_ENABLE_CHIP(bank - 1);
215 + writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
216 +
217 + if (chipnr == 0) {
218 + /* Detect first chip. */
219 + ret = nand_scan_ident(mtd, 1, NULL);
220 + if (ret)
221 + goto notfound_id;
222 +
223 + /* Retrieve the IDs from the first chip. */
224 + chip->select_chip(mtd, 0);
225 + chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
226 + chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
227 + *nand_maf_id = chip->read_byte(mtd);
228 + *nand_dev_id = chip->read_byte(mtd);
229 + } else {
230 + /* Detect additional chip. */
231 + chip->select_chip(mtd, chipnr);
232 + chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
233 + chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
234 + if (*nand_maf_id != chip->read_byte(mtd)
235 + || *nand_dev_id != chip->read_byte(mtd)) {
236 + ret = -ENODEV;
237 + goto notfound_id;
238 + }
239 +
240 + /* Update size of the MTD. */
241 + chip->numchips++;
242 + mtd->size += chip->chipsize;
243 + }
244 +
245 + dev_info(&pdev->dev, "Found chip %i on bank %i\n", chipnr, bank);
246 + return 0;
247 +
248 +notfound_id:
249 + dev_info(&pdev->dev, "No chip found on bank %i\n", bank);
250 + ctrl &= ~(JZ_NAND_CTRL_ENABLE_CHIP(bank - 1));
251 + writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
252 + jz_gpio_set_function(gpio, JZ_GPIO_FUNC_NONE);
253 + jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
254 + nand->bank_base[bank - 1]);
255 +notfound_resource:
256 + gpio_free(gpio);
257 +notfound_gpio:
258 + return ret;
259 +}
260 +
261 static int __devinit jz_nand_probe(struct platform_device *pdev)
262 {
263 int ret;
264 @@ -295,6 +407,8 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
265 struct nand_chip *chip;
266 struct mtd_info *mtd;
267 struct jz_nand_platform_data *pdata = pdev->dev.platform_data;
268 + size_t chipnr, bank_idx;
269 + uint8_t nand_maf_id = 0, nand_dev_id = 0;
270
271 nand = kzalloc(sizeof(*nand), GFP_KERNEL);
272 if (!nand) {
273 @@ -305,10 +419,6 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
274 ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base);
275 if (ret)
276 goto err_free;
277 - ret = jz_nand_ioremap_resource(pdev, "bank", &nand->bank_mem,
278 - &nand->bank_base);
279 - if (ret)
280 - goto err_iounmap_mmio;
281
282 if (pdata && gpio_is_valid(pdata->busy_gpio)) {
283 ret = gpio_request(pdata->busy_gpio, "NAND busy pin");
284 @@ -316,7 +426,7 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
285 dev_err(&pdev->dev,
286 "Failed to request busy gpio %d: %d\n",
287 pdata->busy_gpio, ret);
288 - goto err_iounmap_mem;
289 + goto err_iounmap_mmio;
290 }
291 }
292
293 @@ -338,22 +448,51 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
294
295 chip->chip_delay = 50;
296 chip->cmd_ctrl = jz_nand_cmd_ctrl;
297 + chip->select_chip = jz_nand_select_chip;
298
299 if (pdata && gpio_is_valid(pdata->busy_gpio))
300 chip->dev_ready = jz_nand_dev_ready;
301
302 - chip->IO_ADDR_R = nand->bank_base;
303 - chip->IO_ADDR_W = nand->bank_base;
304 -
305 nand->pdata = pdata;
306 platform_set_drvdata(pdev, nand);
307
308 - writel(JZ_NAND_CTRL_ENABLE_CHIP(0), nand->base + JZ_REG_NAND_CTRL);
309 -
310 - ret = nand_scan_ident(mtd, 1, NULL);
311 - if (ret) {
312 - dev_err(&pdev->dev, "Failed to scan nand\n");
313 - goto err_gpio_free;
314 + /* We are going to autodetect NAND chips in the banks specified in the
315 + * platform data. Although nand_scan_ident() can detect multiple chips,
316 + * it requires those chips to be numbered consecuitively, which is not
317 + * always the case for external memory banks. And a fixed chip-to-bank
318 + * mapping is not practical either, since for example Dingoo units
319 + * produced at different times have NAND chips in different banks.
320 + */
321 + chipnr = 0;
322 + for (bank_idx = 0; bank_idx < JZ_NAND_NUM_BANKS; bank_idx++) {
323 + unsigned char bank;
324 +
325 + /* If there is no platform data, look for NAND in bank 1,
326 + * which is the most likely bank since it is the only one
327 + * that can be booted from.
328 + */
329 + bank = pdata ? pdata->banks[bank_idx] : bank_idx ^ 1;
330 + if (bank == 0)
331 + break;
332 + if (bank > JZ_NAND_NUM_BANKS) {
333 + dev_warn(&pdev->dev,
334 + "Skipping non-existing bank: %d\n", bank);
335 + continue;
336 + }
337 + /* The detection routine will directly or indirectly call
338 + * jz_nand_select_chip(), so nand->banks has to contain the
339 + * bank we're checking.
340 + */
341 + nand->banks[chipnr] = bank;
342 + if (jz_nand_detect_bank(pdev, nand, bank, chipnr,
343 + &nand_maf_id, &nand_dev_id) == 0)
344 + chipnr++;
345 + else
346 + nand->banks[chipnr] = 0;
347 + }
348 + if (chipnr == 0) {
349 + dev_err(&pdev->dev, "No NAND chips found\n");
350 + goto err_gpio_busy;
351 }
352
353 if (pdata && pdata->ident_callback) {
354 @@ -363,8 +502,8 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
355
356 ret = nand_scan_tail(mtd);
357 if (ret) {
358 - dev_err(&pdev->dev, "Failed to scan nand\n");
359 - goto err_gpio_free;
360 + dev_err(&pdev->dev, "Failed to scan NAND\n");
361 + goto err_unclaim_banks;
362 }
363
364 ret = mtd_device_parse_register(mtd, NULL, 0,
365 @@ -381,14 +520,21 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
366 return 0;
367
368 err_nand_release:
369 - nand_release(&nand->mtd);
370 -err_gpio_free:
371 + nand_release(mtd);
372 +err_unclaim_banks:
373 + while (chipnr--) {
374 + unsigned char bank = nand->banks[chipnr];
375 + gpio_free(JZ_GPIO_MEM_CS0 + bank - 1);
376 + jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
377 + nand->bank_base[bank - 1]);
378 + }
379 + writel(0, nand->base + JZ_REG_NAND_CTRL);
380 +err_gpio_busy:
381 + if (pdata && gpio_is_valid(pdata->busy_gpio))
382 + gpio_free(pdata->busy_gpio);
383 platform_set_drvdata(pdev, NULL);
384 - gpio_free(pdata->busy_gpio);
385 -err_iounmap_mem:
386 - iounmap(nand->bank_base);
387 err_iounmap_mmio:
388 - iounmap(nand->base);
389 + jz_nand_iounmap_resource(nand->mem, nand->base);
390 err_free:
391 kfree(nand);
392 return ret;
393 @@ -397,16 +543,26 @@ err_free:
394 static int __devexit jz_nand_remove(struct platform_device *pdev)
395 {
396 struct jz_nand *nand = platform_get_drvdata(pdev);
397 + struct jz_nand_platform_data *pdata = pdev->dev.platform_data;
398 + size_t i;
399
400 nand_release(&nand->mtd);
401
402 /* Deassert and disable all chips */
403 writel(0, nand->base + JZ_REG_NAND_CTRL);
404
405 - iounmap(nand->bank_base);
406 - release_mem_region(nand->bank_mem->start, resource_size(nand->bank_mem));
407 - iounmap(nand->base);
408 - release_mem_region(nand->mem->start, resource_size(nand->mem));
409 + for (i = 0; i < JZ_NAND_NUM_BANKS; ++i) {
410 + unsigned char bank = nand->banks[i];
411 + if (bank != 0) {
412 + jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
413 + nand->bank_base[bank - 1]);
414 + gpio_free(JZ_GPIO_MEM_CS0 + bank - 1);
415 + }
416 + }
417 + if (pdata && gpio_is_valid(pdata->busy_gpio))
418 + gpio_free(pdata->busy_gpio);
419 +
420 + jz_nand_iounmap_resource(nand->mem, nand->base);
421
422 platform_set_drvdata(pdev, NULL);
423 kfree(nand);
424 --
425 1.7.5.4
426
This page took 0.067618 seconds and 5 git commands to generate.