Date:2010-04-24 12:14:46 (12 years 5 months ago)
Author:Lars C.
Commit:7605fd125c7932323c6d1c6072d7639456d7936f
Message:Add jz4740 nand driver

Files: drivers/mtd/nand/Kconfig (1 diff)
drivers/mtd/nand/Makefile (1 diff)
drivers/mtd/nand/jz4740_nand.c (1 diff)
include/linux/mtd/jz4740_nand.h (1 diff)
include/mtd/mtd-abi.h (1 diff)

Change Details

drivers/mtd/nand/Kconfig
488488      This enables the driver for the NAND Flash on evaluation board based
489489      on w90p910.
490490
491config MTD_NAND_JZ4740
492    tristate "Support NAND Flash device on Jz4740 board"
493    depends on SOC_JZ4740
494    help
495    Support NAND Flash device on Jz4740 board
496
491497endif # MTD_NAND
drivers/mtd/nand/Makefile
4242obj-$(CONFIG_MTD_NAND_W90P910) += w90p910_nand.o
4343obj-$(CONFIG_MTD_NAND_NOMADIK) += nomadik_nand.o
4444obj-$(CONFIG_MTD_NAND_BCM_UMI) += bcm_umi_nand.o nand_bcm_umi.o
45obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
4546
4647nand-objs := nand_base.o nand_bbt.o
drivers/mtd/nand/jz4740_nand.c
1/*
2 * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4720/JZ4740 SoC NAND controller driver
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#include <linux/ioport.h>
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/platform_device.h>
20#include <linux/slab.h>
21
22#include <linux/mtd/mtd.h>
23#include <linux/mtd/nand.h>
24#include <linux/mtd/partitions.h>
25
26#include <linux/mtd/jz4740_nand.h>
27#include <linux/gpio.h>
28
29#define JZ_REG_NAND_CTRL 0x50
30#define JZ_REG_NAND_ECC_CTRL 0x100
31#define JZ_REG_NAND_DATA 0x104
32#define JZ_REG_NAND_PAR0 0x108
33#define JZ_REG_NAND_PAR1 0x10C
34#define JZ_REG_NAND_PAR2 0x110
35#define JZ_REG_NAND_IRQ_STAT 0x114
36#define JZ_REG_NAND_IRQ_CTRL 0x118
37#define JZ_REG_NAND_ERR(x) (0x11C + (x << 2))
38
39#define JZ_NAND_ECC_CTRL_PAR_READY BIT(4)
40#define JZ_NAND_ECC_CTRL_ENCODING BIT(3)
41#define JZ_NAND_ECC_CTRL_RS BIT(2)
42#define JZ_NAND_ECC_CTRL_RESET BIT(1)
43#define JZ_NAND_ECC_CTRL_ENABLE BIT(0)
44
45#define JZ_NAND_STATUS_ERR_COUNT (BIT(31) | BIT(30) | BIT(29))
46#define JZ_NAND_STATUS_PAD_FINISH BIT(4)
47#define JZ_NAND_STATUS_DEC_FINISH BIT(3)
48#define JZ_NAND_STATUS_ENC_FINISH BIT(2)
49#define JZ_NAND_STATUS_UNCOR_ERROR BIT(1)
50#define JZ_NAND_STATUS_ERROR BIT(0)
51
52#define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT(x << 1)
53#define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT((x << 1) + 1)
54
55#define JZ_NAND_DATA_ADDR ((void __iomem *)0xB8000000)
56#define JZ_NAND_CMD_ADDR (JZ_NAND_DATA_ADDR + 0x8000)
57#define JZ_NAND_ADDR_ADDR (JZ_NAND_DATA_ADDR + 0x10000)
58
59struct jz_nand {
60    struct mtd_info mtd;
61    struct nand_chip chip;
62    void __iomem *base;
63    struct resource *mem;
64
65    struct jz_nand_platform_data *pdata;
66    bool is_reading;
67};
68
69static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd)
70{
71    return container_of(mtd, struct jz_nand, mtd);
72}
73
74static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
75{
76    struct jz_nand *nand = mtd_to_jz_nand(mtd);
77    struct nand_chip *chip = mtd->priv;
78    uint32_t reg;
79
80    if (ctrl & NAND_CTRL_CHANGE) {
81        BUG_ON((ctrl & NAND_ALE) && (ctrl & NAND_CLE));
82        if (ctrl & NAND_ALE)
83            chip->IO_ADDR_W = JZ_NAND_ADDR_ADDR;
84        else if (ctrl & NAND_CLE)
85            chip->IO_ADDR_W = JZ_NAND_CMD_ADDR;
86        else
87            chip->IO_ADDR_W = JZ_NAND_DATA_ADDR;
88
89        reg = readl(nand->base + JZ_REG_NAND_CTRL);
90        if (ctrl & NAND_NCE)
91            reg |= JZ_NAND_CTRL_ASSERT_CHIP(0);
92        else
93            reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(0);
94        writel(reg, nand->base + JZ_REG_NAND_CTRL);
95    }
96    if (dat != NAND_CMD_NONE)
97        writeb(dat, chip->IO_ADDR_W);
98}
99
100static int jz_nand_dev_ready(struct mtd_info *mtd)
101{
102    struct jz_nand *nand = mtd_to_jz_nand(mtd);
103    return gpio_get_value_cansleep(nand->pdata->busy_gpio);
104}
105
106static void jz_nand_hwctl(struct mtd_info *mtd, int mode)
107{
108    struct jz_nand *nand = mtd_to_jz_nand(mtd);
109    uint32_t reg;
110
111
112    writel(0, nand->base + JZ_REG_NAND_IRQ_STAT);
113    reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
114
115    reg |= JZ_NAND_ECC_CTRL_RESET;
116    reg |= JZ_NAND_ECC_CTRL_ENABLE;
117    reg |= JZ_NAND_ECC_CTRL_RS;
118
119    switch (mode) {
120    case NAND_ECC_READ:
121        reg &= ~JZ_NAND_ECC_CTRL_ENCODING;
122        nand->is_reading = true;
123        break;
124    case NAND_ECC_WRITE:
125        reg |= JZ_NAND_ECC_CTRL_ENCODING;
126        nand->is_reading = false;
127        break;
128    default:
129        break;
130    }
131
132    writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
133}
134
135
136static int jz_nand_calculate_ecc_rs(struct mtd_info* mtd, const uint8_t *dat,
137                    uint8_t *ecc_code)
138{
139    struct jz_nand *nand = mtd_to_jz_nand(mtd);
140    uint32_t reg, status;
141    int i;
142    static uint8_t empty_block_ecc[] = {0xcd, 0x9d, 0x90, 0x58, 0xf4,
143                        0x8b, 0xff, 0xb7, 0x6f};
144
145    if (nand->is_reading)
146        return 0;
147
148    do {
149        status = readl(nand->base + JZ_REG_NAND_IRQ_STAT);
150    } while (!(status & JZ_NAND_STATUS_ENC_FINISH));
151
152    reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
153    reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
154    writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
155
156    for (i = 0; i < 9; ++i)
157        ecc_code[i] = readb(nand->base + JZ_REG_NAND_PAR0 + i);
158
159    /* If the written data is completly 0xff, we also want to write 0xff as
160     * ecc, otherwise we will get in trouble when doing subpage writes. */
161    if (memcmp(ecc_code, empty_block_ecc, 9) == 0)
162        memset(ecc_code, 0xff, 9);
163
164    return 0;
165}
166
167/*#define printkd printk*/
168#define printkd(...)
169
170static void correct_data(uint8_t *dat, int index, int mask)
171{
172    int offset = index & 0x7;
173    uint16_t data;
174    printkd("correct: ");
175
176    index += (index >> 3);
177
178    data = dat[index];
179    data |= dat[index+1] << 8;
180
181    printkd("0x%x -> ", data);
182
183    mask ^= (data >> offset) & 0x1ff;
184    data &= ~(0x1ff << offset);
185    data |= (mask << offset);
186
187    printkd("0x%x\n", data);
188
189    dat[index] = data & 0xff;
190    dat[index+1] = (data >> 8) & 0xff;
191}
192
193static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
194                  uint8_t *read_ecc, uint8_t *calc_ecc)
195{
196    struct jz_nand *nand = mtd_to_jz_nand(mtd);
197    int i, error_count, index;
198    uint32_t reg, status, error;
199    uint32_t t;
200
201    t = read_ecc[0];
202
203    if (t == 0xff) {
204        for (i = 1; i < 9; ++i)
205            t &= read_ecc[i];
206
207        t &= dat[0];
208        t &= dat[nand->chip.ecc.size / 2];
209        t &= dat[nand->chip.ecc.size - 1];
210
211        if (t == 0xff) {
212            for (i = 1; i < nand->chip.ecc.size - 1; ++i)
213                t &= dat[i];
214            if (t == 0xff)
215                return 0;
216        }
217    }
218
219    for (i = 0; i < 9; ++i)
220        writeb(read_ecc[i], nand->base + JZ_REG_NAND_PAR0 + i);
221
222    reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
223    reg |= JZ_NAND_ECC_CTRL_PAR_READY;
224    writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
225
226    do {
227        status = readl(nand->base + JZ_REG_NAND_IRQ_STAT);
228    } while (!(status & JZ_NAND_STATUS_DEC_FINISH));
229
230    reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
231    reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
232    writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
233
234    if (status & JZ_NAND_STATUS_ERROR) {
235        if (status & JZ_NAND_STATUS_UNCOR_ERROR) {
236            printkd("uncorrectable ecc:");
237            for (i = 0; i < 9; ++i)
238                printkd(" 0x%x", read_ecc[i]);
239            printkd("\n");
240            printkd("uncorrectable data:");
241            for (i = 0; i < 32; ++i)
242                printkd(" 0x%x", dat[i]);
243            printkd("\n");
244            return -1;
245        }
246
247        error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29;
248
249        printkd("error_count: %d %x\n", error_count, status);
250
251        for (i = 0; i < error_count; ++i) {
252            error = readl(nand->base + JZ_REG_NAND_ERR(i));
253            index = ((error >> 16) & 0x1ff) - 1;
254            if (index >= 0 && index < 512)
255                correct_data(dat, index, error & 0x1ff);
256        }
257
258        return error_count;
259    }
260
261    return 0;
262}
263
264
265
266#ifdef CONFIG_MTD_CMDLINE_PARTS
267static const char *part_probes[] = {"cmdline", NULL};
268#endif
269
270static int __devinit jz_nand_probe(struct platform_device *pdev)
271{
272    int ret;
273    struct jz_nand *nand;
274    struct nand_chip *chip;
275    struct mtd_info *mtd;
276    struct jz_nand_platform_data *pdata = pdev->dev.platform_data;
277#ifdef CONFIG_MTD_PARTITIONS
278    struct mtd_partition *partition_info;
279    int num_partitions = 0;
280#endif
281
282    nand = kzalloc(sizeof(*nand), GFP_KERNEL);
283    if (!nand) {
284        dev_err(&pdev->dev, "Failed to allocate device structure.\n");
285        return -ENOMEM;
286    }
287
288    nand->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
289    if (!nand->mem) {
290        dev_err(&pdev->dev, "Failed to get platform mmio memory\n");
291        ret = -ENOENT;
292        goto err_free;
293    }
294
295    nand->mem = request_mem_region(nand->mem->start,
296                    resource_size(nand->mem), pdev->name);
297
298    if (!nand->mem) {
299        dev_err(&pdev->dev, "Failed to request mmio memory region\n");
300        ret = -EBUSY;
301        goto err_free;
302    }
303
304    nand->base = ioremap(nand->mem->start, resource_size(nand->mem));
305
306    if (!nand->base) {
307        dev_err(&pdev->dev, "Failed to ioremap mmio memory region\n");
308        ret = -EBUSY;
309        goto err_release_mem;
310    }
311
312    if (pdata && gpio_is_valid(pdata->busy_gpio)) {
313        ret = gpio_request(pdata->busy_gpio, "NAND busy pin");
314        if (ret) {
315            dev_err(&pdev->dev,
316                "Failed to request busy gpio %d: %d\n",
317                pdata->busy_gpio, ret);
318            goto err_iounmap;
319        }
320    }
321
322    mtd = &nand->mtd;
323    chip = &nand->chip;
324    mtd->priv = chip;
325    mtd->owner = THIS_MODULE;
326    mtd->name = "jz4740-nand";
327
328    chip->ecc.hwctl = jz_nand_hwctl;
329
330    chip->ecc.calculate = jz_nand_calculate_ecc_rs;
331    chip->ecc.correct = jz_nand_correct_ecc_rs;
332    chip->ecc.mode = NAND_ECC_HW_OOB_FIRST;
333    chip->ecc.size = 512;
334    chip->ecc.bytes = 9;
335    if (pdata)
336        chip->ecc.layout = pdata->ecc_layout;
337
338    chip->chip_delay = 50;
339    chip->cmd_ctrl = jz_nand_cmd_ctrl;
340
341    if (pdata && gpio_is_valid(pdata->busy_gpio))
342        chip->dev_ready = jz_nand_dev_ready;
343
344    chip->IO_ADDR_R = JZ_NAND_DATA_ADDR;
345    chip->IO_ADDR_W = JZ_NAND_DATA_ADDR;
346
347    nand->pdata = pdata;
348    platform_set_drvdata(pdev, nand);
349
350    ret = nand_scan_ident(mtd, 1);
351    if (ret) {
352        dev_err(&pdev->dev, "Failed to scan nand\n");
353        goto err_gpio_free;
354    }
355
356    if (pdata && pdata->ident_callback) {
357        pdata->ident_callback(pdev, chip, &pdata->partitions,
358                    &pdata->num_partitions);
359    }
360
361    ret = nand_scan_tail(mtd);
362    if (ret) {
363        dev_err(&pdev->dev, "Failed to scan nand\n");
364        goto err_gpio_free;
365    }
366
367#ifdef CONFIG_MTD_PARTITIONS
368#ifdef CONFIG_MTD_CMDLINE_PARTS
369    num_partitions = parse_mtd_partitions(mtd, part_probes,
370                        &partition_info, 0);
371#endif
372    if (num_partitions <= 0 && pdata) {
373        num_partitions = pdata->num_partitions;
374        partition_info = pdata->partitions;
375    }
376
377    if (num_partitions > 0)
378        ret = add_mtd_partitions(mtd, partition_info, num_partitions);
379    else
380#endif
381    ret = add_mtd_device(mtd);
382
383    if (ret) {
384        dev_err(&pdev->dev, "Failed to add mtd device\n");
385        goto err_nand_release;
386    }
387
388    dev_info(&pdev->dev, "Successfully registered JZ4740 NAND driver\n");
389
390    return 0;
391err_nand_release:
392    nand_release(&nand->mtd);
393err_gpio_free:
394    platform_set_drvdata(pdev, NULL);
395    gpio_free(pdata->busy_gpio);
396err_iounmap:
397    iounmap(nand->base);
398err_release_mem:
399    release_mem_region(nand->mem->start, resource_size(nand->mem));
400err_free:
401    kfree(nand);
402    return ret;
403}
404
405static void __devexit jz_nand_remove(struct platform_device *pdev)
406{
407    struct jz_nand *nand = platform_get_drvdata(pdev);
408
409    nand_release(&nand->mtd);
410
411    iounmap(nand->base);
412
413    release_mem_region(nand->mem->start, resource_size(nand->mem));
414
415    platform_set_drvdata(pdev, NULL);
416    kfree(nand);
417}
418
419struct platform_driver jz_nand_driver = {
420    .probe = jz_nand_probe,
421    .remove = __devexit_p(jz_nand_probe),
422    .driver = {
423        .name = "jz4740-nand",
424        .owner = THIS_MODULE,
425    },
426};
427
428static int __init jz_nand_init(void)
429{
430    return platform_driver_register(&jz_nand_driver);
431}
432module_init(jz_nand_init);
433
434static void __exit jz_nand_exit(void)
435{
436    platform_driver_unregister(&jz_nand_driver);
437}
438module_exit(jz_nand_exit);
439
440MODULE_LICENSE("GPL");
441MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
442MODULE_DESCRIPTION("NAND controller driver for JZ4720/JZ4740 SoC");
443MODULE_ALIAS("platform:jz4740-nand");
444MODULE_ALIAS("platform:jz4720-nand");
include/linux/mtd/jz4740_nand.h
1/*
2 * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4720/JZ4740 SoC NAND controller driver
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#ifndef __JZ_NAND_H__
17#define __JZ_NAND_H__
18
19#include <linux/mtd/nand.h>
20#include <linux/mtd/partitions.h>
21
22struct jz_nand_platform_data {
23    int num_partitions;
24    struct mtd_partition *partitions;
25
26    struct nand_ecclayout *ecc_layout;
27
28    unsigned int busy_gpio;
29
30    void (*ident_callback)(struct platform_device *, struct nand_chip *,
31                struct mtd_partition **, int *num_partitions);
32};
33
34#endif
include/mtd/mtd-abi.h
134134 */
135135struct nand_ecclayout {
136136    __u32 eccbytes;
137    __u32 eccpos[64];
137    __u32 eccpos[72];
138138    __u32 oobavail;
139139    struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
140140};

Archive Download the corresponding diff file



interactive