Date:2011-03-06 21:40:10 (9 years 2 months ago)
Author:Peter Zotov
Commit:8786de52702888b95da904e5cccc5b754bf5f4ff
Message:Add JZ4750 NAND driver.

Files: arch/mips/include/asm/mach-jz47xx/base.h (1 diff)
arch/mips/include/asm/mach-jz47xx/jz4750/platform.h (1 diff)
arch/mips/include/asm/mach-jz47xx/jz4750_nand.h (1 diff)
arch/mips/jz47xx/jz4750/platform.c (1 diff)
drivers/mtd/nand/Kconfig (1 diff)
drivers/mtd/nand/Makefile (1 diff)
drivers/mtd/nand/jz4750_nand.c (1 diff)

Change Details

arch/mips/include/asm/mach-jz47xx/base.h
2525#define JZ47XX_SLCD_BASE_ADDR 0x13050000
2626#define JZ47XX_CIM_BASE_ADDR 0x13060000
2727#define JZ47XX_IPU_BASE_ADDR 0x13080000
28#define JZ47XX_BCH_BASE_ADDR 0x130D0000
2829
2930#endif
arch/mips/include/asm/mach-jz47xx/jz4750/platform.h
2020
2121extern struct platform_device jz4750_rtc_device;
2222extern struct platform_device jz4750_udc_device;
23extern struct platform_device jz4750_nand_device;
2324
2425void jz4750_serial_device_register(void);
2526
arch/mips/include/asm/mach-jz47xx/jz4750_nand.h
1/*
2 * Copyright (C) 2011, Peter Zotov <whitequark@whitequark.org>
3 * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
4 * JZ4750 SoC NAND controller driver
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 *
11 * You should have received a copy of the GNU General Public License along
12 * with this program; if not, write to the Free Software Foundation, Inc.,
13 * 675 Mass Ave, Cambridge, MA 02139, USA.
14 *
15 */
16
17#ifndef __ASM_MACH_JZ4750_NAND_H__
18#define __ASM_MACH_JZ4750_NAND_H__
19
20#include <linux/mtd/nand.h>
21#include <linux/mtd/partitions.h>
22
23struct jz_nand_platform_data {
24    int num_partitions;
25    struct mtd_partition *partitions;
26
27    bool bch_8bit;
28    struct nand_ecclayout *ecc_layout;
29
30    unsigned int busy_gpio;
31
32    void (*ident_callback)(struct platform_device *, struct nand_chip *,
33                struct mtd_partition **, int *num_partitions);
34};
35
36#endif
arch/mips/jz47xx/jz4750/platform.c
5757    .resource = jz4750_usb_gdt_resources,
5858};
5959
60/* NAND controller */
61static struct resource jz4750_nand_resources[] = {
62    {
63        .name = "mmio",
64        .start = JZ47XX_EMC_BASE_ADDR,
65        .end = JZ47XX_EMC_BASE_ADDR + 0x1000 - 1,
66        .flags = IORESOURCE_MEM,
67    },
68    {
69        .name = "bch",
70        .start = JZ47XX_BCH_BASE_ADDR,
71        .end = JZ47XX_BCH_BASE_ADDR + 0x40 - 1,
72        .flags = IORESOURCE_MEM,
73    },
74    {
75        .name = "bank",
76        .start = 0x18000000,
77        .end = 0x180C0000 - 1,
78        .flags = IORESOURCE_MEM,
79    },
80};
81
82struct platform_device jz4750_nand_device = {
83    .name = "jz4750-nand",
84    .num_resources = ARRAY_SIZE(jz4750_nand_resources),
85    .resource = jz4750_nand_resources,
86};
6087
6188/* RTC controller */
6289static struct resource jz4750_rtc_resources[] = {
drivers/mtd/nand/Kconfig
525525    help
526526        Enables support for NAND Flash on JZ4740 SoC based boards.
527527
528config MTD_NAND_JZ4750
529    tristate "Support for JZ4750 SoC NAND controller"
530    depends on MACH_JZ4750
531    help
532        Enables support for NAND Flash on JZ4750 SoC based boards.
533
528534config MTD_NAND_FSMC
529535    tristate "Support for NAND on ST Micros FSMC"
530536    depends on PLAT_SPEAR || PLAT_NOMADIK || MACH_U300
drivers/mtd/nand/Makefile
4848obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o
4949obj-$(CONFIG_MTD_NAND_RICOH) += r852.o
5050obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
51obj-$(CONFIG_MTD_NAND_JZ4750) += jz4750_nand.o
5152
5253nand-objs := nand_base.o nand_bbt.o
drivers/mtd/nand/jz4750_nand.c
1/*
2 * Copyright (c) 2011 Peter Zotov <whitequark@whitequark.org>
3 * JZ4750 SoC NAND controller driver
4 *
5 * Based on JZ4740 NAND controller driver,
6 * (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 675 Mass Ave, Cambridge, MA 02139, USA.
16 *
17 */
18
19#include <linux/ioport.h>
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/platform_device.h>
23#include <linux/slab.h>
24
25#include <linux/mtd/mtd.h>
26#include <linux/mtd/nand.h>
27#include <linux/mtd/partitions.h>
28
29#include <linux/gpio.h>
30
31#include <jz4750_nand.h>
32
33#define JZ_REG_NAND_CTRL 0x50
34
35#define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT((x) << 1)
36#define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT(((x) << 1) + 1)
37
38#define JZ_NAND_MEM_ADDR_OFFSET 0x10000
39#define JZ_NAND_MEM_CMD_OFFSET 0x08000
40
41#define JZ_REG_BCH_CR 0x00
42#define JZ_REG_BCH_CR_SET 0x04
43#define JZ_REG_BCH_CR_CLR 0x08
44#define JZ_REG_BCH_CNT 0x0C
45#define JZ_REG_BCH_DR 0x10
46#define JZ_REG_BCH_PAR(i) (0x14 + (i))
47#define JZ_REG_BCH_STATUS 0x24
48#define JZ_REG_BCH_ERR(i) (0x28 + ((i) << 2))
49
50#define JZ_BCH_ENABLE BIT(0)
51#define JZ_BCH_RESET BIT(1)
52#define JZ_BCH_8BIT BIT(2)
53#define JZ_BCH_ENCODE BIT(3)
54#define JZ_BCH_USE_DMA BIT(4)
55
56#define JZ_BCH_STATUS_ERROR BIT(0)
57#define JZ_BCH_STATUS_UNCOR BIT(1)
58#define JZ_BCH_STATUS_ENC_FINISH BIT(2)
59#define JZ_BCH_STATUS_DEC_FINISH BIT(3)
60#define JZ_BCH_STATUS_ALL_F BIT(4)
61#define JZ_BCH_STATUS_ALL_0 BIT(5)
62#define JZ_BCH_STATUS_ERR_COUNT 0xf0000000
63
64struct jz_nand {
65    struct mtd_info mtd;
66    struct nand_chip chip;
67    void __iomem *base;
68    struct resource *mem;
69
70    void __iomem *bank_base;
71    struct resource *bank_mem;
72
73    void __iomem *bch_base;
74    struct resource *bch_mem;
75
76    struct jz_nand_platform_data *pdata;
77    bool is_reading;
78};
79
80static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd)
81{
82    return container_of(mtd, struct jz_nand, mtd);
83}
84
85static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
86{
87    struct jz_nand *nand = mtd_to_jz_nand(mtd);
88    struct nand_chip *chip = mtd->priv;
89    uint32_t reg;
90
91    if (ctrl & NAND_CTRL_CHANGE) {
92        BUG_ON((ctrl & NAND_ALE) && (ctrl & NAND_CLE));
93
94        if (ctrl & NAND_ALE)
95            chip->IO_ADDR_W = nand->bank_base + JZ_NAND_MEM_ADDR_OFFSET;
96        else if (ctrl & NAND_CLE)
97            chip->IO_ADDR_W = nand->bank_base + JZ_NAND_MEM_CMD_OFFSET;
98        else
99            chip->IO_ADDR_W = nand->bank_base;
100
101        reg = readl(nand->base + JZ_REG_NAND_CTRL);
102        if (ctrl & NAND_NCE)
103            reg |= JZ_NAND_CTRL_ASSERT_CHIP(0);
104        else
105            reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(0);
106        writel(reg, nand->base + JZ_REG_NAND_CTRL);
107    }
108
109    if (dat != NAND_CMD_NONE)
110        writeb(dat, chip->IO_ADDR_W);
111}
112
113static int jz_nand_dev_ready(struct mtd_info *mtd)
114{
115    struct jz_nand *nand = mtd_to_jz_nand(mtd);
116    return gpio_get_value_cansleep(nand->pdata->busy_gpio);
117}
118
119static void jz_nand_hwctl(struct mtd_info *mtd, int mode)
120{
121    struct jz_nand *nand = mtd_to_jz_nand(mtd);
122
123    /* While BCH_CR register is defined as RW in manual, it is
124     * not true. It can only be modified through BCH_CR_SET and
125     * BCH_CR_CLR registers.
126     */
127    if (nand->pdata->bch_8bit)
128        writel(JZ_BCH_8BIT, nand->bch_base + JZ_REG_BCH_CR_SET);
129    else
130        writel(JZ_BCH_8BIT, nand->bch_base + JZ_REG_BCH_CR_CLR);
131
132    switch (mode) {
133    case NAND_ECC_READ:
134        writel(JZ_BCH_ENCODE, nand->bch_base + JZ_REG_BCH_CR_CLR);
135        nand->is_reading = true;
136        break;
137    case NAND_ECC_WRITE:
138        writel(JZ_BCH_ENCODE, nand->bch_base + JZ_REG_BCH_CR_SET);
139        nand->is_reading = false;
140        break;
141    default:
142        break;
143    }
144}
145
146static int jz_nand_calculate_ecc_bch(struct mtd_info *mtd, const uint8_t *dat,
147    uint8_t *ecc_code)
148{
149    struct jz_nand *nand = mtd_to_jz_nand(mtd);
150    uint32_t status;
151    int i;
152    unsigned int timeout = 1000;
153
154    int size = nand->chip.ecc.size,
155        bytes = nand->chip.ecc.bytes;
156
157    if (nand->is_reading)
158        return 0;
159
160    writel(JZ_BCH_ENABLE, nand->bch_base + JZ_REG_BCH_CR_SET);
161    writel(JZ_BCH_RESET, nand->bch_base + JZ_REG_BCH_CR_SET);
162
163    writel(size & 0xffff, nand->bch_base + JZ_REG_BCH_CNT);
164
165    for(i = 0; i < size; i++)
166        writeb(dat[i], nand->bch_base + JZ_REG_BCH_DR);
167
168    do {
169        status = readl(nand->bch_base + JZ_REG_BCH_STATUS);
170    } while (!(status & JZ_BCH_STATUS_ENC_FINISH) && --timeout);
171
172    writel(JZ_BCH_ENABLE, nand->bch_base + JZ_REG_BCH_CR_CLR);
173
174    if (timeout == 0)
175        return -1;
176
177    for(i = 0; i < bytes; i++)
178        ecc_code[i] = readb(nand->bch_base + JZ_REG_BCH_PAR(i));
179
180    return 0;
181}
182
183static int jz_nand_correct_ecc_bch(struct mtd_info *mtd, uint8_t *dat,
184    uint8_t *read_ecc, uint8_t *calc_ecc)
185{
186    struct jz_nand *nand = mtd_to_jz_nand(mtd);
187    int i, error_count;
188    uint32_t status, error_regs[4];
189    uint16_t *error_indexes, index;
190    unsigned int timeout = 1000;
191
192    int size = nand->chip.ecc.size,
193        bytes = nand->chip.ecc.bytes;
194
195    writel(JZ_BCH_ENABLE, nand->bch_base + JZ_REG_BCH_CR_SET);
196    writel(JZ_BCH_RESET, nand->bch_base + JZ_REG_BCH_CR_SET);
197
198    /* Clear status bits */
199    writel(0xff, nand->bch_base + JZ_REG_BCH_STATUS);
200
201    writel((size + bytes) << 16, nand->bch_base + JZ_REG_BCH_CNT);
202
203    for (i = 0; i < size; i++)
204        writeb(dat[i], nand->bch_base + JZ_REG_BCH_DR);
205
206    for (i = 0; i < bytes; i++)
207        writeb(read_ecc[i], nand->bch_base + JZ_REG_BCH_DR);
208
209    do {
210        status = readl(nand->bch_base + JZ_REG_BCH_STATUS);
211    } while (!(status & JZ_BCH_STATUS_DEC_FINISH) && --timeout);
212
213    writel(JZ_BCH_ENABLE, nand->bch_base + JZ_REG_BCH_CR_CLR);
214
215    if (timeout == 0)
216        return -1;
217
218    if (status & JZ_BCH_STATUS_ERROR) {
219        if (status & JZ_BCH_STATUS_UNCOR)
220            return -1;
221
222        for(i = 0; i < 4; i++)
223            error_regs[i] = readl(nand->bch_base + JZ_REG_BCH_ERR(i));
224
225        /* All Ingenic processors are little-endian */
226        error_indexes = (uint16_t*) error_regs;
227
228        error_count = (status & JZ_BCH_STATUS_ERR_COUNT) >> 28;
229
230        for (i = 0; i < error_count; i++) {
231            index = error_indexes[i];
232
233            if (index < size)
234                dat[index >> 3] ^= (1 << (index & 0x7));
235        }
236
237        return error_count;
238    }
239
240    return 0;
241}
242
243#ifdef CONFIG_MTD_CMDLINE_PARTS
244static const char *part_probes[] = {"cmdline", NULL};
245#endif
246
247static int jz_nand_ioremap_resource(struct platform_device *pdev,
248    const char *name, struct resource **res, void __iomem **base)
249{
250    int ret;
251
252    *res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
253    if (!*res) {
254        dev_err(&pdev->dev, "Failed to get platform %s memory\n", name);
255        ret = -ENXIO;
256        goto err;
257    }
258
259    *res = request_mem_region((*res)->start, resource_size(*res),
260                pdev->name);
261    if (!*res) {
262        dev_err(&pdev->dev, "Failed to request %s memory region\n", name);
263        ret = -EBUSY;
264        goto err;
265    }
266
267    *base = ioremap((*res)->start, resource_size(*res));
268    if (!*base) {
269        dev_err(&pdev->dev, "Failed to ioremap %s memory region\n", name);
270        ret = -EBUSY;
271        goto err_release_mem;
272    }
273
274    return 0;
275
276err_release_mem:
277    release_mem_region((*res)->start, resource_size(*res));
278err:
279    *res = NULL;
280    *base = NULL;
281    return ret;
282}
283
284static int __devinit jz_nand_probe(struct platform_device *pdev)
285{
286    int ret;
287    struct jz_nand *nand;
288    struct nand_chip *chip;
289    struct mtd_info *mtd;
290    struct jz_nand_platform_data *pdata = pdev->dev.platform_data;
291#ifdef CONFIG_MTD_PARTITIONS
292    struct mtd_partition *partition_info;
293    int num_partitions = 0;
294#endif
295
296    nand = kzalloc(sizeof(*nand), GFP_KERNEL);
297    if (!nand) {
298        dev_err(&pdev->dev, "Failed to allocate device structure.\n");
299        return -ENOMEM;
300    }
301
302    ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base);
303    if (ret)
304        goto err_free;
305
306    ret = jz_nand_ioremap_resource(pdev, "bank", &nand->bank_mem,
307            &nand->bank_base);
308    if (ret)
309        goto err_iounmap_mmio;
310
311    ret = jz_nand_ioremap_resource(pdev, "bch", &nand->bch_mem,
312            &nand->bch_base);
313    if (ret)
314        goto err_iounmap_bank;
315
316    if (pdata && gpio_is_valid(pdata->busy_gpio)) {
317        ret = gpio_request(pdata->busy_gpio, "NAND busy pin");
318        if (ret) {
319            dev_err(&pdev->dev,
320                "Failed to request busy gpio %d: %d\n",
321                pdata->busy_gpio, ret);
322            goto err_iounmap_bch;
323        }
324    }
325
326    mtd = &nand->mtd;
327    chip = &nand->chip;
328    mtd->priv = chip;
329    mtd->owner = THIS_MODULE;
330    mtd->name = "jz4750-nand";
331
332    chip->ecc.hwctl = jz_nand_hwctl;
333    chip->ecc.calculate = jz_nand_calculate_ecc_bch;
334    chip->ecc.correct = jz_nand_correct_ecc_bch;
335    chip->ecc.mode = NAND_ECC_HW;
336    chip->ecc.size = 512;
337    chip->ecc.bytes = 13;
338
339    if (pdata)
340        chip->ecc.layout = pdata->ecc_layout;
341
342    chip->chip_delay = 50;
343    chip->cmd_ctrl = jz_nand_cmd_ctrl;
344
345    if (pdata && gpio_is_valid(pdata->busy_gpio))
346        chip->dev_ready = jz_nand_dev_ready;
347
348    chip->IO_ADDR_R = nand->bank_base;
349    chip->IO_ADDR_W = nand->bank_base;
350
351    nand->pdata = pdata;
352    platform_set_drvdata(pdev, nand);
353
354    writel(JZ_NAND_CTRL_ENABLE_CHIP(0), nand->base + JZ_REG_NAND_CTRL);
355
356    ret = nand_scan_ident(mtd, 1, NULL);
357    if (ret) {
358        dev_err(&pdev->dev, "Failed to scan nand\n");
359        goto err_gpio_free;
360    }
361
362    if (pdata && pdata->ident_callback) {
363        pdata->ident_callback(pdev, chip, &pdata->partitions,
364                    &pdata->num_partitions);
365    }
366
367    ret = nand_scan_tail(mtd);
368    if (ret) {
369        dev_err(&pdev->dev, "Failed to scan nand\n");
370        goto err_gpio_free;
371    }
372
373#ifdef CONFIG_MTD_PARTITIONS
374#ifdef CONFIG_MTD_CMDLINE_PARTS
375    num_partitions = parse_mtd_partitions(mtd, part_probes,
376                        &partition_info, 0);
377#endif
378    if (num_partitions <= 0 && pdata) {
379        num_partitions = pdata->num_partitions;
380        partition_info = pdata->partitions;
381    }
382
383    if (num_partitions > 0)
384        ret = add_mtd_partitions(mtd, partition_info, num_partitions);
385    else
386#endif
387    ret = add_mtd_device(mtd);
388
389    if (ret) {
390        dev_err(&pdev->dev, "Failed to add mtd device\n");
391        goto err_nand_release;
392    }
393
394    dev_info(&pdev->dev, "Successfully registered JZ4750 NAND driver\n");
395
396    return 0;
397
398err_nand_release:
399    nand_release(&nand->mtd);
400err_gpio_free:
401    platform_set_drvdata(pdev, NULL);
402    gpio_free(pdata->busy_gpio);
403err_iounmap_bch:
404    iounmap(nand->bch_base);
405    release_mem_region(nand->bch_mem->start, resource_size(nand->bch_mem));
406err_iounmap_bank:
407    iounmap(nand->bank_base);
408    release_mem_region(nand->bank_mem->start, resource_size(nand->bank_mem));
409err_iounmap_mmio:
410    iounmap(nand->base);
411    release_mem_region(nand->mem->start, resource_size(nand->mem));
412err_free:
413    kfree(nand);
414    return ret;
415}
416
417static int __devexit jz_nand_remove(struct platform_device *pdev)
418{
419    struct jz_nand *nand = platform_get_drvdata(pdev);
420
421    nand_release(&nand->mtd);
422
423    /* Deassert and disable all chips */
424    writel(0, nand->base + JZ_REG_NAND_CTRL);
425
426    iounmap(nand->bch_base);
427    release_mem_region(nand->bch_mem->start, resource_size(nand->bch_mem));
428    iounmap(nand->bank_base);
429    release_mem_region(nand->bank_mem->start, resource_size(nand->bank_mem));
430    iounmap(nand->base);
431    release_mem_region(nand->mem->start, resource_size(nand->mem));
432
433    platform_set_drvdata(pdev, NULL);
434    kfree(nand);
435
436    return 0;
437}
438
439static struct platform_driver jz_nand_driver = {
440    .probe = jz_nand_probe,
441    .remove = __devexit_p(jz_nand_remove),
442    .driver = {
443        .name = "jz4750-nand",
444        .owner = THIS_MODULE,
445    },
446};
447
448static int __init jz_nand_init(void)
449{
450    return platform_driver_register(&jz_nand_driver);
451}
452module_init(jz_nand_init);
453
454static void __exit jz_nand_exit(void)
455{
456    platform_driver_unregister(&jz_nand_driver);
457}
458module_exit(jz_nand_exit);
459
460MODULE_LICENSE("GPL");
461MODULE_AUTHOR("Peter Zotov <whitequark@whitequark.org>");
462MODULE_DESCRIPTION("NAND controller driver for JZ4750 SoC");
463MODULE_ALIAS("platform:jz4750-nand");

Archive Download the corresponding diff file



interactive