blob: dcc969ff73090f04ca8e1c176b5da6a38c6e6f4a [file] [log] [blame]
Kyungmin Park79e90462007-09-10 17:13:49 +09001/*
2 * linux/drivers/mtd/onenand/onenand_base.c
3 *
4 * Copyright (C) 2005-2007 Samsung Electronics
5 * Kyungmin Park <kyungmin.park@samsung.com>
6 *
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09007 * Credits:
8 * Adrian Hunter <ext-adrian.hunter@nokia.com>:
9 * auto-placement support, read-while load support, various fixes
10 * Copyright (C) Nokia Corporation, 2007
11 *
Kyungmin Park79e90462007-09-10 17:13:49 +090012 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 */
16
17#include <common.h>
Kyungmin Park79e90462007-09-10 17:13:49 +090018#include <linux/mtd/compat.h>
19#include <linux/mtd/mtd.h>
20#include <linux/mtd/onenand.h>
21
22#include <asm/io.h>
23#include <asm/errno.h>
Fathi BOUDRA95feb702008-08-06 10:06:20 +020024#include <malloc.h>
Kyungmin Park79e90462007-09-10 17:13:49 +090025
Kyungmin Park6b85c9f2008-03-31 10:40:36 +090026/* It should access 16-bit instead of 8-bit */
Wolfgang Denkd7024b62008-05-01 21:30:16 +020027static inline void *memcpy_16(void *dst, const void *src, unsigned int len)
Kyungmin Park6b85c9f2008-03-31 10:40:36 +090028{
29 void *ret = dst;
30 short *d = dst;
31 const short *s = src;
32
33 len >>= 1;
34 while (len-- > 0)
35 *d++ = *s++;
36 return ret;
37}
38
Kyungmin Park79e90462007-09-10 17:13:49 +090039static const unsigned char ffchars[] = {
40 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
41 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 16 */
42 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
43 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 32 */
44 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
45 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 48 */
46 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
47 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 64 */
48};
49
50/**
51 * onenand_readw - [OneNAND Interface] Read OneNAND register
52 * @param addr address to read
53 *
54 * Read OneNAND register
55 */
56static unsigned short onenand_readw(void __iomem * addr)
57{
58 return readw(addr);
59}
60
61/**
62 * onenand_writew - [OneNAND Interface] Write OneNAND register with value
63 * @param value value to write
64 * @param addr address to write
65 *
66 * Write OneNAND register with value
67 */
68static void onenand_writew(unsigned short value, void __iomem * addr)
69{
70 writew(value, addr);
71}
72
73/**
74 * onenand_block_address - [DEFAULT] Get block address
75 * @param device the device id
76 * @param block the block
77 * @return translated block address if DDP, otherwise same
78 *
79 * Setup Start Address 1 Register (F100h)
80 */
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +090081static int onenand_block_address(struct onenand_chip *this, int block)
Kyungmin Park79e90462007-09-10 17:13:49 +090082{
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +090083 /* Device Flash Core select, NAND Flash Block Address */
84 if (block & this->density_mask)
85 return ONENAND_DDP_CHIP1 | (block ^ this->density_mask);
Kyungmin Park79e90462007-09-10 17:13:49 +090086
87 return block;
88}
89
90/**
91 * onenand_bufferram_address - [DEFAULT] Get bufferram address
92 * @param device the device id
93 * @param block the block
94 * @return set DBS value if DDP, otherwise 0
95 *
96 * Setup Start Address 2 Register (F101h) for DDP
97 */
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +090098static int onenand_bufferram_address(struct onenand_chip *this, int block)
Kyungmin Park79e90462007-09-10 17:13:49 +090099{
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900100 /* Device BufferRAM Select */
101 if (block & this->density_mask)
102 return ONENAND_DDP_CHIP1;
Kyungmin Park79e90462007-09-10 17:13:49 +0900103
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900104 return ONENAND_DDP_CHIP0;
Kyungmin Park79e90462007-09-10 17:13:49 +0900105}
106
107/**
108 * onenand_page_address - [DEFAULT] Get page address
109 * @param page the page address
110 * @param sector the sector address
111 * @return combined page and sector address
112 *
113 * Setup Start Address 8 Register (F107h)
114 */
115static int onenand_page_address(int page, int sector)
116{
117 /* Flash Page Address, Flash Sector Address */
118 int fpa, fsa;
119
120 fpa = page & ONENAND_FPA_MASK;
121 fsa = sector & ONENAND_FSA_MASK;
122
123 return ((fpa << ONENAND_FPA_SHIFT) | fsa);
124}
125
126/**
127 * onenand_buffer_address - [DEFAULT] Get buffer address
128 * @param dataram1 DataRAM index
129 * @param sectors the sector address
130 * @param count the number of sectors
131 * @return the start buffer value
132 *
133 * Setup Start Buffer Register (F200h)
134 */
135static int onenand_buffer_address(int dataram1, int sectors, int count)
136{
137 int bsa, bsc;
138
139 /* BufferRAM Sector Address */
140 bsa = sectors & ONENAND_BSA_MASK;
141
142 if (dataram1)
143 bsa |= ONENAND_BSA_DATARAM1; /* DataRAM1 */
144 else
145 bsa |= ONENAND_BSA_DATARAM0; /* DataRAM0 */
146
147 /* BufferRAM Sector Count */
148 bsc = count & ONENAND_BSC_MASK;
149
150 return ((bsa << ONENAND_BSA_SHIFT) | bsc);
151}
152
153/**
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900154 * onenand_get_density - [DEFAULT] Get OneNAND density
155 * @param dev_id OneNAND device ID
156 *
157 * Get OneNAND density from device ID
158 */
159static inline int onenand_get_density(int dev_id)
160{
161 int density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
162 return (density & ONENAND_DEVICE_DENSITY_MASK);
163}
164
165/**
Kyungmin Park79e90462007-09-10 17:13:49 +0900166 * onenand_command - [DEFAULT] Send command to OneNAND device
167 * @param mtd MTD device structure
168 * @param cmd the command to be sent
169 * @param addr offset to read from or write to
170 * @param len number of bytes to read or write
171 *
172 * Send command to OneNAND device. This function is used for middle/large page
173 * devices (1KB/2KB Bytes per page)
174 */
175static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
176 size_t len)
177{
178 struct onenand_chip *this = mtd->priv;
179 int value, readcmd = 0;
180 int block, page;
181 /* Now we use page size operation */
182 int sectors = 4, count = 4;
183
184 /* Address translation */
185 switch (cmd) {
186 case ONENAND_CMD_UNLOCK:
187 case ONENAND_CMD_LOCK:
188 case ONENAND_CMD_LOCK_TIGHT:
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900189 case ONENAND_CMD_UNLOCK_ALL:
Kyungmin Park79e90462007-09-10 17:13:49 +0900190 block = -1;
191 page = -1;
192 break;
193
194 case ONENAND_CMD_ERASE:
195 case ONENAND_CMD_BUFFERRAM:
196 block = (int)(addr >> this->erase_shift);
197 page = -1;
198 break;
199
200 default:
201 block = (int)(addr >> this->erase_shift);
202 page = (int)(addr >> this->page_shift);
203 page &= this->page_mask;
204 break;
205 }
206
207 /* NOTE: The setting order of the registers is very important! */
208 if (cmd == ONENAND_CMD_BUFFERRAM) {
209 /* Select DataRAM for DDP */
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900210 value = onenand_bufferram_address(this, block);
Kyungmin Park79e90462007-09-10 17:13:49 +0900211 this->write_word(value,
212 this->base + ONENAND_REG_START_ADDRESS2);
213
214 /* Switch to the next data buffer */
215 ONENAND_SET_NEXT_BUFFERRAM(this);
216
217 return 0;
218 }
219
220 if (block != -1) {
221 /* Write 'DFS, FBA' of Flash */
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900222 value = onenand_block_address(this, block);
Kyungmin Park79e90462007-09-10 17:13:49 +0900223 this->write_word(value,
224 this->base + ONENAND_REG_START_ADDRESS1);
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900225
226 /* Write 'DFS, FBA' of Flash */
227 value = onenand_bufferram_address(this, block);
228 this->write_word(value,
229 this->base + ONENAND_REG_START_ADDRESS2);
Kyungmin Park79e90462007-09-10 17:13:49 +0900230 }
231
232 if (page != -1) {
233 int dataram;
234
235 switch (cmd) {
236 case ONENAND_CMD_READ:
237 case ONENAND_CMD_READOOB:
238 dataram = ONENAND_SET_NEXT_BUFFERRAM(this);
239 readcmd = 1;
240 break;
241
242 default:
243 dataram = ONENAND_CURRENT_BUFFERRAM(this);
244 break;
245 }
246
247 /* Write 'FPA, FSA' of Flash */
248 value = onenand_page_address(page, sectors);
249 this->write_word(value,
250 this->base + ONENAND_REG_START_ADDRESS8);
251
252 /* Write 'BSA, BSC' of DataRAM */
253 value = onenand_buffer_address(dataram, sectors, count);
254 this->write_word(value, this->base + ONENAND_REG_START_BUFFER);
Kyungmin Park79e90462007-09-10 17:13:49 +0900255 }
256
257 /* Interrupt clear */
258 this->write_word(ONENAND_INT_CLEAR, this->base + ONENAND_REG_INTERRUPT);
259 /* Write command */
260 this->write_word(cmd, this->base + ONENAND_REG_COMMAND);
261
262 return 0;
263}
264
265/**
266 * onenand_wait - [DEFAULT] wait until the command is done
267 * @param mtd MTD device structure
268 * @param state state to select the max. timeout value
269 *
270 * Wait for command done. This applies to all OneNAND command
271 * Read can take up to 30us, erase up to 2ms and program up to 350us
272 * according to general OneNAND specs
273 */
274static int onenand_wait(struct mtd_info *mtd, int state)
275{
276 struct onenand_chip *this = mtd->priv;
277 unsigned int flags = ONENAND_INT_MASTER;
278 unsigned int interrupt = 0;
279 unsigned int ctrl, ecc;
280
281 while (1) {
282 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
283 if (interrupt & flags)
284 break;
285 }
286
287 ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
288
289 if (ctrl & ONENAND_CTRL_ERROR) {
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900290 printk("onenand_wait: controller error = 0x%04x\n", ctrl);
291 if (ctrl & ONENAND_CTRL_LOCK)
292 printk("onenand_wait: it's locked error = 0x%04x\n",
293 ctrl);
Kyungmin Park79e90462007-09-10 17:13:49 +0900294
Kyungmin Park79e90462007-09-10 17:13:49 +0900295 return -EIO;
296 }
297
298 if (interrupt & ONENAND_INT_READ) {
299 ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
300 if (ecc & ONENAND_ECC_2BIT_ALL) {
Scott Wooddf83c472008-06-20 12:38:57 -0500301 MTDDEBUG (MTD_DEBUG_LEVEL0,
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200302 "onenand_wait: ECC error = 0x%04x\n", ecc);
Kyungmin Park79e90462007-09-10 17:13:49 +0900303 return -EBADMSG;
304 }
305 }
306
307 return 0;
308}
309
310/**
311 * onenand_bufferram_offset - [DEFAULT] BufferRAM offset
312 * @param mtd MTD data structure
313 * @param area BufferRAM area
314 * @return offset given area
315 *
316 * Return BufferRAM offset given area
317 */
318static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area)
319{
320 struct onenand_chip *this = mtd->priv;
321
322 if (ONENAND_CURRENT_BUFFERRAM(this)) {
323 if (area == ONENAND_DATARAM)
Kyungmin Park396b0c42008-08-13 09:11:02 +0900324 return mtd->writesize;
Kyungmin Park79e90462007-09-10 17:13:49 +0900325 if (area == ONENAND_SPARERAM)
326 return mtd->oobsize;
327 }
328
329 return 0;
330}
331
332/**
333 * onenand_read_bufferram - [OneNAND Interface] Read the bufferram area
334 * @param mtd MTD data structure
335 * @param area BufferRAM area
336 * @param buffer the databuffer to put/get data
337 * @param offset offset to read from or write to
338 * @param count number of bytes to read/write
339 *
340 * Read the BufferRAM area
341 */
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900342static int onenand_read_bufferram(struct mtd_info *mtd, loff_t addr, int area,
Kyungmin Park79e90462007-09-10 17:13:49 +0900343 unsigned char *buffer, int offset,
344 size_t count)
345{
346 struct onenand_chip *this = mtd->priv;
347 void __iomem *bufferram;
348
349 bufferram = this->base + area;
350 bufferram += onenand_bufferram_offset(mtd, area);
351
Wolfgang Denkd7024b62008-05-01 21:30:16 +0200352 memcpy_16(buffer, bufferram + offset, count);
Kyungmin Park79e90462007-09-10 17:13:49 +0900353
354 return 0;
355}
356
357/**
358 * onenand_sync_read_bufferram - [OneNAND Interface] Read the bufferram area with Sync. Burst mode
359 * @param mtd MTD data structure
360 * @param area BufferRAM area
361 * @param buffer the databuffer to put/get data
362 * @param offset offset to read from or write to
363 * @param count number of bytes to read/write
364 *
365 * Read the BufferRAM area with Sync. Burst Mode
366 */
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900367static int onenand_sync_read_bufferram(struct mtd_info *mtd, loff_t addr, int area,
Kyungmin Park79e90462007-09-10 17:13:49 +0900368 unsigned char *buffer, int offset,
369 size_t count)
370{
371 struct onenand_chip *this = mtd->priv;
372 void __iomem *bufferram;
373
374 bufferram = this->base + area;
375 bufferram += onenand_bufferram_offset(mtd, area);
376
377 this->mmcontrol(mtd, ONENAND_SYS_CFG1_SYNC_READ);
378
Wolfgang Denkd7024b62008-05-01 21:30:16 +0200379 memcpy_16(buffer, bufferram + offset, count);
Kyungmin Park79e90462007-09-10 17:13:49 +0900380
381 this->mmcontrol(mtd, 0);
382
383 return 0;
384}
385
386/**
387 * onenand_write_bufferram - [OneNAND Interface] Write the bufferram area
388 * @param mtd MTD data structure
389 * @param area BufferRAM area
390 * @param buffer the databuffer to put/get data
391 * @param offset offset to read from or write to
392 * @param count number of bytes to read/write
393 *
394 * Write the BufferRAM area
395 */
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900396static int onenand_write_bufferram(struct mtd_info *mtd, loff_t addr, int area,
Kyungmin Park79e90462007-09-10 17:13:49 +0900397 const unsigned char *buffer, int offset,
398 size_t count)
399{
400 struct onenand_chip *this = mtd->priv;
401 void __iomem *bufferram;
402
403 bufferram = this->base + area;
404 bufferram += onenand_bufferram_offset(mtd, area);
405
Wolfgang Denkd7024b62008-05-01 21:30:16 +0200406 memcpy_16(bufferram + offset, buffer, count);
Kyungmin Park79e90462007-09-10 17:13:49 +0900407
408 return 0;
409}
410
411/**
Stefan Roese5ed79ae2008-11-11 10:28:53 +0100412 * onenand_get_2x_blockpage - [GENERIC] Get blockpage at 2x program mode
413 * @param mtd MTD data structure
414 * @param addr address to check
415 * @return blockpage address
416 *
417 * Get blockpage address at 2x program mode
418 */
419static int onenand_get_2x_blockpage(struct mtd_info *mtd, loff_t addr)
420{
421 struct onenand_chip *this = mtd->priv;
422 int blockpage, block, page;
423
424 /* Calculate the even block number */
425 block = (int) (addr >> this->erase_shift) & ~1;
426 /* Is it the odd plane? */
427 if (addr & this->writesize)
428 block++;
429 page = (int) (addr >> (this->page_shift + 1)) & this->page_mask;
430 blockpage = (block << 7) | page;
431
432 return blockpage;
433}
434
435/**
Kyungmin Park79e90462007-09-10 17:13:49 +0900436 * onenand_check_bufferram - [GENERIC] Check BufferRAM information
437 * @param mtd MTD data structure
438 * @param addr address to check
439 * @return 1 if there are valid data, otherwise 0
440 *
441 * Check bufferram if there is data we required
442 */
443static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr)
444{
445 struct onenand_chip *this = mtd->priv;
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900446 int blockpage, found = 0;
447 unsigned int i;
Kyungmin Park79e90462007-09-10 17:13:49 +0900448
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900449#ifdef CONFIG_S3C64XX
450 return 0;
451#endif
Kyungmin Park79e90462007-09-10 17:13:49 +0900452
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900453 if (ONENAND_IS_2PLANE(this))
454 blockpage = onenand_get_2x_blockpage(mtd, addr);
455 else
456 blockpage = (int) (addr >> this->page_shift);
Kyungmin Park79e90462007-09-10 17:13:49 +0900457
458 /* Is there valid data? */
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900459 i = ONENAND_CURRENT_BUFFERRAM(this);
460 if (this->bufferram[i].blockpage == blockpage)
461 found = 1;
462 else {
463 /* Check another BufferRAM */
464 i = ONENAND_NEXT_BUFFERRAM(this);
465 if (this->bufferram[i].blockpage == blockpage) {
466 ONENAND_SET_NEXT_BUFFERRAM(this);
467 found = 1;
468 }
469 }
Kyungmin Park79e90462007-09-10 17:13:49 +0900470
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900471 if (found && ONENAND_IS_DDP(this)) {
472 /* Select DataRAM for DDP */
473 int block = (int) (addr >> this->erase_shift);
474 int value = onenand_bufferram_address(this, block);
475 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
476 }
477
478 return found;
Kyungmin Park79e90462007-09-10 17:13:49 +0900479}
480
481/**
482 * onenand_update_bufferram - [GENERIC] Update BufferRAM information
483 * @param mtd MTD data structure
484 * @param addr address to update
485 * @param valid valid flag
486 *
487 * Update BufferRAM information
488 */
489static int onenand_update_bufferram(struct mtd_info *mtd, loff_t addr,
490 int valid)
491{
492 struct onenand_chip *this = mtd->priv;
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900493 int blockpage;
494 unsigned int i;
Kyungmin Park79e90462007-09-10 17:13:49 +0900495
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900496 if (ONENAND_IS_2PLANE(this))
497 blockpage = onenand_get_2x_blockpage(mtd, addr);
498 else
499 blockpage = (int)(addr >> this->page_shift);
Kyungmin Park79e90462007-09-10 17:13:49 +0900500
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900501 /* Invalidate another BufferRAM */
502 i = ONENAND_NEXT_BUFFERRAM(this);
503 if (this->bufferram[i].blockpage == blockpage)
504 this->bufferram[i].blockpage = -1;
Kyungmin Park79e90462007-09-10 17:13:49 +0900505
506 /* Update BufferRAM */
507 i = ONENAND_CURRENT_BUFFERRAM(this);
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900508 if (valid)
509 this->bufferram[i].blockpage = blockpage;
510 else
511 this->bufferram[i].blockpage = -1;
Kyungmin Park79e90462007-09-10 17:13:49 +0900512
513 return 0;
514}
515
516/**
Kyungmin Park396b0c42008-08-13 09:11:02 +0900517 * onenand_invalidate_bufferram - [GENERIC] Invalidate BufferRAM information
518 * @param mtd MTD data structure
519 * @param addr start address to invalidate
520 * @param len length to invalidate
521 *
522 * Invalidate BufferRAM information
523 */
524static void onenand_invalidate_bufferram(struct mtd_info *mtd, loff_t addr,
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200525 unsigned int len)
Kyungmin Park396b0c42008-08-13 09:11:02 +0900526{
527 struct onenand_chip *this = mtd->priv;
528 int i;
529 loff_t end_addr = addr + len;
530
531 /* Invalidate BufferRAM */
532 for (i = 0; i < MAX_BUFFERRAM; i++) {
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900533 loff_t buf_addr = this->bufferram[i].blockpage << this->page_shift;
Kyungmin Park396b0c42008-08-13 09:11:02 +0900534
535 if (buf_addr >= addr && buf_addr < end_addr)
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900536 this->bufferram[i].blockpage = -1;
Kyungmin Park396b0c42008-08-13 09:11:02 +0900537 }
538}
539
540/**
Kyungmin Park79e90462007-09-10 17:13:49 +0900541 * onenand_get_device - [GENERIC] Get chip for selected access
542 * @param mtd MTD device structure
543 * @param new_state the state which is requested
544 *
545 * Get the device and lock it for exclusive access
546 */
547static void onenand_get_device(struct mtd_info *mtd, int new_state)
548{
549 /* Do nothing */
550}
551
552/**
553 * onenand_release_device - [GENERIC] release chip
554 * @param mtd MTD device structure
555 *
556 * Deselect, release chip lock and wake up anyone waiting on the device
557 */
558static void onenand_release_device(struct mtd_info *mtd)
559{
560 /* Do nothing */
561}
562
563/**
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900564 * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer
565 * @param mtd MTD device structure
566 * @param buf destination address
567 * @param column oob offset to read from
568 * @param thislen oob length to read
569 */
570static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf,
571 int column, int thislen)
572{
573 struct onenand_chip *this = mtd->priv;
574 struct nand_oobfree *free;
575 int readcol = column;
576 int readend = column + thislen;
577 int lastgap = 0;
578 unsigned int i;
579 uint8_t *oob_buf = this->oob_buf;
580
581 free = this->ecclayout->oobfree;
582 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
583 if (readcol >= lastgap)
584 readcol += free->offset - lastgap;
585 if (readend >= lastgap)
586 readend += free->offset - lastgap;
587 lastgap = free->offset + free->length;
588 }
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900589 this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900590 free = this->ecclayout->oobfree;
591 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
592 int free_end = free->offset + free->length;
593 if (free->offset < readend && free_end > readcol) {
594 int st = max_t(int,free->offset,readcol);
595 int ed = min_t(int,free_end,readend);
596 int n = ed - st;
597 memcpy(buf, oob_buf + st, n);
598 buf += n;
599 } else if (column == 0)
600 break;
601 }
602 return 0;
603}
604
605/**
606 * onenand_read_ops_nolock - [OneNAND Interface] OneNAND read main and/or out-of-band
Kyungmin Park79e90462007-09-10 17:13:49 +0900607 * @param mtd MTD device structure
608 * @param from offset to read from
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900609 * @param ops oob operation description structure
Kyungmin Park79e90462007-09-10 17:13:49 +0900610 *
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900611 * OneNAND read main and/or out-of-band data
Kyungmin Park79e90462007-09-10 17:13:49 +0900612 */
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900613static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
614 struct mtd_oob_ops *ops)
Kyungmin Park79e90462007-09-10 17:13:49 +0900615{
616 struct onenand_chip *this = mtd->priv;
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900617 struct mtd_ecc_stats stats;
618 size_t len = ops->len;
619 size_t ooblen = ops->ooblen;
620 u_char *buf = ops->datbuf;
621 u_char *oobbuf = ops->oobbuf;
622 int read = 0, column, thislen;
623 int oobread = 0, oobcolumn, thisooblen, oobsize;
624 int ret = 0, boundary = 0;
625 int writesize = this->writesize;
Kyungmin Park79e90462007-09-10 17:13:49 +0900626
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900627 MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ops_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900628
629 if (ops->mode == MTD_OOB_AUTO)
630 oobsize = this->ecclayout->oobavail;
631 else
632 oobsize = mtd->oobsize;
633
634 oobcolumn = from & (mtd->oobsize - 1);
Kyungmin Park79e90462007-09-10 17:13:49 +0900635
636 /* Do not allow reads past end of device */
637 if ((from + len) > mtd->size) {
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900638 printk(KERN_ERR "onenand_read_ops_nolock: Attempt read beyond end of device\n");
639 ops->retlen = 0;
640 ops->oobretlen = 0;
Kyungmin Park79e90462007-09-10 17:13:49 +0900641 return -EINVAL;
642 }
643
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900644 stats = mtd->ecc_stats;
Kyungmin Park79e90462007-09-10 17:13:49 +0900645
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900646 /* Read-while-load method */
Kyungmin Park79e90462007-09-10 17:13:49 +0900647
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900648 /* Do first load to bufferRAM */
649 if (read < len) {
Kyungmin Park79e90462007-09-10 17:13:49 +0900650 if (!onenand_check_bufferram(mtd, from)) {
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900651 this->main_buf = buf;
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900652 this->command(mtd, ONENAND_CMD_READ, from, writesize);
Kyungmin Park79e90462007-09-10 17:13:49 +0900653 ret = this->wait(mtd, FL_READING);
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900654 onenand_update_bufferram(mtd, from, !ret);
655 if (ret == -EBADMSG)
656 ret = 0;
Kyungmin Park79e90462007-09-10 17:13:49 +0900657 }
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900658 }
Kyungmin Park79e90462007-09-10 17:13:49 +0900659
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900660 thislen = min_t(int, writesize, len - read);
661 column = from & (writesize - 1);
662 if (column + thislen > writesize)
663 thislen = writesize - column;
Kyungmin Park79e90462007-09-10 17:13:49 +0900664
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900665 while (!ret) {
666 /* If there is more to load then start next load */
667 from += thislen;
668 if (read + thislen < len) {
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900669 this->main_buf = buf + thislen;
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900670 this->command(mtd, ONENAND_CMD_READ, from, writesize);
671 /*
672 * Chip boundary handling in DDP
673 * Now we issued chip 1 read and pointed chip 1
674 * bufferam so we have to point chip 0 bufferam.
675 */
676 if (ONENAND_IS_DDP(this) &&
677 unlikely(from == (this->chipsize >> 1))) {
678 this->write_word(ONENAND_DDP_CHIP0, this->base + ONENAND_REG_START_ADDRESS2);
679 boundary = 1;
680 } else
681 boundary = 0;
682 ONENAND_SET_PREV_BUFFERRAM(this);
683 }
Kyungmin Park79e90462007-09-10 17:13:49 +0900684
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900685 /* While load is going, read from last bufferRAM */
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900686 this->read_bufferram(mtd, from - thislen, ONENAND_DATARAM, buf, column, thislen);
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900687
688 /* Read oob area if needed */
689 if (oobbuf) {
690 thisooblen = oobsize - oobcolumn;
691 thisooblen = min_t(int, thisooblen, ooblen - oobread);
692
693 if (ops->mode == MTD_OOB_AUTO)
694 onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);
695 else
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900696 this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen);
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900697 oobread += thisooblen;
698 oobbuf += thisooblen;
699 oobcolumn = 0;
Kyungmin Park79e90462007-09-10 17:13:49 +0900700 }
701
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900702 /* See if we are done */
703 read += thislen;
704 if (read == len)
705 break;
706 /* Set up for next read from bufferRAM */
707 if (unlikely(boundary))
708 this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);
709 ONENAND_SET_NEXT_BUFFERRAM(this);
Kyungmin Park79e90462007-09-10 17:13:49 +0900710 buf += thislen;
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900711 thislen = min_t(int, writesize, len - read);
712 column = 0;
Kyungmin Park79e90462007-09-10 17:13:49 +0900713
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900714 /* Now wait for load */
715 ret = this->wait(mtd, FL_READING);
716 onenand_update_bufferram(mtd, from, !ret);
717 if (ret == -EBADMSG)
718 ret = 0;
719 }
Kyungmin Park79e90462007-09-10 17:13:49 +0900720
721 /*
722 * Return success, if no ECC failures, else -EBADMSG
723 * fs driver will take care of that, because
724 * retlen == desired len and result == -EBADMSG
725 */
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900726 ops->retlen = read;
727 ops->oobretlen = oobread;
728
729 if (ret)
730 return ret;
731
732 if (mtd->ecc_stats.failed - stats.failed)
733 return -EBADMSG;
734
735 return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
Kyungmin Park79e90462007-09-10 17:13:49 +0900736}
737
738/**
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900739 * onenand_read_oob_nolock - [MTD Interface] OneNAND read out-of-band
740 * @param mtd MTD device structure
741 * @param from offset to read from
742 * @param ops oob operation description structure
743 *
744 * OneNAND read out-of-band data from the spare area
745 */
746static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
747 struct mtd_oob_ops *ops)
748{
749 struct onenand_chip *this = mtd->priv;
750 struct mtd_ecc_stats stats;
751 int read = 0, thislen, column, oobsize;
752 size_t len = ops->ooblen;
753 mtd_oob_mode_t mode = ops->mode;
754 u_char *buf = ops->oobbuf;
755 int ret = 0;
756
757 from += ops->ooboffs;
758
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900759 MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900760
761 /* Initialize return length value */
762 ops->oobretlen = 0;
763
764 if (mode == MTD_OOB_AUTO)
765 oobsize = this->ecclayout->oobavail;
766 else
767 oobsize = mtd->oobsize;
768
769 column = from & (mtd->oobsize - 1);
770
771 if (unlikely(column >= oobsize)) {
772 printk(KERN_ERR "onenand_read_oob_nolock: Attempted to start read outside oob\n");
773 return -EINVAL;
774 }
775
776 /* Do not allow reads past end of device */
777 if (unlikely(from >= mtd->size ||
778 column + len > ((mtd->size >> this->page_shift) -
779 (from >> this->page_shift)) * oobsize)) {
780 printk(KERN_ERR "onenand_read_oob_nolock: Attempted to read beyond end of device\n");
781 return -EINVAL;
782 }
783
784 stats = mtd->ecc_stats;
785
786 while (read < len) {
787 thislen = oobsize - column;
788 thislen = min_t(int, thislen, len);
789
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900790 this->spare_buf = buf;
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900791 this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);
792
793 onenand_update_bufferram(mtd, from, 0);
794
795 ret = this->wait(mtd, FL_READING);
796 if (ret && ret != -EBADMSG) {
797 printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret);
798 break;
799 }
800
801 if (mode == MTD_OOB_AUTO)
802 onenand_transfer_auto_oob(mtd, buf, column, thislen);
803 else
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900804 this->read_bufferram(mtd, 0, ONENAND_SPARERAM, buf, column, thislen);
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900805
806 read += thislen;
807
808 if (read == len)
809 break;
810
811 buf += thislen;
812
813 /* Read more? */
814 if (read < len) {
815 /* Page size */
816 from += mtd->writesize;
817 column = 0;
818 }
819 }
820
821 ops->oobretlen = read;
822
823 if (ret)
824 return ret;
825
826 if (mtd->ecc_stats.failed - stats.failed)
827 return -EBADMSG;
828
829 return 0;
830}
831
832/**
Kyungmin Park79e90462007-09-10 17:13:49 +0900833 * onenand_read - [MTD Interface] MTD compability function for onenand_read_ecc
834 * @param mtd MTD device structure
835 * @param from offset to read from
836 * @param len number of bytes to read
837 * @param retlen pointer to variable to store the number of read bytes
838 * @param buf the databuffer to put data
839 *
840 * This function simply calls onenand_read_ecc with oob buffer and oobsel = NULL
841*/
842int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
843 size_t * retlen, u_char * buf)
844{
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900845 struct mtd_oob_ops ops = {
846 .len = len,
847 .ooblen = 0,
848 .datbuf = buf,
849 .oobbuf = NULL,
850 };
851 int ret;
852
853 onenand_get_device(mtd, FL_READING);
854 ret = onenand_read_ops_nolock(mtd, from, &ops);
855 onenand_release_device(mtd);
856
857 *retlen = ops.retlen;
858 return ret;
Kyungmin Park79e90462007-09-10 17:13:49 +0900859}
860
861/**
862 * onenand_read_oob - [MTD Interface] OneNAND read out-of-band
863 * @param mtd MTD device structure
864 * @param from offset to read from
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900865 * @param ops oob operations description structure
Kyungmin Park79e90462007-09-10 17:13:49 +0900866 *
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900867 * OneNAND main and/or out-of-band
868 */
869int onenand_read_oob(struct mtd_info *mtd, loff_t from,
870 struct mtd_oob_ops *ops)
871{
872 int ret;
873
874 switch (ops->mode) {
875 case MTD_OOB_PLACE:
876 case MTD_OOB_AUTO:
877 break;
878 case MTD_OOB_RAW:
879 /* Not implemented yet */
880 default:
881 return -EINVAL;
882 }
883
884 onenand_get_device(mtd, FL_READING);
885 if (ops->datbuf)
886 ret = onenand_read_ops_nolock(mtd, from, ops);
887 else
888 ret = onenand_read_oob_nolock(mtd, from, ops);
889 onenand_release_device(mtd);
890
891 return ret;
892}
893
894/**
895 * onenand_bbt_wait - [DEFAULT] wait until the command is done
896 * @param mtd MTD device structure
897 * @param state state to select the max. timeout value
898 *
899 * Wait for command done.
Kyungmin Park79e90462007-09-10 17:13:49 +0900900 */
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900901static int onenand_bbt_wait(struct mtd_info *mtd, int state)
Kyungmin Park79e90462007-09-10 17:13:49 +0900902{
903 struct onenand_chip *this = mtd->priv;
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900904 unsigned int flags = ONENAND_INT_MASTER;
905 unsigned int interrupt;
906 unsigned int ctrl;
907
908 while (1) {
909 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
910 if (interrupt & flags)
911 break;
912 }
913
914 /* To get correct interrupt status in timeout case */
915 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
916 ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
917
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900918 if (interrupt & ONENAND_INT_READ) {
919 int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
920 if (ecc & ONENAND_ECC_2BIT_ALL)
921 return ONENAND_BBT_READ_ERROR;
922 } else {
923 printk(KERN_ERR "onenand_bbt_wait: read timeout!"
924 "ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt);
925 return ONENAND_BBT_READ_FATAL_ERROR;
926 }
927
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900928 /* Initial bad block case: 0x2400 or 0x0400 */
929 if (ctrl & ONENAND_CTRL_ERROR) {
930 printk(KERN_DEBUG "onenand_bbt_wait: controller error = 0x%04x\n", ctrl);
931 return ONENAND_BBT_READ_ERROR;
932 }
933
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900934 return 0;
935}
936
937/**
938 * onenand_bbt_read_oob - [MTD Interface] OneNAND read out-of-band for bbt scan
939 * @param mtd MTD device structure
940 * @param from offset to read from
941 * @param ops oob operation description structure
942 *
943 * OneNAND read out-of-band data from the spare area for bbt scan
944 */
945int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
946 struct mtd_oob_ops *ops)
947{
948 struct onenand_chip *this = mtd->priv;
Kyungmin Park79e90462007-09-10 17:13:49 +0900949 int read = 0, thislen, column;
950 int ret = 0;
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900951 size_t len = ops->ooblen;
952 u_char *buf = ops->oobbuf;
Kyungmin Park79e90462007-09-10 17:13:49 +0900953
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900954 MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_bbt_read_oob: from = 0x%08x, len = %zi\n", (unsigned int) from, len);
Kyungmin Park79e90462007-09-10 17:13:49 +0900955
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900956 /* Initialize return value */
957 ops->oobretlen = 0;
Kyungmin Park79e90462007-09-10 17:13:49 +0900958
959 /* Do not allow reads past end of device */
960 if (unlikely((from + len) > mtd->size)) {
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900961 printk(KERN_ERR "onenand_bbt_read_oob: Attempt read beyond end of device\n");
962 return ONENAND_BBT_READ_FATAL_ERROR;
Kyungmin Park79e90462007-09-10 17:13:49 +0900963 }
964
965 /* Grab the lock and see if the device is available */
966 onenand_get_device(mtd, FL_READING);
967
968 column = from & (mtd->oobsize - 1);
969
970 while (read < len) {
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900971
Kyungmin Park79e90462007-09-10 17:13:49 +0900972 thislen = mtd->oobsize - column;
973 thislen = min_t(int, thislen, len);
974
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900975 this->spare_buf = buf;
Kyungmin Park79e90462007-09-10 17:13:49 +0900976 this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);
977
978 onenand_update_bufferram(mtd, from, 0);
979
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900980 ret = this->bbt_wait(mtd, FL_READING);
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900981 if (ret)
982 break;
Kyungmin Park79e90462007-09-10 17:13:49 +0900983
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +0900984 this->read_spareram(mtd, 0, ONENAND_SPARERAM, buf, column, thislen);
Kyungmin Park79e90462007-09-10 17:13:49 +0900985 read += thislen;
986 if (read == len)
987 break;
988
Kyungmin Park79e90462007-09-10 17:13:49 +0900989 buf += thislen;
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900990
Kyungmin Park79e90462007-09-10 17:13:49 +0900991 /* Read more? */
992 if (read < len) {
Kyungmin Park5d7a01c2008-08-19 08:42:53 +0900993 /* Update Page size */
994 from += this->writesize;
Kyungmin Park79e90462007-09-10 17:13:49 +0900995 column = 0;
996 }
997 }
998
999 /* Deselect and wake up anyone waiting on the device */
1000 onenand_release_device(mtd);
1001
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001002 ops->oobretlen = read;
Kyungmin Park79e90462007-09-10 17:13:49 +09001003 return ret;
1004}
1005
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001006
Kyungmin Park79e90462007-09-10 17:13:49 +09001007#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
1008/**
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001009 * onenand_verify_oob - [GENERIC] verify the oob contents after a write
1010 * @param mtd MTD device structure
1011 * @param buf the databuffer to verify
1012 * @param to offset to read from
Kyungmin Park79e90462007-09-10 17:13:49 +09001013 */
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001014static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to)
Kyungmin Park79e90462007-09-10 17:13:49 +09001015{
1016 struct onenand_chip *this = mtd->priv;
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001017 u_char *oob_buf = this->oob_buf;
1018 int status, i;
1019
1020 this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize);
1021 onenand_update_bufferram(mtd, to, 0);
1022 status = this->wait(mtd, FL_READING);
1023 if (status)
1024 return status;
1025
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001026 this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001027 for (i = 0; i < mtd->oobsize; i++)
1028 if (buf[i] != 0xFF && buf[i] != oob_buf[i])
1029 return -EBADMSG;
1030
1031 return 0;
1032}
1033
1034/**
1035 * onenand_verify - [GENERIC] verify the chip contents after a write
1036 * @param mtd MTD device structure
1037 * @param buf the databuffer to verify
1038 * @param addr offset to read from
1039 * @param len number of bytes to read and compare
1040 */
1041static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, size_t len)
1042{
1043 struct onenand_chip *this = mtd->priv;
1044 void __iomem *dataram;
Kyungmin Park79e90462007-09-10 17:13:49 +09001045 int ret = 0;
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001046 int thislen, column;
Kyungmin Park79e90462007-09-10 17:13:49 +09001047
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001048 while (len != 0) {
1049 thislen = min_t(int, this->writesize, len);
1050 column = addr & (this->writesize - 1);
1051 if (column + thislen > this->writesize)
1052 thislen = this->writesize - column;
Kyungmin Park79e90462007-09-10 17:13:49 +09001053
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001054 this->command(mtd, ONENAND_CMD_READ, addr, this->writesize);
Kyungmin Park79e90462007-09-10 17:13:49 +09001055
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001056 onenand_update_bufferram(mtd, addr, 0);
Kyungmin Park79e90462007-09-10 17:13:49 +09001057
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001058 ret = this->wait(mtd, FL_READING);
1059 if (ret)
1060 return ret;
Kyungmin Park79e90462007-09-10 17:13:49 +09001061
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001062 onenand_update_bufferram(mtd, addr, 1);
1063
1064 dataram = this->base + ONENAND_DATARAM;
1065 dataram += onenand_bufferram_offset(mtd, ONENAND_DATARAM);
1066
1067 if (memcmp(buf, dataram + column, thislen))
1068 return -EBADMSG;
1069
1070 len -= thislen;
1071 buf += thislen;
1072 addr += thislen;
1073 }
Kyungmin Park79e90462007-09-10 17:13:49 +09001074
1075 return 0;
1076}
1077#else
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001078#define onenand_verify(...) (0)
1079#define onenand_verify_oob(...) (0)
Kyungmin Park79e90462007-09-10 17:13:49 +09001080#endif
1081
Kyungmin Park396b0c42008-08-13 09:11:02 +09001082#define NOTALIGNED(x) ((x & (mtd->writesize - 1)) != 0)
Kyungmin Park79e90462007-09-10 17:13:49 +09001083
1084/**
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001085 * onenand_fill_auto_oob - [Internal] oob auto-placement transfer
1086 * @param mtd MTD device structure
1087 * @param oob_buf oob buffer
1088 * @param buf source address
1089 * @param column oob offset to write to
1090 * @param thislen oob length to write
1091 */
1092static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
1093 const u_char *buf, int column, int thislen)
1094{
1095 struct onenand_chip *this = mtd->priv;
1096 struct nand_oobfree *free;
1097 int writecol = column;
1098 int writeend = column + thislen;
1099 int lastgap = 0;
1100 unsigned int i;
1101
1102 free = this->ecclayout->oobfree;
1103 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
1104 if (writecol >= lastgap)
1105 writecol += free->offset - lastgap;
1106 if (writeend >= lastgap)
1107 writeend += free->offset - lastgap;
1108 lastgap = free->offset + free->length;
1109 }
1110 free = this->ecclayout->oobfree;
1111 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
1112 int free_end = free->offset + free->length;
1113 if (free->offset < writeend && free_end > writecol) {
1114 int st = max_t(int,free->offset,writecol);
1115 int ed = min_t(int,free_end,writeend);
1116 int n = ed - st;
1117 memcpy(oob_buf + st, buf, n);
1118 buf += n;
1119 } else if (column == 0)
1120 break;
1121 }
1122 return 0;
1123}
1124
1125/**
1126 * onenand_write_ops_nolock - [OneNAND Interface] write main and/or out-of-band
1127 * @param mtd MTD device structure
1128 * @param to offset to write to
1129 * @param ops oob operation description structure
Kyungmin Park79e90462007-09-10 17:13:49 +09001130 *
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001131 * Write main and/or oob with ECC
Kyungmin Park79e90462007-09-10 17:13:49 +09001132 */
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001133static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
1134 struct mtd_oob_ops *ops)
Kyungmin Park79e90462007-09-10 17:13:49 +09001135{
1136 struct onenand_chip *this = mtd->priv;
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001137 int written = 0, column, thislen, subpage;
1138 int oobwritten = 0, oobcolumn, thisooblen, oobsize;
1139 size_t len = ops->len;
1140 size_t ooblen = ops->ooblen;
1141 const u_char *buf = ops->datbuf;
1142 const u_char *oob = ops->oobbuf;
1143 u_char *oobbuf;
Kyungmin Park79e90462007-09-10 17:13:49 +09001144 int ret = 0;
1145
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001146 MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ops_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
Kyungmin Park79e90462007-09-10 17:13:49 +09001147
1148 /* Initialize retlen, in case of early exit */
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001149 ops->retlen = 0;
1150 ops->oobretlen = 0;
Kyungmin Park79e90462007-09-10 17:13:49 +09001151
1152 /* Do not allow writes past end of device */
1153 if (unlikely((to + len) > mtd->size)) {
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001154 printk(KERN_ERR "onenand_write_ops_nolock: Attempt write to past end of device\n");
Kyungmin Park79e90462007-09-10 17:13:49 +09001155 return -EINVAL;
1156 }
1157
1158 /* Reject writes, which are not page aligned */
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001159 if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
1160 printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n");
Kyungmin Park79e90462007-09-10 17:13:49 +09001161 return -EINVAL;
1162 }
1163
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001164 if (ops->mode == MTD_OOB_AUTO)
1165 oobsize = this->ecclayout->oobavail;
1166 else
1167 oobsize = mtd->oobsize;
1168
1169 oobcolumn = to & (mtd->oobsize - 1);
1170
1171 column = to & (mtd->writesize - 1);
Kyungmin Park79e90462007-09-10 17:13:49 +09001172
1173 /* Loop until all data write */
1174 while (written < len) {
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001175 u_char *wbuf = (u_char *) buf;
Kyungmin Park79e90462007-09-10 17:13:49 +09001176
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001177 thislen = min_t(int, mtd->writesize - column, len - written);
1178 thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten);
Kyungmin Park79e90462007-09-10 17:13:49 +09001179
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001180 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
Kyungmin Park79e90462007-09-10 17:13:49 +09001181
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001182 /* Partial page write */
1183 subpage = thislen < mtd->writesize;
1184 if (subpage) {
1185 memset(this->page_buf, 0xff, mtd->writesize);
1186 memcpy(this->page_buf + column, buf, thislen);
1187 wbuf = this->page_buf;
1188 }
Kyungmin Park79e90462007-09-10 17:13:49 +09001189
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001190 this->write_bufferram(mtd, to, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001191
1192 if (oob) {
1193 oobbuf = this->oob_buf;
1194
1195 /* We send data to spare ram with oobsize
1196 * * to prevent byte access */
1197 memset(oobbuf, 0xff, mtd->oobsize);
1198 if (ops->mode == MTD_OOB_AUTO)
1199 onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
1200 else
1201 memcpy(oobbuf + oobcolumn, oob, thisooblen);
1202
1203 oobwritten += thisooblen;
1204 oob += thisooblen;
1205 oobcolumn = 0;
1206 } else
1207 oobbuf = (u_char *) ffchars;
1208
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001209 this->write_bufferram(mtd, 0, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001210
1211 this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
Kyungmin Park79e90462007-09-10 17:13:49 +09001212
1213 ret = this->wait(mtd, FL_WRITING);
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001214
1215 /* In partial page write we don't update bufferram */
1216 onenand_update_bufferram(mtd, to, !ret && !subpage);
1217 if (ONENAND_IS_2PLANE(this)) {
1218 ONENAND_SET_BUFFERRAM1(this);
1219 onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage);
1220 }
1221
Kyungmin Park79e90462007-09-10 17:13:49 +09001222 if (ret) {
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001223 printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
Kyungmin Park79e90462007-09-10 17:13:49 +09001224 break;
1225 }
1226
Kyungmin Park79e90462007-09-10 17:13:49 +09001227 /* Only check verify write turn on */
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001228 ret = onenand_verify(mtd, buf, to, thislen);
Kyungmin Park79e90462007-09-10 17:13:49 +09001229 if (ret) {
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001230 printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
Kyungmin Park79e90462007-09-10 17:13:49 +09001231 break;
1232 }
1233
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001234 written += thislen;
1235
Kyungmin Park79e90462007-09-10 17:13:49 +09001236 if (written == len)
1237 break;
1238
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001239 column = 0;
Kyungmin Park79e90462007-09-10 17:13:49 +09001240 to += thislen;
1241 buf += thislen;
1242 }
1243
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001244 ops->retlen = written;
Kyungmin Park79e90462007-09-10 17:13:49 +09001245
1246 return ret;
1247}
1248
1249/**
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001250 * onenand_write_oob_nolock - [Internal] OneNAND write out-of-band
1251 * @param mtd MTD device structure
1252 * @param to offset to write to
1253 * @param len number of bytes to write
1254 * @param retlen pointer to variable to store the number of written bytes
1255 * @param buf the data to write
1256 * @param mode operation mode
Kyungmin Park79e90462007-09-10 17:13:49 +09001257 *
1258 * OneNAND write out-of-band
1259 */
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001260static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
1261 struct mtd_oob_ops *ops)
Kyungmin Park79e90462007-09-10 17:13:49 +09001262{
1263 struct onenand_chip *this = mtd->priv;
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001264 int column, ret = 0, oobsize;
Kyungmin Park79e90462007-09-10 17:13:49 +09001265 int written = 0;
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001266 u_char *oobbuf;
1267 size_t len = ops->ooblen;
1268 const u_char *buf = ops->oobbuf;
1269 mtd_oob_mode_t mode = ops->mode;
1270
1271 to += ops->ooboffs;
Kyungmin Park79e90462007-09-10 17:13:49 +09001272
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001273 MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
Kyungmin Park79e90462007-09-10 17:13:49 +09001274
1275 /* Initialize retlen, in case of early exit */
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001276 ops->oobretlen = 0;
Kyungmin Park79e90462007-09-10 17:13:49 +09001277
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001278 if (mode == MTD_OOB_AUTO)
1279 oobsize = this->ecclayout->oobavail;
1280 else
1281 oobsize = mtd->oobsize;
1282
1283 column = to & (mtd->oobsize - 1);
1284
1285 if (unlikely(column >= oobsize)) {
1286 printk(KERN_ERR "onenand_write_oob_nolock: Attempted to start write outside oob\n");
Kyungmin Park79e90462007-09-10 17:13:49 +09001287 return -EINVAL;
1288 }
1289
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001290 /* For compatibility with NAND: Do not allow write past end of page */
1291 if (unlikely(column + len > oobsize)) {
1292 printk(KERN_ERR "onenand_write_oob_nolock: "
1293 "Attempt to write past end of page\n");
1294 return -EINVAL;
1295 }
1296
1297 /* Do not allow reads past end of device */
1298 if (unlikely(to >= mtd->size ||
1299 column + len > ((mtd->size >> this->page_shift) -
1300 (to >> this->page_shift)) * oobsize)) {
1301 printk(KERN_ERR "onenand_write_oob_nolock: Attempted to write past end of device\n");
1302 return -EINVAL;
1303 }
1304
1305 oobbuf = this->oob_buf;
Kyungmin Park79e90462007-09-10 17:13:49 +09001306
1307 /* Loop until all data write */
1308 while (written < len) {
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001309 int thislen = min_t(int, oobsize, len - written);
Kyungmin Park79e90462007-09-10 17:13:49 +09001310
1311 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize);
1312
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001313 /* We send data to spare ram with oobsize
1314 * to prevent byte access */
1315 memset(oobbuf, 0xff, mtd->oobsize);
1316 if (mode == MTD_OOB_AUTO)
1317 onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen);
1318 else
1319 memcpy(oobbuf + column, buf, thislen);
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001320 this->write_bufferram(mtd, 0, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
Kyungmin Park79e90462007-09-10 17:13:49 +09001321
1322 this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize);
1323
1324 onenand_update_bufferram(mtd, to, 0);
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001325 if (ONENAND_IS_2PLANE(this)) {
1326 ONENAND_SET_BUFFERRAM1(this);
1327 onenand_update_bufferram(mtd, to + this->writesize, 0);
1328 }
Kyungmin Park79e90462007-09-10 17:13:49 +09001329
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001330 ret = this->wait(mtd, FL_WRITING);
1331 if (ret) {
1332 printk(KERN_ERR "onenand_write_oob_nolock: write failed %d\n", ret);
Kyungmin Park79e90462007-09-10 17:13:49 +09001333 break;
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001334 }
1335
1336 ret = onenand_verify_oob(mtd, oobbuf, to);
1337 if (ret) {
1338 printk(KERN_ERR "onenand_write_oob_nolock: verify failed %d\n", ret);
1339 break;
1340 }
Kyungmin Park79e90462007-09-10 17:13:49 +09001341
1342 written += thislen;
1343 if (written == len)
1344 break;
1345
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001346 to += mtd->writesize;
Kyungmin Park79e90462007-09-10 17:13:49 +09001347 buf += thislen;
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001348 column = 0;
Kyungmin Park79e90462007-09-10 17:13:49 +09001349 }
1350
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001351 ops->oobretlen = written;
1352
1353 return ret;
1354}
1355
1356/**
1357 * onenand_write - [MTD Interface] compability function for onenand_write_ecc
1358 * @param mtd MTD device structure
1359 * @param to offset to write to
1360 * @param len number of bytes to write
1361 * @param retlen pointer to variable to store the number of written bytes
1362 * @param buf the data to write
1363 *
1364 * Write with ECC
1365 */
1366int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
1367 size_t * retlen, const u_char * buf)
1368{
1369 struct mtd_oob_ops ops = {
1370 .len = len,
1371 .ooblen = 0,
1372 .datbuf = (u_char *) buf,
1373 .oobbuf = NULL,
1374 };
1375 int ret;
1376
1377 onenand_get_device(mtd, FL_WRITING);
1378 ret = onenand_write_ops_nolock(mtd, to, &ops);
Kyungmin Park79e90462007-09-10 17:13:49 +09001379 onenand_release_device(mtd);
1380
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001381 *retlen = ops.retlen;
1382 return ret;
1383}
Kyungmin Park79e90462007-09-10 17:13:49 +09001384
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001385/**
1386 * onenand_write_oob - [MTD Interface] OneNAND write out-of-band
1387 * @param mtd MTD device structure
1388 * @param to offset to write to
1389 * @param ops oob operation description structure
1390 *
1391 * OneNAND write main and/or out-of-band
1392 */
1393int onenand_write_oob(struct mtd_info *mtd, loff_t to,
1394 struct mtd_oob_ops *ops)
1395{
1396 int ret;
1397
1398 switch (ops->mode) {
1399 case MTD_OOB_PLACE:
1400 case MTD_OOB_AUTO:
1401 break;
1402 case MTD_OOB_RAW:
1403 /* Not implemented yet */
1404 default:
1405 return -EINVAL;
1406 }
1407
1408 onenand_get_device(mtd, FL_WRITING);
1409 if (ops->datbuf)
1410 ret = onenand_write_ops_nolock(mtd, to, ops);
1411 else
1412 ret = onenand_write_oob_nolock(mtd, to, ops);
1413 onenand_release_device(mtd);
1414
1415 return ret;
1416
Kyungmin Park79e90462007-09-10 17:13:49 +09001417}
1418
Kyungmin Park396b0c42008-08-13 09:11:02 +09001419/**
1420 * onenand_block_isbad_nolock - [GENERIC] Check if a block is marked bad
1421 * @param mtd MTD device structure
1422 * @param ofs offset from device start
1423 * @param allowbbt 1, if its allowed to access the bbt area
1424 *
1425 * Check, if the block is bad, Either by reading the bad block table or
1426 * calling of the scan function.
1427 */
1428static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int allowbbt)
1429{
1430 struct onenand_chip *this = mtd->priv;
1431 struct bbm_info *bbm = this->bbm;
1432
1433 /* Return info from the table */
1434 return bbm->isbad_bbt(mtd, ofs, allowbbt);
1435}
1436
1437
Kyungmin Park79e90462007-09-10 17:13:49 +09001438/**
1439 * onenand_erase - [MTD Interface] erase block(s)
1440 * @param mtd MTD device structure
1441 * @param instr erase instruction
1442 *
1443 * Erase one ore more blocks
1444 */
1445int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
1446{
1447 struct onenand_chip *this = mtd->priv;
1448 unsigned int block_size;
1449 loff_t addr;
1450 int len;
1451 int ret = 0;
1452
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001453 MTDDEBUG (MTD_DEBUG_LEVEL3,
1454 "onenand_erase: start = 0x%08x, len = %i\n",
Scott Wood3628f002008-10-24 16:20:43 -05001455 (unsigned int)instr->addr, (unsigned int)instr->len);
Kyungmin Park79e90462007-09-10 17:13:49 +09001456
1457 block_size = (1 << this->erase_shift);
1458
1459 /* Start address must align on block boundary */
1460 if (unlikely(instr->addr & (block_size - 1))) {
Scott Wooddf83c472008-06-20 12:38:57 -05001461 MTDDEBUG (MTD_DEBUG_LEVEL0,
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001462 "onenand_erase: Unaligned address\n");
Kyungmin Park79e90462007-09-10 17:13:49 +09001463 return -EINVAL;
1464 }
1465
1466 /* Length must align on block boundary */
1467 if (unlikely(instr->len & (block_size - 1))) {
Scott Wooddf83c472008-06-20 12:38:57 -05001468 MTDDEBUG (MTD_DEBUG_LEVEL0,
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001469 "onenand_erase: Length not block aligned\n");
Kyungmin Park79e90462007-09-10 17:13:49 +09001470 return -EINVAL;
1471 }
1472
1473 /* Do not allow erase past end of device */
1474 if (unlikely((instr->len + instr->addr) > mtd->size)) {
Scott Wooddf83c472008-06-20 12:38:57 -05001475 MTDDEBUG (MTD_DEBUG_LEVEL0,
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09001476 "onenand_erase: Erase past end of device\n");
Kyungmin Park79e90462007-09-10 17:13:49 +09001477 return -EINVAL;
1478 }
1479
1480 instr->fail_addr = 0xffffffff;
1481
1482 /* Grab the lock and see if the device is available */
1483 onenand_get_device(mtd, FL_ERASING);
1484
1485 /* Loop throught the pages */
1486 len = instr->len;
1487 addr = instr->addr;
1488
1489 instr->state = MTD_ERASING;
1490
1491 while (len) {
1492
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001493 /* Check if we have a bad block, we do not erase bad blocks */
1494 if (instr->priv == 0 && onenand_block_isbad_nolock(mtd, addr, 0)) {
1495 printk(KERN_WARNING "onenand_erase: attempt to erase"
1496 " a bad block at addr 0x%08x\n",
1497 (unsigned int) addr);
1498 instr->state = MTD_ERASE_FAILED;
1499 goto erase_exit;
1500 }
Kyungmin Park79e90462007-09-10 17:13:49 +09001501
1502 this->command(mtd, ONENAND_CMD_ERASE, addr, block_size);
1503
Kyungmin Park396b0c42008-08-13 09:11:02 +09001504 onenand_invalidate_bufferram(mtd, addr, block_size);
1505
Kyungmin Park79e90462007-09-10 17:13:49 +09001506 ret = this->wait(mtd, FL_ERASING);
1507 /* Check, if it is write protected */
1508 if (ret) {
1509 if (ret == -EPERM)
Scott Wooddf83c472008-06-20 12:38:57 -05001510 MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: "
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001511 "Device is write protected!!!\n");
Kyungmin Park79e90462007-09-10 17:13:49 +09001512 else
Scott Wooddf83c472008-06-20 12:38:57 -05001513 MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: "
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001514 "Failed erase, block %d\n",
1515 (unsigned)(addr >> this->erase_shift));
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001516 if (ret == -EPERM)
1517 printk("onenand_erase: "
1518 "Device is write protected!!!\n");
1519 else
1520 printk("onenand_erase: "
1521 "Failed erase, block %d\n",
1522 (unsigned)(addr >> this->erase_shift));
Kyungmin Park79e90462007-09-10 17:13:49 +09001523 instr->state = MTD_ERASE_FAILED;
1524 instr->fail_addr = addr;
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001525
Kyungmin Park79e90462007-09-10 17:13:49 +09001526 goto erase_exit;
1527 }
1528
1529 len -= block_size;
1530 addr += block_size;
1531 }
1532
1533 instr->state = MTD_ERASE_DONE;
1534
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001535erase_exit:
Kyungmin Park79e90462007-09-10 17:13:49 +09001536
1537 ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
1538 /* Do call back function */
1539 if (!ret)
1540 mtd_erase_callback(instr);
1541
1542 /* Deselect and wake up anyone waiting on the device */
1543 onenand_release_device(mtd);
1544
1545 return ret;
1546}
1547
1548/**
1549 * onenand_sync - [MTD Interface] sync
1550 * @param mtd MTD device structure
1551 *
1552 * Sync is actually a wait for chip ready function
1553 */
1554void onenand_sync(struct mtd_info *mtd)
1555{
Scott Wooddf83c472008-06-20 12:38:57 -05001556 MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_sync: called\n");
Kyungmin Park79e90462007-09-10 17:13:49 +09001557
1558 /* Grab the lock and see if the device is available */
1559 onenand_get_device(mtd, FL_SYNCING);
1560
1561 /* Release it and go back */
1562 onenand_release_device(mtd);
1563}
1564
1565/**
1566 * onenand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad
1567 * @param mtd MTD device structure
1568 * @param ofs offset relative to mtd start
Kyungmin Park396b0c42008-08-13 09:11:02 +09001569 *
1570 * Check whether the block is bad
Kyungmin Park79e90462007-09-10 17:13:49 +09001571 */
1572int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs)
1573{
Kyungmin Park396b0c42008-08-13 09:11:02 +09001574 int ret;
1575
1576 /* Check for invalid offset */
1577 if (ofs > mtd->size)
1578 return -EINVAL;
1579
1580 onenand_get_device(mtd, FL_READING);
1581 ret = onenand_block_isbad_nolock(mtd,ofs, 0);
1582 onenand_release_device(mtd);
1583 return ret;
Kyungmin Park79e90462007-09-10 17:13:49 +09001584}
1585
1586/**
Kyungmin Park87b49502008-11-13 15:14:33 +09001587 * onenand_default_block_markbad - [DEFAULT] mark a block bad
1588 * @param mtd MTD device structure
1589 * @param ofs offset from device start
1590 *
1591 * This is the default implementation, which can be overridden by
1592 * a hardware specific driver.
1593 */
1594static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
1595{
1596 struct onenand_chip *this = mtd->priv;
1597 struct bbm_info *bbm = this->bbm;
1598 u_char buf[2] = {0, 0};
1599 struct mtd_oob_ops ops = {
1600 .mode = MTD_OOB_PLACE,
1601 .ooblen = 2,
1602 .oobbuf = buf,
1603 .ooboffs = 0,
1604 };
1605 int block;
1606
1607 /* Get block number */
1608 block = ((int) ofs) >> bbm->bbt_erase_shift;
1609 if (bbm->bbt)
1610 bbm->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
1611
1612 /* We write two bytes, so we dont have to mess with 16 bit access */
1613 ofs += mtd->oobsize + (bbm->badblockpos & ~0x01);
1614 return onenand_write_oob_nolock(mtd, ofs, &ops);
1615}
1616
1617/**
Kyungmin Park79e90462007-09-10 17:13:49 +09001618 * onenand_block_markbad - [MTD Interface] Mark the block at the given offset as bad
1619 * @param mtd MTD device structure
1620 * @param ofs offset relative to mtd start
Kyungmin Park396b0c42008-08-13 09:11:02 +09001621 *
1622 * Mark the block as bad
Kyungmin Park79e90462007-09-10 17:13:49 +09001623 */
1624int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
1625{
Kyungmin Park396b0c42008-08-13 09:11:02 +09001626 struct onenand_chip *this = mtd->priv;
1627 int ret;
1628
1629 ret = onenand_block_isbad(mtd, ofs);
1630 if (ret) {
1631 /* If it was bad already, return success and do nothing */
1632 if (ret > 0)
1633 return 0;
1634 return ret;
1635 }
1636
1637 ret = this->block_markbad(mtd, ofs);
1638 return ret;
Kyungmin Park79e90462007-09-10 17:13:49 +09001639}
1640
1641/**
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001642 * onenand_do_lock_cmd - [OneNAND Interface] Lock or unlock block(s)
1643 * @param mtd MTD device structure
1644 * @param ofs offset relative to mtd start
1645 * @param len number of bytes to lock or unlock
1646 * @param cmd lock or unlock command
Kyungmin Park79e90462007-09-10 17:13:49 +09001647 *
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001648 * Lock or unlock one or more blocks
Kyungmin Park79e90462007-09-10 17:13:49 +09001649 */
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001650static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int cmd)
Kyungmin Park79e90462007-09-10 17:13:49 +09001651{
1652 struct onenand_chip *this = mtd->priv;
1653 int start, end, block, value, status;
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001654 int wp_status_mask;
Kyungmin Park79e90462007-09-10 17:13:49 +09001655
1656 start = ofs >> this->erase_shift;
1657 end = len >> this->erase_shift;
1658
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001659 if (cmd == ONENAND_CMD_LOCK)
1660 wp_status_mask = ONENAND_WP_LS;
1661 else
1662 wp_status_mask = ONENAND_WP_US;
1663
Kyungmin Park79e90462007-09-10 17:13:49 +09001664 /* Continuous lock scheme */
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001665 if (this->options & ONENAND_HAS_CONT_LOCK) {
Kyungmin Park79e90462007-09-10 17:13:49 +09001666 /* Set start block address */
1667 this->write_word(start,
1668 this->base + ONENAND_REG_START_BLOCK_ADDRESS);
1669 /* Set end block address */
1670 this->write_word(end - 1,
1671 this->base + ONENAND_REG_END_BLOCK_ADDRESS);
1672 /* Write unlock command */
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001673 this->command(mtd, cmd, 0, 0);
Kyungmin Park79e90462007-09-10 17:13:49 +09001674
1675 /* There's no return value */
1676 this->wait(mtd, FL_UNLOCKING);
1677
1678 /* Sanity check */
1679 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
1680 & ONENAND_CTRL_ONGO)
1681 continue;
1682
1683 /* Check lock status */
1684 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
1685 if (!(status & ONENAND_WP_US))
1686 printk(KERN_ERR "wp status = 0x%x\n", status);
1687
1688 return 0;
1689 }
1690
1691 /* Block lock scheme */
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001692 for (block = start; block < start + end; block++) {
1693 /* Set block address */
1694 value = onenand_block_address(this, block);
1695 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
1696 /* Select DataRAM for DDP */
1697 value = onenand_bufferram_address(this, block);
1698 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
1699
Kyungmin Park79e90462007-09-10 17:13:49 +09001700 /* Set start block address */
1701 this->write_word(block,
1702 this->base + ONENAND_REG_START_BLOCK_ADDRESS);
1703 /* Write unlock command */
1704 this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0);
1705
1706 /* There's no return value */
1707 this->wait(mtd, FL_UNLOCKING);
1708
1709 /* Sanity check */
1710 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
1711 & ONENAND_CTRL_ONGO)
1712 continue;
1713
Kyungmin Park79e90462007-09-10 17:13:49 +09001714 /* Check lock status */
1715 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
1716 if (!(status & ONENAND_WP_US))
1717 printk(KERN_ERR "block = %d, wp status = 0x%x\n",
1718 block, status);
1719 }
1720
1721 return 0;
1722}
1723
Stefan Roese5ed79ae2008-11-11 10:28:53 +01001724#ifdef ONENAND_LINUX
Kyungmin Park79e90462007-09-10 17:13:49 +09001725/**
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001726 * onenand_lock - [MTD Interface] Lock block(s)
1727 * @param mtd MTD device structure
1728 * @param ofs offset relative to mtd start
1729 * @param len number of bytes to unlock
1730 *
1731 * Lock one or more blocks
1732 */
1733static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
1734{
1735 int ret;
1736
1737 onenand_get_device(mtd, FL_LOCKING);
1738 ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK);
1739 onenand_release_device(mtd);
1740 return ret;
1741}
1742
1743/**
1744 * onenand_unlock - [MTD Interface] Unlock block(s)
1745 * @param mtd MTD device structure
1746 * @param ofs offset relative to mtd start
1747 * @param len number of bytes to unlock
1748 *
1749 * Unlock one or more blocks
1750 */
1751static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
1752{
1753 int ret;
1754
1755 onenand_get_device(mtd, FL_LOCKING);
1756 ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
1757 onenand_release_device(mtd);
1758 return ret;
1759}
Stefan Roese5ed79ae2008-11-11 10:28:53 +01001760#endif
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001761
1762/**
1763 * onenand_check_lock_status - [OneNAND Interface] Check lock status
1764 * @param this onenand chip data structure
1765 *
1766 * Check lock status
1767 */
1768static int onenand_check_lock_status(struct onenand_chip *this)
1769{
1770 unsigned int value, block, status;
1771 unsigned int end;
1772
1773 end = this->chipsize >> this->erase_shift;
1774 for (block = 0; block < end; block++) {
1775 /* Set block address */
1776 value = onenand_block_address(this, block);
1777 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
1778 /* Select DataRAM for DDP */
1779 value = onenand_bufferram_address(this, block);
1780 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
1781 /* Set start block address */
1782 this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
1783
1784 /* Check lock status */
1785 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
1786 if (!(status & ONENAND_WP_US)) {
1787 printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status);
1788 return 0;
1789 }
1790 }
1791
1792 return 1;
1793}
1794
1795/**
1796 * onenand_unlock_all - [OneNAND Interface] unlock all blocks
1797 * @param mtd MTD device structure
1798 *
1799 * Unlock all blocks
1800 */
1801static void onenand_unlock_all(struct mtd_info *mtd)
1802{
1803 struct onenand_chip *this = mtd->priv;
1804 loff_t ofs = 0;
1805 size_t len = this->chipsize;
1806
1807 if (this->options & ONENAND_HAS_UNLOCK_ALL) {
1808 /* Set start block address */
1809 this->write_word(0, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
1810 /* Write unlock command */
1811 this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0);
1812
1813 /* There's no return value */
1814 this->wait(mtd, FL_LOCKING);
1815
1816 /* Sanity check */
1817 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
1818 & ONENAND_CTRL_ONGO)
1819 continue;
1820
1821 return;
1822
1823 /* Check lock status */
1824 if (onenand_check_lock_status(this))
1825 return;
1826
1827 /* Workaround for all block unlock in DDP */
1828 if (ONENAND_IS_DDP(this)) {
1829 /* All blocks on another chip */
1830 ofs = this->chipsize >> 1;
1831 len = this->chipsize >> 1;
1832 }
1833 }
1834
1835 onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
1836}
1837
1838
1839/**
1840 * onenand_check_features - Check and set OneNAND features
1841 * @param mtd MTD data structure
1842 *
1843 * Check and set OneNAND features
1844 * - lock scheme
1845 * - two plane
1846 */
1847static void onenand_check_features(struct mtd_info *mtd)
1848{
1849 struct onenand_chip *this = mtd->priv;
1850 unsigned int density, process;
1851
1852 /* Lock scheme depends on density and process */
1853 density = onenand_get_density(this->device_id);
1854 process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT;
1855
1856 /* Lock scheme */
1857 switch (density) {
1858 case ONENAND_DEVICE_DENSITY_4Gb:
1859 this->options |= ONENAND_HAS_2PLANE;
1860
1861 case ONENAND_DEVICE_DENSITY_2Gb:
1862 /* 2Gb DDP don't have 2 plane */
1863 if (!ONENAND_IS_DDP(this))
1864 this->options |= ONENAND_HAS_2PLANE;
1865 this->options |= ONENAND_HAS_UNLOCK_ALL;
1866
1867 case ONENAND_DEVICE_DENSITY_1Gb:
1868 /* A-Die has all block unlock */
1869 if (process)
1870 this->options |= ONENAND_HAS_UNLOCK_ALL;
1871 break;
1872
1873 default:
1874 /* Some OneNAND has continuous lock scheme */
1875 if (!process)
1876 this->options |= ONENAND_HAS_CONT_LOCK;
1877 break;
1878 }
1879
1880 if (this->options & ONENAND_HAS_CONT_LOCK)
1881 printk(KERN_DEBUG "Lock scheme is Continuous Lock\n");
1882 if (this->options & ONENAND_HAS_UNLOCK_ALL)
1883 printk(KERN_DEBUG "Chip support all block unlock\n");
1884 if (this->options & ONENAND_HAS_2PLANE)
1885 printk(KERN_DEBUG "Chip has 2 plane\n");
1886}
1887
1888/**
Kyungmin Park79e90462007-09-10 17:13:49 +09001889 * onenand_print_device_info - Print device ID
1890 * @param device device ID
1891 *
1892 * Print device ID
1893 */
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001894char *onenand_print_device_info(int device, int version)
Kyungmin Park79e90462007-09-10 17:13:49 +09001895{
1896 int vcc, demuxed, ddp, density;
Fathi BOUDRA95feb702008-08-06 10:06:20 +02001897 char *dev_info = malloc(80);
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001898 char *p = dev_info;
Kyungmin Park79e90462007-09-10 17:13:49 +09001899
1900 vcc = device & ONENAND_DEVICE_VCC_MASK;
1901 demuxed = device & ONENAND_DEVICE_IS_DEMUX;
1902 ddp = device & ONENAND_DEVICE_IS_DDP;
1903 density = device >> ONENAND_DEVICE_DENSITY_SHIFT;
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001904 p += sprintf(dev_info, "%sOneNAND%s %dMB %sV 16-bit (0x%02x)",
Kyungmin Park79e90462007-09-10 17:13:49 +09001905 demuxed ? "" : "Muxed ",
1906 ddp ? "(DDP)" : "",
1907 (16 << density), vcc ? "2.65/3.3" : "1.8", device);
Fathi BOUDRA95feb702008-08-06 10:06:20 +02001908
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001909 sprintf(p, "\nOneNAND version = 0x%04x", version);
1910 printk("%s\n", dev_info);
1911
Fathi BOUDRA95feb702008-08-06 10:06:20 +02001912 return dev_info;
Kyungmin Park79e90462007-09-10 17:13:49 +09001913}
1914
1915static const struct onenand_manufacturers onenand_manuf_ids[] = {
1916 {ONENAND_MFR_SAMSUNG, "Samsung"},
Kyungmin Park79e90462007-09-10 17:13:49 +09001917};
1918
1919/**
1920 * onenand_check_maf - Check manufacturer ID
1921 * @param manuf manufacturer ID
1922 *
1923 * Check manufacturer ID
1924 */
1925static int onenand_check_maf(int manuf)
1926{
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001927 int size = ARRAY_SIZE(onenand_manuf_ids);
1928 char *name;
Kyungmin Park79e90462007-09-10 17:13:49 +09001929 int i;
1930
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001931 for (i = 0; size; i++)
Kyungmin Park79e90462007-09-10 17:13:49 +09001932 if (manuf == onenand_manuf_ids[i].id)
1933 break;
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001934
1935 if (i < size)
1936 name = onenand_manuf_ids[i].name;
1937 else
1938 name = "Unknown";
Kyungmin Park79e90462007-09-10 17:13:49 +09001939
1940#ifdef ONENAND_DEBUG
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001941 printk(KERN_DEBUG "OneNAND Manufacturer: %s (0x%0x)\n", name, manuf);
Kyungmin Park79e90462007-09-10 17:13:49 +09001942#endif
1943
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001944 return i == size;
Kyungmin Park79e90462007-09-10 17:13:49 +09001945}
1946
1947/**
1948 * onenand_probe - [OneNAND Interface] Probe the OneNAND device
1949 * @param mtd MTD device structure
1950 *
1951 * OneNAND detection method:
1952 * Compare the the values from command with ones from register
1953 */
1954static int onenand_probe(struct mtd_info *mtd)
1955{
1956 struct onenand_chip *this = mtd->priv;
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001957 int bram_maf_id, bram_dev_id, maf_id, dev_id, ver_id;
Kyungmin Park79e90462007-09-10 17:13:49 +09001958 int density;
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001959 int syscfg;
1960
1961 /* Save system configuration 1 */
1962 syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
1963 /* Clear Sync. Burst Read mode to read BootRAM */
1964 this->write_word((syscfg & ~ONENAND_SYS_CFG1_SYNC_READ), this->base + ONENAND_REG_SYS_CFG1);
Kyungmin Park79e90462007-09-10 17:13:49 +09001965
1966 /* Send the command for reading device ID from BootRAM */
1967 this->write_word(ONENAND_CMD_READID, this->base + ONENAND_BOOTRAM);
1968
1969 /* Read manufacturer and device IDs from BootRAM */
1970 bram_maf_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x0);
1971 bram_dev_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x2);
1972
Kyungmin Park79e90462007-09-10 17:13:49 +09001973 /* Reset OneNAND to read default register values */
1974 this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM);
1975
Kyungmin Park396b0c42008-08-13 09:11:02 +09001976 /* Wait reset */
1977 this->wait(mtd, FL_RESETING);
Kyungmin Park79e90462007-09-10 17:13:49 +09001978
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001979 /* Restore system configuration 1 */
1980 this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
1981
1982 /* Check manufacturer ID */
1983 if (onenand_check_maf(bram_maf_id))
1984 return -ENXIO;
1985
Kyungmin Park79e90462007-09-10 17:13:49 +09001986 /* Read manufacturer and device IDs from Register */
1987 maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);
1988 dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09001989 ver_id = this->read_word(this->base + ONENAND_REG_VERSION_ID);
Kyungmin Park79e90462007-09-10 17:13:49 +09001990
1991 /* Check OneNAND device */
1992 if (maf_id != bram_maf_id || dev_id != bram_dev_id)
1993 return -ENXIO;
1994
Kyungmin Park05d23182008-03-17 08:54:06 +09001995 /* FIXME : Current OneNAND MTD doesn't support Flex-OneNAND */
1996 if (dev_id & (1 << 9)) {
1997 printk("Not yet support Flex-OneNAND\n");
1998 return -ENXIO;
1999 }
2000
Kyungmin Park79e90462007-09-10 17:13:49 +09002001 /* Flash device information */
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09002002 mtd->name = onenand_print_device_info(dev_id, ver_id);
Kyungmin Park79e90462007-09-10 17:13:49 +09002003 this->device_id = dev_id;
Stefan Roese7c9aafe2008-11-11 10:29:09 +01002004 this->version_id = ver_id;
Kyungmin Park79e90462007-09-10 17:13:49 +09002005
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09002006 density = onenand_get_density(dev_id);
Kyungmin Park79e90462007-09-10 17:13:49 +09002007 this->chipsize = (16 << density) << 20;
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09002008 /* Set density mask. it is used for DDP */
2009 if (ONENAND_IS_DDP(this))
2010 this->density_mask = (1 << (density + 6));
2011 else
2012 this->density_mask = 0;
Kyungmin Park79e90462007-09-10 17:13:49 +09002013
2014 /* OneNAND page size & block size */
2015 /* The data buffer size is equal to page size */
Kyungmin Park396b0c42008-08-13 09:11:02 +09002016 mtd->writesize =
Kyungmin Park79e90462007-09-10 17:13:49 +09002017 this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE);
Kyungmin Park396b0c42008-08-13 09:11:02 +09002018 mtd->oobsize = mtd->writesize >> 5;
Kyungmin Park79e90462007-09-10 17:13:49 +09002019 /* Pagers per block is always 64 in OneNAND */
Kyungmin Park396b0c42008-08-13 09:11:02 +09002020 mtd->erasesize = mtd->writesize << 6;
Kyungmin Park79e90462007-09-10 17:13:49 +09002021
2022 this->erase_shift = ffs(mtd->erasesize) - 1;
Kyungmin Park396b0c42008-08-13 09:11:02 +09002023 this->page_shift = ffs(mtd->writesize) - 1;
Kyungmin Park79e90462007-09-10 17:13:49 +09002024 this->ppb_shift = (this->erase_shift - this->page_shift);
Kyungmin Park396b0c42008-08-13 09:11:02 +09002025 this->page_mask = (mtd->erasesize / mtd->writesize) - 1;
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09002026 /* It's real page size */
2027 this->writesize = mtd->writesize;
Kyungmin Park79e90462007-09-10 17:13:49 +09002028
2029 /* REVIST: Multichip handling */
2030
2031 mtd->size = this->chipsize;
2032
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09002033 /* Check OneNAND features */
2034 onenand_check_features(mtd);
Kyungmin Park79e90462007-09-10 17:13:49 +09002035
Kyungmin Park396b0c42008-08-13 09:11:02 +09002036 mtd->flags = MTD_CAP_NANDFLASH;
Fathi BOUDRA95feb702008-08-06 10:06:20 +02002037 mtd->erase = onenand_erase;
2038 mtd->read = onenand_read;
2039 mtd->write = onenand_write;
Fathi BOUDRA95feb702008-08-06 10:06:20 +02002040 mtd->read_oob = onenand_read_oob;
2041 mtd->write_oob = onenand_write_oob;
2042 mtd->sync = onenand_sync;
2043 mtd->block_isbad = onenand_block_isbad;
2044 mtd->block_markbad = onenand_block_markbad;
2045
Kyungmin Park79e90462007-09-10 17:13:49 +09002046 return 0;
2047}
2048
2049/**
2050 * onenand_scan - [OneNAND Interface] Scan for the OneNAND device
2051 * @param mtd MTD device structure
2052 * @param maxchips Number of chips to scan for
2053 *
2054 * This fills out all the not initialized function pointers
2055 * with the defaults.
2056 * The flash ID is read and the mtd/chip structures are
2057 * filled with the appropriate values.
2058 */
2059int onenand_scan(struct mtd_info *mtd, int maxchips)
2060{
2061 struct onenand_chip *this = mtd->priv;
2062
2063 if (!this->read_word)
2064 this->read_word = onenand_readw;
2065 if (!this->write_word)
2066 this->write_word = onenand_writew;
2067
2068 if (!this->command)
2069 this->command = onenand_command;
2070 if (!this->wait)
2071 this->wait = onenand_wait;
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09002072 if (!this->bbt_wait)
2073 this->bbt_wait = onenand_bbt_wait;
Kyungmin Park79e90462007-09-10 17:13:49 +09002074
2075 if (!this->read_bufferram)
2076 this->read_bufferram = onenand_read_bufferram;
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09002077 if (!this->read_spareram)
2078 this->read_spareram = onenand_read_bufferram;
Kyungmin Park79e90462007-09-10 17:13:49 +09002079 if (!this->write_bufferram)
2080 this->write_bufferram = onenand_write_bufferram;
2081
Kyungmin Park87b49502008-11-13 15:14:33 +09002082 if (!this->block_markbad)
2083 this->block_markbad = onenand_default_block_markbad;
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09002084 if (!this->scan_bbt)
2085 this->scan_bbt = onenand_default_bbt;
2086
Kyungmin Park79e90462007-09-10 17:13:49 +09002087 if (onenand_probe(mtd))
2088 return -ENXIO;
2089
2090 /* Set Sync. Burst Read after probing */
2091 if (this->mmcontrol) {
2092 printk(KERN_INFO "OneNAND Sync. Burst Read support\n");
2093 this->read_bufferram = onenand_sync_read_bufferram;
2094 }
2095
Kyungmin Park5d7a01c2008-08-19 08:42:53 +09002096 /* Allocate buffers, if necessary */
2097 if (!this->page_buf) {
2098 this->page_buf = kzalloc(mtd->writesize, GFP_KERNEL);
2099 if (!this->page_buf) {
2100 printk(KERN_ERR "onenand_scan(): Can't allocate page_buf\n");
2101 return -ENOMEM;
2102 }
2103 this->options |= ONENAND_PAGEBUF_ALLOC;
2104 }
2105 if (!this->oob_buf) {
2106 this->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
2107 if (!this->oob_buf) {
2108 printk(KERN_ERR "onenand_scan: Can't allocate oob_buf\n");
2109 if (this->options & ONENAND_PAGEBUF_ALLOC) {
2110 this->options &= ~ONENAND_PAGEBUF_ALLOC;
2111 kfree(this->page_buf);
2112 }
2113 return -ENOMEM;
2114 }
2115 this->options |= ONENAND_OOBBUF_ALLOC;
2116 }
2117
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09002118 /* Unlock whole block */
2119 onenand_unlock_all(mtd);
Kyungmin Park79e90462007-09-10 17:13:49 +09002120
Kyungmin Parkdc7a79c2008-11-04 09:24:07 +09002121 return this->scan_bbt(mtd);
Kyungmin Park79e90462007-09-10 17:13:49 +09002122}
2123
2124/**
2125 * onenand_release - [OneNAND Interface] Free resources held by the OneNAND device
2126 * @param mtd MTD device structure
2127 */
2128void onenand_release(struct mtd_info *mtd)
2129{
2130}