blob: c22a8a8029652166f203327c64c7efaccc2bae17 [file] [log] [blame]
Kyungmin Park916527f2007-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 Parkbfd7f382008-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 Park916527f2007-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 Park916527f2007-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 BOUDRA195ccfc2008-08-06 10:06:20 +020024#include <malloc.h>
Kyungmin Park916527f2007-09-10 17:13:49 +090025
Kyungmin Park77e475c2008-03-31 10:40:36 +090026/* It should access 16-bit instead of 8-bit */
Wolfgang Denkd2c6fbe2008-05-01 21:30:16 +020027static inline void *memcpy_16(void *dst, const void *src, unsigned int len)
Kyungmin Park77e475c2008-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 Park916527f2007-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 */
81static int onenand_block_address(int device, int block)
82{
83 if (device & ONENAND_DEVICE_IS_DDP) {
84 /* Device Flash Core select, NAND Flash Block Address */
85 int dfs = 0, density, mask;
86
87 density = device >> ONENAND_DEVICE_DENSITY_SHIFT;
88 mask = (1 << (density + 6));
89
90 if (block & mask)
91 dfs = 1;
92
93 return (dfs << ONENAND_DDP_SHIFT) | (block & (mask - 1));
94 }
95
96 return block;
97}
98
99/**
100 * onenand_bufferram_address - [DEFAULT] Get bufferram address
101 * @param device the device id
102 * @param block the block
103 * @return set DBS value if DDP, otherwise 0
104 *
105 * Setup Start Address 2 Register (F101h) for DDP
106 */
107static int onenand_bufferram_address(int device, int block)
108{
109 if (device & ONENAND_DEVICE_IS_DDP) {
110 /* Device BufferRAM Select */
111 int dbs = 0, density, mask;
112
113 density = device >> ONENAND_DEVICE_DENSITY_SHIFT;
114 mask = (1 << (density + 6));
115
116 if (block & mask)
117 dbs = 1;
118
119 return (dbs << ONENAND_DDP_SHIFT);
120 }
121
122 return 0;
123}
124
125/**
126 * onenand_page_address - [DEFAULT] Get page address
127 * @param page the page address
128 * @param sector the sector address
129 * @return combined page and sector address
130 *
131 * Setup Start Address 8 Register (F107h)
132 */
133static int onenand_page_address(int page, int sector)
134{
135 /* Flash Page Address, Flash Sector Address */
136 int fpa, fsa;
137
138 fpa = page & ONENAND_FPA_MASK;
139 fsa = sector & ONENAND_FSA_MASK;
140
141 return ((fpa << ONENAND_FPA_SHIFT) | fsa);
142}
143
144/**
145 * onenand_buffer_address - [DEFAULT] Get buffer address
146 * @param dataram1 DataRAM index
147 * @param sectors the sector address
148 * @param count the number of sectors
149 * @return the start buffer value
150 *
151 * Setup Start Buffer Register (F200h)
152 */
153static int onenand_buffer_address(int dataram1, int sectors, int count)
154{
155 int bsa, bsc;
156
157 /* BufferRAM Sector Address */
158 bsa = sectors & ONENAND_BSA_MASK;
159
160 if (dataram1)
161 bsa |= ONENAND_BSA_DATARAM1; /* DataRAM1 */
162 else
163 bsa |= ONENAND_BSA_DATARAM0; /* DataRAM0 */
164
165 /* BufferRAM Sector Count */
166 bsc = count & ONENAND_BSC_MASK;
167
168 return ((bsa << ONENAND_BSA_SHIFT) | bsc);
169}
170
171/**
172 * onenand_command - [DEFAULT] Send command to OneNAND device
173 * @param mtd MTD device structure
174 * @param cmd the command to be sent
175 * @param addr offset to read from or write to
176 * @param len number of bytes to read or write
177 *
178 * Send command to OneNAND device. This function is used for middle/large page
179 * devices (1KB/2KB Bytes per page)
180 */
181static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
182 size_t len)
183{
184 struct onenand_chip *this = mtd->priv;
185 int value, readcmd = 0;
186 int block, page;
187 /* Now we use page size operation */
188 int sectors = 4, count = 4;
189
190 /* Address translation */
191 switch (cmd) {
192 case ONENAND_CMD_UNLOCK:
193 case ONENAND_CMD_LOCK:
194 case ONENAND_CMD_LOCK_TIGHT:
195 block = -1;
196 page = -1;
197 break;
198
199 case ONENAND_CMD_ERASE:
200 case ONENAND_CMD_BUFFERRAM:
201 block = (int)(addr >> this->erase_shift);
202 page = -1;
203 break;
204
205 default:
206 block = (int)(addr >> this->erase_shift);
207 page = (int)(addr >> this->page_shift);
208 page &= this->page_mask;
209 break;
210 }
211
212 /* NOTE: The setting order of the registers is very important! */
213 if (cmd == ONENAND_CMD_BUFFERRAM) {
214 /* Select DataRAM for DDP */
215 value = onenand_bufferram_address(this->device_id, block);
216 this->write_word(value,
217 this->base + ONENAND_REG_START_ADDRESS2);
218
219 /* Switch to the next data buffer */
220 ONENAND_SET_NEXT_BUFFERRAM(this);
221
222 return 0;
223 }
224
225 if (block != -1) {
226 /* Write 'DFS, FBA' of Flash */
227 value = onenand_block_address(this->device_id, block);
228 this->write_word(value,
229 this->base + ONENAND_REG_START_ADDRESS1);
230 }
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);
255
256 if (readcmd) {
257 /* Select DataRAM for DDP */
258 value =
259 onenand_bufferram_address(this->device_id, block);
260 this->write_word(value,
261 this->base +
262 ONENAND_REG_START_ADDRESS2);
263 }
264 }
265
266 /* Interrupt clear */
267 this->write_word(ONENAND_INT_CLEAR, this->base + ONENAND_REG_INTERRUPT);
268 /* Write command */
269 this->write_word(cmd, this->base + ONENAND_REG_COMMAND);
270
271 return 0;
272}
273
274/**
275 * onenand_wait - [DEFAULT] wait until the command is done
276 * @param mtd MTD device structure
277 * @param state state to select the max. timeout value
278 *
279 * Wait for command done. This applies to all OneNAND command
280 * Read can take up to 30us, erase up to 2ms and program up to 350us
281 * according to general OneNAND specs
282 */
283static int onenand_wait(struct mtd_info *mtd, int state)
284{
285 struct onenand_chip *this = mtd->priv;
286 unsigned int flags = ONENAND_INT_MASTER;
287 unsigned int interrupt = 0;
288 unsigned int ctrl, ecc;
289
290 while (1) {
291 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
292 if (interrupt & flags)
293 break;
294 }
295
296 ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
297
298 if (ctrl & ONENAND_CTRL_ERROR) {
Scott Wood3167c532008-06-20 12:38:57 -0500299 MTDDEBUG (MTD_DEBUG_LEVEL0,
Wolfgang Denk4b070802008-08-14 14:41:06 +0200300 "onenand_wait: controller error = 0x%04x\n", ctrl);
Kyungmin Park916527f2007-09-10 17:13:49 +0900301 return -EAGAIN;
302 }
303
304 if (ctrl & ONENAND_CTRL_LOCK) {
Scott Wood3167c532008-06-20 12:38:57 -0500305 MTDDEBUG (MTD_DEBUG_LEVEL0,
Wolfgang Denk4b070802008-08-14 14:41:06 +0200306 "onenand_wait: it's locked error = 0x%04x\n", ctrl);
Kyungmin Park916527f2007-09-10 17:13:49 +0900307 return -EIO;
308 }
309
310 if (interrupt & ONENAND_INT_READ) {
311 ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
312 if (ecc & ONENAND_ECC_2BIT_ALL) {
Scott Wood3167c532008-06-20 12:38:57 -0500313 MTDDEBUG (MTD_DEBUG_LEVEL0,
Wolfgang Denk4b070802008-08-14 14:41:06 +0200314 "onenand_wait: ECC error = 0x%04x\n", ecc);
Kyungmin Park916527f2007-09-10 17:13:49 +0900315 return -EBADMSG;
316 }
317 }
318
319 return 0;
320}
321
322/**
323 * onenand_bufferram_offset - [DEFAULT] BufferRAM offset
324 * @param mtd MTD data structure
325 * @param area BufferRAM area
326 * @return offset given area
327 *
328 * Return BufferRAM offset given area
329 */
330static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area)
331{
332 struct onenand_chip *this = mtd->priv;
333
334 if (ONENAND_CURRENT_BUFFERRAM(this)) {
335 if (area == ONENAND_DATARAM)
Kyungmin Parkd438d502008-08-13 09:11:02 +0900336 return mtd->writesize;
Kyungmin Park916527f2007-09-10 17:13:49 +0900337 if (area == ONENAND_SPARERAM)
338 return mtd->oobsize;
339 }
340
341 return 0;
342}
343
344/**
345 * onenand_read_bufferram - [OneNAND Interface] Read the bufferram area
346 * @param mtd MTD data structure
347 * @param area BufferRAM area
348 * @param buffer the databuffer to put/get data
349 * @param offset offset to read from or write to
350 * @param count number of bytes to read/write
351 *
352 * Read the BufferRAM area
353 */
354static int onenand_read_bufferram(struct mtd_info *mtd, int area,
355 unsigned char *buffer, int offset,
356 size_t count)
357{
358 struct onenand_chip *this = mtd->priv;
359 void __iomem *bufferram;
360
361 bufferram = this->base + area;
362 bufferram += onenand_bufferram_offset(mtd, area);
363
Wolfgang Denkd2c6fbe2008-05-01 21:30:16 +0200364 memcpy_16(buffer, bufferram + offset, count);
Kyungmin Park916527f2007-09-10 17:13:49 +0900365
366 return 0;
367}
368
369/**
370 * onenand_sync_read_bufferram - [OneNAND Interface] Read the bufferram area with Sync. Burst mode
371 * @param mtd MTD data structure
372 * @param area BufferRAM area
373 * @param buffer the databuffer to put/get data
374 * @param offset offset to read from or write to
375 * @param count number of bytes to read/write
376 *
377 * Read the BufferRAM area with Sync. Burst Mode
378 */
379static int onenand_sync_read_bufferram(struct mtd_info *mtd, int area,
380 unsigned char *buffer, int offset,
381 size_t count)
382{
383 struct onenand_chip *this = mtd->priv;
384 void __iomem *bufferram;
385
386 bufferram = this->base + area;
387 bufferram += onenand_bufferram_offset(mtd, area);
388
389 this->mmcontrol(mtd, ONENAND_SYS_CFG1_SYNC_READ);
390
Wolfgang Denkd2c6fbe2008-05-01 21:30:16 +0200391 memcpy_16(buffer, bufferram + offset, count);
Kyungmin Park916527f2007-09-10 17:13:49 +0900392
393 this->mmcontrol(mtd, 0);
394
395 return 0;
396}
397
398/**
399 * onenand_write_bufferram - [OneNAND Interface] Write the bufferram area
400 * @param mtd MTD data structure
401 * @param area BufferRAM area
402 * @param buffer the databuffer to put/get data
403 * @param offset offset to read from or write to
404 * @param count number of bytes to read/write
405 *
406 * Write the BufferRAM area
407 */
408static int onenand_write_bufferram(struct mtd_info *mtd, int area,
409 const unsigned char *buffer, int offset,
410 size_t count)
411{
412 struct onenand_chip *this = mtd->priv;
413 void __iomem *bufferram;
414
415 bufferram = this->base + area;
416 bufferram += onenand_bufferram_offset(mtd, area);
417
Wolfgang Denkd2c6fbe2008-05-01 21:30:16 +0200418 memcpy_16(bufferram + offset, buffer, count);
Kyungmin Park916527f2007-09-10 17:13:49 +0900419
420 return 0;
421}
422
423/**
424 * onenand_check_bufferram - [GENERIC] Check BufferRAM information
425 * @param mtd MTD data structure
426 * @param addr address to check
427 * @return 1 if there are valid data, otherwise 0
428 *
429 * Check bufferram if there is data we required
430 */
431static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr)
432{
433 struct onenand_chip *this = mtd->priv;
434 int block, page;
435 int i;
436
437 block = (int)(addr >> this->erase_shift);
438 page = (int)(addr >> this->page_shift);
439 page &= this->page_mask;
440
441 i = ONENAND_CURRENT_BUFFERRAM(this);
442
443 /* Is there valid data? */
444 if (this->bufferram[i].block == block &&
445 this->bufferram[i].page == page && this->bufferram[i].valid)
446 return 1;
447
448 return 0;
449}
450
451/**
452 * onenand_update_bufferram - [GENERIC] Update BufferRAM information
453 * @param mtd MTD data structure
454 * @param addr address to update
455 * @param valid valid flag
456 *
457 * Update BufferRAM information
458 */
459static int onenand_update_bufferram(struct mtd_info *mtd, loff_t addr,
460 int valid)
461{
462 struct onenand_chip *this = mtd->priv;
463 int block, page;
464 int i;
465
466 block = (int)(addr >> this->erase_shift);
467 page = (int)(addr >> this->page_shift);
468 page &= this->page_mask;
469
470 /* Invalidate BufferRAM */
471 for (i = 0; i < MAX_BUFFERRAM; i++) {
472 if (this->bufferram[i].block == block &&
473 this->bufferram[i].page == page)
474 this->bufferram[i].valid = 0;
475 }
476
477 /* Update BufferRAM */
478 i = ONENAND_CURRENT_BUFFERRAM(this);
479 this->bufferram[i].block = block;
480 this->bufferram[i].page = page;
481 this->bufferram[i].valid = valid;
482
483 return 0;
484}
485
486/**
Kyungmin Parkd438d502008-08-13 09:11:02 +0900487 * onenand_invalidate_bufferram - [GENERIC] Invalidate BufferRAM information
488 * @param mtd MTD data structure
489 * @param addr start address to invalidate
490 * @param len length to invalidate
491 *
492 * Invalidate BufferRAM information
493 */
494static void onenand_invalidate_bufferram(struct mtd_info *mtd, loff_t addr,
Wolfgang Denk4b070802008-08-14 14:41:06 +0200495 unsigned int len)
Kyungmin Parkd438d502008-08-13 09:11:02 +0900496{
497 struct onenand_chip *this = mtd->priv;
498 int i;
499 loff_t end_addr = addr + len;
500
501 /* Invalidate BufferRAM */
502 for (i = 0; i < MAX_BUFFERRAM; i++) {
503 loff_t buf_addr = this->bufferram[i].block << this->erase_shift;
504
505 if (buf_addr >= addr && buf_addr < end_addr)
506 this->bufferram[i].valid = 0;
507 }
508}
509
510/**
Kyungmin Park916527f2007-09-10 17:13:49 +0900511 * onenand_get_device - [GENERIC] Get chip for selected access
512 * @param mtd MTD device structure
513 * @param new_state the state which is requested
514 *
515 * Get the device and lock it for exclusive access
516 */
517static void onenand_get_device(struct mtd_info *mtd, int new_state)
518{
519 /* Do nothing */
520}
521
522/**
523 * onenand_release_device - [GENERIC] release chip
524 * @param mtd MTD device structure
525 *
526 * Deselect, release chip lock and wake up anyone waiting on the device
527 */
528static void onenand_release_device(struct mtd_info *mtd)
529{
530 /* Do nothing */
531}
532
533/**
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900534 * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer
Kyungmin Park916527f2007-09-10 17:13:49 +0900535 * @param mtd MTD device structure
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900536 * @param buf destination address
537 * @param column oob offset to read from
538 * @param thislen oob length to read
Kyungmin Park916527f2007-09-10 17:13:49 +0900539 */
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900540static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf,
541 int column, int thislen)
Kyungmin Park916527f2007-09-10 17:13:49 +0900542{
543 struct onenand_chip *this = mtd->priv;
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900544 struct nand_oobfree *free;
545 int readcol = column;
546 int readend = column + thislen;
547 int lastgap = 0;
548 unsigned int i;
549 uint8_t *oob_buf = this->oob_buf;
Kyungmin Park916527f2007-09-10 17:13:49 +0900550
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900551 free = this->ecclayout->oobfree;
552 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
553 if (readcol >= lastgap)
554 readcol += free->offset - lastgap;
555 if (readend >= lastgap)
556 readend += free->offset - lastgap;
557 lastgap = free->offset + free->length;
558 }
559 this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
560 free = this->ecclayout->oobfree;
561 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
562 int free_end = free->offset + free->length;
563 if (free->offset < readend && free_end > readcol) {
564 int st = max_t(int,free->offset,readcol);
565 int ed = min_t(int,free_end,readend);
566 int n = ed - st;
567 memcpy(buf, oob_buf + st, n);
568 buf += n;
569 } else if (column == 0)
570 break;
571 }
572 return 0;
573}
574
575/**
576 * onenand_read_ops_nolock - [OneNAND Interface] OneNAND read main and/or out-of-band
577 * @param mtd MTD device structure
578 * @param from offset to read from
579 * @param ops oob operation description structure
580 *
581 * OneNAND read main and/or out-of-band data
582 */
583static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
584 struct mtd_oob_ops *ops)
585{
586 struct onenand_chip *this = mtd->priv;
587 struct mtd_ecc_stats stats;
588 size_t len = ops->len;
589 size_t ooblen = ops->ooblen;
590 u_char *buf = ops->datbuf;
591 u_char *oobbuf = ops->oobbuf;
592 int read = 0, column, thislen;
593 int oobread = 0, oobcolumn, thisooblen, oobsize;
594 int ret = 0, boundary = 0;
595 int writesize = this->writesize;
596
597 MTDDEBUG(MTD_DEBUG_LEVEL3,
598 "onenand_read_ops_nolock: from = 0x%08x, len = %i\n",
599 (unsigned int) from, (int) len);
600
601 if (ops->mode == MTD_OOB_AUTO)
602 oobsize = this->ecclayout->oobavail;
603 else
604 oobsize = mtd->oobsize;
605
606 oobcolumn = from & (mtd->oobsize - 1);
Kyungmin Park916527f2007-09-10 17:13:49 +0900607
608 /* Do not allow reads past end of device */
609 if ((from + len) > mtd->size) {
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900610 printk(KERN_ERR "onenand_read_ops_nolock: Attempt read beyond end of device\n");
611 ops->retlen = 0;
612 ops->oobretlen = 0;
Kyungmin Park916527f2007-09-10 17:13:49 +0900613 return -EINVAL;
614 }
615
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900616 stats = mtd->ecc_stats;
Kyungmin Park916527f2007-09-10 17:13:49 +0900617
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900618 /* Read-while-load method */
Kyungmin Park916527f2007-09-10 17:13:49 +0900619
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900620 /* Do first load to bufferRAM */
621 if (read < len) {
Kyungmin Park916527f2007-09-10 17:13:49 +0900622 if (!onenand_check_bufferram(mtd, from)) {
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900623 this->command(mtd, ONENAND_CMD_READ, from, writesize);
Kyungmin Park916527f2007-09-10 17:13:49 +0900624 ret = this->wait(mtd, FL_READING);
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900625 onenand_update_bufferram(mtd, from, !ret);
626 if (ret == -EBADMSG)
627 ret = 0;
628 }
629 }
630
631 thislen = min_t(int, writesize, len - read);
632 column = from & (writesize - 1);
633 if (column + thislen > writesize)
634 thislen = writesize - column;
635
636 while (!ret) {
637 /* If there is more to load then start next load */
638 from += thislen;
639 if (read + thislen < len) {
640 this->command(mtd, ONENAND_CMD_READ, from, writesize);
641 /*
642 * Chip boundary handling in DDP
643 * Now we issued chip 1 read and pointed chip 1
644 * bufferam so we have to point chip 0 bufferam.
645 */
646 if (ONENAND_IS_DDP(this) &&
647 unlikely(from == (this->chipsize >> 1))) {
648 this->write_word(ONENAND_DDP_CHIP0, this->base + ONENAND_REG_START_ADDRESS2);
649 boundary = 1;
650 } else
651 boundary = 0;
652 ONENAND_SET_PREV_BUFFERRAM(this);
Kyungmin Park916527f2007-09-10 17:13:49 +0900653 }
654
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900655 /* While load is going, read from last bufferRAM */
656 this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
Kyungmin Park916527f2007-09-10 17:13:49 +0900657
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900658 /* Read oob area if needed */
659 if (oobbuf) {
660 thisooblen = oobsize - oobcolumn;
661 thisooblen = min_t(int, thisooblen, ooblen - oobread);
662
663 if (ops->mode == MTD_OOB_AUTO)
664 onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);
665 else
666 this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen);
667 oobread += thisooblen;
668 oobbuf += thisooblen;
669 oobcolumn = 0;
670 }
671
672 /* See if we are done */
Kyungmin Park916527f2007-09-10 17:13:49 +0900673 read += thislen;
674 if (read == len)
675 break;
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900676 /* Set up for next read from bufferRAM */
677 if (unlikely(boundary))
678 this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);
679 ONENAND_SET_NEXT_BUFFERRAM(this);
Kyungmin Park916527f2007-09-10 17:13:49 +0900680 buf += thislen;
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900681 thislen = min_t(int, writesize, len - read);
682 column = 0;
Kyungmin Park916527f2007-09-10 17:13:49 +0900683
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900684 /* Now wait for load */
685 ret = this->wait(mtd, FL_READING);
686 onenand_update_bufferram(mtd, from, !ret);
687 if (ret == -EBADMSG)
688 ret = 0;
689 }
Kyungmin Park916527f2007-09-10 17:13:49 +0900690
691 /*
692 * Return success, if no ECC failures, else -EBADMSG
693 * fs driver will take care of that, because
694 * retlen == desired len and result == -EBADMSG
695 */
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900696 ops->retlen = read;
697 ops->oobretlen = oobread;
698
699 if (ret)
700 return ret;
701
702 if (mtd->ecc_stats.failed - stats.failed)
703 return -EBADMSG;
704
705 return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
706}
707
708/**
709 * onenand_read_oob_nolock - [MTD Interface] OneNAND read out-of-band
710 * @param mtd MTD device structure
711 * @param from offset to read from
712 * @param ops oob operation description structure
713 *
714 * OneNAND read out-of-band data from the spare area
715 */
716static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
717 struct mtd_oob_ops *ops)
718{
719 struct onenand_chip *this = mtd->priv;
720 struct mtd_ecc_stats stats;
721 int read = 0, thislen, column, oobsize;
722 size_t len = ops->ooblen;
723 mtd_oob_mode_t mode = ops->mode;
724 u_char *buf = ops->oobbuf;
725 int ret = 0;
726
727 from += ops->ooboffs;
728
729 MTDDEBUG(MTD_DEBUG_LEVEL3,
730 "onenand_read_oob_nolock: from = 0x%08x, len = %i\n",
731 (unsigned int) from, (int) len);
732
733 /* Initialize return length value */
734 ops->oobretlen = 0;
735
736 if (mode == MTD_OOB_AUTO)
737 oobsize = this->ecclayout->oobavail;
738 else
739 oobsize = mtd->oobsize;
740
741 column = from & (mtd->oobsize - 1);
742
743 if (unlikely(column >= oobsize)) {
744 printk(KERN_ERR "onenand_read_oob_nolock: Attempted to start read outside oob\n");
745 return -EINVAL;
746 }
747
748 /* Do not allow reads past end of device */
749 if (unlikely(from >= mtd->size ||
750 column + len > ((mtd->size >> this->page_shift) -
751 (from >> this->page_shift)) * oobsize)) {
752 printk(KERN_ERR "onenand_read_oob_nolock: Attempted to read beyond end of device\n");
753 return -EINVAL;
754 }
755
756 stats = mtd->ecc_stats;
757
758 while (read < len) {
759 thislen = oobsize - column;
760 thislen = min_t(int, thislen, len);
761
762 this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);
763
764 onenand_update_bufferram(mtd, from, 0);
765
766 ret = this->wait(mtd, FL_READING);
767 if (ret && ret != -EBADMSG) {
768 printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret);
769 break;
770 }
771
772 if (mode == MTD_OOB_AUTO)
773 onenand_transfer_auto_oob(mtd, buf, column, thislen);
774 else
775 this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
776
777 read += thislen;
778
779 if (read == len)
780 break;
781
782 buf += thislen;
783
784 /* Read more? */
785 if (read < len) {
786 /* Page size */
787 from += mtd->writesize;
788 column = 0;
789 }
790 }
791
792 ops->oobretlen = read;
793
794 if (ret)
795 return ret;
796
797 if (mtd->ecc_stats.failed - stats.failed)
798 return -EBADMSG;
799
800 return 0;
Kyungmin Park916527f2007-09-10 17:13:49 +0900801}
802
803/**
804 * onenand_read - [MTD Interface] MTD compability function for onenand_read_ecc
805 * @param mtd MTD device structure
806 * @param from offset to read from
807 * @param len number of bytes to read
808 * @param retlen pointer to variable to store the number of read bytes
809 * @param buf the databuffer to put data
810 *
811 * This function simply calls onenand_read_ecc with oob buffer and oobsel = NULL
812*/
813int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
814 size_t * retlen, u_char * buf)
815{
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900816 struct mtd_oob_ops ops = {
817 .len = len,
818 .ooblen = 0,
819 .datbuf = buf,
820 .oobbuf = NULL,
821 };
822 int ret;
823
824 onenand_get_device(mtd, FL_READING);
825 ret = onenand_read_ops_nolock(mtd, from, &ops);
826 onenand_release_device(mtd);
827
828 *retlen = ops.retlen;
829 return ret;
Kyungmin Park916527f2007-09-10 17:13:49 +0900830}
831
832/**
833 * onenand_read_oob - [MTD Interface] OneNAND read out-of-band
834 * @param mtd MTD device structure
835 * @param from offset to read from
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900836 * @param ops oob operations description structure
Kyungmin Park916527f2007-09-10 17:13:49 +0900837 *
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900838 * OneNAND main and/or out-of-band
Kyungmin Park916527f2007-09-10 17:13:49 +0900839 */
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900840int onenand_read_oob(struct mtd_info *mtd, loff_t from,
841 struct mtd_oob_ops *ops)
842{
843 int ret;
844
845 switch (ops->mode) {
846 case MTD_OOB_PLACE:
847 case MTD_OOB_AUTO:
848 break;
849 case MTD_OOB_RAW:
850 /* Not implemented yet */
851 default:
852 return -EINVAL;
853 }
854
855 onenand_get_device(mtd, FL_READING);
856 if (ops->datbuf)
857 ret = onenand_read_ops_nolock(mtd, from, ops);
858 else
859 ret = onenand_read_oob_nolock(mtd, from, ops);
860 onenand_release_device(mtd);
861
862 return ret;
863}
864
865/**
866 * onenand_bbt_wait - [DEFAULT] wait until the command is done
867 * @param mtd MTD device structure
868 * @param state state to select the max. timeout value
869 *
870 * Wait for command done.
871 */
872static int onenand_bbt_wait(struct mtd_info *mtd, int state)
873{
874 struct onenand_chip *this = mtd->priv;
875 unsigned int flags = ONENAND_INT_MASTER;
876 unsigned int interrupt;
877 unsigned int ctrl;
878
879 while (1) {
880 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
881 if (interrupt & flags)
882 break;
883 }
884
885 /* To get correct interrupt status in timeout case */
886 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
887 ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
888
889 /* Initial bad block case: 0x2400 or 0x0400 */
890 if (ctrl & ONENAND_CTRL_ERROR) {
891 printk(KERN_DEBUG "onenand_bbt_wait: controller error = 0x%04x\n", ctrl);
892 return ONENAND_BBT_READ_ERROR;
893 }
894
895 if (interrupt & ONENAND_INT_READ) {
896 int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
897 if (ecc & ONENAND_ECC_2BIT_ALL)
898 return ONENAND_BBT_READ_ERROR;
899 } else {
900 printk(KERN_ERR "onenand_bbt_wait: read timeout!"
901 "ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt);
902 return ONENAND_BBT_READ_FATAL_ERROR;
903 }
904
905 return 0;
906}
907
908/**
909 * onenand_bbt_read_oob - [MTD Interface] OneNAND read out-of-band for bbt scan
910 * @param mtd MTD device structure
911 * @param from offset to read from
912 * @param ops oob operation description structure
913 *
914 * OneNAND read out-of-band data from the spare area for bbt scan
915 */
916int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
917 struct mtd_oob_ops *ops)
Kyungmin Park916527f2007-09-10 17:13:49 +0900918{
919 struct onenand_chip *this = mtd->priv;
920 int read = 0, thislen, column;
921 int ret = 0;
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900922 size_t len = ops->ooblen;
923 u_char *buf = ops->oobbuf;
Kyungmin Park916527f2007-09-10 17:13:49 +0900924
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900925 MTDDEBUG(MTD_DEBUG_LEVEL3,
926 "onenand_bbt_read_oob: from = 0x%08x, len = %zi\n",
927 (unsigned int) from, len);
Kyungmin Park916527f2007-09-10 17:13:49 +0900928
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900929 /* Initialize return value */
930 ops->oobretlen = 0;
Kyungmin Park916527f2007-09-10 17:13:49 +0900931
932 /* Do not allow reads past end of device */
933 if (unlikely((from + len) > mtd->size)) {
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900934 printk(KERN_ERR "onenand_bbt_read_oob: Attempt read beyond end of device\n");
935 return ONENAND_BBT_READ_FATAL_ERROR;
Kyungmin Park916527f2007-09-10 17:13:49 +0900936 }
937
938 /* Grab the lock and see if the device is available */
939 onenand_get_device(mtd, FL_READING);
940
941 column = from & (mtd->oobsize - 1);
942
943 while (read < len) {
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900944
Kyungmin Park916527f2007-09-10 17:13:49 +0900945 thislen = mtd->oobsize - column;
946 thislen = min_t(int, thislen, len);
947
948 this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);
949
950 onenand_update_bufferram(mtd, from, 0);
951
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900952 ret = onenand_bbt_wait(mtd, FL_READING);
953 if (ret)
954 break;
Kyungmin Park916527f2007-09-10 17:13:49 +0900955
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900956 this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
Kyungmin Park916527f2007-09-10 17:13:49 +0900957 read += thislen;
958 if (read == len)
959 break;
960
Kyungmin Park916527f2007-09-10 17:13:49 +0900961 buf += thislen;
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900962
Kyungmin Park916527f2007-09-10 17:13:49 +0900963 /* Read more? */
964 if (read < len) {
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900965 /* Update Page size */
966 from += this->writesize;
Kyungmin Park916527f2007-09-10 17:13:49 +0900967 column = 0;
968 }
969 }
970
971 /* Deselect and wake up anyone waiting on the device */
972 onenand_release_device(mtd);
973
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900974 ops->oobretlen = read;
Kyungmin Park916527f2007-09-10 17:13:49 +0900975 return ret;
976}
977
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900978
Kyungmin Park916527f2007-09-10 17:13:49 +0900979#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
980/**
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900981 * onenand_verify_oob - [GENERIC] verify the oob contents after a write
982 * @param mtd MTD device structure
983 * @param buf the databuffer to verify
984 * @param to offset to read from
Kyungmin Park916527f2007-09-10 17:13:49 +0900985 */
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900986static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to)
Kyungmin Park916527f2007-09-10 17:13:49 +0900987{
988 struct onenand_chip *this = mtd->priv;
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900989 u_char *oob_buf = this->oob_buf;
990 int status, i;
991
992 this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize);
993 onenand_update_bufferram(mtd, to, 0);
994 status = this->wait(mtd, FL_READING);
995 if (status)
996 return status;
997
998 this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
999 for (i = 0; i < mtd->oobsize; i++)
1000 if (buf[i] != 0xFF && buf[i] != oob_buf[i])
1001 return -EBADMSG;
1002
1003 return 0;
1004}
1005
1006/**
1007 * onenand_verify - [GENERIC] verify the chip contents after a write
1008 * @param mtd MTD device structure
1009 * @param buf the databuffer to verify
1010 * @param addr offset to read from
1011 * @param len number of bytes to read and compare
1012 */
1013static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, size_t len)
1014{
1015 struct onenand_chip *this = mtd->priv;
1016 void __iomem *dataram;
Kyungmin Park916527f2007-09-10 17:13:49 +09001017 int ret = 0;
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001018 int thislen, column;
Kyungmin Park916527f2007-09-10 17:13:49 +09001019
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001020 while (len != 0) {
1021 thislen = min_t(int, this->writesize, len);
1022 column = addr & (this->writesize - 1);
1023 if (column + thislen > this->writesize)
1024 thislen = this->writesize - column;
Kyungmin Park916527f2007-09-10 17:13:49 +09001025
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001026 this->command(mtd, ONENAND_CMD_READ, addr, this->writesize);
Kyungmin Park916527f2007-09-10 17:13:49 +09001027
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001028 onenand_update_bufferram(mtd, addr, 0);
Kyungmin Park916527f2007-09-10 17:13:49 +09001029
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001030 ret = this->wait(mtd, FL_READING);
1031 if (ret)
1032 return ret;
Kyungmin Park916527f2007-09-10 17:13:49 +09001033
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001034 onenand_update_bufferram(mtd, addr, 1);
1035
1036 dataram = this->base + ONENAND_DATARAM;
1037 dataram += onenand_bufferram_offset(mtd, ONENAND_DATARAM);
1038
1039 if (memcmp(buf, dataram + column, thislen))
1040 return -EBADMSG;
1041
1042 len -= thislen;
1043 buf += thislen;
1044 addr += thislen;
1045 }
Kyungmin Park916527f2007-09-10 17:13:49 +09001046
1047 return 0;
1048}
1049#else
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001050#define onenand_verify(...) (0)
1051#define onenand_verify_oob(...) (0)
Kyungmin Park916527f2007-09-10 17:13:49 +09001052#endif
1053
Kyungmin Parkd438d502008-08-13 09:11:02 +09001054#define NOTALIGNED(x) ((x & (mtd->writesize - 1)) != 0)
Kyungmin Park916527f2007-09-10 17:13:49 +09001055
1056/**
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001057 * onenand_fill_auto_oob - [Internal] oob auto-placement transfer
1058 * @param mtd MTD device structure
1059 * @param oob_buf oob buffer
1060 * @param buf source address
1061 * @param column oob offset to write to
1062 * @param thislen oob length to write
Kyungmin Park916527f2007-09-10 17:13:49 +09001063 */
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001064static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
1065 const u_char *buf, int column, int thislen)
Kyungmin Park916527f2007-09-10 17:13:49 +09001066{
1067 struct onenand_chip *this = mtd->priv;
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001068 struct nand_oobfree *free;
1069 int writecol = column;
1070 int writeend = column + thislen;
1071 int lastgap = 0;
1072 unsigned int i;
1073
1074 free = this->ecclayout->oobfree;
1075 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
1076 if (writecol >= lastgap)
1077 writecol += free->offset - lastgap;
1078 if (writeend >= lastgap)
1079 writeend += free->offset - lastgap;
1080 lastgap = free->offset + free->length;
1081 }
1082 free = this->ecclayout->oobfree;
1083 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
1084 int free_end = free->offset + free->length;
1085 if (free->offset < writeend && free_end > writecol) {
1086 int st = max_t(int,free->offset,writecol);
1087 int ed = min_t(int,free_end,writeend);
1088 int n = ed - st;
1089 memcpy(oob_buf + st, buf, n);
1090 buf += n;
1091 } else if (column == 0)
1092 break;
1093 }
1094 return 0;
1095}
1096
1097/**
1098 * onenand_write_ops_nolock - [OneNAND Interface] write main and/or out-of-band
1099 * @param mtd MTD device structure
1100 * @param to offset to write to
1101 * @param ops oob operation description structure
1102 *
1103 * Write main and/or oob with ECC
1104 */
1105static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
1106 struct mtd_oob_ops *ops)
1107{
1108 struct onenand_chip *this = mtd->priv;
1109 int written = 0, column, thislen, subpage;
1110 int oobwritten = 0, oobcolumn, thisooblen, oobsize;
1111 size_t len = ops->len;
1112 size_t ooblen = ops->ooblen;
1113 const u_char *buf = ops->datbuf;
1114 const u_char *oob = ops->oobbuf;
1115 u_char *oobbuf;
Kyungmin Park916527f2007-09-10 17:13:49 +09001116 int ret = 0;
1117
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001118 MTDDEBUG(MTD_DEBUG_LEVEL3,
1119 "onenand_write_ops_nolock: to = 0x%08x, len = %i\n",
1120 (unsigned int) to, (int) len);
Kyungmin Park916527f2007-09-10 17:13:49 +09001121
1122 /* Initialize retlen, in case of early exit */
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001123 ops->retlen = 0;
1124 ops->oobretlen = 0;
Kyungmin Park916527f2007-09-10 17:13:49 +09001125
1126 /* Do not allow writes past end of device */
1127 if (unlikely((to + len) > mtd->size)) {
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001128 printk(KERN_ERR "onenand_write_ops_nolock: Attempt write to past end of device\n");
Kyungmin Park916527f2007-09-10 17:13:49 +09001129 return -EINVAL;
1130 }
1131
1132 /* Reject writes, which are not page aligned */
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001133 if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
1134 printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n");
Kyungmin Park916527f2007-09-10 17:13:49 +09001135 return -EINVAL;
1136 }
1137
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001138 if (ops->mode == MTD_OOB_AUTO)
1139 oobsize = this->ecclayout->oobavail;
1140 else
1141 oobsize = mtd->oobsize;
1142
1143 oobcolumn = to & (mtd->oobsize - 1);
1144
1145 column = to & (mtd->writesize - 1);
Kyungmin Park916527f2007-09-10 17:13:49 +09001146
1147 /* Loop until all data write */
1148 while (written < len) {
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001149 u_char *wbuf = (u_char *) buf;
Kyungmin Park916527f2007-09-10 17:13:49 +09001150
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001151 thislen = min_t(int, mtd->writesize - column, len - written);
1152 thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten);
Kyungmin Park916527f2007-09-10 17:13:49 +09001153
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001154 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
1155
1156 /* Partial page write */
1157 subpage = thislen < mtd->writesize;
1158 if (subpage) {
1159 memset(this->page_buf, 0xff, mtd->writesize);
1160 memcpy(this->page_buf + column, buf, thislen);
1161 wbuf = this->page_buf;
1162 }
1163
1164 this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
1165
1166 if (oob) {
1167 oobbuf = this->oob_buf;
1168
1169 /* We send data to spare ram with oobsize
1170 * * to prevent byte access */
1171 memset(oobbuf, 0xff, mtd->oobsize);
1172 if (ops->mode == MTD_OOB_AUTO)
1173 onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
1174 else
1175 memcpy(oobbuf + oobcolumn, oob, thisooblen);
1176
1177 oobwritten += thisooblen;
1178 oob += thisooblen;
1179 oobcolumn = 0;
1180 } else
1181 oobbuf = (u_char *) ffchars;
1182
1183 this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
Kyungmin Park916527f2007-09-10 17:13:49 +09001184
Kyungmin Parkd438d502008-08-13 09:11:02 +09001185 this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
Kyungmin Park916527f2007-09-10 17:13:49 +09001186
Kyungmin Park916527f2007-09-10 17:13:49 +09001187 ret = this->wait(mtd, FL_WRITING);
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001188
1189 /* In partial page write we don't update bufferram */
1190 onenand_update_bufferram(mtd, to, !ret && !subpage);
1191 if (ONENAND_IS_2PLANE(this)) {
1192 ONENAND_SET_BUFFERRAM1(this);
1193 onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage);
1194 }
1195
Kyungmin Park916527f2007-09-10 17:13:49 +09001196 if (ret) {
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001197 printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
1198 break;
1199 }
1200
1201 /* Only check verify write turn on */
1202 ret = onenand_verify(mtd, buf, to, thislen);
1203 if (ret) {
1204 printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
Kyungmin Park916527f2007-09-10 17:13:49 +09001205 break;
1206 }
1207
1208 written += thislen;
1209
Kyungmin Park916527f2007-09-10 17:13:49 +09001210 if (written == len)
1211 break;
1212
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001213 column = 0;
Kyungmin Park916527f2007-09-10 17:13:49 +09001214 to += thislen;
1215 buf += thislen;
1216 }
1217
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001218 ops->retlen = written;
Kyungmin Park916527f2007-09-10 17:13:49 +09001219
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001220 return ret;
1221}
1222
1223/**
1224 * onenand_write_oob_nolock - [Internal] OneNAND write out-of-band
1225 * @param mtd MTD device structure
1226 * @param to offset to write to
1227 * @param len number of bytes to write
1228 * @param retlen pointer to variable to store the number of written bytes
1229 * @param buf the data to write
1230 * @param mode operation mode
1231 *
1232 * OneNAND write out-of-band
1233 */
1234static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
1235 struct mtd_oob_ops *ops)
1236{
1237 struct onenand_chip *this = mtd->priv;
1238 int column, ret = 0, oobsize;
1239 int written = 0;
1240 u_char *oobbuf;
1241 size_t len = ops->ooblen;
1242 const u_char *buf = ops->oobbuf;
1243 mtd_oob_mode_t mode = ops->mode;
1244
1245 to += ops->ooboffs;
1246
1247 MTDDEBUG(MTD_DEBUG_LEVEL3,
1248 "onenand_write_oob_nolock: to = 0x%08x, len = %i\n",
1249 (unsigned int) to, (int) len);
1250
1251 /* Initialize retlen, in case of early exit */
1252 ops->oobretlen = 0;
1253
1254 if (mode == MTD_OOB_AUTO)
1255 oobsize = this->ecclayout->oobavail;
1256 else
1257 oobsize = mtd->oobsize;
1258
1259 column = to & (mtd->oobsize - 1);
1260
1261 if (unlikely(column >= oobsize)) {
1262 printk(KERN_ERR "onenand_write_oob_nolock: Attempted to start write outside oob\n");
1263 return -EINVAL;
1264 }
1265
1266 /* For compatibility with NAND: Do not allow write past end of page */
1267 if (unlikely(column + len > oobsize)) {
1268 printk(KERN_ERR "onenand_write_oob_nolock: "
1269 "Attempt to write past end of page\n");
1270 return -EINVAL;
1271 }
1272
1273 /* Do not allow reads past end of device */
1274 if (unlikely(to >= mtd->size ||
1275 column + len > ((mtd->size >> this->page_shift) -
1276 (to >> this->page_shift)) * oobsize)) {
1277 printk(KERN_ERR "onenand_write_oob_nolock: Attempted to write past end of device\n");
1278 return -EINVAL;
1279 }
1280
1281 oobbuf = this->oob_buf;
1282
1283 /* Loop until all data write */
1284 while (written < len) {
1285 int thislen = min_t(int, oobsize, len - written);
1286
1287 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize);
1288
1289 /* We send data to spare ram with oobsize
1290 * to prevent byte access */
1291 memset(oobbuf, 0xff, mtd->oobsize);
1292 if (mode == MTD_OOB_AUTO)
1293 onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen);
1294 else
1295 memcpy(oobbuf + column, buf, thislen);
1296 this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
1297
1298 this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize);
1299
1300 onenand_update_bufferram(mtd, to, 0);
1301 if (ONENAND_IS_2PLANE(this)) {
1302 ONENAND_SET_BUFFERRAM1(this);
1303 onenand_update_bufferram(mtd, to + this->writesize, 0);
1304 }
1305
1306 ret = this->wait(mtd, FL_WRITING);
1307 if (ret) {
1308 printk(KERN_ERR "onenand_write_oob_nolock: write failed %d\n", ret);
1309 break;
1310 }
1311
1312 ret = onenand_verify_oob(mtd, oobbuf, to);
1313 if (ret) {
1314 printk(KERN_ERR "onenand_write_oob_nolock: verify failed %d\n", ret);
1315 break;
1316 }
1317
1318 written += thislen;
1319 if (written == len)
1320 break;
1321
1322 to += mtd->writesize;
1323 buf += thislen;
1324 column = 0;
1325 }
1326
1327 ops->oobretlen = written;
Kyungmin Park916527f2007-09-10 17:13:49 +09001328
1329 return ret;
1330}
1331
1332/**
1333 * onenand_write - [MTD Interface] compability function for onenand_write_ecc
1334 * @param mtd MTD device structure
1335 * @param to offset to write to
1336 * @param len number of bytes to write
1337 * @param retlen pointer to variable to store the number of written bytes
1338 * @param buf the data to write
1339 *
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001340 * Write with ECC
Kyungmin Park916527f2007-09-10 17:13:49 +09001341 */
1342int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
1343 size_t * retlen, const u_char * buf)
1344{
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001345 struct mtd_oob_ops ops = {
1346 .len = len,
1347 .ooblen = 0,
1348 .datbuf = (u_char *) buf,
1349 .oobbuf = NULL,
1350 };
1351 int ret;
1352
1353 onenand_get_device(mtd, FL_WRITING);
1354 ret = onenand_write_ops_nolock(mtd, to, &ops);
1355 onenand_release_device(mtd);
1356
1357 *retlen = ops.retlen;
1358 return ret;
Kyungmin Park916527f2007-09-10 17:13:49 +09001359}
1360
1361/**
1362 * onenand_write_oob - [MTD Interface] OneNAND write out-of-band
1363 * @param mtd MTD device structure
1364 * @param to offset to write to
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001365 * @param ops oob operation description structure
Kyungmin Park916527f2007-09-10 17:13:49 +09001366 *
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001367 * OneNAND write main and/or out-of-band
Kyungmin Park916527f2007-09-10 17:13:49 +09001368 */
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001369int onenand_write_oob(struct mtd_info *mtd, loff_t to,
1370 struct mtd_oob_ops *ops)
Kyungmin Park916527f2007-09-10 17:13:49 +09001371{
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001372 int ret;
Kyungmin Park916527f2007-09-10 17:13:49 +09001373
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001374 switch (ops->mode) {
1375 case MTD_OOB_PLACE:
1376 case MTD_OOB_AUTO:
1377 break;
1378 case MTD_OOB_RAW:
1379 /* Not implemented yet */
1380 default:
Kyungmin Park916527f2007-09-10 17:13:49 +09001381 return -EINVAL;
1382 }
1383
Kyungmin Park916527f2007-09-10 17:13:49 +09001384 onenand_get_device(mtd, FL_WRITING);
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001385 if (ops->datbuf)
1386 ret = onenand_write_ops_nolock(mtd, to, ops);
1387 else
1388 ret = onenand_write_oob_nolock(mtd, to, ops);
Kyungmin Park916527f2007-09-10 17:13:49 +09001389 onenand_release_device(mtd);
1390
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001391 return ret;
Kyungmin Park916527f2007-09-10 17:13:49 +09001392
Kyungmin Park916527f2007-09-10 17:13:49 +09001393}
1394
1395/**
Kyungmin Parkd438d502008-08-13 09:11:02 +09001396 * onenand_block_isbad_nolock - [GENERIC] Check if a block is marked bad
1397 * @param mtd MTD device structure
1398 * @param ofs offset from device start
1399 * @param allowbbt 1, if its allowed to access the bbt area
1400 *
1401 * Check, if the block is bad, Either by reading the bad block table or
1402 * calling of the scan function.
1403 */
1404static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int allowbbt)
1405{
1406 struct onenand_chip *this = mtd->priv;
1407 struct bbm_info *bbm = this->bbm;
1408
1409 /* Return info from the table */
1410 return bbm->isbad_bbt(mtd, ofs, allowbbt);
1411}
1412
1413
1414/**
Kyungmin Park916527f2007-09-10 17:13:49 +09001415 * onenand_erase - [MTD Interface] erase block(s)
1416 * @param mtd MTD device structure
1417 * @param instr erase instruction
1418 *
1419 * Erase one ore more blocks
1420 */
1421int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
1422{
1423 struct onenand_chip *this = mtd->priv;
1424 unsigned int block_size;
1425 loff_t addr;
1426 int len;
1427 int ret = 0;
1428
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001429 MTDDEBUG (MTD_DEBUG_LEVEL3,
1430 "onenand_erase: start = 0x%08x, len = %i\n",
1431 (unsigned int)instr->addr, (unsigned int)ins tr->len);
Kyungmin Park916527f2007-09-10 17:13:49 +09001432
1433 block_size = (1 << this->erase_shift);
1434
1435 /* Start address must align on block boundary */
1436 if (unlikely(instr->addr & (block_size - 1))) {
Scott Wood3167c532008-06-20 12:38:57 -05001437 MTDDEBUG (MTD_DEBUG_LEVEL0,
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001438 "onenand_erase: Unaligned address\n");
Kyungmin Park916527f2007-09-10 17:13:49 +09001439 return -EINVAL;
1440 }
1441
1442 /* Length must align on block boundary */
1443 if (unlikely(instr->len & (block_size - 1))) {
Scott Wood3167c532008-06-20 12:38:57 -05001444 MTDDEBUG (MTD_DEBUG_LEVEL0,
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001445 "onenand_erase: Length not block aligned\n");
Kyungmin Park916527f2007-09-10 17:13:49 +09001446 return -EINVAL;
1447 }
1448
1449 /* Do not allow erase past end of device */
1450 if (unlikely((instr->len + instr->addr) > mtd->size)) {
Scott Wood3167c532008-06-20 12:38:57 -05001451 MTDDEBUG (MTD_DEBUG_LEVEL0,
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001452 "onenand_erase: Erase past end of device\n");
Kyungmin Park916527f2007-09-10 17:13:49 +09001453 return -EINVAL;
1454 }
1455
1456 instr->fail_addr = 0xffffffff;
1457
1458 /* Grab the lock and see if the device is available */
1459 onenand_get_device(mtd, FL_ERASING);
1460
1461 /* Loop throught the pages */
1462 len = instr->len;
1463 addr = instr->addr;
1464
1465 instr->state = MTD_ERASING;
1466
1467 while (len) {
1468
1469 /* TODO Check badblock */
1470
1471 this->command(mtd, ONENAND_CMD_ERASE, addr, block_size);
1472
Kyungmin Parkd438d502008-08-13 09:11:02 +09001473 onenand_invalidate_bufferram(mtd, addr, block_size);
1474
Kyungmin Park916527f2007-09-10 17:13:49 +09001475 ret = this->wait(mtd, FL_ERASING);
1476 /* Check, if it is write protected */
1477 if (ret) {
1478 if (ret == -EPERM)
Scott Wood3167c532008-06-20 12:38:57 -05001479 MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: "
Wolfgang Denk4b070802008-08-14 14:41:06 +02001480 "Device is write protected!!!\n");
Kyungmin Park916527f2007-09-10 17:13:49 +09001481 else
Scott Wood3167c532008-06-20 12:38:57 -05001482 MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: "
Wolfgang Denk4b070802008-08-14 14:41:06 +02001483 "Failed erase, block %d\n",
1484 (unsigned)(addr >> this->erase_shift));
Kyungmin Park916527f2007-09-10 17:13:49 +09001485 instr->state = MTD_ERASE_FAILED;
1486 instr->fail_addr = addr;
1487 goto erase_exit;
1488 }
1489
1490 len -= block_size;
1491 addr += block_size;
1492 }
1493
1494 instr->state = MTD_ERASE_DONE;
1495
1496 erase_exit:
1497
1498 ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
1499 /* Do call back function */
1500 if (!ret)
1501 mtd_erase_callback(instr);
1502
1503 /* Deselect and wake up anyone waiting on the device */
1504 onenand_release_device(mtd);
1505
1506 return ret;
1507}
1508
1509/**
1510 * onenand_sync - [MTD Interface] sync
1511 * @param mtd MTD device structure
1512 *
1513 * Sync is actually a wait for chip ready function
1514 */
1515void onenand_sync(struct mtd_info *mtd)
1516{
Scott Wood3167c532008-06-20 12:38:57 -05001517 MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_sync: called\n");
Kyungmin Park916527f2007-09-10 17:13:49 +09001518
1519 /* Grab the lock and see if the device is available */
1520 onenand_get_device(mtd, FL_SYNCING);
1521
1522 /* Release it and go back */
1523 onenand_release_device(mtd);
1524}
1525
1526/**
1527 * onenand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad
1528 * @param mtd MTD device structure
1529 * @param ofs offset relative to mtd start
Kyungmin Parkd438d502008-08-13 09:11:02 +09001530 *
1531 * Check whether the block is bad
Kyungmin Park916527f2007-09-10 17:13:49 +09001532 */
1533int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs)
1534{
Kyungmin Parkd438d502008-08-13 09:11:02 +09001535 int ret;
1536
1537 /* Check for invalid offset */
1538 if (ofs > mtd->size)
1539 return -EINVAL;
1540
1541 onenand_get_device(mtd, FL_READING);
1542 ret = onenand_block_isbad_nolock(mtd,ofs, 0);
1543 onenand_release_device(mtd);
1544 return ret;
Kyungmin Park916527f2007-09-10 17:13:49 +09001545}
1546
1547/**
1548 * onenand_block_markbad - [MTD Interface] Mark the block at the given offset as bad
1549 * @param mtd MTD device structure
1550 * @param ofs offset relative to mtd start
Kyungmin Parkd438d502008-08-13 09:11:02 +09001551 *
1552 * Mark the block as bad
Kyungmin Park916527f2007-09-10 17:13:49 +09001553 */
1554int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
1555{
Kyungmin Parkd438d502008-08-13 09:11:02 +09001556 struct onenand_chip *this = mtd->priv;
1557 int ret;
1558
1559 ret = onenand_block_isbad(mtd, ofs);
1560 if (ret) {
1561 /* If it was bad already, return success and do nothing */
1562 if (ret > 0)
1563 return 0;
1564 return ret;
1565 }
1566
1567 ret = this->block_markbad(mtd, ofs);
1568 return ret;
Kyungmin Park916527f2007-09-10 17:13:49 +09001569}
1570
1571/**
1572 * onenand_unlock - [MTD Interface] Unlock block(s)
1573 * @param mtd MTD device structure
1574 * @param ofs offset relative to mtd start
1575 * @param len number of bytes to unlock
1576 *
1577 * Unlock one or more blocks
1578 */
1579int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
1580{
1581 struct onenand_chip *this = mtd->priv;
1582 int start, end, block, value, status;
1583
1584 start = ofs >> this->erase_shift;
1585 end = len >> this->erase_shift;
1586
1587 /* Continuous lock scheme */
1588 if (this->options & ONENAND_CONT_LOCK) {
1589 /* Set start block address */
1590 this->write_word(start,
1591 this->base + ONENAND_REG_START_BLOCK_ADDRESS);
1592 /* Set end block address */
1593 this->write_word(end - 1,
1594 this->base + ONENAND_REG_END_BLOCK_ADDRESS);
1595 /* Write unlock command */
1596 this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0);
1597
1598 /* There's no return value */
1599 this->wait(mtd, FL_UNLOCKING);
1600
1601 /* Sanity check */
1602 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
1603 & ONENAND_CTRL_ONGO)
1604 continue;
1605
1606 /* Check lock status */
1607 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
1608 if (!(status & ONENAND_WP_US))
1609 printk(KERN_ERR "wp status = 0x%x\n", status);
1610
1611 return 0;
1612 }
1613
1614 /* Block lock scheme */
1615 for (block = start; block < end; block++) {
1616 /* Set start block address */
1617 this->write_word(block,
1618 this->base + ONENAND_REG_START_BLOCK_ADDRESS);
1619 /* Write unlock command */
1620 this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0);
1621
1622 /* There's no return value */
1623 this->wait(mtd, FL_UNLOCKING);
1624
1625 /* Sanity check */
1626 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
1627 & ONENAND_CTRL_ONGO)
1628 continue;
1629
1630 /* Set block address for read block status */
1631 value = onenand_block_address(this->device_id, block);
1632 this->write_word(value,
1633 this->base + ONENAND_REG_START_ADDRESS1);
1634
1635 /* Check lock status */
1636 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
1637 if (!(status & ONENAND_WP_US))
1638 printk(KERN_ERR "block = %d, wp status = 0x%x\n",
1639 block, status);
1640 }
1641
1642 return 0;
1643}
1644
1645/**
1646 * onenand_print_device_info - Print device ID
1647 * @param device device ID
1648 *
1649 * Print device ID
1650 */
Fathi BOUDRA195ccfc2008-08-06 10:06:20 +02001651char * onenand_print_device_info(int device)
Kyungmin Park916527f2007-09-10 17:13:49 +09001652{
1653 int vcc, demuxed, ddp, density;
Fathi BOUDRA195ccfc2008-08-06 10:06:20 +02001654 char *dev_info = malloc(80);
Kyungmin Park916527f2007-09-10 17:13:49 +09001655
1656 vcc = device & ONENAND_DEVICE_VCC_MASK;
1657 demuxed = device & ONENAND_DEVICE_IS_DEMUX;
1658 ddp = device & ONENAND_DEVICE_IS_DDP;
1659 density = device >> ONENAND_DEVICE_DENSITY_SHIFT;
Fathi BOUDRA195ccfc2008-08-06 10:06:20 +02001660 sprintf(dev_info, "%sOneNAND%s %dMB %sV 16-bit (0x%02x)",
Kyungmin Park916527f2007-09-10 17:13:49 +09001661 demuxed ? "" : "Muxed ",
1662 ddp ? "(DDP)" : "",
1663 (16 << density), vcc ? "2.65/3.3" : "1.8", device);
Fathi BOUDRA195ccfc2008-08-06 10:06:20 +02001664
1665 return dev_info;
Kyungmin Park916527f2007-09-10 17:13:49 +09001666}
1667
1668static const struct onenand_manufacturers onenand_manuf_ids[] = {
1669 {ONENAND_MFR_SAMSUNG, "Samsung"},
1670 {ONENAND_MFR_UNKNOWN, "Unknown"}
1671};
1672
1673/**
1674 * onenand_check_maf - Check manufacturer ID
1675 * @param manuf manufacturer ID
1676 *
1677 * Check manufacturer ID
1678 */
1679static int onenand_check_maf(int manuf)
1680{
1681 int i;
1682
1683 for (i = 0; onenand_manuf_ids[i].id; i++) {
1684 if (manuf == onenand_manuf_ids[i].id)
1685 break;
1686 }
1687
1688#ifdef ONENAND_DEBUG
1689 printk(KERN_DEBUG "OneNAND Manufacturer: %s (0x%0x)\n",
1690 onenand_manuf_ids[i].name, manuf);
1691#endif
1692
1693 return (i != ONENAND_MFR_UNKNOWN);
1694}
1695
1696/**
1697 * onenand_probe - [OneNAND Interface] Probe the OneNAND device
1698 * @param mtd MTD device structure
1699 *
1700 * OneNAND detection method:
1701 * Compare the the values from command with ones from register
1702 */
1703static int onenand_probe(struct mtd_info *mtd)
1704{
1705 struct onenand_chip *this = mtd->priv;
1706 int bram_maf_id, bram_dev_id, maf_id, dev_id;
1707 int version_id;
1708 int density;
1709
1710 /* Send the command for reading device ID from BootRAM */
1711 this->write_word(ONENAND_CMD_READID, this->base + ONENAND_BOOTRAM);
1712
1713 /* Read manufacturer and device IDs from BootRAM */
1714 bram_maf_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x0);
1715 bram_dev_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x2);
1716
1717 /* Check manufacturer ID */
1718 if (onenand_check_maf(bram_maf_id))
1719 return -ENXIO;
1720
1721 /* Reset OneNAND to read default register values */
1722 this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM);
1723
Kyungmin Parkd438d502008-08-13 09:11:02 +09001724 /* Wait reset */
1725 this->wait(mtd, FL_RESETING);
Kyungmin Park916527f2007-09-10 17:13:49 +09001726
1727 /* Read manufacturer and device IDs from Register */
1728 maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);
1729 dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
1730
1731 /* Check OneNAND device */
1732 if (maf_id != bram_maf_id || dev_id != bram_dev_id)
1733 return -ENXIO;
1734
Kyungmin Park1bb707c2008-03-17 08:54:06 +09001735 /* FIXME : Current OneNAND MTD doesn't support Flex-OneNAND */
1736 if (dev_id & (1 << 9)) {
1737 printk("Not yet support Flex-OneNAND\n");
1738 return -ENXIO;
1739 }
1740
Kyungmin Park916527f2007-09-10 17:13:49 +09001741 /* Flash device information */
Fathi BOUDRA195ccfc2008-08-06 10:06:20 +02001742 mtd->name = onenand_print_device_info(dev_id);
Kyungmin Park916527f2007-09-10 17:13:49 +09001743 this->device_id = dev_id;
1744
1745 density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
1746 this->chipsize = (16 << density) << 20;
1747
1748 /* OneNAND page size & block size */
1749 /* The data buffer size is equal to page size */
Kyungmin Parkd438d502008-08-13 09:11:02 +09001750 mtd->writesize =
Kyungmin Park916527f2007-09-10 17:13:49 +09001751 this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE);
Kyungmin Parkd438d502008-08-13 09:11:02 +09001752 mtd->oobsize = mtd->writesize >> 5;
Kyungmin Park916527f2007-09-10 17:13:49 +09001753 /* Pagers per block is always 64 in OneNAND */
Kyungmin Parkd438d502008-08-13 09:11:02 +09001754 mtd->erasesize = mtd->writesize << 6;
Kyungmin Park916527f2007-09-10 17:13:49 +09001755
1756 this->erase_shift = ffs(mtd->erasesize) - 1;
Kyungmin Parkd438d502008-08-13 09:11:02 +09001757 this->page_shift = ffs(mtd->writesize) - 1;
Kyungmin Park916527f2007-09-10 17:13:49 +09001758 this->ppb_shift = (this->erase_shift - this->page_shift);
Kyungmin Parkd438d502008-08-13 09:11:02 +09001759 this->page_mask = (mtd->erasesize / mtd->writesize) - 1;
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001760 /* It's real page size */
1761 this->writesize = mtd->writesize;
Kyungmin Park916527f2007-09-10 17:13:49 +09001762
1763 /* REVIST: Multichip handling */
1764
1765 mtd->size = this->chipsize;
1766
1767 /* Version ID */
1768 version_id = this->read_word(this->base + ONENAND_REG_VERSION_ID);
1769#ifdef ONENAND_DEBUG
1770 printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version_id);
1771#endif
1772
1773 /* Lock scheme */
1774 if (density <= ONENAND_DEVICE_DENSITY_512Mb &&
1775 !(version_id >> ONENAND_VERSION_PROCESS_SHIFT)) {
1776 printk(KERN_INFO "Lock scheme is Continues Lock\n");
1777 this->options |= ONENAND_CONT_LOCK;
1778 }
1779
Kyungmin Parkd438d502008-08-13 09:11:02 +09001780 mtd->flags = MTD_CAP_NANDFLASH;
Fathi BOUDRA195ccfc2008-08-06 10:06:20 +02001781 mtd->erase = onenand_erase;
1782 mtd->read = onenand_read;
1783 mtd->write = onenand_write;
Fathi BOUDRA195ccfc2008-08-06 10:06:20 +02001784 mtd->read_oob = onenand_read_oob;
1785 mtd->write_oob = onenand_write_oob;
1786 mtd->sync = onenand_sync;
1787 mtd->block_isbad = onenand_block_isbad;
1788 mtd->block_markbad = onenand_block_markbad;
1789
Kyungmin Park916527f2007-09-10 17:13:49 +09001790 return 0;
1791}
1792
1793/**
1794 * onenand_scan - [OneNAND Interface] Scan for the OneNAND device
1795 * @param mtd MTD device structure
1796 * @param maxchips Number of chips to scan for
1797 *
1798 * This fills out all the not initialized function pointers
1799 * with the defaults.
1800 * The flash ID is read and the mtd/chip structures are
1801 * filled with the appropriate values.
1802 */
1803int onenand_scan(struct mtd_info *mtd, int maxchips)
1804{
1805 struct onenand_chip *this = mtd->priv;
1806
1807 if (!this->read_word)
1808 this->read_word = onenand_readw;
1809 if (!this->write_word)
1810 this->write_word = onenand_writew;
1811
1812 if (!this->command)
1813 this->command = onenand_command;
1814 if (!this->wait)
1815 this->wait = onenand_wait;
1816
1817 if (!this->read_bufferram)
1818 this->read_bufferram = onenand_read_bufferram;
1819 if (!this->write_bufferram)
1820 this->write_bufferram = onenand_write_bufferram;
1821
1822 if (onenand_probe(mtd))
1823 return -ENXIO;
1824
1825 /* Set Sync. Burst Read after probing */
1826 if (this->mmcontrol) {
1827 printk(KERN_INFO "OneNAND Sync. Burst Read support\n");
1828 this->read_bufferram = onenand_sync_read_bufferram;
1829 }
1830
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001831 /* Allocate buffers, if necessary */
1832 if (!this->page_buf) {
1833 this->page_buf = kzalloc(mtd->writesize, GFP_KERNEL);
1834 if (!this->page_buf) {
1835 printk(KERN_ERR "onenand_scan(): Can't allocate page_buf\n");
1836 return -ENOMEM;
1837 }
1838 this->options |= ONENAND_PAGEBUF_ALLOC;
1839 }
1840 if (!this->oob_buf) {
1841 this->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
1842 if (!this->oob_buf) {
1843 printk(KERN_ERR "onenand_scan: Can't allocate oob_buf\n");
1844 if (this->options & ONENAND_PAGEBUF_ALLOC) {
1845 this->options &= ~ONENAND_PAGEBUF_ALLOC;
1846 kfree(this->page_buf);
1847 }
1848 return -ENOMEM;
1849 }
1850 this->options |= ONENAND_OOBBUF_ALLOC;
1851 }
1852
Kyungmin Park916527f2007-09-10 17:13:49 +09001853 onenand_unlock(mtd, 0, mtd->size);
1854
1855 return onenand_default_bbt(mtd);
1856}
1857
1858/**
1859 * onenand_release - [OneNAND Interface] Free resources held by the OneNAND device
1860 * @param mtd MTD device structure
1861 */
1862void onenand_release(struct mtd_info *mtd)
1863{
1864}