blob: a8394730b4b6fc7e9e84fcdd919e9a09c0b669da [file] [log] [blame]
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001/*
2 * linux/drivers/mtd/onenand/onenand_base.c
3 *
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05304 * Copyright © 2005-2009 Samsung Electronics
5 * Copyright © 2007 Nokia Corporation
6 *
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01007 * Kyungmin Park <kyungmin.park@samsung.com>
8 *
Adrian Hunter81280d52007-02-15 09:47:29 +09009 * Credits:
10 * Adrian Hunter <ext-adrian.hunter@nokia.com>:
11 * auto-placement support, read-while load support, various fixes
Adrian Hunter81280d52007-02-15 09:47:29 +090012 *
Rohit Hagargundgi5988af22009-05-12 13:46:57 -070013 * Vishak G <vishak.g at samsung.com>, Rohit Hagargundgi <h.rohit at samsung.com>
14 * Flex-OneNAND support
Amul Kumar Saha3cf60252009-10-21 17:00:05 +053015 * Amul Kumar Saha <amul.saha at samsung.com>
16 * OTP support
Rohit Hagargundgi5988af22009-05-12 13:46:57 -070017 *
Kyungmin Parkcd5f6342005-07-11 11:41:53 +010018 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License version 2 as
20 * published by the Free Software Foundation.
21 */
22
23#include <linux/kernel.h>
24#include <linux/module.h>
Amul Sahac90173f2009-06-16 11:24:01 +053025#include <linux/moduleparam.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090026#include <linux/slab.h>
Kyungmin Parkcd5f6342005-07-11 11:41:53 +010027#include <linux/init.h>
Andrew Morton015953d2005-11-08 21:34:28 -080028#include <linux/sched.h>
Richard Purdie6c77fd62008-02-06 10:18:22 +000029#include <linux/delay.h>
Kyungmin Park2c221202006-11-16 11:23:48 +090030#include <linux/interrupt.h>
Andrew Morton015953d2005-11-08 21:34:28 -080031#include <linux/jiffies.h>
Kyungmin Parkcd5f6342005-07-11 11:41:53 +010032#include <linux/mtd/mtd.h>
33#include <linux/mtd/onenand.h>
34#include <linux/mtd/partitions.h>
35
36#include <asm/io.h>
37
Mika Korhonen72073022009-10-23 07:50:43 +020038/*
39 * Multiblock erase if number of blocks to erase is 2 or more.
40 * Maximum number of blocks for simultaneous erase is 64.
41 */
42#define MB_ERASE_MIN_BLK_COUNT 2
43#define MB_ERASE_MAX_BLK_COUNT 64
44
Rohit Hagargundgi5988af22009-05-12 13:46:57 -070045/* Default Flex-OneNAND boundary and lock respectively */
46static int flex_bdry[MAX_DIES * 2] = { -1, 0, -1, 0 };
47
Amul Sahac90173f2009-06-16 11:24:01 +053048module_param_array(flex_bdry, int, NULL, 0400);
49MODULE_PARM_DESC(flex_bdry, "SLC Boundary information for Flex-OneNAND"
50 "Syntax:flex_bdry=DIE_BDRY,LOCK,..."
51 "DIE_BDRY: SLC boundary of the die"
52 "LOCK: Locking information for SLC boundary"
53 " : 0->Set boundary in unlocked status"
54 " : 1->Set boundary in locked status");
55
Amul Kumar Saha3cf60252009-10-21 17:00:05 +053056/* Default OneNAND/Flex-OneNAND OTP options*/
57static int otp;
58
59module_param(otp, int, 0400);
60MODULE_PARM_DESC(otp, "Corresponding behaviour of OneNAND in OTP"
61 "Syntax : otp=LOCK_TYPE"
62 "LOCK_TYPE : Keys issued, for specific OTP Lock type"
63 " : 0 -> Default (No Blocks Locked)"
64 " : 1 -> OTP Block lock"
65 " : 2 -> 1st Block lock"
66 " : 3 -> BOTH OTP Block and 1st Block lock");
67
Roman Tereshonkov99b17c02011-04-11 12:52:01 +030068/*
69 * flexonenand_oob_128 - oob info for Flex-Onenand with 4KB page
70 * For now, we expose only 64 out of 80 ecc bytes
Rohit Hagargundgi5988af22009-05-12 13:46:57 -070071 */
Roman Tereshonkov99b17c02011-04-11 12:52:01 +030072static struct nand_ecclayout flexonenand_oob_128 = {
Rohit Hagargundgi5988af22009-05-12 13:46:57 -070073 .eccbytes = 64,
74 .eccpos = {
75 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
76 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
77 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
78 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
79 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
80 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
81 102, 103, 104, 105
82 },
83 .oobfree = {
84 {2, 4}, {18, 4}, {34, 4}, {50, 4},
85 {66, 4}, {82, 4}, {98, 4}, {114, 4}
86 }
87};
88
Roman Tereshonkov99b17c02011-04-11 12:52:01 +030089/*
90 * onenand_oob_128 - oob info for OneNAND with 4KB page
91 *
92 * Based on specification:
93 * 4Gb M-die OneNAND Flash (KFM4G16Q4M, KFN8G16Q4M). Rev. 1.3, Apr. 2010
94 *
95 * For eccpos we expose only 64 bytes out of 72 (see struct nand_ecclayout)
96 *
97 * oobfree uses the spare area fields marked as
98 * "Managed by internal ECC logic for Logical Sector Number area"
99 */
100static struct nand_ecclayout onenand_oob_128 = {
101 .eccbytes = 64,
102 .eccpos = {
103 7, 8, 9, 10, 11, 12, 13, 14, 15,
104 23, 24, 25, 26, 27, 28, 29, 30, 31,
105 39, 40, 41, 42, 43, 44, 45, 46, 47,
106 55, 56, 57, 58, 59, 60, 61, 62, 63,
107 71, 72, 73, 74, 75, 76, 77, 78, 79,
108 87, 88, 89, 90, 91, 92, 93, 94, 95,
109 103, 104, 105, 106, 107, 108, 109, 110, 111,
110 119
111 },
112 .oobfree = {
113 {2, 3}, {18, 3}, {34, 3}, {50, 3},
114 {66, 3}, {82, 3}, {98, 3}, {114, 3}
115 }
116};
117
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100118/**
119 * onenand_oob_64 - oob info for large (2KB) page
120 */
Thomas Gleixner5bd34c02006-05-27 22:16:10 +0200121static struct nand_ecclayout onenand_oob_64 = {
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100122 .eccbytes = 20,
123 .eccpos = {
124 8, 9, 10, 11, 12,
125 24, 25, 26, 27, 28,
126 40, 41, 42, 43, 44,
127 56, 57, 58, 59, 60,
128 },
129 .oobfree = {
130 {2, 3}, {14, 2}, {18, 3}, {30, 2},
Jarkko Lavinend9777f12006-05-12 17:02:35 +0300131 {34, 3}, {46, 2}, {50, 3}, {62, 2}
132 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100133};
134
135/**
136 * onenand_oob_32 - oob info for middle (1KB) page
137 */
Thomas Gleixner5bd34c02006-05-27 22:16:10 +0200138static struct nand_ecclayout onenand_oob_32 = {
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100139 .eccbytes = 10,
140 .eccpos = {
141 8, 9, 10, 11, 12,
142 24, 25, 26, 27, 28,
143 },
144 .oobfree = { {2, 3}, {14, 2}, {18, 3}, {30, 2} }
145};
146
147static const unsigned char ffchars[] = {
148 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
149 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 16 */
150 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
151 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 32 */
152 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
153 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 48 */
154 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
155 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 64 */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700156 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
157 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 80 */
158 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
159 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 96 */
160 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
161 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 112 */
162 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
163 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 128 */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100164};
165
166/**
167 * onenand_readw - [OneNAND Interface] Read OneNAND register
168 * @param addr address to read
169 *
170 * Read OneNAND register
171 */
172static unsigned short onenand_readw(void __iomem *addr)
173{
174 return readw(addr);
175}
176
177/**
178 * onenand_writew - [OneNAND Interface] Write OneNAND register with value
179 * @param value value to write
180 * @param addr address to write
181 *
182 * Write OneNAND register with value
183 */
184static void onenand_writew(unsigned short value, void __iomem *addr)
185{
186 writew(value, addr);
187}
188
189/**
190 * onenand_block_address - [DEFAULT] Get block address
Kyungmin Park83a36832005-09-29 04:53:16 +0100191 * @param this onenand chip data structure
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100192 * @param block the block
193 * @return translated block address if DDP, otherwise same
194 *
195 * Setup Start Address 1 Register (F100h)
196 */
Kyungmin Park83a36832005-09-29 04:53:16 +0100197static int onenand_block_address(struct onenand_chip *this, int block)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100198{
Kyungmin Park738d61f2007-01-15 17:09:14 +0900199 /* Device Flash Core select, NAND Flash Block Address */
200 if (block & this->density_mask)
201 return ONENAND_DDP_CHIP1 | (block ^ this->density_mask);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100202
203 return block;
204}
205
206/**
207 * onenand_bufferram_address - [DEFAULT] Get bufferram address
Kyungmin Park83a36832005-09-29 04:53:16 +0100208 * @param this onenand chip data structure
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100209 * @param block the block
210 * @return set DBS value if DDP, otherwise 0
211 *
212 * Setup Start Address 2 Register (F101h) for DDP
213 */
Kyungmin Park83a36832005-09-29 04:53:16 +0100214static int onenand_bufferram_address(struct onenand_chip *this, int block)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100215{
Kyungmin Park738d61f2007-01-15 17:09:14 +0900216 /* Device BufferRAM Select */
217 if (block & this->density_mask)
218 return ONENAND_DDP_CHIP1;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100219
Kyungmin Park738d61f2007-01-15 17:09:14 +0900220 return ONENAND_DDP_CHIP0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100221}
222
223/**
224 * onenand_page_address - [DEFAULT] Get page address
225 * @param page the page address
226 * @param sector the sector address
227 * @return combined page and sector address
228 *
229 * Setup Start Address 8 Register (F107h)
230 */
231static int onenand_page_address(int page, int sector)
232{
233 /* Flash Page Address, Flash Sector Address */
234 int fpa, fsa;
235
236 fpa = page & ONENAND_FPA_MASK;
237 fsa = sector & ONENAND_FSA_MASK;
238
239 return ((fpa << ONENAND_FPA_SHIFT) | fsa);
240}
241
242/**
243 * onenand_buffer_address - [DEFAULT] Get buffer address
244 * @param dataram1 DataRAM index
245 * @param sectors the sector address
246 * @param count the number of sectors
247 * @return the start buffer value
248 *
249 * Setup Start Buffer Register (F200h)
250 */
251static int onenand_buffer_address(int dataram1, int sectors, int count)
252{
253 int bsa, bsc;
254
255 /* BufferRAM Sector Address */
256 bsa = sectors & ONENAND_BSA_MASK;
257
258 if (dataram1)
259 bsa |= ONENAND_BSA_DATARAM1; /* DataRAM1 */
260 else
261 bsa |= ONENAND_BSA_DATARAM0; /* DataRAM0 */
262
263 /* BufferRAM Sector Count */
264 bsc = count & ONENAND_BSC_MASK;
265
266 return ((bsa << ONENAND_BSA_SHIFT) | bsc);
267}
268
269/**
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700270 * flexonenand_block- For given address return block number
271 * @param this - OneNAND device structure
272 * @param addr - Address for which block number is needed
273 */
274static unsigned flexonenand_block(struct onenand_chip *this, loff_t addr)
275{
276 unsigned boundary, blk, die = 0;
277
278 if (ONENAND_IS_DDP(this) && addr >= this->diesize[0]) {
279 die = 1;
280 addr -= this->diesize[0];
281 }
282
283 boundary = this->boundary[die];
284
285 blk = addr >> (this->erase_shift - 1);
286 if (blk > boundary)
287 blk = (blk + boundary + 1) >> 1;
288
289 blk += die ? this->density_mask : 0;
290 return blk;
291}
292
293inline unsigned onenand_block(struct onenand_chip *this, loff_t addr)
294{
295 if (!FLEXONENAND(this))
296 return addr >> this->erase_shift;
297 return flexonenand_block(this, addr);
298}
299
300/**
301 * flexonenand_addr - Return address of the block
302 * @this: OneNAND device structure
303 * @block: Block number on Flex-OneNAND
304 *
305 * Return address of the block
306 */
307static loff_t flexonenand_addr(struct onenand_chip *this, int block)
308{
309 loff_t ofs = 0;
310 int die = 0, boundary;
311
312 if (ONENAND_IS_DDP(this) && block >= this->density_mask) {
313 block -= this->density_mask;
314 die = 1;
315 ofs = this->diesize[0];
316 }
317
318 boundary = this->boundary[die];
319 ofs += (loff_t)block << (this->erase_shift - 1);
320 if (block > (boundary + 1))
321 ofs += (loff_t)(block - boundary - 1) << (this->erase_shift - 1);
322 return ofs;
323}
324
325loff_t onenand_addr(struct onenand_chip *this, int block)
326{
327 if (!FLEXONENAND(this))
328 return (loff_t)block << this->erase_shift;
329 return flexonenand_addr(this, block);
330}
331EXPORT_SYMBOL(onenand_addr);
332
333/**
Kyungmin Parke71f04f2007-12-11 11:23:45 +0900334 * onenand_get_density - [DEFAULT] Get OneNAND density
335 * @param dev_id OneNAND device ID
336 *
337 * Get OneNAND density from device ID
338 */
339static inline int onenand_get_density(int dev_id)
340{
341 int density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
342 return (density & ONENAND_DEVICE_DENSITY_MASK);
343}
344
345/**
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700346 * flexonenand_region - [Flex-OneNAND] Return erase region of addr
347 * @param mtd MTD device structure
348 * @param addr address whose erase region needs to be identified
349 */
350int flexonenand_region(struct mtd_info *mtd, loff_t addr)
351{
352 int i;
353
354 for (i = 0; i < mtd->numeraseregions; i++)
355 if (addr < mtd->eraseregions[i].offset)
356 break;
357 return i - 1;
358}
359EXPORT_SYMBOL(flexonenand_region);
360
361/**
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100362 * onenand_command - [DEFAULT] Send command to OneNAND device
363 * @param mtd MTD device structure
364 * @param cmd the command to be sent
365 * @param addr offset to read from or write to
366 * @param len number of bytes to read or write
367 *
368 * Send command to OneNAND device. This function is used for middle/large page
369 * devices (1KB/2KB Bytes per page)
370 */
371static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t len)
372{
373 struct onenand_chip *this = mtd->priv;
Kyungmin Parkb21b72c2007-12-11 11:13:18 +0900374 int value, block, page;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100375
376 /* Address translation */
377 switch (cmd) {
378 case ONENAND_CMD_UNLOCK:
379 case ONENAND_CMD_LOCK:
380 case ONENAND_CMD_LOCK_TIGHT:
Kyungmin Park28b79ff2006-09-26 09:45:28 +0000381 case ONENAND_CMD_UNLOCK_ALL:
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100382 block = -1;
383 page = -1;
384 break;
385
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700386 case FLEXONENAND_CMD_PI_ACCESS:
387 /* addr contains die index */
388 block = addr * this->density_mask;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100389 page = -1;
390 break;
391
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700392 case ONENAND_CMD_ERASE:
Mika Korhonen72073022009-10-23 07:50:43 +0200393 case ONENAND_CMD_MULTIBLOCK_ERASE:
394 case ONENAND_CMD_ERASE_VERIFY:
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700395 case ONENAND_CMD_BUFFERRAM:
396 case ONENAND_CMD_OTP_ACCESS:
397 block = onenand_block(this, addr);
398 page = -1;
399 break;
400
401 case FLEXONENAND_CMD_READ_PI:
402 cmd = ONENAND_CMD_READ;
403 block = addr * this->density_mask;
404 page = 0;
405 break;
406
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100407 default:
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700408 block = onenand_block(this, addr);
Rohit Hassan Sathyanarayan42b0aab2010-07-23 12:29:25 +0530409 if (FLEXONENAND(this))
410 page = (int) (addr - onenand_addr(this, block))>>\
411 this->page_shift;
412 else
413 page = (int) (addr >> this->page_shift);
Kyungmin Parkee9745f2007-06-30 13:57:49 +0900414 if (ONENAND_IS_2PLANE(this)) {
415 /* Make the even block number */
416 block &= ~1;
417 /* Is it the odd plane? */
418 if (addr & this->writesize)
419 block++;
420 page >>= 1;
421 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100422 page &= this->page_mask;
423 break;
424 }
425
426 /* NOTE: The setting order of the registers is very important! */
427 if (cmd == ONENAND_CMD_BUFFERRAM) {
428 /* Select DataRAM for DDP */
Kyungmin Park83a36832005-09-29 04:53:16 +0100429 value = onenand_bufferram_address(this, block);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100430 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
431
Kyungmin Park8a8f6322010-12-02 09:24:16 +0900432 if (ONENAND_IS_2PLANE(this) || ONENAND_IS_4KB_PAGE(this))
Kyungmin Parkee9745f2007-06-30 13:57:49 +0900433 /* It is always BufferRAM0 */
434 ONENAND_SET_BUFFERRAM0(this);
435 else
436 /* Switch to the next data buffer */
437 ONENAND_SET_NEXT_BUFFERRAM(this);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100438
439 return 0;
440 }
441
442 if (block != -1) {
443 /* Write 'DFS, FBA' of Flash */
Kyungmin Park83a36832005-09-29 04:53:16 +0100444 value = onenand_block_address(this, block);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100445 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
Kyungmin Park3cecf692006-05-12 17:02:51 +0300446
Kyungmin Parkb21b72c2007-12-11 11:13:18 +0900447 /* Select DataRAM for DDP */
448 value = onenand_bufferram_address(this, block);
449 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100450 }
451
452 if (page != -1) {
Kyungmin Park60d84f92006-12-22 16:21:54 +0900453 /* Now we use page size operation */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700454 int sectors = 0, count = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100455 int dataram;
456
457 switch (cmd) {
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700458 case FLEXONENAND_CMD_RECOVER_LSB:
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100459 case ONENAND_CMD_READ:
460 case ONENAND_CMD_READOOB:
Kyungmin Park8a8f6322010-12-02 09:24:16 +0900461 if (ONENAND_IS_4KB_PAGE(this))
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700462 /* It is always BufferRAM0 */
463 dataram = ONENAND_SET_BUFFERRAM0(this);
464 else
465 dataram = ONENAND_SET_NEXT_BUFFERRAM(this);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100466 break;
467
468 default:
Kyungmin Parkee9745f2007-06-30 13:57:49 +0900469 if (ONENAND_IS_2PLANE(this) && cmd == ONENAND_CMD_PROG)
470 cmd = ONENAND_CMD_2X_PROG;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100471 dataram = ONENAND_CURRENT_BUFFERRAM(this);
472 break;
473 }
474
475 /* Write 'FPA, FSA' of Flash */
476 value = onenand_page_address(page, sectors);
477 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS8);
478
479 /* Write 'BSA, BSC' of DataRAM */
480 value = onenand_buffer_address(dataram, sectors, count);
481 this->write_word(value, this->base + ONENAND_REG_START_BUFFER);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100482 }
483
484 /* Interrupt clear */
485 this->write_word(ONENAND_INT_CLEAR, this->base + ONENAND_REG_INTERRUPT);
486
487 /* Write command */
488 this->write_word(cmd, this->base + ONENAND_REG_COMMAND);
489
490 return 0;
491}
492
493/**
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700494 * onenand_read_ecc - return ecc status
495 * @param this onenand chip structure
496 */
497static inline int onenand_read_ecc(struct onenand_chip *this)
498{
499 int ecc, i, result = 0;
500
Kyungmin Park6a88c472010-04-28 17:46:45 +0200501 if (!FLEXONENAND(this) && !ONENAND_IS_4KB_PAGE(this))
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700502 return this->read_word(this->base + ONENAND_REG_ECC_STATUS);
503
504 for (i = 0; i < 4; i++) {
Kyungmin Park6a88c472010-04-28 17:46:45 +0200505 ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS + i*2);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700506 if (likely(!ecc))
507 continue;
508 if (ecc & FLEXONENAND_UNCORRECTABLE_ERROR)
509 return ONENAND_ECC_2BIT_ALL;
510 else
511 result = ONENAND_ECC_1BIT_ALL;
512 }
513
514 return result;
515}
516
517/**
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100518 * onenand_wait - [DEFAULT] wait until the command is done
519 * @param mtd MTD device structure
520 * @param state state to select the max. timeout value
521 *
522 * Wait for command done. This applies to all OneNAND command
523 * Read can take up to 30us, erase up to 2ms and program up to 350us
524 * according to general OneNAND specs
525 */
526static int onenand_wait(struct mtd_info *mtd, int state)
527{
528 struct onenand_chip * this = mtd->priv;
529 unsigned long timeout;
530 unsigned int flags = ONENAND_INT_MASTER;
531 unsigned int interrupt = 0;
Kyungmin Park2fd32d42006-12-29 11:51:40 +0900532 unsigned int ctrl;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100533
534 /* The 20 msec is enough */
535 timeout = jiffies + msecs_to_jiffies(20);
536 while (time_before(jiffies, timeout)) {
537 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
538
539 if (interrupt & flags)
540 break;
541
Mika Korhonen72073022009-10-23 07:50:43 +0200542 if (state != FL_READING && state != FL_PREPARING_ERASE)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100543 cond_resched();
544 }
545 /* To get correct interrupt status in timeout case */
546 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
547
548 ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
549
Kyungmin Park83973b82008-05-29 14:52:40 +0900550 /*
551 * In the Spec. it checks the controller status first
552 * However if you get the correct information in case of
553 * power off recovery (POR) test, it should read ECC status first
554 */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100555 if (interrupt & ONENAND_INT_READ) {
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700556 int ecc = onenand_read_ecc(this);
Kyungmin Parkf4f91ac2006-11-16 12:03:56 +0900557 if (ecc) {
Kyungmin Parkb3c9f8b2007-01-05 19:16:04 +0900558 if (ecc & ONENAND_ECC_2BIT_ALL) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +0530559 printk(KERN_ERR "%s: ECC error = 0x%04x\n",
560 __func__, ecc);
Kyungmin Parkf4f91ac2006-11-16 12:03:56 +0900561 mtd->ecc_stats.failed++;
Adrian Hunter30a7eb22007-10-12 10:19:38 +0300562 return -EBADMSG;
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +0300563 } else if (ecc & ONENAND_ECC_1BIT_ALL) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +0530564 printk(KERN_DEBUG "%s: correctable ECC error = 0x%04x\n",
565 __func__, ecc);
Kyungmin Parkf4f91ac2006-11-16 12:03:56 +0900566 mtd->ecc_stats.corrected++;
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +0300567 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100568 }
Adrian Hunter9d032802007-01-10 07:51:26 +0200569 } else if (state == FL_READING) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +0530570 printk(KERN_ERR "%s: read timeout! ctrl=0x%04x intr=0x%04x\n",
571 __func__, ctrl, interrupt);
Adrian Hunter9d032802007-01-10 07:51:26 +0200572 return -EIO;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100573 }
574
Mika Korhonen72073022009-10-23 07:50:43 +0200575 if (state == FL_PREPARING_ERASE && !(interrupt & ONENAND_INT_ERASE)) {
576 printk(KERN_ERR "%s: mb erase timeout! ctrl=0x%04x intr=0x%04x\n",
577 __func__, ctrl, interrupt);
578 return -EIO;
579 }
580
581 if (!(interrupt & ONENAND_INT_MASTER)) {
582 printk(KERN_ERR "%s: timeout! ctrl=0x%04x intr=0x%04x\n",
583 __func__, ctrl, interrupt);
584 return -EIO;
585 }
586
Kyungmin Park83973b82008-05-29 14:52:40 +0900587 /* If there's controller error, it's a real error */
588 if (ctrl & ONENAND_CTRL_ERROR) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +0530589 printk(KERN_ERR "%s: controller error = 0x%04x\n",
590 __func__, ctrl);
Kyungmin Park83973b82008-05-29 14:52:40 +0900591 if (ctrl & ONENAND_CTRL_LOCK)
Amul Kumar Saha297758f2009-10-02 16:59:11 +0530592 printk(KERN_ERR "%s: it's locked error.\n", __func__);
Kyungmin Park83973b82008-05-29 14:52:40 +0900593 return -EIO;
594 }
595
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100596 return 0;
597}
598
Kyungmin Park2c221202006-11-16 11:23:48 +0900599/*
600 * onenand_interrupt - [DEFAULT] onenand interrupt handler
601 * @param irq onenand interrupt number
602 * @param dev_id interrupt data
603 *
604 * complete the work
605 */
606static irqreturn_t onenand_interrupt(int irq, void *data)
607{
Jeff Garzik06efcad2007-10-19 03:10:11 -0400608 struct onenand_chip *this = data;
Kyungmin Park2c221202006-11-16 11:23:48 +0900609
610 /* To handle shared interrupt */
611 if (!this->complete.done)
612 complete(&this->complete);
613
614 return IRQ_HANDLED;
615}
616
617/*
618 * onenand_interrupt_wait - [DEFAULT] wait until the command is done
619 * @param mtd MTD device structure
620 * @param state state to select the max. timeout value
621 *
622 * Wait for command done.
623 */
624static int onenand_interrupt_wait(struct mtd_info *mtd, int state)
625{
626 struct onenand_chip *this = mtd->priv;
627
Kyungmin Park2c221202006-11-16 11:23:48 +0900628 wait_for_completion(&this->complete);
629
630 return onenand_wait(mtd, state);
631}
632
633/*
634 * onenand_try_interrupt_wait - [DEFAULT] try interrupt wait
635 * @param mtd MTD device structure
636 * @param state state to select the max. timeout value
637 *
638 * Try interrupt based wait (It is used one-time)
639 */
640static int onenand_try_interrupt_wait(struct mtd_info *mtd, int state)
641{
642 struct onenand_chip *this = mtd->priv;
643 unsigned long remain, timeout;
644
645 /* We use interrupt wait first */
646 this->wait = onenand_interrupt_wait;
647
Kyungmin Park2c221202006-11-16 11:23:48 +0900648 timeout = msecs_to_jiffies(100);
649 remain = wait_for_completion_timeout(&this->complete, timeout);
650 if (!remain) {
651 printk(KERN_INFO "OneNAND: There's no interrupt. "
652 "We use the normal wait\n");
653
654 /* Release the irq */
655 free_irq(this->irq, this);
David Woodhousec9ac5972006-11-30 08:17:38 +0000656
Kyungmin Park2c221202006-11-16 11:23:48 +0900657 this->wait = onenand_wait;
658 }
659
660 return onenand_wait(mtd, state);
661}
662
663/*
664 * onenand_setup_wait - [OneNAND Interface] setup onenand wait method
665 * @param mtd MTD device structure
666 *
667 * There's two method to wait onenand work
668 * 1. polling - read interrupt status register
669 * 2. interrupt - use the kernel interrupt method
670 */
671static void onenand_setup_wait(struct mtd_info *mtd)
672{
673 struct onenand_chip *this = mtd->priv;
674 int syscfg;
675
676 init_completion(&this->complete);
677
678 if (this->irq <= 0) {
679 this->wait = onenand_wait;
680 return;
681 }
682
683 if (request_irq(this->irq, &onenand_interrupt,
684 IRQF_SHARED, "onenand", this)) {
685 /* If we can't get irq, use the normal wait */
686 this->wait = onenand_wait;
687 return;
688 }
689
690 /* Enable interrupt */
691 syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
692 syscfg |= ONENAND_SYS_CFG1_IOBE;
693 this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
694
695 this->wait = onenand_try_interrupt_wait;
696}
697
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100698/**
699 * onenand_bufferram_offset - [DEFAULT] BufferRAM offset
700 * @param mtd MTD data structure
701 * @param area BufferRAM area
702 * @return offset given area
703 *
704 * Return BufferRAM offset given area
705 */
706static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area)
707{
708 struct onenand_chip *this = mtd->priv;
709
710 if (ONENAND_CURRENT_BUFFERRAM(this)) {
Kyungmin Parkee9745f2007-06-30 13:57:49 +0900711 /* Note: the 'this->writesize' is a real page size */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100712 if (area == ONENAND_DATARAM)
Kyungmin Parkee9745f2007-06-30 13:57:49 +0900713 return this->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100714 if (area == ONENAND_SPARERAM)
715 return mtd->oobsize;
716 }
717
718 return 0;
719}
720
721/**
722 * onenand_read_bufferram - [OneNAND Interface] Read the bufferram area
723 * @param mtd MTD data structure
724 * @param area BufferRAM area
725 * @param buffer the databuffer to put/get data
726 * @param offset offset to read from or write to
727 * @param count number of bytes to read/write
728 *
729 * Read the BufferRAM area
730 */
731static int onenand_read_bufferram(struct mtd_info *mtd, int area,
732 unsigned char *buffer, int offset, size_t count)
733{
734 struct onenand_chip *this = mtd->priv;
735 void __iomem *bufferram;
736
737 bufferram = this->base + area;
738
739 bufferram += onenand_bufferram_offset(mtd, area);
740
Kyungmin Park9c01f87d2006-05-12 17:02:31 +0300741 if (ONENAND_CHECK_BYTE_ACCESS(count)) {
742 unsigned short word;
743
744 /* Align with word(16-bit) size */
745 count--;
746
747 /* Read word and save byte */
748 word = this->read_word(bufferram + offset + count);
749 buffer[count] = (word & 0xff);
750 }
751
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100752 memcpy(buffer, bufferram + offset, count);
753
754 return 0;
755}
756
757/**
Kyungmin Park52b0eea2005-09-03 07:07:19 +0100758 * onenand_sync_read_bufferram - [OneNAND Interface] Read the bufferram area with Sync. Burst mode
759 * @param mtd MTD data structure
760 * @param area BufferRAM area
761 * @param buffer the databuffer to put/get data
762 * @param offset offset to read from or write to
763 * @param count number of bytes to read/write
764 *
765 * Read the BufferRAM area with Sync. Burst Mode
766 */
767static int onenand_sync_read_bufferram(struct mtd_info *mtd, int area,
768 unsigned char *buffer, int offset, size_t count)
769{
770 struct onenand_chip *this = mtd->priv;
771 void __iomem *bufferram;
772
773 bufferram = this->base + area;
774
775 bufferram += onenand_bufferram_offset(mtd, area);
776
777 this->mmcontrol(mtd, ONENAND_SYS_CFG1_SYNC_READ);
778
Kyungmin Park9c01f87d2006-05-12 17:02:31 +0300779 if (ONENAND_CHECK_BYTE_ACCESS(count)) {
780 unsigned short word;
781
782 /* Align with word(16-bit) size */
783 count--;
784
785 /* Read word and save byte */
786 word = this->read_word(bufferram + offset + count);
787 buffer[count] = (word & 0xff);
788 }
789
Kyungmin Park52b0eea2005-09-03 07:07:19 +0100790 memcpy(buffer, bufferram + offset, count);
791
792 this->mmcontrol(mtd, 0);
793
794 return 0;
795}
796
797/**
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100798 * onenand_write_bufferram - [OneNAND Interface] Write the bufferram area
799 * @param mtd MTD data structure
800 * @param area BufferRAM area
801 * @param buffer the databuffer to put/get data
802 * @param offset offset to read from or write to
803 * @param count number of bytes to read/write
804 *
805 * Write the BufferRAM area
806 */
807static int onenand_write_bufferram(struct mtd_info *mtd, int area,
808 const unsigned char *buffer, int offset, size_t count)
809{
810 struct onenand_chip *this = mtd->priv;
811 void __iomem *bufferram;
812
813 bufferram = this->base + area;
814
815 bufferram += onenand_bufferram_offset(mtd, area);
816
Kyungmin Park9c01f87d2006-05-12 17:02:31 +0300817 if (ONENAND_CHECK_BYTE_ACCESS(count)) {
818 unsigned short word;
819 int byte_offset;
820
821 /* Align with word(16-bit) size */
822 count--;
823
824 /* Calculate byte access offset */
825 byte_offset = offset + count;
826
827 /* Read word and save byte */
828 word = this->read_word(bufferram + byte_offset);
829 word = (word & ~0xff) | buffer[count];
830 this->write_word(word, bufferram + byte_offset);
831 }
832
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100833 memcpy(bufferram + offset, buffer, count);
834
835 return 0;
836}
837
838/**
Kyungmin Parkee9745f2007-06-30 13:57:49 +0900839 * onenand_get_2x_blockpage - [GENERIC] Get blockpage at 2x program mode
840 * @param mtd MTD data structure
841 * @param addr address to check
842 * @return blockpage address
843 *
844 * Get blockpage address at 2x program mode
845 */
846static int onenand_get_2x_blockpage(struct mtd_info *mtd, loff_t addr)
847{
848 struct onenand_chip *this = mtd->priv;
849 int blockpage, block, page;
850
851 /* Calculate the even block number */
852 block = (int) (addr >> this->erase_shift) & ~1;
853 /* Is it the odd plane? */
854 if (addr & this->writesize)
855 block++;
856 page = (int) (addr >> (this->page_shift + 1)) & this->page_mask;
857 blockpage = (block << 7) | page;
858
859 return blockpage;
860}
861
862/**
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100863 * onenand_check_bufferram - [GENERIC] Check BufferRAM information
864 * @param mtd MTD data structure
865 * @param addr address to check
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +0000866 * @return 1 if there are valid data, otherwise 0
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100867 *
868 * Check bufferram if there is data we required
869 */
870static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr)
871{
872 struct onenand_chip *this = mtd->priv;
Adrian Huntercde36b32007-02-08 10:28:08 +0200873 int blockpage, found = 0;
Kyungmin Parkabf3c0f2007-02-02 09:29:36 +0900874 unsigned int i;
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +0000875
Kyungmin Parkee9745f2007-06-30 13:57:49 +0900876 if (ONENAND_IS_2PLANE(this))
877 blockpage = onenand_get_2x_blockpage(mtd, addr);
878 else
879 blockpage = (int) (addr >> this->page_shift);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100880
881 /* Is there valid data? */
Kyungmin Parkabf3c0f2007-02-02 09:29:36 +0900882 i = ONENAND_CURRENT_BUFFERRAM(this);
883 if (this->bufferram[i].blockpage == blockpage)
Adrian Huntercde36b32007-02-08 10:28:08 +0200884 found = 1;
885 else {
886 /* Check another BufferRAM */
887 i = ONENAND_NEXT_BUFFERRAM(this);
888 if (this->bufferram[i].blockpage == blockpage) {
889 ONENAND_SET_NEXT_BUFFERRAM(this);
890 found = 1;
891 }
Kyungmin Parkabf3c0f2007-02-02 09:29:36 +0900892 }
893
Adrian Huntercde36b32007-02-08 10:28:08 +0200894 if (found && ONENAND_IS_DDP(this)) {
895 /* Select DataRAM for DDP */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700896 int block = onenand_block(this, addr);
Adrian Huntercde36b32007-02-08 10:28:08 +0200897 int value = onenand_bufferram_address(this, block);
898 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
899 }
900
901 return found;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100902}
903
904/**
905 * onenand_update_bufferram - [GENERIC] Update BufferRAM information
906 * @param mtd MTD data structure
907 * @param addr address to update
908 * @param valid valid flag
909 *
910 * Update BufferRAM information
911 */
Kyungmin Parkabf3c0f2007-02-02 09:29:36 +0900912static void onenand_update_bufferram(struct mtd_info *mtd, loff_t addr,
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100913 int valid)
914{
915 struct onenand_chip *this = mtd->priv;
Kyungmin Parkabf3c0f2007-02-02 09:29:36 +0900916 int blockpage;
917 unsigned int i;
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +0000918
Kyungmin Parkee9745f2007-06-30 13:57:49 +0900919 if (ONENAND_IS_2PLANE(this))
920 blockpage = onenand_get_2x_blockpage(mtd, addr);
921 else
922 blockpage = (int) (addr >> this->page_shift);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100923
Kyungmin Parkabf3c0f2007-02-02 09:29:36 +0900924 /* Invalidate another BufferRAM */
925 i = ONENAND_NEXT_BUFFERRAM(this);
Kyungmin Park5b4246f2007-02-02 09:39:21 +0900926 if (this->bufferram[i].blockpage == blockpage)
Kyungmin Parkabf3c0f2007-02-02 09:29:36 +0900927 this->bufferram[i].blockpage = -1;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100928
929 /* Update BufferRAM */
930 i = ONENAND_CURRENT_BUFFERRAM(this);
Kyungmin Parkabf3c0f2007-02-02 09:29:36 +0900931 if (valid)
932 this->bufferram[i].blockpage = blockpage;
933 else
934 this->bufferram[i].blockpage = -1;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100935}
936
937/**
Adrian Hunter480b9df2007-02-07 13:55:19 +0200938 * onenand_invalidate_bufferram - [GENERIC] Invalidate BufferRAM information
939 * @param mtd MTD data structure
940 * @param addr start address to invalidate
941 * @param len length to invalidate
942 *
943 * Invalidate BufferRAM information
944 */
945static void onenand_invalidate_bufferram(struct mtd_info *mtd, loff_t addr,
946 unsigned int len)
947{
948 struct onenand_chip *this = mtd->priv;
949 int i;
950 loff_t end_addr = addr + len;
951
952 /* Invalidate BufferRAM */
953 for (i = 0; i < MAX_BUFFERRAM; i++) {
954 loff_t buf_addr = this->bufferram[i].blockpage << this->page_shift;
955 if (buf_addr >= addr && buf_addr < end_addr)
956 this->bufferram[i].blockpage = -1;
957 }
958}
959
960/**
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100961 * onenand_get_device - [GENERIC] Get chip for selected access
962 * @param mtd MTD device structure
963 * @param new_state the state which is requested
964 *
965 * Get the device and lock it for exclusive access
966 */
Kyungmin Parka41371e2005-09-29 03:55:31 +0100967static int onenand_get_device(struct mtd_info *mtd, int new_state)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100968{
969 struct onenand_chip *this = mtd->priv;
970 DECLARE_WAITQUEUE(wait, current);
971
972 /*
973 * Grab the lock and see if the device is available
974 */
975 while (1) {
976 spin_lock(&this->chip_lock);
977 if (this->state == FL_READY) {
978 this->state = new_state;
979 spin_unlock(&this->chip_lock);
Adrian Huntercf24dc82010-02-19 15:39:52 +0100980 if (new_state != FL_PM_SUSPENDED && this->enable)
981 this->enable(mtd);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100982 break;
983 }
Kyungmin Parka41371e2005-09-29 03:55:31 +0100984 if (new_state == FL_PM_SUSPENDED) {
985 spin_unlock(&this->chip_lock);
986 return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;
987 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100988 set_current_state(TASK_UNINTERRUPTIBLE);
989 add_wait_queue(&this->wq, &wait);
990 spin_unlock(&this->chip_lock);
991 schedule();
992 remove_wait_queue(&this->wq, &wait);
993 }
Kyungmin Parka41371e2005-09-29 03:55:31 +0100994
995 return 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100996}
997
998/**
999 * onenand_release_device - [GENERIC] release chip
1000 * @param mtd MTD device structure
1001 *
1002 * Deselect, release chip lock and wake up anyone waiting on the device
1003 */
1004static void onenand_release_device(struct mtd_info *mtd)
1005{
1006 struct onenand_chip *this = mtd->priv;
1007
Adrian Huntercf24dc82010-02-19 15:39:52 +01001008 if (this->state != FL_PM_SUSPENDED && this->disable)
1009 this->disable(mtd);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001010 /* Release the chip */
1011 spin_lock(&this->chip_lock);
1012 this->state = FL_READY;
1013 wake_up(&this->wq);
1014 spin_unlock(&this->chip_lock);
1015}
1016
1017/**
Brian Norris7854d3f2011-06-23 14:12:08 -07001018 * onenand_transfer_auto_oob - [INTERN] oob auto-placement transfer
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001019 * @param mtd MTD device structure
1020 * @param buf destination address
1021 * @param column oob offset to read from
1022 * @param thislen oob length to read
1023 */
1024static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int column,
1025 int thislen)
1026{
1027 struct onenand_chip *this = mtd->priv;
1028 struct nand_oobfree *free;
1029 int readcol = column;
1030 int readend = column + thislen;
1031 int lastgap = 0;
1032 unsigned int i;
1033 uint8_t *oob_buf = this->oob_buf;
1034
1035 free = this->ecclayout->oobfree;
1036 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
1037 if (readcol >= lastgap)
1038 readcol += free->offset - lastgap;
1039 if (readend >= lastgap)
1040 readend += free->offset - lastgap;
1041 lastgap = free->offset + free->length;
1042 }
1043 this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
1044 free = this->ecclayout->oobfree;
1045 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
1046 int free_end = free->offset + free->length;
1047 if (free->offset < readend && free_end > readcol) {
1048 int st = max_t(int,free->offset,readcol);
1049 int ed = min_t(int,free_end,readend);
1050 int n = ed - st;
1051 memcpy(buf, oob_buf + st, n);
1052 buf += n;
1053 } else if (column == 0)
1054 break;
1055 }
1056 return 0;
1057}
1058
1059/**
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001060 * onenand_recover_lsb - [Flex-OneNAND] Recover LSB page data
1061 * @param mtd MTD device structure
1062 * @param addr address to recover
1063 * @param status return value from onenand_wait / onenand_bbt_wait
1064 *
1065 * MLC NAND Flash cell has paired pages - LSB page and MSB page. LSB page has
1066 * lower page address and MSB page has higher page address in paired pages.
1067 * If power off occurs during MSB page program, the paired LSB page data can
1068 * become corrupt. LSB page recovery read is a way to read LSB page though page
1069 * data are corrupted. When uncorrectable error occurs as a result of LSB page
1070 * read after power up, issue LSB page recovery read.
1071 */
1072static int onenand_recover_lsb(struct mtd_info *mtd, loff_t addr, int status)
1073{
1074 struct onenand_chip *this = mtd->priv;
1075 int i;
1076
1077 /* Recovery is only for Flex-OneNAND */
1078 if (!FLEXONENAND(this))
1079 return status;
1080
1081 /* check if we failed due to uncorrectable error */
Brian Norrisd57f40542011-09-20 18:34:25 -07001082 if (!mtd_is_eccerr(status) && status != ONENAND_BBT_READ_ECC_ERROR)
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001083 return status;
1084
1085 /* check if address lies in MLC region */
1086 i = flexonenand_region(mtd, addr);
1087 if (mtd->eraseregions[i].erasesize < (1 << this->erase_shift))
1088 return status;
1089
1090 /* We are attempting to reread, so decrement stats.failed
1091 * which was incremented by onenand_wait due to read failure
1092 */
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301093 printk(KERN_INFO "%s: Attempting to recover from uncorrectable read\n",
1094 __func__);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001095 mtd->ecc_stats.failed--;
1096
1097 /* Issue the LSB page recovery command */
1098 this->command(mtd, FLEXONENAND_CMD_RECOVER_LSB, addr, this->writesize);
1099 return this->wait(mtd, FL_READING);
1100}
1101
1102/**
1103 * onenand_mlc_read_ops_nolock - MLC OneNAND read main and/or out-of-band
1104 * @param mtd MTD device structure
1105 * @param from offset to read from
1106 * @param ops: oob operation description structure
1107 *
1108 * MLC OneNAND / Flex-OneNAND has 4KB page size and 4KB dataram.
1109 * So, read-while-load is not present.
1110 */
1111static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from,
1112 struct mtd_oob_ops *ops)
1113{
1114 struct onenand_chip *this = mtd->priv;
1115 struct mtd_ecc_stats stats;
1116 size_t len = ops->len;
1117 size_t ooblen = ops->ooblen;
1118 u_char *buf = ops->datbuf;
1119 u_char *oobbuf = ops->oobbuf;
1120 int read = 0, column, thislen;
1121 int oobread = 0, oobcolumn, thisooblen, oobsize;
1122 int ret = 0;
1123 int writesize = this->writesize;
1124
Brian Norris0a32a102011-07-19 10:06:10 -07001125 pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from,
1126 (int)len);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001127
Brian Norris0612b9d2011-08-30 18:45:40 -07001128 if (ops->mode == MTD_OPS_AUTO_OOB)
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001129 oobsize = this->ecclayout->oobavail;
1130 else
1131 oobsize = mtd->oobsize;
1132
1133 oobcolumn = from & (mtd->oobsize - 1);
1134
1135 /* Do not allow reads past end of device */
1136 if (from + len > mtd->size) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301137 printk(KERN_ERR "%s: Attempt read beyond end of device\n",
1138 __func__);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001139 ops->retlen = 0;
1140 ops->oobretlen = 0;
1141 return -EINVAL;
1142 }
1143
1144 stats = mtd->ecc_stats;
1145
1146 while (read < len) {
1147 cond_resched();
1148
1149 thislen = min_t(int, writesize, len - read);
1150
1151 column = from & (writesize - 1);
1152 if (column + thislen > writesize)
1153 thislen = writesize - column;
1154
1155 if (!onenand_check_bufferram(mtd, from)) {
1156 this->command(mtd, ONENAND_CMD_READ, from, writesize);
1157
1158 ret = this->wait(mtd, FL_READING);
1159 if (unlikely(ret))
1160 ret = onenand_recover_lsb(mtd, from, ret);
1161 onenand_update_bufferram(mtd, from, !ret);
Brian Norrisd57f40542011-09-20 18:34:25 -07001162 if (mtd_is_eccerr(ret))
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001163 ret = 0;
Adrian Hunterb0850582011-02-08 12:02:38 +02001164 if (ret)
1165 break;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001166 }
1167
1168 this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
1169 if (oobbuf) {
1170 thisooblen = oobsize - oobcolumn;
1171 thisooblen = min_t(int, thisooblen, ooblen - oobread);
1172
Brian Norris0612b9d2011-08-30 18:45:40 -07001173 if (ops->mode == MTD_OPS_AUTO_OOB)
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001174 onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);
1175 else
1176 this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen);
1177 oobread += thisooblen;
1178 oobbuf += thisooblen;
1179 oobcolumn = 0;
1180 }
1181
1182 read += thislen;
1183 if (read == len)
1184 break;
1185
1186 from += thislen;
1187 buf += thislen;
1188 }
1189
1190 /*
1191 * Return success, if no ECC failures, else -EBADMSG
1192 * fs driver will take care of that, because
1193 * retlen == desired len and result == -EBADMSG
1194 */
1195 ops->retlen = read;
1196 ops->oobretlen = oobread;
1197
1198 if (ret)
1199 return ret;
1200
1201 if (mtd->ecc_stats.failed - stats.failed)
1202 return -EBADMSG;
1203
1204 return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
1205}
1206
1207/**
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001208 * onenand_read_ops_nolock - [OneNAND Interface] OneNAND read main and/or out-of-band
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001209 * @param mtd MTD device structure
1210 * @param from offset to read from
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001211 * @param ops: oob operation description structure
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001212 *
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001213 * OneNAND read main and/or out-of-band data
1214 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001215static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001216 struct mtd_oob_ops *ops)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001217{
1218 struct onenand_chip *this = mtd->priv;
Kyungmin Parkf4f91ac2006-11-16 12:03:56 +09001219 struct mtd_ecc_stats stats;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001220 size_t len = ops->len;
1221 size_t ooblen = ops->ooblen;
1222 u_char *buf = ops->datbuf;
1223 u_char *oobbuf = ops->oobbuf;
1224 int read = 0, column, thislen;
1225 int oobread = 0, oobcolumn, thisooblen, oobsize;
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001226 int ret = 0, boundary = 0;
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001227 int writesize = this->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001228
Brian Norris0a32a102011-07-19 10:06:10 -07001229 pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from,
1230 (int)len);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001231
Brian Norris0612b9d2011-08-30 18:45:40 -07001232 if (ops->mode == MTD_OPS_AUTO_OOB)
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001233 oobsize = this->ecclayout->oobavail;
1234 else
1235 oobsize = mtd->oobsize;
1236
1237 oobcolumn = from & (mtd->oobsize - 1);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001238
1239 /* Do not allow reads past end of device */
1240 if ((from + len) > mtd->size) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301241 printk(KERN_ERR "%s: Attempt read beyond end of device\n",
1242 __func__);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001243 ops->retlen = 0;
1244 ops->oobretlen = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001245 return -EINVAL;
1246 }
1247
Kyungmin Parkf4f91ac2006-11-16 12:03:56 +09001248 stats = mtd->ecc_stats;
Artem Bityutskiy61a7e192006-12-26 16:41:24 +09001249
Adrian Huntera8de85d2007-01-04 09:51:26 +02001250 /* Read-while-load method */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001251
Adrian Huntera8de85d2007-01-04 09:51:26 +02001252 /* Do first load to bufferRAM */
1253 if (read < len) {
1254 if (!onenand_check_bufferram(mtd, from)) {
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001255 this->command(mtd, ONENAND_CMD_READ, from, writesize);
Adrian Huntera8de85d2007-01-04 09:51:26 +02001256 ret = this->wait(mtd, FL_READING);
1257 onenand_update_bufferram(mtd, from, !ret);
Brian Norrisd57f40542011-09-20 18:34:25 -07001258 if (mtd_is_eccerr(ret))
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001259 ret = 0;
Adrian Huntera8de85d2007-01-04 09:51:26 +02001260 }
1261 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001262
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001263 thislen = min_t(int, writesize, len - read);
1264 column = from & (writesize - 1);
1265 if (column + thislen > writesize)
1266 thislen = writesize - column;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001267
Adrian Huntera8de85d2007-01-04 09:51:26 +02001268 while (!ret) {
1269 /* If there is more to load then start next load */
1270 from += thislen;
1271 if (read + thislen < len) {
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001272 this->command(mtd, ONENAND_CMD_READ, from, writesize);
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001273 /*
1274 * Chip boundary handling in DDP
1275 * Now we issued chip 1 read and pointed chip 1
Mika Korhonen492e1502009-06-09 21:52:35 +03001276 * bufferram so we have to point chip 0 bufferram.
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001277 */
Kyungmin Park738d61f2007-01-15 17:09:14 +09001278 if (ONENAND_IS_DDP(this) &&
1279 unlikely(from == (this->chipsize >> 1))) {
1280 this->write_word(ONENAND_DDP_CHIP0, this->base + ONENAND_REG_START_ADDRESS2);
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001281 boundary = 1;
1282 } else
1283 boundary = 0;
Adrian Huntera8de85d2007-01-04 09:51:26 +02001284 ONENAND_SET_PREV_BUFFERRAM(this);
1285 }
1286 /* While load is going, read from last bufferRAM */
1287 this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001288
1289 /* Read oob area if needed */
1290 if (oobbuf) {
1291 thisooblen = oobsize - oobcolumn;
1292 thisooblen = min_t(int, thisooblen, ooblen - oobread);
1293
Brian Norris0612b9d2011-08-30 18:45:40 -07001294 if (ops->mode == MTD_OPS_AUTO_OOB)
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001295 onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);
1296 else
1297 this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen);
1298 oobread += thisooblen;
1299 oobbuf += thisooblen;
1300 oobcolumn = 0;
1301 }
1302
Adrian Huntera8de85d2007-01-04 09:51:26 +02001303 /* See if we are done */
1304 read += thislen;
1305 if (read == len)
1306 break;
1307 /* Set up for next read from bufferRAM */
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001308 if (unlikely(boundary))
Kyungmin Park738d61f2007-01-15 17:09:14 +09001309 this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);
Adrian Huntera8de85d2007-01-04 09:51:26 +02001310 ONENAND_SET_NEXT_BUFFERRAM(this);
1311 buf += thislen;
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001312 thislen = min_t(int, writesize, len - read);
Adrian Huntera8de85d2007-01-04 09:51:26 +02001313 column = 0;
1314 cond_resched();
1315 /* Now wait for load */
1316 ret = this->wait(mtd, FL_READING);
1317 onenand_update_bufferram(mtd, from, !ret);
Brian Norrisd57f40542011-09-20 18:34:25 -07001318 if (mtd_is_eccerr(ret))
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001319 ret = 0;
Adrian Huntera8de85d2007-01-04 09:51:26 +02001320 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001321
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001322 /*
1323 * Return success, if no ECC failures, else -EBADMSG
1324 * fs driver will take care of that, because
1325 * retlen == desired len and result == -EBADMSG
1326 */
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001327 ops->retlen = read;
1328 ops->oobretlen = oobread;
Kyungmin Parkf4f91ac2006-11-16 12:03:56 +09001329
Adrian Huntera8de85d2007-01-04 09:51:26 +02001330 if (ret)
1331 return ret;
1332
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001333 if (mtd->ecc_stats.failed - stats.failed)
1334 return -EBADMSG;
1335
Kyungmin Parkf4f91ac2006-11-16 12:03:56 +09001336 return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001337}
1338
1339/**
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001340 * onenand_read_oob_nolock - [MTD Interface] OneNAND read out-of-band
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001341 * @param mtd MTD device structure
1342 * @param from offset to read from
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001343 * @param ops: oob operation description structure
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001344 *
1345 * OneNAND read out-of-band data from the spare area
1346 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001347static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
Kyungmin Park12f77c92007-08-30 09:36:05 +09001348 struct mtd_oob_ops *ops)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001349{
1350 struct onenand_chip *this = mtd->priv;
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001351 struct mtd_ecc_stats stats;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001352 int read = 0, thislen, column, oobsize;
Kyungmin Park12f77c92007-08-30 09:36:05 +09001353 size_t len = ops->ooblen;
Brian Norris905c6bc2011-08-30 18:45:39 -07001354 unsigned int mode = ops->mode;
Kyungmin Park12f77c92007-08-30 09:36:05 +09001355 u_char *buf = ops->oobbuf;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001356 int ret = 0, readcmd;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001357
Kyungmin Park12f77c92007-08-30 09:36:05 +09001358 from += ops->ooboffs;
1359
Brian Norris0a32a102011-07-19 10:06:10 -07001360 pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from,
1361 (int)len);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001362
1363 /* Initialize return length value */
Kyungmin Park12f77c92007-08-30 09:36:05 +09001364 ops->oobretlen = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001365
Brian Norris0612b9d2011-08-30 18:45:40 -07001366 if (mode == MTD_OPS_AUTO_OOB)
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001367 oobsize = this->ecclayout->oobavail;
1368 else
1369 oobsize = mtd->oobsize;
1370
1371 column = from & (mtd->oobsize - 1);
1372
1373 if (unlikely(column >= oobsize)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301374 printk(KERN_ERR "%s: Attempted to start read outside oob\n",
1375 __func__);
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001376 return -EINVAL;
1377 }
1378
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001379 /* Do not allow reads past end of device */
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001380 if (unlikely(from >= mtd->size ||
1381 column + len > ((mtd->size >> this->page_shift) -
1382 (from >> this->page_shift)) * oobsize)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301383 printk(KERN_ERR "%s: Attempted to read beyond end of device\n",
1384 __func__);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001385 return -EINVAL;
1386 }
1387
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001388 stats = mtd->ecc_stats;
1389
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001390 readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001391
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001392 while (read < len) {
Artem Bityutskiy61a7e192006-12-26 16:41:24 +09001393 cond_resched();
1394
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001395 thislen = oobsize - column;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001396 thislen = min_t(int, thislen, len);
1397
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001398 this->command(mtd, readcmd, from, mtd->oobsize);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001399
1400 onenand_update_bufferram(mtd, from, 0);
1401
1402 ret = this->wait(mtd, FL_READING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001403 if (unlikely(ret))
1404 ret = onenand_recover_lsb(mtd, from, ret);
1405
Brian Norrisd57f40542011-09-20 18:34:25 -07001406 if (ret && !mtd_is_eccerr(ret)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301407 printk(KERN_ERR "%s: read failed = 0x%x\n",
1408 __func__, ret);
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001409 break;
1410 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001411
Brian Norris0612b9d2011-08-30 18:45:40 -07001412 if (mode == MTD_OPS_AUTO_OOB)
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001413 onenand_transfer_auto_oob(mtd, buf, column, thislen);
1414 else
1415 this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001416
1417 read += thislen;
1418
1419 if (read == len)
1420 break;
1421
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001422 buf += thislen;
1423
1424 /* Read more? */
1425 if (read < len) {
1426 /* Page size */
Joern Engel28318772006-05-22 23:18:05 +02001427 from += mtd->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001428 column = 0;
1429 }
1430 }
1431
Kyungmin Park12f77c92007-08-30 09:36:05 +09001432 ops->oobretlen = read;
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001433
1434 if (ret)
1435 return ret;
1436
1437 if (mtd->ecc_stats.failed - stats.failed)
1438 return -EBADMSG;
1439
1440 return 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001441}
1442
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001443/**
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001444 * onenand_read - [MTD Interface] Read data from flash
1445 * @param mtd MTD device structure
1446 * @param from offset to read from
1447 * @param len number of bytes to read
1448 * @param retlen pointer to variable to store the number of read bytes
1449 * @param buf the databuffer to put data
1450 *
1451 * Read with ecc
1452*/
1453static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
1454 size_t *retlen, u_char *buf)
1455{
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001456 struct onenand_chip *this = mtd->priv;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001457 struct mtd_oob_ops ops = {
1458 .len = len,
1459 .ooblen = 0,
1460 .datbuf = buf,
1461 .oobbuf = NULL,
1462 };
1463 int ret;
1464
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001465 onenand_get_device(mtd, FL_READING);
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001466 ret = ONENAND_IS_4KB_PAGE(this) ?
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001467 onenand_mlc_read_ops_nolock(mtd, from, &ops) :
1468 onenand_read_ops_nolock(mtd, from, &ops);
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001469 onenand_release_device(mtd);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001470
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001471 *retlen = ops.retlen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001472 return ret;
1473}
1474
1475/**
1476 * onenand_read_oob - [MTD Interface] Read main and/or out-of-band
Kyungmin Parke3da8062007-02-15 09:36:39 +09001477 * @param mtd: MTD device structure
1478 * @param from: offset to read from
1479 * @param ops: oob operation description structure
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001480
1481 * Read main and/or out-of-band
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001482 */
1483static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
1484 struct mtd_oob_ops *ops)
1485{
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001486 struct onenand_chip *this = mtd->priv;
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001487 int ret;
1488
Kyungmin Park4f4fad22007-02-02 09:22:21 +09001489 switch (ops->mode) {
Brian Norris0612b9d2011-08-30 18:45:40 -07001490 case MTD_OPS_PLACE_OOB:
1491 case MTD_OPS_AUTO_OOB:
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001492 break;
Brian Norris0612b9d2011-08-30 18:45:40 -07001493 case MTD_OPS_RAW:
Kyungmin Park4f4fad22007-02-02 09:22:21 +09001494 /* Not implemented yet */
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001495 default:
1496 return -EINVAL;
1497 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001498
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001499 onenand_get_device(mtd, FL_READING);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001500 if (ops->datbuf)
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001501 ret = ONENAND_IS_4KB_PAGE(this) ?
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001502 onenand_mlc_read_ops_nolock(mtd, from, ops) :
1503 onenand_read_ops_nolock(mtd, from, ops);
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001504 else
1505 ret = onenand_read_oob_nolock(mtd, from, ops);
1506 onenand_release_device(mtd);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001507
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001508 return ret;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001509}
1510
Kyungmin Park211ac752007-02-07 12:15:01 +09001511/**
1512 * onenand_bbt_wait - [DEFAULT] wait until the command is done
1513 * @param mtd MTD device structure
1514 * @param state state to select the max. timeout value
1515 *
1516 * Wait for command done.
1517 */
1518static int onenand_bbt_wait(struct mtd_info *mtd, int state)
1519{
1520 struct onenand_chip *this = mtd->priv;
1521 unsigned long timeout;
Adrian Huntere0c1a922010-12-10 12:04:20 +02001522 unsigned int interrupt, ctrl, ecc, addr1, addr8;
Kyungmin Park211ac752007-02-07 12:15:01 +09001523
1524 /* The 20 msec is enough */
1525 timeout = jiffies + msecs_to_jiffies(20);
1526 while (time_before(jiffies, timeout)) {
1527 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
1528 if (interrupt & ONENAND_INT_MASTER)
1529 break;
1530 }
1531 /* To get correct interrupt status in timeout case */
1532 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
1533 ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
Adrian Huntere0c1a922010-12-10 12:04:20 +02001534 addr1 = this->read_word(this->base + ONENAND_REG_START_ADDRESS1);
1535 addr8 = this->read_word(this->base + ONENAND_REG_START_ADDRESS8);
Kyungmin Park211ac752007-02-07 12:15:01 +09001536
Kyungmin Park211ac752007-02-07 12:15:01 +09001537 if (interrupt & ONENAND_INT_READ) {
Adrian Huntere0c1a922010-12-10 12:04:20 +02001538 ecc = onenand_read_ecc(this);
Kyungmin Park83973b82008-05-29 14:52:40 +09001539 if (ecc & ONENAND_ECC_2BIT_ALL) {
Adrian Huntere0c1a922010-12-10 12:04:20 +02001540 printk(KERN_DEBUG "%s: ecc 0x%04x ctrl 0x%04x "
1541 "intr 0x%04x addr1 %#x addr8 %#x\n",
1542 __func__, ecc, ctrl, interrupt, addr1, addr8);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001543 return ONENAND_BBT_READ_ECC_ERROR;
Kyungmin Park83973b82008-05-29 14:52:40 +09001544 }
Kyungmin Park211ac752007-02-07 12:15:01 +09001545 } else {
Adrian Huntere0c1a922010-12-10 12:04:20 +02001546 printk(KERN_ERR "%s: read timeout! ctrl 0x%04x "
1547 "intr 0x%04x addr1 %#x addr8 %#x\n",
1548 __func__, ctrl, interrupt, addr1, addr8);
Kyungmin Park211ac752007-02-07 12:15:01 +09001549 return ONENAND_BBT_READ_FATAL_ERROR;
1550 }
1551
Kyungmin Park83973b82008-05-29 14:52:40 +09001552 /* Initial bad block case: 0x2400 or 0x0400 */
1553 if (ctrl & ONENAND_CTRL_ERROR) {
Adrian Huntere0c1a922010-12-10 12:04:20 +02001554 printk(KERN_DEBUG "%s: ctrl 0x%04x intr 0x%04x addr1 %#x "
1555 "addr8 %#x\n", __func__, ctrl, interrupt, addr1, addr8);
Kyungmin Park83973b82008-05-29 14:52:40 +09001556 return ONENAND_BBT_READ_ERROR;
1557 }
1558
Kyungmin Park211ac752007-02-07 12:15:01 +09001559 return 0;
1560}
1561
1562/**
1563 * onenand_bbt_read_oob - [MTD Interface] OneNAND read out-of-band for bbt scan
1564 * @param mtd MTD device structure
1565 * @param from offset to read from
Kyungmin Parke3da8062007-02-15 09:36:39 +09001566 * @param ops oob operation description structure
Kyungmin Park211ac752007-02-07 12:15:01 +09001567 *
1568 * OneNAND read out-of-band data from the spare area for bbt scan
1569 */
1570int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
1571 struct mtd_oob_ops *ops)
1572{
1573 struct onenand_chip *this = mtd->priv;
1574 int read = 0, thislen, column;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001575 int ret = 0, readcmd;
Kyungmin Park211ac752007-02-07 12:15:01 +09001576 size_t len = ops->ooblen;
1577 u_char *buf = ops->oobbuf;
1578
Brian Norris0a32a102011-07-19 10:06:10 -07001579 pr_debug("%s: from = 0x%08x, len = %zi\n", __func__, (unsigned int)from,
1580 len);
Kyungmin Park211ac752007-02-07 12:15:01 +09001581
1582 /* Initialize return value */
1583 ops->oobretlen = 0;
1584
1585 /* Do not allow reads past end of device */
1586 if (unlikely((from + len) > mtd->size)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301587 printk(KERN_ERR "%s: Attempt read beyond end of device\n",
1588 __func__);
Kyungmin Park211ac752007-02-07 12:15:01 +09001589 return ONENAND_BBT_READ_FATAL_ERROR;
1590 }
1591
1592 /* Grab the lock and see if the device is available */
1593 onenand_get_device(mtd, FL_READING);
1594
1595 column = from & (mtd->oobsize - 1);
1596
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001597 readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001598
Kyungmin Park211ac752007-02-07 12:15:01 +09001599 while (read < len) {
1600 cond_resched();
1601
1602 thislen = mtd->oobsize - column;
1603 thislen = min_t(int, thislen, len);
1604
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001605 this->command(mtd, readcmd, from, mtd->oobsize);
Kyungmin Park211ac752007-02-07 12:15:01 +09001606
1607 onenand_update_bufferram(mtd, from, 0);
1608
Kyungmin Park31bb9992009-05-12 13:46:57 -07001609 ret = this->bbt_wait(mtd, FL_READING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001610 if (unlikely(ret))
1611 ret = onenand_recover_lsb(mtd, from, ret);
1612
Kyungmin Park211ac752007-02-07 12:15:01 +09001613 if (ret)
1614 break;
1615
1616 this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
1617 read += thislen;
1618 if (read == len)
1619 break;
1620
1621 buf += thislen;
1622
1623 /* Read more? */
1624 if (read < len) {
1625 /* Update Page size */
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001626 from += this->writesize;
Kyungmin Park211ac752007-02-07 12:15:01 +09001627 column = 0;
1628 }
1629 }
1630
1631 /* Deselect and wake up anyone waiting on the device */
1632 onenand_release_device(mtd);
1633
1634 ops->oobretlen = read;
1635 return ret;
1636}
1637
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001638#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
1639/**
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001640 * onenand_verify_oob - [GENERIC] verify the oob contents after a write
1641 * @param mtd MTD device structure
1642 * @param buf the databuffer to verify
1643 * @param to offset to read from
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001644 */
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001645static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to)
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001646{
1647 struct onenand_chip *this = mtd->priv;
Kyungmin Park69d79182007-12-14 14:47:21 +09001648 u_char *oob_buf = this->oob_buf;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001649 int status, i, readcmd;
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001650
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001651 readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001652
1653 this->command(mtd, readcmd, to, mtd->oobsize);
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001654 onenand_update_bufferram(mtd, to, 0);
1655 status = this->wait(mtd, FL_READING);
1656 if (status)
1657 return status;
1658
Kyungmin Park69d79182007-12-14 14:47:21 +09001659 this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
Kyungmin Park91014e92007-02-12 10:34:39 +09001660 for (i = 0; i < mtd->oobsize; i++)
Kyungmin Park69d79182007-12-14 14:47:21 +09001661 if (buf[i] != 0xFF && buf[i] != oob_buf[i])
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001662 return -EBADMSG;
1663
1664 return 0;
1665}
1666
1667/**
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001668 * onenand_verify - [GENERIC] verify the chip contents after a write
1669 * @param mtd MTD device structure
1670 * @param buf the databuffer to verify
1671 * @param addr offset to read from
1672 * @param len number of bytes to read and compare
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001673 */
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001674static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, size_t len)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001675{
1676 struct onenand_chip *this = mtd->priv;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001677 int ret = 0;
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001678 int thislen, column;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001679
Roman Tereshonkove6da8562011-02-08 12:02:42 +02001680 column = addr & (this->writesize - 1);
1681
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001682 while (len != 0) {
Roman Tereshonkove6da8562011-02-08 12:02:42 +02001683 thislen = min_t(int, this->writesize - column, len);
Kyungmin Park60d84f92006-12-22 16:21:54 +09001684
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001685 this->command(mtd, ONENAND_CMD_READ, addr, this->writesize);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001686
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001687 onenand_update_bufferram(mtd, addr, 0);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001688
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001689 ret = this->wait(mtd, FL_READING);
1690 if (ret)
1691 return ret;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001692
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001693 onenand_update_bufferram(mtd, addr, 1);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001694
Kyungmin Park3328dc32010-04-28 17:46:47 +02001695 this->read_bufferram(mtd, ONENAND_DATARAM, this->verify_buf, 0, mtd->writesize);
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001696
Roman Tereshonkove6da8562011-02-08 12:02:42 +02001697 if (memcmp(buf, this->verify_buf + column, thislen))
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001698 return -EBADMSG;
1699
1700 len -= thislen;
1701 buf += thislen;
1702 addr += thislen;
Roman Tereshonkove6da8562011-02-08 12:02:42 +02001703 column = 0;
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001704 }
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +00001705
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001706 return 0;
1707}
1708#else
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001709#define onenand_verify(...) (0)
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001710#define onenand_verify_oob(...) (0)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001711#endif
1712
Kyungmin Park60d84f92006-12-22 16:21:54 +09001713#define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001714
Richard Purdie6c77fd62008-02-06 10:18:22 +00001715static void onenand_panic_wait(struct mtd_info *mtd)
1716{
1717 struct onenand_chip *this = mtd->priv;
1718 unsigned int interrupt;
1719 int i;
1720
1721 for (i = 0; i < 2000; i++) {
1722 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
1723 if (interrupt & ONENAND_INT_MASTER)
1724 break;
1725 udelay(10);
1726 }
1727}
1728
1729/**
1730 * onenand_panic_write - [MTD Interface] write buffer to FLASH in a panic context
1731 * @param mtd MTD device structure
1732 * @param to offset to write to
1733 * @param len number of bytes to write
1734 * @param retlen pointer to variable to store the number of written bytes
1735 * @param buf the data to write
1736 *
1737 * Write with ECC
1738 */
1739static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
1740 size_t *retlen, const u_char *buf)
1741{
1742 struct onenand_chip *this = mtd->priv;
1743 int column, subpage;
1744 int written = 0;
1745 int ret = 0;
1746
1747 if (this->state == FL_PM_SUSPENDED)
1748 return -EBUSY;
1749
1750 /* Wait for any existing operation to clear */
1751 onenand_panic_wait(mtd);
1752
Brian Norris0a32a102011-07-19 10:06:10 -07001753 pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to,
1754 (int)len);
Richard Purdie6c77fd62008-02-06 10:18:22 +00001755
1756 /* Initialize retlen, in case of early exit */
1757 *retlen = 0;
1758
1759 /* Do not allow writes past end of device */
1760 if (unlikely((to + len) > mtd->size)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301761 printk(KERN_ERR "%s: Attempt write to past end of device\n",
1762 __func__);
Richard Purdie6c77fd62008-02-06 10:18:22 +00001763 return -EINVAL;
1764 }
1765
1766 /* Reject writes, which are not page aligned */
Roel Kluinb73d7e432008-02-16 18:14:35 +01001767 if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301768 printk(KERN_ERR "%s: Attempt to write not page aligned data\n",
1769 __func__);
Richard Purdie6c77fd62008-02-06 10:18:22 +00001770 return -EINVAL;
1771 }
1772
1773 column = to & (mtd->writesize - 1);
1774
1775 /* Loop until all data write */
1776 while (written < len) {
1777 int thislen = min_t(int, mtd->writesize - column, len - written);
1778 u_char *wbuf = (u_char *) buf;
1779
1780 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
1781
1782 /* Partial page write */
1783 subpage = thislen < mtd->writesize;
1784 if (subpage) {
1785 memset(this->page_buf, 0xff, mtd->writesize);
1786 memcpy(this->page_buf + column, buf, thislen);
1787 wbuf = this->page_buf;
1788 }
1789
1790 this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
1791 this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);
1792
1793 this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
1794
1795 onenand_panic_wait(mtd);
1796
1797 /* In partial page write we don't update bufferram */
1798 onenand_update_bufferram(mtd, to, !ret && !subpage);
1799 if (ONENAND_IS_2PLANE(this)) {
1800 ONENAND_SET_BUFFERRAM1(this);
1801 onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage);
1802 }
1803
1804 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301805 printk(KERN_ERR "%s: write failed %d\n", __func__, ret);
Richard Purdie6c77fd62008-02-06 10:18:22 +00001806 break;
1807 }
1808
1809 written += thislen;
1810
1811 if (written == len)
1812 break;
1813
1814 column = 0;
1815 to += thislen;
1816 buf += thislen;
1817 }
1818
1819 *retlen = written;
1820 return ret;
1821}
1822
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001823/**
Brian Norris7854d3f2011-06-23 14:12:08 -07001824 * onenand_fill_auto_oob - [INTERN] oob auto-placement transfer
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001825 * @param mtd MTD device structure
1826 * @param oob_buf oob buffer
1827 * @param buf source address
1828 * @param column oob offset to write to
1829 * @param thislen oob length to write
1830 */
1831static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
1832 const u_char *buf, int column, int thislen)
1833{
1834 struct onenand_chip *this = mtd->priv;
1835 struct nand_oobfree *free;
1836 int writecol = column;
1837 int writeend = column + thislen;
1838 int lastgap = 0;
Kyungmin Parkad286342007-03-23 10:19:52 +09001839 unsigned int i;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001840
Kyungmin Parkad286342007-03-23 10:19:52 +09001841 free = this->ecclayout->oobfree;
1842 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001843 if (writecol >= lastgap)
1844 writecol += free->offset - lastgap;
1845 if (writeend >= lastgap)
1846 writeend += free->offset - lastgap;
1847 lastgap = free->offset + free->length;
1848 }
Kyungmin Parkad286342007-03-23 10:19:52 +09001849 free = this->ecclayout->oobfree;
1850 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001851 int free_end = free->offset + free->length;
1852 if (free->offset < writeend && free_end > writecol) {
1853 int st = max_t(int,free->offset,writecol);
1854 int ed = min_t(int,free_end,writeend);
1855 int n = ed - st;
1856 memcpy(oob_buf + st, buf, n);
1857 buf += n;
Adrian Hunterc36c46d2007-03-23 17:16:22 +09001858 } else if (column == 0)
Kyungmin Park5bc399e2007-03-09 09:41:07 +09001859 break;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001860 }
1861 return 0;
1862}
1863
1864/**
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001865 * onenand_write_ops_nolock - [OneNAND Interface] write main and/or out-of-band
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001866 * @param mtd MTD device structure
1867 * @param to offset to write to
1868 * @param ops oob operation description structure
1869 *
1870 * Write main and/or oob with ECC
1871 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001872static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001873 struct mtd_oob_ops *ops)
1874{
1875 struct onenand_chip *this = mtd->priv;
Kyungmin Park9ce96902008-11-17 17:54:28 +09001876 int written = 0, column, thislen = 0, subpage = 0;
1877 int prev = 0, prevlen = 0, prev_subpage = 0, first = 1;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001878 int oobwritten = 0, oobcolumn, thisooblen, oobsize;
1879 size_t len = ops->len;
1880 size_t ooblen = ops->ooblen;
1881 const u_char *buf = ops->datbuf;
1882 const u_char *oob = ops->oobbuf;
1883 u_char *oobbuf;
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02001884 int ret = 0, cmd;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001885
Brian Norris0a32a102011-07-19 10:06:10 -07001886 pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to,
1887 (int)len);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001888
1889 /* Initialize retlen, in case of early exit */
1890 ops->retlen = 0;
1891 ops->oobretlen = 0;
1892
1893 /* Do not allow writes past end of device */
1894 if (unlikely((to + len) > mtd->size)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301895 printk(KERN_ERR "%s: Attempt write to past end of device\n",
1896 __func__);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001897 return -EINVAL;
1898 }
1899
1900 /* Reject writes, which are not page aligned */
Roel Kluinb73d7e432008-02-16 18:14:35 +01001901 if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301902 printk(KERN_ERR "%s: Attempt to write not page aligned data\n",
1903 __func__);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001904 return -EINVAL;
1905 }
1906
Kyungmin Park9ce96902008-11-17 17:54:28 +09001907 /* Check zero length */
1908 if (!len)
1909 return 0;
1910
Brian Norris0612b9d2011-08-30 18:45:40 -07001911 if (ops->mode == MTD_OPS_AUTO_OOB)
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001912 oobsize = this->ecclayout->oobavail;
1913 else
1914 oobsize = mtd->oobsize;
1915
1916 oobcolumn = to & (mtd->oobsize - 1);
1917
1918 column = to & (mtd->writesize - 1);
1919
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001920 /* Loop until all data write */
Kyungmin Park9ce96902008-11-17 17:54:28 +09001921 while (1) {
1922 if (written < len) {
1923 u_char *wbuf = (u_char *) buf;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001924
Kyungmin Park9ce96902008-11-17 17:54:28 +09001925 thislen = min_t(int, mtd->writesize - column, len - written);
1926 thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001927
Kyungmin Park9ce96902008-11-17 17:54:28 +09001928 cond_resched();
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001929
Kyungmin Park9ce96902008-11-17 17:54:28 +09001930 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001931
Kyungmin Park9ce96902008-11-17 17:54:28 +09001932 /* Partial page write */
1933 subpage = thislen < mtd->writesize;
1934 if (subpage) {
1935 memset(this->page_buf, 0xff, mtd->writesize);
1936 memcpy(this->page_buf + column, buf, thislen);
1937 wbuf = this->page_buf;
1938 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001939
Kyungmin Park9ce96902008-11-17 17:54:28 +09001940 this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001941
Kyungmin Park9ce96902008-11-17 17:54:28 +09001942 if (oob) {
1943 oobbuf = this->oob_buf;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001944
Kyungmin Park9ce96902008-11-17 17:54:28 +09001945 /* We send data to spare ram with oobsize
1946 * to prevent byte access */
1947 memset(oobbuf, 0xff, mtd->oobsize);
Brian Norris0612b9d2011-08-30 18:45:40 -07001948 if (ops->mode == MTD_OPS_AUTO_OOB)
Kyungmin Park9ce96902008-11-17 17:54:28 +09001949 onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
1950 else
1951 memcpy(oobbuf + oobcolumn, oob, thisooblen);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001952
Kyungmin Park9ce96902008-11-17 17:54:28 +09001953 oobwritten += thisooblen;
1954 oob += thisooblen;
1955 oobcolumn = 0;
1956 } else
1957 oobbuf = (u_char *) ffchars;
1958
1959 this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001960 } else
Kyungmin Park9ce96902008-11-17 17:54:28 +09001961 ONENAND_SET_NEXT_BUFFERRAM(this);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001962
Kyungmin Park9ce96902008-11-17 17:54:28 +09001963 /*
Mika Korhonen492e1502009-06-09 21:52:35 +03001964 * 2 PLANE, MLC, and Flex-OneNAND do not support
1965 * write-while-program feature.
Kyungmin Park9ce96902008-11-17 17:54:28 +09001966 */
Kyungmin Park6a88c472010-04-28 17:46:45 +02001967 if (!ONENAND_IS_2PLANE(this) && !ONENAND_IS_4KB_PAGE(this) && !first) {
Kyungmin Park9ce96902008-11-17 17:54:28 +09001968 ONENAND_SET_PREV_BUFFERRAM(this);
1969
1970 ret = this->wait(mtd, FL_WRITING);
1971
1972 /* In partial page write we don't update bufferram */
1973 onenand_update_bufferram(mtd, prev, !ret && !prev_subpage);
1974 if (ret) {
1975 written -= prevlen;
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301976 printk(KERN_ERR "%s: write failed %d\n",
1977 __func__, ret);
Kyungmin Park9ce96902008-11-17 17:54:28 +09001978 break;
1979 }
1980
1981 if (written == len) {
1982 /* Only check verify write turn on */
1983 ret = onenand_verify(mtd, buf - len, to - len, len);
1984 if (ret)
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301985 printk(KERN_ERR "%s: verify failed %d\n",
1986 __func__, ret);
Kyungmin Park9ce96902008-11-17 17:54:28 +09001987 break;
1988 }
1989
1990 ONENAND_SET_NEXT_BUFFERRAM(this);
1991 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001992
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02001993 this->ongoing = 0;
1994 cmd = ONENAND_CMD_PROG;
1995
1996 /* Exclude 1st OTP and OTP blocks for cache program feature */
1997 if (ONENAND_IS_CACHE_PROGRAM(this) &&
1998 likely(onenand_block(this, to) != 0) &&
1999 ONENAND_IS_4KB_PAGE(this) &&
2000 ((written + thislen) < len)) {
2001 cmd = ONENAND_CMD_2X_CACHE_PROG;
2002 this->ongoing = 1;
2003 }
2004
2005 this->command(mtd, cmd, to, mtd->writesize);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002006
Kyungmin Park9ce96902008-11-17 17:54:28 +09002007 /*
2008 * 2 PLANE, MLC, and Flex-OneNAND wait here
2009 */
Kyungmin Park6a88c472010-04-28 17:46:45 +02002010 if (ONENAND_IS_2PLANE(this) || ONENAND_IS_4KB_PAGE(this)) {
Kyungmin Park9ce96902008-11-17 17:54:28 +09002011 ret = this->wait(mtd, FL_WRITING);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002012
Kyungmin Park9ce96902008-11-17 17:54:28 +09002013 /* In partial page write we don't update bufferram */
2014 onenand_update_bufferram(mtd, to, !ret && !subpage);
2015 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302016 printk(KERN_ERR "%s: write failed %d\n",
2017 __func__, ret);
Kyungmin Park9ce96902008-11-17 17:54:28 +09002018 break;
2019 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002020
Kyungmin Park9ce96902008-11-17 17:54:28 +09002021 /* Only check verify write turn on */
2022 ret = onenand_verify(mtd, buf, to, thislen);
2023 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302024 printk(KERN_ERR "%s: verify failed %d\n",
2025 __func__, ret);
Kyungmin Park9ce96902008-11-17 17:54:28 +09002026 break;
2027 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002028
Kyungmin Park9ce96902008-11-17 17:54:28 +09002029 written += thislen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002030
Kyungmin Park9ce96902008-11-17 17:54:28 +09002031 if (written == len)
2032 break;
2033
2034 } else
2035 written += thislen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002036
2037 column = 0;
Kyungmin Park9ce96902008-11-17 17:54:28 +09002038 prev_subpage = subpage;
2039 prev = to;
2040 prevlen = thislen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002041 to += thislen;
2042 buf += thislen;
Kyungmin Park9ce96902008-11-17 17:54:28 +09002043 first = 0;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002044 }
2045
Kyungmin Park9ce96902008-11-17 17:54:28 +09002046 /* In error case, clear all bufferrams */
2047 if (written != len)
2048 onenand_invalidate_bufferram(mtd, 0, -1);
2049
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002050 ops->retlen = written;
Kyungmin Park9ce96902008-11-17 17:54:28 +09002051 ops->oobretlen = oobwritten;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002052
2053 return ret;
2054}
2055
2056
2057/**
Brian Norris7854d3f2011-06-23 14:12:08 -07002058 * onenand_write_oob_nolock - [INTERN] OneNAND write out-of-band
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002059 * @param mtd MTD device structure
2060 * @param to offset to write to
2061 * @param len number of bytes to write
2062 * @param retlen pointer to variable to store the number of written bytes
2063 * @param buf the data to write
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002064 * @param mode operation mode
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002065 *
2066 * OneNAND write out-of-band
2067 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002068static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
2069 struct mtd_oob_ops *ops)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002070{
2071 struct onenand_chip *this = mtd->priv;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002072 int column, ret = 0, oobsize;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002073 int written = 0, oobcmd;
Kyungmin Park91014e92007-02-12 10:34:39 +09002074 u_char *oobbuf;
Kyungmin Park12f77c92007-08-30 09:36:05 +09002075 size_t len = ops->ooblen;
2076 const u_char *buf = ops->oobbuf;
Brian Norris905c6bc2011-08-30 18:45:39 -07002077 unsigned int mode = ops->mode;
Kyungmin Park12f77c92007-08-30 09:36:05 +09002078
2079 to += ops->ooboffs;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002080
Brian Norris0a32a102011-07-19 10:06:10 -07002081 pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to,
2082 (int)len);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002083
2084 /* Initialize retlen, in case of early exit */
Kyungmin Park12f77c92007-08-30 09:36:05 +09002085 ops->oobretlen = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002086
Brian Norris0612b9d2011-08-30 18:45:40 -07002087 if (mode == MTD_OPS_AUTO_OOB)
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002088 oobsize = this->ecclayout->oobavail;
2089 else
2090 oobsize = mtd->oobsize;
2091
2092 column = to & (mtd->oobsize - 1);
2093
2094 if (unlikely(column >= oobsize)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302095 printk(KERN_ERR "%s: Attempted to start write outside oob\n",
2096 __func__);
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002097 return -EINVAL;
2098 }
2099
Adrian Hunter52e42002007-02-06 09:15:39 +09002100 /* For compatibility with NAND: Do not allow write past end of page */
Kyungmin Park91014e92007-02-12 10:34:39 +09002101 if (unlikely(column + len > oobsize)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302102 printk(KERN_ERR "%s: Attempt to write past end of page\n",
2103 __func__);
Adrian Hunter52e42002007-02-06 09:15:39 +09002104 return -EINVAL;
2105 }
2106
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002107 /* Do not allow reads past end of device */
2108 if (unlikely(to >= mtd->size ||
2109 column + len > ((mtd->size >> this->page_shift) -
2110 (to >> this->page_shift)) * oobsize)) {
David Woodhouse80327472009-10-05 08:30:04 +01002111 printk(KERN_ERR "%s: Attempted to write past end of device\n",
2112 __func__);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002113 return -EINVAL;
2114 }
2115
Kyungmin Park470bc842007-03-09 10:08:11 +09002116 oobbuf = this->oob_buf;
Kyungmin Park91014e92007-02-12 10:34:39 +09002117
Kyungmin Park8a8f6322010-12-02 09:24:16 +09002118 oobcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002119
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002120 /* Loop until all data write */
2121 while (written < len) {
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002122 int thislen = min_t(int, oobsize, len - written);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002123
Artem Bityutskiy61a7e192006-12-26 16:41:24 +09002124 cond_resched();
2125
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002126 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize);
2127
Kyungmin Park34c10602006-05-12 17:02:46 +03002128 /* We send data to spare ram with oobsize
2129 * to prevent byte access */
Kyungmin Park91014e92007-02-12 10:34:39 +09002130 memset(oobbuf, 0xff, mtd->oobsize);
Brian Norris0612b9d2011-08-30 18:45:40 -07002131 if (mode == MTD_OPS_AUTO_OOB)
Kyungmin Park91014e92007-02-12 10:34:39 +09002132 onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen);
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002133 else
Kyungmin Park91014e92007-02-12 10:34:39 +09002134 memcpy(oobbuf + column, buf, thislen);
2135 this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002136
Kyungmin Park8a8f6322010-12-02 09:24:16 +09002137 if (ONENAND_IS_4KB_PAGE(this)) {
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002138 /* Set main area of DataRAM to 0xff*/
2139 memset(this->page_buf, 0xff, mtd->writesize);
2140 this->write_bufferram(mtd, ONENAND_DATARAM,
2141 this->page_buf, 0, mtd->writesize);
2142 }
2143
2144 this->command(mtd, oobcmd, to, mtd->oobsize);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002145
2146 onenand_update_bufferram(mtd, to, 0);
Kyungmin Parkee9745f2007-06-30 13:57:49 +09002147 if (ONENAND_IS_2PLANE(this)) {
2148 ONENAND_SET_BUFFERRAM1(this);
2149 onenand_update_bufferram(mtd, to + this->writesize, 0);
2150 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002151
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002152 ret = this->wait(mtd, FL_WRITING);
2153 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302154 printk(KERN_ERR "%s: write failed %d\n", __func__, ret);
Kyungmin Park5b4246f2007-02-02 09:39:21 +09002155 break;
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002156 }
2157
Kyungmin Park91014e92007-02-12 10:34:39 +09002158 ret = onenand_verify_oob(mtd, oobbuf, to);
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002159 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302160 printk(KERN_ERR "%s: verify failed %d\n",
2161 __func__, ret);
Kyungmin Park5b4246f2007-02-02 09:39:21 +09002162 break;
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002163 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002164
2165 written += thislen;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002166 if (written == len)
2167 break;
2168
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002169 to += mtd->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002170 buf += thislen;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002171 column = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002172 }
2173
Kyungmin Park12f77c92007-08-30 09:36:05 +09002174 ops->oobretlen = written;
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +00002175
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002176 return ret;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002177}
2178
2179/**
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002180 * onenand_write - [MTD Interface] write buffer to FLASH
2181 * @param mtd MTD device structure
2182 * @param to offset to write to
2183 * @param len number of bytes to write
2184 * @param retlen pointer to variable to store the number of written bytes
2185 * @param buf the data to write
2186 *
2187 * Write with ECC
2188 */
2189static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
2190 size_t *retlen, const u_char *buf)
2191{
2192 struct mtd_oob_ops ops = {
2193 .len = len,
2194 .ooblen = 0,
2195 .datbuf = (u_char *) buf,
2196 .oobbuf = NULL,
2197 };
2198 int ret;
2199
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002200 onenand_get_device(mtd, FL_WRITING);
2201 ret = onenand_write_ops_nolock(mtd, to, &ops);
2202 onenand_release_device(mtd);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002203
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002204 *retlen = ops.retlen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002205 return ret;
2206}
2207
2208/**
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02002209 * onenand_write_oob - [MTD Interface] NAND write data and/or out-of-band
Kyungmin Parke3da8062007-02-15 09:36:39 +09002210 * @param mtd: MTD device structure
2211 * @param to: offset to write
2212 * @param ops: oob operation description structure
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02002213 */
2214static int onenand_write_oob(struct mtd_info *mtd, loff_t to,
2215 struct mtd_oob_ops *ops)
2216{
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002217 int ret;
2218
Kyungmin Park4f4fad22007-02-02 09:22:21 +09002219 switch (ops->mode) {
Brian Norris0612b9d2011-08-30 18:45:40 -07002220 case MTD_OPS_PLACE_OOB:
2221 case MTD_OPS_AUTO_OOB:
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002222 break;
Brian Norris0612b9d2011-08-30 18:45:40 -07002223 case MTD_OPS_RAW:
Kyungmin Park4f4fad22007-02-02 09:22:21 +09002224 /* Not implemented yet */
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002225 default:
2226 return -EINVAL;
2227 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002228
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002229 onenand_get_device(mtd, FL_WRITING);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002230 if (ops->datbuf)
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002231 ret = onenand_write_ops_nolock(mtd, to, ops);
2232 else
2233 ret = onenand_write_oob_nolock(mtd, to, ops);
2234 onenand_release_device(mtd);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002235
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002236 return ret;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02002237}
2238
2239/**
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002240 * onenand_block_isbad_nolock - [GENERIC] Check if a block is marked bad
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002241 * @param mtd MTD device structure
2242 * @param ofs offset from device start
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002243 * @param allowbbt 1, if its allowed to access the bbt area
2244 *
2245 * Check, if the block is bad. Either by reading the bad block table or
2246 * calling of the scan function.
2247 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002248static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int allowbbt)
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002249{
2250 struct onenand_chip *this = mtd->priv;
2251 struct bbm_info *bbm = this->bbm;
2252
2253 /* Return info from the table */
2254 return bbm->isbad_bbt(mtd, ofs, allowbbt);
2255}
2256
Mika Korhonen72073022009-10-23 07:50:43 +02002257
2258static int onenand_multiblock_erase_verify(struct mtd_info *mtd,
2259 struct erase_info *instr)
2260{
2261 struct onenand_chip *this = mtd->priv;
2262 loff_t addr = instr->addr;
2263 int len = instr->len;
2264 unsigned int block_size = (1 << this->erase_shift);
2265 int ret = 0;
2266
2267 while (len) {
2268 this->command(mtd, ONENAND_CMD_ERASE_VERIFY, addr, block_size);
2269 ret = this->wait(mtd, FL_VERIFYING_ERASE);
2270 if (ret) {
2271 printk(KERN_ERR "%s: Failed verify, block %d\n",
2272 __func__, onenand_block(this, addr));
2273 instr->state = MTD_ERASE_FAILED;
2274 instr->fail_addr = addr;
2275 return -1;
2276 }
2277 len -= block_size;
2278 addr += block_size;
2279 }
2280 return 0;
2281}
2282
2283/**
Brian Norris7854d3f2011-06-23 14:12:08 -07002284 * onenand_multiblock_erase - [INTERN] erase block(s) using multiblock erase
Mika Korhonen72073022009-10-23 07:50:43 +02002285 * @param mtd MTD device structure
2286 * @param instr erase instruction
2287 * @param region erase region
2288 *
2289 * Erase one or more blocks up to 64 block at a time
2290 */
2291static int onenand_multiblock_erase(struct mtd_info *mtd,
2292 struct erase_info *instr,
2293 unsigned int block_size)
2294{
2295 struct onenand_chip *this = mtd->priv;
2296 loff_t addr = instr->addr;
2297 int len = instr->len;
2298 int eb_count = 0;
2299 int ret = 0;
2300 int bdry_block = 0;
2301
2302 instr->state = MTD_ERASING;
2303
2304 if (ONENAND_IS_DDP(this)) {
2305 loff_t bdry_addr = this->chipsize >> 1;
2306 if (addr < bdry_addr && (addr + len) > bdry_addr)
2307 bdry_block = bdry_addr >> this->erase_shift;
2308 }
2309
2310 /* Pre-check bbs */
2311 while (len) {
2312 /* Check if we have a bad block, we do not erase bad blocks */
2313 if (onenand_block_isbad_nolock(mtd, addr, 0)) {
2314 printk(KERN_WARNING "%s: attempt to erase a bad block "
2315 "at addr 0x%012llx\n",
2316 __func__, (unsigned long long) addr);
2317 instr->state = MTD_ERASE_FAILED;
2318 return -EIO;
2319 }
2320 len -= block_size;
2321 addr += block_size;
2322 }
2323
2324 len = instr->len;
2325 addr = instr->addr;
2326
2327 /* loop over 64 eb batches */
2328 while (len) {
2329 struct erase_info verify_instr = *instr;
2330 int max_eb_count = MB_ERASE_MAX_BLK_COUNT;
2331
2332 verify_instr.addr = addr;
2333 verify_instr.len = 0;
2334
2335 /* do not cross chip boundary */
2336 if (bdry_block) {
2337 int this_block = (addr >> this->erase_shift);
2338
2339 if (this_block < bdry_block) {
2340 max_eb_count = min(max_eb_count,
2341 (bdry_block - this_block));
2342 }
2343 }
2344
2345 eb_count = 0;
2346
2347 while (len > block_size && eb_count < (max_eb_count - 1)) {
2348 this->command(mtd, ONENAND_CMD_MULTIBLOCK_ERASE,
2349 addr, block_size);
2350 onenand_invalidate_bufferram(mtd, addr, block_size);
2351
2352 ret = this->wait(mtd, FL_PREPARING_ERASE);
2353 if (ret) {
2354 printk(KERN_ERR "%s: Failed multiblock erase, "
2355 "block %d\n", __func__,
2356 onenand_block(this, addr));
2357 instr->state = MTD_ERASE_FAILED;
2358 instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
2359 return -EIO;
2360 }
2361
2362 len -= block_size;
2363 addr += block_size;
2364 eb_count++;
2365 }
2366
2367 /* last block of 64-eb series */
2368 cond_resched();
2369 this->command(mtd, ONENAND_CMD_ERASE, addr, block_size);
2370 onenand_invalidate_bufferram(mtd, addr, block_size);
2371
2372 ret = this->wait(mtd, FL_ERASING);
2373 /* Check if it is write protected */
2374 if (ret) {
2375 printk(KERN_ERR "%s: Failed erase, block %d\n",
2376 __func__, onenand_block(this, addr));
2377 instr->state = MTD_ERASE_FAILED;
2378 instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
2379 return -EIO;
2380 }
2381
2382 len -= block_size;
2383 addr += block_size;
2384 eb_count++;
2385
2386 /* verify */
2387 verify_instr.len = eb_count * block_size;
2388 if (onenand_multiblock_erase_verify(mtd, &verify_instr)) {
2389 instr->state = verify_instr.state;
2390 instr->fail_addr = verify_instr.fail_addr;
2391 return -EIO;
2392 }
2393
2394 }
2395 return 0;
2396}
2397
2398
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002399/**
Brian Norris7854d3f2011-06-23 14:12:08 -07002400 * onenand_block_by_block_erase - [INTERN] erase block(s) using regular erase
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002401 * @param mtd MTD device structure
2402 * @param instr erase instruction
Mika Korhonen73885ae2009-10-23 07:50:42 +02002403 * @param region erase region
2404 * @param block_size erase block size
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002405 *
Mika Korhonen73885ae2009-10-23 07:50:42 +02002406 * Erase one or more blocks one block at a time
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002407 */
Mika Korhonen73885ae2009-10-23 07:50:42 +02002408static int onenand_block_by_block_erase(struct mtd_info *mtd,
2409 struct erase_info *instr,
2410 struct mtd_erase_region_info *region,
2411 unsigned int block_size)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002412{
2413 struct onenand_chip *this = mtd->priv;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002414 loff_t addr = instr->addr;
Mika Korhonen73885ae2009-10-23 07:50:42 +02002415 int len = instr->len;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002416 loff_t region_end = 0;
Mika Korhonen73885ae2009-10-23 07:50:42 +02002417 int ret = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002418
Mika Korhonen73885ae2009-10-23 07:50:42 +02002419 if (region) {
2420 /* region is set for Flex-OneNAND */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002421 region_end = region->offset + region->erasesize * region->numblocks;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002422 }
2423
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002424 instr->state = MTD_ERASING;
2425
Mika Korhonen73885ae2009-10-23 07:50:42 +02002426 /* Loop through the blocks */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002427 while (len) {
Artem Bityutskiy61a7e192006-12-26 16:41:24 +09002428 cond_resched();
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002429
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002430 /* Check if we have a bad block, we do not erase bad blocks */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002431 if (onenand_block_isbad_nolock(mtd, addr, 0)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302432 printk(KERN_WARNING "%s: attempt to erase a bad block "
2433 "at addr 0x%012llx\n",
2434 __func__, (unsigned long long) addr);
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002435 instr->state = MTD_ERASE_FAILED;
Mika Korhonen73885ae2009-10-23 07:50:42 +02002436 return -EIO;
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002437 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002438
2439 this->command(mtd, ONENAND_CMD_ERASE, addr, block_size);
2440
Adrian Hunter480b9df2007-02-07 13:55:19 +02002441 onenand_invalidate_bufferram(mtd, addr, block_size);
2442
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002443 ret = this->wait(mtd, FL_ERASING);
2444 /* Check, if it is write protected */
2445 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302446 printk(KERN_ERR "%s: Failed erase, block %d\n",
2447 __func__, onenand_block(this, addr));
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002448 instr->state = MTD_ERASE_FAILED;
2449 instr->fail_addr = addr;
Mika Korhonen73885ae2009-10-23 07:50:42 +02002450 return -EIO;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002451 }
2452
2453 len -= block_size;
2454 addr += block_size;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002455
john.maxin@nokia.comeff3bba2011-05-06 09:17:21 +00002456 if (region && addr == region_end) {
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002457 if (!len)
2458 break;
2459 region++;
2460
2461 block_size = region->erasesize;
2462 region_end = region->offset + region->erasesize * region->numblocks;
2463
2464 if (len & (block_size - 1)) {
2465 /* FIXME: This should be handled at MTD partitioning level. */
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302466 printk(KERN_ERR "%s: Unaligned address\n",
2467 __func__);
Mika Korhonen73885ae2009-10-23 07:50:42 +02002468 return -EIO;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002469 }
2470 }
Mika Korhonen73885ae2009-10-23 07:50:42 +02002471 }
2472 return 0;
2473}
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002474
Mika Korhonen73885ae2009-10-23 07:50:42 +02002475/**
2476 * onenand_erase - [MTD Interface] erase block(s)
2477 * @param mtd MTD device structure
2478 * @param instr erase instruction
2479 *
2480 * Erase one or more blocks
2481 */
2482static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
2483{
2484 struct onenand_chip *this = mtd->priv;
2485 unsigned int block_size;
2486 loff_t addr = instr->addr;
2487 loff_t len = instr->len;
2488 int ret = 0;
2489 struct mtd_erase_region_info *region = NULL;
2490 loff_t region_offset = 0;
2491
Brian Norris289c0522011-07-19 10:06:09 -07002492 pr_debug("%s: start=0x%012llx, len=%llu\n", __func__,
Brian Norris0a32a102011-07-19 10:06:10 -07002493 (unsigned long long)instr->addr,
2494 (unsigned long long)instr->len);
Mika Korhonen73885ae2009-10-23 07:50:42 +02002495
2496 /* Do not allow erase past end of device */
2497 if (unlikely((len + addr) > mtd->size)) {
2498 printk(KERN_ERR "%s: Erase past end of device\n", __func__);
2499 return -EINVAL;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002500 }
2501
Mika Korhonen73885ae2009-10-23 07:50:42 +02002502 if (FLEXONENAND(this)) {
2503 /* Find the eraseregion of this address */
2504 int i = flexonenand_region(mtd, addr);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002505
Mika Korhonen73885ae2009-10-23 07:50:42 +02002506 region = &mtd->eraseregions[i];
2507 block_size = region->erasesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002508
Mika Korhonen73885ae2009-10-23 07:50:42 +02002509 /* Start address within region must align on block boundary.
2510 * Erase region's start offset is always block start address.
2511 */
2512 region_offset = region->offset;
2513 } else
2514 block_size = 1 << this->erase_shift;
2515
2516 /* Start address must align on block boundary */
2517 if (unlikely((addr - region_offset) & (block_size - 1))) {
2518 printk(KERN_ERR "%s: Unaligned address\n", __func__);
2519 return -EINVAL;
2520 }
2521
2522 /* Length must align on block boundary */
2523 if (unlikely(len & (block_size - 1))) {
2524 printk(KERN_ERR "%s: Length not block aligned\n", __func__);
2525 return -EINVAL;
2526 }
2527
2528 instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
2529
2530 /* Grab the lock and see if the device is available */
2531 onenand_get_device(mtd, FL_ERASING);
2532
Kyungmin Parkd983c542010-12-06 09:05:18 +09002533 if (ONENAND_IS_4KB_PAGE(this) || region ||
2534 instr->len < MB_ERASE_MIN_BLK_COUNT * block_size) {
Mika Korhonen72073022009-10-23 07:50:43 +02002535 /* region is set for Flex-OneNAND (no mb erase) */
2536 ret = onenand_block_by_block_erase(mtd, instr,
2537 region, block_size);
2538 } else {
2539 ret = onenand_multiblock_erase(mtd, instr, block_size);
2540 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002541
2542 /* Deselect and wake up anyone waiting on the device */
2543 onenand_release_device(mtd);
2544
Adrian Hunter3cd3a862007-10-12 10:34:01 +03002545 /* Do call back function */
Mika Korhonen73885ae2009-10-23 07:50:42 +02002546 if (!ret) {
2547 instr->state = MTD_ERASE_DONE;
Adrian Hunter3cd3a862007-10-12 10:34:01 +03002548 mtd_erase_callback(instr);
Mika Korhonen73885ae2009-10-23 07:50:42 +02002549 }
Adrian Hunter3cd3a862007-10-12 10:34:01 +03002550
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002551 return ret;
2552}
2553
2554/**
2555 * onenand_sync - [MTD Interface] sync
2556 * @param mtd MTD device structure
2557 *
2558 * Sync is actually a wait for chip ready function
2559 */
2560static void onenand_sync(struct mtd_info *mtd)
2561{
Brian Norris289c0522011-07-19 10:06:09 -07002562 pr_debug("%s: called\n", __func__);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002563
2564 /* Grab the lock and see if the device is available */
2565 onenand_get_device(mtd, FL_SYNCING);
2566
2567 /* Release it and go back */
2568 onenand_release_device(mtd);
2569}
2570
2571/**
2572 * onenand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad
2573 * @param mtd MTD device structure
2574 * @param ofs offset relative to mtd start
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002575 *
2576 * Check whether the block is bad
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002577 */
2578static int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs)
2579{
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002580 int ret;
2581
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002582 /* Check for invalid offset */
2583 if (ofs > mtd->size)
2584 return -EINVAL;
2585
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002586 onenand_get_device(mtd, FL_READING);
2587 ret = onenand_block_isbad_nolock(mtd, ofs, 0);
2588 onenand_release_device(mtd);
2589 return ret;
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002590}
2591
2592/**
2593 * onenand_default_block_markbad - [DEFAULT] mark a block bad
2594 * @param mtd MTD device structure
2595 * @param ofs offset from device start
2596 *
2597 * This is the default implementation, which can be overridden by
2598 * a hardware specific driver.
2599 */
2600static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
2601{
2602 struct onenand_chip *this = mtd->priv;
2603 struct bbm_info *bbm = this->bbm;
2604 u_char buf[2] = {0, 0};
Kyungmin Park12f77c92007-08-30 09:36:05 +09002605 struct mtd_oob_ops ops = {
Brian Norris0612b9d2011-08-30 18:45:40 -07002606 .mode = MTD_OPS_PLACE_OOB,
Kyungmin Park12f77c92007-08-30 09:36:05 +09002607 .ooblen = 2,
2608 .oobbuf = buf,
2609 .ooboffs = 0,
2610 };
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002611 int block;
2612
2613 /* Get block number */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002614 block = onenand_block(this, ofs);
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002615 if (bbm->bbt)
2616 bbm->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
2617
Mika Korhonen492e1502009-06-09 21:52:35 +03002618 /* We write two bytes, so we don't have to mess with 16-bit access */
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002619 ofs += mtd->oobsize + (bbm->badblockpos & ~0x01);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002620 /* FIXME : What to do when marking SLC block in partition
2621 * with MLC erasesize? For now, it is not advisable to
2622 * create partitions containing both SLC and MLC regions.
2623 */
2624 return onenand_write_oob_nolock(mtd, ofs, &ops);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002625}
2626
2627/**
2628 * onenand_block_markbad - [MTD Interface] Mark the block at the given offset as bad
2629 * @param mtd MTD device structure
2630 * @param ofs offset relative to mtd start
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002631 *
2632 * Mark the block as bad
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002633 */
2634static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
2635{
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002636 struct onenand_chip *this = mtd->priv;
2637 int ret;
2638
2639 ret = onenand_block_isbad(mtd, ofs);
2640 if (ret) {
2641 /* If it was bad already, return success and do nothing */
2642 if (ret > 0)
2643 return 0;
2644 return ret;
2645 }
2646
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002647 onenand_get_device(mtd, FL_WRITING);
2648 ret = this->block_markbad(mtd, ofs);
2649 onenand_release_device(mtd);
2650 return ret;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002651}
2652
2653/**
Kyungmin Park08f782b2006-11-16 11:29:39 +09002654 * onenand_do_lock_cmd - [OneNAND Interface] Lock or unlock block(s)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002655 * @param mtd MTD device structure
2656 * @param ofs offset relative to mtd start
Kyungmin Park08f782b2006-11-16 11:29:39 +09002657 * @param len number of bytes to lock or unlock
Kyungmin Parke3da8062007-02-15 09:36:39 +09002658 * @param cmd lock or unlock command
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002659 *
Kyungmin Park08f782b2006-11-16 11:29:39 +09002660 * Lock or unlock one or more blocks
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002661 */
Kyungmin Park08f782b2006-11-16 11:29:39 +09002662static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int cmd)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002663{
2664 struct onenand_chip *this = mtd->priv;
2665 int start, end, block, value, status;
Kyungmin Park08f782b2006-11-16 11:29:39 +09002666 int wp_status_mask;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002667
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002668 start = onenand_block(this, ofs);
2669 end = onenand_block(this, ofs + len) - 1;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002670
Kyungmin Park08f782b2006-11-16 11:29:39 +09002671 if (cmd == ONENAND_CMD_LOCK)
2672 wp_status_mask = ONENAND_WP_LS;
2673 else
2674 wp_status_mask = ONENAND_WP_US;
2675
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002676 /* Continuous lock scheme */
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002677 if (this->options & ONENAND_HAS_CONT_LOCK) {
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002678 /* Set start block address */
2679 this->write_word(start, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
2680 /* Set end block address */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002681 this->write_word(end, this->base + ONENAND_REG_END_BLOCK_ADDRESS);
Kyungmin Park08f782b2006-11-16 11:29:39 +09002682 /* Write lock command */
2683 this->command(mtd, cmd, 0, 0);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002684
2685 /* There's no return value */
Kyungmin Park08f782b2006-11-16 11:29:39 +09002686 this->wait(mtd, FL_LOCKING);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002687
2688 /* Sanity check */
2689 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
2690 & ONENAND_CTRL_ONGO)
2691 continue;
2692
2693 /* Check lock status */
2694 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
Kyungmin Park08f782b2006-11-16 11:29:39 +09002695 if (!(status & wp_status_mask))
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302696 printk(KERN_ERR "%s: wp status = 0x%x\n",
2697 __func__, status);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002698
2699 return 0;
2700 }
2701
2702 /* Block lock scheme */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002703 for (block = start; block < end + 1; block++) {
Kyungmin Park20ba89a2005-12-16 11:17:29 +09002704 /* Set block address */
2705 value = onenand_block_address(this, block);
2706 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
2707 /* Select DataRAM for DDP */
2708 value = onenand_bufferram_address(this, block);
2709 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002710 /* Set start block address */
2711 this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
Kyungmin Park08f782b2006-11-16 11:29:39 +09002712 /* Write lock command */
2713 this->command(mtd, cmd, 0, 0);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002714
2715 /* There's no return value */
Kyungmin Park08f782b2006-11-16 11:29:39 +09002716 this->wait(mtd, FL_LOCKING);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002717
2718 /* Sanity check */
2719 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
2720 & ONENAND_CTRL_ONGO)
2721 continue;
2722
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002723 /* Check lock status */
2724 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
Kyungmin Park08f782b2006-11-16 11:29:39 +09002725 if (!(status & wp_status_mask))
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302726 printk(KERN_ERR "%s: block = %d, wp status = 0x%x\n",
2727 __func__, block, status);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002728 }
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +00002729
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002730 return 0;
2731}
2732
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002733/**
Kyungmin Park08f782b2006-11-16 11:29:39 +09002734 * onenand_lock - [MTD Interface] Lock block(s)
2735 * @param mtd MTD device structure
2736 * @param ofs offset relative to mtd start
2737 * @param len number of bytes to unlock
2738 *
2739 * Lock one or more blocks
2740 */
Adrian Hunter69423d92008-12-10 13:37:21 +00002741static int onenand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
Kyungmin Park08f782b2006-11-16 11:29:39 +09002742{
Adrian Hunter34627f02007-10-12 10:19:26 +03002743 int ret;
2744
2745 onenand_get_device(mtd, FL_LOCKING);
2746 ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK);
2747 onenand_release_device(mtd);
2748 return ret;
Kyungmin Park08f782b2006-11-16 11:29:39 +09002749}
2750
Kyungmin Park08f782b2006-11-16 11:29:39 +09002751/**
2752 * onenand_unlock - [MTD Interface] Unlock block(s)
2753 * @param mtd MTD device structure
2754 * @param ofs offset relative to mtd start
2755 * @param len number of bytes to unlock
2756 *
2757 * Unlock one or more blocks
2758 */
Adrian Hunter69423d92008-12-10 13:37:21 +00002759static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
Kyungmin Park08f782b2006-11-16 11:29:39 +09002760{
Adrian Hunter34627f02007-10-12 10:19:26 +03002761 int ret;
2762
2763 onenand_get_device(mtd, FL_LOCKING);
2764 ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
2765 onenand_release_device(mtd);
2766 return ret;
Kyungmin Park08f782b2006-11-16 11:29:39 +09002767}
2768
2769/**
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002770 * onenand_check_lock_status - [OneNAND Interface] Check lock status
2771 * @param this onenand chip data structure
2772 *
2773 * Check lock status
2774 */
Kyungmin Park66a10502008-02-13 15:55:38 +09002775static int onenand_check_lock_status(struct onenand_chip *this)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002776{
2777 unsigned int value, block, status;
2778 unsigned int end;
2779
2780 end = this->chipsize >> this->erase_shift;
2781 for (block = 0; block < end; block++) {
2782 /* Set block address */
2783 value = onenand_block_address(this, block);
2784 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
2785 /* Select DataRAM for DDP */
2786 value = onenand_bufferram_address(this, block);
2787 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
2788 /* Set start block address */
2789 this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
2790
2791 /* Check lock status */
2792 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
Kyungmin Park66a10502008-02-13 15:55:38 +09002793 if (!(status & ONENAND_WP_US)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302794 printk(KERN_ERR "%s: block = %d, wp status = 0x%x\n",
2795 __func__, block, status);
Kyungmin Park66a10502008-02-13 15:55:38 +09002796 return 0;
2797 }
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002798 }
Kyungmin Park66a10502008-02-13 15:55:38 +09002799
2800 return 1;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002801}
2802
2803/**
2804 * onenand_unlock_all - [OneNAND Interface] unlock all blocks
2805 * @param mtd MTD device structure
2806 *
2807 * Unlock all blocks
2808 */
Kyungmin Park66a10502008-02-13 15:55:38 +09002809static void onenand_unlock_all(struct mtd_info *mtd)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002810{
2811 struct onenand_chip *this = mtd->priv;
Kyungmin Park66a10502008-02-13 15:55:38 +09002812 loff_t ofs = 0;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002813 loff_t len = mtd->size;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002814
2815 if (this->options & ONENAND_HAS_UNLOCK_ALL) {
Kyungmin Park10b7a2b2007-01-12 05:45:34 +09002816 /* Set start block address */
2817 this->write_word(0, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002818 /* Write unlock command */
2819 this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0);
2820
2821 /* There's no return value */
Kyungmin Park08f782b2006-11-16 11:29:39 +09002822 this->wait(mtd, FL_LOCKING);
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002823
2824 /* Sanity check */
2825 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
2826 & ONENAND_CTRL_ONGO)
2827 continue;
2828
Kyungmin Park31bb9992009-05-12 13:46:57 -07002829 /* Don't check lock status */
2830 if (this->options & ONENAND_SKIP_UNLOCK_CHECK)
2831 return;
2832
Kyungmin Park66a10502008-02-13 15:55:38 +09002833 /* Check lock status */
2834 if (onenand_check_lock_status(this))
2835 return;
2836
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002837 /* Workaround for all block unlock in DDP */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002838 if (ONENAND_IS_DDP(this) && !FLEXONENAND(this)) {
Kyungmin Park66a10502008-02-13 15:55:38 +09002839 /* All blocks on another chip */
2840 ofs = this->chipsize >> 1;
2841 len = this->chipsize >> 1;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002842 }
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002843 }
2844
Kyungmin Park66a10502008-02-13 15:55:38 +09002845 onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002846}
2847
Kyungmin Park493c6462006-05-12 17:03:07 +03002848#ifdef CONFIG_MTD_ONENAND_OTP
2849
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05302850/**
2851 * onenand_otp_command - Send OTP specific command to OneNAND device
2852 * @param mtd MTD device structure
2853 * @param cmd the command to be sent
2854 * @param addr offset to read from or write to
2855 * @param len number of bytes to read or write
2856 */
2857static int onenand_otp_command(struct mtd_info *mtd, int cmd, loff_t addr,
2858 size_t len)
2859{
2860 struct onenand_chip *this = mtd->priv;
2861 int value, block, page;
2862
2863 /* Address translation */
2864 switch (cmd) {
2865 case ONENAND_CMD_OTP_ACCESS:
2866 block = (int) (addr >> this->erase_shift);
2867 page = -1;
2868 break;
2869
2870 default:
2871 block = (int) (addr >> this->erase_shift);
2872 page = (int) (addr >> this->page_shift);
2873
2874 if (ONENAND_IS_2PLANE(this)) {
2875 /* Make the even block number */
2876 block &= ~1;
2877 /* Is it the odd plane? */
2878 if (addr & this->writesize)
2879 block++;
2880 page >>= 1;
2881 }
2882 page &= this->page_mask;
2883 break;
2884 }
2885
2886 if (block != -1) {
2887 /* Write 'DFS, FBA' of Flash */
2888 value = onenand_block_address(this, block);
2889 this->write_word(value, this->base +
2890 ONENAND_REG_START_ADDRESS1);
2891 }
2892
2893 if (page != -1) {
2894 /* Now we use page size operation */
2895 int sectors = 4, count = 4;
2896 int dataram;
2897
2898 switch (cmd) {
2899 default:
2900 if (ONENAND_IS_2PLANE(this) && cmd == ONENAND_CMD_PROG)
2901 cmd = ONENAND_CMD_2X_PROG;
2902 dataram = ONENAND_CURRENT_BUFFERRAM(this);
2903 break;
2904 }
2905
2906 /* Write 'FPA, FSA' of Flash */
2907 value = onenand_page_address(page, sectors);
2908 this->write_word(value, this->base +
2909 ONENAND_REG_START_ADDRESS8);
2910
2911 /* Write 'BSA, BSC' of DataRAM */
2912 value = onenand_buffer_address(dataram, sectors, count);
2913 this->write_word(value, this->base + ONENAND_REG_START_BUFFER);
2914 }
2915
2916 /* Interrupt clear */
2917 this->write_word(ONENAND_INT_CLEAR, this->base + ONENAND_REG_INTERRUPT);
2918
2919 /* Write command */
2920 this->write_word(cmd, this->base + ONENAND_REG_COMMAND);
2921
2922 return 0;
2923}
2924
2925/**
Brian Norris7854d3f2011-06-23 14:12:08 -07002926 * onenand_otp_write_oob_nolock - [INTERN] OneNAND write out-of-band, specific to OTP
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05302927 * @param mtd MTD device structure
2928 * @param to offset to write to
2929 * @param len number of bytes to write
2930 * @param retlen pointer to variable to store the number of written bytes
2931 * @param buf the data to write
2932 *
2933 * OneNAND write out-of-band only for OTP
2934 */
2935static int onenand_otp_write_oob_nolock(struct mtd_info *mtd, loff_t to,
2936 struct mtd_oob_ops *ops)
2937{
2938 struct onenand_chip *this = mtd->priv;
2939 int column, ret = 0, oobsize;
2940 int written = 0;
2941 u_char *oobbuf;
2942 size_t len = ops->ooblen;
2943 const u_char *buf = ops->oobbuf;
2944 int block, value, status;
2945
2946 to += ops->ooboffs;
2947
2948 /* Initialize retlen, in case of early exit */
2949 ops->oobretlen = 0;
2950
2951 oobsize = mtd->oobsize;
2952
2953 column = to & (mtd->oobsize - 1);
2954
2955 oobbuf = this->oob_buf;
2956
2957 /* Loop until all data write */
2958 while (written < len) {
2959 int thislen = min_t(int, oobsize, len - written);
2960
2961 cond_resched();
2962
2963 block = (int) (to >> this->erase_shift);
2964 /*
2965 * Write 'DFS, FBA' of Flash
2966 * Add: F100h DQ=DFS, FBA
2967 */
2968
2969 value = onenand_block_address(this, block);
2970 this->write_word(value, this->base +
2971 ONENAND_REG_START_ADDRESS1);
2972
2973 /*
2974 * Select DataRAM for DDP
2975 * Add: F101h DQ=DBS
2976 */
2977
2978 value = onenand_bufferram_address(this, block);
2979 this->write_word(value, this->base +
2980 ONENAND_REG_START_ADDRESS2);
2981 ONENAND_SET_NEXT_BUFFERRAM(this);
2982
2983 /*
2984 * Enter OTP access mode
2985 */
2986 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
2987 this->wait(mtd, FL_OTPING);
2988
2989 /* We send data to spare ram with oobsize
2990 * to prevent byte access */
2991 memcpy(oobbuf + column, buf, thislen);
2992
2993 /*
2994 * Write Data into DataRAM
2995 * Add: 8th Word
2996 * in sector0/spare/page0
2997 * DQ=XXFCh
2998 */
2999 this->write_bufferram(mtd, ONENAND_SPARERAM,
3000 oobbuf, 0, mtd->oobsize);
3001
3002 onenand_otp_command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize);
3003 onenand_update_bufferram(mtd, to, 0);
3004 if (ONENAND_IS_2PLANE(this)) {
3005 ONENAND_SET_BUFFERRAM1(this);
3006 onenand_update_bufferram(mtd, to + this->writesize, 0);
3007 }
3008
3009 ret = this->wait(mtd, FL_WRITING);
3010 if (ret) {
3011 printk(KERN_ERR "%s: write failed %d\n", __func__, ret);
3012 break;
3013 }
3014
3015 /* Exit OTP access mode */
3016 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
3017 this->wait(mtd, FL_RESETING);
3018
3019 status = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
3020 status &= 0x60;
3021
3022 if (status == 0x60) {
3023 printk(KERN_DEBUG "\nBLOCK\tSTATUS\n");
3024 printk(KERN_DEBUG "1st Block\tLOCKED\n");
3025 printk(KERN_DEBUG "OTP Block\tLOCKED\n");
3026 } else if (status == 0x20) {
3027 printk(KERN_DEBUG "\nBLOCK\tSTATUS\n");
3028 printk(KERN_DEBUG "1st Block\tLOCKED\n");
3029 printk(KERN_DEBUG "OTP Block\tUN-LOCKED\n");
3030 } else if (status == 0x40) {
3031 printk(KERN_DEBUG "\nBLOCK\tSTATUS\n");
3032 printk(KERN_DEBUG "1st Block\tUN-LOCKED\n");
3033 printk(KERN_DEBUG "OTP Block\tLOCKED\n");
3034 } else {
3035 printk(KERN_DEBUG "Reboot to check\n");
3036 }
3037
3038 written += thislen;
3039 if (written == len)
3040 break;
3041
3042 to += mtd->writesize;
3043 buf += thislen;
3044 column = 0;
3045 }
3046
3047 ops->oobretlen = written;
3048
3049 return ret;
3050}
3051
Mika Korhonen492e1502009-06-09 21:52:35 +03003052/* Internal OTP operation */
Kyungmin Park493c6462006-05-12 17:03:07 +03003053typedef int (*otp_op_t)(struct mtd_info *mtd, loff_t form, size_t len,
3054 size_t *retlen, u_char *buf);
3055
3056/**
3057 * do_otp_read - [DEFAULT] Read OTP block area
3058 * @param mtd MTD device structure
3059 * @param from The offset to read
3060 * @param len number of bytes to read
3061 * @param retlen pointer to variable to store the number of readbytes
3062 * @param buf the databuffer to put/get data
3063 *
3064 * Read OTP block area.
3065 */
3066static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len,
3067 size_t *retlen, u_char *buf)
3068{
3069 struct onenand_chip *this = mtd->priv;
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003070 struct mtd_oob_ops ops = {
3071 .len = len,
3072 .ooblen = 0,
3073 .datbuf = buf,
3074 .oobbuf = NULL,
3075 };
Kyungmin Park493c6462006-05-12 17:03:07 +03003076 int ret;
3077
3078 /* Enter OTP access mode */
3079 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
3080 this->wait(mtd, FL_OTPING);
3081
Kyungmin Park8a8f6322010-12-02 09:24:16 +09003082 ret = ONENAND_IS_4KB_PAGE(this) ?
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003083 onenand_mlc_read_ops_nolock(mtd, from, &ops) :
3084 onenand_read_ops_nolock(mtd, from, &ops);
Kyungmin Park493c6462006-05-12 17:03:07 +03003085
3086 /* Exit OTP access mode */
3087 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
3088 this->wait(mtd, FL_RESETING);
3089
3090 return ret;
3091}
3092
3093/**
3094 * do_otp_write - [DEFAULT] Write OTP block area
3095 * @param mtd MTD device structure
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003096 * @param to The offset to write
Kyungmin Park493c6462006-05-12 17:03:07 +03003097 * @param len number of bytes to write
3098 * @param retlen pointer to variable to store the number of write bytes
3099 * @param buf the databuffer to put/get data
3100 *
3101 * Write OTP block area.
3102 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003103static int do_otp_write(struct mtd_info *mtd, loff_t to, size_t len,
Kyungmin Park493c6462006-05-12 17:03:07 +03003104 size_t *retlen, u_char *buf)
3105{
3106 struct onenand_chip *this = mtd->priv;
3107 unsigned char *pbuf = buf;
3108 int ret;
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003109 struct mtd_oob_ops ops;
Kyungmin Park493c6462006-05-12 17:03:07 +03003110
3111 /* Force buffer page aligned */
Joern Engel28318772006-05-22 23:18:05 +02003112 if (len < mtd->writesize) {
Kyungmin Park493c6462006-05-12 17:03:07 +03003113 memcpy(this->page_buf, buf, len);
Joern Engel28318772006-05-22 23:18:05 +02003114 memset(this->page_buf + len, 0xff, mtd->writesize - len);
Kyungmin Park493c6462006-05-12 17:03:07 +03003115 pbuf = this->page_buf;
Joern Engel28318772006-05-22 23:18:05 +02003116 len = mtd->writesize;
Kyungmin Park493c6462006-05-12 17:03:07 +03003117 }
3118
3119 /* Enter OTP access mode */
3120 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
3121 this->wait(mtd, FL_OTPING);
3122
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003123 ops.len = len;
3124 ops.ooblen = 0;
Kyungmin Park14370852007-10-10 13:48:14 +09003125 ops.datbuf = pbuf;
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003126 ops.oobbuf = NULL;
3127 ret = onenand_write_ops_nolock(mtd, to, &ops);
3128 *retlen = ops.retlen;
Kyungmin Park493c6462006-05-12 17:03:07 +03003129
3130 /* Exit OTP access mode */
3131 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
3132 this->wait(mtd, FL_RESETING);
3133
3134 return ret;
3135}
3136
3137/**
3138 * do_otp_lock - [DEFAULT] Lock OTP block area
3139 * @param mtd MTD device structure
3140 * @param from The offset to lock
3141 * @param len number of bytes to lock
3142 * @param retlen pointer to variable to store the number of lock bytes
3143 * @param buf the databuffer to put/get data
3144 *
3145 * Lock OTP block area.
3146 */
3147static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len,
3148 size_t *retlen, u_char *buf)
3149{
3150 struct onenand_chip *this = mtd->priv;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003151 struct mtd_oob_ops ops;
Kyungmin Park493c6462006-05-12 17:03:07 +03003152 int ret;
3153
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003154 if (FLEXONENAND(this)) {
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303155
3156 /* Enter OTP access mode */
3157 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
3158 this->wait(mtd, FL_OTPING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003159 /*
3160 * For Flex-OneNAND, we write lock mark to 1st word of sector 4 of
3161 * main area of page 49.
3162 */
3163 ops.len = mtd->writesize;
3164 ops.ooblen = 0;
3165 ops.datbuf = buf;
3166 ops.oobbuf = NULL;
3167 ret = onenand_write_ops_nolock(mtd, mtd->writesize * 49, &ops);
3168 *retlen = ops.retlen;
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303169
3170 /* Exit OTP access mode */
3171 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
3172 this->wait(mtd, FL_RESETING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003173 } else {
Brian Norris0612b9d2011-08-30 18:45:40 -07003174 ops.mode = MTD_OPS_PLACE_OOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003175 ops.ooblen = len;
3176 ops.oobbuf = buf;
3177 ops.ooboffs = 0;
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303178 ret = onenand_otp_write_oob_nolock(mtd, from, &ops);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003179 *retlen = ops.oobretlen;
3180 }
Kyungmin Park493c6462006-05-12 17:03:07 +03003181
Kyungmin Park493c6462006-05-12 17:03:07 +03003182 return ret;
3183}
3184
3185/**
3186 * onenand_otp_walk - [DEFAULT] Handle OTP operation
3187 * @param mtd MTD device structure
3188 * @param from The offset to read/write
3189 * @param len number of bytes to read/write
3190 * @param retlen pointer to variable to store the number of read bytes
3191 * @param buf the databuffer to put/get data
3192 * @param action do given action
3193 * @param mode specify user and factory
3194 *
3195 * Handle OTP operation.
3196 */
3197static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
3198 size_t *retlen, u_char *buf,
3199 otp_op_t action, int mode)
3200{
3201 struct onenand_chip *this = mtd->priv;
3202 int otp_pages;
3203 int density;
3204 int ret = 0;
3205
3206 *retlen = 0;
3207
Kyungmin Parke71f04f2007-12-11 11:23:45 +09003208 density = onenand_get_density(this->device_id);
Kyungmin Park493c6462006-05-12 17:03:07 +03003209 if (density < ONENAND_DEVICE_DENSITY_512Mb)
3210 otp_pages = 20;
3211 else
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303212 otp_pages = 50;
Kyungmin Park493c6462006-05-12 17:03:07 +03003213
3214 if (mode == MTD_OTP_FACTORY) {
Joern Engel28318772006-05-22 23:18:05 +02003215 from += mtd->writesize * otp_pages;
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303216 otp_pages = ONENAND_PAGES_PER_BLOCK - otp_pages;
Kyungmin Park493c6462006-05-12 17:03:07 +03003217 }
3218
3219 /* Check User/Factory boundary */
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303220 if (mode == MTD_OTP_USER) {
Roel Kluin0a032a42009-12-16 01:37:17 +01003221 if (mtd->writesize * otp_pages < from + len)
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303222 return 0;
3223 } else {
Roel Kluin0a032a42009-12-16 01:37:17 +01003224 if (mtd->writesize * otp_pages < len)
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303225 return 0;
3226 }
Kyungmin Park493c6462006-05-12 17:03:07 +03003227
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003228 onenand_get_device(mtd, FL_OTPING);
Kyungmin Park493c6462006-05-12 17:03:07 +03003229 while (len > 0 && otp_pages > 0) {
3230 if (!action) { /* OTP Info functions */
3231 struct otp_info *otpinfo;
3232
3233 len -= sizeof(struct otp_info);
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003234 if (len <= 0) {
3235 ret = -ENOSPC;
3236 break;
3237 }
Kyungmin Park493c6462006-05-12 17:03:07 +03003238
3239 otpinfo = (struct otp_info *) buf;
3240 otpinfo->start = from;
Joern Engel28318772006-05-22 23:18:05 +02003241 otpinfo->length = mtd->writesize;
Kyungmin Park493c6462006-05-12 17:03:07 +03003242 otpinfo->locked = 0;
3243
Joern Engel28318772006-05-22 23:18:05 +02003244 from += mtd->writesize;
Kyungmin Park493c6462006-05-12 17:03:07 +03003245 buf += sizeof(struct otp_info);
3246 *retlen += sizeof(struct otp_info);
3247 } else {
3248 size_t tmp_retlen;
Kyungmin Park493c6462006-05-12 17:03:07 +03003249
3250 ret = action(mtd, from, len, &tmp_retlen, buf);
3251
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303252 buf += tmp_retlen;
3253 len -= tmp_retlen;
3254 *retlen += tmp_retlen;
Kyungmin Park493c6462006-05-12 17:03:07 +03003255
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003256 if (ret)
3257 break;
Kyungmin Park493c6462006-05-12 17:03:07 +03003258 }
3259 otp_pages--;
3260 }
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003261 onenand_release_device(mtd);
Kyungmin Park493c6462006-05-12 17:03:07 +03003262
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003263 return ret;
Kyungmin Park493c6462006-05-12 17:03:07 +03003264}
3265
3266/**
3267 * onenand_get_fact_prot_info - [MTD Interface] Read factory OTP info
3268 * @param mtd MTD device structure
3269 * @param buf the databuffer to put/get data
3270 * @param len number of bytes to read
3271 *
3272 * Read factory OTP info.
3273 */
3274static int onenand_get_fact_prot_info(struct mtd_info *mtd,
3275 struct otp_info *buf, size_t len)
3276{
3277 size_t retlen;
3278 int ret;
3279
3280 ret = onenand_otp_walk(mtd, 0, len, &retlen, (u_char *) buf, NULL, MTD_OTP_FACTORY);
3281
3282 return ret ? : retlen;
3283}
3284
3285/**
3286 * onenand_read_fact_prot_reg - [MTD Interface] Read factory OTP area
3287 * @param mtd MTD device structure
3288 * @param from The offset to read
3289 * @param len number of bytes to read
3290 * @param retlen pointer to variable to store the number of read bytes
3291 * @param buf the databuffer to put/get data
3292 *
3293 * Read factory OTP area.
3294 */
3295static int onenand_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
3296 size_t len, size_t *retlen, u_char *buf)
3297{
3298 return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_read, MTD_OTP_FACTORY);
3299}
3300
3301/**
3302 * onenand_get_user_prot_info - [MTD Interface] Read user OTP info
3303 * @param mtd MTD device structure
3304 * @param buf the databuffer to put/get data
3305 * @param len number of bytes to read
3306 *
3307 * Read user OTP info.
3308 */
3309static int onenand_get_user_prot_info(struct mtd_info *mtd,
3310 struct otp_info *buf, size_t len)
3311{
3312 size_t retlen;
3313 int ret;
3314
3315 ret = onenand_otp_walk(mtd, 0, len, &retlen, (u_char *) buf, NULL, MTD_OTP_USER);
3316
3317 return ret ? : retlen;
3318}
3319
3320/**
3321 * onenand_read_user_prot_reg - [MTD Interface] Read user OTP area
3322 * @param mtd MTD device structure
3323 * @param from The offset to read
3324 * @param len number of bytes to read
3325 * @param retlen pointer to variable to store the number of read bytes
3326 * @param buf the databuffer to put/get data
3327 *
3328 * Read user OTP area.
3329 */
3330static int onenand_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
3331 size_t len, size_t *retlen, u_char *buf)
3332{
3333 return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_read, MTD_OTP_USER);
3334}
3335
3336/**
3337 * onenand_write_user_prot_reg - [MTD Interface] Write user OTP area
3338 * @param mtd MTD device structure
3339 * @param from The offset to write
3340 * @param len number of bytes to write
3341 * @param retlen pointer to variable to store the number of write bytes
3342 * @param buf the databuffer to put/get data
3343 *
3344 * Write user OTP area.
3345 */
3346static int onenand_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
3347 size_t len, size_t *retlen, u_char *buf)
3348{
3349 return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_write, MTD_OTP_USER);
3350}
3351
3352/**
3353 * onenand_lock_user_prot_reg - [MTD Interface] Lock user OTP area
3354 * @param mtd MTD device structure
3355 * @param from The offset to lock
3356 * @param len number of bytes to unlock
3357 *
3358 * Write lock mark on spare area in page 0 in OTP block
3359 */
3360static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
3361 size_t len)
3362{
Kyungmin Park69d79182007-12-14 14:47:21 +09003363 struct onenand_chip *this = mtd->priv;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003364 u_char *buf = FLEXONENAND(this) ? this->page_buf : this->oob_buf;
Kyungmin Park493c6462006-05-12 17:03:07 +03003365 size_t retlen;
3366 int ret;
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303367 unsigned int otp_lock_offset = ONENAND_OTP_LOCK_OFFSET;
Kyungmin Park493c6462006-05-12 17:03:07 +03003368
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003369 memset(buf, 0xff, FLEXONENAND(this) ? this->writesize
3370 : mtd->oobsize);
Kyungmin Park493c6462006-05-12 17:03:07 +03003371 /*
Kyungmin Park493c6462006-05-12 17:03:07 +03003372 * Write lock mark to 8th word of sector0 of page0 of the spare0.
3373 * We write 16 bytes spare area instead of 2 bytes.
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003374 * For Flex-OneNAND, we write lock mark to 1st word of sector 4 of
3375 * main area of page 49.
Kyungmin Park493c6462006-05-12 17:03:07 +03003376 */
Kyungmin Park493c6462006-05-12 17:03:07 +03003377
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003378 from = 0;
3379 len = FLEXONENAND(this) ? mtd->writesize : 16;
3380
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303381 /*
3382 * Note: OTP lock operation
3383 * OTP block : 0xXXFC XX 1111 1100
3384 * 1st block : 0xXXF3 (If chip support) XX 1111 0011
3385 * Both : 0xXXF0 (If chip support) XX 1111 0000
3386 */
3387 if (FLEXONENAND(this))
3388 otp_lock_offset = FLEXONENAND_OTP_LOCK_OFFSET;
3389
3390 /* ONENAND_OTP_AREA | ONENAND_OTP_BLOCK0 | ONENAND_OTP_AREA_BLOCK0 */
3391 if (otp == 1)
3392 buf[otp_lock_offset] = 0xFC;
3393 else if (otp == 2)
3394 buf[otp_lock_offset] = 0xF3;
3395 else if (otp == 3)
3396 buf[otp_lock_offset] = 0xF0;
3397 else if (otp != 0)
3398 printk(KERN_DEBUG "[OneNAND] Invalid option selected for OTP\n");
3399
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003400 ret = onenand_otp_walk(mtd, from, len, &retlen, buf, do_otp_lock, MTD_OTP_USER);
Kyungmin Park493c6462006-05-12 17:03:07 +03003401
3402 return ret ? : retlen;
3403}
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303404
Kyungmin Park493c6462006-05-12 17:03:07 +03003405#endif /* CONFIG_MTD_ONENAND_OTP */
3406
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003407/**
Kyungmin Park75384b02007-01-18 11:10:57 +09003408 * onenand_check_features - Check and set OneNAND features
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003409 * @param mtd MTD data structure
3410 *
Kyungmin Park75384b02007-01-18 11:10:57 +09003411 * Check and set OneNAND features
3412 * - lock scheme
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003413 * - two plane
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003414 */
Kyungmin Park75384b02007-01-18 11:10:57 +09003415static void onenand_check_features(struct mtd_info *mtd)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003416{
3417 struct onenand_chip *this = mtd->priv;
Roman Tereshonkovedb44b92010-10-11 14:47:32 +03003418 unsigned int density, process, numbufs;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003419
3420 /* Lock scheme depends on density and process */
Kyungmin Parke71f04f2007-12-11 11:23:45 +09003421 density = onenand_get_density(this->device_id);
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003422 process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT;
Roman Tereshonkovedb44b92010-10-11 14:47:32 +03003423 numbufs = this->read_word(this->base + ONENAND_REG_NUM_BUFFERS) >> 8;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003424
3425 /* Lock scheme */
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003426 switch (density) {
3427 case ONENAND_DEVICE_DENSITY_4Gb:
Kyungmin Park6a88c472010-04-28 17:46:45 +02003428 if (ONENAND_IS_DDP(this))
3429 this->options |= ONENAND_HAS_2PLANE;
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02003430 else if (numbufs == 1) {
Kyungmin Park6a88c472010-04-28 17:46:45 +02003431 this->options |= ONENAND_HAS_4KB_PAGE;
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02003432 this->options |= ONENAND_HAS_CACHE_PROGRAM;
Kyungmin Parke1c10242011-06-22 14:16:49 +09003433 /*
3434 * There are two different 4KiB pagesize chips
3435 * and no way to detect it by H/W config values.
3436 *
3437 * To detect the correct NOP for each chips,
3438 * It should check the version ID as workaround.
3439 *
3440 * Now it has as following
3441 * KFM4G16Q4M has NOP 4 with version ID 0x0131
3442 * KFM4G16Q5M has NOP 1 with versoin ID 0x013e
3443 */
3444 if ((this->version_id & 0xf) == 0xe)
3445 this->options |= ONENAND_HAS_NOP_1;
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02003446 }
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003447
3448 case ONENAND_DEVICE_DENSITY_2Gb:
Mika Korhonen492e1502009-06-09 21:52:35 +03003449 /* 2Gb DDP does not have 2 plane */
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003450 if (!ONENAND_IS_DDP(this))
3451 this->options |= ONENAND_HAS_2PLANE;
3452 this->options |= ONENAND_HAS_UNLOCK_ALL;
3453
3454 case ONENAND_DEVICE_DENSITY_1Gb:
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003455 /* A-Die has all block unlock */
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003456 if (process)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003457 this->options |= ONENAND_HAS_UNLOCK_ALL;
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003458 break;
3459
3460 default:
3461 /* Some OneNAND has continuous lock scheme */
3462 if (!process)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003463 this->options |= ONENAND_HAS_CONT_LOCK;
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003464 break;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003465 }
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003466
Kyungmin Park8a8f6322010-12-02 09:24:16 +09003467 /* The MLC has 4KiB pagesize. */
3468 if (ONENAND_IS_MLC(this))
3469 this->options |= ONENAND_HAS_4KB_PAGE;
3470
3471 if (ONENAND_IS_4KB_PAGE(this))
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003472 this->options &= ~ONENAND_HAS_2PLANE;
3473
3474 if (FLEXONENAND(this)) {
3475 this->options &= ~ONENAND_HAS_CONT_LOCK;
3476 this->options |= ONENAND_HAS_UNLOCK_ALL;
3477 }
3478
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003479 if (this->options & ONENAND_HAS_CONT_LOCK)
3480 printk(KERN_DEBUG "Lock scheme is Continuous Lock\n");
3481 if (this->options & ONENAND_HAS_UNLOCK_ALL)
3482 printk(KERN_DEBUG "Chip support all block unlock\n");
3483 if (this->options & ONENAND_HAS_2PLANE)
3484 printk(KERN_DEBUG "Chip has 2 plane\n");
Kyungmin Park6a88c472010-04-28 17:46:45 +02003485 if (this->options & ONENAND_HAS_4KB_PAGE)
3486 printk(KERN_DEBUG "Chip has 4KiB pagesize\n");
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02003487 if (this->options & ONENAND_HAS_CACHE_PROGRAM)
3488 printk(KERN_DEBUG "Chip has cache program feature\n");
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003489}
3490
3491/**
Kyungmin Parke3da8062007-02-15 09:36:39 +09003492 * onenand_print_device_info - Print device & version ID
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003493 * @param device device ID
Kyungmin Parke3da8062007-02-15 09:36:39 +09003494 * @param version version ID
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003495 *
Kyungmin Parke3da8062007-02-15 09:36:39 +09003496 * Print device & version ID
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003497 */
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003498static void onenand_print_device_info(int device, int version)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003499{
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003500 int vcc, demuxed, ddp, density, flexonenand;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003501
3502 vcc = device & ONENAND_DEVICE_VCC_MASK;
3503 demuxed = device & ONENAND_DEVICE_IS_DEMUX;
3504 ddp = device & ONENAND_DEVICE_IS_DDP;
Kyungmin Parke71f04f2007-12-11 11:23:45 +09003505 density = onenand_get_density(device);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003506 flexonenand = device & DEVICE_IS_FLEXONENAND;
3507 printk(KERN_INFO "%s%sOneNAND%s %dMB %sV 16-bit (0x%02x)\n",
3508 demuxed ? "" : "Muxed ",
3509 flexonenand ? "Flex-" : "",
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003510 ddp ? "(DDP)" : "",
3511 (16 << density),
3512 vcc ? "2.65/3.3" : "1.8",
3513 device);
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003514 printk(KERN_INFO "OneNAND version = 0x%04x\n", version);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003515}
3516
3517static const struct onenand_manufacturers onenand_manuf_ids[] = {
3518 {ONENAND_MFR_SAMSUNG, "Samsung"},
Adrian Hunteree8f3762009-05-05 11:04:19 +03003519 {ONENAND_MFR_NUMONYX, "Numonyx"},
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003520};
3521
3522/**
3523 * onenand_check_maf - Check manufacturer ID
3524 * @param manuf manufacturer ID
3525 *
3526 * Check manufacturer ID
3527 */
3528static int onenand_check_maf(int manuf)
3529{
Kyungmin Park37b1cc32005-12-16 11:17:29 +09003530 int size = ARRAY_SIZE(onenand_manuf_ids);
3531 char *name;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003532 int i;
3533
Kyungmin Park37b1cc32005-12-16 11:17:29 +09003534 for (i = 0; i < size; i++)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003535 if (manuf == onenand_manuf_ids[i].id)
3536 break;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003537
Kyungmin Park37b1cc32005-12-16 11:17:29 +09003538 if (i < size)
3539 name = onenand_manuf_ids[i].name;
3540 else
3541 name = "Unknown";
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003542
Kyungmin Park37b1cc32005-12-16 11:17:29 +09003543 printk(KERN_DEBUG "OneNAND Manufacturer: %s (0x%0x)\n", name, manuf);
3544
3545 return (i == size);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003546}
3547
3548/**
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003549* flexonenand_get_boundary - Reads the SLC boundary
3550* @param onenand_info - onenand info structure
3551**/
3552static int flexonenand_get_boundary(struct mtd_info *mtd)
3553{
3554 struct onenand_chip *this = mtd->priv;
3555 unsigned die, bdry;
3556 int ret, syscfg, locked;
3557
3558 /* Disable ECC */
3559 syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
3560 this->write_word((syscfg | 0x0100), this->base + ONENAND_REG_SYS_CFG1);
3561
3562 for (die = 0; die < this->dies; die++) {
3563 this->command(mtd, FLEXONENAND_CMD_PI_ACCESS, die, 0);
3564 this->wait(mtd, FL_SYNCING);
3565
3566 this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0);
3567 ret = this->wait(mtd, FL_READING);
3568
3569 bdry = this->read_word(this->base + ONENAND_DATARAM);
3570 if ((bdry >> FLEXONENAND_PI_UNLOCK_SHIFT) == 3)
3571 locked = 0;
3572 else
3573 locked = 1;
3574 this->boundary[die] = bdry & FLEXONENAND_PI_MASK;
3575
3576 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
3577 ret = this->wait(mtd, FL_RESETING);
3578
3579 printk(KERN_INFO "Die %d boundary: %d%s\n", die,
3580 this->boundary[die], locked ? "(Locked)" : "(Unlocked)");
3581 }
3582
3583 /* Enable ECC */
3584 this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
3585 return 0;
3586}
3587
3588/**
3589 * flexonenand_get_size - Fill up fields in onenand_chip and mtd_info
3590 * boundary[], diesize[], mtd->size, mtd->erasesize
3591 * @param mtd - MTD device structure
3592 */
3593static void flexonenand_get_size(struct mtd_info *mtd)
3594{
3595 struct onenand_chip *this = mtd->priv;
3596 int die, i, eraseshift, density;
3597 int blksperdie, maxbdry;
3598 loff_t ofs;
3599
3600 density = onenand_get_density(this->device_id);
3601 blksperdie = ((loff_t)(16 << density) << 20) >> (this->erase_shift);
3602 blksperdie >>= ONENAND_IS_DDP(this) ? 1 : 0;
3603 maxbdry = blksperdie - 1;
3604 eraseshift = this->erase_shift - 1;
3605
3606 mtd->numeraseregions = this->dies << 1;
3607
3608 /* This fills up the device boundary */
3609 flexonenand_get_boundary(mtd);
3610 die = ofs = 0;
3611 i = -1;
3612 for (; die < this->dies; die++) {
3613 if (!die || this->boundary[die-1] != maxbdry) {
3614 i++;
3615 mtd->eraseregions[i].offset = ofs;
3616 mtd->eraseregions[i].erasesize = 1 << eraseshift;
3617 mtd->eraseregions[i].numblocks =
3618 this->boundary[die] + 1;
3619 ofs += mtd->eraseregions[i].numblocks << eraseshift;
3620 eraseshift++;
3621 } else {
3622 mtd->numeraseregions -= 1;
3623 mtd->eraseregions[i].numblocks +=
3624 this->boundary[die] + 1;
3625 ofs += (this->boundary[die] + 1) << (eraseshift - 1);
3626 }
3627 if (this->boundary[die] != maxbdry) {
3628 i++;
3629 mtd->eraseregions[i].offset = ofs;
3630 mtd->eraseregions[i].erasesize = 1 << eraseshift;
3631 mtd->eraseregions[i].numblocks = maxbdry ^
3632 this->boundary[die];
3633 ofs += mtd->eraseregions[i].numblocks << eraseshift;
3634 eraseshift--;
3635 } else
3636 mtd->numeraseregions -= 1;
3637 }
3638
3639 /* Expose MLC erase size except when all blocks are SLC */
3640 mtd->erasesize = 1 << this->erase_shift;
3641 if (mtd->numeraseregions == 1)
3642 mtd->erasesize >>= 1;
3643
3644 printk(KERN_INFO "Device has %d eraseregions\n", mtd->numeraseregions);
3645 for (i = 0; i < mtd->numeraseregions; i++)
3646 printk(KERN_INFO "[offset: 0x%08x, erasesize: 0x%05x,"
3647 " numblocks: %04u]\n",
3648 (unsigned int) mtd->eraseregions[i].offset,
3649 mtd->eraseregions[i].erasesize,
3650 mtd->eraseregions[i].numblocks);
3651
3652 for (die = 0, mtd->size = 0; die < this->dies; die++) {
3653 this->diesize[die] = (loff_t)blksperdie << this->erase_shift;
3654 this->diesize[die] -= (loff_t)(this->boundary[die] + 1)
3655 << (this->erase_shift - 1);
3656 mtd->size += this->diesize[die];
3657 }
3658}
3659
3660/**
3661 * flexonenand_check_blocks_erased - Check if blocks are erased
3662 * @param mtd_info - mtd info structure
3663 * @param start - first erase block to check
3664 * @param end - last erase block to check
3665 *
3666 * Converting an unerased block from MLC to SLC
3667 * causes byte values to change. Since both data and its ECC
3668 * have changed, reads on the block give uncorrectable error.
3669 * This might lead to the block being detected as bad.
3670 *
3671 * Avoid this by ensuring that the block to be converted is
3672 * erased.
3673 */
3674static int flexonenand_check_blocks_erased(struct mtd_info *mtd, int start, int end)
3675{
3676 struct onenand_chip *this = mtd->priv;
3677 int i, ret;
3678 int block;
3679 struct mtd_oob_ops ops = {
Brian Norris0612b9d2011-08-30 18:45:40 -07003680 .mode = MTD_OPS_PLACE_OOB,
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003681 .ooboffs = 0,
3682 .ooblen = mtd->oobsize,
3683 .datbuf = NULL,
3684 .oobbuf = this->oob_buf,
3685 };
3686 loff_t addr;
3687
3688 printk(KERN_DEBUG "Check blocks from %d to %d\n", start, end);
3689
3690 for (block = start; block <= end; block++) {
3691 addr = flexonenand_addr(this, block);
3692 if (onenand_block_isbad_nolock(mtd, addr, 0))
3693 continue;
3694
3695 /*
3696 * Since main area write results in ECC write to spare,
3697 * it is sufficient to check only ECC bytes for change.
3698 */
3699 ret = onenand_read_oob_nolock(mtd, addr, &ops);
3700 if (ret)
3701 return ret;
3702
3703 for (i = 0; i < mtd->oobsize; i++)
3704 if (this->oob_buf[i] != 0xff)
3705 break;
3706
3707 if (i != mtd->oobsize) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303708 printk(KERN_WARNING "%s: Block %d not erased.\n",
3709 __func__, block);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003710 return 1;
3711 }
3712 }
3713
3714 return 0;
3715}
3716
3717/**
3718 * flexonenand_set_boundary - Writes the SLC boundary
3719 * @param mtd - mtd info structure
3720 */
3721int flexonenand_set_boundary(struct mtd_info *mtd, int die,
3722 int boundary, int lock)
3723{
3724 struct onenand_chip *this = mtd->priv;
3725 int ret, density, blksperdie, old, new, thisboundary;
3726 loff_t addr;
3727
3728 /* Change only once for SDP Flex-OneNAND */
3729 if (die && (!ONENAND_IS_DDP(this)))
3730 return 0;
3731
3732 /* boundary value of -1 indicates no required change */
3733 if (boundary < 0 || boundary == this->boundary[die])
3734 return 0;
3735
3736 density = onenand_get_density(this->device_id);
3737 blksperdie = ((16 << density) << 20) >> this->erase_shift;
3738 blksperdie >>= ONENAND_IS_DDP(this) ? 1 : 0;
3739
3740 if (boundary >= blksperdie) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303741 printk(KERN_ERR "%s: Invalid boundary value. "
3742 "Boundary not changed.\n", __func__);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003743 return -EINVAL;
3744 }
3745
3746 /* Check if converting blocks are erased */
3747 old = this->boundary[die] + (die * this->density_mask);
3748 new = boundary + (die * this->density_mask);
3749 ret = flexonenand_check_blocks_erased(mtd, min(old, new) + 1, max(old, new));
3750 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303751 printk(KERN_ERR "%s: Please erase blocks "
3752 "before boundary change\n", __func__);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003753 return ret;
3754 }
3755
3756 this->command(mtd, FLEXONENAND_CMD_PI_ACCESS, die, 0);
3757 this->wait(mtd, FL_SYNCING);
3758
3759 /* Check is boundary is locked */
3760 this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0);
3761 ret = this->wait(mtd, FL_READING);
3762
3763 thisboundary = this->read_word(this->base + ONENAND_DATARAM);
3764 if ((thisboundary >> FLEXONENAND_PI_UNLOCK_SHIFT) != 3) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303765 printk(KERN_ERR "%s: boundary locked\n", __func__);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003766 ret = 1;
3767 goto out;
3768 }
3769
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303770 printk(KERN_INFO "Changing die %d boundary: %d%s\n",
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003771 die, boundary, lock ? "(Locked)" : "(Unlocked)");
3772
3773 addr = die ? this->diesize[0] : 0;
3774
3775 boundary &= FLEXONENAND_PI_MASK;
3776 boundary |= lock ? 0 : (3 << FLEXONENAND_PI_UNLOCK_SHIFT);
3777
3778 this->command(mtd, ONENAND_CMD_ERASE, addr, 0);
3779 ret = this->wait(mtd, FL_ERASING);
3780 if (ret) {
Mika Korhonenf369c7e2009-10-23 07:50:44 +02003781 printk(KERN_ERR "%s: Failed PI erase for Die %d\n",
3782 __func__, die);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003783 goto out;
3784 }
3785
3786 this->write_word(boundary, this->base + ONENAND_DATARAM);
3787 this->command(mtd, ONENAND_CMD_PROG, addr, 0);
3788 ret = this->wait(mtd, FL_WRITING);
3789 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303790 printk(KERN_ERR "%s: Failed PI write for Die %d\n",
3791 __func__, die);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003792 goto out;
3793 }
3794
3795 this->command(mtd, FLEXONENAND_CMD_PI_UPDATE, die, 0);
3796 ret = this->wait(mtd, FL_WRITING);
3797out:
3798 this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_REG_COMMAND);
3799 this->wait(mtd, FL_RESETING);
3800 if (!ret)
3801 /* Recalculate device size on boundary change*/
3802 flexonenand_get_size(mtd);
3803
3804 return ret;
3805}
3806
3807/**
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003808 * onenand_chip_probe - [OneNAND Interface] The generic chip probe
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003809 * @param mtd MTD device structure
3810 *
3811 * OneNAND detection method:
Michael Opdenacker59c51592007-05-09 08:57:56 +02003812 * Compare the values from command with ones from register
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003813 */
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003814static int onenand_chip_probe(struct mtd_info *mtd)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003815{
3816 struct onenand_chip *this = mtd->priv;
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003817 int bram_maf_id, bram_dev_id, maf_id, dev_id;
Kyungmin Park47e777e2006-09-25 23:53:28 +00003818 int syscfg;
3819
3820 /* Save system configuration 1 */
3821 syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
3822 /* Clear Sync. Burst Read mode to read BootRAM */
Adrian Hunteree8f3762009-05-05 11:04:19 +03003823 this->write_word((syscfg & ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE), this->base + ONENAND_REG_SYS_CFG1);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003824
3825 /* Send the command for reading device ID from BootRAM */
3826 this->write_word(ONENAND_CMD_READID, this->base + ONENAND_BOOTRAM);
3827
3828 /* Read manufacturer and device IDs from BootRAM */
3829 bram_maf_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x0);
3830 bram_dev_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x2);
3831
Kyungmin Park47e777e2006-09-25 23:53:28 +00003832 /* Reset OneNAND to read default register values */
3833 this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM);
3834 /* Wait reset */
3835 this->wait(mtd, FL_RESETING);
3836
3837 /* Restore system configuration 1 */
3838 this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
3839
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003840 /* Check manufacturer ID */
3841 if (onenand_check_maf(bram_maf_id))
3842 return -ENXIO;
3843
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003844 /* Read manufacturer and device IDs from Register */
3845 maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);
3846 dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
3847
3848 /* Check OneNAND device */
3849 if (maf_id != bram_maf_id || dev_id != bram_dev_id)
3850 return -ENXIO;
3851
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003852 return 0;
3853}
3854
3855/**
3856 * onenand_probe - [OneNAND Interface] Probe the OneNAND device
3857 * @param mtd MTD device structure
3858 */
3859static int onenand_probe(struct mtd_info *mtd)
3860{
3861 struct onenand_chip *this = mtd->priv;
3862 int maf_id, dev_id, ver_id;
3863 int density;
3864 int ret;
3865
3866 ret = this->chip_probe(mtd);
3867 if (ret)
3868 return ret;
3869
3870 /* Read manufacturer and device IDs from Register */
3871 maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);
3872 dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
3873 ver_id = this->read_word(this->base + ONENAND_REG_VERSION_ID);
3874 this->technology = this->read_word(this->base + ONENAND_REG_TECHNOLOGY);
3875
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003876 /* Flash device information */
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003877 onenand_print_device_info(dev_id, ver_id);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003878 this->device_id = dev_id;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003879 this->version_id = ver_id;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003880
Kyungmin Parkc37cb562010-04-28 17:46:48 +02003881 /* Check OneNAND features */
3882 onenand_check_features(mtd);
3883
Kyungmin Parke71f04f2007-12-11 11:23:45 +09003884 density = onenand_get_density(dev_id);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003885 if (FLEXONENAND(this)) {
3886 this->dies = ONENAND_IS_DDP(this) ? 2 : 1;
3887 /* Maximum possible erase regions */
3888 mtd->numeraseregions = this->dies << 1;
3889 mtd->eraseregions = kzalloc(sizeof(struct mtd_erase_region_info)
3890 * (this->dies << 1), GFP_KERNEL);
3891 if (!mtd->eraseregions)
3892 return -ENOMEM;
3893 }
3894
3895 /*
3896 * For Flex-OneNAND, chipsize represents maximum possible device size.
3897 * mtd->size represents the actual device size.
3898 */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003899 this->chipsize = (16 << density) << 20;
3900
3901 /* OneNAND page size & block size */
3902 /* The data buffer size is equal to page size */
Joern Engel28318772006-05-22 23:18:05 +02003903 mtd->writesize = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003904 /* We use the full BufferRAM */
Kyungmin Park8a8f6322010-12-02 09:24:16 +09003905 if (ONENAND_IS_4KB_PAGE(this))
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003906 mtd->writesize <<= 1;
3907
Joern Engel28318772006-05-22 23:18:05 +02003908 mtd->oobsize = mtd->writesize >> 5;
Kyungmin Park9bfbc9b2007-01-31 14:25:21 +09003909 /* Pages per a block are always 64 in OneNAND */
Joern Engel28318772006-05-22 23:18:05 +02003910 mtd->erasesize = mtd->writesize << 6;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003911 /*
3912 * Flex-OneNAND SLC area has 64 pages per block.
3913 * Flex-OneNAND MLC area has 128 pages per block.
3914 * Expose MLC erase size to find erase_shift and page_mask.
3915 */
3916 if (FLEXONENAND(this))
3917 mtd->erasesize <<= 1;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003918
3919 this->erase_shift = ffs(mtd->erasesize) - 1;
Joern Engel28318772006-05-22 23:18:05 +02003920 this->page_shift = ffs(mtd->writesize) - 1;
Kyungmin Park9bfbc9b2007-01-31 14:25:21 +09003921 this->page_mask = (1 << (this->erase_shift - this->page_shift)) - 1;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003922 /* Set density mask. it is used for DDP */
3923 if (ONENAND_IS_DDP(this))
3924 this->density_mask = this->chipsize >> (this->erase_shift + 1);
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003925 /* It's real page size */
3926 this->writesize = mtd->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003927
Mika Korhonen492e1502009-06-09 21:52:35 +03003928 /* REVISIT: Multichip handling */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003929
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003930 if (FLEXONENAND(this))
3931 flexonenand_get_size(mtd);
3932 else
3933 mtd->size = this->chipsize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003934
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003935 /*
3936 * We emulate the 4KiB page and 256KiB erase block size
3937 * But oobsize is still 64 bytes.
3938 * It is only valid if you turn on 2X program support,
3939 * Otherwise it will be ignored by compiler.
3940 */
3941 if (ONENAND_IS_2PLANE(this)) {
3942 mtd->writesize <<= 1;
3943 mtd->erasesize <<= 1;
3944 }
3945
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003946 return 0;
3947}
3948
Kyungmin Parka41371e2005-09-29 03:55:31 +01003949/**
3950 * onenand_suspend - [MTD Interface] Suspend the OneNAND flash
3951 * @param mtd MTD device structure
3952 */
3953static int onenand_suspend(struct mtd_info *mtd)
3954{
3955 return onenand_get_device(mtd, FL_PM_SUSPENDED);
3956}
3957
3958/**
3959 * onenand_resume - [MTD Interface] Resume the OneNAND flash
3960 * @param mtd MTD device structure
3961 */
3962static void onenand_resume(struct mtd_info *mtd)
3963{
3964 struct onenand_chip *this = mtd->priv;
3965
3966 if (this->state == FL_PM_SUSPENDED)
3967 onenand_release_device(mtd);
3968 else
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303969 printk(KERN_ERR "%s: resume() called for the chip which is not "
3970 "in suspended state\n", __func__);
Kyungmin Parka41371e2005-09-29 03:55:31 +01003971}
3972
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003973/**
3974 * onenand_scan - [OneNAND Interface] Scan for the OneNAND device
3975 * @param mtd MTD device structure
3976 * @param maxchips Number of chips to scan for
3977 *
3978 * This fills out all the not initialized function pointers
3979 * with the defaults.
3980 * The flash ID is read and the mtd/chip structures are
3981 * filled with the appropriate values.
3982 */
3983int onenand_scan(struct mtd_info *mtd, int maxchips)
3984{
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003985 int i, ret;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003986 struct onenand_chip *this = mtd->priv;
3987
3988 if (!this->read_word)
3989 this->read_word = onenand_readw;
3990 if (!this->write_word)
3991 this->write_word = onenand_writew;
3992
3993 if (!this->command)
3994 this->command = onenand_command;
3995 if (!this->wait)
Kyungmin Park2c221202006-11-16 11:23:48 +09003996 onenand_setup_wait(mtd);
Kyungmin Park31bb9992009-05-12 13:46:57 -07003997 if (!this->bbt_wait)
3998 this->bbt_wait = onenand_bbt_wait;
3999 if (!this->unlock_all)
4000 this->unlock_all = onenand_unlock_all;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004001
Kyungmin Parkad0d3632010-05-28 11:03:11 +09004002 if (!this->chip_probe)
4003 this->chip_probe = onenand_chip_probe;
4004
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004005 if (!this->read_bufferram)
4006 this->read_bufferram = onenand_read_bufferram;
4007 if (!this->write_bufferram)
4008 this->write_bufferram = onenand_write_bufferram;
4009
Kyungmin Parkcdc00132005-09-03 07:15:48 +01004010 if (!this->block_markbad)
4011 this->block_markbad = onenand_default_block_markbad;
4012 if (!this->scan_bbt)
4013 this->scan_bbt = onenand_default_bbt;
4014
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004015 if (onenand_probe(mtd))
4016 return -ENXIO;
4017
Kyungmin Park52b0eea2005-09-03 07:07:19 +01004018 /* Set Sync. Burst Read after probing */
4019 if (this->mmcontrol) {
4020 printk(KERN_INFO "OneNAND Sync. Burst Read support\n");
4021 this->read_bufferram = onenand_sync_read_bufferram;
4022 }
4023
Kyungmin Park532a37c2005-12-16 11:17:29 +09004024 /* Allocate buffers, if necessary */
4025 if (!this->page_buf) {
Kyungmin Park470bc842007-03-09 10:08:11 +09004026 this->page_buf = kzalloc(mtd->writesize, GFP_KERNEL);
Kyungmin Park532a37c2005-12-16 11:17:29 +09004027 if (!this->page_buf) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05304028 printk(KERN_ERR "%s: Can't allocate page_buf\n",
4029 __func__);
Kyungmin Park532a37c2005-12-16 11:17:29 +09004030 return -ENOMEM;
4031 }
Kyungmin Park4a8ce0b2010-04-28 17:46:46 +02004032#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
4033 this->verify_buf = kzalloc(mtd->writesize, GFP_KERNEL);
4034 if (!this->verify_buf) {
4035 kfree(this->page_buf);
4036 return -ENOMEM;
4037 }
4038#endif
Kyungmin Park532a37c2005-12-16 11:17:29 +09004039 this->options |= ONENAND_PAGEBUF_ALLOC;
4040 }
Kyungmin Park470bc842007-03-09 10:08:11 +09004041 if (!this->oob_buf) {
4042 this->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
4043 if (!this->oob_buf) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05304044 printk(KERN_ERR "%s: Can't allocate oob_buf\n",
4045 __func__);
Kyungmin Park470bc842007-03-09 10:08:11 +09004046 if (this->options & ONENAND_PAGEBUF_ALLOC) {
4047 this->options &= ~ONENAND_PAGEBUF_ALLOC;
4048 kfree(this->page_buf);
4049 }
4050 return -ENOMEM;
4051 }
4052 this->options |= ONENAND_OOBBUF_ALLOC;
4053 }
Kyungmin Park532a37c2005-12-16 11:17:29 +09004054
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004055 this->state = FL_READY;
4056 init_waitqueue_head(&this->wq);
4057 spin_lock_init(&this->chip_lock);
4058
Kyungmin Park60d84f92006-12-22 16:21:54 +09004059 /*
4060 * Allow subpage writes up to oobsize.
4061 */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004062 switch (mtd->oobsize) {
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07004063 case 128:
Roman Tereshonkov99b17c02011-04-11 12:52:01 +03004064 if (FLEXONENAND(this)) {
4065 this->ecclayout = &flexonenand_oob_128;
4066 mtd->subpage_sft = 0;
4067 } else {
4068 this->ecclayout = &onenand_oob_128;
4069 mtd->subpage_sft = 2;
4070 }
Kyungmin Parke1c10242011-06-22 14:16:49 +09004071 if (ONENAND_IS_NOP_1(this))
4072 mtd->subpage_sft = 0;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07004073 break;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004074 case 64:
Thomas Gleixner5bd34c02006-05-27 22:16:10 +02004075 this->ecclayout = &onenand_oob_64;
Kyungmin Park60d84f92006-12-22 16:21:54 +09004076 mtd->subpage_sft = 2;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004077 break;
4078
4079 case 32:
Thomas Gleixner5bd34c02006-05-27 22:16:10 +02004080 this->ecclayout = &onenand_oob_32;
Kyungmin Park60d84f92006-12-22 16:21:54 +09004081 mtd->subpage_sft = 1;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004082 break;
4083
4084 default:
Amul Kumar Saha297758f2009-10-02 16:59:11 +05304085 printk(KERN_WARNING "%s: No OOB scheme defined for oobsize %d\n",
4086 __func__, mtd->oobsize);
Kyungmin Park60d84f92006-12-22 16:21:54 +09004087 mtd->subpage_sft = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004088 /* To prevent kernel oops */
Thomas Gleixner5bd34c02006-05-27 22:16:10 +02004089 this->ecclayout = &onenand_oob_32;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004090 break;
4091 }
4092
Kyungmin Park60d84f92006-12-22 16:21:54 +09004093 this->subpagesize = mtd->writesize >> mtd->subpage_sft;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02004094
4095 /*
4096 * The number of bytes available for a client to place data into
4097 * the out of band area
4098 */
4099 this->ecclayout->oobavail = 0;
Kyungmin Parkad286342007-03-23 10:19:52 +09004100 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES &&
4101 this->ecclayout->oobfree[i].length; i++)
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02004102 this->ecclayout->oobavail +=
4103 this->ecclayout->oobfree[i].length;
Vitaly Wool1f922672007-03-06 16:56:34 +03004104 mtd->oobavail = this->ecclayout->oobavail;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02004105
Thomas Gleixner5bd34c02006-05-27 22:16:10 +02004106 mtd->ecclayout = this->ecclayout;
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +00004107
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004108 /* Fill in remaining MTD driver data */
Rohit Hassan Sathyanarayanc7626802010-09-27 16:02:10 +05304109 mtd->type = ONENAND_IS_MLC(this) ? MTD_MLCNANDFLASH : MTD_NANDFLASH;
Joern Engel5fa43392006-05-22 23:18:29 +02004110 mtd->flags = MTD_CAP_NANDFLASH;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004111 mtd->erase = onenand_erase;
4112 mtd->point = NULL;
4113 mtd->unpoint = NULL;
4114 mtd->read = onenand_read;
4115 mtd->write = onenand_write;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004116 mtd->read_oob = onenand_read_oob;
4117 mtd->write_oob = onenand_write_oob;
Richard Purdie6c77fd62008-02-06 10:18:22 +00004118 mtd->panic_write = onenand_panic_write;
Kyungmin Park493c6462006-05-12 17:03:07 +03004119#ifdef CONFIG_MTD_ONENAND_OTP
4120 mtd->get_fact_prot_info = onenand_get_fact_prot_info;
4121 mtd->read_fact_prot_reg = onenand_read_fact_prot_reg;
4122 mtd->get_user_prot_info = onenand_get_user_prot_info;
4123 mtd->read_user_prot_reg = onenand_read_user_prot_reg;
4124 mtd->write_user_prot_reg = onenand_write_user_prot_reg;
4125 mtd->lock_user_prot_reg = onenand_lock_user_prot_reg;
4126#endif
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004127 mtd->sync = onenand_sync;
Kyungmin Park08f782b2006-11-16 11:29:39 +09004128 mtd->lock = onenand_lock;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004129 mtd->unlock = onenand_unlock;
Kyungmin Parka41371e2005-09-29 03:55:31 +01004130 mtd->suspend = onenand_suspend;
4131 mtd->resume = onenand_resume;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004132 mtd->block_isbad = onenand_block_isbad;
4133 mtd->block_markbad = onenand_block_markbad;
4134 mtd->owner = THIS_MODULE;
Anatolij Gustschin25dcd292010-12-16 23:42:17 +01004135 mtd->writebufsize = mtd->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004136
4137 /* Unlock whole block */
Roman Tereshonkovb3dcfd32011-02-17 13:44:41 +02004138 if (!(this->options & ONENAND_SKIP_INITIAL_UNLOCKING))
4139 this->unlock_all(mtd);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004140
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07004141 ret = this->scan_bbt(mtd);
4142 if ((!FLEXONENAND(this)) || ret)
4143 return ret;
4144
4145 /* Change Flex-OneNAND boundaries if required */
4146 for (i = 0; i < MAX_DIES; i++)
4147 flexonenand_set_boundary(mtd, i, flex_bdry[2 * i],
4148 flex_bdry[(2 * i) + 1]);
4149
4150 return 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004151}
4152
4153/**
4154 * onenand_release - [OneNAND Interface] Free resources held by the OneNAND device
4155 * @param mtd MTD device structure
4156 */
4157void onenand_release(struct mtd_info *mtd)
4158{
Kyungmin Park532a37c2005-12-16 11:17:29 +09004159 struct onenand_chip *this = mtd->priv;
4160
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004161 /* Deregister partitions */
Jamie Iles711a6322011-05-23 10:22:56 +01004162 mtd_device_unregister(mtd);
Kyungmin Park532a37c2005-12-16 11:17:29 +09004163
4164 /* Free bad block table memory, if allocated */
Adrian Hunterf00b0042007-01-22 17:01:01 +09004165 if (this->bbm) {
4166 struct bbm_info *bbm = this->bbm;
4167 kfree(bbm->bbt);
Kyungmin Park532a37c2005-12-16 11:17:29 +09004168 kfree(this->bbm);
Adrian Hunterf00b0042007-01-22 17:01:01 +09004169 }
Kyungmin Park470bc842007-03-09 10:08:11 +09004170 /* Buffers allocated by onenand_scan */
Kyungmin Park4a8ce0b2010-04-28 17:46:46 +02004171 if (this->options & ONENAND_PAGEBUF_ALLOC) {
Kyungmin Park532a37c2005-12-16 11:17:29 +09004172 kfree(this->page_buf);
Kyungmin Park4a8ce0b2010-04-28 17:46:46 +02004173#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
4174 kfree(this->verify_buf);
4175#endif
4176 }
Kyungmin Park470bc842007-03-09 10:08:11 +09004177 if (this->options & ONENAND_OOBBUF_ALLOC)
4178 kfree(this->oob_buf);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07004179 kfree(mtd->eraseregions);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004180}
4181
4182EXPORT_SYMBOL_GPL(onenand_scan);
4183EXPORT_SYMBOL_GPL(onenand_release);
4184
4185MODULE_LICENSE("GPL");
4186MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");
4187MODULE_DESCRIPTION("Generic OneNAND flash driver code");