blob: 1de33b5d390358b58a2cbaaaf6991e08ebcc97db [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
Mike Dunnedbc45402012-04-25 12:06:11 -07001204 /* return max bitflips per ecc step; ONENANDs correct 1 bit only */
1205 return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001206}
1207
1208/**
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001209 * onenand_read_ops_nolock - [OneNAND Interface] OneNAND read main and/or out-of-band
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001210 * @param mtd MTD device structure
1211 * @param from offset to read from
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001212 * @param ops: oob operation description structure
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001213 *
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001214 * OneNAND read main and/or out-of-band data
1215 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001216static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001217 struct mtd_oob_ops *ops)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001218{
1219 struct onenand_chip *this = mtd->priv;
Kyungmin Parkf4f91ac2006-11-16 12:03:56 +09001220 struct mtd_ecc_stats stats;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001221 size_t len = ops->len;
1222 size_t ooblen = ops->ooblen;
1223 u_char *buf = ops->datbuf;
1224 u_char *oobbuf = ops->oobbuf;
1225 int read = 0, column, thislen;
1226 int oobread = 0, oobcolumn, thisooblen, oobsize;
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001227 int ret = 0, boundary = 0;
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001228 int writesize = this->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001229
Brian Norris0a32a102011-07-19 10:06:10 -07001230 pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from,
1231 (int)len);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001232
Brian Norris0612b9d2011-08-30 18:45:40 -07001233 if (ops->mode == MTD_OPS_AUTO_OOB)
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001234 oobsize = this->ecclayout->oobavail;
1235 else
1236 oobsize = mtd->oobsize;
1237
1238 oobcolumn = from & (mtd->oobsize - 1);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001239
1240 /* Do not allow reads past end of device */
1241 if ((from + len) > mtd->size) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301242 printk(KERN_ERR "%s: Attempt read beyond end of device\n",
1243 __func__);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001244 ops->retlen = 0;
1245 ops->oobretlen = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001246 return -EINVAL;
1247 }
1248
Kyungmin Parkf4f91ac2006-11-16 12:03:56 +09001249 stats = mtd->ecc_stats;
Artem Bityutskiy61a7e192006-12-26 16:41:24 +09001250
Adrian Huntera8de85d2007-01-04 09:51:26 +02001251 /* Read-while-load method */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001252
Adrian Huntera8de85d2007-01-04 09:51:26 +02001253 /* Do first load to bufferRAM */
1254 if (read < len) {
1255 if (!onenand_check_bufferram(mtd, from)) {
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001256 this->command(mtd, ONENAND_CMD_READ, from, writesize);
Adrian Huntera8de85d2007-01-04 09:51:26 +02001257 ret = this->wait(mtd, FL_READING);
1258 onenand_update_bufferram(mtd, from, !ret);
Brian Norrisd57f40542011-09-20 18:34:25 -07001259 if (mtd_is_eccerr(ret))
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001260 ret = 0;
Adrian Huntera8de85d2007-01-04 09:51:26 +02001261 }
1262 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001263
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001264 thislen = min_t(int, writesize, len - read);
1265 column = from & (writesize - 1);
1266 if (column + thislen > writesize)
1267 thislen = writesize - column;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001268
Adrian Huntera8de85d2007-01-04 09:51:26 +02001269 while (!ret) {
1270 /* If there is more to load then start next load */
1271 from += thislen;
1272 if (read + thislen < len) {
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001273 this->command(mtd, ONENAND_CMD_READ, from, writesize);
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001274 /*
1275 * Chip boundary handling in DDP
1276 * Now we issued chip 1 read and pointed chip 1
Mika Korhonen492e1502009-06-09 21:52:35 +03001277 * bufferram so we have to point chip 0 bufferram.
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001278 */
Kyungmin Park738d61f2007-01-15 17:09:14 +09001279 if (ONENAND_IS_DDP(this) &&
1280 unlikely(from == (this->chipsize >> 1))) {
1281 this->write_word(ONENAND_DDP_CHIP0, this->base + ONENAND_REG_START_ADDRESS2);
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001282 boundary = 1;
1283 } else
1284 boundary = 0;
Adrian Huntera8de85d2007-01-04 09:51:26 +02001285 ONENAND_SET_PREV_BUFFERRAM(this);
1286 }
1287 /* While load is going, read from last bufferRAM */
1288 this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001289
1290 /* Read oob area if needed */
1291 if (oobbuf) {
1292 thisooblen = oobsize - oobcolumn;
1293 thisooblen = min_t(int, thisooblen, ooblen - oobread);
1294
Brian Norris0612b9d2011-08-30 18:45:40 -07001295 if (ops->mode == MTD_OPS_AUTO_OOB)
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001296 onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);
1297 else
1298 this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen);
1299 oobread += thisooblen;
1300 oobbuf += thisooblen;
1301 oobcolumn = 0;
1302 }
1303
Adrian Huntera8de85d2007-01-04 09:51:26 +02001304 /* See if we are done */
1305 read += thislen;
1306 if (read == len)
1307 break;
1308 /* Set up for next read from bufferRAM */
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001309 if (unlikely(boundary))
Kyungmin Park738d61f2007-01-15 17:09:14 +09001310 this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);
Adrian Huntera8de85d2007-01-04 09:51:26 +02001311 ONENAND_SET_NEXT_BUFFERRAM(this);
1312 buf += thislen;
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001313 thislen = min_t(int, writesize, len - read);
Adrian Huntera8de85d2007-01-04 09:51:26 +02001314 column = 0;
1315 cond_resched();
1316 /* Now wait for load */
1317 ret = this->wait(mtd, FL_READING);
1318 onenand_update_bufferram(mtd, from, !ret);
Brian Norrisd57f40542011-09-20 18:34:25 -07001319 if (mtd_is_eccerr(ret))
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001320 ret = 0;
Adrian Huntera8de85d2007-01-04 09:51:26 +02001321 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001322
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001323 /*
1324 * Return success, if no ECC failures, else -EBADMSG
1325 * fs driver will take care of that, because
1326 * retlen == desired len and result == -EBADMSG
1327 */
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001328 ops->retlen = read;
1329 ops->oobretlen = oobread;
Kyungmin Parkf4f91ac2006-11-16 12:03:56 +09001330
Adrian Huntera8de85d2007-01-04 09:51:26 +02001331 if (ret)
1332 return ret;
1333
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001334 if (mtd->ecc_stats.failed - stats.failed)
1335 return -EBADMSG;
1336
Mike Dunnedbc45402012-04-25 12:06:11 -07001337 /* return max bitflips per ecc step; ONENANDs correct 1 bit only */
1338 return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001339}
1340
1341/**
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001342 * onenand_read_oob_nolock - [MTD Interface] OneNAND read out-of-band
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001343 * @param mtd MTD device structure
1344 * @param from offset to read from
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001345 * @param ops: oob operation description structure
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001346 *
1347 * OneNAND read out-of-band data from the spare area
1348 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001349static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
Kyungmin Park12f77c92007-08-30 09:36:05 +09001350 struct mtd_oob_ops *ops)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001351{
1352 struct onenand_chip *this = mtd->priv;
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001353 struct mtd_ecc_stats stats;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001354 int read = 0, thislen, column, oobsize;
Kyungmin Park12f77c92007-08-30 09:36:05 +09001355 size_t len = ops->ooblen;
Brian Norris905c6bc2011-08-30 18:45:39 -07001356 unsigned int mode = ops->mode;
Kyungmin Park12f77c92007-08-30 09:36:05 +09001357 u_char *buf = ops->oobbuf;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001358 int ret = 0, readcmd;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001359
Kyungmin Park12f77c92007-08-30 09:36:05 +09001360 from += ops->ooboffs;
1361
Brian Norris0a32a102011-07-19 10:06:10 -07001362 pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from,
1363 (int)len);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001364
1365 /* Initialize return length value */
Kyungmin Park12f77c92007-08-30 09:36:05 +09001366 ops->oobretlen = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001367
Brian Norris0612b9d2011-08-30 18:45:40 -07001368 if (mode == MTD_OPS_AUTO_OOB)
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001369 oobsize = this->ecclayout->oobavail;
1370 else
1371 oobsize = mtd->oobsize;
1372
1373 column = from & (mtd->oobsize - 1);
1374
1375 if (unlikely(column >= oobsize)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301376 printk(KERN_ERR "%s: Attempted to start read outside oob\n",
1377 __func__);
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001378 return -EINVAL;
1379 }
1380
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001381 /* Do not allow reads past end of device */
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001382 if (unlikely(from >= mtd->size ||
1383 column + len > ((mtd->size >> this->page_shift) -
1384 (from >> this->page_shift)) * oobsize)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301385 printk(KERN_ERR "%s: Attempted to read beyond end of device\n",
1386 __func__);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001387 return -EINVAL;
1388 }
1389
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001390 stats = mtd->ecc_stats;
1391
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001392 readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001393
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001394 while (read < len) {
Artem Bityutskiy61a7e192006-12-26 16:41:24 +09001395 cond_resched();
1396
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001397 thislen = oobsize - column;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001398 thislen = min_t(int, thislen, len);
1399
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001400 this->command(mtd, readcmd, from, mtd->oobsize);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001401
1402 onenand_update_bufferram(mtd, from, 0);
1403
1404 ret = this->wait(mtd, FL_READING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001405 if (unlikely(ret))
1406 ret = onenand_recover_lsb(mtd, from, ret);
1407
Brian Norrisd57f40542011-09-20 18:34:25 -07001408 if (ret && !mtd_is_eccerr(ret)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301409 printk(KERN_ERR "%s: read failed = 0x%x\n",
1410 __func__, ret);
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001411 break;
1412 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001413
Brian Norris0612b9d2011-08-30 18:45:40 -07001414 if (mode == MTD_OPS_AUTO_OOB)
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001415 onenand_transfer_auto_oob(mtd, buf, column, thislen);
1416 else
1417 this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001418
1419 read += thislen;
1420
1421 if (read == len)
1422 break;
1423
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001424 buf += thislen;
1425
1426 /* Read more? */
1427 if (read < len) {
1428 /* Page size */
Joern Engel28318772006-05-22 23:18:05 +02001429 from += mtd->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001430 column = 0;
1431 }
1432 }
1433
Kyungmin Park12f77c92007-08-30 09:36:05 +09001434 ops->oobretlen = read;
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001435
1436 if (ret)
1437 return ret;
1438
1439 if (mtd->ecc_stats.failed - stats.failed)
1440 return -EBADMSG;
1441
1442 return 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001443}
1444
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001445/**
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001446 * onenand_read - [MTD Interface] Read data from flash
1447 * @param mtd MTD device structure
1448 * @param from offset to read from
1449 * @param len number of bytes to read
1450 * @param retlen pointer to variable to store the number of read bytes
1451 * @param buf the databuffer to put data
1452 *
1453 * Read with ecc
1454*/
1455static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
1456 size_t *retlen, u_char *buf)
1457{
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001458 struct onenand_chip *this = mtd->priv;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001459 struct mtd_oob_ops ops = {
1460 .len = len,
1461 .ooblen = 0,
1462 .datbuf = buf,
1463 .oobbuf = NULL,
1464 };
1465 int ret;
1466
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001467 onenand_get_device(mtd, FL_READING);
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001468 ret = ONENAND_IS_4KB_PAGE(this) ?
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001469 onenand_mlc_read_ops_nolock(mtd, from, &ops) :
1470 onenand_read_ops_nolock(mtd, from, &ops);
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001471 onenand_release_device(mtd);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001472
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001473 *retlen = ops.retlen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001474 return ret;
1475}
1476
1477/**
1478 * onenand_read_oob - [MTD Interface] Read main and/or out-of-band
Kyungmin Parke3da8062007-02-15 09:36:39 +09001479 * @param mtd: MTD device structure
1480 * @param from: offset to read from
1481 * @param ops: oob operation description structure
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001482
1483 * Read main and/or out-of-band
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001484 */
1485static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
1486 struct mtd_oob_ops *ops)
1487{
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001488 struct onenand_chip *this = mtd->priv;
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001489 int ret;
1490
Kyungmin Park4f4fad22007-02-02 09:22:21 +09001491 switch (ops->mode) {
Brian Norris0612b9d2011-08-30 18:45:40 -07001492 case MTD_OPS_PLACE_OOB:
1493 case MTD_OPS_AUTO_OOB:
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001494 break;
Brian Norris0612b9d2011-08-30 18:45:40 -07001495 case MTD_OPS_RAW:
Kyungmin Park4f4fad22007-02-02 09:22:21 +09001496 /* Not implemented yet */
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001497 default:
1498 return -EINVAL;
1499 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001500
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001501 onenand_get_device(mtd, FL_READING);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001502 if (ops->datbuf)
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001503 ret = ONENAND_IS_4KB_PAGE(this) ?
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001504 onenand_mlc_read_ops_nolock(mtd, from, ops) :
1505 onenand_read_ops_nolock(mtd, from, ops);
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001506 else
1507 ret = onenand_read_oob_nolock(mtd, from, ops);
1508 onenand_release_device(mtd);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001509
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001510 return ret;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001511}
1512
Kyungmin Park211ac752007-02-07 12:15:01 +09001513/**
1514 * onenand_bbt_wait - [DEFAULT] wait until the command is done
1515 * @param mtd MTD device structure
1516 * @param state state to select the max. timeout value
1517 *
1518 * Wait for command done.
1519 */
1520static int onenand_bbt_wait(struct mtd_info *mtd, int state)
1521{
1522 struct onenand_chip *this = mtd->priv;
1523 unsigned long timeout;
Adrian Huntere0c1a922010-12-10 12:04:20 +02001524 unsigned int interrupt, ctrl, ecc, addr1, addr8;
Kyungmin Park211ac752007-02-07 12:15:01 +09001525
1526 /* The 20 msec is enough */
1527 timeout = jiffies + msecs_to_jiffies(20);
1528 while (time_before(jiffies, timeout)) {
1529 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
1530 if (interrupt & ONENAND_INT_MASTER)
1531 break;
1532 }
1533 /* To get correct interrupt status in timeout case */
1534 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
1535 ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
Adrian Huntere0c1a922010-12-10 12:04:20 +02001536 addr1 = this->read_word(this->base + ONENAND_REG_START_ADDRESS1);
1537 addr8 = this->read_word(this->base + ONENAND_REG_START_ADDRESS8);
Kyungmin Park211ac752007-02-07 12:15:01 +09001538
Kyungmin Park211ac752007-02-07 12:15:01 +09001539 if (interrupt & ONENAND_INT_READ) {
Adrian Huntere0c1a922010-12-10 12:04:20 +02001540 ecc = onenand_read_ecc(this);
Kyungmin Park83973b82008-05-29 14:52:40 +09001541 if (ecc & ONENAND_ECC_2BIT_ALL) {
Adrian Huntere0c1a922010-12-10 12:04:20 +02001542 printk(KERN_DEBUG "%s: ecc 0x%04x ctrl 0x%04x "
1543 "intr 0x%04x addr1 %#x addr8 %#x\n",
1544 __func__, ecc, ctrl, interrupt, addr1, addr8);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001545 return ONENAND_BBT_READ_ECC_ERROR;
Kyungmin Park83973b82008-05-29 14:52:40 +09001546 }
Kyungmin Park211ac752007-02-07 12:15:01 +09001547 } else {
Adrian Huntere0c1a922010-12-10 12:04:20 +02001548 printk(KERN_ERR "%s: read timeout! ctrl 0x%04x "
1549 "intr 0x%04x addr1 %#x addr8 %#x\n",
1550 __func__, ctrl, interrupt, addr1, addr8);
Kyungmin Park211ac752007-02-07 12:15:01 +09001551 return ONENAND_BBT_READ_FATAL_ERROR;
1552 }
1553
Kyungmin Park83973b82008-05-29 14:52:40 +09001554 /* Initial bad block case: 0x2400 or 0x0400 */
1555 if (ctrl & ONENAND_CTRL_ERROR) {
Adrian Huntere0c1a922010-12-10 12:04:20 +02001556 printk(KERN_DEBUG "%s: ctrl 0x%04x intr 0x%04x addr1 %#x "
1557 "addr8 %#x\n", __func__, ctrl, interrupt, addr1, addr8);
Kyungmin Park83973b82008-05-29 14:52:40 +09001558 return ONENAND_BBT_READ_ERROR;
1559 }
1560
Kyungmin Park211ac752007-02-07 12:15:01 +09001561 return 0;
1562}
1563
1564/**
1565 * onenand_bbt_read_oob - [MTD Interface] OneNAND read out-of-band for bbt scan
1566 * @param mtd MTD device structure
1567 * @param from offset to read from
Kyungmin Parke3da8062007-02-15 09:36:39 +09001568 * @param ops oob operation description structure
Kyungmin Park211ac752007-02-07 12:15:01 +09001569 *
1570 * OneNAND read out-of-band data from the spare area for bbt scan
1571 */
1572int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
1573 struct mtd_oob_ops *ops)
1574{
1575 struct onenand_chip *this = mtd->priv;
1576 int read = 0, thislen, column;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001577 int ret = 0, readcmd;
Kyungmin Park211ac752007-02-07 12:15:01 +09001578 size_t len = ops->ooblen;
1579 u_char *buf = ops->oobbuf;
1580
Brian Norris0a32a102011-07-19 10:06:10 -07001581 pr_debug("%s: from = 0x%08x, len = %zi\n", __func__, (unsigned int)from,
1582 len);
Kyungmin Park211ac752007-02-07 12:15:01 +09001583
1584 /* Initialize return value */
1585 ops->oobretlen = 0;
1586
1587 /* Do not allow reads past end of device */
1588 if (unlikely((from + len) > mtd->size)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301589 printk(KERN_ERR "%s: Attempt read beyond end of device\n",
1590 __func__);
Kyungmin Park211ac752007-02-07 12:15:01 +09001591 return ONENAND_BBT_READ_FATAL_ERROR;
1592 }
1593
1594 /* Grab the lock and see if the device is available */
1595 onenand_get_device(mtd, FL_READING);
1596
1597 column = from & (mtd->oobsize - 1);
1598
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001599 readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001600
Kyungmin Park211ac752007-02-07 12:15:01 +09001601 while (read < len) {
1602 cond_resched();
1603
1604 thislen = mtd->oobsize - column;
1605 thislen = min_t(int, thislen, len);
1606
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001607 this->command(mtd, readcmd, from, mtd->oobsize);
Kyungmin Park211ac752007-02-07 12:15:01 +09001608
1609 onenand_update_bufferram(mtd, from, 0);
1610
Kyungmin Park31bb9992009-05-12 13:46:57 -07001611 ret = this->bbt_wait(mtd, FL_READING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001612 if (unlikely(ret))
1613 ret = onenand_recover_lsb(mtd, from, ret);
1614
Kyungmin Park211ac752007-02-07 12:15:01 +09001615 if (ret)
1616 break;
1617
1618 this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
1619 read += thislen;
1620 if (read == len)
1621 break;
1622
1623 buf += thislen;
1624
1625 /* Read more? */
1626 if (read < len) {
1627 /* Update Page size */
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001628 from += this->writesize;
Kyungmin Park211ac752007-02-07 12:15:01 +09001629 column = 0;
1630 }
1631 }
1632
1633 /* Deselect and wake up anyone waiting on the device */
1634 onenand_release_device(mtd);
1635
1636 ops->oobretlen = read;
1637 return ret;
1638}
1639
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001640#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
1641/**
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001642 * onenand_verify_oob - [GENERIC] verify the oob contents after a write
1643 * @param mtd MTD device structure
1644 * @param buf the databuffer to verify
1645 * @param to offset to read from
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001646 */
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001647static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to)
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001648{
1649 struct onenand_chip *this = mtd->priv;
Kyungmin Park69d79182007-12-14 14:47:21 +09001650 u_char *oob_buf = this->oob_buf;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001651 int status, i, readcmd;
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001652
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001653 readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001654
1655 this->command(mtd, readcmd, to, mtd->oobsize);
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001656 onenand_update_bufferram(mtd, to, 0);
1657 status = this->wait(mtd, FL_READING);
1658 if (status)
1659 return status;
1660
Kyungmin Park69d79182007-12-14 14:47:21 +09001661 this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
Kyungmin Park91014e92007-02-12 10:34:39 +09001662 for (i = 0; i < mtd->oobsize; i++)
Kyungmin Park69d79182007-12-14 14:47:21 +09001663 if (buf[i] != 0xFF && buf[i] != oob_buf[i])
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001664 return -EBADMSG;
1665
1666 return 0;
1667}
1668
1669/**
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001670 * onenand_verify - [GENERIC] verify the chip contents after a write
1671 * @param mtd MTD device structure
1672 * @param buf the databuffer to verify
1673 * @param addr offset to read from
1674 * @param len number of bytes to read and compare
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001675 */
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001676static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, size_t len)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001677{
1678 struct onenand_chip *this = mtd->priv;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001679 int ret = 0;
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001680 int thislen, column;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001681
Roman Tereshonkove6da8562011-02-08 12:02:42 +02001682 column = addr & (this->writesize - 1);
1683
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001684 while (len != 0) {
Roman Tereshonkove6da8562011-02-08 12:02:42 +02001685 thislen = min_t(int, this->writesize - column, len);
Kyungmin Park60d84f92006-12-22 16:21:54 +09001686
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001687 this->command(mtd, ONENAND_CMD_READ, addr, this->writesize);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001688
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001689 onenand_update_bufferram(mtd, addr, 0);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001690
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001691 ret = this->wait(mtd, FL_READING);
1692 if (ret)
1693 return ret;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001694
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001695 onenand_update_bufferram(mtd, addr, 1);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001696
Kyungmin Park3328dc32010-04-28 17:46:47 +02001697 this->read_bufferram(mtd, ONENAND_DATARAM, this->verify_buf, 0, mtd->writesize);
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001698
Roman Tereshonkove6da8562011-02-08 12:02:42 +02001699 if (memcmp(buf, this->verify_buf + column, thislen))
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001700 return -EBADMSG;
1701
1702 len -= thislen;
1703 buf += thislen;
1704 addr += thislen;
Roman Tereshonkove6da8562011-02-08 12:02:42 +02001705 column = 0;
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001706 }
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +00001707
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001708 return 0;
1709}
1710#else
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001711#define onenand_verify(...) (0)
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001712#define onenand_verify_oob(...) (0)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001713#endif
1714
Kyungmin Park60d84f92006-12-22 16:21:54 +09001715#define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001716
Richard Purdie6c77fd62008-02-06 10:18:22 +00001717static void onenand_panic_wait(struct mtd_info *mtd)
1718{
1719 struct onenand_chip *this = mtd->priv;
1720 unsigned int interrupt;
1721 int i;
1722
1723 for (i = 0; i < 2000; i++) {
1724 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
1725 if (interrupt & ONENAND_INT_MASTER)
1726 break;
1727 udelay(10);
1728 }
1729}
1730
1731/**
1732 * onenand_panic_write - [MTD Interface] write buffer to FLASH in a panic context
1733 * @param mtd MTD device structure
1734 * @param to offset to write to
1735 * @param len number of bytes to write
1736 * @param retlen pointer to variable to store the number of written bytes
1737 * @param buf the data to write
1738 *
1739 * Write with ECC
1740 */
1741static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
1742 size_t *retlen, const u_char *buf)
1743{
1744 struct onenand_chip *this = mtd->priv;
1745 int column, subpage;
1746 int written = 0;
1747 int ret = 0;
1748
1749 if (this->state == FL_PM_SUSPENDED)
1750 return -EBUSY;
1751
1752 /* Wait for any existing operation to clear */
1753 onenand_panic_wait(mtd);
1754
Brian Norris0a32a102011-07-19 10:06:10 -07001755 pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to,
1756 (int)len);
Richard Purdie6c77fd62008-02-06 10:18:22 +00001757
Richard Purdie6c77fd62008-02-06 10:18:22 +00001758 /* Reject writes, which are not page aligned */
Roel Kluinb73d7e432008-02-16 18:14:35 +01001759 if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301760 printk(KERN_ERR "%s: Attempt to write not page aligned data\n",
1761 __func__);
Richard Purdie6c77fd62008-02-06 10:18:22 +00001762 return -EINVAL;
1763 }
1764
1765 column = to & (mtd->writesize - 1);
1766
1767 /* Loop until all data write */
1768 while (written < len) {
1769 int thislen = min_t(int, mtd->writesize - column, len - written);
1770 u_char *wbuf = (u_char *) buf;
1771
1772 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
1773
1774 /* Partial page write */
1775 subpage = thislen < mtd->writesize;
1776 if (subpage) {
1777 memset(this->page_buf, 0xff, mtd->writesize);
1778 memcpy(this->page_buf + column, buf, thislen);
1779 wbuf = this->page_buf;
1780 }
1781
1782 this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
1783 this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);
1784
1785 this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
1786
1787 onenand_panic_wait(mtd);
1788
1789 /* In partial page write we don't update bufferram */
1790 onenand_update_bufferram(mtd, to, !ret && !subpage);
1791 if (ONENAND_IS_2PLANE(this)) {
1792 ONENAND_SET_BUFFERRAM1(this);
1793 onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage);
1794 }
1795
1796 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301797 printk(KERN_ERR "%s: write failed %d\n", __func__, ret);
Richard Purdie6c77fd62008-02-06 10:18:22 +00001798 break;
1799 }
1800
1801 written += thislen;
1802
1803 if (written == len)
1804 break;
1805
1806 column = 0;
1807 to += thislen;
1808 buf += thislen;
1809 }
1810
1811 *retlen = written;
1812 return ret;
1813}
1814
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001815/**
Brian Norris7854d3f2011-06-23 14:12:08 -07001816 * onenand_fill_auto_oob - [INTERN] oob auto-placement transfer
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001817 * @param mtd MTD device structure
1818 * @param oob_buf oob buffer
1819 * @param buf source address
1820 * @param column oob offset to write to
1821 * @param thislen oob length to write
1822 */
1823static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
1824 const u_char *buf, int column, int thislen)
1825{
1826 struct onenand_chip *this = mtd->priv;
1827 struct nand_oobfree *free;
1828 int writecol = column;
1829 int writeend = column + thislen;
1830 int lastgap = 0;
Kyungmin Parkad286342007-03-23 10:19:52 +09001831 unsigned int i;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001832
Kyungmin Parkad286342007-03-23 10:19:52 +09001833 free = this->ecclayout->oobfree;
1834 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001835 if (writecol >= lastgap)
1836 writecol += free->offset - lastgap;
1837 if (writeend >= lastgap)
1838 writeend += free->offset - lastgap;
1839 lastgap = free->offset + free->length;
1840 }
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 int free_end = free->offset + free->length;
1844 if (free->offset < writeend && free_end > writecol) {
1845 int st = max_t(int,free->offset,writecol);
1846 int ed = min_t(int,free_end,writeend);
1847 int n = ed - st;
1848 memcpy(oob_buf + st, buf, n);
1849 buf += n;
Adrian Hunterc36c46d2007-03-23 17:16:22 +09001850 } else if (column == 0)
Kyungmin Park5bc399e2007-03-09 09:41:07 +09001851 break;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001852 }
1853 return 0;
1854}
1855
1856/**
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001857 * onenand_write_ops_nolock - [OneNAND Interface] write main and/or out-of-band
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001858 * @param mtd MTD device structure
1859 * @param to offset to write to
1860 * @param ops oob operation description structure
1861 *
1862 * Write main and/or oob with ECC
1863 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001864static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001865 struct mtd_oob_ops *ops)
1866{
1867 struct onenand_chip *this = mtd->priv;
Kyungmin Park9ce96902008-11-17 17:54:28 +09001868 int written = 0, column, thislen = 0, subpage = 0;
1869 int prev = 0, prevlen = 0, prev_subpage = 0, first = 1;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001870 int oobwritten = 0, oobcolumn, thisooblen, oobsize;
1871 size_t len = ops->len;
1872 size_t ooblen = ops->ooblen;
1873 const u_char *buf = ops->datbuf;
1874 const u_char *oob = ops->oobbuf;
1875 u_char *oobbuf;
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02001876 int ret = 0, cmd;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001877
Brian Norris0a32a102011-07-19 10:06:10 -07001878 pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to,
1879 (int)len);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001880
1881 /* Initialize retlen, in case of early exit */
1882 ops->retlen = 0;
1883 ops->oobretlen = 0;
1884
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001885 /* Reject writes, which are not page aligned */
Roel Kluinb73d7e432008-02-16 18:14:35 +01001886 if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301887 printk(KERN_ERR "%s: Attempt to write not page aligned data\n",
1888 __func__);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001889 return -EINVAL;
1890 }
1891
Kyungmin Park9ce96902008-11-17 17:54:28 +09001892 /* Check zero length */
1893 if (!len)
1894 return 0;
1895
Brian Norris0612b9d2011-08-30 18:45:40 -07001896 if (ops->mode == MTD_OPS_AUTO_OOB)
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001897 oobsize = this->ecclayout->oobavail;
1898 else
1899 oobsize = mtd->oobsize;
1900
1901 oobcolumn = to & (mtd->oobsize - 1);
1902
1903 column = to & (mtd->writesize - 1);
1904
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001905 /* Loop until all data write */
Kyungmin Park9ce96902008-11-17 17:54:28 +09001906 while (1) {
1907 if (written < len) {
1908 u_char *wbuf = (u_char *) buf;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001909
Kyungmin Park9ce96902008-11-17 17:54:28 +09001910 thislen = min_t(int, mtd->writesize - column, len - written);
1911 thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001912
Kyungmin Park9ce96902008-11-17 17:54:28 +09001913 cond_resched();
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001914
Kyungmin Park9ce96902008-11-17 17:54:28 +09001915 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001916
Kyungmin Park9ce96902008-11-17 17:54:28 +09001917 /* Partial page write */
1918 subpage = thislen < mtd->writesize;
1919 if (subpage) {
1920 memset(this->page_buf, 0xff, mtd->writesize);
1921 memcpy(this->page_buf + column, buf, thislen);
1922 wbuf = this->page_buf;
1923 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001924
Kyungmin Park9ce96902008-11-17 17:54:28 +09001925 this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001926
Kyungmin Park9ce96902008-11-17 17:54:28 +09001927 if (oob) {
1928 oobbuf = this->oob_buf;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001929
Kyungmin Park9ce96902008-11-17 17:54:28 +09001930 /* We send data to spare ram with oobsize
1931 * to prevent byte access */
1932 memset(oobbuf, 0xff, mtd->oobsize);
Brian Norris0612b9d2011-08-30 18:45:40 -07001933 if (ops->mode == MTD_OPS_AUTO_OOB)
Kyungmin Park9ce96902008-11-17 17:54:28 +09001934 onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
1935 else
1936 memcpy(oobbuf + oobcolumn, oob, thisooblen);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001937
Kyungmin Park9ce96902008-11-17 17:54:28 +09001938 oobwritten += thisooblen;
1939 oob += thisooblen;
1940 oobcolumn = 0;
1941 } else
1942 oobbuf = (u_char *) ffchars;
1943
1944 this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001945 } else
Kyungmin Park9ce96902008-11-17 17:54:28 +09001946 ONENAND_SET_NEXT_BUFFERRAM(this);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001947
Kyungmin Park9ce96902008-11-17 17:54:28 +09001948 /*
Mika Korhonen492e1502009-06-09 21:52:35 +03001949 * 2 PLANE, MLC, and Flex-OneNAND do not support
1950 * write-while-program feature.
Kyungmin Park9ce96902008-11-17 17:54:28 +09001951 */
Kyungmin Park6a88c472010-04-28 17:46:45 +02001952 if (!ONENAND_IS_2PLANE(this) && !ONENAND_IS_4KB_PAGE(this) && !first) {
Kyungmin Park9ce96902008-11-17 17:54:28 +09001953 ONENAND_SET_PREV_BUFFERRAM(this);
1954
1955 ret = this->wait(mtd, FL_WRITING);
1956
1957 /* In partial page write we don't update bufferram */
1958 onenand_update_bufferram(mtd, prev, !ret && !prev_subpage);
1959 if (ret) {
1960 written -= prevlen;
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301961 printk(KERN_ERR "%s: write failed %d\n",
1962 __func__, ret);
Kyungmin Park9ce96902008-11-17 17:54:28 +09001963 break;
1964 }
1965
1966 if (written == len) {
1967 /* Only check verify write turn on */
1968 ret = onenand_verify(mtd, buf - len, to - len, len);
1969 if (ret)
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301970 printk(KERN_ERR "%s: verify failed %d\n",
1971 __func__, ret);
Kyungmin Park9ce96902008-11-17 17:54:28 +09001972 break;
1973 }
1974
1975 ONENAND_SET_NEXT_BUFFERRAM(this);
1976 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001977
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02001978 this->ongoing = 0;
1979 cmd = ONENAND_CMD_PROG;
1980
1981 /* Exclude 1st OTP and OTP blocks for cache program feature */
1982 if (ONENAND_IS_CACHE_PROGRAM(this) &&
1983 likely(onenand_block(this, to) != 0) &&
1984 ONENAND_IS_4KB_PAGE(this) &&
1985 ((written + thislen) < len)) {
1986 cmd = ONENAND_CMD_2X_CACHE_PROG;
1987 this->ongoing = 1;
1988 }
1989
1990 this->command(mtd, cmd, to, mtd->writesize);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001991
Kyungmin Park9ce96902008-11-17 17:54:28 +09001992 /*
1993 * 2 PLANE, MLC, and Flex-OneNAND wait here
1994 */
Kyungmin Park6a88c472010-04-28 17:46:45 +02001995 if (ONENAND_IS_2PLANE(this) || ONENAND_IS_4KB_PAGE(this)) {
Kyungmin Park9ce96902008-11-17 17:54:28 +09001996 ret = this->wait(mtd, FL_WRITING);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001997
Kyungmin Park9ce96902008-11-17 17:54:28 +09001998 /* In partial page write we don't update bufferram */
1999 onenand_update_bufferram(mtd, to, !ret && !subpage);
2000 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302001 printk(KERN_ERR "%s: write failed %d\n",
2002 __func__, ret);
Kyungmin Park9ce96902008-11-17 17:54:28 +09002003 break;
2004 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002005
Kyungmin Park9ce96902008-11-17 17:54:28 +09002006 /* Only check verify write turn on */
2007 ret = onenand_verify(mtd, buf, to, thislen);
2008 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302009 printk(KERN_ERR "%s: verify failed %d\n",
2010 __func__, ret);
Kyungmin Park9ce96902008-11-17 17:54:28 +09002011 break;
2012 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002013
Kyungmin Park9ce96902008-11-17 17:54:28 +09002014 written += thislen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002015
Kyungmin Park9ce96902008-11-17 17:54:28 +09002016 if (written == len)
2017 break;
2018
2019 } else
2020 written += thislen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002021
2022 column = 0;
Kyungmin Park9ce96902008-11-17 17:54:28 +09002023 prev_subpage = subpage;
2024 prev = to;
2025 prevlen = thislen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002026 to += thislen;
2027 buf += thislen;
Kyungmin Park9ce96902008-11-17 17:54:28 +09002028 first = 0;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002029 }
2030
Kyungmin Park9ce96902008-11-17 17:54:28 +09002031 /* In error case, clear all bufferrams */
2032 if (written != len)
2033 onenand_invalidate_bufferram(mtd, 0, -1);
2034
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002035 ops->retlen = written;
Kyungmin Park9ce96902008-11-17 17:54:28 +09002036 ops->oobretlen = oobwritten;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002037
2038 return ret;
2039}
2040
2041
2042/**
Brian Norris7854d3f2011-06-23 14:12:08 -07002043 * onenand_write_oob_nolock - [INTERN] OneNAND write out-of-band
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002044 * @param mtd MTD device structure
2045 * @param to offset to write to
2046 * @param len number of bytes to write
2047 * @param retlen pointer to variable to store the number of written bytes
2048 * @param buf the data to write
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002049 * @param mode operation mode
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002050 *
2051 * OneNAND write out-of-band
2052 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002053static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
2054 struct mtd_oob_ops *ops)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002055{
2056 struct onenand_chip *this = mtd->priv;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002057 int column, ret = 0, oobsize;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002058 int written = 0, oobcmd;
Kyungmin Park91014e92007-02-12 10:34:39 +09002059 u_char *oobbuf;
Kyungmin Park12f77c92007-08-30 09:36:05 +09002060 size_t len = ops->ooblen;
2061 const u_char *buf = ops->oobbuf;
Brian Norris905c6bc2011-08-30 18:45:39 -07002062 unsigned int mode = ops->mode;
Kyungmin Park12f77c92007-08-30 09:36:05 +09002063
2064 to += ops->ooboffs;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002065
Brian Norris0a32a102011-07-19 10:06:10 -07002066 pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to,
2067 (int)len);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002068
2069 /* Initialize retlen, in case of early exit */
Kyungmin Park12f77c92007-08-30 09:36:05 +09002070 ops->oobretlen = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002071
Brian Norris0612b9d2011-08-30 18:45:40 -07002072 if (mode == MTD_OPS_AUTO_OOB)
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002073 oobsize = this->ecclayout->oobavail;
2074 else
2075 oobsize = mtd->oobsize;
2076
2077 column = to & (mtd->oobsize - 1);
2078
2079 if (unlikely(column >= oobsize)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302080 printk(KERN_ERR "%s: Attempted to start write outside oob\n",
2081 __func__);
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002082 return -EINVAL;
2083 }
2084
Adrian Hunter52e42002007-02-06 09:15:39 +09002085 /* For compatibility with NAND: Do not allow write past end of page */
Kyungmin Park91014e92007-02-12 10:34:39 +09002086 if (unlikely(column + len > oobsize)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302087 printk(KERN_ERR "%s: Attempt to write past end of page\n",
2088 __func__);
Adrian Hunter52e42002007-02-06 09:15:39 +09002089 return -EINVAL;
2090 }
2091
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002092 /* Do not allow reads past end of device */
2093 if (unlikely(to >= mtd->size ||
2094 column + len > ((mtd->size >> this->page_shift) -
2095 (to >> this->page_shift)) * oobsize)) {
David Woodhouse80327472009-10-05 08:30:04 +01002096 printk(KERN_ERR "%s: Attempted to write past end of device\n",
2097 __func__);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002098 return -EINVAL;
2099 }
2100
Kyungmin Park470bc842007-03-09 10:08:11 +09002101 oobbuf = this->oob_buf;
Kyungmin Park91014e92007-02-12 10:34:39 +09002102
Kyungmin Park8a8f6322010-12-02 09:24:16 +09002103 oobcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002104
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002105 /* Loop until all data write */
2106 while (written < len) {
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002107 int thislen = min_t(int, oobsize, len - written);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002108
Artem Bityutskiy61a7e192006-12-26 16:41:24 +09002109 cond_resched();
2110
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002111 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize);
2112
Kyungmin Park34c10602006-05-12 17:02:46 +03002113 /* We send data to spare ram with oobsize
2114 * to prevent byte access */
Kyungmin Park91014e92007-02-12 10:34:39 +09002115 memset(oobbuf, 0xff, mtd->oobsize);
Brian Norris0612b9d2011-08-30 18:45:40 -07002116 if (mode == MTD_OPS_AUTO_OOB)
Kyungmin Park91014e92007-02-12 10:34:39 +09002117 onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen);
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002118 else
Kyungmin Park91014e92007-02-12 10:34:39 +09002119 memcpy(oobbuf + column, buf, thislen);
2120 this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002121
Kyungmin Park8a8f6322010-12-02 09:24:16 +09002122 if (ONENAND_IS_4KB_PAGE(this)) {
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002123 /* Set main area of DataRAM to 0xff*/
2124 memset(this->page_buf, 0xff, mtd->writesize);
2125 this->write_bufferram(mtd, ONENAND_DATARAM,
2126 this->page_buf, 0, mtd->writesize);
2127 }
2128
2129 this->command(mtd, oobcmd, to, mtd->oobsize);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002130
2131 onenand_update_bufferram(mtd, to, 0);
Kyungmin Parkee9745f2007-06-30 13:57:49 +09002132 if (ONENAND_IS_2PLANE(this)) {
2133 ONENAND_SET_BUFFERRAM1(this);
2134 onenand_update_bufferram(mtd, to + this->writesize, 0);
2135 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002136
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002137 ret = this->wait(mtd, FL_WRITING);
2138 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302139 printk(KERN_ERR "%s: write failed %d\n", __func__, ret);
Kyungmin Park5b4246f2007-02-02 09:39:21 +09002140 break;
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002141 }
2142
Kyungmin Park91014e92007-02-12 10:34:39 +09002143 ret = onenand_verify_oob(mtd, oobbuf, to);
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002144 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302145 printk(KERN_ERR "%s: verify failed %d\n",
2146 __func__, ret);
Kyungmin Park5b4246f2007-02-02 09:39:21 +09002147 break;
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002148 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002149
2150 written += thislen;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002151 if (written == len)
2152 break;
2153
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002154 to += mtd->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002155 buf += thislen;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002156 column = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002157 }
2158
Kyungmin Park12f77c92007-08-30 09:36:05 +09002159 ops->oobretlen = written;
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +00002160
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002161 return ret;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002162}
2163
2164/**
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002165 * onenand_write - [MTD Interface] write buffer to FLASH
2166 * @param mtd MTD device structure
2167 * @param to offset to write to
2168 * @param len number of bytes to write
2169 * @param retlen pointer to variable to store the number of written bytes
2170 * @param buf the data to write
2171 *
2172 * Write with ECC
2173 */
2174static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
2175 size_t *retlen, const u_char *buf)
2176{
2177 struct mtd_oob_ops ops = {
2178 .len = len,
2179 .ooblen = 0,
2180 .datbuf = (u_char *) buf,
2181 .oobbuf = NULL,
2182 };
2183 int ret;
2184
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002185 onenand_get_device(mtd, FL_WRITING);
2186 ret = onenand_write_ops_nolock(mtd, to, &ops);
2187 onenand_release_device(mtd);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002188
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002189 *retlen = ops.retlen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002190 return ret;
2191}
2192
2193/**
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02002194 * onenand_write_oob - [MTD Interface] NAND write data and/or out-of-band
Kyungmin Parke3da8062007-02-15 09:36:39 +09002195 * @param mtd: MTD device structure
2196 * @param to: offset to write
2197 * @param ops: oob operation description structure
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02002198 */
2199static int onenand_write_oob(struct mtd_info *mtd, loff_t to,
2200 struct mtd_oob_ops *ops)
2201{
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002202 int ret;
2203
Kyungmin Park4f4fad22007-02-02 09:22:21 +09002204 switch (ops->mode) {
Brian Norris0612b9d2011-08-30 18:45:40 -07002205 case MTD_OPS_PLACE_OOB:
2206 case MTD_OPS_AUTO_OOB:
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002207 break;
Brian Norris0612b9d2011-08-30 18:45:40 -07002208 case MTD_OPS_RAW:
Kyungmin Park4f4fad22007-02-02 09:22:21 +09002209 /* Not implemented yet */
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002210 default:
2211 return -EINVAL;
2212 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002213
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002214 onenand_get_device(mtd, FL_WRITING);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002215 if (ops->datbuf)
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002216 ret = onenand_write_ops_nolock(mtd, to, ops);
2217 else
2218 ret = onenand_write_oob_nolock(mtd, to, ops);
2219 onenand_release_device(mtd);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002220
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002221 return ret;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02002222}
2223
2224/**
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002225 * onenand_block_isbad_nolock - [GENERIC] Check if a block is marked bad
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002226 * @param mtd MTD device structure
2227 * @param ofs offset from device start
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002228 * @param allowbbt 1, if its allowed to access the bbt area
2229 *
2230 * Check, if the block is bad. Either by reading the bad block table or
2231 * calling of the scan function.
2232 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002233static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int allowbbt)
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002234{
2235 struct onenand_chip *this = mtd->priv;
2236 struct bbm_info *bbm = this->bbm;
2237
2238 /* Return info from the table */
2239 return bbm->isbad_bbt(mtd, ofs, allowbbt);
2240}
2241
Mika Korhonen72073022009-10-23 07:50:43 +02002242
2243static int onenand_multiblock_erase_verify(struct mtd_info *mtd,
2244 struct erase_info *instr)
2245{
2246 struct onenand_chip *this = mtd->priv;
2247 loff_t addr = instr->addr;
2248 int len = instr->len;
2249 unsigned int block_size = (1 << this->erase_shift);
2250 int ret = 0;
2251
2252 while (len) {
2253 this->command(mtd, ONENAND_CMD_ERASE_VERIFY, addr, block_size);
2254 ret = this->wait(mtd, FL_VERIFYING_ERASE);
2255 if (ret) {
2256 printk(KERN_ERR "%s: Failed verify, block %d\n",
2257 __func__, onenand_block(this, addr));
2258 instr->state = MTD_ERASE_FAILED;
2259 instr->fail_addr = addr;
2260 return -1;
2261 }
2262 len -= block_size;
2263 addr += block_size;
2264 }
2265 return 0;
2266}
2267
2268/**
Brian Norris7854d3f2011-06-23 14:12:08 -07002269 * onenand_multiblock_erase - [INTERN] erase block(s) using multiblock erase
Mika Korhonen72073022009-10-23 07:50:43 +02002270 * @param mtd MTD device structure
2271 * @param instr erase instruction
2272 * @param region erase region
2273 *
2274 * Erase one or more blocks up to 64 block at a time
2275 */
2276static int onenand_multiblock_erase(struct mtd_info *mtd,
2277 struct erase_info *instr,
2278 unsigned int block_size)
2279{
2280 struct onenand_chip *this = mtd->priv;
2281 loff_t addr = instr->addr;
2282 int len = instr->len;
2283 int eb_count = 0;
2284 int ret = 0;
2285 int bdry_block = 0;
2286
2287 instr->state = MTD_ERASING;
2288
2289 if (ONENAND_IS_DDP(this)) {
2290 loff_t bdry_addr = this->chipsize >> 1;
2291 if (addr < bdry_addr && (addr + len) > bdry_addr)
2292 bdry_block = bdry_addr >> this->erase_shift;
2293 }
2294
2295 /* Pre-check bbs */
2296 while (len) {
2297 /* Check if we have a bad block, we do not erase bad blocks */
2298 if (onenand_block_isbad_nolock(mtd, addr, 0)) {
2299 printk(KERN_WARNING "%s: attempt to erase a bad block "
2300 "at addr 0x%012llx\n",
2301 __func__, (unsigned long long) addr);
2302 instr->state = MTD_ERASE_FAILED;
2303 return -EIO;
2304 }
2305 len -= block_size;
2306 addr += block_size;
2307 }
2308
2309 len = instr->len;
2310 addr = instr->addr;
2311
2312 /* loop over 64 eb batches */
2313 while (len) {
2314 struct erase_info verify_instr = *instr;
2315 int max_eb_count = MB_ERASE_MAX_BLK_COUNT;
2316
2317 verify_instr.addr = addr;
2318 verify_instr.len = 0;
2319
2320 /* do not cross chip boundary */
2321 if (bdry_block) {
2322 int this_block = (addr >> this->erase_shift);
2323
2324 if (this_block < bdry_block) {
2325 max_eb_count = min(max_eb_count,
2326 (bdry_block - this_block));
2327 }
2328 }
2329
2330 eb_count = 0;
2331
2332 while (len > block_size && eb_count < (max_eb_count - 1)) {
2333 this->command(mtd, ONENAND_CMD_MULTIBLOCK_ERASE,
2334 addr, block_size);
2335 onenand_invalidate_bufferram(mtd, addr, block_size);
2336
2337 ret = this->wait(mtd, FL_PREPARING_ERASE);
2338 if (ret) {
2339 printk(KERN_ERR "%s: Failed multiblock erase, "
2340 "block %d\n", __func__,
2341 onenand_block(this, addr));
2342 instr->state = MTD_ERASE_FAILED;
2343 instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
2344 return -EIO;
2345 }
2346
2347 len -= block_size;
2348 addr += block_size;
2349 eb_count++;
2350 }
2351
2352 /* last block of 64-eb series */
2353 cond_resched();
2354 this->command(mtd, ONENAND_CMD_ERASE, addr, block_size);
2355 onenand_invalidate_bufferram(mtd, addr, block_size);
2356
2357 ret = this->wait(mtd, FL_ERASING);
2358 /* Check if it is write protected */
2359 if (ret) {
2360 printk(KERN_ERR "%s: Failed erase, block %d\n",
2361 __func__, onenand_block(this, addr));
2362 instr->state = MTD_ERASE_FAILED;
2363 instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
2364 return -EIO;
2365 }
2366
2367 len -= block_size;
2368 addr += block_size;
2369 eb_count++;
2370
2371 /* verify */
2372 verify_instr.len = eb_count * block_size;
2373 if (onenand_multiblock_erase_verify(mtd, &verify_instr)) {
2374 instr->state = verify_instr.state;
2375 instr->fail_addr = verify_instr.fail_addr;
2376 return -EIO;
2377 }
2378
2379 }
2380 return 0;
2381}
2382
2383
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002384/**
Brian Norris7854d3f2011-06-23 14:12:08 -07002385 * onenand_block_by_block_erase - [INTERN] erase block(s) using regular erase
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002386 * @param mtd MTD device structure
2387 * @param instr erase instruction
Mika Korhonen73885ae2009-10-23 07:50:42 +02002388 * @param region erase region
2389 * @param block_size erase block size
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002390 *
Mika Korhonen73885ae2009-10-23 07:50:42 +02002391 * Erase one or more blocks one block at a time
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002392 */
Mika Korhonen73885ae2009-10-23 07:50:42 +02002393static int onenand_block_by_block_erase(struct mtd_info *mtd,
2394 struct erase_info *instr,
2395 struct mtd_erase_region_info *region,
2396 unsigned int block_size)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002397{
2398 struct onenand_chip *this = mtd->priv;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002399 loff_t addr = instr->addr;
Mika Korhonen73885ae2009-10-23 07:50:42 +02002400 int len = instr->len;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002401 loff_t region_end = 0;
Mika Korhonen73885ae2009-10-23 07:50:42 +02002402 int ret = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002403
Mika Korhonen73885ae2009-10-23 07:50:42 +02002404 if (region) {
2405 /* region is set for Flex-OneNAND */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002406 region_end = region->offset + region->erasesize * region->numblocks;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002407 }
2408
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002409 instr->state = MTD_ERASING;
2410
Mika Korhonen73885ae2009-10-23 07:50:42 +02002411 /* Loop through the blocks */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002412 while (len) {
Artem Bityutskiy61a7e192006-12-26 16:41:24 +09002413 cond_resched();
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002414
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002415 /* Check if we have a bad block, we do not erase bad blocks */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002416 if (onenand_block_isbad_nolock(mtd, addr, 0)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302417 printk(KERN_WARNING "%s: attempt to erase a bad block "
2418 "at addr 0x%012llx\n",
2419 __func__, (unsigned long long) addr);
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002420 instr->state = MTD_ERASE_FAILED;
Mika Korhonen73885ae2009-10-23 07:50:42 +02002421 return -EIO;
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002422 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002423
2424 this->command(mtd, ONENAND_CMD_ERASE, addr, block_size);
2425
Adrian Hunter480b9df2007-02-07 13:55:19 +02002426 onenand_invalidate_bufferram(mtd, addr, block_size);
2427
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002428 ret = this->wait(mtd, FL_ERASING);
2429 /* Check, if it is write protected */
2430 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302431 printk(KERN_ERR "%s: Failed erase, block %d\n",
2432 __func__, onenand_block(this, addr));
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002433 instr->state = MTD_ERASE_FAILED;
2434 instr->fail_addr = addr;
Mika Korhonen73885ae2009-10-23 07:50:42 +02002435 return -EIO;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002436 }
2437
2438 len -= block_size;
2439 addr += block_size;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002440
john.maxin@nokia.comeff3bba2011-05-06 09:17:21 +00002441 if (region && addr == region_end) {
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002442 if (!len)
2443 break;
2444 region++;
2445
2446 block_size = region->erasesize;
2447 region_end = region->offset + region->erasesize * region->numblocks;
2448
2449 if (len & (block_size - 1)) {
2450 /* FIXME: This should be handled at MTD partitioning level. */
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302451 printk(KERN_ERR "%s: Unaligned address\n",
2452 __func__);
Mika Korhonen73885ae2009-10-23 07:50:42 +02002453 return -EIO;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002454 }
2455 }
Mika Korhonen73885ae2009-10-23 07:50:42 +02002456 }
2457 return 0;
2458}
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002459
Mika Korhonen73885ae2009-10-23 07:50:42 +02002460/**
2461 * onenand_erase - [MTD Interface] erase block(s)
2462 * @param mtd MTD device structure
2463 * @param instr erase instruction
2464 *
2465 * Erase one or more blocks
2466 */
2467static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
2468{
2469 struct onenand_chip *this = mtd->priv;
2470 unsigned int block_size;
2471 loff_t addr = instr->addr;
2472 loff_t len = instr->len;
2473 int ret = 0;
2474 struct mtd_erase_region_info *region = NULL;
2475 loff_t region_offset = 0;
2476
Brian Norris289c0522011-07-19 10:06:09 -07002477 pr_debug("%s: start=0x%012llx, len=%llu\n", __func__,
Brian Norris0a32a102011-07-19 10:06:10 -07002478 (unsigned long long)instr->addr,
2479 (unsigned long long)instr->len);
Mika Korhonen73885ae2009-10-23 07:50:42 +02002480
Mika Korhonen73885ae2009-10-23 07:50:42 +02002481 if (FLEXONENAND(this)) {
2482 /* Find the eraseregion of this address */
2483 int i = flexonenand_region(mtd, addr);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002484
Mika Korhonen73885ae2009-10-23 07:50:42 +02002485 region = &mtd->eraseregions[i];
2486 block_size = region->erasesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002487
Mika Korhonen73885ae2009-10-23 07:50:42 +02002488 /* Start address within region must align on block boundary.
2489 * Erase region's start offset is always block start address.
2490 */
2491 region_offset = region->offset;
2492 } else
2493 block_size = 1 << this->erase_shift;
2494
2495 /* Start address must align on block boundary */
2496 if (unlikely((addr - region_offset) & (block_size - 1))) {
2497 printk(KERN_ERR "%s: Unaligned address\n", __func__);
2498 return -EINVAL;
2499 }
2500
2501 /* Length must align on block boundary */
2502 if (unlikely(len & (block_size - 1))) {
2503 printk(KERN_ERR "%s: Length not block aligned\n", __func__);
2504 return -EINVAL;
2505 }
2506
Mika Korhonen73885ae2009-10-23 07:50:42 +02002507 /* Grab the lock and see if the device is available */
2508 onenand_get_device(mtd, FL_ERASING);
2509
Kyungmin Parkd983c542010-12-06 09:05:18 +09002510 if (ONENAND_IS_4KB_PAGE(this) || region ||
2511 instr->len < MB_ERASE_MIN_BLK_COUNT * block_size) {
Mika Korhonen72073022009-10-23 07:50:43 +02002512 /* region is set for Flex-OneNAND (no mb erase) */
2513 ret = onenand_block_by_block_erase(mtd, instr,
2514 region, block_size);
2515 } else {
2516 ret = onenand_multiblock_erase(mtd, instr, block_size);
2517 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002518
2519 /* Deselect and wake up anyone waiting on the device */
2520 onenand_release_device(mtd);
2521
Adrian Hunter3cd3a862007-10-12 10:34:01 +03002522 /* Do call back function */
Mika Korhonen73885ae2009-10-23 07:50:42 +02002523 if (!ret) {
2524 instr->state = MTD_ERASE_DONE;
Adrian Hunter3cd3a862007-10-12 10:34:01 +03002525 mtd_erase_callback(instr);
Mika Korhonen73885ae2009-10-23 07:50:42 +02002526 }
Adrian Hunter3cd3a862007-10-12 10:34:01 +03002527
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002528 return ret;
2529}
2530
2531/**
2532 * onenand_sync - [MTD Interface] sync
2533 * @param mtd MTD device structure
2534 *
2535 * Sync is actually a wait for chip ready function
2536 */
2537static void onenand_sync(struct mtd_info *mtd)
2538{
Brian Norris289c0522011-07-19 10:06:09 -07002539 pr_debug("%s: called\n", __func__);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002540
2541 /* Grab the lock and see if the device is available */
2542 onenand_get_device(mtd, FL_SYNCING);
2543
2544 /* Release it and go back */
2545 onenand_release_device(mtd);
2546}
2547
2548/**
2549 * onenand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad
2550 * @param mtd MTD device structure
2551 * @param ofs offset relative to mtd start
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002552 *
2553 * Check whether the block is bad
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002554 */
2555static int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs)
2556{
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002557 int ret;
2558
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002559 onenand_get_device(mtd, FL_READING);
2560 ret = onenand_block_isbad_nolock(mtd, ofs, 0);
2561 onenand_release_device(mtd);
2562 return ret;
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002563}
2564
2565/**
2566 * onenand_default_block_markbad - [DEFAULT] mark a block bad
2567 * @param mtd MTD device structure
2568 * @param ofs offset from device start
2569 *
2570 * This is the default implementation, which can be overridden by
2571 * a hardware specific driver.
2572 */
2573static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
2574{
2575 struct onenand_chip *this = mtd->priv;
2576 struct bbm_info *bbm = this->bbm;
2577 u_char buf[2] = {0, 0};
Kyungmin Park12f77c92007-08-30 09:36:05 +09002578 struct mtd_oob_ops ops = {
Brian Norris0612b9d2011-08-30 18:45:40 -07002579 .mode = MTD_OPS_PLACE_OOB,
Kyungmin Park12f77c92007-08-30 09:36:05 +09002580 .ooblen = 2,
2581 .oobbuf = buf,
2582 .ooboffs = 0,
2583 };
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002584 int block;
2585
2586 /* Get block number */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002587 block = onenand_block(this, ofs);
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002588 if (bbm->bbt)
2589 bbm->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
2590
Mika Korhonen492e1502009-06-09 21:52:35 +03002591 /* We write two bytes, so we don't have to mess with 16-bit access */
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002592 ofs += mtd->oobsize + (bbm->badblockpos & ~0x01);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002593 /* FIXME : What to do when marking SLC block in partition
2594 * with MLC erasesize? For now, it is not advisable to
2595 * create partitions containing both SLC and MLC regions.
2596 */
2597 return onenand_write_oob_nolock(mtd, ofs, &ops);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002598}
2599
2600/**
2601 * onenand_block_markbad - [MTD Interface] Mark the block at the given offset as bad
2602 * @param mtd MTD device structure
2603 * @param ofs offset relative to mtd start
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002604 *
2605 * Mark the block as bad
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002606 */
2607static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
2608{
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002609 int ret;
2610
2611 ret = onenand_block_isbad(mtd, ofs);
2612 if (ret) {
2613 /* If it was bad already, return success and do nothing */
2614 if (ret > 0)
2615 return 0;
2616 return ret;
2617 }
2618
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002619 onenand_get_device(mtd, FL_WRITING);
Artem Bityutskiy5942ddb2011-12-23 19:37:38 +02002620 ret = mtd_block_markbad(mtd, ofs);
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002621 onenand_release_device(mtd);
2622 return ret;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002623}
2624
2625/**
Kyungmin Park08f782b2006-11-16 11:29:39 +09002626 * onenand_do_lock_cmd - [OneNAND Interface] Lock or unlock block(s)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002627 * @param mtd MTD device structure
2628 * @param ofs offset relative to mtd start
Kyungmin Park08f782b2006-11-16 11:29:39 +09002629 * @param len number of bytes to lock or unlock
Kyungmin Parke3da8062007-02-15 09:36:39 +09002630 * @param cmd lock or unlock command
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002631 *
Kyungmin Park08f782b2006-11-16 11:29:39 +09002632 * Lock or unlock one or more blocks
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002633 */
Kyungmin Park08f782b2006-11-16 11:29:39 +09002634static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int cmd)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002635{
2636 struct onenand_chip *this = mtd->priv;
2637 int start, end, block, value, status;
Kyungmin Park08f782b2006-11-16 11:29:39 +09002638 int wp_status_mask;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002639
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002640 start = onenand_block(this, ofs);
2641 end = onenand_block(this, ofs + len) - 1;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002642
Kyungmin Park08f782b2006-11-16 11:29:39 +09002643 if (cmd == ONENAND_CMD_LOCK)
2644 wp_status_mask = ONENAND_WP_LS;
2645 else
2646 wp_status_mask = ONENAND_WP_US;
2647
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002648 /* Continuous lock scheme */
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002649 if (this->options & ONENAND_HAS_CONT_LOCK) {
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002650 /* Set start block address */
2651 this->write_word(start, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
2652 /* Set end block address */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002653 this->write_word(end, this->base + ONENAND_REG_END_BLOCK_ADDRESS);
Kyungmin Park08f782b2006-11-16 11:29:39 +09002654 /* Write lock command */
2655 this->command(mtd, cmd, 0, 0);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002656
2657 /* There's no return value */
Kyungmin Park08f782b2006-11-16 11:29:39 +09002658 this->wait(mtd, FL_LOCKING);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002659
2660 /* Sanity check */
2661 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
2662 & ONENAND_CTRL_ONGO)
2663 continue;
2664
2665 /* Check lock status */
2666 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
Kyungmin Park08f782b2006-11-16 11:29:39 +09002667 if (!(status & wp_status_mask))
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302668 printk(KERN_ERR "%s: wp status = 0x%x\n",
2669 __func__, status);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002670
2671 return 0;
2672 }
2673
2674 /* Block lock scheme */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002675 for (block = start; block < end + 1; block++) {
Kyungmin Park20ba89a2005-12-16 11:17:29 +09002676 /* Set block address */
2677 value = onenand_block_address(this, block);
2678 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
2679 /* Select DataRAM for DDP */
2680 value = onenand_bufferram_address(this, block);
2681 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002682 /* Set start block address */
2683 this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
Kyungmin Park08f782b2006-11-16 11:29:39 +09002684 /* Write lock command */
2685 this->command(mtd, cmd, 0, 0);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002686
2687 /* There's no return value */
Kyungmin Park08f782b2006-11-16 11:29:39 +09002688 this->wait(mtd, FL_LOCKING);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002689
2690 /* Sanity check */
2691 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
2692 & ONENAND_CTRL_ONGO)
2693 continue;
2694
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002695 /* Check lock status */
2696 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
Kyungmin Park08f782b2006-11-16 11:29:39 +09002697 if (!(status & wp_status_mask))
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302698 printk(KERN_ERR "%s: block = %d, wp status = 0x%x\n",
2699 __func__, block, status);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002700 }
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +00002701
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002702 return 0;
2703}
2704
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002705/**
Kyungmin Park08f782b2006-11-16 11:29:39 +09002706 * onenand_lock - [MTD Interface] Lock block(s)
2707 * @param mtd MTD device structure
2708 * @param ofs offset relative to mtd start
2709 * @param len number of bytes to unlock
2710 *
2711 * Lock one or more blocks
2712 */
Adrian Hunter69423d92008-12-10 13:37:21 +00002713static int onenand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
Kyungmin Park08f782b2006-11-16 11:29:39 +09002714{
Adrian Hunter34627f02007-10-12 10:19:26 +03002715 int ret;
2716
2717 onenand_get_device(mtd, FL_LOCKING);
2718 ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK);
2719 onenand_release_device(mtd);
2720 return ret;
Kyungmin Park08f782b2006-11-16 11:29:39 +09002721}
2722
Kyungmin Park08f782b2006-11-16 11:29:39 +09002723/**
2724 * onenand_unlock - [MTD Interface] Unlock block(s)
2725 * @param mtd MTD device structure
2726 * @param ofs offset relative to mtd start
2727 * @param len number of bytes to unlock
2728 *
2729 * Unlock one or more blocks
2730 */
Adrian Hunter69423d92008-12-10 13:37:21 +00002731static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
Kyungmin Park08f782b2006-11-16 11:29:39 +09002732{
Adrian Hunter34627f02007-10-12 10:19:26 +03002733 int ret;
2734
2735 onenand_get_device(mtd, FL_LOCKING);
2736 ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
2737 onenand_release_device(mtd);
2738 return ret;
Kyungmin Park08f782b2006-11-16 11:29:39 +09002739}
2740
2741/**
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002742 * onenand_check_lock_status - [OneNAND Interface] Check lock status
2743 * @param this onenand chip data structure
2744 *
2745 * Check lock status
2746 */
Kyungmin Park66a10502008-02-13 15:55:38 +09002747static int onenand_check_lock_status(struct onenand_chip *this)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002748{
2749 unsigned int value, block, status;
2750 unsigned int end;
2751
2752 end = this->chipsize >> this->erase_shift;
2753 for (block = 0; block < end; block++) {
2754 /* Set block address */
2755 value = onenand_block_address(this, block);
2756 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
2757 /* Select DataRAM for DDP */
2758 value = onenand_bufferram_address(this, block);
2759 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
2760 /* Set start block address */
2761 this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
2762
2763 /* Check lock status */
2764 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
Kyungmin Park66a10502008-02-13 15:55:38 +09002765 if (!(status & ONENAND_WP_US)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302766 printk(KERN_ERR "%s: block = %d, wp status = 0x%x\n",
2767 __func__, block, status);
Kyungmin Park66a10502008-02-13 15:55:38 +09002768 return 0;
2769 }
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002770 }
Kyungmin Park66a10502008-02-13 15:55:38 +09002771
2772 return 1;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002773}
2774
2775/**
2776 * onenand_unlock_all - [OneNAND Interface] unlock all blocks
2777 * @param mtd MTD device structure
2778 *
2779 * Unlock all blocks
2780 */
Kyungmin Park66a10502008-02-13 15:55:38 +09002781static void onenand_unlock_all(struct mtd_info *mtd)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002782{
2783 struct onenand_chip *this = mtd->priv;
Kyungmin Park66a10502008-02-13 15:55:38 +09002784 loff_t ofs = 0;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002785 loff_t len = mtd->size;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002786
2787 if (this->options & ONENAND_HAS_UNLOCK_ALL) {
Kyungmin Park10b7a2b2007-01-12 05:45:34 +09002788 /* Set start block address */
2789 this->write_word(0, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002790 /* Write unlock command */
2791 this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0);
2792
2793 /* There's no return value */
Kyungmin Park08f782b2006-11-16 11:29:39 +09002794 this->wait(mtd, FL_LOCKING);
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002795
2796 /* Sanity check */
2797 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
2798 & ONENAND_CTRL_ONGO)
2799 continue;
2800
Kyungmin Park31bb9992009-05-12 13:46:57 -07002801 /* Don't check lock status */
2802 if (this->options & ONENAND_SKIP_UNLOCK_CHECK)
2803 return;
2804
Kyungmin Park66a10502008-02-13 15:55:38 +09002805 /* Check lock status */
2806 if (onenand_check_lock_status(this))
2807 return;
2808
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002809 /* Workaround for all block unlock in DDP */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002810 if (ONENAND_IS_DDP(this) && !FLEXONENAND(this)) {
Kyungmin Park66a10502008-02-13 15:55:38 +09002811 /* All blocks on another chip */
2812 ofs = this->chipsize >> 1;
2813 len = this->chipsize >> 1;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002814 }
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002815 }
2816
Kyungmin Park66a10502008-02-13 15:55:38 +09002817 onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002818}
2819
Kyungmin Park493c6462006-05-12 17:03:07 +03002820#ifdef CONFIG_MTD_ONENAND_OTP
2821
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05302822/**
2823 * onenand_otp_command - Send OTP specific command to OneNAND device
2824 * @param mtd MTD device structure
2825 * @param cmd the command to be sent
2826 * @param addr offset to read from or write to
2827 * @param len number of bytes to read or write
2828 */
2829static int onenand_otp_command(struct mtd_info *mtd, int cmd, loff_t addr,
2830 size_t len)
2831{
2832 struct onenand_chip *this = mtd->priv;
2833 int value, block, page;
2834
2835 /* Address translation */
2836 switch (cmd) {
2837 case ONENAND_CMD_OTP_ACCESS:
2838 block = (int) (addr >> this->erase_shift);
2839 page = -1;
2840 break;
2841
2842 default:
2843 block = (int) (addr >> this->erase_shift);
2844 page = (int) (addr >> this->page_shift);
2845
2846 if (ONENAND_IS_2PLANE(this)) {
2847 /* Make the even block number */
2848 block &= ~1;
2849 /* Is it the odd plane? */
2850 if (addr & this->writesize)
2851 block++;
2852 page >>= 1;
2853 }
2854 page &= this->page_mask;
2855 break;
2856 }
2857
2858 if (block != -1) {
2859 /* Write 'DFS, FBA' of Flash */
2860 value = onenand_block_address(this, block);
2861 this->write_word(value, this->base +
2862 ONENAND_REG_START_ADDRESS1);
2863 }
2864
2865 if (page != -1) {
2866 /* Now we use page size operation */
2867 int sectors = 4, count = 4;
2868 int dataram;
2869
2870 switch (cmd) {
2871 default:
2872 if (ONENAND_IS_2PLANE(this) && cmd == ONENAND_CMD_PROG)
2873 cmd = ONENAND_CMD_2X_PROG;
2874 dataram = ONENAND_CURRENT_BUFFERRAM(this);
2875 break;
2876 }
2877
2878 /* Write 'FPA, FSA' of Flash */
2879 value = onenand_page_address(page, sectors);
2880 this->write_word(value, this->base +
2881 ONENAND_REG_START_ADDRESS8);
2882
2883 /* Write 'BSA, BSC' of DataRAM */
2884 value = onenand_buffer_address(dataram, sectors, count);
2885 this->write_word(value, this->base + ONENAND_REG_START_BUFFER);
2886 }
2887
2888 /* Interrupt clear */
2889 this->write_word(ONENAND_INT_CLEAR, this->base + ONENAND_REG_INTERRUPT);
2890
2891 /* Write command */
2892 this->write_word(cmd, this->base + ONENAND_REG_COMMAND);
2893
2894 return 0;
2895}
2896
2897/**
Brian Norris7854d3f2011-06-23 14:12:08 -07002898 * onenand_otp_write_oob_nolock - [INTERN] OneNAND write out-of-band, specific to OTP
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05302899 * @param mtd MTD device structure
2900 * @param to offset to write to
2901 * @param len number of bytes to write
2902 * @param retlen pointer to variable to store the number of written bytes
2903 * @param buf the data to write
2904 *
2905 * OneNAND write out-of-band only for OTP
2906 */
2907static int onenand_otp_write_oob_nolock(struct mtd_info *mtd, loff_t to,
2908 struct mtd_oob_ops *ops)
2909{
2910 struct onenand_chip *this = mtd->priv;
2911 int column, ret = 0, oobsize;
2912 int written = 0;
2913 u_char *oobbuf;
2914 size_t len = ops->ooblen;
2915 const u_char *buf = ops->oobbuf;
2916 int block, value, status;
2917
2918 to += ops->ooboffs;
2919
2920 /* Initialize retlen, in case of early exit */
2921 ops->oobretlen = 0;
2922
2923 oobsize = mtd->oobsize;
2924
2925 column = to & (mtd->oobsize - 1);
2926
2927 oobbuf = this->oob_buf;
2928
2929 /* Loop until all data write */
2930 while (written < len) {
2931 int thislen = min_t(int, oobsize, len - written);
2932
2933 cond_resched();
2934
2935 block = (int) (to >> this->erase_shift);
2936 /*
2937 * Write 'DFS, FBA' of Flash
2938 * Add: F100h DQ=DFS, FBA
2939 */
2940
2941 value = onenand_block_address(this, block);
2942 this->write_word(value, this->base +
2943 ONENAND_REG_START_ADDRESS1);
2944
2945 /*
2946 * Select DataRAM for DDP
2947 * Add: F101h DQ=DBS
2948 */
2949
2950 value = onenand_bufferram_address(this, block);
2951 this->write_word(value, this->base +
2952 ONENAND_REG_START_ADDRESS2);
2953 ONENAND_SET_NEXT_BUFFERRAM(this);
2954
2955 /*
2956 * Enter OTP access mode
2957 */
2958 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
2959 this->wait(mtd, FL_OTPING);
2960
2961 /* We send data to spare ram with oobsize
2962 * to prevent byte access */
2963 memcpy(oobbuf + column, buf, thislen);
2964
2965 /*
2966 * Write Data into DataRAM
2967 * Add: 8th Word
2968 * in sector0/spare/page0
2969 * DQ=XXFCh
2970 */
2971 this->write_bufferram(mtd, ONENAND_SPARERAM,
2972 oobbuf, 0, mtd->oobsize);
2973
2974 onenand_otp_command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize);
2975 onenand_update_bufferram(mtd, to, 0);
2976 if (ONENAND_IS_2PLANE(this)) {
2977 ONENAND_SET_BUFFERRAM1(this);
2978 onenand_update_bufferram(mtd, to + this->writesize, 0);
2979 }
2980
2981 ret = this->wait(mtd, FL_WRITING);
2982 if (ret) {
2983 printk(KERN_ERR "%s: write failed %d\n", __func__, ret);
2984 break;
2985 }
2986
2987 /* Exit OTP access mode */
2988 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
2989 this->wait(mtd, FL_RESETING);
2990
2991 status = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
2992 status &= 0x60;
2993
2994 if (status == 0x60) {
2995 printk(KERN_DEBUG "\nBLOCK\tSTATUS\n");
2996 printk(KERN_DEBUG "1st Block\tLOCKED\n");
2997 printk(KERN_DEBUG "OTP Block\tLOCKED\n");
2998 } else if (status == 0x20) {
2999 printk(KERN_DEBUG "\nBLOCK\tSTATUS\n");
3000 printk(KERN_DEBUG "1st Block\tLOCKED\n");
3001 printk(KERN_DEBUG "OTP Block\tUN-LOCKED\n");
3002 } else if (status == 0x40) {
3003 printk(KERN_DEBUG "\nBLOCK\tSTATUS\n");
3004 printk(KERN_DEBUG "1st Block\tUN-LOCKED\n");
3005 printk(KERN_DEBUG "OTP Block\tLOCKED\n");
3006 } else {
3007 printk(KERN_DEBUG "Reboot to check\n");
3008 }
3009
3010 written += thislen;
3011 if (written == len)
3012 break;
3013
3014 to += mtd->writesize;
3015 buf += thislen;
3016 column = 0;
3017 }
3018
3019 ops->oobretlen = written;
3020
3021 return ret;
3022}
3023
Mika Korhonen492e1502009-06-09 21:52:35 +03003024/* Internal OTP operation */
Kyungmin Park493c6462006-05-12 17:03:07 +03003025typedef int (*otp_op_t)(struct mtd_info *mtd, loff_t form, size_t len,
3026 size_t *retlen, u_char *buf);
3027
3028/**
3029 * do_otp_read - [DEFAULT] Read OTP block area
3030 * @param mtd MTD device structure
3031 * @param from The offset to read
3032 * @param len number of bytes to read
3033 * @param retlen pointer to variable to store the number of readbytes
3034 * @param buf the databuffer to put/get data
3035 *
3036 * Read OTP block area.
3037 */
3038static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len,
3039 size_t *retlen, u_char *buf)
3040{
3041 struct onenand_chip *this = mtd->priv;
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003042 struct mtd_oob_ops ops = {
3043 .len = len,
3044 .ooblen = 0,
3045 .datbuf = buf,
3046 .oobbuf = NULL,
3047 };
Kyungmin Park493c6462006-05-12 17:03:07 +03003048 int ret;
3049
3050 /* Enter OTP access mode */
3051 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
3052 this->wait(mtd, FL_OTPING);
3053
Kyungmin Park8a8f6322010-12-02 09:24:16 +09003054 ret = ONENAND_IS_4KB_PAGE(this) ?
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003055 onenand_mlc_read_ops_nolock(mtd, from, &ops) :
3056 onenand_read_ops_nolock(mtd, from, &ops);
Kyungmin Park493c6462006-05-12 17:03:07 +03003057
3058 /* Exit OTP access mode */
3059 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
3060 this->wait(mtd, FL_RESETING);
3061
3062 return ret;
3063}
3064
3065/**
3066 * do_otp_write - [DEFAULT] Write OTP block area
3067 * @param mtd MTD device structure
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003068 * @param to The offset to write
Kyungmin Park493c6462006-05-12 17:03:07 +03003069 * @param len number of bytes to write
3070 * @param retlen pointer to variable to store the number of write bytes
3071 * @param buf the databuffer to put/get data
3072 *
3073 * Write OTP block area.
3074 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003075static int do_otp_write(struct mtd_info *mtd, loff_t to, size_t len,
Kyungmin Park493c6462006-05-12 17:03:07 +03003076 size_t *retlen, u_char *buf)
3077{
3078 struct onenand_chip *this = mtd->priv;
3079 unsigned char *pbuf = buf;
3080 int ret;
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003081 struct mtd_oob_ops ops;
Kyungmin Park493c6462006-05-12 17:03:07 +03003082
3083 /* Force buffer page aligned */
Joern Engel28318772006-05-22 23:18:05 +02003084 if (len < mtd->writesize) {
Kyungmin Park493c6462006-05-12 17:03:07 +03003085 memcpy(this->page_buf, buf, len);
Joern Engel28318772006-05-22 23:18:05 +02003086 memset(this->page_buf + len, 0xff, mtd->writesize - len);
Kyungmin Park493c6462006-05-12 17:03:07 +03003087 pbuf = this->page_buf;
Joern Engel28318772006-05-22 23:18:05 +02003088 len = mtd->writesize;
Kyungmin Park493c6462006-05-12 17:03:07 +03003089 }
3090
3091 /* Enter OTP access mode */
3092 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
3093 this->wait(mtd, FL_OTPING);
3094
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003095 ops.len = len;
3096 ops.ooblen = 0;
Kyungmin Park14370852007-10-10 13:48:14 +09003097 ops.datbuf = pbuf;
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003098 ops.oobbuf = NULL;
3099 ret = onenand_write_ops_nolock(mtd, to, &ops);
3100 *retlen = ops.retlen;
Kyungmin Park493c6462006-05-12 17:03:07 +03003101
3102 /* Exit OTP access mode */
3103 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
3104 this->wait(mtd, FL_RESETING);
3105
3106 return ret;
3107}
3108
3109/**
3110 * do_otp_lock - [DEFAULT] Lock OTP block area
3111 * @param mtd MTD device structure
3112 * @param from The offset to lock
3113 * @param len number of bytes to lock
3114 * @param retlen pointer to variable to store the number of lock bytes
3115 * @param buf the databuffer to put/get data
3116 *
3117 * Lock OTP block area.
3118 */
3119static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len,
3120 size_t *retlen, u_char *buf)
3121{
3122 struct onenand_chip *this = mtd->priv;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003123 struct mtd_oob_ops ops;
Kyungmin Park493c6462006-05-12 17:03:07 +03003124 int ret;
3125
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003126 if (FLEXONENAND(this)) {
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303127
3128 /* Enter OTP access mode */
3129 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
3130 this->wait(mtd, FL_OTPING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003131 /*
3132 * For Flex-OneNAND, we write lock mark to 1st word of sector 4 of
3133 * main area of page 49.
3134 */
3135 ops.len = mtd->writesize;
3136 ops.ooblen = 0;
3137 ops.datbuf = buf;
3138 ops.oobbuf = NULL;
3139 ret = onenand_write_ops_nolock(mtd, mtd->writesize * 49, &ops);
3140 *retlen = ops.retlen;
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303141
3142 /* Exit OTP access mode */
3143 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
3144 this->wait(mtd, FL_RESETING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003145 } else {
Brian Norris0612b9d2011-08-30 18:45:40 -07003146 ops.mode = MTD_OPS_PLACE_OOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003147 ops.ooblen = len;
3148 ops.oobbuf = buf;
3149 ops.ooboffs = 0;
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303150 ret = onenand_otp_write_oob_nolock(mtd, from, &ops);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003151 *retlen = ops.oobretlen;
3152 }
Kyungmin Park493c6462006-05-12 17:03:07 +03003153
Kyungmin Park493c6462006-05-12 17:03:07 +03003154 return ret;
3155}
3156
3157/**
3158 * onenand_otp_walk - [DEFAULT] Handle OTP operation
3159 * @param mtd MTD device structure
3160 * @param from The offset to read/write
3161 * @param len number of bytes to read/write
3162 * @param retlen pointer to variable to store the number of read bytes
3163 * @param buf the databuffer to put/get data
3164 * @param action do given action
3165 * @param mode specify user and factory
3166 *
3167 * Handle OTP operation.
3168 */
3169static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
3170 size_t *retlen, u_char *buf,
3171 otp_op_t action, int mode)
3172{
3173 struct onenand_chip *this = mtd->priv;
3174 int otp_pages;
3175 int density;
3176 int ret = 0;
3177
3178 *retlen = 0;
3179
Kyungmin Parke71f04f2007-12-11 11:23:45 +09003180 density = onenand_get_density(this->device_id);
Kyungmin Park493c6462006-05-12 17:03:07 +03003181 if (density < ONENAND_DEVICE_DENSITY_512Mb)
3182 otp_pages = 20;
3183 else
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303184 otp_pages = 50;
Kyungmin Park493c6462006-05-12 17:03:07 +03003185
3186 if (mode == MTD_OTP_FACTORY) {
Joern Engel28318772006-05-22 23:18:05 +02003187 from += mtd->writesize * otp_pages;
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303188 otp_pages = ONENAND_PAGES_PER_BLOCK - otp_pages;
Kyungmin Park493c6462006-05-12 17:03:07 +03003189 }
3190
3191 /* Check User/Factory boundary */
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303192 if (mode == MTD_OTP_USER) {
Roel Kluin0a032a42009-12-16 01:37:17 +01003193 if (mtd->writesize * otp_pages < from + len)
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303194 return 0;
3195 } else {
Roel Kluin0a032a42009-12-16 01:37:17 +01003196 if (mtd->writesize * otp_pages < len)
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303197 return 0;
3198 }
Kyungmin Park493c6462006-05-12 17:03:07 +03003199
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003200 onenand_get_device(mtd, FL_OTPING);
Kyungmin Park493c6462006-05-12 17:03:07 +03003201 while (len > 0 && otp_pages > 0) {
3202 if (!action) { /* OTP Info functions */
3203 struct otp_info *otpinfo;
3204
3205 len -= sizeof(struct otp_info);
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003206 if (len <= 0) {
3207 ret = -ENOSPC;
3208 break;
3209 }
Kyungmin Park493c6462006-05-12 17:03:07 +03003210
3211 otpinfo = (struct otp_info *) buf;
3212 otpinfo->start = from;
Joern Engel28318772006-05-22 23:18:05 +02003213 otpinfo->length = mtd->writesize;
Kyungmin Park493c6462006-05-12 17:03:07 +03003214 otpinfo->locked = 0;
3215
Joern Engel28318772006-05-22 23:18:05 +02003216 from += mtd->writesize;
Kyungmin Park493c6462006-05-12 17:03:07 +03003217 buf += sizeof(struct otp_info);
3218 *retlen += sizeof(struct otp_info);
3219 } else {
3220 size_t tmp_retlen;
Kyungmin Park493c6462006-05-12 17:03:07 +03003221
3222 ret = action(mtd, from, len, &tmp_retlen, buf);
3223
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303224 buf += tmp_retlen;
3225 len -= tmp_retlen;
3226 *retlen += tmp_retlen;
Kyungmin Park493c6462006-05-12 17:03:07 +03003227
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003228 if (ret)
3229 break;
Kyungmin Park493c6462006-05-12 17:03:07 +03003230 }
3231 otp_pages--;
3232 }
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003233 onenand_release_device(mtd);
Kyungmin Park493c6462006-05-12 17:03:07 +03003234
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003235 return ret;
Kyungmin Park493c6462006-05-12 17:03:07 +03003236}
3237
3238/**
3239 * onenand_get_fact_prot_info - [MTD Interface] Read factory OTP info
3240 * @param mtd MTD device structure
3241 * @param buf the databuffer to put/get data
3242 * @param len number of bytes to read
3243 *
3244 * Read factory OTP info.
3245 */
3246static int onenand_get_fact_prot_info(struct mtd_info *mtd,
3247 struct otp_info *buf, size_t len)
3248{
3249 size_t retlen;
3250 int ret;
3251
3252 ret = onenand_otp_walk(mtd, 0, len, &retlen, (u_char *) buf, NULL, MTD_OTP_FACTORY);
3253
3254 return ret ? : retlen;
3255}
3256
3257/**
3258 * onenand_read_fact_prot_reg - [MTD Interface] Read factory OTP area
3259 * @param mtd MTD device structure
3260 * @param from The offset to read
3261 * @param len number of bytes to read
3262 * @param retlen pointer to variable to store the number of read bytes
3263 * @param buf the databuffer to put/get data
3264 *
3265 * Read factory OTP area.
3266 */
3267static int onenand_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
3268 size_t len, size_t *retlen, u_char *buf)
3269{
3270 return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_read, MTD_OTP_FACTORY);
3271}
3272
3273/**
3274 * onenand_get_user_prot_info - [MTD Interface] Read user OTP info
3275 * @param mtd MTD device structure
3276 * @param buf the databuffer to put/get data
3277 * @param len number of bytes to read
3278 *
3279 * Read user OTP info.
3280 */
3281static int onenand_get_user_prot_info(struct mtd_info *mtd,
3282 struct otp_info *buf, size_t len)
3283{
3284 size_t retlen;
3285 int ret;
3286
3287 ret = onenand_otp_walk(mtd, 0, len, &retlen, (u_char *) buf, NULL, MTD_OTP_USER);
3288
3289 return ret ? : retlen;
3290}
3291
3292/**
3293 * onenand_read_user_prot_reg - [MTD Interface] Read user OTP area
3294 * @param mtd MTD device structure
3295 * @param from The offset to read
3296 * @param len number of bytes to read
3297 * @param retlen pointer to variable to store the number of read bytes
3298 * @param buf the databuffer to put/get data
3299 *
3300 * Read user OTP area.
3301 */
3302static int onenand_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
3303 size_t len, size_t *retlen, u_char *buf)
3304{
3305 return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_read, MTD_OTP_USER);
3306}
3307
3308/**
3309 * onenand_write_user_prot_reg - [MTD Interface] Write user OTP area
3310 * @param mtd MTD device structure
3311 * @param from The offset to write
3312 * @param len number of bytes to write
3313 * @param retlen pointer to variable to store the number of write bytes
3314 * @param buf the databuffer to put/get data
3315 *
3316 * Write user OTP area.
3317 */
3318static int onenand_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
3319 size_t len, size_t *retlen, u_char *buf)
3320{
3321 return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_write, MTD_OTP_USER);
3322}
3323
3324/**
3325 * onenand_lock_user_prot_reg - [MTD Interface] Lock user OTP area
3326 * @param mtd MTD device structure
3327 * @param from The offset to lock
3328 * @param len number of bytes to unlock
3329 *
3330 * Write lock mark on spare area in page 0 in OTP block
3331 */
3332static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
3333 size_t len)
3334{
Kyungmin Park69d79182007-12-14 14:47:21 +09003335 struct onenand_chip *this = mtd->priv;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003336 u_char *buf = FLEXONENAND(this) ? this->page_buf : this->oob_buf;
Kyungmin Park493c6462006-05-12 17:03:07 +03003337 size_t retlen;
3338 int ret;
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303339 unsigned int otp_lock_offset = ONENAND_OTP_LOCK_OFFSET;
Kyungmin Park493c6462006-05-12 17:03:07 +03003340
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003341 memset(buf, 0xff, FLEXONENAND(this) ? this->writesize
3342 : mtd->oobsize);
Kyungmin Park493c6462006-05-12 17:03:07 +03003343 /*
Kyungmin Park493c6462006-05-12 17:03:07 +03003344 * Write lock mark to 8th word of sector0 of page0 of the spare0.
3345 * We write 16 bytes spare area instead of 2 bytes.
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003346 * For Flex-OneNAND, we write lock mark to 1st word of sector 4 of
3347 * main area of page 49.
Kyungmin Park493c6462006-05-12 17:03:07 +03003348 */
Kyungmin Park493c6462006-05-12 17:03:07 +03003349
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003350 from = 0;
3351 len = FLEXONENAND(this) ? mtd->writesize : 16;
3352
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303353 /*
3354 * Note: OTP lock operation
3355 * OTP block : 0xXXFC XX 1111 1100
3356 * 1st block : 0xXXF3 (If chip support) XX 1111 0011
3357 * Both : 0xXXF0 (If chip support) XX 1111 0000
3358 */
3359 if (FLEXONENAND(this))
3360 otp_lock_offset = FLEXONENAND_OTP_LOCK_OFFSET;
3361
3362 /* ONENAND_OTP_AREA | ONENAND_OTP_BLOCK0 | ONENAND_OTP_AREA_BLOCK0 */
3363 if (otp == 1)
3364 buf[otp_lock_offset] = 0xFC;
3365 else if (otp == 2)
3366 buf[otp_lock_offset] = 0xF3;
3367 else if (otp == 3)
3368 buf[otp_lock_offset] = 0xF0;
3369 else if (otp != 0)
3370 printk(KERN_DEBUG "[OneNAND] Invalid option selected for OTP\n");
3371
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003372 ret = onenand_otp_walk(mtd, from, len, &retlen, buf, do_otp_lock, MTD_OTP_USER);
Kyungmin Park493c6462006-05-12 17:03:07 +03003373
3374 return ret ? : retlen;
3375}
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303376
Kyungmin Park493c6462006-05-12 17:03:07 +03003377#endif /* CONFIG_MTD_ONENAND_OTP */
3378
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003379/**
Kyungmin Park75384b02007-01-18 11:10:57 +09003380 * onenand_check_features - Check and set OneNAND features
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003381 * @param mtd MTD data structure
3382 *
Kyungmin Park75384b02007-01-18 11:10:57 +09003383 * Check and set OneNAND features
3384 * - lock scheme
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003385 * - two plane
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003386 */
Kyungmin Park75384b02007-01-18 11:10:57 +09003387static void onenand_check_features(struct mtd_info *mtd)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003388{
3389 struct onenand_chip *this = mtd->priv;
Roman Tereshonkovedb44b92010-10-11 14:47:32 +03003390 unsigned int density, process, numbufs;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003391
3392 /* Lock scheme depends on density and process */
Kyungmin Parke71f04f2007-12-11 11:23:45 +09003393 density = onenand_get_density(this->device_id);
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003394 process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT;
Roman Tereshonkovedb44b92010-10-11 14:47:32 +03003395 numbufs = this->read_word(this->base + ONENAND_REG_NUM_BUFFERS) >> 8;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003396
3397 /* Lock scheme */
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003398 switch (density) {
3399 case ONENAND_DEVICE_DENSITY_4Gb:
Kyungmin Park6a88c472010-04-28 17:46:45 +02003400 if (ONENAND_IS_DDP(this))
3401 this->options |= ONENAND_HAS_2PLANE;
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02003402 else if (numbufs == 1) {
Kyungmin Park6a88c472010-04-28 17:46:45 +02003403 this->options |= ONENAND_HAS_4KB_PAGE;
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02003404 this->options |= ONENAND_HAS_CACHE_PROGRAM;
Kyungmin Parke1c10242011-06-22 14:16:49 +09003405 /*
3406 * There are two different 4KiB pagesize chips
3407 * and no way to detect it by H/W config values.
3408 *
3409 * To detect the correct NOP for each chips,
3410 * It should check the version ID as workaround.
3411 *
3412 * Now it has as following
3413 * KFM4G16Q4M has NOP 4 with version ID 0x0131
3414 * KFM4G16Q5M has NOP 1 with versoin ID 0x013e
3415 */
3416 if ((this->version_id & 0xf) == 0xe)
3417 this->options |= ONENAND_HAS_NOP_1;
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02003418 }
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003419
3420 case ONENAND_DEVICE_DENSITY_2Gb:
Mika Korhonen492e1502009-06-09 21:52:35 +03003421 /* 2Gb DDP does not have 2 plane */
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003422 if (!ONENAND_IS_DDP(this))
3423 this->options |= ONENAND_HAS_2PLANE;
3424 this->options |= ONENAND_HAS_UNLOCK_ALL;
3425
3426 case ONENAND_DEVICE_DENSITY_1Gb:
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003427 /* A-Die has all block unlock */
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003428 if (process)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003429 this->options |= ONENAND_HAS_UNLOCK_ALL;
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003430 break;
3431
3432 default:
3433 /* Some OneNAND has continuous lock scheme */
3434 if (!process)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003435 this->options |= ONENAND_HAS_CONT_LOCK;
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003436 break;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003437 }
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003438
Kyungmin Park8a8f6322010-12-02 09:24:16 +09003439 /* The MLC has 4KiB pagesize. */
3440 if (ONENAND_IS_MLC(this))
3441 this->options |= ONENAND_HAS_4KB_PAGE;
3442
3443 if (ONENAND_IS_4KB_PAGE(this))
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003444 this->options &= ~ONENAND_HAS_2PLANE;
3445
3446 if (FLEXONENAND(this)) {
3447 this->options &= ~ONENAND_HAS_CONT_LOCK;
3448 this->options |= ONENAND_HAS_UNLOCK_ALL;
3449 }
3450
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003451 if (this->options & ONENAND_HAS_CONT_LOCK)
3452 printk(KERN_DEBUG "Lock scheme is Continuous Lock\n");
3453 if (this->options & ONENAND_HAS_UNLOCK_ALL)
3454 printk(KERN_DEBUG "Chip support all block unlock\n");
3455 if (this->options & ONENAND_HAS_2PLANE)
3456 printk(KERN_DEBUG "Chip has 2 plane\n");
Kyungmin Park6a88c472010-04-28 17:46:45 +02003457 if (this->options & ONENAND_HAS_4KB_PAGE)
3458 printk(KERN_DEBUG "Chip has 4KiB pagesize\n");
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02003459 if (this->options & ONENAND_HAS_CACHE_PROGRAM)
3460 printk(KERN_DEBUG "Chip has cache program feature\n");
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003461}
3462
3463/**
Kyungmin Parke3da8062007-02-15 09:36:39 +09003464 * onenand_print_device_info - Print device & version ID
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003465 * @param device device ID
Kyungmin Parke3da8062007-02-15 09:36:39 +09003466 * @param version version ID
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003467 *
Kyungmin Parke3da8062007-02-15 09:36:39 +09003468 * Print device & version ID
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003469 */
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003470static void onenand_print_device_info(int device, int version)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003471{
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003472 int vcc, demuxed, ddp, density, flexonenand;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003473
3474 vcc = device & ONENAND_DEVICE_VCC_MASK;
3475 demuxed = device & ONENAND_DEVICE_IS_DEMUX;
3476 ddp = device & ONENAND_DEVICE_IS_DDP;
Kyungmin Parke71f04f2007-12-11 11:23:45 +09003477 density = onenand_get_density(device);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003478 flexonenand = device & DEVICE_IS_FLEXONENAND;
3479 printk(KERN_INFO "%s%sOneNAND%s %dMB %sV 16-bit (0x%02x)\n",
3480 demuxed ? "" : "Muxed ",
3481 flexonenand ? "Flex-" : "",
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003482 ddp ? "(DDP)" : "",
3483 (16 << density),
3484 vcc ? "2.65/3.3" : "1.8",
3485 device);
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003486 printk(KERN_INFO "OneNAND version = 0x%04x\n", version);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003487}
3488
3489static const struct onenand_manufacturers onenand_manuf_ids[] = {
3490 {ONENAND_MFR_SAMSUNG, "Samsung"},
Adrian Hunteree8f3762009-05-05 11:04:19 +03003491 {ONENAND_MFR_NUMONYX, "Numonyx"},
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003492};
3493
3494/**
3495 * onenand_check_maf - Check manufacturer ID
3496 * @param manuf manufacturer ID
3497 *
3498 * Check manufacturer ID
3499 */
3500static int onenand_check_maf(int manuf)
3501{
Kyungmin Park37b1cc32005-12-16 11:17:29 +09003502 int size = ARRAY_SIZE(onenand_manuf_ids);
3503 char *name;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003504 int i;
3505
Kyungmin Park37b1cc32005-12-16 11:17:29 +09003506 for (i = 0; i < size; i++)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003507 if (manuf == onenand_manuf_ids[i].id)
3508 break;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003509
Kyungmin Park37b1cc32005-12-16 11:17:29 +09003510 if (i < size)
3511 name = onenand_manuf_ids[i].name;
3512 else
3513 name = "Unknown";
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003514
Kyungmin Park37b1cc32005-12-16 11:17:29 +09003515 printk(KERN_DEBUG "OneNAND Manufacturer: %s (0x%0x)\n", name, manuf);
3516
3517 return (i == size);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003518}
3519
3520/**
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003521* flexonenand_get_boundary - Reads the SLC boundary
3522* @param onenand_info - onenand info structure
3523**/
3524static int flexonenand_get_boundary(struct mtd_info *mtd)
3525{
3526 struct onenand_chip *this = mtd->priv;
3527 unsigned die, bdry;
Brian Norris6b7368c2013-08-27 18:01:19 -07003528 int syscfg, locked;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003529
3530 /* Disable ECC */
3531 syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
3532 this->write_word((syscfg | 0x0100), this->base + ONENAND_REG_SYS_CFG1);
3533
3534 for (die = 0; die < this->dies; die++) {
3535 this->command(mtd, FLEXONENAND_CMD_PI_ACCESS, die, 0);
3536 this->wait(mtd, FL_SYNCING);
3537
3538 this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0);
Brian Norris6b7368c2013-08-27 18:01:19 -07003539 this->wait(mtd, FL_READING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003540
3541 bdry = this->read_word(this->base + ONENAND_DATARAM);
3542 if ((bdry >> FLEXONENAND_PI_UNLOCK_SHIFT) == 3)
3543 locked = 0;
3544 else
3545 locked = 1;
3546 this->boundary[die] = bdry & FLEXONENAND_PI_MASK;
3547
3548 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
Brian Norris6b7368c2013-08-27 18:01:19 -07003549 this->wait(mtd, FL_RESETING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003550
3551 printk(KERN_INFO "Die %d boundary: %d%s\n", die,
3552 this->boundary[die], locked ? "(Locked)" : "(Unlocked)");
3553 }
3554
3555 /* Enable ECC */
3556 this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
3557 return 0;
3558}
3559
3560/**
3561 * flexonenand_get_size - Fill up fields in onenand_chip and mtd_info
3562 * boundary[], diesize[], mtd->size, mtd->erasesize
3563 * @param mtd - MTD device structure
3564 */
3565static void flexonenand_get_size(struct mtd_info *mtd)
3566{
3567 struct onenand_chip *this = mtd->priv;
3568 int die, i, eraseshift, density;
3569 int blksperdie, maxbdry;
3570 loff_t ofs;
3571
3572 density = onenand_get_density(this->device_id);
3573 blksperdie = ((loff_t)(16 << density) << 20) >> (this->erase_shift);
3574 blksperdie >>= ONENAND_IS_DDP(this) ? 1 : 0;
3575 maxbdry = blksperdie - 1;
3576 eraseshift = this->erase_shift - 1;
3577
3578 mtd->numeraseregions = this->dies << 1;
3579
3580 /* This fills up the device boundary */
3581 flexonenand_get_boundary(mtd);
3582 die = ofs = 0;
3583 i = -1;
3584 for (; die < this->dies; die++) {
3585 if (!die || this->boundary[die-1] != maxbdry) {
3586 i++;
3587 mtd->eraseregions[i].offset = ofs;
3588 mtd->eraseregions[i].erasesize = 1 << eraseshift;
3589 mtd->eraseregions[i].numblocks =
3590 this->boundary[die] + 1;
3591 ofs += mtd->eraseregions[i].numblocks << eraseshift;
3592 eraseshift++;
3593 } else {
3594 mtd->numeraseregions -= 1;
3595 mtd->eraseregions[i].numblocks +=
3596 this->boundary[die] + 1;
3597 ofs += (this->boundary[die] + 1) << (eraseshift - 1);
3598 }
3599 if (this->boundary[die] != maxbdry) {
3600 i++;
3601 mtd->eraseregions[i].offset = ofs;
3602 mtd->eraseregions[i].erasesize = 1 << eraseshift;
3603 mtd->eraseregions[i].numblocks = maxbdry ^
3604 this->boundary[die];
3605 ofs += mtd->eraseregions[i].numblocks << eraseshift;
3606 eraseshift--;
3607 } else
3608 mtd->numeraseregions -= 1;
3609 }
3610
3611 /* Expose MLC erase size except when all blocks are SLC */
3612 mtd->erasesize = 1 << this->erase_shift;
3613 if (mtd->numeraseregions == 1)
3614 mtd->erasesize >>= 1;
3615
3616 printk(KERN_INFO "Device has %d eraseregions\n", mtd->numeraseregions);
3617 for (i = 0; i < mtd->numeraseregions; i++)
3618 printk(KERN_INFO "[offset: 0x%08x, erasesize: 0x%05x,"
3619 " numblocks: %04u]\n",
3620 (unsigned int) mtd->eraseregions[i].offset,
3621 mtd->eraseregions[i].erasesize,
3622 mtd->eraseregions[i].numblocks);
3623
3624 for (die = 0, mtd->size = 0; die < this->dies; die++) {
3625 this->diesize[die] = (loff_t)blksperdie << this->erase_shift;
3626 this->diesize[die] -= (loff_t)(this->boundary[die] + 1)
3627 << (this->erase_shift - 1);
3628 mtd->size += this->diesize[die];
3629 }
3630}
3631
3632/**
3633 * flexonenand_check_blocks_erased - Check if blocks are erased
3634 * @param mtd_info - mtd info structure
3635 * @param start - first erase block to check
3636 * @param end - last erase block to check
3637 *
3638 * Converting an unerased block from MLC to SLC
3639 * causes byte values to change. Since both data and its ECC
3640 * have changed, reads on the block give uncorrectable error.
3641 * This might lead to the block being detected as bad.
3642 *
3643 * Avoid this by ensuring that the block to be converted is
3644 * erased.
3645 */
3646static int flexonenand_check_blocks_erased(struct mtd_info *mtd, int start, int end)
3647{
3648 struct onenand_chip *this = mtd->priv;
3649 int i, ret;
3650 int block;
3651 struct mtd_oob_ops ops = {
Brian Norris0612b9d2011-08-30 18:45:40 -07003652 .mode = MTD_OPS_PLACE_OOB,
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003653 .ooboffs = 0,
3654 .ooblen = mtd->oobsize,
3655 .datbuf = NULL,
3656 .oobbuf = this->oob_buf,
3657 };
3658 loff_t addr;
3659
3660 printk(KERN_DEBUG "Check blocks from %d to %d\n", start, end);
3661
3662 for (block = start; block <= end; block++) {
3663 addr = flexonenand_addr(this, block);
3664 if (onenand_block_isbad_nolock(mtd, addr, 0))
3665 continue;
3666
3667 /*
3668 * Since main area write results in ECC write to spare,
3669 * it is sufficient to check only ECC bytes for change.
3670 */
3671 ret = onenand_read_oob_nolock(mtd, addr, &ops);
3672 if (ret)
3673 return ret;
3674
3675 for (i = 0; i < mtd->oobsize; i++)
3676 if (this->oob_buf[i] != 0xff)
3677 break;
3678
3679 if (i != mtd->oobsize) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303680 printk(KERN_WARNING "%s: Block %d not erased.\n",
3681 __func__, block);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003682 return 1;
3683 }
3684 }
3685
3686 return 0;
3687}
3688
3689/**
3690 * flexonenand_set_boundary - Writes the SLC boundary
3691 * @param mtd - mtd info structure
3692 */
Sachin Kamat01319502012-09-22 11:42:31 +05303693static int flexonenand_set_boundary(struct mtd_info *mtd, int die,
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003694 int boundary, int lock)
3695{
3696 struct onenand_chip *this = mtd->priv;
3697 int ret, density, blksperdie, old, new, thisboundary;
3698 loff_t addr;
3699
3700 /* Change only once for SDP Flex-OneNAND */
3701 if (die && (!ONENAND_IS_DDP(this)))
3702 return 0;
3703
3704 /* boundary value of -1 indicates no required change */
3705 if (boundary < 0 || boundary == this->boundary[die])
3706 return 0;
3707
3708 density = onenand_get_density(this->device_id);
3709 blksperdie = ((16 << density) << 20) >> this->erase_shift;
3710 blksperdie >>= ONENAND_IS_DDP(this) ? 1 : 0;
3711
3712 if (boundary >= blksperdie) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303713 printk(KERN_ERR "%s: Invalid boundary value. "
3714 "Boundary not changed.\n", __func__);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003715 return -EINVAL;
3716 }
3717
3718 /* Check if converting blocks are erased */
3719 old = this->boundary[die] + (die * this->density_mask);
3720 new = boundary + (die * this->density_mask);
3721 ret = flexonenand_check_blocks_erased(mtd, min(old, new) + 1, max(old, new));
3722 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303723 printk(KERN_ERR "%s: Please erase blocks "
3724 "before boundary change\n", __func__);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003725 return ret;
3726 }
3727
3728 this->command(mtd, FLEXONENAND_CMD_PI_ACCESS, die, 0);
3729 this->wait(mtd, FL_SYNCING);
3730
3731 /* Check is boundary is locked */
3732 this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0);
Brian Norris6b7368c2013-08-27 18:01:19 -07003733 this->wait(mtd, FL_READING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003734
3735 thisboundary = this->read_word(this->base + ONENAND_DATARAM);
3736 if ((thisboundary >> FLEXONENAND_PI_UNLOCK_SHIFT) != 3) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303737 printk(KERN_ERR "%s: boundary locked\n", __func__);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003738 ret = 1;
3739 goto out;
3740 }
3741
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303742 printk(KERN_INFO "Changing die %d boundary: %d%s\n",
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003743 die, boundary, lock ? "(Locked)" : "(Unlocked)");
3744
3745 addr = die ? this->diesize[0] : 0;
3746
3747 boundary &= FLEXONENAND_PI_MASK;
3748 boundary |= lock ? 0 : (3 << FLEXONENAND_PI_UNLOCK_SHIFT);
3749
3750 this->command(mtd, ONENAND_CMD_ERASE, addr, 0);
3751 ret = this->wait(mtd, FL_ERASING);
3752 if (ret) {
Mika Korhonenf369c7e2009-10-23 07:50:44 +02003753 printk(KERN_ERR "%s: Failed PI erase for Die %d\n",
3754 __func__, die);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003755 goto out;
3756 }
3757
3758 this->write_word(boundary, this->base + ONENAND_DATARAM);
3759 this->command(mtd, ONENAND_CMD_PROG, addr, 0);
3760 ret = this->wait(mtd, FL_WRITING);
3761 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303762 printk(KERN_ERR "%s: Failed PI write for Die %d\n",
3763 __func__, die);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003764 goto out;
3765 }
3766
3767 this->command(mtd, FLEXONENAND_CMD_PI_UPDATE, die, 0);
3768 ret = this->wait(mtd, FL_WRITING);
3769out:
3770 this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_REG_COMMAND);
3771 this->wait(mtd, FL_RESETING);
3772 if (!ret)
3773 /* Recalculate device size on boundary change*/
3774 flexonenand_get_size(mtd);
3775
3776 return ret;
3777}
3778
3779/**
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003780 * onenand_chip_probe - [OneNAND Interface] The generic chip probe
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003781 * @param mtd MTD device structure
3782 *
3783 * OneNAND detection method:
Michael Opdenacker59c51592007-05-09 08:57:56 +02003784 * Compare the values from command with ones from register
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003785 */
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003786static int onenand_chip_probe(struct mtd_info *mtd)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003787{
3788 struct onenand_chip *this = mtd->priv;
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003789 int bram_maf_id, bram_dev_id, maf_id, dev_id;
Kyungmin Park47e777e2006-09-25 23:53:28 +00003790 int syscfg;
3791
3792 /* Save system configuration 1 */
3793 syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
3794 /* Clear Sync. Burst Read mode to read BootRAM */
Adrian Hunteree8f3762009-05-05 11:04:19 +03003795 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 +01003796
3797 /* Send the command for reading device ID from BootRAM */
3798 this->write_word(ONENAND_CMD_READID, this->base + ONENAND_BOOTRAM);
3799
3800 /* Read manufacturer and device IDs from BootRAM */
3801 bram_maf_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x0);
3802 bram_dev_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x2);
3803
Kyungmin Park47e777e2006-09-25 23:53:28 +00003804 /* Reset OneNAND to read default register values */
3805 this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM);
3806 /* Wait reset */
3807 this->wait(mtd, FL_RESETING);
3808
3809 /* Restore system configuration 1 */
3810 this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
3811
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003812 /* Check manufacturer ID */
3813 if (onenand_check_maf(bram_maf_id))
3814 return -ENXIO;
3815
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003816 /* Read manufacturer and device IDs from Register */
3817 maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);
3818 dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
3819
3820 /* Check OneNAND device */
3821 if (maf_id != bram_maf_id || dev_id != bram_dev_id)
3822 return -ENXIO;
3823
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003824 return 0;
3825}
3826
3827/**
3828 * onenand_probe - [OneNAND Interface] Probe the OneNAND device
3829 * @param mtd MTD device structure
3830 */
3831static int onenand_probe(struct mtd_info *mtd)
3832{
3833 struct onenand_chip *this = mtd->priv;
Brian Norris6b7368c2013-08-27 18:01:19 -07003834 int dev_id, ver_id;
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003835 int density;
3836 int ret;
3837
3838 ret = this->chip_probe(mtd);
3839 if (ret)
3840 return ret;
3841
Brian Norris6b7368c2013-08-27 18:01:19 -07003842 /* Device and version IDs from Register */
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003843 dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
3844 ver_id = this->read_word(this->base + ONENAND_REG_VERSION_ID);
3845 this->technology = this->read_word(this->base + ONENAND_REG_TECHNOLOGY);
3846
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003847 /* Flash device information */
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003848 onenand_print_device_info(dev_id, ver_id);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003849 this->device_id = dev_id;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003850 this->version_id = ver_id;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003851
Kyungmin Parkc37cb562010-04-28 17:46:48 +02003852 /* Check OneNAND features */
3853 onenand_check_features(mtd);
3854
Kyungmin Parke71f04f2007-12-11 11:23:45 +09003855 density = onenand_get_density(dev_id);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003856 if (FLEXONENAND(this)) {
3857 this->dies = ONENAND_IS_DDP(this) ? 2 : 1;
3858 /* Maximum possible erase regions */
3859 mtd->numeraseregions = this->dies << 1;
3860 mtd->eraseregions = kzalloc(sizeof(struct mtd_erase_region_info)
3861 * (this->dies << 1), GFP_KERNEL);
3862 if (!mtd->eraseregions)
3863 return -ENOMEM;
3864 }
3865
3866 /*
3867 * For Flex-OneNAND, chipsize represents maximum possible device size.
3868 * mtd->size represents the actual device size.
3869 */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003870 this->chipsize = (16 << density) << 20;
3871
3872 /* OneNAND page size & block size */
3873 /* The data buffer size is equal to page size */
Joern Engel28318772006-05-22 23:18:05 +02003874 mtd->writesize = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003875 /* We use the full BufferRAM */
Kyungmin Park8a8f6322010-12-02 09:24:16 +09003876 if (ONENAND_IS_4KB_PAGE(this))
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003877 mtd->writesize <<= 1;
3878
Joern Engel28318772006-05-22 23:18:05 +02003879 mtd->oobsize = mtd->writesize >> 5;
Kyungmin Park9bfbc9b2007-01-31 14:25:21 +09003880 /* Pages per a block are always 64 in OneNAND */
Joern Engel28318772006-05-22 23:18:05 +02003881 mtd->erasesize = mtd->writesize << 6;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003882 /*
3883 * Flex-OneNAND SLC area has 64 pages per block.
3884 * Flex-OneNAND MLC area has 128 pages per block.
3885 * Expose MLC erase size to find erase_shift and page_mask.
3886 */
3887 if (FLEXONENAND(this))
3888 mtd->erasesize <<= 1;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003889
3890 this->erase_shift = ffs(mtd->erasesize) - 1;
Joern Engel28318772006-05-22 23:18:05 +02003891 this->page_shift = ffs(mtd->writesize) - 1;
Kyungmin Park9bfbc9b2007-01-31 14:25:21 +09003892 this->page_mask = (1 << (this->erase_shift - this->page_shift)) - 1;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003893 /* Set density mask. it is used for DDP */
3894 if (ONENAND_IS_DDP(this))
3895 this->density_mask = this->chipsize >> (this->erase_shift + 1);
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003896 /* It's real page size */
3897 this->writesize = mtd->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003898
Mika Korhonen492e1502009-06-09 21:52:35 +03003899 /* REVISIT: Multichip handling */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003900
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003901 if (FLEXONENAND(this))
3902 flexonenand_get_size(mtd);
3903 else
3904 mtd->size = this->chipsize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003905
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003906 /*
3907 * We emulate the 4KiB page and 256KiB erase block size
3908 * But oobsize is still 64 bytes.
3909 * It is only valid if you turn on 2X program support,
3910 * Otherwise it will be ignored by compiler.
3911 */
3912 if (ONENAND_IS_2PLANE(this)) {
3913 mtd->writesize <<= 1;
3914 mtd->erasesize <<= 1;
3915 }
3916
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003917 return 0;
3918}
3919
Kyungmin Parka41371e2005-09-29 03:55:31 +01003920/**
3921 * onenand_suspend - [MTD Interface] Suspend the OneNAND flash
3922 * @param mtd MTD device structure
3923 */
3924static int onenand_suspend(struct mtd_info *mtd)
3925{
3926 return onenand_get_device(mtd, FL_PM_SUSPENDED);
3927}
3928
3929/**
3930 * onenand_resume - [MTD Interface] Resume the OneNAND flash
3931 * @param mtd MTD device structure
3932 */
3933static void onenand_resume(struct mtd_info *mtd)
3934{
3935 struct onenand_chip *this = mtd->priv;
3936
3937 if (this->state == FL_PM_SUSPENDED)
3938 onenand_release_device(mtd);
3939 else
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303940 printk(KERN_ERR "%s: resume() called for the chip which is not "
3941 "in suspended state\n", __func__);
Kyungmin Parka41371e2005-09-29 03:55:31 +01003942}
3943
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003944/**
3945 * onenand_scan - [OneNAND Interface] Scan for the OneNAND device
3946 * @param mtd MTD device structure
3947 * @param maxchips Number of chips to scan for
3948 *
3949 * This fills out all the not initialized function pointers
3950 * with the defaults.
3951 * The flash ID is read and the mtd/chip structures are
3952 * filled with the appropriate values.
3953 */
3954int onenand_scan(struct mtd_info *mtd, int maxchips)
3955{
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003956 int i, ret;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003957 struct onenand_chip *this = mtd->priv;
3958
3959 if (!this->read_word)
3960 this->read_word = onenand_readw;
3961 if (!this->write_word)
3962 this->write_word = onenand_writew;
3963
3964 if (!this->command)
3965 this->command = onenand_command;
3966 if (!this->wait)
Kyungmin Park2c221202006-11-16 11:23:48 +09003967 onenand_setup_wait(mtd);
Kyungmin Park31bb9992009-05-12 13:46:57 -07003968 if (!this->bbt_wait)
3969 this->bbt_wait = onenand_bbt_wait;
3970 if (!this->unlock_all)
3971 this->unlock_all = onenand_unlock_all;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003972
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003973 if (!this->chip_probe)
3974 this->chip_probe = onenand_chip_probe;
3975
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003976 if (!this->read_bufferram)
3977 this->read_bufferram = onenand_read_bufferram;
3978 if (!this->write_bufferram)
3979 this->write_bufferram = onenand_write_bufferram;
3980
Kyungmin Parkcdc00132005-09-03 07:15:48 +01003981 if (!this->block_markbad)
3982 this->block_markbad = onenand_default_block_markbad;
3983 if (!this->scan_bbt)
3984 this->scan_bbt = onenand_default_bbt;
3985
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003986 if (onenand_probe(mtd))
3987 return -ENXIO;
3988
Kyungmin Park52b0eea2005-09-03 07:07:19 +01003989 /* Set Sync. Burst Read after probing */
3990 if (this->mmcontrol) {
3991 printk(KERN_INFO "OneNAND Sync. Burst Read support\n");
3992 this->read_bufferram = onenand_sync_read_bufferram;
3993 }
3994
Kyungmin Park532a37c2005-12-16 11:17:29 +09003995 /* Allocate buffers, if necessary */
3996 if (!this->page_buf) {
Kyungmin Park470bc842007-03-09 10:08:11 +09003997 this->page_buf = kzalloc(mtd->writesize, GFP_KERNEL);
Kyungmin Park532a37c2005-12-16 11:17:29 +09003998 if (!this->page_buf) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303999 printk(KERN_ERR "%s: Can't allocate page_buf\n",
4000 __func__);
Kyungmin Park532a37c2005-12-16 11:17:29 +09004001 return -ENOMEM;
4002 }
Kyungmin Park4a8ce0b2010-04-28 17:46:46 +02004003#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
4004 this->verify_buf = kzalloc(mtd->writesize, GFP_KERNEL);
4005 if (!this->verify_buf) {
4006 kfree(this->page_buf);
4007 return -ENOMEM;
4008 }
4009#endif
Kyungmin Park532a37c2005-12-16 11:17:29 +09004010 this->options |= ONENAND_PAGEBUF_ALLOC;
4011 }
Kyungmin Park470bc842007-03-09 10:08:11 +09004012 if (!this->oob_buf) {
4013 this->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
4014 if (!this->oob_buf) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05304015 printk(KERN_ERR "%s: Can't allocate oob_buf\n",
4016 __func__);
Kyungmin Park470bc842007-03-09 10:08:11 +09004017 if (this->options & ONENAND_PAGEBUF_ALLOC) {
4018 this->options &= ~ONENAND_PAGEBUF_ALLOC;
4019 kfree(this->page_buf);
4020 }
4021 return -ENOMEM;
4022 }
4023 this->options |= ONENAND_OOBBUF_ALLOC;
4024 }
Kyungmin Park532a37c2005-12-16 11:17:29 +09004025
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004026 this->state = FL_READY;
4027 init_waitqueue_head(&this->wq);
4028 spin_lock_init(&this->chip_lock);
4029
Kyungmin Park60d84f92006-12-22 16:21:54 +09004030 /*
4031 * Allow subpage writes up to oobsize.
4032 */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004033 switch (mtd->oobsize) {
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07004034 case 128:
Roman Tereshonkov99b17c02011-04-11 12:52:01 +03004035 if (FLEXONENAND(this)) {
4036 this->ecclayout = &flexonenand_oob_128;
4037 mtd->subpage_sft = 0;
4038 } else {
4039 this->ecclayout = &onenand_oob_128;
4040 mtd->subpage_sft = 2;
4041 }
Kyungmin Parke1c10242011-06-22 14:16:49 +09004042 if (ONENAND_IS_NOP_1(this))
4043 mtd->subpage_sft = 0;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07004044 break;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004045 case 64:
Thomas Gleixner5bd34c02006-05-27 22:16:10 +02004046 this->ecclayout = &onenand_oob_64;
Kyungmin Park60d84f92006-12-22 16:21:54 +09004047 mtd->subpage_sft = 2;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004048 break;
4049
4050 case 32:
Thomas Gleixner5bd34c02006-05-27 22:16:10 +02004051 this->ecclayout = &onenand_oob_32;
Kyungmin Park60d84f92006-12-22 16:21:54 +09004052 mtd->subpage_sft = 1;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004053 break;
4054
4055 default:
Amul Kumar Saha297758f2009-10-02 16:59:11 +05304056 printk(KERN_WARNING "%s: No OOB scheme defined for oobsize %d\n",
4057 __func__, mtd->oobsize);
Kyungmin Park60d84f92006-12-22 16:21:54 +09004058 mtd->subpage_sft = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004059 /* To prevent kernel oops */
Thomas Gleixner5bd34c02006-05-27 22:16:10 +02004060 this->ecclayout = &onenand_oob_32;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004061 break;
4062 }
4063
Kyungmin Park60d84f92006-12-22 16:21:54 +09004064 this->subpagesize = mtd->writesize >> mtd->subpage_sft;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02004065
4066 /*
4067 * The number of bytes available for a client to place data into
4068 * the out of band area
4069 */
4070 this->ecclayout->oobavail = 0;
Kyungmin Parkad286342007-03-23 10:19:52 +09004071 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES &&
4072 this->ecclayout->oobfree[i].length; i++)
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02004073 this->ecclayout->oobavail +=
4074 this->ecclayout->oobfree[i].length;
Vitaly Wool1f922672007-03-06 16:56:34 +03004075 mtd->oobavail = this->ecclayout->oobavail;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02004076
Thomas Gleixner5bd34c02006-05-27 22:16:10 +02004077 mtd->ecclayout = this->ecclayout;
Mike Dunn6a918ba2012-03-11 14:21:11 -07004078 mtd->ecc_strength = 1;
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +00004079
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004080 /* Fill in remaining MTD driver data */
Rohit Hassan Sathyanarayanc7626802010-09-27 16:02:10 +05304081 mtd->type = ONENAND_IS_MLC(this) ? MTD_MLCNANDFLASH : MTD_NANDFLASH;
Joern Engel5fa43392006-05-22 23:18:29 +02004082 mtd->flags = MTD_CAP_NANDFLASH;
Artem Bityutskiy3c3c10b2012-01-30 14:58:32 +02004083 mtd->_erase = onenand_erase;
4084 mtd->_point = NULL;
4085 mtd->_unpoint = NULL;
4086 mtd->_read = onenand_read;
4087 mtd->_write = onenand_write;
4088 mtd->_read_oob = onenand_read_oob;
4089 mtd->_write_oob = onenand_write_oob;
4090 mtd->_panic_write = onenand_panic_write;
Kyungmin Park493c6462006-05-12 17:03:07 +03004091#ifdef CONFIG_MTD_ONENAND_OTP
Artem Bityutskiy3c3c10b2012-01-30 14:58:32 +02004092 mtd->_get_fact_prot_info = onenand_get_fact_prot_info;
4093 mtd->_read_fact_prot_reg = onenand_read_fact_prot_reg;
4094 mtd->_get_user_prot_info = onenand_get_user_prot_info;
4095 mtd->_read_user_prot_reg = onenand_read_user_prot_reg;
4096 mtd->_write_user_prot_reg = onenand_write_user_prot_reg;
4097 mtd->_lock_user_prot_reg = onenand_lock_user_prot_reg;
Kyungmin Park493c6462006-05-12 17:03:07 +03004098#endif
Artem Bityutskiy3c3c10b2012-01-30 14:58:32 +02004099 mtd->_sync = onenand_sync;
4100 mtd->_lock = onenand_lock;
4101 mtd->_unlock = onenand_unlock;
4102 mtd->_suspend = onenand_suspend;
4103 mtd->_resume = onenand_resume;
4104 mtd->_block_isbad = onenand_block_isbad;
4105 mtd->_block_markbad = onenand_block_markbad;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004106 mtd->owner = THIS_MODULE;
Anatolij Gustschin25dcd292010-12-16 23:42:17 +01004107 mtd->writebufsize = mtd->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004108
4109 /* Unlock whole block */
Roman Tereshonkovb3dcfd32011-02-17 13:44:41 +02004110 if (!(this->options & ONENAND_SKIP_INITIAL_UNLOCKING))
4111 this->unlock_all(mtd);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004112
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07004113 ret = this->scan_bbt(mtd);
4114 if ((!FLEXONENAND(this)) || ret)
4115 return ret;
4116
4117 /* Change Flex-OneNAND boundaries if required */
4118 for (i = 0; i < MAX_DIES; i++)
4119 flexonenand_set_boundary(mtd, i, flex_bdry[2 * i],
4120 flex_bdry[(2 * i) + 1]);
4121
4122 return 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004123}
4124
4125/**
4126 * onenand_release - [OneNAND Interface] Free resources held by the OneNAND device
4127 * @param mtd MTD device structure
4128 */
4129void onenand_release(struct mtd_info *mtd)
4130{
Kyungmin Park532a37c2005-12-16 11:17:29 +09004131 struct onenand_chip *this = mtd->priv;
4132
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004133 /* Deregister partitions */
Jamie Iles711a6322011-05-23 10:22:56 +01004134 mtd_device_unregister(mtd);
Kyungmin Park532a37c2005-12-16 11:17:29 +09004135
4136 /* Free bad block table memory, if allocated */
Adrian Hunterf00b0042007-01-22 17:01:01 +09004137 if (this->bbm) {
4138 struct bbm_info *bbm = this->bbm;
4139 kfree(bbm->bbt);
Kyungmin Park532a37c2005-12-16 11:17:29 +09004140 kfree(this->bbm);
Adrian Hunterf00b0042007-01-22 17:01:01 +09004141 }
Kyungmin Park470bc842007-03-09 10:08:11 +09004142 /* Buffers allocated by onenand_scan */
Kyungmin Park4a8ce0b2010-04-28 17:46:46 +02004143 if (this->options & ONENAND_PAGEBUF_ALLOC) {
Kyungmin Park532a37c2005-12-16 11:17:29 +09004144 kfree(this->page_buf);
Kyungmin Park4a8ce0b2010-04-28 17:46:46 +02004145#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
4146 kfree(this->verify_buf);
4147#endif
4148 }
Kyungmin Park470bc842007-03-09 10:08:11 +09004149 if (this->options & ONENAND_OOBBUF_ALLOC)
4150 kfree(this->oob_buf);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07004151 kfree(mtd->eraseregions);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004152}
4153
4154EXPORT_SYMBOL_GPL(onenand_scan);
4155EXPORT_SYMBOL_GPL(onenand_release);
4156
4157MODULE_LICENSE("GPL");
4158MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");
4159MODULE_DESCRIPTION("Generic OneNAND flash driver code");