blob: 66214e86d3c2f9671ccf298f4652363dee03535f [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 */
Kyungmin Parkef0921d2008-11-04 09:24:07 +090081static int onenand_block_address(struct onenand_chip *this, int block)
Kyungmin Park916527f2007-09-10 17:13:49 +090082{
Kyungmin Parkef0921d2008-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 Park916527f2007-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 Parkef0921d2008-11-04 09:24:07 +090098static int onenand_bufferram_address(struct onenand_chip *this, int block)
Kyungmin Park916527f2007-09-10 17:13:49 +090099{
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900100 /* Device BufferRAM Select */
101 if (block & this->density_mask)
102 return ONENAND_DDP_CHIP1;
Kyungmin Park916527f2007-09-10 17:13:49 +0900103
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900104 return ONENAND_DDP_CHIP0;
Kyungmin Park916527f2007-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 Parkef0921d2008-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 Park916527f2007-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 Parkef0921d2008-11-04 09:24:07 +0900189 case ONENAND_CMD_UNLOCK_ALL:
Kyungmin Park916527f2007-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 Parkef0921d2008-11-04 09:24:07 +0900210 value = onenand_bufferram_address(this, block);
Kyungmin Park916527f2007-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 Parkef0921d2008-11-04 09:24:07 +0900222 value = onenand_block_address(this, block);
Kyungmin Park916527f2007-09-10 17:13:49 +0900223 this->write_word(value,
224 this->base + ONENAND_REG_START_ADDRESS1);
Kyungmin Parkef0921d2008-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 Park916527f2007-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 Park916527f2007-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 Parkef0921d2008-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 Park916527f2007-09-10 17:13:49 +0900294
Kyungmin Park916527f2007-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 Wood3167c532008-06-20 12:38:57 -0500301 MTDDEBUG (MTD_DEBUG_LEVEL0,
Wolfgang Denk4b070802008-08-14 14:41:06 +0200302 "onenand_wait: ECC error = 0x%04x\n", ecc);
Kyungmin Park916527f2007-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 Parkd438d502008-08-13 09:11:02 +0900324 return mtd->writesize;
Kyungmin Park916527f2007-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 Parkef0921d2008-11-04 09:24:07 +0900342static int onenand_read_bufferram(struct mtd_info *mtd, loff_t addr, int area,
Kyungmin Park916527f2007-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 Denkd2c6fbe2008-05-01 21:30:16 +0200352 memcpy_16(buffer, bufferram + offset, count);
Kyungmin Park916527f2007-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 Parkef0921d2008-11-04 09:24:07 +0900367static int onenand_sync_read_bufferram(struct mtd_info *mtd, loff_t addr, int area,
Kyungmin Park916527f2007-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 Denkd2c6fbe2008-05-01 21:30:16 +0200379 memcpy_16(buffer, bufferram + offset, count);
Kyungmin Park916527f2007-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 Parkef0921d2008-11-04 09:24:07 +0900396static int onenand_write_bufferram(struct mtd_info *mtd, loff_t addr, int area,
Kyungmin Park916527f2007-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 Denkd2c6fbe2008-05-01 21:30:16 +0200406 memcpy_16(bufferram + offset, buffer, count);
Kyungmin Park916527f2007-09-10 17:13:49 +0900407
408 return 0;
409}
410
411/**
412 * onenand_check_bufferram - [GENERIC] Check BufferRAM information
413 * @param mtd MTD data structure
414 * @param addr address to check
415 * @return 1 if there are valid data, otherwise 0
416 *
417 * Check bufferram if there is data we required
418 */
419static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr)
420{
421 struct onenand_chip *this = mtd->priv;
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900422 int blockpage, found = 0;
423 unsigned int i;
Kyungmin Park916527f2007-09-10 17:13:49 +0900424
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900425#ifdef CONFIG_S3C64XX
426 return 0;
427#endif
Kyungmin Park916527f2007-09-10 17:13:49 +0900428
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900429 if (ONENAND_IS_2PLANE(this))
430 blockpage = onenand_get_2x_blockpage(mtd, addr);
431 else
432 blockpage = (int) (addr >> this->page_shift);
Kyungmin Park916527f2007-09-10 17:13:49 +0900433
434 /* Is there valid data? */
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900435 i = ONENAND_CURRENT_BUFFERRAM(this);
436 if (this->bufferram[i].blockpage == blockpage)
437 found = 1;
438 else {
439 /* Check another BufferRAM */
440 i = ONENAND_NEXT_BUFFERRAM(this);
441 if (this->bufferram[i].blockpage == blockpage) {
442 ONENAND_SET_NEXT_BUFFERRAM(this);
443 found = 1;
444 }
445 }
Kyungmin Park916527f2007-09-10 17:13:49 +0900446
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900447 if (found && ONENAND_IS_DDP(this)) {
448 /* Select DataRAM for DDP */
449 int block = (int) (addr >> this->erase_shift);
450 int value = onenand_bufferram_address(this, block);
451 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
452 }
453
454 return found;
Kyungmin Park916527f2007-09-10 17:13:49 +0900455}
456
457/**
458 * onenand_update_bufferram - [GENERIC] Update BufferRAM information
459 * @param mtd MTD data structure
460 * @param addr address to update
461 * @param valid valid flag
462 *
463 * Update BufferRAM information
464 */
465static int onenand_update_bufferram(struct mtd_info *mtd, loff_t addr,
466 int valid)
467{
468 struct onenand_chip *this = mtd->priv;
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900469 int blockpage;
470 unsigned int i;
Kyungmin Park916527f2007-09-10 17:13:49 +0900471
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900472 if (ONENAND_IS_2PLANE(this))
473 blockpage = onenand_get_2x_blockpage(mtd, addr);
474 else
475 blockpage = (int)(addr >> this->page_shift);
Kyungmin Park916527f2007-09-10 17:13:49 +0900476
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900477 /* Invalidate another BufferRAM */
478 i = ONENAND_NEXT_BUFFERRAM(this);
479 if (this->bufferram[i].blockpage == blockpage)
480 this->bufferram[i].blockpage = -1;
Kyungmin Park916527f2007-09-10 17:13:49 +0900481
482 /* Update BufferRAM */
483 i = ONENAND_CURRENT_BUFFERRAM(this);
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900484 if (valid)
485 this->bufferram[i].blockpage = blockpage;
486 else
487 this->bufferram[i].blockpage = -1;
Kyungmin Park916527f2007-09-10 17:13:49 +0900488
489 return 0;
490}
491
492/**
Kyungmin Parkd438d502008-08-13 09:11:02 +0900493 * onenand_invalidate_bufferram - [GENERIC] Invalidate BufferRAM information
494 * @param mtd MTD data structure
495 * @param addr start address to invalidate
496 * @param len length to invalidate
497 *
498 * Invalidate BufferRAM information
499 */
500static void onenand_invalidate_bufferram(struct mtd_info *mtd, loff_t addr,
Wolfgang Denk4b070802008-08-14 14:41:06 +0200501 unsigned int len)
Kyungmin Parkd438d502008-08-13 09:11:02 +0900502{
503 struct onenand_chip *this = mtd->priv;
504 int i;
505 loff_t end_addr = addr + len;
506
507 /* Invalidate BufferRAM */
508 for (i = 0; i < MAX_BUFFERRAM; i++) {
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900509 loff_t buf_addr = this->bufferram[i].blockpage << this->page_shift;
Kyungmin Parkd438d502008-08-13 09:11:02 +0900510
511 if (buf_addr >= addr && buf_addr < end_addr)
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900512 this->bufferram[i].blockpage = -1;
Kyungmin Parkd438d502008-08-13 09:11:02 +0900513 }
514}
515
516/**
Kyungmin Park916527f2007-09-10 17:13:49 +0900517 * onenand_get_device - [GENERIC] Get chip for selected access
518 * @param mtd MTD device structure
519 * @param new_state the state which is requested
520 *
521 * Get the device and lock it for exclusive access
522 */
523static void onenand_get_device(struct mtd_info *mtd, int new_state)
524{
525 /* Do nothing */
526}
527
528/**
529 * onenand_release_device - [GENERIC] release chip
530 * @param mtd MTD device structure
531 *
532 * Deselect, release chip lock and wake up anyone waiting on the device
533 */
534static void onenand_release_device(struct mtd_info *mtd)
535{
536 /* Do nothing */
537}
538
539/**
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900540 * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer
Kyungmin Park916527f2007-09-10 17:13:49 +0900541 * @param mtd MTD device structure
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900542 * @param buf destination address
543 * @param column oob offset to read from
544 * @param thislen oob length to read
Kyungmin Park916527f2007-09-10 17:13:49 +0900545 */
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900546static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf,
547 int column, int thislen)
Kyungmin Park916527f2007-09-10 17:13:49 +0900548{
549 struct onenand_chip *this = mtd->priv;
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900550 struct nand_oobfree *free;
551 int readcol = column;
552 int readend = column + thislen;
553 int lastgap = 0;
554 unsigned int i;
555 uint8_t *oob_buf = this->oob_buf;
Kyungmin Park916527f2007-09-10 17:13:49 +0900556
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900557 free = this->ecclayout->oobfree;
558 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
559 if (readcol >= lastgap)
560 readcol += free->offset - lastgap;
561 if (readend >= lastgap)
562 readend += free->offset - lastgap;
563 lastgap = free->offset + free->length;
564 }
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900565 this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900566 free = this->ecclayout->oobfree;
567 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
568 int free_end = free->offset + free->length;
569 if (free->offset < readend && free_end > readcol) {
570 int st = max_t(int,free->offset,readcol);
571 int ed = min_t(int,free_end,readend);
572 int n = ed - st;
573 memcpy(buf, oob_buf + st, n);
574 buf += n;
575 } else if (column == 0)
576 break;
577 }
578 return 0;
579}
580
581/**
582 * onenand_read_ops_nolock - [OneNAND Interface] OneNAND read main and/or out-of-band
583 * @param mtd MTD device structure
584 * @param from offset to read from
585 * @param ops oob operation description structure
586 *
587 * OneNAND read main and/or out-of-band data
588 */
589static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
590 struct mtd_oob_ops *ops)
591{
592 struct onenand_chip *this = mtd->priv;
593 struct mtd_ecc_stats stats;
594 size_t len = ops->len;
595 size_t ooblen = ops->ooblen;
596 u_char *buf = ops->datbuf;
597 u_char *oobbuf = ops->oobbuf;
598 int read = 0, column, thislen;
599 int oobread = 0, oobcolumn, thisooblen, oobsize;
600 int ret = 0, boundary = 0;
601 int writesize = this->writesize;
602
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900603 MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ops_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900604
605 if (ops->mode == MTD_OOB_AUTO)
606 oobsize = this->ecclayout->oobavail;
607 else
608 oobsize = mtd->oobsize;
609
610 oobcolumn = from & (mtd->oobsize - 1);
Kyungmin Park916527f2007-09-10 17:13:49 +0900611
612 /* Do not allow reads past end of device */
613 if ((from + len) > mtd->size) {
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900614 printk(KERN_ERR "onenand_read_ops_nolock: Attempt read beyond end of device\n");
615 ops->retlen = 0;
616 ops->oobretlen = 0;
Kyungmin Park916527f2007-09-10 17:13:49 +0900617 return -EINVAL;
618 }
619
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900620 stats = mtd->ecc_stats;
Kyungmin Park916527f2007-09-10 17:13:49 +0900621
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900622 /* Read-while-load method */
Kyungmin Park916527f2007-09-10 17:13:49 +0900623
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900624 /* Do first load to bufferRAM */
625 if (read < len) {
Kyungmin Park916527f2007-09-10 17:13:49 +0900626 if (!onenand_check_bufferram(mtd, from)) {
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900627 this->main_buf = buf;
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900628 this->command(mtd, ONENAND_CMD_READ, from, writesize);
Kyungmin Park916527f2007-09-10 17:13:49 +0900629 ret = this->wait(mtd, FL_READING);
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900630 onenand_update_bufferram(mtd, from, !ret);
631 if (ret == -EBADMSG)
632 ret = 0;
633 }
634 }
635
636 thislen = min_t(int, writesize, len - read);
637 column = from & (writesize - 1);
638 if (column + thislen > writesize)
639 thislen = writesize - column;
640
641 while (!ret) {
642 /* If there is more to load then start next load */
643 from += thislen;
644 if (read + thislen < len) {
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900645 this->main_buf = buf + thislen;
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900646 this->command(mtd, ONENAND_CMD_READ, from, writesize);
647 /*
648 * Chip boundary handling in DDP
649 * Now we issued chip 1 read and pointed chip 1
650 * bufferam so we have to point chip 0 bufferam.
651 */
652 if (ONENAND_IS_DDP(this) &&
653 unlikely(from == (this->chipsize >> 1))) {
654 this->write_word(ONENAND_DDP_CHIP0, this->base + ONENAND_REG_START_ADDRESS2);
655 boundary = 1;
656 } else
657 boundary = 0;
658 ONENAND_SET_PREV_BUFFERRAM(this);
Kyungmin Park916527f2007-09-10 17:13:49 +0900659 }
660
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900661 /* While load is going, read from last bufferRAM */
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900662 this->read_bufferram(mtd, from - thislen, ONENAND_DATARAM, buf, column, thislen);
Kyungmin Park916527f2007-09-10 17:13:49 +0900663
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900664 /* Read oob area if needed */
665 if (oobbuf) {
666 thisooblen = oobsize - oobcolumn;
667 thisooblen = min_t(int, thisooblen, ooblen - oobread);
668
669 if (ops->mode == MTD_OOB_AUTO)
670 onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);
671 else
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900672 this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen);
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900673 oobread += thisooblen;
674 oobbuf += thisooblen;
675 oobcolumn = 0;
676 }
677
678 /* See if we are done */
Kyungmin Park916527f2007-09-10 17:13:49 +0900679 read += thislen;
680 if (read == len)
681 break;
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900682 /* Set up for next read from bufferRAM */
683 if (unlikely(boundary))
684 this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);
685 ONENAND_SET_NEXT_BUFFERRAM(this);
Kyungmin Park916527f2007-09-10 17:13:49 +0900686 buf += thislen;
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900687 thislen = min_t(int, writesize, len - read);
688 column = 0;
Kyungmin Park916527f2007-09-10 17:13:49 +0900689
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900690 /* Now wait for load */
691 ret = this->wait(mtd, FL_READING);
692 onenand_update_bufferram(mtd, from, !ret);
693 if (ret == -EBADMSG)
694 ret = 0;
695 }
Kyungmin Park916527f2007-09-10 17:13:49 +0900696
697 /*
698 * Return success, if no ECC failures, else -EBADMSG
699 * fs driver will take care of that, because
700 * retlen == desired len and result == -EBADMSG
701 */
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900702 ops->retlen = read;
703 ops->oobretlen = oobread;
704
705 if (ret)
706 return ret;
707
708 if (mtd->ecc_stats.failed - stats.failed)
709 return -EBADMSG;
710
711 return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
712}
713
714/**
715 * onenand_read_oob_nolock - [MTD Interface] OneNAND read out-of-band
716 * @param mtd MTD device structure
717 * @param from offset to read from
718 * @param ops oob operation description structure
719 *
720 * OneNAND read out-of-band data from the spare area
721 */
722static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
723 struct mtd_oob_ops *ops)
724{
725 struct onenand_chip *this = mtd->priv;
726 struct mtd_ecc_stats stats;
727 int read = 0, thislen, column, oobsize;
728 size_t len = ops->ooblen;
729 mtd_oob_mode_t mode = ops->mode;
730 u_char *buf = ops->oobbuf;
731 int ret = 0;
732
733 from += ops->ooboffs;
734
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900735 MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900736
737 /* Initialize return length value */
738 ops->oobretlen = 0;
739
740 if (mode == MTD_OOB_AUTO)
741 oobsize = this->ecclayout->oobavail;
742 else
743 oobsize = mtd->oobsize;
744
745 column = from & (mtd->oobsize - 1);
746
747 if (unlikely(column >= oobsize)) {
748 printk(KERN_ERR "onenand_read_oob_nolock: Attempted to start read outside oob\n");
749 return -EINVAL;
750 }
751
752 /* Do not allow reads past end of device */
753 if (unlikely(from >= mtd->size ||
754 column + len > ((mtd->size >> this->page_shift) -
755 (from >> this->page_shift)) * oobsize)) {
756 printk(KERN_ERR "onenand_read_oob_nolock: Attempted to read beyond end of device\n");
757 return -EINVAL;
758 }
759
760 stats = mtd->ecc_stats;
761
762 while (read < len) {
763 thislen = oobsize - column;
764 thislen = min_t(int, thislen, len);
765
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900766 this->spare_buf = buf;
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900767 this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);
768
769 onenand_update_bufferram(mtd, from, 0);
770
771 ret = this->wait(mtd, FL_READING);
772 if (ret && ret != -EBADMSG) {
773 printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret);
774 break;
775 }
776
777 if (mode == MTD_OOB_AUTO)
778 onenand_transfer_auto_oob(mtd, buf, column, thislen);
779 else
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900780 this->read_bufferram(mtd, 0, ONENAND_SPARERAM, buf, column, thislen);
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900781
782 read += thislen;
783
784 if (read == len)
785 break;
786
787 buf += thislen;
788
789 /* Read more? */
790 if (read < len) {
791 /* Page size */
792 from += mtd->writesize;
793 column = 0;
794 }
795 }
796
797 ops->oobretlen = read;
798
799 if (ret)
800 return ret;
801
802 if (mtd->ecc_stats.failed - stats.failed)
803 return -EBADMSG;
804
805 return 0;
Kyungmin Park916527f2007-09-10 17:13:49 +0900806}
807
808/**
809 * onenand_read - [MTD Interface] MTD compability function for onenand_read_ecc
810 * @param mtd MTD device structure
811 * @param from offset to read from
812 * @param len number of bytes to read
813 * @param retlen pointer to variable to store the number of read bytes
814 * @param buf the databuffer to put data
815 *
816 * This function simply calls onenand_read_ecc with oob buffer and oobsel = NULL
817*/
818int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
819 size_t * retlen, u_char * buf)
820{
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900821 struct mtd_oob_ops ops = {
822 .len = len,
823 .ooblen = 0,
824 .datbuf = buf,
825 .oobbuf = NULL,
826 };
827 int ret;
828
829 onenand_get_device(mtd, FL_READING);
830 ret = onenand_read_ops_nolock(mtd, from, &ops);
831 onenand_release_device(mtd);
832
833 *retlen = ops.retlen;
834 return ret;
Kyungmin Park916527f2007-09-10 17:13:49 +0900835}
836
837/**
838 * onenand_read_oob - [MTD Interface] OneNAND read out-of-band
839 * @param mtd MTD device structure
840 * @param from offset to read from
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900841 * @param ops oob operations description structure
Kyungmin Park916527f2007-09-10 17:13:49 +0900842 *
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900843 * OneNAND main and/or out-of-band
Kyungmin Park916527f2007-09-10 17:13:49 +0900844 */
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900845int onenand_read_oob(struct mtd_info *mtd, loff_t from,
846 struct mtd_oob_ops *ops)
847{
848 int ret;
849
850 switch (ops->mode) {
851 case MTD_OOB_PLACE:
852 case MTD_OOB_AUTO:
853 break;
854 case MTD_OOB_RAW:
855 /* Not implemented yet */
856 default:
857 return -EINVAL;
858 }
859
860 onenand_get_device(mtd, FL_READING);
861 if (ops->datbuf)
862 ret = onenand_read_ops_nolock(mtd, from, ops);
863 else
864 ret = onenand_read_oob_nolock(mtd, from, ops);
865 onenand_release_device(mtd);
866
867 return ret;
868}
869
870/**
871 * onenand_bbt_wait - [DEFAULT] wait until the command is done
872 * @param mtd MTD device structure
873 * @param state state to select the max. timeout value
874 *
875 * Wait for command done.
876 */
877static int onenand_bbt_wait(struct mtd_info *mtd, int state)
878{
879 struct onenand_chip *this = mtd->priv;
880 unsigned int flags = ONENAND_INT_MASTER;
881 unsigned int interrupt;
882 unsigned int ctrl;
883
884 while (1) {
885 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
886 if (interrupt & flags)
887 break;
888 }
889
890 /* To get correct interrupt status in timeout case */
891 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
892 ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
893
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900894 if (interrupt & ONENAND_INT_READ) {
895 int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
896 if (ecc & ONENAND_ECC_2BIT_ALL)
897 return ONENAND_BBT_READ_ERROR;
898 } else {
899 printk(KERN_ERR "onenand_bbt_wait: read timeout!"
900 "ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt);
901 return ONENAND_BBT_READ_FATAL_ERROR;
902 }
903
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900904 /* Initial bad block case: 0x2400 or 0x0400 */
905 if (ctrl & ONENAND_CTRL_ERROR) {
906 printk(KERN_DEBUG "onenand_bbt_wait: controller error = 0x%04x\n", ctrl);
907 return ONENAND_BBT_READ_ERROR;
908 }
909
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900910 return 0;
911}
912
913/**
914 * onenand_bbt_read_oob - [MTD Interface] OneNAND read out-of-band for bbt scan
915 * @param mtd MTD device structure
916 * @param from offset to read from
917 * @param ops oob operation description structure
918 *
919 * OneNAND read out-of-band data from the spare area for bbt scan
920 */
921int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
922 struct mtd_oob_ops *ops)
Kyungmin Park916527f2007-09-10 17:13:49 +0900923{
924 struct onenand_chip *this = mtd->priv;
925 int read = 0, thislen, column;
926 int ret = 0;
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900927 size_t len = ops->ooblen;
928 u_char *buf = ops->oobbuf;
Kyungmin Park916527f2007-09-10 17:13:49 +0900929
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900930 MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_bbt_read_oob: from = 0x%08x, len = %zi\n", (unsigned int) from, len);
Kyungmin Park916527f2007-09-10 17:13:49 +0900931
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900932 /* Initialize return value */
933 ops->oobretlen = 0;
Kyungmin Park916527f2007-09-10 17:13:49 +0900934
935 /* Do not allow reads past end of device */
936 if (unlikely((from + len) > mtd->size)) {
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900937 printk(KERN_ERR "onenand_bbt_read_oob: Attempt read beyond end of device\n");
938 return ONENAND_BBT_READ_FATAL_ERROR;
Kyungmin Park916527f2007-09-10 17:13:49 +0900939 }
940
941 /* Grab the lock and see if the device is available */
942 onenand_get_device(mtd, FL_READING);
943
944 column = from & (mtd->oobsize - 1);
945
946 while (read < len) {
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900947
Kyungmin Park916527f2007-09-10 17:13:49 +0900948 thislen = mtd->oobsize - column;
949 thislen = min_t(int, thislen, len);
950
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900951 this->spare_buf = buf;
Kyungmin Park916527f2007-09-10 17:13:49 +0900952 this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);
953
954 onenand_update_bufferram(mtd, from, 0);
955
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900956 ret = this->bbt_wait(mtd, FL_READING);
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900957 if (ret)
958 break;
Kyungmin Park916527f2007-09-10 17:13:49 +0900959
Kyungmin Parkef0921d2008-11-04 09:24:07 +0900960 this->read_spareram(mtd, 0, ONENAND_SPARERAM, buf, column, thislen);
Kyungmin Park916527f2007-09-10 17:13:49 +0900961 read += thislen;
962 if (read == len)
963 break;
964
Kyungmin Park916527f2007-09-10 17:13:49 +0900965 buf += thislen;
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900966
Kyungmin Park916527f2007-09-10 17:13:49 +0900967 /* Read more? */
968 if (read < len) {
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900969 /* Update Page size */
970 from += this->writesize;
Kyungmin Park916527f2007-09-10 17:13:49 +0900971 column = 0;
972 }
973 }
974
975 /* Deselect and wake up anyone waiting on the device */
976 onenand_release_device(mtd);
977
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900978 ops->oobretlen = read;
Kyungmin Park916527f2007-09-10 17:13:49 +0900979 return ret;
980}
981
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900982
Kyungmin Park916527f2007-09-10 17:13:49 +0900983#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
984/**
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900985 * onenand_verify_oob - [GENERIC] verify the oob contents after a write
986 * @param mtd MTD device structure
987 * @param buf the databuffer to verify
988 * @param to offset to read from
Kyungmin Park916527f2007-09-10 17:13:49 +0900989 */
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900990static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to)
Kyungmin Park916527f2007-09-10 17:13:49 +0900991{
992 struct onenand_chip *this = mtd->priv;
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900993 u_char *oob_buf = this->oob_buf;
994 int status, i;
995
996 this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize);
997 onenand_update_bufferram(mtd, to, 0);
998 status = this->wait(mtd, FL_READING);
999 if (status)
1000 return status;
1001
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001002 this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001003 for (i = 0; i < mtd->oobsize; i++)
1004 if (buf[i] != 0xFF && buf[i] != oob_buf[i])
1005 return -EBADMSG;
1006
1007 return 0;
1008}
1009
1010/**
1011 * onenand_verify - [GENERIC] verify the chip contents after a write
1012 * @param mtd MTD device structure
1013 * @param buf the databuffer to verify
1014 * @param addr offset to read from
1015 * @param len number of bytes to read and compare
1016 */
1017static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, size_t len)
1018{
1019 struct onenand_chip *this = mtd->priv;
1020 void __iomem *dataram;
Kyungmin Park916527f2007-09-10 17:13:49 +09001021 int ret = 0;
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001022 int thislen, column;
Kyungmin Park916527f2007-09-10 17:13:49 +09001023
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001024 while (len != 0) {
1025 thislen = min_t(int, this->writesize, len);
1026 column = addr & (this->writesize - 1);
1027 if (column + thislen > this->writesize)
1028 thislen = this->writesize - column;
Kyungmin Park916527f2007-09-10 17:13:49 +09001029
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001030 this->command(mtd, ONENAND_CMD_READ, addr, this->writesize);
Kyungmin Park916527f2007-09-10 17:13:49 +09001031
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001032 onenand_update_bufferram(mtd, addr, 0);
Kyungmin Park916527f2007-09-10 17:13:49 +09001033
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001034 ret = this->wait(mtd, FL_READING);
1035 if (ret)
1036 return ret;
Kyungmin Park916527f2007-09-10 17:13:49 +09001037
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001038 onenand_update_bufferram(mtd, addr, 1);
1039
1040 dataram = this->base + ONENAND_DATARAM;
1041 dataram += onenand_bufferram_offset(mtd, ONENAND_DATARAM);
1042
1043 if (memcmp(buf, dataram + column, thislen))
1044 return -EBADMSG;
1045
1046 len -= thislen;
1047 buf += thislen;
1048 addr += thislen;
1049 }
Kyungmin Park916527f2007-09-10 17:13:49 +09001050
1051 return 0;
1052}
1053#else
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001054#define onenand_verify(...) (0)
1055#define onenand_verify_oob(...) (0)
Kyungmin Park916527f2007-09-10 17:13:49 +09001056#endif
1057
Kyungmin Parkd438d502008-08-13 09:11:02 +09001058#define NOTALIGNED(x) ((x & (mtd->writesize - 1)) != 0)
Kyungmin Park916527f2007-09-10 17:13:49 +09001059
1060/**
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001061 * onenand_fill_auto_oob - [Internal] oob auto-placement transfer
1062 * @param mtd MTD device structure
1063 * @param oob_buf oob buffer
1064 * @param buf source address
1065 * @param column oob offset to write to
1066 * @param thislen oob length to write
Kyungmin Park916527f2007-09-10 17:13:49 +09001067 */
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001068static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
1069 const u_char *buf, int column, int thislen)
Kyungmin Park916527f2007-09-10 17:13:49 +09001070{
1071 struct onenand_chip *this = mtd->priv;
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001072 struct nand_oobfree *free;
1073 int writecol = column;
1074 int writeend = column + thislen;
1075 int lastgap = 0;
1076 unsigned int i;
1077
1078 free = this->ecclayout->oobfree;
1079 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
1080 if (writecol >= lastgap)
1081 writecol += free->offset - lastgap;
1082 if (writeend >= lastgap)
1083 writeend += free->offset - lastgap;
1084 lastgap = free->offset + free->length;
1085 }
1086 free = this->ecclayout->oobfree;
1087 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
1088 int free_end = free->offset + free->length;
1089 if (free->offset < writeend && free_end > writecol) {
1090 int st = max_t(int,free->offset,writecol);
1091 int ed = min_t(int,free_end,writeend);
1092 int n = ed - st;
1093 memcpy(oob_buf + st, buf, n);
1094 buf += n;
1095 } else if (column == 0)
1096 break;
1097 }
1098 return 0;
1099}
1100
1101/**
1102 * onenand_write_ops_nolock - [OneNAND Interface] write main and/or out-of-band
1103 * @param mtd MTD device structure
1104 * @param to offset to write to
1105 * @param ops oob operation description structure
1106 *
1107 * Write main and/or oob with ECC
1108 */
1109static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
1110 struct mtd_oob_ops *ops)
1111{
1112 struct onenand_chip *this = mtd->priv;
1113 int written = 0, column, thislen, subpage;
1114 int oobwritten = 0, oobcolumn, thisooblen, oobsize;
1115 size_t len = ops->len;
1116 size_t ooblen = ops->ooblen;
1117 const u_char *buf = ops->datbuf;
1118 const u_char *oob = ops->oobbuf;
1119 u_char *oobbuf;
Kyungmin Park916527f2007-09-10 17:13:49 +09001120 int ret = 0;
1121
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001122 MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ops_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
Kyungmin Park916527f2007-09-10 17:13:49 +09001123
1124 /* Initialize retlen, in case of early exit */
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001125 ops->retlen = 0;
1126 ops->oobretlen = 0;
Kyungmin Park916527f2007-09-10 17:13:49 +09001127
1128 /* Do not allow writes past end of device */
1129 if (unlikely((to + len) > mtd->size)) {
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001130 printk(KERN_ERR "onenand_write_ops_nolock: Attempt write to past end of device\n");
Kyungmin Park916527f2007-09-10 17:13:49 +09001131 return -EINVAL;
1132 }
1133
1134 /* Reject writes, which are not page aligned */
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001135 if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
1136 printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n");
Kyungmin Park916527f2007-09-10 17:13:49 +09001137 return -EINVAL;
1138 }
1139
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001140 if (ops->mode == MTD_OOB_AUTO)
1141 oobsize = this->ecclayout->oobavail;
1142 else
1143 oobsize = mtd->oobsize;
1144
1145 oobcolumn = to & (mtd->oobsize - 1);
1146
1147 column = to & (mtd->writesize - 1);
Kyungmin Park916527f2007-09-10 17:13:49 +09001148
1149 /* Loop until all data write */
1150 while (written < len) {
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001151 u_char *wbuf = (u_char *) buf;
Kyungmin Park916527f2007-09-10 17:13:49 +09001152
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001153 thislen = min_t(int, mtd->writesize - column, len - written);
1154 thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten);
Kyungmin Park916527f2007-09-10 17:13:49 +09001155
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001156 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
1157
1158 /* Partial page write */
1159 subpage = thislen < mtd->writesize;
1160 if (subpage) {
1161 memset(this->page_buf, 0xff, mtd->writesize);
1162 memcpy(this->page_buf + column, buf, thislen);
1163 wbuf = this->page_buf;
1164 }
1165
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001166 this->write_bufferram(mtd, to, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001167
1168 if (oob) {
1169 oobbuf = this->oob_buf;
1170
1171 /* We send data to spare ram with oobsize
1172 * * to prevent byte access */
1173 memset(oobbuf, 0xff, mtd->oobsize);
1174 if (ops->mode == MTD_OOB_AUTO)
1175 onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
1176 else
1177 memcpy(oobbuf + oobcolumn, oob, thisooblen);
1178
1179 oobwritten += thisooblen;
1180 oob += thisooblen;
1181 oobcolumn = 0;
1182 } else
1183 oobbuf = (u_char *) ffchars;
1184
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001185 this->write_bufferram(mtd, 0, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
Kyungmin Park916527f2007-09-10 17:13:49 +09001186
Kyungmin Parkd438d502008-08-13 09:11:02 +09001187 this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
Kyungmin Park916527f2007-09-10 17:13:49 +09001188
Kyungmin Park916527f2007-09-10 17:13:49 +09001189 ret = this->wait(mtd, FL_WRITING);
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001190
1191 /* In partial page write we don't update bufferram */
1192 onenand_update_bufferram(mtd, to, !ret && !subpage);
1193 if (ONENAND_IS_2PLANE(this)) {
1194 ONENAND_SET_BUFFERRAM1(this);
1195 onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage);
1196 }
1197
Kyungmin Park916527f2007-09-10 17:13:49 +09001198 if (ret) {
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001199 printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
1200 break;
1201 }
1202
1203 /* Only check verify write turn on */
1204 ret = onenand_verify(mtd, buf, to, thislen);
1205 if (ret) {
1206 printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
Kyungmin Park916527f2007-09-10 17:13:49 +09001207 break;
1208 }
1209
1210 written += thislen;
1211
Kyungmin Park916527f2007-09-10 17:13:49 +09001212 if (written == len)
1213 break;
1214
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001215 column = 0;
Kyungmin Park916527f2007-09-10 17:13:49 +09001216 to += thislen;
1217 buf += thislen;
1218 }
1219
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001220 ops->retlen = written;
Kyungmin Park916527f2007-09-10 17:13:49 +09001221
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001222 return ret;
1223}
1224
1225/**
1226 * onenand_write_oob_nolock - [Internal] OneNAND write out-of-band
1227 * @param mtd MTD device structure
1228 * @param to offset to write to
1229 * @param len number of bytes to write
1230 * @param retlen pointer to variable to store the number of written bytes
1231 * @param buf the data to write
1232 * @param mode operation mode
1233 *
1234 * OneNAND write out-of-band
1235 */
1236static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
1237 struct mtd_oob_ops *ops)
1238{
1239 struct onenand_chip *this = mtd->priv;
1240 int column, ret = 0, oobsize;
1241 int written = 0;
1242 u_char *oobbuf;
1243 size_t len = ops->ooblen;
1244 const u_char *buf = ops->oobbuf;
1245 mtd_oob_mode_t mode = ops->mode;
1246
1247 to += ops->ooboffs;
1248
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001249 MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001250
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);
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001296 this->write_bufferram(mtd, 0, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001297
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",
Scott Woodc45912d2008-10-24 16:20:43 -05001431 (unsigned int)instr->addr, (unsigned int)instr->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
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001469 /* Check if we have a bad block, we do not erase bad blocks */
1470 if (instr->priv == 0 && onenand_block_isbad_nolock(mtd, addr, 0)) {
1471 printk(KERN_WARNING "onenand_erase: attempt to erase"
1472 " a bad block at addr 0x%08x\n",
1473 (unsigned int) addr);
1474 instr->state = MTD_ERASE_FAILED;
1475 goto erase_exit;
1476 }
Kyungmin Park916527f2007-09-10 17:13:49 +09001477
1478 this->command(mtd, ONENAND_CMD_ERASE, addr, block_size);
1479
Kyungmin Parkd438d502008-08-13 09:11:02 +09001480 onenand_invalidate_bufferram(mtd, addr, block_size);
1481
Kyungmin Park916527f2007-09-10 17:13:49 +09001482 ret = this->wait(mtd, FL_ERASING);
1483 /* Check, if it is write protected */
1484 if (ret) {
1485 if (ret == -EPERM)
Scott Wood3167c532008-06-20 12:38:57 -05001486 MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: "
Wolfgang Denk4b070802008-08-14 14:41:06 +02001487 "Device is write protected!!!\n");
Kyungmin Park916527f2007-09-10 17:13:49 +09001488 else
Scott Wood3167c532008-06-20 12:38:57 -05001489 MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: "
Wolfgang Denk4b070802008-08-14 14:41:06 +02001490 "Failed erase, block %d\n",
1491 (unsigned)(addr >> this->erase_shift));
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001492 if (ret == -EPERM)
1493 printk("onenand_erase: "
1494 "Device is write protected!!!\n");
1495 else
1496 printk("onenand_erase: "
1497 "Failed erase, block %d\n",
1498 (unsigned)(addr >> this->erase_shift));
Kyungmin Park916527f2007-09-10 17:13:49 +09001499 instr->state = MTD_ERASE_FAILED;
1500 instr->fail_addr = addr;
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001501
Kyungmin Park916527f2007-09-10 17:13:49 +09001502 goto erase_exit;
1503 }
1504
1505 len -= block_size;
1506 addr += block_size;
1507 }
1508
1509 instr->state = MTD_ERASE_DONE;
1510
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001511erase_exit:
Kyungmin Park916527f2007-09-10 17:13:49 +09001512
1513 ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
1514 /* Do call back function */
1515 if (!ret)
1516 mtd_erase_callback(instr);
1517
1518 /* Deselect and wake up anyone waiting on the device */
1519 onenand_release_device(mtd);
1520
1521 return ret;
1522}
1523
1524/**
1525 * onenand_sync - [MTD Interface] sync
1526 * @param mtd MTD device structure
1527 *
1528 * Sync is actually a wait for chip ready function
1529 */
1530void onenand_sync(struct mtd_info *mtd)
1531{
Scott Wood3167c532008-06-20 12:38:57 -05001532 MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_sync: called\n");
Kyungmin Park916527f2007-09-10 17:13:49 +09001533
1534 /* Grab the lock and see if the device is available */
1535 onenand_get_device(mtd, FL_SYNCING);
1536
1537 /* Release it and go back */
1538 onenand_release_device(mtd);
1539}
1540
1541/**
1542 * onenand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad
1543 * @param mtd MTD device structure
1544 * @param ofs offset relative to mtd start
Kyungmin Parkd438d502008-08-13 09:11:02 +09001545 *
1546 * Check whether the block is bad
Kyungmin Park916527f2007-09-10 17:13:49 +09001547 */
1548int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs)
1549{
Kyungmin Parkd438d502008-08-13 09:11:02 +09001550 int ret;
1551
1552 /* Check for invalid offset */
1553 if (ofs > mtd->size)
1554 return -EINVAL;
1555
1556 onenand_get_device(mtd, FL_READING);
1557 ret = onenand_block_isbad_nolock(mtd,ofs, 0);
1558 onenand_release_device(mtd);
1559 return ret;
Kyungmin Park916527f2007-09-10 17:13:49 +09001560}
1561
1562/**
1563 * onenand_block_markbad - [MTD Interface] Mark the block at the given offset as bad
1564 * @param mtd MTD device structure
1565 * @param ofs offset relative to mtd start
Kyungmin Parkd438d502008-08-13 09:11:02 +09001566 *
1567 * Mark the block as bad
Kyungmin Park916527f2007-09-10 17:13:49 +09001568 */
1569int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
1570{
Kyungmin Parkd438d502008-08-13 09:11:02 +09001571 struct onenand_chip *this = mtd->priv;
1572 int ret;
1573
1574 ret = onenand_block_isbad(mtd, ofs);
1575 if (ret) {
1576 /* If it was bad already, return success and do nothing */
1577 if (ret > 0)
1578 return 0;
1579 return ret;
1580 }
1581
1582 ret = this->block_markbad(mtd, ofs);
1583 return ret;
Kyungmin Park916527f2007-09-10 17:13:49 +09001584}
1585
1586/**
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001587 * onenand_do_lock_cmd - [OneNAND Interface] Lock or unlock block(s)
1588 * @param mtd MTD device structure
1589 * @param ofs offset relative to mtd start
1590 * @param len number of bytes to lock or unlock
1591 * @param cmd lock or unlock command
Kyungmin Park916527f2007-09-10 17:13:49 +09001592 *
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001593 * Lock or unlock one or more blocks
Kyungmin Park916527f2007-09-10 17:13:49 +09001594 */
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001595static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int cmd)
Kyungmin Park916527f2007-09-10 17:13:49 +09001596{
1597 struct onenand_chip *this = mtd->priv;
1598 int start, end, block, value, status;
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001599 int wp_status_mask;
Kyungmin Park916527f2007-09-10 17:13:49 +09001600
1601 start = ofs >> this->erase_shift;
1602 end = len >> this->erase_shift;
1603
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001604 if (cmd == ONENAND_CMD_LOCK)
1605 wp_status_mask = ONENAND_WP_LS;
1606 else
1607 wp_status_mask = ONENAND_WP_US;
1608
Kyungmin Park916527f2007-09-10 17:13:49 +09001609 /* Continuous lock scheme */
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001610 if (this->options & ONENAND_HAS_CONT_LOCK) {
Kyungmin Park916527f2007-09-10 17:13:49 +09001611 /* Set start block address */
1612 this->write_word(start,
1613 this->base + ONENAND_REG_START_BLOCK_ADDRESS);
1614 /* Set end block address */
1615 this->write_word(end - 1,
1616 this->base + ONENAND_REG_END_BLOCK_ADDRESS);
1617 /* Write unlock command */
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001618 this->command(mtd, cmd, 0, 0);
Kyungmin Park916527f2007-09-10 17:13:49 +09001619
1620 /* There's no return value */
1621 this->wait(mtd, FL_UNLOCKING);
1622
1623 /* Sanity check */
1624 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
1625 & ONENAND_CTRL_ONGO)
1626 continue;
1627
1628 /* Check lock status */
1629 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
1630 if (!(status & ONENAND_WP_US))
1631 printk(KERN_ERR "wp status = 0x%x\n", status);
1632
1633 return 0;
1634 }
1635
1636 /* Block lock scheme */
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001637 for (block = start; block < start + end; block++) {
1638 /* Set block address */
1639 value = onenand_block_address(this, block);
1640 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
1641 /* Select DataRAM for DDP */
1642 value = onenand_bufferram_address(this, block);
1643 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
1644
Kyungmin Park916527f2007-09-10 17:13:49 +09001645 /* Set start block address */
1646 this->write_word(block,
1647 this->base + ONENAND_REG_START_BLOCK_ADDRESS);
1648 /* Write unlock command */
1649 this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0);
1650
1651 /* There's no return value */
1652 this->wait(mtd, FL_UNLOCKING);
1653
1654 /* Sanity check */
1655 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
1656 & ONENAND_CTRL_ONGO)
1657 continue;
1658
Kyungmin Park916527f2007-09-10 17:13:49 +09001659 /* Check lock status */
1660 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
1661 if (!(status & ONENAND_WP_US))
1662 printk(KERN_ERR "block = %d, wp status = 0x%x\n",
1663 block, status);
1664 }
1665
1666 return 0;
1667}
1668
1669/**
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001670 * onenand_lock - [MTD Interface] Lock block(s)
1671 * @param mtd MTD device structure
1672 * @param ofs offset relative to mtd start
1673 * @param len number of bytes to unlock
1674 *
1675 * Lock one or more blocks
1676 */
1677static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
1678{
1679 int ret;
1680
1681 onenand_get_device(mtd, FL_LOCKING);
1682 ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK);
1683 onenand_release_device(mtd);
1684 return ret;
1685}
1686
1687/**
1688 * onenand_unlock - [MTD Interface] Unlock block(s)
1689 * @param mtd MTD device structure
1690 * @param ofs offset relative to mtd start
1691 * @param len number of bytes to unlock
1692 *
1693 * Unlock one or more blocks
1694 */
1695static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
1696{
1697 int ret;
1698
1699 onenand_get_device(mtd, FL_LOCKING);
1700 ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
1701 onenand_release_device(mtd);
1702 return ret;
1703}
1704
1705/**
1706 * onenand_check_lock_status - [OneNAND Interface] Check lock status
1707 * @param this onenand chip data structure
1708 *
1709 * Check lock status
1710 */
1711static int onenand_check_lock_status(struct onenand_chip *this)
1712{
1713 unsigned int value, block, status;
1714 unsigned int end;
1715
1716 end = this->chipsize >> this->erase_shift;
1717 for (block = 0; block < end; block++) {
1718 /* Set block address */
1719 value = onenand_block_address(this, block);
1720 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
1721 /* Select DataRAM for DDP */
1722 value = onenand_bufferram_address(this, block);
1723 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
1724 /* Set start block address */
1725 this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
1726
1727 /* Check lock status */
1728 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
1729 if (!(status & ONENAND_WP_US)) {
1730 printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status);
1731 return 0;
1732 }
1733 }
1734
1735 return 1;
1736}
1737
1738/**
1739 * onenand_unlock_all - [OneNAND Interface] unlock all blocks
1740 * @param mtd MTD device structure
1741 *
1742 * Unlock all blocks
1743 */
1744static void onenand_unlock_all(struct mtd_info *mtd)
1745{
1746 struct onenand_chip *this = mtd->priv;
1747 loff_t ofs = 0;
1748 size_t len = this->chipsize;
1749
1750 if (this->options & ONENAND_HAS_UNLOCK_ALL) {
1751 /* Set start block address */
1752 this->write_word(0, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
1753 /* Write unlock command */
1754 this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0);
1755
1756 /* There's no return value */
1757 this->wait(mtd, FL_LOCKING);
1758
1759 /* Sanity check */
1760 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
1761 & ONENAND_CTRL_ONGO)
1762 continue;
1763
1764 return;
1765
1766 /* Check lock status */
1767 if (onenand_check_lock_status(this))
1768 return;
1769
1770 /* Workaround for all block unlock in DDP */
1771 if (ONENAND_IS_DDP(this)) {
1772 /* All blocks on another chip */
1773 ofs = this->chipsize >> 1;
1774 len = this->chipsize >> 1;
1775 }
1776 }
1777
1778 onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
1779}
1780
1781
1782/**
1783 * onenand_check_features - Check and set OneNAND features
1784 * @param mtd MTD data structure
1785 *
1786 * Check and set OneNAND features
1787 * - lock scheme
1788 * - two plane
1789 */
1790static void onenand_check_features(struct mtd_info *mtd)
1791{
1792 struct onenand_chip *this = mtd->priv;
1793 unsigned int density, process;
1794
1795 /* Lock scheme depends on density and process */
1796 density = onenand_get_density(this->device_id);
1797 process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT;
1798
1799 /* Lock scheme */
1800 switch (density) {
1801 case ONENAND_DEVICE_DENSITY_4Gb:
1802 this->options |= ONENAND_HAS_2PLANE;
1803
1804 case ONENAND_DEVICE_DENSITY_2Gb:
1805 /* 2Gb DDP don't have 2 plane */
1806 if (!ONENAND_IS_DDP(this))
1807 this->options |= ONENAND_HAS_2PLANE;
1808 this->options |= ONENAND_HAS_UNLOCK_ALL;
1809
1810 case ONENAND_DEVICE_DENSITY_1Gb:
1811 /* A-Die has all block unlock */
1812 if (process)
1813 this->options |= ONENAND_HAS_UNLOCK_ALL;
1814 break;
1815
1816 default:
1817 /* Some OneNAND has continuous lock scheme */
1818 if (!process)
1819 this->options |= ONENAND_HAS_CONT_LOCK;
1820 break;
1821 }
1822
1823 if (this->options & ONENAND_HAS_CONT_LOCK)
1824 printk(KERN_DEBUG "Lock scheme is Continuous Lock\n");
1825 if (this->options & ONENAND_HAS_UNLOCK_ALL)
1826 printk(KERN_DEBUG "Chip support all block unlock\n");
1827 if (this->options & ONENAND_HAS_2PLANE)
1828 printk(KERN_DEBUG "Chip has 2 plane\n");
1829}
1830
1831/**
Kyungmin Park916527f2007-09-10 17:13:49 +09001832 * onenand_print_device_info - Print device ID
1833 * @param device device ID
1834 *
1835 * Print device ID
1836 */
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001837char *onenand_print_device_info(int device, int version)
Kyungmin Park916527f2007-09-10 17:13:49 +09001838{
1839 int vcc, demuxed, ddp, density;
Fathi BOUDRA195ccfc2008-08-06 10:06:20 +02001840 char *dev_info = malloc(80);
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001841 char *p = dev_info;
Kyungmin Park916527f2007-09-10 17:13:49 +09001842
1843 vcc = device & ONENAND_DEVICE_VCC_MASK;
1844 demuxed = device & ONENAND_DEVICE_IS_DEMUX;
1845 ddp = device & ONENAND_DEVICE_IS_DDP;
1846 density = device >> ONENAND_DEVICE_DENSITY_SHIFT;
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001847 p += sprintf(dev_info, "%sOneNAND%s %dMB %sV 16-bit (0x%02x)",
Kyungmin Park916527f2007-09-10 17:13:49 +09001848 demuxed ? "" : "Muxed ",
1849 ddp ? "(DDP)" : "",
1850 (16 << density), vcc ? "2.65/3.3" : "1.8", device);
Fathi BOUDRA195ccfc2008-08-06 10:06:20 +02001851
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001852 sprintf(p, "\nOneNAND version = 0x%04x", version);
1853 printk("%s\n", dev_info);
1854
Fathi BOUDRA195ccfc2008-08-06 10:06:20 +02001855 return dev_info;
Kyungmin Park916527f2007-09-10 17:13:49 +09001856}
1857
1858static const struct onenand_manufacturers onenand_manuf_ids[] = {
1859 {ONENAND_MFR_SAMSUNG, "Samsung"},
Kyungmin Park916527f2007-09-10 17:13:49 +09001860};
1861
1862/**
1863 * onenand_check_maf - Check manufacturer ID
1864 * @param manuf manufacturer ID
1865 *
1866 * Check manufacturer ID
1867 */
1868static int onenand_check_maf(int manuf)
1869{
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001870 int size = ARRAY_SIZE(onenand_manuf_ids);
1871 char *name;
Kyungmin Park916527f2007-09-10 17:13:49 +09001872 int i;
1873
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001874 for (i = 0; size; i++)
Kyungmin Park916527f2007-09-10 17:13:49 +09001875 if (manuf == onenand_manuf_ids[i].id)
1876 break;
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001877
1878 if (i < size)
1879 name = onenand_manuf_ids[i].name;
1880 else
1881 name = "Unknown";
Kyungmin Park916527f2007-09-10 17:13:49 +09001882
1883#ifdef ONENAND_DEBUG
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001884 printk(KERN_DEBUG "OneNAND Manufacturer: %s (0x%0x)\n", name, manuf);
Kyungmin Park916527f2007-09-10 17:13:49 +09001885#endif
1886
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001887 return i == size;
Kyungmin Park916527f2007-09-10 17:13:49 +09001888}
1889
1890/**
1891 * onenand_probe - [OneNAND Interface] Probe the OneNAND device
1892 * @param mtd MTD device structure
1893 *
1894 * OneNAND detection method:
1895 * Compare the the values from command with ones from register
1896 */
1897static int onenand_probe(struct mtd_info *mtd)
1898{
1899 struct onenand_chip *this = mtd->priv;
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001900 int bram_maf_id, bram_dev_id, maf_id, dev_id, ver_id;
Kyungmin Park916527f2007-09-10 17:13:49 +09001901 int density;
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001902 int syscfg;
1903
1904 /* Save system configuration 1 */
1905 syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
1906 /* Clear Sync. Burst Read mode to read BootRAM */
1907 this->write_word((syscfg & ~ONENAND_SYS_CFG1_SYNC_READ), this->base + ONENAND_REG_SYS_CFG1);
Kyungmin Park916527f2007-09-10 17:13:49 +09001908
1909 /* Send the command for reading device ID from BootRAM */
1910 this->write_word(ONENAND_CMD_READID, this->base + ONENAND_BOOTRAM);
1911
1912 /* Read manufacturer and device IDs from BootRAM */
1913 bram_maf_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x0);
1914 bram_dev_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x2);
1915
Kyungmin Park916527f2007-09-10 17:13:49 +09001916 /* Reset OneNAND to read default register values */
1917 this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM);
1918
Kyungmin Parkd438d502008-08-13 09:11:02 +09001919 /* Wait reset */
1920 this->wait(mtd, FL_RESETING);
Kyungmin Park916527f2007-09-10 17:13:49 +09001921
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001922 /* Restore system configuration 1 */
1923 this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
1924
1925 /* Check manufacturer ID */
1926 if (onenand_check_maf(bram_maf_id))
1927 return -ENXIO;
1928
Kyungmin Park916527f2007-09-10 17:13:49 +09001929 /* Read manufacturer and device IDs from Register */
1930 maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);
1931 dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001932 ver_id = this->read_word(this->base + ONENAND_REG_VERSION_ID);
Kyungmin Park916527f2007-09-10 17:13:49 +09001933
1934 /* Check OneNAND device */
1935 if (maf_id != bram_maf_id || dev_id != bram_dev_id)
1936 return -ENXIO;
1937
Kyungmin Park1bb707c2008-03-17 08:54:06 +09001938 /* FIXME : Current OneNAND MTD doesn't support Flex-OneNAND */
1939 if (dev_id & (1 << 9)) {
1940 printk("Not yet support Flex-OneNAND\n");
1941 return -ENXIO;
1942 }
1943
Kyungmin Park916527f2007-09-10 17:13:49 +09001944 /* Flash device information */
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001945 mtd->name = onenand_print_device_info(dev_id, ver_id);
Kyungmin Park916527f2007-09-10 17:13:49 +09001946 this->device_id = dev_id;
1947
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001948 density = onenand_get_density(dev_id);
Kyungmin Park916527f2007-09-10 17:13:49 +09001949 this->chipsize = (16 << density) << 20;
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001950 /* Set density mask. it is used for DDP */
1951 if (ONENAND_IS_DDP(this))
1952 this->density_mask = (1 << (density + 6));
1953 else
1954 this->density_mask = 0;
Kyungmin Park916527f2007-09-10 17:13:49 +09001955
1956 /* OneNAND page size & block size */
1957 /* The data buffer size is equal to page size */
Kyungmin Parkd438d502008-08-13 09:11:02 +09001958 mtd->writesize =
Kyungmin Park916527f2007-09-10 17:13:49 +09001959 this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE);
Kyungmin Parkd438d502008-08-13 09:11:02 +09001960 mtd->oobsize = mtd->writesize >> 5;
Kyungmin Park916527f2007-09-10 17:13:49 +09001961 /* Pagers per block is always 64 in OneNAND */
Kyungmin Parkd438d502008-08-13 09:11:02 +09001962 mtd->erasesize = mtd->writesize << 6;
Kyungmin Park916527f2007-09-10 17:13:49 +09001963
1964 this->erase_shift = ffs(mtd->erasesize) - 1;
Kyungmin Parkd438d502008-08-13 09:11:02 +09001965 this->page_shift = ffs(mtd->writesize) - 1;
Kyungmin Park916527f2007-09-10 17:13:49 +09001966 this->ppb_shift = (this->erase_shift - this->page_shift);
Kyungmin Parkd438d502008-08-13 09:11:02 +09001967 this->page_mask = (mtd->erasesize / mtd->writesize) - 1;
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09001968 /* It's real page size */
1969 this->writesize = mtd->writesize;
Kyungmin Park916527f2007-09-10 17:13:49 +09001970
1971 /* REVIST: Multichip handling */
1972
1973 mtd->size = this->chipsize;
1974
Kyungmin Parkef0921d2008-11-04 09:24:07 +09001975 /* Check OneNAND features */
1976 onenand_check_features(mtd);
Kyungmin Park916527f2007-09-10 17:13:49 +09001977
Kyungmin Parkd438d502008-08-13 09:11:02 +09001978 mtd->flags = MTD_CAP_NANDFLASH;
Fathi BOUDRA195ccfc2008-08-06 10:06:20 +02001979 mtd->erase = onenand_erase;
1980 mtd->read = onenand_read;
1981 mtd->write = onenand_write;
Fathi BOUDRA195ccfc2008-08-06 10:06:20 +02001982 mtd->read_oob = onenand_read_oob;
1983 mtd->write_oob = onenand_write_oob;
1984 mtd->sync = onenand_sync;
1985 mtd->block_isbad = onenand_block_isbad;
1986 mtd->block_markbad = onenand_block_markbad;
1987
Kyungmin Park916527f2007-09-10 17:13:49 +09001988 return 0;
1989}
1990
1991/**
1992 * onenand_scan - [OneNAND Interface] Scan for the OneNAND device
1993 * @param mtd MTD device structure
1994 * @param maxchips Number of chips to scan for
1995 *
1996 * This fills out all the not initialized function pointers
1997 * with the defaults.
1998 * The flash ID is read and the mtd/chip structures are
1999 * filled with the appropriate values.
2000 */
2001int onenand_scan(struct mtd_info *mtd, int maxchips)
2002{
2003 struct onenand_chip *this = mtd->priv;
2004
2005 if (!this->read_word)
2006 this->read_word = onenand_readw;
2007 if (!this->write_word)
2008 this->write_word = onenand_writew;
2009
2010 if (!this->command)
2011 this->command = onenand_command;
2012 if (!this->wait)
2013 this->wait = onenand_wait;
Kyungmin Parkef0921d2008-11-04 09:24:07 +09002014 if (!this->bbt_wait)
2015 this->bbt_wait = onenand_bbt_wait;
Kyungmin Park916527f2007-09-10 17:13:49 +09002016
2017 if (!this->read_bufferram)
2018 this->read_bufferram = onenand_read_bufferram;
Kyungmin Parkef0921d2008-11-04 09:24:07 +09002019 if (!this->read_spareram)
2020 this->read_spareram = onenand_read_bufferram;
Kyungmin Park916527f2007-09-10 17:13:49 +09002021 if (!this->write_bufferram)
2022 this->write_bufferram = onenand_write_bufferram;
2023
Kyungmin Parkef0921d2008-11-04 09:24:07 +09002024 if (!this->scan_bbt)
2025 this->scan_bbt = onenand_default_bbt;
2026
Kyungmin Park916527f2007-09-10 17:13:49 +09002027 if (onenand_probe(mtd))
2028 return -ENXIO;
2029
2030 /* Set Sync. Burst Read after probing */
2031 if (this->mmcontrol) {
2032 printk(KERN_INFO "OneNAND Sync. Burst Read support\n");
2033 this->read_bufferram = onenand_sync_read_bufferram;
2034 }
2035
Kyungmin Parkbfd7f382008-08-19 08:42:53 +09002036 /* Allocate buffers, if necessary */
2037 if (!this->page_buf) {
2038 this->page_buf = kzalloc(mtd->writesize, GFP_KERNEL);
2039 if (!this->page_buf) {
2040 printk(KERN_ERR "onenand_scan(): Can't allocate page_buf\n");
2041 return -ENOMEM;
2042 }
2043 this->options |= ONENAND_PAGEBUF_ALLOC;
2044 }
2045 if (!this->oob_buf) {
2046 this->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
2047 if (!this->oob_buf) {
2048 printk(KERN_ERR "onenand_scan: Can't allocate oob_buf\n");
2049 if (this->options & ONENAND_PAGEBUF_ALLOC) {
2050 this->options &= ~ONENAND_PAGEBUF_ALLOC;
2051 kfree(this->page_buf);
2052 }
2053 return -ENOMEM;
2054 }
2055 this->options |= ONENAND_OOBBUF_ALLOC;
2056 }
2057
Kyungmin Parkef0921d2008-11-04 09:24:07 +09002058 /* Unlock whole block */
2059 onenand_unlock_all(mtd);
Kyungmin Park916527f2007-09-10 17:13:49 +09002060
Kyungmin Parkef0921d2008-11-04 09:24:07 +09002061 return this->scan_bbt(mtd);
Kyungmin Park916527f2007-09-10 17:13:49 +09002062}
2063
2064/**
2065 * onenand_release - [OneNAND Interface] Free resources held by the OneNAND device
2066 * @param mtd MTD device structure
2067 */
2068void onenand_release(struct mtd_info *mtd)
2069{
2070}