aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/configs/nhk8815_defconfig2
-rw-r--r--arch/arm/mach-nomadik/board-nhk8815.c92
-rw-r--r--arch/arm/mach-nomadik/include/mach/fsmc.h29
-rw-r--r--arch/arm/mach-nomadik/include/mach/nand.h16
-rw-r--r--drivers/mtd/nand/Kconfig6
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/nomadik_nand.c250
7 files changed, 395 insertions, 1 deletions
diff --git a/arch/arm/configs/nhk8815_defconfig b/arch/arm/configs/nhk8815_defconfig
index 9bb45b932f04..600cb270f2bf 100644
--- a/arch/arm/configs/nhk8815_defconfig
+++ b/arch/arm/configs/nhk8815_defconfig
@@ -498,7 +498,7 @@ CONFIG_MTD_CFI_I2=y
498# CONFIG_MTD_DOC2001PLUS is not set 498# CONFIG_MTD_DOC2001PLUS is not set
499CONFIG_MTD_NAND=y 499CONFIG_MTD_NAND=y
500CONFIG_MTD_NAND_VERIFY_WRITE=y 500CONFIG_MTD_NAND_VERIFY_WRITE=y
501# CONFIG_MTD_NAND_ECC_SMC is not set 501CONFIG_MTD_NAND_ECC_SMC=y
502# CONFIG_MTD_NAND_MUSEUM_IDS is not set 502# CONFIG_MTD_NAND_MUSEUM_IDS is not set
503# CONFIG_MTD_NAND_GPIO is not set 503# CONFIG_MTD_NAND_GPIO is not set
504CONFIG_MTD_NAND_IDS=y 504CONFIG_MTD_NAND_IDS=y
diff --git a/arch/arm/mach-nomadik/board-nhk8815.c b/arch/arm/mach-nomadik/board-nhk8815.c
index 79bdea943eb4..59c1dbb686c9 100644
--- a/arch/arm/mach-nomadik/board-nhk8815.c
+++ b/arch/arm/mach-nomadik/board-nhk8815.c
@@ -16,12 +16,103 @@
16#include <linux/amba/bus.h> 16#include <linux/amba/bus.h>
17#include <linux/interrupt.h> 17#include <linux/interrupt.h>
18#include <linux/gpio.h> 18#include <linux/gpio.h>
19#include <linux/mtd/mtd.h>
20#include <linux/mtd/nand.h>
21#include <linux/mtd/partitions.h>
22#include <linux/io.h>
23#include <asm/sizes.h>
19#include <asm/mach-types.h> 24#include <asm/mach-types.h>
20#include <asm/mach/arch.h> 25#include <asm/mach/arch.h>
21#include <asm/mach/irq.h> 26#include <asm/mach/irq.h>
22#include <mach/setup.h> 27#include <mach/setup.h>
28#include <mach/nand.h>
29#include <mach/fsmc.h>
23#include "clock.h" 30#include "clock.h"
24 31
32/* These adresses span 16MB, so use three individual pages */
33static struct resource nhk8815_nand_resources[] = {
34 {
35 .name = "nand_addr",
36 .start = NAND_IO_ADDR,
37 .end = NAND_IO_ADDR + 0xfff,
38 .flags = IORESOURCE_MEM,
39 }, {
40 .name = "nand_cmd",
41 .start = NAND_IO_CMD,
42 .end = NAND_IO_CMD + 0xfff,
43 .flags = IORESOURCE_MEM,
44 }, {
45 .name = "nand_data",
46 .start = NAND_IO_DATA,
47 .end = NAND_IO_DATA + 0xfff,
48 .flags = IORESOURCE_MEM,
49 }
50};
51
52static int nhk8815_nand_init(void)
53{
54 /* FSMC setup for nand chip select (8-bit nand in 8815NHK) */
55 writel(0x0000000E, FSMC_PCR(0));
56 writel(0x000D0A00, FSMC_PMEM(0));
57 writel(0x00100A00, FSMC_PATT(0));
58
59 /* enable access to the chip select area */
60 writel(readl(FSMC_PCR(0)) | 0x04, FSMC_PCR(0));
61
62 return 0;
63}
64
65/*
66 * These partitions are the same as those used in the 2.6.20 release
67 * shipped by the vendor; the first two partitions are mandated
68 * by the boot ROM, and the bootloader area is somehow oversized...
69 */
70static struct mtd_partition nhk8815_partitions[] = {
71 {
72 .name = "X-Loader(NAND)",
73 .offset = 0,
74 .size = SZ_256K,
75 }, {
76 .name = "MemInit(NAND)",
77 .offset = MTDPART_OFS_APPEND,
78 .size = SZ_256K,
79 }, {
80 .name = "BootLoader(NAND)",
81 .offset = MTDPART_OFS_APPEND,
82 .size = SZ_2M,
83 }, {
84 .name = "Kernel zImage(NAND)",
85 .offset = MTDPART_OFS_APPEND,
86 .size = 3 * SZ_1M,
87 }, {
88 .name = "Root Filesystem(NAND)",
89 .offset = MTDPART_OFS_APPEND,
90 .size = 22 * SZ_1M,
91 }, {
92 .name = "User Filesystem(NAND)",
93 .offset = MTDPART_OFS_APPEND,
94 .size = MTDPART_SIZ_FULL,
95 }
96};
97
98static struct nomadik_nand_platform_data nhk8815_nand_data = {
99 .parts = nhk8815_partitions,
100 .nparts = ARRAY_SIZE(nhk8815_partitions),
101 .options = NAND_COPYBACK | NAND_CACHEPRG | NAND_NO_PADDING \
102 | NAND_NO_READRDY | NAND_NO_AUTOINCR,
103 .init = nhk8815_nand_init,
104};
105
106static struct platform_device nhk8815_nand_device = {
107 .name = "nomadik_nand",
108 .dev = {
109 .platform_data = &nhk8815_nand_data,
110 },
111 .resource = nhk8815_nand_resources,
112 .num_resources = ARRAY_SIZE(nhk8815_nand_resources),
113};
114
115
25#define __MEM_4K_RESOURCE(x) \ 116#define __MEM_4K_RESOURCE(x) \
26 .res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM} 117 .res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM}
27 118
@@ -81,6 +172,7 @@ static int __init nhk8815_eth_init(void)
81device_initcall(nhk8815_eth_init); 172device_initcall(nhk8815_eth_init);
82 173
83static struct platform_device *nhk8815_platform_devices[] __initdata = { 174static struct platform_device *nhk8815_platform_devices[] __initdata = {
175 &nhk8815_nand_device,
84 &nhk8815_eth_device, 176 &nhk8815_eth_device,
85 /* will add more devices */ 177 /* will add more devices */
86}; 178};
diff --git a/arch/arm/mach-nomadik/include/mach/fsmc.h b/arch/arm/mach-nomadik/include/mach/fsmc.h
new file mode 100644
index 000000000000..8c2c05183685
--- /dev/null
+++ b/arch/arm/mach-nomadik/include/mach/fsmc.h
@@ -0,0 +1,29 @@
1
2/* Definitions for the Nomadik FSMC "Flexible Static Memory controller" */
3
4#ifndef __ASM_ARCH_FSMC_H
5#define __ASM_ARCH_FSMC_H
6
7#include <mach/hardware.h>
8/*
9 * Register list
10 */
11
12/* bus control reg. and bus timing reg. for CS0..CS3 */
13#define FSMC_BCR(x) (NOMADIK_FSMC_VA + (x << 3))
14#define FSMC_BTR(x) (NOMADIK_FSMC_VA + (x << 3) + 0x04)
15
16/* PC-card and NAND:
17 * PCR = control register
18 * PMEM = memory timing
19 * PATT = attribute timing
20 * PIO = I/O timing
21 * PECCR = ECC result
22 */
23#define FSMC_PCR(x) (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x00)
24#define FSMC_PMEM(x) (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x08)
25#define FSMC_PATT(x) (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x0c)
26#define FSMC_PIO(x) (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x10)
27#define FSMC_PECCR(x) (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x14)
28
29#endif /* __ASM_ARCH_FSMC_H */
diff --git a/arch/arm/mach-nomadik/include/mach/nand.h b/arch/arm/mach-nomadik/include/mach/nand.h
new file mode 100644
index 000000000000..c3c8254c22a5
--- /dev/null
+++ b/arch/arm/mach-nomadik/include/mach/nand.h
@@ -0,0 +1,16 @@
1#ifndef __ASM_ARCH_NAND_H
2#define __ASM_ARCH_NAND_H
3
4struct nomadik_nand_platform_data {
5 struct mtd_partition *parts;
6 int nparts;
7 int options;
8 int (*init) (void);
9 int (*exit) (void);
10};
11
12#define NAND_IO_DATA 0x40000000
13#define NAND_IO_CMD 0x40800000
14#define NAND_IO_ADDR 0x41000000
15
16#endif /* __ASM_ARCH_NAND_H */
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 2c9a0ed4aed8..2fda0b615246 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -443,6 +443,12 @@ config MTD_NAND_MXC
443 This enables the driver for the NAND flash controller on the 443 This enables the driver for the NAND flash controller on the
444 MXC processors. 444 MXC processors.
445 445
446config MTD_NAND_NOMADIK
447 tristate "ST Nomadik 8815 NAND support"
448 depends on ARCH_NOMADIK
449 help
450 Driver for the NAND flash controller on the Nomadik, with ECC.
451
446config MTD_NAND_SH_FLCTL 452config MTD_NAND_SH_FLCTL
447 tristate "Support for NAND on Renesas SuperH FLCTL" 453 tristate "Support for NAND on Renesas SuperH FLCTL"
448 depends on MTD_NAND && SUPERH && CPU_SUBTYPE_SH7723 454 depends on MTD_NAND && SUPERH && CPU_SUBTYPE_SH7723
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 4f7b1890f83c..6950d3dabf10 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -41,5 +41,6 @@ obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o
41obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o 41obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o
42obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o 42obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o
43obj-$(CONFIG_MTD_NAND_W90P910) += w90p910_nand.o 43obj-$(CONFIG_MTD_NAND_W90P910) += w90p910_nand.o
44obj-$(CONFIG_MTD_NAND_NOMADIK) += nomadik_nand.o
44 45
45nand-objs := nand_base.o nand_bbt.o 46nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/nomadik_nand.c b/drivers/mtd/nand/nomadik_nand.c
new file mode 100644
index 000000000000..7c302d55910e
--- /dev/null
+++ b/drivers/mtd/nand/nomadik_nand.c
@@ -0,0 +1,250 @@
1/*
2 * drivers/mtd/nand/nomadik_nand.c
3 *
4 * Overview:
5 * Driver for on-board NAND flash on Nomadik Platforms
6 *
7 * Copyright © 2007 STMicroelectronics Pvt. Ltd.
8 * Author: Sachin Verma <sachin.verma@st.com>
9 *
10 * Copyright © 2009 Alessandro Rubini
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 */
23
24#include <linux/init.h>
25#include <linux/module.h>
26#include <linux/types.h>
27#include <linux/mtd/mtd.h>
28#include <linux/mtd/nand.h>
29#include <linux/mtd/nand_ecc.h>
30#include <linux/platform_device.h>
31#include <linux/mtd/partitions.h>
32#include <linux/io.h>
33#include <mach/nand.h>
34#include <mach/fsmc.h>
35
36#include <mtd/mtd-abi.h>
37
38struct nomadik_nand_host {
39 struct mtd_info mtd;
40 struct nand_chip nand;
41 void __iomem *data_va;
42 void __iomem *cmd_va;
43 void __iomem *addr_va;
44 struct nand_bbt_descr *bbt_desc;
45};
46
47static struct nand_ecclayout nomadik_ecc_layout = {
48 .eccbytes = 3 * 4,
49 .eccpos = { /* each subpage has 16 bytes: pos 2,3,4 hosts ECC */
50 0x02, 0x03, 0x04,
51 0x12, 0x13, 0x14,
52 0x22, 0x23, 0x24,
53 0x32, 0x33, 0x34},
54 /* let's keep bytes 5,6,7 for us, just in case we change ECC algo */
55 .oobfree = { {0x08, 0x08}, {0x18, 0x08}, {0x28, 0x08}, {0x38, 0x08} },
56};
57
58static void nomadik_ecc_control(struct mtd_info *mtd, int mode)
59{
60 /* No need to enable hw ecc, it's on by default */
61}
62
63static void nomadik_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
64{
65 struct nand_chip *nand = mtd->priv;
66 struct nomadik_nand_host *host = nand->priv;
67
68 if (cmd == NAND_CMD_NONE)
69 return;
70
71 if (ctrl & NAND_CLE)
72 writeb(cmd, host->cmd_va);
73 else
74 writeb(cmd, host->addr_va);
75}
76
77static int nomadik_nand_probe(struct platform_device *pdev)
78{
79 struct nomadik_nand_platform_data *pdata = pdev->dev.platform_data;
80 struct nomadik_nand_host *host;
81 struct mtd_info *mtd;
82 struct nand_chip *nand;
83 struct resource *res;
84 int ret = 0;
85
86 /* Allocate memory for the device structure (and zero it) */
87 host = kzalloc(sizeof(struct nomadik_nand_host), GFP_KERNEL);
88 if (!host) {
89 dev_err(&pdev->dev, "Failed to allocate device structure.\n");
90 return -ENOMEM;
91 }
92
93 /* Call the client's init function, if any */
94 if (pdata->init)
95 ret = pdata->init();
96 if (ret < 0) {
97 dev_err(&pdev->dev, "Init function failed\n");
98 goto err;
99 }
100
101 /* ioremap three regions */
102 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr");
103 if (!res) {
104 ret = -EIO;
105 goto err_unmap;
106 }
107 host->addr_va = ioremap(res->start, res->end - res->start + 1);
108
109 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
110 if (!res) {
111 ret = -EIO;
112 goto err_unmap;
113 }
114 host->data_va = ioremap(res->start, res->end - res->start + 1);
115
116 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd");
117 if (!res) {
118 ret = -EIO;
119 goto err_unmap;
120 }
121 host->cmd_va = ioremap(res->start, res->end - res->start + 1);
122
123 if (!host->addr_va || !host->data_va || !host->cmd_va) {
124 ret = -ENOMEM;
125 goto err_unmap;
126 }
127
128 /* Link all private pointers */
129 mtd = &host->mtd;
130 nand = &host->nand;
131 mtd->priv = nand;
132 nand->priv = host;
133
134 host->mtd.owner = THIS_MODULE;
135 nand->IO_ADDR_R = host->data_va;
136 nand->IO_ADDR_W = host->data_va;
137 nand->cmd_ctrl = nomadik_cmd_ctrl;
138
139 /*
140 * This stanza declares ECC_HW but uses soft routines. It's because
141 * HW claims to make the calculation but not the correction. However,
142 * I haven't managed to get the desired data out of it until now.
143 */
144 nand->ecc.mode = NAND_ECC_SOFT;
145 nand->ecc.layout = &nomadik_ecc_layout;
146 nand->ecc.hwctl = nomadik_ecc_control;
147 nand->ecc.size = 512;
148 nand->ecc.bytes = 3;
149
150 nand->options = pdata->options;
151
152 /*
153 * Scan to find existance of the device
154 */
155 if (nand_scan(&host->mtd, 1)) {
156 ret = -ENXIO;
157 goto err_unmap;
158 }
159
160#ifdef CONFIG_MTD_PARTITIONS
161 add_mtd_partitions(&host->mtd, pdata->parts, pdata->nparts);
162#else
163 pr_info("Registering %s as whole device\n", mtd->name);
164 add_mtd_device(mtd);
165#endif
166
167 platform_set_drvdata(pdev, host);
168 return 0;
169
170 err_unmap:
171 if (host->cmd_va)
172 iounmap(host->cmd_va);
173 if (host->data_va)
174 iounmap(host->data_va);
175 if (host->addr_va)
176 iounmap(host->addr_va);
177 err:
178 kfree(host);
179 return ret;
180}
181
182/*
183 * Clean up routine
184 */
185static int nomadik_nand_remove(struct platform_device *pdev)
186{
187 struct nomadik_nand_host *host = platform_get_drvdata(pdev);
188 struct nomadik_nand_platform_data *pdata = pdev->dev.platform_data;
189
190 if (pdata->exit)
191 pdata->exit();
192
193 if (host) {
194 iounmap(host->cmd_va);
195 iounmap(host->data_va);
196 iounmap(host->addr_va);
197 kfree(host);
198 }
199 return 0;
200}
201
202static int nomadik_nand_suspend(struct device *dev)
203{
204 struct nomadik_nand_host *host = dev_get_drvdata(dev);
205 int ret = 0;
206 if (host)
207 ret = host->mtd.suspend(&host->mtd);
208 return ret;
209}
210
211static int nomadik_nand_resume(struct device *dev)
212{
213 struct nomadik_nand_host *host = dev_get_drvdata(dev);
214 if (host)
215 host->mtd.resume(&host->mtd);
216 return 0;
217}
218
219static struct dev_pm_ops nomadik_nand_pm_ops = {
220 .suspend = nomadik_nand_suspend,
221 .resume = nomadik_nand_resume,
222};
223
224static struct platform_driver nomadik_nand_driver = {
225 .probe = nomadik_nand_probe,
226 .remove = nomadik_nand_remove,
227 .driver = {
228 .owner = THIS_MODULE,
229 .name = "nomadik_nand",
230 .pm = &nomadik_nand_pm_ops,
231 },
232};
233
234static int __init nand_nomadik_init(void)
235{
236 pr_info("Nomadik NAND driver\n");
237 return platform_driver_register(&nomadik_nand_driver);
238}
239
240static void __exit nand_nomadik_exit(void)
241{
242 platform_driver_unregister(&nomadik_nand_driver);
243}
244
245module_init(nand_nomadik_init);
246module_exit(nand_nomadik_exit);
247
248MODULE_LICENSE("GPL");
249MODULE_AUTHOR("ST Microelectronics (sachin.verma@st.com)");
250MODULE_DESCRIPTION("NAND driver for Nomadik Platform");