diff options
author | Anatolij Gustschin <agust@denx.de> | 2010-02-15 12:35:05 -0500 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2010-02-26 11:56:43 -0500 |
commit | bb315f749f8c800cb8bf8d7dabc4b5fbab97b328 (patch) | |
tree | 310fb72cd30b3f4697b57c005871b5939807311d /drivers/mtd/nand/mpc5121_nfc.c | |
parent | 1385858ee07cbfd68c503a10e4a526d24223d465 (diff) |
mtd: nand: Add MPC5121 NAND Flash Controller driver
Adds NAND Flash Controller driver for MPC5121 Revision 2.
All device features, except hardware ECC and power management,
are supported.
Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Wolfgang Denk <wd@denx.de>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/nand/mpc5121_nfc.c')
-rw-r--r-- | drivers/mtd/nand/mpc5121_nfc.c | 916 |
1 files changed, 916 insertions, 0 deletions
diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c new file mode 100644 index 000000000000..d7333f4dae86 --- /dev/null +++ b/drivers/mtd/nand/mpc5121_nfc.c | |||
@@ -0,0 +1,916 @@ | |||
1 | /* | ||
2 | * Copyright 2004-2008 Freescale Semiconductor, Inc. | ||
3 | * Copyright 2009 Semihalf. | ||
4 | * | ||
5 | * Approved as OSADL project by a majority of OSADL members and funded | ||
6 | * by OSADL membership fees in 2009; for details see www.osadl.org. | ||
7 | * | ||
8 | * Based on original driver from Freescale Semiconductor | ||
9 | * written by John Rigby <jrigby@freescale.com> on basis | ||
10 | * of drivers/mtd/nand/mxc_nand.c. Reworked and extended | ||
11 | * Piotr Ziecik <kosmo@semihalf.com>. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version 2 | ||
16 | * of the License, or (at your option) any later version. | ||
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 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | ||
25 | * MA 02110-1301, USA. | ||
26 | */ | ||
27 | |||
28 | #include <linux/module.h> | ||
29 | #include <linux/clk.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/interrupt.h> | ||
33 | #include <linux/io.h> | ||
34 | #include <linux/mtd/mtd.h> | ||
35 | #include <linux/mtd/nand.h> | ||
36 | #include <linux/mtd/partitions.h> | ||
37 | #include <linux/of_device.h> | ||
38 | #include <linux/of_platform.h> | ||
39 | |||
40 | #include <asm/mpc5121.h> | ||
41 | |||
42 | /* Addresses for NFC MAIN RAM BUFFER areas */ | ||
43 | #define NFC_MAIN_AREA(n) ((n) * 0x200) | ||
44 | |||
45 | /* Addresses for NFC SPARE BUFFER areas */ | ||
46 | #define NFC_SPARE_BUFFERS 8 | ||
47 | #define NFC_SPARE_LEN 0x40 | ||
48 | #define NFC_SPARE_AREA(n) (0x1000 + ((n) * NFC_SPARE_LEN)) | ||
49 | |||
50 | /* MPC5121 NFC registers */ | ||
51 | #define NFC_BUF_ADDR 0x1E04 | ||
52 | #define NFC_FLASH_ADDR 0x1E06 | ||
53 | #define NFC_FLASH_CMD 0x1E08 | ||
54 | #define NFC_CONFIG 0x1E0A | ||
55 | #define NFC_ECC_STATUS1 0x1E0C | ||
56 | #define NFC_ECC_STATUS2 0x1E0E | ||
57 | #define NFC_SPAS 0x1E10 | ||
58 | #define NFC_WRPROT 0x1E12 | ||
59 | #define NFC_NF_WRPRST 0x1E18 | ||
60 | #define NFC_CONFIG1 0x1E1A | ||
61 | #define NFC_CONFIG2 0x1E1C | ||
62 | #define NFC_UNLOCKSTART_BLK0 0x1E20 | ||
63 | #define NFC_UNLOCKEND_BLK0 0x1E22 | ||
64 | #define NFC_UNLOCKSTART_BLK1 0x1E24 | ||
65 | #define NFC_UNLOCKEND_BLK1 0x1E26 | ||
66 | #define NFC_UNLOCKSTART_BLK2 0x1E28 | ||
67 | #define NFC_UNLOCKEND_BLK2 0x1E2A | ||
68 | #define NFC_UNLOCKSTART_BLK3 0x1E2C | ||
69 | #define NFC_UNLOCKEND_BLK3 0x1E2E | ||
70 | |||
71 | /* Bit Definitions: NFC_BUF_ADDR */ | ||
72 | #define NFC_RBA_MASK (7 << 0) | ||
73 | #define NFC_ACTIVE_CS_SHIFT 5 | ||
74 | #define NFC_ACTIVE_CS_MASK (3 << NFC_ACTIVE_CS_SHIFT) | ||
75 | |||
76 | /* Bit Definitions: NFC_CONFIG */ | ||
77 | #define NFC_BLS_UNLOCKED (1 << 1) | ||
78 | |||
79 | /* Bit Definitions: NFC_CONFIG1 */ | ||
80 | #define NFC_ECC_4BIT (1 << 0) | ||
81 | #define NFC_FULL_PAGE_DMA (1 << 1) | ||
82 | #define NFC_SPARE_ONLY (1 << 2) | ||
83 | #define NFC_ECC_ENABLE (1 << 3) | ||
84 | #define NFC_INT_MASK (1 << 4) | ||
85 | #define NFC_BIG_ENDIAN (1 << 5) | ||
86 | #define NFC_RESET (1 << 6) | ||
87 | #define NFC_CE (1 << 7) | ||
88 | #define NFC_ONE_CYCLE (1 << 8) | ||
89 | #define NFC_PPB_32 (0 << 9) | ||
90 | #define NFC_PPB_64 (1 << 9) | ||
91 | #define NFC_PPB_128 (2 << 9) | ||
92 | #define NFC_PPB_256 (3 << 9) | ||
93 | #define NFC_PPB_MASK (3 << 9) | ||
94 | #define NFC_FULL_PAGE_INT (1 << 11) | ||
95 | |||
96 | /* Bit Definitions: NFC_CONFIG2 */ | ||
97 | #define NFC_COMMAND (1 << 0) | ||
98 | #define NFC_ADDRESS (1 << 1) | ||
99 | #define NFC_INPUT (1 << 2) | ||
100 | #define NFC_OUTPUT (1 << 3) | ||
101 | #define NFC_ID (1 << 4) | ||
102 | #define NFC_STATUS (1 << 5) | ||
103 | #define NFC_CMD_FAIL (1 << 15) | ||
104 | #define NFC_INT (1 << 15) | ||
105 | |||
106 | /* Bit Definitions: NFC_WRPROT */ | ||
107 | #define NFC_WPC_LOCK_TIGHT (1 << 0) | ||
108 | #define NFC_WPC_LOCK (1 << 1) | ||
109 | #define NFC_WPC_UNLOCK (1 << 2) | ||
110 | |||
111 | #define DRV_NAME "mpc5121_nfc" | ||
112 | |||
113 | /* Timeouts */ | ||
114 | #define NFC_RESET_TIMEOUT 1000 /* 1 ms */ | ||
115 | #define NFC_TIMEOUT (HZ / 10) /* 1/10 s */ | ||
116 | |||
117 | struct mpc5121_nfc_prv { | ||
118 | struct mtd_info mtd; | ||
119 | struct nand_chip chip; | ||
120 | int irq; | ||
121 | void __iomem *regs; | ||
122 | struct clk *clk; | ||
123 | wait_queue_head_t irq_waitq; | ||
124 | uint column; | ||
125 | int spareonly; | ||
126 | void __iomem *csreg; | ||
127 | struct device *dev; | ||
128 | }; | ||
129 | |||
130 | static void mpc5121_nfc_done(struct mtd_info *mtd); | ||
131 | |||
132 | #ifdef CONFIG_MTD_PARTITIONS | ||
133 | static const char *mpc5121_nfc_pprobes[] = { "cmdlinepart", NULL }; | ||
134 | #endif | ||
135 | |||
136 | /* Read NFC register */ | ||
137 | static inline u16 nfc_read(struct mtd_info *mtd, uint reg) | ||
138 | { | ||
139 | struct nand_chip *chip = mtd->priv; | ||
140 | struct mpc5121_nfc_prv *prv = chip->priv; | ||
141 | |||
142 | return in_be16(prv->regs + reg); | ||
143 | } | ||
144 | |||
145 | /* Write NFC register */ | ||
146 | static inline void nfc_write(struct mtd_info *mtd, uint reg, u16 val) | ||
147 | { | ||
148 | struct nand_chip *chip = mtd->priv; | ||
149 | struct mpc5121_nfc_prv *prv = chip->priv; | ||
150 | |||
151 | out_be16(prv->regs + reg, val); | ||
152 | } | ||
153 | |||
154 | /* Set bits in NFC register */ | ||
155 | static inline void nfc_set(struct mtd_info *mtd, uint reg, u16 bits) | ||
156 | { | ||
157 | nfc_write(mtd, reg, nfc_read(mtd, reg) | bits); | ||
158 | } | ||
159 | |||
160 | /* Clear bits in NFC register */ | ||
161 | static inline void nfc_clear(struct mtd_info *mtd, uint reg, u16 bits) | ||
162 | { | ||
163 | nfc_write(mtd, reg, nfc_read(mtd, reg) & ~bits); | ||
164 | } | ||
165 | |||
166 | /* Invoke address cycle */ | ||
167 | static inline void mpc5121_nfc_send_addr(struct mtd_info *mtd, u16 addr) | ||
168 | { | ||
169 | nfc_write(mtd, NFC_FLASH_ADDR, addr); | ||
170 | nfc_write(mtd, NFC_CONFIG2, NFC_ADDRESS); | ||
171 | mpc5121_nfc_done(mtd); | ||
172 | } | ||
173 | |||
174 | /* Invoke command cycle */ | ||
175 | static inline void mpc5121_nfc_send_cmd(struct mtd_info *mtd, u16 cmd) | ||
176 | { | ||
177 | nfc_write(mtd, NFC_FLASH_CMD, cmd); | ||
178 | nfc_write(mtd, NFC_CONFIG2, NFC_COMMAND); | ||
179 | mpc5121_nfc_done(mtd); | ||
180 | } | ||
181 | |||
182 | /* Send data from NFC buffers to NAND flash */ | ||
183 | static inline void mpc5121_nfc_send_prog_page(struct mtd_info *mtd) | ||
184 | { | ||
185 | nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK); | ||
186 | nfc_write(mtd, NFC_CONFIG2, NFC_INPUT); | ||
187 | mpc5121_nfc_done(mtd); | ||
188 | } | ||
189 | |||
190 | /* Receive data from NAND flash */ | ||
191 | static inline void mpc5121_nfc_send_read_page(struct mtd_info *mtd) | ||
192 | { | ||
193 | nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK); | ||
194 | nfc_write(mtd, NFC_CONFIG2, NFC_OUTPUT); | ||
195 | mpc5121_nfc_done(mtd); | ||
196 | } | ||
197 | |||
198 | /* Receive ID from NAND flash */ | ||
199 | static inline void mpc5121_nfc_send_read_id(struct mtd_info *mtd) | ||
200 | { | ||
201 | nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK); | ||
202 | nfc_write(mtd, NFC_CONFIG2, NFC_ID); | ||
203 | mpc5121_nfc_done(mtd); | ||
204 | } | ||
205 | |||
206 | /* Receive status from NAND flash */ | ||
207 | static inline void mpc5121_nfc_send_read_status(struct mtd_info *mtd) | ||
208 | { | ||
209 | nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK); | ||
210 | nfc_write(mtd, NFC_CONFIG2, NFC_STATUS); | ||
211 | mpc5121_nfc_done(mtd); | ||
212 | } | ||
213 | |||
214 | /* NFC interrupt handler */ | ||
215 | static irqreturn_t mpc5121_nfc_irq(int irq, void *data) | ||
216 | { | ||
217 | struct mtd_info *mtd = data; | ||
218 | struct nand_chip *chip = mtd->priv; | ||
219 | struct mpc5121_nfc_prv *prv = chip->priv; | ||
220 | |||
221 | nfc_set(mtd, NFC_CONFIG1, NFC_INT_MASK); | ||
222 | wake_up(&prv->irq_waitq); | ||
223 | |||
224 | return IRQ_HANDLED; | ||
225 | } | ||
226 | |||
227 | /* Wait for operation complete */ | ||
228 | static void mpc5121_nfc_done(struct mtd_info *mtd) | ||
229 | { | ||
230 | struct nand_chip *chip = mtd->priv; | ||
231 | struct mpc5121_nfc_prv *prv = chip->priv; | ||
232 | int rv; | ||
233 | |||
234 | if ((nfc_read(mtd, NFC_CONFIG2) & NFC_INT) == 0) { | ||
235 | nfc_clear(mtd, NFC_CONFIG1, NFC_INT_MASK); | ||
236 | rv = wait_event_timeout(prv->irq_waitq, | ||
237 | (nfc_read(mtd, NFC_CONFIG2) & NFC_INT), NFC_TIMEOUT); | ||
238 | |||
239 | if (!rv) | ||
240 | dev_warn(prv->dev, | ||
241 | "Timeout while waiting for interrupt.\n"); | ||
242 | } | ||
243 | |||
244 | nfc_clear(mtd, NFC_CONFIG2, NFC_INT); | ||
245 | } | ||
246 | |||
247 | /* Do address cycle(s) */ | ||
248 | static void mpc5121_nfc_addr_cycle(struct mtd_info *mtd, int column, int page) | ||
249 | { | ||
250 | struct nand_chip *chip = mtd->priv; | ||
251 | u32 pagemask = chip->pagemask; | ||
252 | |||
253 | if (column != -1) { | ||
254 | mpc5121_nfc_send_addr(mtd, column); | ||
255 | if (mtd->writesize > 512) | ||
256 | mpc5121_nfc_send_addr(mtd, column >> 8); | ||
257 | } | ||
258 | |||
259 | if (page != -1) { | ||
260 | do { | ||
261 | mpc5121_nfc_send_addr(mtd, page & 0xFF); | ||
262 | page >>= 8; | ||
263 | pagemask >>= 8; | ||
264 | } while (pagemask); | ||
265 | } | ||
266 | } | ||
267 | |||
268 | /* Control chip select signals */ | ||
269 | static void mpc5121_nfc_select_chip(struct mtd_info *mtd, int chip) | ||
270 | { | ||
271 | if (chip < 0) { | ||
272 | nfc_clear(mtd, NFC_CONFIG1, NFC_CE); | ||
273 | return; | ||
274 | } | ||
275 | |||
276 | nfc_clear(mtd, NFC_BUF_ADDR, NFC_ACTIVE_CS_MASK); | ||
277 | nfc_set(mtd, NFC_BUF_ADDR, (chip << NFC_ACTIVE_CS_SHIFT) & | ||
278 | NFC_ACTIVE_CS_MASK); | ||
279 | nfc_set(mtd, NFC_CONFIG1, NFC_CE); | ||
280 | } | ||
281 | |||
282 | /* Init external chip select logic on ADS5121 board */ | ||
283 | static int ads5121_chipselect_init(struct mtd_info *mtd) | ||
284 | { | ||
285 | struct nand_chip *chip = mtd->priv; | ||
286 | struct mpc5121_nfc_prv *prv = chip->priv; | ||
287 | struct device_node *dn; | ||
288 | |||
289 | dn = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld"); | ||
290 | if (dn) { | ||
291 | prv->csreg = of_iomap(dn, 0); | ||
292 | of_node_put(dn); | ||
293 | if (!prv->csreg) | ||
294 | return -ENOMEM; | ||
295 | |||
296 | /* CPLD Register 9 controls NAND /CE Lines */ | ||
297 | prv->csreg += 9; | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | return -EINVAL; | ||
302 | } | ||
303 | |||
304 | /* Control chips select signal on ADS5121 board */ | ||
305 | static void ads5121_select_chip(struct mtd_info *mtd, int chip) | ||
306 | { | ||
307 | struct nand_chip *nand = mtd->priv; | ||
308 | struct mpc5121_nfc_prv *prv = nand->priv; | ||
309 | u8 v; | ||
310 | |||
311 | v = in_8(prv->csreg); | ||
312 | v |= 0x0F; | ||
313 | |||
314 | if (chip >= 0) { | ||
315 | mpc5121_nfc_select_chip(mtd, 0); | ||
316 | v &= ~(1 << chip); | ||
317 | } else | ||
318 | mpc5121_nfc_select_chip(mtd, -1); | ||
319 | |||
320 | out_8(prv->csreg, v); | ||
321 | } | ||
322 | |||
323 | /* Read NAND Ready/Busy signal */ | ||
324 | static int mpc5121_nfc_dev_ready(struct mtd_info *mtd) | ||
325 | { | ||
326 | /* | ||
327 | * NFC handles ready/busy signal internally. Therefore, this function | ||
328 | * always returns status as ready. | ||
329 | */ | ||
330 | return 1; | ||
331 | } | ||
332 | |||
333 | /* Write command to NAND flash */ | ||
334 | static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command, | ||
335 | int column, int page) | ||
336 | { | ||
337 | struct nand_chip *chip = mtd->priv; | ||
338 | struct mpc5121_nfc_prv *prv = chip->priv; | ||
339 | |||
340 | prv->column = (column >= 0) ? column : 0; | ||
341 | prv->spareonly = 0; | ||
342 | |||
343 | switch (command) { | ||
344 | case NAND_CMD_PAGEPROG: | ||
345 | mpc5121_nfc_send_prog_page(mtd); | ||
346 | break; | ||
347 | /* | ||
348 | * NFC does not support sub-page reads and writes, | ||
349 | * so emulate them using full page transfers. | ||
350 | */ | ||
351 | case NAND_CMD_READ0: | ||
352 | column = 0; | ||
353 | break; | ||
354 | |||
355 | case NAND_CMD_READ1: | ||
356 | prv->column += 256; | ||
357 | command = NAND_CMD_READ0; | ||
358 | column = 0; | ||
359 | break; | ||
360 | |||
361 | case NAND_CMD_READOOB: | ||
362 | prv->spareonly = 1; | ||
363 | command = NAND_CMD_READ0; | ||
364 | column = 0; | ||
365 | break; | ||
366 | |||
367 | case NAND_CMD_SEQIN: | ||
368 | mpc5121_nfc_command(mtd, NAND_CMD_READ0, column, page); | ||
369 | column = 0; | ||
370 | break; | ||
371 | |||
372 | case NAND_CMD_ERASE1: | ||
373 | case NAND_CMD_ERASE2: | ||
374 | case NAND_CMD_READID: | ||
375 | case NAND_CMD_STATUS: | ||
376 | break; | ||
377 | |||
378 | default: | ||
379 | return; | ||
380 | } | ||
381 | |||
382 | mpc5121_nfc_send_cmd(mtd, command); | ||
383 | mpc5121_nfc_addr_cycle(mtd, column, page); | ||
384 | |||
385 | switch (command) { | ||
386 | case NAND_CMD_READ0: | ||
387 | if (mtd->writesize > 512) | ||
388 | mpc5121_nfc_send_cmd(mtd, NAND_CMD_READSTART); | ||
389 | mpc5121_nfc_send_read_page(mtd); | ||
390 | break; | ||
391 | |||
392 | case NAND_CMD_READID: | ||
393 | mpc5121_nfc_send_read_id(mtd); | ||
394 | break; | ||
395 | |||
396 | case NAND_CMD_STATUS: | ||
397 | mpc5121_nfc_send_read_status(mtd); | ||
398 | if (chip->options & NAND_BUSWIDTH_16) | ||
399 | prv->column = 1; | ||
400 | else | ||
401 | prv->column = 0; | ||
402 | break; | ||
403 | } | ||
404 | } | ||
405 | |||
406 | /* Copy data from/to NFC spare buffers. */ | ||
407 | static void mpc5121_nfc_copy_spare(struct mtd_info *mtd, uint offset, | ||
408 | u8 *buffer, uint size, int wr) | ||
409 | { | ||
410 | struct nand_chip *nand = mtd->priv; | ||
411 | struct mpc5121_nfc_prv *prv = nand->priv; | ||
412 | uint o, s, sbsize, blksize; | ||
413 | |||
414 | /* | ||
415 | * NAND spare area is available through NFC spare buffers. | ||
416 | * The NFC divides spare area into (page_size / 512) chunks. | ||
417 | * Each chunk is placed into separate spare memory area, using | ||
418 | * first (spare_size / num_of_chunks) bytes of the buffer. | ||
419 | * | ||
420 | * For NAND device in which the spare area is not divided fully | ||
421 | * by the number of chunks, number of used bytes in each spare | ||
422 | * buffer is rounded down to the nearest even number of bytes, | ||
423 | * and all remaining bytes are added to the last used spare area. | ||
424 | * | ||
425 | * For more information read section 26.6.10 of MPC5121e | ||
426 | * Microcontroller Reference Manual, Rev. 3. | ||
427 | */ | ||
428 | |||
429 | /* Calculate number of valid bytes in each spare buffer */ | ||
430 | sbsize = (mtd->oobsize / (mtd->writesize / 512)) & ~1; | ||
431 | |||
432 | while (size) { | ||
433 | /* Calculate spare buffer number */ | ||
434 | s = offset / sbsize; | ||
435 | if (s > NFC_SPARE_BUFFERS - 1) | ||
436 | s = NFC_SPARE_BUFFERS - 1; | ||
437 | |||
438 | /* | ||
439 | * Calculate offset to requested data block in selected spare | ||
440 | * buffer and its size. | ||
441 | */ | ||
442 | o = offset - (s * sbsize); | ||
443 | blksize = min(sbsize - o, size); | ||
444 | |||
445 | if (wr) | ||
446 | memcpy_toio(prv->regs + NFC_SPARE_AREA(s) + o, | ||
447 | buffer, blksize); | ||
448 | else | ||
449 | memcpy_fromio(buffer, | ||
450 | prv->regs + NFC_SPARE_AREA(s) + o, blksize); | ||
451 | |||
452 | buffer += blksize; | ||
453 | offset += blksize; | ||
454 | size -= blksize; | ||
455 | }; | ||
456 | } | ||
457 | |||
458 | /* Copy data from/to NFC main and spare buffers */ | ||
459 | static void mpc5121_nfc_buf_copy(struct mtd_info *mtd, u_char *buf, int len, | ||
460 | int wr) | ||
461 | { | ||
462 | struct nand_chip *chip = mtd->priv; | ||
463 | struct mpc5121_nfc_prv *prv = chip->priv; | ||
464 | uint c = prv->column; | ||
465 | uint l; | ||
466 | |||
467 | /* Handle spare area access */ | ||
468 | if (prv->spareonly || c >= mtd->writesize) { | ||
469 | /* Calculate offset from beginning of spare area */ | ||
470 | if (c >= mtd->writesize) | ||
471 | c -= mtd->writesize; | ||
472 | |||
473 | prv->column += len; | ||
474 | mpc5121_nfc_copy_spare(mtd, c, buf, len, wr); | ||
475 | return; | ||
476 | } | ||
477 | |||
478 | /* | ||
479 | * Handle main area access - limit copy length to prevent | ||
480 | * crossing main/spare boundary. | ||
481 | */ | ||
482 | l = min((uint)len, mtd->writesize - c); | ||
483 | prv->column += l; | ||
484 | |||
485 | if (wr) | ||
486 | memcpy_toio(prv->regs + NFC_MAIN_AREA(0) + c, buf, l); | ||
487 | else | ||
488 | memcpy_fromio(buf, prv->regs + NFC_MAIN_AREA(0) + c, l); | ||
489 | |||
490 | /* Handle crossing main/spare boundary */ | ||
491 | if (l != len) { | ||
492 | buf += l; | ||
493 | len -= l; | ||
494 | mpc5121_nfc_buf_copy(mtd, buf, len, wr); | ||
495 | } | ||
496 | } | ||
497 | |||
498 | /* Read data from NFC buffers */ | ||
499 | static void mpc5121_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len) | ||
500 | { | ||
501 | mpc5121_nfc_buf_copy(mtd, buf, len, 0); | ||
502 | } | ||
503 | |||
504 | /* Write data to NFC buffers */ | ||
505 | static void mpc5121_nfc_write_buf(struct mtd_info *mtd, | ||
506 | const u_char *buf, int len) | ||
507 | { | ||
508 | mpc5121_nfc_buf_copy(mtd, (u_char *)buf, len, 1); | ||
509 | } | ||
510 | |||
511 | /* Compare buffer with NAND flash */ | ||
512 | static int mpc5121_nfc_verify_buf(struct mtd_info *mtd, | ||
513 | const u_char *buf, int len) | ||
514 | { | ||
515 | u_char tmp[256]; | ||
516 | uint bsize; | ||
517 | |||
518 | while (len) { | ||
519 | bsize = min(len, 256); | ||
520 | mpc5121_nfc_read_buf(mtd, tmp, bsize); | ||
521 | |||
522 | if (memcmp(buf, tmp, bsize)) | ||
523 | return 1; | ||
524 | |||
525 | buf += bsize; | ||
526 | len -= bsize; | ||
527 | } | ||
528 | |||
529 | return 0; | ||
530 | } | ||
531 | |||
532 | /* Read byte from NFC buffers */ | ||
533 | static u8 mpc5121_nfc_read_byte(struct mtd_info *mtd) | ||
534 | { | ||
535 | u8 tmp; | ||
536 | |||
537 | mpc5121_nfc_read_buf(mtd, &tmp, sizeof(tmp)); | ||
538 | |||
539 | return tmp; | ||
540 | } | ||
541 | |||
542 | /* Read word from NFC buffers */ | ||
543 | static u16 mpc5121_nfc_read_word(struct mtd_info *mtd) | ||
544 | { | ||
545 | u16 tmp; | ||
546 | |||
547 | mpc5121_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp)); | ||
548 | |||
549 | return tmp; | ||
550 | } | ||
551 | |||
552 | /* | ||
553 | * Read NFC configuration from Reset Config Word | ||
554 | * | ||
555 | * NFC is configured during reset in basis of information stored | ||
556 | * in Reset Config Word. There is no other way to set NAND block | ||
557 | * size, spare size and bus width. | ||
558 | */ | ||
559 | static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd) | ||
560 | { | ||
561 | struct nand_chip *chip = mtd->priv; | ||
562 | struct mpc5121_nfc_prv *prv = chip->priv; | ||
563 | struct mpc512x_reset_module *rm; | ||
564 | struct device_node *rmnode; | ||
565 | uint rcw_pagesize = 0; | ||
566 | uint rcw_sparesize = 0; | ||
567 | uint rcw_width; | ||
568 | uint rcwh; | ||
569 | uint romloc, ps; | ||
570 | |||
571 | rmnode = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-reset"); | ||
572 | if (!rmnode) { | ||
573 | dev_err(prv->dev, "Missing 'fsl,mpc5121-reset' " | ||
574 | "node in device tree!\n"); | ||
575 | return -ENODEV; | ||
576 | } | ||
577 | |||
578 | rm = of_iomap(rmnode, 0); | ||
579 | if (!rm) { | ||
580 | dev_err(prv->dev, "Error mapping reset module node!\n"); | ||
581 | return -EBUSY; | ||
582 | } | ||
583 | |||
584 | rcwh = in_be32(&rm->rcwhr); | ||
585 | |||
586 | /* Bit 6: NFC bus width */ | ||
587 | rcw_width = ((rcwh >> 6) & 0x1) ? 2 : 1; | ||
588 | |||
589 | /* Bit 7: NFC Page/Spare size */ | ||
590 | ps = (rcwh >> 7) & 0x1; | ||
591 | |||
592 | /* Bits [22:21]: ROM Location */ | ||
593 | romloc = (rcwh >> 21) & 0x3; | ||
594 | |||
595 | /* Decode RCW bits */ | ||
596 | switch ((ps << 2) | romloc) { | ||
597 | case 0x00: | ||
598 | case 0x01: | ||
599 | rcw_pagesize = 512; | ||
600 | rcw_sparesize = 16; | ||
601 | break; | ||
602 | case 0x02: | ||
603 | case 0x03: | ||
604 | rcw_pagesize = 4096; | ||
605 | rcw_sparesize = 128; | ||
606 | break; | ||
607 | case 0x04: | ||
608 | case 0x05: | ||
609 | rcw_pagesize = 2048; | ||
610 | rcw_sparesize = 64; | ||
611 | break; | ||
612 | case 0x06: | ||
613 | case 0x07: | ||
614 | rcw_pagesize = 4096; | ||
615 | rcw_sparesize = 218; | ||
616 | break; | ||
617 | } | ||
618 | |||
619 | mtd->writesize = rcw_pagesize; | ||
620 | mtd->oobsize = rcw_sparesize; | ||
621 | if (rcw_width == 2) | ||
622 | chip->options |= NAND_BUSWIDTH_16; | ||
623 | |||
624 | dev_notice(prv->dev, "Configured for " | ||
625 | "%u-bit NAND, page size %u " | ||
626 | "with %u spare.\n", | ||
627 | rcw_width * 8, rcw_pagesize, | ||
628 | rcw_sparesize); | ||
629 | iounmap(rm); | ||
630 | of_node_put(rmnode); | ||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | /* Free driver resources */ | ||
635 | static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd) | ||
636 | { | ||
637 | struct nand_chip *chip = mtd->priv; | ||
638 | struct mpc5121_nfc_prv *prv = chip->priv; | ||
639 | |||
640 | if (prv->clk) { | ||
641 | clk_disable(prv->clk); | ||
642 | clk_put(prv->clk); | ||
643 | } | ||
644 | |||
645 | if (prv->csreg) | ||
646 | iounmap(prv->csreg); | ||
647 | } | ||
648 | |||
649 | static int __devinit mpc5121_nfc_probe(struct of_device *op, | ||
650 | const struct of_device_id *match) | ||
651 | { | ||
652 | struct device_node *rootnode, *dn = op->node; | ||
653 | struct device *dev = &op->dev; | ||
654 | struct mpc5121_nfc_prv *prv; | ||
655 | struct resource res; | ||
656 | struct mtd_info *mtd; | ||
657 | #ifdef CONFIG_MTD_PARTITIONS | ||
658 | struct mtd_partition *parts; | ||
659 | #endif | ||
660 | struct nand_chip *chip; | ||
661 | unsigned long regs_paddr, regs_size; | ||
662 | const uint *chips_no; | ||
663 | int resettime = 0; | ||
664 | int retval = 0; | ||
665 | int rev, len; | ||
666 | |||
667 | /* | ||
668 | * Check SoC revision. This driver supports only NFC | ||
669 | * in MPC5121 revision 2. | ||
670 | */ | ||
671 | rev = (mfspr(SPRN_SVR) >> 4) & 0xF; | ||
672 | if (rev != 2) { | ||
673 | dev_err(dev, "SoC revision %u is not supported!\n", rev); | ||
674 | return -ENXIO; | ||
675 | } | ||
676 | |||
677 | prv = devm_kzalloc(dev, sizeof(*prv), GFP_KERNEL); | ||
678 | if (!prv) { | ||
679 | dev_err(dev, "Memory exhausted!\n"); | ||
680 | return -ENOMEM; | ||
681 | } | ||
682 | |||
683 | mtd = &prv->mtd; | ||
684 | chip = &prv->chip; | ||
685 | |||
686 | mtd->priv = chip; | ||
687 | chip->priv = prv; | ||
688 | prv->dev = dev; | ||
689 | |||
690 | /* Read NFC configuration from Reset Config Word */ | ||
691 | retval = mpc5121_nfc_read_hw_config(mtd); | ||
692 | if (retval) { | ||
693 | dev_err(dev, "Unable to read NFC config!\n"); | ||
694 | return retval; | ||
695 | } | ||
696 | |||
697 | prv->irq = irq_of_parse_and_map(dn, 0); | ||
698 | if (prv->irq == NO_IRQ) { | ||
699 | dev_err(dev, "Error mapping IRQ!\n"); | ||
700 | return -EINVAL; | ||
701 | } | ||
702 | |||
703 | retval = of_address_to_resource(dn, 0, &res); | ||
704 | if (retval) { | ||
705 | dev_err(dev, "Error parsing memory region!\n"); | ||
706 | return retval; | ||
707 | } | ||
708 | |||
709 | chips_no = of_get_property(dn, "chips", &len); | ||
710 | if (!chips_no || len != sizeof(*chips_no)) { | ||
711 | dev_err(dev, "Invalid/missing 'chips' property!\n"); | ||
712 | return -EINVAL; | ||
713 | } | ||
714 | |||
715 | regs_paddr = res.start; | ||
716 | regs_size = res.end - res.start + 1; | ||
717 | |||
718 | if (!devm_request_mem_region(dev, regs_paddr, regs_size, DRV_NAME)) { | ||
719 | dev_err(dev, "Error requesting memory region!\n"); | ||
720 | return -EBUSY; | ||
721 | } | ||
722 | |||
723 | prv->regs = devm_ioremap(dev, regs_paddr, regs_size); | ||
724 | if (!prv->regs) { | ||
725 | dev_err(dev, "Error mapping memory region!\n"); | ||
726 | return -ENOMEM; | ||
727 | } | ||
728 | |||
729 | mtd->name = "MPC5121 NAND"; | ||
730 | chip->dev_ready = mpc5121_nfc_dev_ready; | ||
731 | chip->cmdfunc = mpc5121_nfc_command; | ||
732 | chip->read_byte = mpc5121_nfc_read_byte; | ||
733 | chip->read_word = mpc5121_nfc_read_word; | ||
734 | chip->read_buf = mpc5121_nfc_read_buf; | ||
735 | chip->write_buf = mpc5121_nfc_write_buf; | ||
736 | chip->verify_buf = mpc5121_nfc_verify_buf; | ||
737 | chip->select_chip = mpc5121_nfc_select_chip; | ||
738 | chip->options = NAND_NO_AUTOINCR | NAND_USE_FLASH_BBT; | ||
739 | chip->ecc.mode = NAND_ECC_SOFT; | ||
740 | |||
741 | /* Support external chip-select logic on ADS5121 board */ | ||
742 | rootnode = of_find_node_by_path("/"); | ||
743 | if (of_device_is_compatible(rootnode, "fsl,mpc5121ads")) { | ||
744 | retval = ads5121_chipselect_init(mtd); | ||
745 | if (retval) { | ||
746 | dev_err(dev, "Chipselect init error!\n"); | ||
747 | of_node_put(rootnode); | ||
748 | return retval; | ||
749 | } | ||
750 | |||
751 | chip->select_chip = ads5121_select_chip; | ||
752 | } | ||
753 | of_node_put(rootnode); | ||
754 | |||
755 | /* Enable NFC clock */ | ||
756 | prv->clk = clk_get(dev, "nfc_clk"); | ||
757 | if (!prv->clk) { | ||
758 | dev_err(dev, "Unable to acquire NFC clock!\n"); | ||
759 | retval = -ENODEV; | ||
760 | goto error; | ||
761 | } | ||
762 | |||
763 | clk_enable(prv->clk); | ||
764 | |||
765 | /* Reset NAND Flash controller */ | ||
766 | nfc_set(mtd, NFC_CONFIG1, NFC_RESET); | ||
767 | while (nfc_read(mtd, NFC_CONFIG1) & NFC_RESET) { | ||
768 | if (resettime++ >= NFC_RESET_TIMEOUT) { | ||
769 | dev_err(dev, "Timeout while resetting NFC!\n"); | ||
770 | retval = -EINVAL; | ||
771 | goto error; | ||
772 | } | ||
773 | |||
774 | udelay(1); | ||
775 | } | ||
776 | |||
777 | /* Enable write to NFC memory */ | ||
778 | nfc_write(mtd, NFC_CONFIG, NFC_BLS_UNLOCKED); | ||
779 | |||
780 | /* Enable write to all NAND pages */ | ||
781 | nfc_write(mtd, NFC_UNLOCKSTART_BLK0, 0x0000); | ||
782 | nfc_write(mtd, NFC_UNLOCKEND_BLK0, 0xFFFF); | ||
783 | nfc_write(mtd, NFC_WRPROT, NFC_WPC_UNLOCK); | ||
784 | |||
785 | /* | ||
786 | * Setup NFC: | ||
787 | * - Big Endian transfers, | ||
788 | * - Interrupt after full page read/write. | ||
789 | */ | ||
790 | nfc_write(mtd, NFC_CONFIG1, NFC_BIG_ENDIAN | NFC_INT_MASK | | ||
791 | NFC_FULL_PAGE_INT); | ||
792 | |||
793 | /* Set spare area size */ | ||
794 | nfc_write(mtd, NFC_SPAS, mtd->oobsize >> 1); | ||
795 | |||
796 | init_waitqueue_head(&prv->irq_waitq); | ||
797 | retval = devm_request_irq(dev, prv->irq, &mpc5121_nfc_irq, 0, DRV_NAME, | ||
798 | mtd); | ||
799 | if (retval) { | ||
800 | dev_err(dev, "Error requesting IRQ!\n"); | ||
801 | goto error; | ||
802 | } | ||
803 | |||
804 | /* Detect NAND chips */ | ||
805 | if (nand_scan(mtd, *chips_no)) { | ||
806 | dev_err(dev, "NAND Flash not found !\n"); | ||
807 | devm_free_irq(dev, prv->irq, mtd); | ||
808 | retval = -ENXIO; | ||
809 | goto error; | ||
810 | } | ||
811 | |||
812 | /* Set erase block size */ | ||
813 | switch (mtd->erasesize / mtd->writesize) { | ||
814 | case 32: | ||
815 | nfc_set(mtd, NFC_CONFIG1, NFC_PPB_32); | ||
816 | break; | ||
817 | |||
818 | case 64: | ||
819 | nfc_set(mtd, NFC_CONFIG1, NFC_PPB_64); | ||
820 | break; | ||
821 | |||
822 | case 128: | ||
823 | nfc_set(mtd, NFC_CONFIG1, NFC_PPB_128); | ||
824 | break; | ||
825 | |||
826 | case 256: | ||
827 | nfc_set(mtd, NFC_CONFIG1, NFC_PPB_256); | ||
828 | break; | ||
829 | |||
830 | default: | ||
831 | dev_err(dev, "Unsupported NAND flash!\n"); | ||
832 | devm_free_irq(dev, prv->irq, mtd); | ||
833 | retval = -ENXIO; | ||
834 | goto error; | ||
835 | } | ||
836 | |||
837 | dev_set_drvdata(dev, mtd); | ||
838 | |||
839 | /* Register device in MTD */ | ||
840 | #ifdef CONFIG_MTD_PARTITIONS | ||
841 | retval = parse_mtd_partitions(mtd, mpc5121_nfc_pprobes, &parts, 0); | ||
842 | #ifdef CONFIG_MTD_OF_PARTS | ||
843 | if (retval == 0) | ||
844 | retval = of_mtd_parse_partitions(dev, dn, &parts); | ||
845 | #endif | ||
846 | if (retval < 0) { | ||
847 | dev_err(dev, "Error parsing MTD partitions!\n"); | ||
848 | devm_free_irq(dev, prv->irq, mtd); | ||
849 | retval = -EINVAL; | ||
850 | goto error; | ||
851 | } | ||
852 | |||
853 | if (retval > 0) | ||
854 | retval = add_mtd_partitions(mtd, parts, retval); | ||
855 | else | ||
856 | #endif | ||
857 | retval = add_mtd_device(mtd); | ||
858 | |||
859 | if (retval) { | ||
860 | dev_err(dev, "Error adding MTD device!\n"); | ||
861 | devm_free_irq(dev, prv->irq, mtd); | ||
862 | goto error; | ||
863 | } | ||
864 | |||
865 | return 0; | ||
866 | error: | ||
867 | mpc5121_nfc_free(dev, mtd); | ||
868 | return retval; | ||
869 | } | ||
870 | |||
871 | static int __devexit mpc5121_nfc_remove(struct of_device *op) | ||
872 | { | ||
873 | struct device *dev = &op->dev; | ||
874 | struct mtd_info *mtd = dev_get_drvdata(dev); | ||
875 | struct nand_chip *chip = mtd->priv; | ||
876 | struct mpc5121_nfc_prv *prv = chip->priv; | ||
877 | |||
878 | nand_release(mtd); | ||
879 | devm_free_irq(dev, prv->irq, mtd); | ||
880 | mpc5121_nfc_free(dev, mtd); | ||
881 | |||
882 | return 0; | ||
883 | } | ||
884 | |||
885 | static struct of_device_id mpc5121_nfc_match[] __devinitdata = { | ||
886 | { .compatible = "fsl,mpc5121-nfc", }, | ||
887 | {}, | ||
888 | }; | ||
889 | |||
890 | static struct of_platform_driver mpc5121_nfc_driver = { | ||
891 | .match_table = mpc5121_nfc_match, | ||
892 | .probe = mpc5121_nfc_probe, | ||
893 | .remove = __devexit_p(mpc5121_nfc_remove), | ||
894 | .driver = { | ||
895 | .name = DRV_NAME, | ||
896 | .owner = THIS_MODULE, | ||
897 | }, | ||
898 | }; | ||
899 | |||
900 | static int __init mpc5121_nfc_init(void) | ||
901 | { | ||
902 | return of_register_platform_driver(&mpc5121_nfc_driver); | ||
903 | } | ||
904 | |||
905 | module_init(mpc5121_nfc_init); | ||
906 | |||
907 | static void __exit mpc5121_nfc_cleanup(void) | ||
908 | { | ||
909 | of_unregister_platform_driver(&mpc5121_nfc_driver); | ||
910 | } | ||
911 | |||
912 | module_exit(mpc5121_nfc_cleanup); | ||
913 | |||
914 | MODULE_AUTHOR("Freescale Semiconductor, Inc."); | ||
915 | MODULE_DESCRIPTION("MPC5121 NAND MTD driver"); | ||
916 | MODULE_LICENSE("GPL"); | ||