diff options
Diffstat (limited to 'arch/mips/basler/excite/excite_flashtest.c')
-rw-r--r-- | arch/mips/basler/excite/excite_flashtest.c | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/arch/mips/basler/excite/excite_flashtest.c b/arch/mips/basler/excite/excite_flashtest.c new file mode 100644 index 000000000000..f0024a8e3294 --- /dev/null +++ b/arch/mips/basler/excite/excite_flashtest.c | |||
@@ -0,0 +1,294 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005 by Basler Vision Technologies AG | ||
3 | * Author: Thies Moeller <thies.moeller@baslerweb.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/types.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/string.h> | ||
25 | #include <linux/ioport.h> | ||
26 | #include <linux/device.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/err.h> | ||
29 | #include <linux/kernel.h> | ||
30 | |||
31 | #include <excite.h> | ||
32 | |||
33 | #include <asm/io.h> | ||
34 | |||
35 | #include <linux/mtd/mtd.h> | ||
36 | #include <linux/mtd/nand.h> | ||
37 | #include <linux/mtd/nand_ecc.h> | ||
38 | #include <linux/mtd/partitions.h> | ||
39 | #include <asm/rm9k-ocd.h> // for ocd_write | ||
40 | #include <linux/workqueue.h> // for queue | ||
41 | |||
42 | #include "excite_nandflash.h" | ||
43 | #include "nandflash.h" | ||
44 | |||
45 | #define PFX "excite flashtest: " | ||
46 | typedef void __iomem *io_reg_t; | ||
47 | |||
48 | #define io_readb(__a__) __raw_readb((__a__)) | ||
49 | #define io_writeb(__v__, __a__) __raw_writeb((__v__), (__a__)) | ||
50 | |||
51 | |||
52 | |||
53 | static inline const struct resource *excite_nandflash_get_resource( | ||
54 | struct platform_device *d, unsigned long flags, const char *basename) | ||
55 | { | ||
56 | const char fmt[] = "%s_%u"; | ||
57 | char buf[80]; | ||
58 | |||
59 | if (unlikely(snprintf(buf, sizeof buf, fmt, basename, d->id) >= sizeof buf)) | ||
60 | return NULL; | ||
61 | |||
62 | return platform_get_resource_byname(d, flags, buf); | ||
63 | } | ||
64 | |||
65 | static inline io_reg_t | ||
66 | excite_nandflash_map_regs(struct platform_device *d, const char *basename) | ||
67 | { | ||
68 | void *result = NULL; | ||
69 | const struct resource *const r = | ||
70 | excite_nandflash_get_resource(d, IORESOURCE_MEM, basename); | ||
71 | if (r) | ||
72 | result = ioremap_nocache(r->start, r->end + 1 - r->start); | ||
73 | return result; | ||
74 | } | ||
75 | |||
76 | /* controller and mtd information */ | ||
77 | |||
78 | struct excite_nandflash_drvdata { | ||
79 | struct mtd_info board_mtd; | ||
80 | struct nand_chip board_chip; | ||
81 | io_reg_t regs; | ||
82 | }; | ||
83 | |||
84 | |||
85 | /* command and control functions */ | ||
86 | static void excite_nandflash_hwcontrol(struct mtd_info *mtd, int cmd) | ||
87 | { | ||
88 | struct nand_chip *this = mtd->priv; | ||
89 | io_reg_t regs = container_of(mtd,struct excite_nandflash_drvdata,board_mtd)->regs; | ||
90 | |||
91 | switch (cmd) { | ||
92 | /* Select the command latch */ | ||
93 | case NAND_CTL_SETCLE: this->IO_ADDR_W = regs + EXCITE_NANDFLASH_CMD; | ||
94 | break; | ||
95 | /* Deselect the command latch */ | ||
96 | case NAND_CTL_CLRCLE: this->IO_ADDR_W = regs + EXCITE_NANDFLASH_DATA; | ||
97 | break; | ||
98 | /* Select the address latch */ | ||
99 | case NAND_CTL_SETALE: this->IO_ADDR_W = regs + EXCITE_NANDFLASH_ADDR; | ||
100 | break; | ||
101 | /* Deselect the address latch */ | ||
102 | case NAND_CTL_CLRALE: this->IO_ADDR_W = regs + EXCITE_NANDFLASH_DATA; | ||
103 | break; | ||
104 | /* Select the chip -- not used */ | ||
105 | case NAND_CTL_SETNCE: | ||
106 | break; | ||
107 | /* Deselect the chip -- not used */ | ||
108 | case NAND_CTL_CLRNCE: | ||
109 | break; | ||
110 | } | ||
111 | |||
112 | this->IO_ADDR_R = this->IO_ADDR_W; | ||
113 | } | ||
114 | |||
115 | /* excite_nandflash_devready() | ||
116 | * | ||
117 | * returns 0 if the nand is busy, 1 if it is ready | ||
118 | */ | ||
119 | static int excite_nandflash_devready(struct mtd_info *mtd) | ||
120 | { | ||
121 | struct excite_nandflash_drvdata *drvdata = | ||
122 | container_of(mtd, struct excite_nandflash_drvdata, board_mtd); | ||
123 | |||
124 | return io_readb(drvdata->regs + EXCITE_NANDFLASH_STATUS); | ||
125 | } | ||
126 | |||
127 | /* device management functions */ | ||
128 | |||
129 | /* excite_nandflash_remove | ||
130 | * | ||
131 | * called by device layer to remove the driver | ||
132 | * the binding to the mtd and all allocated | ||
133 | * resources are released | ||
134 | */ | ||
135 | static int excite_nandflash_remove(struct device *dev) | ||
136 | { | ||
137 | struct excite_nandflash_drvdata *this = dev_get_drvdata(dev); | ||
138 | |||
139 | pr_info(PFX "remove"); | ||
140 | |||
141 | dev_set_drvdata(dev, NULL); | ||
142 | |||
143 | if (this == NULL) { | ||
144 | pr_debug(PFX "call remove without private data!!"); | ||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | |||
149 | /* free the common resources */ | ||
150 | if (this->regs != NULL) { | ||
151 | iounmap(this->regs); | ||
152 | this->regs = NULL; | ||
153 | } | ||
154 | |||
155 | kfree(this); | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static int elapsed; | ||
161 | |||
162 | void my_workqueue_handler(void *arg) | ||
163 | { | ||
164 | elapsed = 1; | ||
165 | } | ||
166 | |||
167 | DECLARE_WORK(sigElapsed, my_workqueue_handler, 0); | ||
168 | |||
169 | |||
170 | /* excite_nandflash_probe | ||
171 | * | ||
172 | * called by device layer when it finds a device matching | ||
173 | * one our driver can handled. This code checks to see if | ||
174 | * it can allocate all necessary resources then calls the | ||
175 | * nand layer to look for devices | ||
176 | */ | ||
177 | static int excite_nandflash_probe(struct device *dev) | ||
178 | { | ||
179 | struct platform_device *pdev = to_platform_device(dev); | ||
180 | |||
181 | struct excite_nandflash_drvdata *drvdata; /* private driver data */ | ||
182 | struct nand_chip *board_chip; /* private flash chip data */ | ||
183 | struct mtd_info *board_mtd; /* mtd info for this board */ | ||
184 | |||
185 | int err = 0; | ||
186 | int count = 0; | ||
187 | struct timeval tv,endtv; | ||
188 | unsigned int dt; | ||
189 | |||
190 | pr_info(PFX "probe dev: (%p)\n", dev); | ||
191 | |||
192 | pr_info(PFX "adjust LB timing\n"); | ||
193 | ocd_writel(0x00000330, LDP2); | ||
194 | |||
195 | drvdata = kmalloc(sizeof(*drvdata), GFP_KERNEL); | ||
196 | if (unlikely(!drvdata)) { | ||
197 | printk(KERN_ERR PFX "no memory for drvdata\n"); | ||
198 | err = -ENOMEM; | ||
199 | goto mem_error; | ||
200 | } | ||
201 | |||
202 | /* Initialize structures */ | ||
203 | memset(drvdata, 0, sizeof(*drvdata)); | ||
204 | |||
205 | /* bind private data into driver */ | ||
206 | dev_set_drvdata(dev, drvdata); | ||
207 | |||
208 | /* allocate and map the resource */ | ||
209 | drvdata->regs = | ||
210 | excite_nandflash_map_regs(pdev, EXCITE_NANDFLASH_RESOURCE_REGS); | ||
211 | |||
212 | if (unlikely(!drvdata->regs)) { | ||
213 | printk(KERN_ERR PFX "cannot reserve register region\n"); | ||
214 | err = -ENXIO; | ||
215 | goto io_error; | ||
216 | } | ||
217 | |||
218 | /* initialise our chip */ | ||
219 | board_chip = &drvdata->board_chip; | ||
220 | |||
221 | board_chip->IO_ADDR_R = drvdata->regs + EXCITE_NANDFLASH_DATA; | ||
222 | board_chip->IO_ADDR_W = drvdata->regs + EXCITE_NANDFLASH_DATA; | ||
223 | |||
224 | board_chip->hwcontrol = excite_nandflash_hwcontrol; | ||
225 | board_chip->dev_ready = excite_nandflash_devready; | ||
226 | |||
227 | board_chip->chip_delay = 25; | ||
228 | #if 0 | ||
229 | /* TODO: speedup the initial scan */ | ||
230 | board_chip->options = NAND_USE_FLASH_BBT; | ||
231 | #endif | ||
232 | board_chip->eccmode = NAND_ECC_SOFT; | ||
233 | |||
234 | /* link chip to mtd */ | ||
235 | board_mtd = &drvdata->board_mtd; | ||
236 | board_mtd->priv = board_chip; | ||
237 | |||
238 | |||
239 | pr_info(PFX "FlashTest\n"); | ||
240 | elapsed = 0; | ||
241 | /* schedule_delayed_work(&sigElapsed, 1*HZ); | ||
242 | while (!elapsed) { | ||
243 | io_readb(drvdata->regs + EXCITE_NANDFLASH_STATUS); | ||
244 | count++; | ||
245 | } | ||
246 | pr_info(PFX "reads in 1 sec --> %d\n",count); | ||
247 | */ | ||
248 | do_gettimeofday(&tv); | ||
249 | for (count = 0 ; count < 1000000; count ++) { | ||
250 | io_readb(drvdata->regs + EXCITE_NANDFLASH_STATUS); | ||
251 | } | ||
252 | do_gettimeofday(&endtv); | ||
253 | dt = (endtv.tv_sec - tv.tv_sec) * 1000000 + endtv.tv_usec - tv.tv_usec; | ||
254 | pr_info(PFX "%8d us timeval\n",dt); | ||
255 | pr_info(PFX "EndFlashTest\n"); | ||
256 | |||
257 | /* return with error to unload everything | ||
258 | */ | ||
259 | io_error: | ||
260 | iounmap(drvdata->regs); | ||
261 | |||
262 | mem_error: | ||
263 | kfree(drvdata); | ||
264 | |||
265 | if (err == 0) | ||
266 | err = -EINVAL; | ||
267 | return err; | ||
268 | } | ||
269 | |||
270 | static struct device_driver excite_nandflash_driver = { | ||
271 | .name = "excite_nand", | ||
272 | .bus = &platform_bus_type, | ||
273 | .probe = excite_nandflash_probe, | ||
274 | .remove = excite_nandflash_remove, | ||
275 | }; | ||
276 | |||
277 | static int __init excite_nandflash_init(void) | ||
278 | { | ||
279 | pr_info(PFX "register Driver (Rev: $Revision:$)\n"); | ||
280 | return driver_register(&excite_nandflash_driver); | ||
281 | } | ||
282 | |||
283 | static void __exit excite_nandflash_exit(void) | ||
284 | { | ||
285 | driver_unregister(&excite_nandflash_driver); | ||
286 | pr_info(PFX "Driver unregistered"); | ||
287 | } | ||
288 | |||
289 | module_init(excite_nandflash_init); | ||
290 | module_exit(excite_nandflash_exit); | ||
291 | |||
292 | MODULE_AUTHOR("Thies Moeller <thies.moeller@baslerweb.com>"); | ||
293 | MODULE_DESCRIPTION("Basler eXcite NAND-Flash driver"); | ||
294 | MODULE_LICENSE("GPL"); | ||