blob: 635ee0027691eb771bc31eac771209b48987d8e2 [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>
Andrew Morton015953d2005-11-08 21:34:28 -080027#include <linux/sched.h>
Richard Purdie6c77fd642008-02-06 10:18:22 +000028#include <linux/delay.h>
Kyungmin Park2c221202006-11-16 11:23:48 +090029#include <linux/interrupt.h>
Andrew Morton015953d2005-11-08 21:34:28 -080030#include <linux/jiffies.h>
Kyungmin Parkcd5f6342005-07-11 11:41:53 +010031#include <linux/mtd/mtd.h>
32#include <linux/mtd/onenand.h>
33#include <linux/mtd/partitions.h>
34
35#include <asm/io.h>
36
Mika Korhonen72073022009-10-23 07:50:43 +020037/*
38 * Multiblock erase if number of blocks to erase is 2 or more.
39 * Maximum number of blocks for simultaneous erase is 64.
40 */
41#define MB_ERASE_MIN_BLK_COUNT 2
42#define MB_ERASE_MAX_BLK_COUNT 64
43
Rohit Hagargundgi5988af22009-05-12 13:46:57 -070044/* Default Flex-OneNAND boundary and lock respectively */
45static int flex_bdry[MAX_DIES * 2] = { -1, 0, -1, 0 };
46
Amul Sahac90173f2009-06-16 11:24:01 +053047module_param_array(flex_bdry, int, NULL, 0400);
48MODULE_PARM_DESC(flex_bdry, "SLC Boundary information for Flex-OneNAND"
49 "Syntax:flex_bdry=DIE_BDRY,LOCK,..."
50 "DIE_BDRY: SLC boundary of the die"
51 "LOCK: Locking information for SLC boundary"
52 " : 0->Set boundary in unlocked status"
53 " : 1->Set boundary in locked status");
54
Amul Kumar Saha3cf60252009-10-21 17:00:05 +053055/* Default OneNAND/Flex-OneNAND OTP options*/
56static int otp;
57
58module_param(otp, int, 0400);
59MODULE_PARM_DESC(otp, "Corresponding behaviour of OneNAND in OTP"
60 "Syntax : otp=LOCK_TYPE"
61 "LOCK_TYPE : Keys issued, for specific OTP Lock type"
62 " : 0 -> Default (No Blocks Locked)"
63 " : 1 -> OTP Block lock"
64 " : 2 -> 1st Block lock"
65 " : 3 -> BOTH OTP Block and 1st Block lock");
66
Roman Tereshonkov99b17c02011-04-11 12:52:01 +030067/*
68 * flexonenand_oob_128 - oob info for Flex-Onenand with 4KB page
69 * For now, we expose only 64 out of 80 ecc bytes
Rohit Hagargundgi5988af22009-05-12 13:46:57 -070070 */
Roman Tereshonkov99b17c02011-04-11 12:52:01 +030071static struct nand_ecclayout flexonenand_oob_128 = {
Rohit Hagargundgi5988af22009-05-12 13:46:57 -070072 .eccbytes = 64,
73 .eccpos = {
74 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
75 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
76 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
77 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
78 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
79 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
80 102, 103, 104, 105
81 },
82 .oobfree = {
83 {2, 4}, {18, 4}, {34, 4}, {50, 4},
84 {66, 4}, {82, 4}, {98, 4}, {114, 4}
85 }
86};
87
Roman Tereshonkov99b17c02011-04-11 12:52:01 +030088/*
89 * onenand_oob_128 - oob info for OneNAND with 4KB page
90 *
91 * Based on specification:
92 * 4Gb M-die OneNAND Flash (KFM4G16Q4M, KFN8G16Q4M). Rev. 1.3, Apr. 2010
93 *
94 * For eccpos we expose only 64 bytes out of 72 (see struct nand_ecclayout)
95 *
96 * oobfree uses the spare area fields marked as
97 * "Managed by internal ECC logic for Logical Sector Number area"
98 */
99static struct nand_ecclayout onenand_oob_128 = {
100 .eccbytes = 64,
101 .eccpos = {
102 7, 8, 9, 10, 11, 12, 13, 14, 15,
103 23, 24, 25, 26, 27, 28, 29, 30, 31,
104 39, 40, 41, 42, 43, 44, 45, 46, 47,
105 55, 56, 57, 58, 59, 60, 61, 62, 63,
106 71, 72, 73, 74, 75, 76, 77, 78, 79,
107 87, 88, 89, 90, 91, 92, 93, 94, 95,
108 103, 104, 105, 106, 107, 108, 109, 110, 111,
109 119
110 },
111 .oobfree = {
112 {2, 3}, {18, 3}, {34, 3}, {50, 3},
113 {66, 3}, {82, 3}, {98, 3}, {114, 3}
114 }
115};
116
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100117/**
118 * onenand_oob_64 - oob info for large (2KB) page
119 */
Thomas Gleixner5bd34c02006-05-27 22:16:10 +0200120static struct nand_ecclayout onenand_oob_64 = {
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100121 .eccbytes = 20,
122 .eccpos = {
123 8, 9, 10, 11, 12,
124 24, 25, 26, 27, 28,
125 40, 41, 42, 43, 44,
126 56, 57, 58, 59, 60,
127 },
128 .oobfree = {
129 {2, 3}, {14, 2}, {18, 3}, {30, 2},
Jarkko Lavinend9777f12006-05-12 17:02:35 +0300130 {34, 3}, {46, 2}, {50, 3}, {62, 2}
131 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100132};
133
134/**
135 * onenand_oob_32 - oob info for middle (1KB) page
136 */
Thomas Gleixner5bd34c02006-05-27 22:16:10 +0200137static struct nand_ecclayout onenand_oob_32 = {
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100138 .eccbytes = 10,
139 .eccpos = {
140 8, 9, 10, 11, 12,
141 24, 25, 26, 27, 28,
142 },
143 .oobfree = { {2, 3}, {14, 2}, {18, 3}, {30, 2} }
144};
145
146static const unsigned char ffchars[] = {
147 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
148 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 16 */
149 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
150 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 32 */
151 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
152 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 48 */
153 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
154 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 64 */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700155 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
156 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 80 */
157 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
158 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 96 */
159 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
160 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 112 */
161 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
162 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 128 */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100163};
164
165/**
166 * onenand_readw - [OneNAND Interface] Read OneNAND register
167 * @param addr address to read
168 *
169 * Read OneNAND register
170 */
171static unsigned short onenand_readw(void __iomem *addr)
172{
173 return readw(addr);
174}
175
176/**
177 * onenand_writew - [OneNAND Interface] Write OneNAND register with value
178 * @param value value to write
179 * @param addr address to write
180 *
181 * Write OneNAND register with value
182 */
183static void onenand_writew(unsigned short value, void __iomem *addr)
184{
185 writew(value, addr);
186}
187
188/**
189 * onenand_block_address - [DEFAULT] Get block address
Kyungmin Park83a36832005-09-29 04:53:16 +0100190 * @param this onenand chip data structure
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100191 * @param block the block
192 * @return translated block address if DDP, otherwise same
193 *
194 * Setup Start Address 1 Register (F100h)
195 */
Kyungmin Park83a36832005-09-29 04:53:16 +0100196static int onenand_block_address(struct onenand_chip *this, int block)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100197{
Kyungmin Park738d61f2007-01-15 17:09:14 +0900198 /* Device Flash Core select, NAND Flash Block Address */
199 if (block & this->density_mask)
200 return ONENAND_DDP_CHIP1 | (block ^ this->density_mask);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100201
202 return block;
203}
204
205/**
206 * onenand_bufferram_address - [DEFAULT] Get bufferram address
Kyungmin Park83a36832005-09-29 04:53:16 +0100207 * @param this onenand chip data structure
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100208 * @param block the block
209 * @return set DBS value if DDP, otherwise 0
210 *
211 * Setup Start Address 2 Register (F101h) for DDP
212 */
Kyungmin Park83a36832005-09-29 04:53:16 +0100213static int onenand_bufferram_address(struct onenand_chip *this, int block)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100214{
Kyungmin Park738d61f2007-01-15 17:09:14 +0900215 /* Device BufferRAM Select */
216 if (block & this->density_mask)
217 return ONENAND_DDP_CHIP1;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100218
Kyungmin Park738d61f2007-01-15 17:09:14 +0900219 return ONENAND_DDP_CHIP0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100220}
221
222/**
223 * onenand_page_address - [DEFAULT] Get page address
224 * @param page the page address
225 * @param sector the sector address
226 * @return combined page and sector address
227 *
228 * Setup Start Address 8 Register (F107h)
229 */
230static int onenand_page_address(int page, int sector)
231{
232 /* Flash Page Address, Flash Sector Address */
233 int fpa, fsa;
234
235 fpa = page & ONENAND_FPA_MASK;
236 fsa = sector & ONENAND_FSA_MASK;
237
238 return ((fpa << ONENAND_FPA_SHIFT) | fsa);
239}
240
241/**
242 * onenand_buffer_address - [DEFAULT] Get buffer address
243 * @param dataram1 DataRAM index
244 * @param sectors the sector address
245 * @param count the number of sectors
246 * @return the start buffer value
247 *
248 * Setup Start Buffer Register (F200h)
249 */
250static int onenand_buffer_address(int dataram1, int sectors, int count)
251{
252 int bsa, bsc;
253
254 /* BufferRAM Sector Address */
255 bsa = sectors & ONENAND_BSA_MASK;
256
257 if (dataram1)
258 bsa |= ONENAND_BSA_DATARAM1; /* DataRAM1 */
259 else
260 bsa |= ONENAND_BSA_DATARAM0; /* DataRAM0 */
261
262 /* BufferRAM Sector Count */
263 bsc = count & ONENAND_BSC_MASK;
264
265 return ((bsa << ONENAND_BSA_SHIFT) | bsc);
266}
267
268/**
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700269 * flexonenand_block- For given address return block number
270 * @param this - OneNAND device structure
271 * @param addr - Address for which block number is needed
272 */
273static unsigned flexonenand_block(struct onenand_chip *this, loff_t addr)
274{
275 unsigned boundary, blk, die = 0;
276
277 if (ONENAND_IS_DDP(this) && addr >= this->diesize[0]) {
278 die = 1;
279 addr -= this->diesize[0];
280 }
281
282 boundary = this->boundary[die];
283
284 blk = addr >> (this->erase_shift - 1);
285 if (blk > boundary)
286 blk = (blk + boundary + 1) >> 1;
287
288 blk += die ? this->density_mask : 0;
289 return blk;
290}
291
292inline unsigned onenand_block(struct onenand_chip *this, loff_t addr)
293{
294 if (!FLEXONENAND(this))
295 return addr >> this->erase_shift;
296 return flexonenand_block(this, addr);
297}
298
299/**
300 * flexonenand_addr - Return address of the block
301 * @this: OneNAND device structure
302 * @block: Block number on Flex-OneNAND
303 *
304 * Return address of the block
305 */
306static loff_t flexonenand_addr(struct onenand_chip *this, int block)
307{
308 loff_t ofs = 0;
309 int die = 0, boundary;
310
311 if (ONENAND_IS_DDP(this) && block >= this->density_mask) {
312 block -= this->density_mask;
313 die = 1;
314 ofs = this->diesize[0];
315 }
316
317 boundary = this->boundary[die];
318 ofs += (loff_t)block << (this->erase_shift - 1);
319 if (block > (boundary + 1))
320 ofs += (loff_t)(block - boundary - 1) << (this->erase_shift - 1);
321 return ofs;
322}
323
324loff_t onenand_addr(struct onenand_chip *this, int block)
325{
326 if (!FLEXONENAND(this))
327 return (loff_t)block << this->erase_shift;
328 return flexonenand_addr(this, block);
329}
330EXPORT_SYMBOL(onenand_addr);
331
332/**
Kyungmin Parke71f04f2007-12-11 11:23:45 +0900333 * onenand_get_density - [DEFAULT] Get OneNAND density
334 * @param dev_id OneNAND device ID
335 *
336 * Get OneNAND density from device ID
337 */
338static inline int onenand_get_density(int dev_id)
339{
340 int density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
341 return (density & ONENAND_DEVICE_DENSITY_MASK);
342}
343
344/**
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700345 * flexonenand_region - [Flex-OneNAND] Return erase region of addr
346 * @param mtd MTD device structure
347 * @param addr address whose erase region needs to be identified
348 */
349int flexonenand_region(struct mtd_info *mtd, loff_t addr)
350{
351 int i;
352
353 for (i = 0; i < mtd->numeraseregions; i++)
354 if (addr < mtd->eraseregions[i].offset)
355 break;
356 return i - 1;
357}
358EXPORT_SYMBOL(flexonenand_region);
359
360/**
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100361 * onenand_command - [DEFAULT] Send command to OneNAND device
362 * @param mtd MTD device structure
363 * @param cmd the command to be sent
364 * @param addr offset to read from or write to
365 * @param len number of bytes to read or write
366 *
367 * Send command to OneNAND device. This function is used for middle/large page
368 * devices (1KB/2KB Bytes per page)
369 */
370static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t len)
371{
372 struct onenand_chip *this = mtd->priv;
Kyungmin Parkb21b72c2007-12-11 11:13:18 +0900373 int value, block, page;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100374
375 /* Address translation */
376 switch (cmd) {
377 case ONENAND_CMD_UNLOCK:
378 case ONENAND_CMD_LOCK:
379 case ONENAND_CMD_LOCK_TIGHT:
Kyungmin Park28b79ff2006-09-26 09:45:28 +0000380 case ONENAND_CMD_UNLOCK_ALL:
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100381 block = -1;
382 page = -1;
383 break;
384
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700385 case FLEXONENAND_CMD_PI_ACCESS:
386 /* addr contains die index */
387 block = addr * this->density_mask;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100388 page = -1;
389 break;
390
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700391 case ONENAND_CMD_ERASE:
Mika Korhonen72073022009-10-23 07:50:43 +0200392 case ONENAND_CMD_MULTIBLOCK_ERASE:
393 case ONENAND_CMD_ERASE_VERIFY:
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700394 case ONENAND_CMD_BUFFERRAM:
395 case ONENAND_CMD_OTP_ACCESS:
396 block = onenand_block(this, addr);
397 page = -1;
398 break;
399
400 case FLEXONENAND_CMD_READ_PI:
401 cmd = ONENAND_CMD_READ;
402 block = addr * this->density_mask;
403 page = 0;
404 break;
405
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100406 default:
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700407 block = onenand_block(this, addr);
Rohit Hassan Sathyanarayan42b0aab2010-07-23 12:29:25 +0530408 if (FLEXONENAND(this))
409 page = (int) (addr - onenand_addr(this, block))>>\
410 this->page_shift;
411 else
412 page = (int) (addr >> this->page_shift);
Kyungmin Parkee9745f2007-06-30 13:57:49 +0900413 if (ONENAND_IS_2PLANE(this)) {
414 /* Make the even block number */
415 block &= ~1;
416 /* Is it the odd plane? */
417 if (addr & this->writesize)
418 block++;
419 page >>= 1;
420 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100421 page &= this->page_mask;
422 break;
423 }
424
425 /* NOTE: The setting order of the registers is very important! */
426 if (cmd == ONENAND_CMD_BUFFERRAM) {
427 /* Select DataRAM for DDP */
Kyungmin Park83a36832005-09-29 04:53:16 +0100428 value = onenand_bufferram_address(this, block);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100429 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
430
Kyungmin Park8a8f6322010-12-02 09:24:16 +0900431 if (ONENAND_IS_2PLANE(this) || ONENAND_IS_4KB_PAGE(this))
Kyungmin Parkee9745f2007-06-30 13:57:49 +0900432 /* It is always BufferRAM0 */
433 ONENAND_SET_BUFFERRAM0(this);
434 else
435 /* Switch to the next data buffer */
436 ONENAND_SET_NEXT_BUFFERRAM(this);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100437
438 return 0;
439 }
440
441 if (block != -1) {
442 /* Write 'DFS, FBA' of Flash */
Kyungmin Park83a36832005-09-29 04:53:16 +0100443 value = onenand_block_address(this, block);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100444 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
Kyungmin Park3cecf692006-05-12 17:02:51 +0300445
Kyungmin Parkb21b72c2007-12-11 11:13:18 +0900446 /* Select DataRAM for DDP */
447 value = onenand_bufferram_address(this, block);
448 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100449 }
450
451 if (page != -1) {
Kyungmin Park60d84f92006-12-22 16:21:54 +0900452 /* Now we use page size operation */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700453 int sectors = 0, count = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100454 int dataram;
455
456 switch (cmd) {
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700457 case FLEXONENAND_CMD_RECOVER_LSB:
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100458 case ONENAND_CMD_READ:
459 case ONENAND_CMD_READOOB:
Kyungmin Park8a8f6322010-12-02 09:24:16 +0900460 if (ONENAND_IS_4KB_PAGE(this))
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700461 /* It is always BufferRAM0 */
462 dataram = ONENAND_SET_BUFFERRAM0(this);
463 else
464 dataram = ONENAND_SET_NEXT_BUFFERRAM(this);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100465 break;
466
467 default:
Kyungmin Parkee9745f2007-06-30 13:57:49 +0900468 if (ONENAND_IS_2PLANE(this) && cmd == ONENAND_CMD_PROG)
469 cmd = ONENAND_CMD_2X_PROG;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100470 dataram = ONENAND_CURRENT_BUFFERRAM(this);
471 break;
472 }
473
474 /* Write 'FPA, FSA' of Flash */
475 value = onenand_page_address(page, sectors);
476 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS8);
477
478 /* Write 'BSA, BSC' of DataRAM */
479 value = onenand_buffer_address(dataram, sectors, count);
480 this->write_word(value, this->base + ONENAND_REG_START_BUFFER);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100481 }
482
483 /* Interrupt clear */
484 this->write_word(ONENAND_INT_CLEAR, this->base + ONENAND_REG_INTERRUPT);
485
486 /* Write command */
487 this->write_word(cmd, this->base + ONENAND_REG_COMMAND);
488
489 return 0;
490}
491
492/**
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700493 * onenand_read_ecc - return ecc status
494 * @param this onenand chip structure
495 */
496static inline int onenand_read_ecc(struct onenand_chip *this)
497{
498 int ecc, i, result = 0;
499
Kyungmin Park6a88c472010-04-28 17:46:45 +0200500 if (!FLEXONENAND(this) && !ONENAND_IS_4KB_PAGE(this))
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700501 return this->read_word(this->base + ONENAND_REG_ECC_STATUS);
502
503 for (i = 0; i < 4; i++) {
Kyungmin Park6a88c472010-04-28 17:46:45 +0200504 ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS + i*2);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700505 if (likely(!ecc))
506 continue;
507 if (ecc & FLEXONENAND_UNCORRECTABLE_ERROR)
508 return ONENAND_ECC_2BIT_ALL;
509 else
510 result = ONENAND_ECC_1BIT_ALL;
511 }
512
513 return result;
514}
515
516/**
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100517 * onenand_wait - [DEFAULT] wait until the command is done
518 * @param mtd MTD device structure
519 * @param state state to select the max. timeout value
520 *
521 * Wait for command done. This applies to all OneNAND command
522 * Read can take up to 30us, erase up to 2ms and program up to 350us
523 * according to general OneNAND specs
524 */
525static int onenand_wait(struct mtd_info *mtd, int state)
526{
527 struct onenand_chip * this = mtd->priv;
528 unsigned long timeout;
529 unsigned int flags = ONENAND_INT_MASTER;
530 unsigned int interrupt = 0;
Kyungmin Park2fd32d42006-12-29 11:51:40 +0900531 unsigned int ctrl;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100532
533 /* The 20 msec is enough */
534 timeout = jiffies + msecs_to_jiffies(20);
535 while (time_before(jiffies, timeout)) {
536 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
537
538 if (interrupt & flags)
539 break;
540
Mika Korhonen72073022009-10-23 07:50:43 +0200541 if (state != FL_READING && state != FL_PREPARING_ERASE)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100542 cond_resched();
543 }
544 /* To get correct interrupt status in timeout case */
545 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
546
547 ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
548
Kyungmin Park83973b82008-05-29 14:52:40 +0900549 /*
550 * In the Spec. it checks the controller status first
551 * However if you get the correct information in case of
552 * power off recovery (POR) test, it should read ECC status first
553 */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100554 if (interrupt & ONENAND_INT_READ) {
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700555 int ecc = onenand_read_ecc(this);
Kyungmin Parkf4f91ac2006-11-16 12:03:56 +0900556 if (ecc) {
Kyungmin Parkb3c9f8b2007-01-05 19:16:04 +0900557 if (ecc & ONENAND_ECC_2BIT_ALL) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +0530558 printk(KERN_ERR "%s: ECC error = 0x%04x\n",
559 __func__, ecc);
Kyungmin Parkf4f91ac2006-11-16 12:03:56 +0900560 mtd->ecc_stats.failed++;
Adrian Hunter30a7eb22007-10-12 10:19:38 +0300561 return -EBADMSG;
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +0300562 } else if (ecc & ONENAND_ECC_1BIT_ALL) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +0530563 printk(KERN_DEBUG "%s: correctable ECC error = 0x%04x\n",
564 __func__, ecc);
Kyungmin Parkf4f91ac2006-11-16 12:03:56 +0900565 mtd->ecc_stats.corrected++;
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +0300566 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100567 }
Adrian Hunter9d032802007-01-10 07:51:26 +0200568 } else if (state == FL_READING) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +0530569 printk(KERN_ERR "%s: read timeout! ctrl=0x%04x intr=0x%04x\n",
570 __func__, ctrl, interrupt);
Adrian Hunter9d032802007-01-10 07:51:26 +0200571 return -EIO;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100572 }
573
Mika Korhonen72073022009-10-23 07:50:43 +0200574 if (state == FL_PREPARING_ERASE && !(interrupt & ONENAND_INT_ERASE)) {
575 printk(KERN_ERR "%s: mb erase timeout! ctrl=0x%04x intr=0x%04x\n",
576 __func__, ctrl, interrupt);
577 return -EIO;
578 }
579
580 if (!(interrupt & ONENAND_INT_MASTER)) {
581 printk(KERN_ERR "%s: timeout! ctrl=0x%04x intr=0x%04x\n",
582 __func__, ctrl, interrupt);
583 return -EIO;
584 }
585
Kyungmin Park83973b82008-05-29 14:52:40 +0900586 /* If there's controller error, it's a real error */
587 if (ctrl & ONENAND_CTRL_ERROR) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +0530588 printk(KERN_ERR "%s: controller error = 0x%04x\n",
589 __func__, ctrl);
Kyungmin Park83973b82008-05-29 14:52:40 +0900590 if (ctrl & ONENAND_CTRL_LOCK)
Amul Kumar Saha297758f2009-10-02 16:59:11 +0530591 printk(KERN_ERR "%s: it's locked error.\n", __func__);
Kyungmin Park83973b82008-05-29 14:52:40 +0900592 return -EIO;
593 }
594
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100595 return 0;
596}
597
Kyungmin Park2c221202006-11-16 11:23:48 +0900598/*
599 * onenand_interrupt - [DEFAULT] onenand interrupt handler
600 * @param irq onenand interrupt number
601 * @param dev_id interrupt data
602 *
603 * complete the work
604 */
605static irqreturn_t onenand_interrupt(int irq, void *data)
606{
Jeff Garzik06efcad2007-10-19 03:10:11 -0400607 struct onenand_chip *this = data;
Kyungmin Park2c221202006-11-16 11:23:48 +0900608
609 /* To handle shared interrupt */
610 if (!this->complete.done)
611 complete(&this->complete);
612
613 return IRQ_HANDLED;
614}
615
616/*
617 * onenand_interrupt_wait - [DEFAULT] wait until the command is done
618 * @param mtd MTD device structure
619 * @param state state to select the max. timeout value
620 *
621 * Wait for command done.
622 */
623static int onenand_interrupt_wait(struct mtd_info *mtd, int state)
624{
625 struct onenand_chip *this = mtd->priv;
626
Kyungmin Park2c221202006-11-16 11:23:48 +0900627 wait_for_completion(&this->complete);
628
629 return onenand_wait(mtd, state);
630}
631
632/*
633 * onenand_try_interrupt_wait - [DEFAULT] try interrupt wait
634 * @param mtd MTD device structure
635 * @param state state to select the max. timeout value
636 *
637 * Try interrupt based wait (It is used one-time)
638 */
639static int onenand_try_interrupt_wait(struct mtd_info *mtd, int state)
640{
641 struct onenand_chip *this = mtd->priv;
642 unsigned long remain, timeout;
643
644 /* We use interrupt wait first */
645 this->wait = onenand_interrupt_wait;
646
Kyungmin Park2c221202006-11-16 11:23:48 +0900647 timeout = msecs_to_jiffies(100);
648 remain = wait_for_completion_timeout(&this->complete, timeout);
649 if (!remain) {
650 printk(KERN_INFO "OneNAND: There's no interrupt. "
651 "We use the normal wait\n");
652
653 /* Release the irq */
654 free_irq(this->irq, this);
David Woodhousec9ac5972006-11-30 08:17:38 +0000655
Kyungmin Park2c221202006-11-16 11:23:48 +0900656 this->wait = onenand_wait;
657 }
658
659 return onenand_wait(mtd, state);
660}
661
662/*
663 * onenand_setup_wait - [OneNAND Interface] setup onenand wait method
664 * @param mtd MTD device structure
665 *
666 * There's two method to wait onenand work
667 * 1. polling - read interrupt status register
668 * 2. interrupt - use the kernel interrupt method
669 */
670static void onenand_setup_wait(struct mtd_info *mtd)
671{
672 struct onenand_chip *this = mtd->priv;
673 int syscfg;
674
675 init_completion(&this->complete);
676
677 if (this->irq <= 0) {
678 this->wait = onenand_wait;
679 return;
680 }
681
682 if (request_irq(this->irq, &onenand_interrupt,
683 IRQF_SHARED, "onenand", this)) {
684 /* If we can't get irq, use the normal wait */
685 this->wait = onenand_wait;
686 return;
687 }
688
689 /* Enable interrupt */
690 syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
691 syscfg |= ONENAND_SYS_CFG1_IOBE;
692 this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
693
694 this->wait = onenand_try_interrupt_wait;
695}
696
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100697/**
698 * onenand_bufferram_offset - [DEFAULT] BufferRAM offset
699 * @param mtd MTD data structure
700 * @param area BufferRAM area
701 * @return offset given area
702 *
703 * Return BufferRAM offset given area
704 */
705static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area)
706{
707 struct onenand_chip *this = mtd->priv;
708
709 if (ONENAND_CURRENT_BUFFERRAM(this)) {
Kyungmin Parkee9745f2007-06-30 13:57:49 +0900710 /* Note: the 'this->writesize' is a real page size */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100711 if (area == ONENAND_DATARAM)
Kyungmin Parkee9745f2007-06-30 13:57:49 +0900712 return this->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100713 if (area == ONENAND_SPARERAM)
714 return mtd->oobsize;
715 }
716
717 return 0;
718}
719
720/**
721 * onenand_read_bufferram - [OneNAND Interface] Read the bufferram area
722 * @param mtd MTD data structure
723 * @param area BufferRAM area
724 * @param buffer the databuffer to put/get data
725 * @param offset offset to read from or write to
726 * @param count number of bytes to read/write
727 *
728 * Read the BufferRAM area
729 */
730static int onenand_read_bufferram(struct mtd_info *mtd, int area,
731 unsigned char *buffer, int offset, size_t count)
732{
733 struct onenand_chip *this = mtd->priv;
734 void __iomem *bufferram;
735
736 bufferram = this->base + area;
737
738 bufferram += onenand_bufferram_offset(mtd, area);
739
Kyungmin Park9c01f87d2006-05-12 17:02:31 +0300740 if (ONENAND_CHECK_BYTE_ACCESS(count)) {
741 unsigned short word;
742
743 /* Align with word(16-bit) size */
744 count--;
745
746 /* Read word and save byte */
747 word = this->read_word(bufferram + offset + count);
748 buffer[count] = (word & 0xff);
749 }
750
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100751 memcpy(buffer, bufferram + offset, count);
752
753 return 0;
754}
755
756/**
Kyungmin Park52b0eea2005-09-03 07:07:19 +0100757 * onenand_sync_read_bufferram - [OneNAND Interface] Read the bufferram area with Sync. Burst mode
758 * @param mtd MTD data structure
759 * @param area BufferRAM area
760 * @param buffer the databuffer to put/get data
761 * @param offset offset to read from or write to
762 * @param count number of bytes to read/write
763 *
764 * Read the BufferRAM area with Sync. Burst Mode
765 */
766static int onenand_sync_read_bufferram(struct mtd_info *mtd, int area,
767 unsigned char *buffer, int offset, size_t count)
768{
769 struct onenand_chip *this = mtd->priv;
770 void __iomem *bufferram;
771
772 bufferram = this->base + area;
773
774 bufferram += onenand_bufferram_offset(mtd, area);
775
776 this->mmcontrol(mtd, ONENAND_SYS_CFG1_SYNC_READ);
777
Kyungmin Park9c01f87d2006-05-12 17:02:31 +0300778 if (ONENAND_CHECK_BYTE_ACCESS(count)) {
779 unsigned short word;
780
781 /* Align with word(16-bit) size */
782 count--;
783
784 /* Read word and save byte */
785 word = this->read_word(bufferram + offset + count);
786 buffer[count] = (word & 0xff);
787 }
788
Kyungmin Park52b0eea2005-09-03 07:07:19 +0100789 memcpy(buffer, bufferram + offset, count);
790
791 this->mmcontrol(mtd, 0);
792
793 return 0;
794}
795
796/**
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100797 * onenand_write_bufferram - [OneNAND Interface] Write the bufferram area
798 * @param mtd MTD data structure
799 * @param area BufferRAM area
800 * @param buffer the databuffer to put/get data
801 * @param offset offset to read from or write to
802 * @param count number of bytes to read/write
803 *
804 * Write the BufferRAM area
805 */
806static int onenand_write_bufferram(struct mtd_info *mtd, int area,
807 const unsigned char *buffer, int offset, size_t count)
808{
809 struct onenand_chip *this = mtd->priv;
810 void __iomem *bufferram;
811
812 bufferram = this->base + area;
813
814 bufferram += onenand_bufferram_offset(mtd, area);
815
Kyungmin Park9c01f87d2006-05-12 17:02:31 +0300816 if (ONENAND_CHECK_BYTE_ACCESS(count)) {
817 unsigned short word;
818 int byte_offset;
819
820 /* Align with word(16-bit) size */
821 count--;
822
823 /* Calculate byte access offset */
824 byte_offset = offset + count;
825
826 /* Read word and save byte */
827 word = this->read_word(bufferram + byte_offset);
828 word = (word & ~0xff) | buffer[count];
829 this->write_word(word, bufferram + byte_offset);
830 }
831
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100832 memcpy(bufferram + offset, buffer, count);
833
834 return 0;
835}
836
837/**
Kyungmin Parkee9745f2007-06-30 13:57:49 +0900838 * onenand_get_2x_blockpage - [GENERIC] Get blockpage at 2x program mode
839 * @param mtd MTD data structure
840 * @param addr address to check
841 * @return blockpage address
842 *
843 * Get blockpage address at 2x program mode
844 */
845static int onenand_get_2x_blockpage(struct mtd_info *mtd, loff_t addr)
846{
847 struct onenand_chip *this = mtd->priv;
848 int blockpage, block, page;
849
850 /* Calculate the even block number */
851 block = (int) (addr >> this->erase_shift) & ~1;
852 /* Is it the odd plane? */
853 if (addr & this->writesize)
854 block++;
855 page = (int) (addr >> (this->page_shift + 1)) & this->page_mask;
856 blockpage = (block << 7) | page;
857
858 return blockpage;
859}
860
861/**
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100862 * onenand_check_bufferram - [GENERIC] Check BufferRAM information
863 * @param mtd MTD data structure
864 * @param addr address to check
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +0000865 * @return 1 if there are valid data, otherwise 0
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100866 *
867 * Check bufferram if there is data we required
868 */
869static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr)
870{
871 struct onenand_chip *this = mtd->priv;
Adrian Huntercde36b32007-02-08 10:28:08 +0200872 int blockpage, found = 0;
Kyungmin Parkabf3c0f2007-02-02 09:29:36 +0900873 unsigned int i;
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +0000874
Kyungmin Parkee9745f2007-06-30 13:57:49 +0900875 if (ONENAND_IS_2PLANE(this))
876 blockpage = onenand_get_2x_blockpage(mtd, addr);
877 else
878 blockpage = (int) (addr >> this->page_shift);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100879
880 /* Is there valid data? */
Kyungmin Parkabf3c0f2007-02-02 09:29:36 +0900881 i = ONENAND_CURRENT_BUFFERRAM(this);
882 if (this->bufferram[i].blockpage == blockpage)
Adrian Huntercde36b32007-02-08 10:28:08 +0200883 found = 1;
884 else {
885 /* Check another BufferRAM */
886 i = ONENAND_NEXT_BUFFERRAM(this);
887 if (this->bufferram[i].blockpage == blockpage) {
888 ONENAND_SET_NEXT_BUFFERRAM(this);
889 found = 1;
890 }
Kyungmin Parkabf3c0f2007-02-02 09:29:36 +0900891 }
892
Adrian Huntercde36b32007-02-08 10:28:08 +0200893 if (found && ONENAND_IS_DDP(this)) {
894 /* Select DataRAM for DDP */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -0700895 int block = onenand_block(this, addr);
Adrian Huntercde36b32007-02-08 10:28:08 +0200896 int value = onenand_bufferram_address(this, block);
897 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
898 }
899
900 return found;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100901}
902
903/**
904 * onenand_update_bufferram - [GENERIC] Update BufferRAM information
905 * @param mtd MTD data structure
906 * @param addr address to update
907 * @param valid valid flag
908 *
909 * Update BufferRAM information
910 */
Kyungmin Parkabf3c0f2007-02-02 09:29:36 +0900911static void onenand_update_bufferram(struct mtd_info *mtd, loff_t addr,
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100912 int valid)
913{
914 struct onenand_chip *this = mtd->priv;
Kyungmin Parkabf3c0f2007-02-02 09:29:36 +0900915 int blockpage;
916 unsigned int i;
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +0000917
Kyungmin Parkee9745f2007-06-30 13:57:49 +0900918 if (ONENAND_IS_2PLANE(this))
919 blockpage = onenand_get_2x_blockpage(mtd, addr);
920 else
921 blockpage = (int) (addr >> this->page_shift);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100922
Kyungmin Parkabf3c0f2007-02-02 09:29:36 +0900923 /* Invalidate another BufferRAM */
924 i = ONENAND_NEXT_BUFFERRAM(this);
Kyungmin Park5b4246f2007-02-02 09:39:21 +0900925 if (this->bufferram[i].blockpage == blockpage)
Kyungmin Parkabf3c0f2007-02-02 09:29:36 +0900926 this->bufferram[i].blockpage = -1;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100927
928 /* Update BufferRAM */
929 i = ONENAND_CURRENT_BUFFERRAM(this);
Kyungmin Parkabf3c0f2007-02-02 09:29:36 +0900930 if (valid)
931 this->bufferram[i].blockpage = blockpage;
932 else
933 this->bufferram[i].blockpage = -1;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100934}
935
936/**
Adrian Hunter480b9df2007-02-07 13:55:19 +0200937 * onenand_invalidate_bufferram - [GENERIC] Invalidate BufferRAM information
938 * @param mtd MTD data structure
939 * @param addr start address to invalidate
940 * @param len length to invalidate
941 *
942 * Invalidate BufferRAM information
943 */
944static void onenand_invalidate_bufferram(struct mtd_info *mtd, loff_t addr,
945 unsigned int len)
946{
947 struct onenand_chip *this = mtd->priv;
948 int i;
949 loff_t end_addr = addr + len;
950
951 /* Invalidate BufferRAM */
952 for (i = 0; i < MAX_BUFFERRAM; i++) {
953 loff_t buf_addr = this->bufferram[i].blockpage << this->page_shift;
954 if (buf_addr >= addr && buf_addr < end_addr)
955 this->bufferram[i].blockpage = -1;
956 }
957}
958
959/**
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100960 * onenand_get_device - [GENERIC] Get chip for selected access
961 * @param mtd MTD device structure
962 * @param new_state the state which is requested
963 *
964 * Get the device and lock it for exclusive access
965 */
Kyungmin Parka41371e2005-09-29 03:55:31 +0100966static int onenand_get_device(struct mtd_info *mtd, int new_state)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100967{
968 struct onenand_chip *this = mtd->priv;
969 DECLARE_WAITQUEUE(wait, current);
970
971 /*
972 * Grab the lock and see if the device is available
973 */
974 while (1) {
975 spin_lock(&this->chip_lock);
976 if (this->state == FL_READY) {
977 this->state = new_state;
978 spin_unlock(&this->chip_lock);
Adrian Huntercf24dc82010-02-19 15:39:52 +0100979 if (new_state != FL_PM_SUSPENDED && this->enable)
980 this->enable(mtd);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100981 break;
982 }
Kyungmin Parka41371e2005-09-29 03:55:31 +0100983 if (new_state == FL_PM_SUSPENDED) {
984 spin_unlock(&this->chip_lock);
985 return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;
986 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100987 set_current_state(TASK_UNINTERRUPTIBLE);
988 add_wait_queue(&this->wq, &wait);
989 spin_unlock(&this->chip_lock);
990 schedule();
991 remove_wait_queue(&this->wq, &wait);
992 }
Kyungmin Parka41371e2005-09-29 03:55:31 +0100993
994 return 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +0100995}
996
997/**
998 * onenand_release_device - [GENERIC] release chip
999 * @param mtd MTD device structure
1000 *
1001 * Deselect, release chip lock and wake up anyone waiting on the device
1002 */
1003static void onenand_release_device(struct mtd_info *mtd)
1004{
1005 struct onenand_chip *this = mtd->priv;
1006
Adrian Huntercf24dc82010-02-19 15:39:52 +01001007 if (this->state != FL_PM_SUSPENDED && this->disable)
1008 this->disable(mtd);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001009 /* Release the chip */
1010 spin_lock(&this->chip_lock);
1011 this->state = FL_READY;
1012 wake_up(&this->wq);
1013 spin_unlock(&this->chip_lock);
1014}
1015
1016/**
Brian Norris7854d3f2011-06-23 14:12:08 -07001017 * onenand_transfer_auto_oob - [INTERN] oob auto-placement transfer
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001018 * @param mtd MTD device structure
1019 * @param buf destination address
1020 * @param column oob offset to read from
1021 * @param thislen oob length to read
1022 */
1023static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int column,
1024 int thislen)
1025{
1026 struct onenand_chip *this = mtd->priv;
1027 struct nand_oobfree *free;
1028 int readcol = column;
1029 int readend = column + thislen;
1030 int lastgap = 0;
1031 unsigned int i;
1032 uint8_t *oob_buf = this->oob_buf;
1033
1034 free = this->ecclayout->oobfree;
1035 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
1036 if (readcol >= lastgap)
1037 readcol += free->offset - lastgap;
1038 if (readend >= lastgap)
1039 readend += free->offset - lastgap;
1040 lastgap = free->offset + free->length;
1041 }
1042 this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
1043 free = this->ecclayout->oobfree;
1044 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
1045 int free_end = free->offset + free->length;
1046 if (free->offset < readend && free_end > readcol) {
1047 int st = max_t(int,free->offset,readcol);
1048 int ed = min_t(int,free_end,readend);
1049 int n = ed - st;
1050 memcpy(buf, oob_buf + st, n);
1051 buf += n;
1052 } else if (column == 0)
1053 break;
1054 }
1055 return 0;
1056}
1057
1058/**
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001059 * onenand_recover_lsb - [Flex-OneNAND] Recover LSB page data
1060 * @param mtd MTD device structure
1061 * @param addr address to recover
1062 * @param status return value from onenand_wait / onenand_bbt_wait
1063 *
1064 * MLC NAND Flash cell has paired pages - LSB page and MSB page. LSB page has
1065 * lower page address and MSB page has higher page address in paired pages.
1066 * If power off occurs during MSB page program, the paired LSB page data can
1067 * become corrupt. LSB page recovery read is a way to read LSB page though page
1068 * data are corrupted. When uncorrectable error occurs as a result of LSB page
1069 * read after power up, issue LSB page recovery read.
1070 */
1071static int onenand_recover_lsb(struct mtd_info *mtd, loff_t addr, int status)
1072{
1073 struct onenand_chip *this = mtd->priv;
1074 int i;
1075
1076 /* Recovery is only for Flex-OneNAND */
1077 if (!FLEXONENAND(this))
1078 return status;
1079
1080 /* check if we failed due to uncorrectable error */
Brian Norrisd57f40542011-09-20 18:34:25 -07001081 if (!mtd_is_eccerr(status) && status != ONENAND_BBT_READ_ECC_ERROR)
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001082 return status;
1083
1084 /* check if address lies in MLC region */
1085 i = flexonenand_region(mtd, addr);
1086 if (mtd->eraseregions[i].erasesize < (1 << this->erase_shift))
1087 return status;
1088
1089 /* We are attempting to reread, so decrement stats.failed
1090 * which was incremented by onenand_wait due to read failure
1091 */
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301092 printk(KERN_INFO "%s: Attempting to recover from uncorrectable read\n",
1093 __func__);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001094 mtd->ecc_stats.failed--;
1095
1096 /* Issue the LSB page recovery command */
1097 this->command(mtd, FLEXONENAND_CMD_RECOVER_LSB, addr, this->writesize);
1098 return this->wait(mtd, FL_READING);
1099}
1100
1101/**
1102 * onenand_mlc_read_ops_nolock - MLC OneNAND read main and/or out-of-band
1103 * @param mtd MTD device structure
1104 * @param from offset to read from
1105 * @param ops: oob operation description structure
1106 *
1107 * MLC OneNAND / Flex-OneNAND has 4KB page size and 4KB dataram.
1108 * So, read-while-load is not present.
1109 */
1110static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from,
1111 struct mtd_oob_ops *ops)
1112{
1113 struct onenand_chip *this = mtd->priv;
1114 struct mtd_ecc_stats stats;
1115 size_t len = ops->len;
1116 size_t ooblen = ops->ooblen;
1117 u_char *buf = ops->datbuf;
1118 u_char *oobbuf = ops->oobbuf;
1119 int read = 0, column, thislen;
1120 int oobread = 0, oobcolumn, thisooblen, oobsize;
1121 int ret = 0;
1122 int writesize = this->writesize;
1123
Brian Norris0a32a102011-07-19 10:06:10 -07001124 pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from,
1125 (int)len);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001126
Brian Norris0612b9d2011-08-30 18:45:40 -07001127 if (ops->mode == MTD_OPS_AUTO_OOB)
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001128 oobsize = this->ecclayout->oobavail;
1129 else
1130 oobsize = mtd->oobsize;
1131
1132 oobcolumn = from & (mtd->oobsize - 1);
1133
1134 /* Do not allow reads past end of device */
1135 if (from + len > mtd->size) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301136 printk(KERN_ERR "%s: Attempt read beyond end of device\n",
1137 __func__);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001138 ops->retlen = 0;
1139 ops->oobretlen = 0;
1140 return -EINVAL;
1141 }
1142
1143 stats = mtd->ecc_stats;
1144
1145 while (read < len) {
1146 cond_resched();
1147
1148 thislen = min_t(int, writesize, len - read);
1149
1150 column = from & (writesize - 1);
1151 if (column + thislen > writesize)
1152 thislen = writesize - column;
1153
1154 if (!onenand_check_bufferram(mtd, from)) {
1155 this->command(mtd, ONENAND_CMD_READ, from, writesize);
1156
1157 ret = this->wait(mtd, FL_READING);
1158 if (unlikely(ret))
1159 ret = onenand_recover_lsb(mtd, from, ret);
1160 onenand_update_bufferram(mtd, from, !ret);
Brian Norrisd57f40542011-09-20 18:34:25 -07001161 if (mtd_is_eccerr(ret))
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001162 ret = 0;
Adrian Hunterb0850582011-02-08 12:02:38 +02001163 if (ret)
1164 break;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001165 }
1166
1167 this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
1168 if (oobbuf) {
1169 thisooblen = oobsize - oobcolumn;
1170 thisooblen = min_t(int, thisooblen, ooblen - oobread);
1171
Brian Norris0612b9d2011-08-30 18:45:40 -07001172 if (ops->mode == MTD_OPS_AUTO_OOB)
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001173 onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);
1174 else
1175 this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen);
1176 oobread += thisooblen;
1177 oobbuf += thisooblen;
1178 oobcolumn = 0;
1179 }
1180
1181 read += thislen;
1182 if (read == len)
1183 break;
1184
1185 from += thislen;
1186 buf += thislen;
1187 }
1188
1189 /*
1190 * Return success, if no ECC failures, else -EBADMSG
1191 * fs driver will take care of that, because
1192 * retlen == desired len and result == -EBADMSG
1193 */
1194 ops->retlen = read;
1195 ops->oobretlen = oobread;
1196
1197 if (ret)
1198 return ret;
1199
1200 if (mtd->ecc_stats.failed - stats.failed)
1201 return -EBADMSG;
1202
Mike Dunnedbc45402012-04-25 12:06:11 -07001203 /* return max bitflips per ecc step; ONENANDs correct 1 bit only */
1204 return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001205}
1206
1207/**
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001208 * onenand_read_ops_nolock - [OneNAND Interface] OneNAND read main and/or out-of-band
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001209 * @param mtd MTD device structure
1210 * @param from offset to read from
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001211 * @param ops: oob operation description structure
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001212 *
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001213 * OneNAND read main and/or out-of-band data
1214 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001215static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001216 struct mtd_oob_ops *ops)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001217{
1218 struct onenand_chip *this = mtd->priv;
Kyungmin Parkf4f91ac2006-11-16 12:03:56 +09001219 struct mtd_ecc_stats stats;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001220 size_t len = ops->len;
1221 size_t ooblen = ops->ooblen;
1222 u_char *buf = ops->datbuf;
1223 u_char *oobbuf = ops->oobbuf;
1224 int read = 0, column, thislen;
1225 int oobread = 0, oobcolumn, thisooblen, oobsize;
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001226 int ret = 0, boundary = 0;
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001227 int writesize = this->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001228
Brian Norris0a32a102011-07-19 10:06:10 -07001229 pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from,
1230 (int)len);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001231
Brian Norris0612b9d2011-08-30 18:45:40 -07001232 if (ops->mode == MTD_OPS_AUTO_OOB)
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001233 oobsize = this->ecclayout->oobavail;
1234 else
1235 oobsize = mtd->oobsize;
1236
1237 oobcolumn = from & (mtd->oobsize - 1);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001238
1239 /* Do not allow reads past end of device */
1240 if ((from + len) > mtd->size) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301241 printk(KERN_ERR "%s: Attempt read beyond end of device\n",
1242 __func__);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001243 ops->retlen = 0;
1244 ops->oobretlen = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001245 return -EINVAL;
1246 }
1247
Kyungmin Parkf4f91ac2006-11-16 12:03:56 +09001248 stats = mtd->ecc_stats;
Artem Bityutskiy61a7e192006-12-26 16:41:24 +09001249
Adrian Huntera8de85d2007-01-04 09:51:26 +02001250 /* Read-while-load method */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001251
Adrian Huntera8de85d2007-01-04 09:51:26 +02001252 /* Do first load to bufferRAM */
1253 if (read < len) {
1254 if (!onenand_check_bufferram(mtd, from)) {
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001255 this->command(mtd, ONENAND_CMD_READ, from, writesize);
Adrian Huntera8de85d2007-01-04 09:51:26 +02001256 ret = this->wait(mtd, FL_READING);
1257 onenand_update_bufferram(mtd, from, !ret);
Brian Norrisd57f40542011-09-20 18:34:25 -07001258 if (mtd_is_eccerr(ret))
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001259 ret = 0;
Adrian Huntera8de85d2007-01-04 09:51:26 +02001260 }
1261 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001262
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001263 thislen = min_t(int, writesize, len - read);
1264 column = from & (writesize - 1);
1265 if (column + thislen > writesize)
1266 thislen = writesize - column;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001267
Adrian Huntera8de85d2007-01-04 09:51:26 +02001268 while (!ret) {
1269 /* If there is more to load then start next load */
1270 from += thislen;
1271 if (read + thislen < len) {
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001272 this->command(mtd, ONENAND_CMD_READ, from, writesize);
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001273 /*
1274 * Chip boundary handling in DDP
1275 * Now we issued chip 1 read and pointed chip 1
Mika Korhonen492e1502009-06-09 21:52:35 +03001276 * bufferram so we have to point chip 0 bufferram.
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001277 */
Kyungmin Park738d61f2007-01-15 17:09:14 +09001278 if (ONENAND_IS_DDP(this) &&
1279 unlikely(from == (this->chipsize >> 1))) {
1280 this->write_word(ONENAND_DDP_CHIP0, this->base + ONENAND_REG_START_ADDRESS2);
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001281 boundary = 1;
1282 } else
1283 boundary = 0;
Adrian Huntera8de85d2007-01-04 09:51:26 +02001284 ONENAND_SET_PREV_BUFFERRAM(this);
1285 }
1286 /* While load is going, read from last bufferRAM */
1287 this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001288
1289 /* Read oob area if needed */
1290 if (oobbuf) {
1291 thisooblen = oobsize - oobcolumn;
1292 thisooblen = min_t(int, thisooblen, ooblen - oobread);
1293
Brian Norris0612b9d2011-08-30 18:45:40 -07001294 if (ops->mode == MTD_OPS_AUTO_OOB)
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001295 onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);
1296 else
1297 this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen);
1298 oobread += thisooblen;
1299 oobbuf += thisooblen;
1300 oobcolumn = 0;
1301 }
1302
Adrian Huntera8de85d2007-01-04 09:51:26 +02001303 /* See if we are done */
1304 read += thislen;
1305 if (read == len)
1306 break;
1307 /* Set up for next read from bufferRAM */
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001308 if (unlikely(boundary))
Kyungmin Park738d61f2007-01-15 17:09:14 +09001309 this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);
Adrian Huntera8de85d2007-01-04 09:51:26 +02001310 ONENAND_SET_NEXT_BUFFERRAM(this);
1311 buf += thislen;
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001312 thislen = min_t(int, writesize, len - read);
Adrian Huntera8de85d2007-01-04 09:51:26 +02001313 column = 0;
1314 cond_resched();
1315 /* Now wait for load */
1316 ret = this->wait(mtd, FL_READING);
1317 onenand_update_bufferram(mtd, from, !ret);
Brian Norrisd57f40542011-09-20 18:34:25 -07001318 if (mtd_is_eccerr(ret))
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001319 ret = 0;
Adrian Huntera8de85d2007-01-04 09:51:26 +02001320 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001321
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001322 /*
1323 * Return success, if no ECC failures, else -EBADMSG
1324 * fs driver will take care of that, because
1325 * retlen == desired len and result == -EBADMSG
1326 */
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001327 ops->retlen = read;
1328 ops->oobretlen = oobread;
Kyungmin Parkf4f91ac2006-11-16 12:03:56 +09001329
Adrian Huntera8de85d2007-01-04 09:51:26 +02001330 if (ret)
1331 return ret;
1332
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001333 if (mtd->ecc_stats.failed - stats.failed)
1334 return -EBADMSG;
1335
Mike Dunnedbc45402012-04-25 12:06:11 -07001336 /* return max bitflips per ecc step; ONENANDs correct 1 bit only */
1337 return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001338}
1339
1340/**
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001341 * onenand_read_oob_nolock - [MTD Interface] OneNAND read out-of-band
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001342 * @param mtd MTD device structure
1343 * @param from offset to read from
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001344 * @param ops: oob operation description structure
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001345 *
1346 * OneNAND read out-of-band data from the spare area
1347 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001348static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
Kyungmin Park12f77c92007-08-30 09:36:05 +09001349 struct mtd_oob_ops *ops)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001350{
1351 struct onenand_chip *this = mtd->priv;
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001352 struct mtd_ecc_stats stats;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001353 int read = 0, thislen, column, oobsize;
Kyungmin Park12f77c92007-08-30 09:36:05 +09001354 size_t len = ops->ooblen;
Brian Norris905c6bc2011-08-30 18:45:39 -07001355 unsigned int mode = ops->mode;
Kyungmin Park12f77c92007-08-30 09:36:05 +09001356 u_char *buf = ops->oobbuf;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001357 int ret = 0, readcmd;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001358
Kyungmin Park12f77c92007-08-30 09:36:05 +09001359 from += ops->ooboffs;
1360
Brian Norris0a32a102011-07-19 10:06:10 -07001361 pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from,
1362 (int)len);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001363
1364 /* Initialize return length value */
Kyungmin Park12f77c92007-08-30 09:36:05 +09001365 ops->oobretlen = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001366
Brian Norris0612b9d2011-08-30 18:45:40 -07001367 if (mode == MTD_OPS_AUTO_OOB)
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001368 oobsize = this->ecclayout->oobavail;
1369 else
1370 oobsize = mtd->oobsize;
1371
1372 column = from & (mtd->oobsize - 1);
1373
1374 if (unlikely(column >= oobsize)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301375 printk(KERN_ERR "%s: Attempted to start read outside oob\n",
1376 __func__);
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001377 return -EINVAL;
1378 }
1379
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001380 /* Do not allow reads past end of device */
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001381 if (unlikely(from >= mtd->size ||
1382 column + len > ((mtd->size >> this->page_shift) -
1383 (from >> this->page_shift)) * oobsize)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301384 printk(KERN_ERR "%s: Attempted to read beyond end of device\n",
1385 __func__);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001386 return -EINVAL;
1387 }
1388
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001389 stats = mtd->ecc_stats;
1390
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001391 readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001392
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001393 while (read < len) {
Artem Bityutskiy61a7e192006-12-26 16:41:24 +09001394 cond_resched();
1395
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001396 thislen = oobsize - column;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001397 thislen = min_t(int, thislen, len);
1398
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001399 this->command(mtd, readcmd, from, mtd->oobsize);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001400
1401 onenand_update_bufferram(mtd, from, 0);
1402
1403 ret = this->wait(mtd, FL_READING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001404 if (unlikely(ret))
1405 ret = onenand_recover_lsb(mtd, from, ret);
1406
Brian Norrisd57f40542011-09-20 18:34:25 -07001407 if (ret && !mtd_is_eccerr(ret)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301408 printk(KERN_ERR "%s: read failed = 0x%x\n",
1409 __func__, ret);
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001410 break;
1411 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001412
Brian Norris0612b9d2011-08-30 18:45:40 -07001413 if (mode == MTD_OPS_AUTO_OOB)
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001414 onenand_transfer_auto_oob(mtd, buf, column, thislen);
1415 else
1416 this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001417
1418 read += thislen;
1419
1420 if (read == len)
1421 break;
1422
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001423 buf += thislen;
1424
1425 /* Read more? */
1426 if (read < len) {
1427 /* Page size */
Joern Engel28318772006-05-22 23:18:05 +02001428 from += mtd->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001429 column = 0;
1430 }
1431 }
1432
Kyungmin Park12f77c92007-08-30 09:36:05 +09001433 ops->oobretlen = read;
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001434
1435 if (ret)
1436 return ret;
1437
1438 if (mtd->ecc_stats.failed - stats.failed)
1439 return -EBADMSG;
1440
1441 return 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001442}
1443
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001444/**
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001445 * onenand_read - [MTD Interface] Read data from flash
1446 * @param mtd MTD device structure
1447 * @param from offset to read from
1448 * @param len number of bytes to read
1449 * @param retlen pointer to variable to store the number of read bytes
1450 * @param buf the databuffer to put data
1451 *
1452 * Read with ecc
1453*/
1454static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
1455 size_t *retlen, u_char *buf)
1456{
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001457 struct onenand_chip *this = mtd->priv;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001458 struct mtd_oob_ops ops = {
1459 .len = len,
1460 .ooblen = 0,
1461 .datbuf = buf,
1462 .oobbuf = NULL,
1463 };
1464 int ret;
1465
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001466 onenand_get_device(mtd, FL_READING);
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001467 ret = ONENAND_IS_4KB_PAGE(this) ?
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001468 onenand_mlc_read_ops_nolock(mtd, from, &ops) :
1469 onenand_read_ops_nolock(mtd, from, &ops);
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001470 onenand_release_device(mtd);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001471
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001472 *retlen = ops.retlen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001473 return ret;
1474}
1475
1476/**
1477 * onenand_read_oob - [MTD Interface] Read main and/or out-of-band
Kyungmin Parke3da8062007-02-15 09:36:39 +09001478 * @param mtd: MTD device structure
1479 * @param from: offset to read from
1480 * @param ops: oob operation description structure
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001481
1482 * Read main and/or out-of-band
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001483 */
1484static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
1485 struct mtd_oob_ops *ops)
1486{
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001487 struct onenand_chip *this = mtd->priv;
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001488 int ret;
1489
Kyungmin Park4f4fad22007-02-02 09:22:21 +09001490 switch (ops->mode) {
Brian Norris0612b9d2011-08-30 18:45:40 -07001491 case MTD_OPS_PLACE_OOB:
1492 case MTD_OPS_AUTO_OOB:
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001493 break;
Brian Norris0612b9d2011-08-30 18:45:40 -07001494 case MTD_OPS_RAW:
Kyungmin Park4f4fad22007-02-02 09:22:21 +09001495 /* Not implemented yet */
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001496 default:
1497 return -EINVAL;
1498 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001499
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001500 onenand_get_device(mtd, FL_READING);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001501 if (ops->datbuf)
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001502 ret = ONENAND_IS_4KB_PAGE(this) ?
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001503 onenand_mlc_read_ops_nolock(mtd, from, ops) :
1504 onenand_read_ops_nolock(mtd, from, ops);
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001505 else
1506 ret = onenand_read_oob_nolock(mtd, from, ops);
1507 onenand_release_device(mtd);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001508
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001509 return ret;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001510}
1511
Kyungmin Park211ac752007-02-07 12:15:01 +09001512/**
1513 * onenand_bbt_wait - [DEFAULT] wait until the command is done
1514 * @param mtd MTD device structure
1515 * @param state state to select the max. timeout value
1516 *
1517 * Wait for command done.
1518 */
1519static int onenand_bbt_wait(struct mtd_info *mtd, int state)
1520{
1521 struct onenand_chip *this = mtd->priv;
1522 unsigned long timeout;
Adrian Huntere0c1a922010-12-10 12:04:20 +02001523 unsigned int interrupt, ctrl, ecc, addr1, addr8;
Kyungmin Park211ac752007-02-07 12:15:01 +09001524
1525 /* The 20 msec is enough */
1526 timeout = jiffies + msecs_to_jiffies(20);
1527 while (time_before(jiffies, timeout)) {
1528 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
1529 if (interrupt & ONENAND_INT_MASTER)
1530 break;
1531 }
1532 /* To get correct interrupt status in timeout case */
1533 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
1534 ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
Adrian Huntere0c1a922010-12-10 12:04:20 +02001535 addr1 = this->read_word(this->base + ONENAND_REG_START_ADDRESS1);
1536 addr8 = this->read_word(this->base + ONENAND_REG_START_ADDRESS8);
Kyungmin Park211ac752007-02-07 12:15:01 +09001537
Kyungmin Park211ac752007-02-07 12:15:01 +09001538 if (interrupt & ONENAND_INT_READ) {
Adrian Huntere0c1a922010-12-10 12:04:20 +02001539 ecc = onenand_read_ecc(this);
Kyungmin Park83973b82008-05-29 14:52:40 +09001540 if (ecc & ONENAND_ECC_2BIT_ALL) {
Adrian Huntere0c1a922010-12-10 12:04:20 +02001541 printk(KERN_DEBUG "%s: ecc 0x%04x ctrl 0x%04x "
1542 "intr 0x%04x addr1 %#x addr8 %#x\n",
1543 __func__, ecc, ctrl, interrupt, addr1, addr8);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001544 return ONENAND_BBT_READ_ECC_ERROR;
Kyungmin Park83973b82008-05-29 14:52:40 +09001545 }
Kyungmin Park211ac752007-02-07 12:15:01 +09001546 } else {
Adrian Huntere0c1a922010-12-10 12:04:20 +02001547 printk(KERN_ERR "%s: read timeout! ctrl 0x%04x "
1548 "intr 0x%04x addr1 %#x addr8 %#x\n",
1549 __func__, ctrl, interrupt, addr1, addr8);
Kyungmin Park211ac752007-02-07 12:15:01 +09001550 return ONENAND_BBT_READ_FATAL_ERROR;
1551 }
1552
Kyungmin Park83973b82008-05-29 14:52:40 +09001553 /* Initial bad block case: 0x2400 or 0x0400 */
1554 if (ctrl & ONENAND_CTRL_ERROR) {
Adrian Huntere0c1a922010-12-10 12:04:20 +02001555 printk(KERN_DEBUG "%s: ctrl 0x%04x intr 0x%04x addr1 %#x "
1556 "addr8 %#x\n", __func__, ctrl, interrupt, addr1, addr8);
Kyungmin Park83973b82008-05-29 14:52:40 +09001557 return ONENAND_BBT_READ_ERROR;
1558 }
1559
Kyungmin Park211ac752007-02-07 12:15:01 +09001560 return 0;
1561}
1562
1563/**
1564 * onenand_bbt_read_oob - [MTD Interface] OneNAND read out-of-band for bbt scan
1565 * @param mtd MTD device structure
1566 * @param from offset to read from
Kyungmin Parke3da8062007-02-15 09:36:39 +09001567 * @param ops oob operation description structure
Kyungmin Park211ac752007-02-07 12:15:01 +09001568 *
1569 * OneNAND read out-of-band data from the spare area for bbt scan
1570 */
1571int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
1572 struct mtd_oob_ops *ops)
1573{
1574 struct onenand_chip *this = mtd->priv;
1575 int read = 0, thislen, column;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001576 int ret = 0, readcmd;
Kyungmin Park211ac752007-02-07 12:15:01 +09001577 size_t len = ops->ooblen;
1578 u_char *buf = ops->oobbuf;
1579
Brian Norris0a32a102011-07-19 10:06:10 -07001580 pr_debug("%s: from = 0x%08x, len = %zi\n", __func__, (unsigned int)from,
1581 len);
Kyungmin Park211ac752007-02-07 12:15:01 +09001582
1583 /* Initialize return value */
1584 ops->oobretlen = 0;
1585
1586 /* Do not allow reads past end of device */
1587 if (unlikely((from + len) > mtd->size)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301588 printk(KERN_ERR "%s: Attempt read beyond end of device\n",
1589 __func__);
Kyungmin Park211ac752007-02-07 12:15:01 +09001590 return ONENAND_BBT_READ_FATAL_ERROR;
1591 }
1592
1593 /* Grab the lock and see if the device is available */
1594 onenand_get_device(mtd, FL_READING);
1595
1596 column = from & (mtd->oobsize - 1);
1597
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001598 readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001599
Kyungmin Park211ac752007-02-07 12:15:01 +09001600 while (read < len) {
1601 cond_resched();
1602
1603 thislen = mtd->oobsize - column;
1604 thislen = min_t(int, thislen, len);
1605
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001606 this->command(mtd, readcmd, from, mtd->oobsize);
Kyungmin Park211ac752007-02-07 12:15:01 +09001607
1608 onenand_update_bufferram(mtd, from, 0);
1609
Kyungmin Park31bb9992009-05-12 13:46:57 -07001610 ret = this->bbt_wait(mtd, FL_READING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001611 if (unlikely(ret))
1612 ret = onenand_recover_lsb(mtd, from, ret);
1613
Kyungmin Park211ac752007-02-07 12:15:01 +09001614 if (ret)
1615 break;
1616
1617 this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
1618 read += thislen;
1619 if (read == len)
1620 break;
1621
1622 buf += thislen;
1623
1624 /* Read more? */
1625 if (read < len) {
1626 /* Update Page size */
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001627 from += this->writesize;
Kyungmin Park211ac752007-02-07 12:15:01 +09001628 column = 0;
1629 }
1630 }
1631
1632 /* Deselect and wake up anyone waiting on the device */
1633 onenand_release_device(mtd);
1634
1635 ops->oobretlen = read;
1636 return ret;
1637}
1638
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001639#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
1640/**
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001641 * onenand_verify_oob - [GENERIC] verify the oob contents after a write
1642 * @param mtd MTD device structure
1643 * @param buf the databuffer to verify
1644 * @param to offset to read from
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001645 */
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001646static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to)
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001647{
1648 struct onenand_chip *this = mtd->priv;
Kyungmin Park69d79182007-12-14 14:47:21 +09001649 u_char *oob_buf = this->oob_buf;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001650 int status, i, readcmd;
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001651
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001652 readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001653
1654 this->command(mtd, readcmd, to, mtd->oobsize);
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001655 onenand_update_bufferram(mtd, to, 0);
1656 status = this->wait(mtd, FL_READING);
1657 if (status)
1658 return status;
1659
Kyungmin Park69d79182007-12-14 14:47:21 +09001660 this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
Kyungmin Park91014e92007-02-12 10:34:39 +09001661 for (i = 0; i < mtd->oobsize; i++)
Kyungmin Park69d79182007-12-14 14:47:21 +09001662 if (buf[i] != 0xFF && buf[i] != oob_buf[i])
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001663 return -EBADMSG;
1664
1665 return 0;
1666}
1667
1668/**
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001669 * onenand_verify - [GENERIC] verify the chip contents after a write
1670 * @param mtd MTD device structure
1671 * @param buf the databuffer to verify
1672 * @param addr offset to read from
1673 * @param len number of bytes to read and compare
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001674 */
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001675static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, size_t len)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001676{
1677 struct onenand_chip *this = mtd->priv;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001678 int ret = 0;
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001679 int thislen, column;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001680
Roman Tereshonkove6da8562011-02-08 12:02:42 +02001681 column = addr & (this->writesize - 1);
1682
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001683 while (len != 0) {
Roman Tereshonkove6da8562011-02-08 12:02:42 +02001684 thislen = min_t(int, this->writesize - column, len);
Kyungmin Park60d84f92006-12-22 16:21:54 +09001685
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001686 this->command(mtd, ONENAND_CMD_READ, addr, this->writesize);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001687
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001688 onenand_update_bufferram(mtd, addr, 0);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001689
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001690 ret = this->wait(mtd, FL_READING);
1691 if (ret)
1692 return ret;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001693
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001694 onenand_update_bufferram(mtd, addr, 1);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001695
Kyungmin Park3328dc32010-04-28 17:46:47 +02001696 this->read_bufferram(mtd, ONENAND_DATARAM, this->verify_buf, 0, mtd->writesize);
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001697
Roman Tereshonkove6da8562011-02-08 12:02:42 +02001698 if (memcmp(buf, this->verify_buf + column, thislen))
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001699 return -EBADMSG;
1700
1701 len -= thislen;
1702 buf += thislen;
1703 addr += thislen;
Roman Tereshonkove6da8562011-02-08 12:02:42 +02001704 column = 0;
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001705 }
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +00001706
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001707 return 0;
1708}
1709#else
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001710#define onenand_verify(...) (0)
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001711#define onenand_verify_oob(...) (0)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001712#endif
1713
Kyungmin Park60d84f92006-12-22 16:21:54 +09001714#define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001715
Richard Purdie6c77fd642008-02-06 10:18:22 +00001716static void onenand_panic_wait(struct mtd_info *mtd)
1717{
1718 struct onenand_chip *this = mtd->priv;
1719 unsigned int interrupt;
1720 int i;
1721
1722 for (i = 0; i < 2000; i++) {
1723 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
1724 if (interrupt & ONENAND_INT_MASTER)
1725 break;
1726 udelay(10);
1727 }
1728}
1729
1730/**
1731 * onenand_panic_write - [MTD Interface] write buffer to FLASH in a panic context
1732 * @param mtd MTD device structure
1733 * @param to offset to write to
1734 * @param len number of bytes to write
1735 * @param retlen pointer to variable to store the number of written bytes
1736 * @param buf the data to write
1737 *
1738 * Write with ECC
1739 */
1740static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
1741 size_t *retlen, const u_char *buf)
1742{
1743 struct onenand_chip *this = mtd->priv;
1744 int column, subpage;
1745 int written = 0;
1746 int ret = 0;
1747
1748 if (this->state == FL_PM_SUSPENDED)
1749 return -EBUSY;
1750
1751 /* Wait for any existing operation to clear */
1752 onenand_panic_wait(mtd);
1753
Brian Norris0a32a102011-07-19 10:06:10 -07001754 pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to,
1755 (int)len);
Richard Purdie6c77fd642008-02-06 10:18:22 +00001756
Richard Purdie6c77fd642008-02-06 10:18:22 +00001757 /* Reject writes, which are not page aligned */
Roel Kluinb73d7e432008-02-16 18:14:35 +01001758 if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301759 printk(KERN_ERR "%s: Attempt to write not page aligned data\n",
1760 __func__);
Richard Purdie6c77fd642008-02-06 10:18:22 +00001761 return -EINVAL;
1762 }
1763
1764 column = to & (mtd->writesize - 1);
1765
1766 /* Loop until all data write */
1767 while (written < len) {
1768 int thislen = min_t(int, mtd->writesize - column, len - written);
1769 u_char *wbuf = (u_char *) buf;
1770
1771 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
1772
1773 /* Partial page write */
1774 subpage = thislen < mtd->writesize;
1775 if (subpage) {
1776 memset(this->page_buf, 0xff, mtd->writesize);
1777 memcpy(this->page_buf + column, buf, thislen);
1778 wbuf = this->page_buf;
1779 }
1780
1781 this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
1782 this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);
1783
1784 this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
1785
1786 onenand_panic_wait(mtd);
1787
1788 /* In partial page write we don't update bufferram */
1789 onenand_update_bufferram(mtd, to, !ret && !subpage);
1790 if (ONENAND_IS_2PLANE(this)) {
1791 ONENAND_SET_BUFFERRAM1(this);
1792 onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage);
1793 }
1794
1795 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301796 printk(KERN_ERR "%s: write failed %d\n", __func__, ret);
Richard Purdie6c77fd642008-02-06 10:18:22 +00001797 break;
1798 }
1799
1800 written += thislen;
1801
1802 if (written == len)
1803 break;
1804
1805 column = 0;
1806 to += thislen;
1807 buf += thislen;
1808 }
1809
1810 *retlen = written;
1811 return ret;
1812}
1813
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001814/**
Brian Norris7854d3f2011-06-23 14:12:08 -07001815 * onenand_fill_auto_oob - [INTERN] oob auto-placement transfer
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001816 * @param mtd MTD device structure
1817 * @param oob_buf oob buffer
1818 * @param buf source address
1819 * @param column oob offset to write to
1820 * @param thislen oob length to write
1821 */
1822static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
1823 const u_char *buf, int column, int thislen)
1824{
1825 struct onenand_chip *this = mtd->priv;
1826 struct nand_oobfree *free;
1827 int writecol = column;
1828 int writeend = column + thislen;
1829 int lastgap = 0;
Kyungmin Parkad286342007-03-23 10:19:52 +09001830 unsigned int i;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001831
Kyungmin Parkad286342007-03-23 10:19:52 +09001832 free = this->ecclayout->oobfree;
1833 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001834 if (writecol >= lastgap)
1835 writecol += free->offset - lastgap;
1836 if (writeend >= lastgap)
1837 writeend += free->offset - lastgap;
1838 lastgap = free->offset + free->length;
1839 }
Kyungmin Parkad286342007-03-23 10:19:52 +09001840 free = this->ecclayout->oobfree;
1841 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001842 int free_end = free->offset + free->length;
1843 if (free->offset < writeend && free_end > writecol) {
1844 int st = max_t(int,free->offset,writecol);
1845 int ed = min_t(int,free_end,writeend);
1846 int n = ed - st;
1847 memcpy(oob_buf + st, buf, n);
1848 buf += n;
Adrian Hunterc36c46d2007-03-23 17:16:22 +09001849 } else if (column == 0)
Kyungmin Park5bc399e2007-03-09 09:41:07 +09001850 break;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001851 }
1852 return 0;
1853}
1854
1855/**
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001856 * onenand_write_ops_nolock - [OneNAND Interface] write main and/or out-of-band
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001857 * @param mtd MTD device structure
1858 * @param to offset to write to
1859 * @param ops oob operation description structure
1860 *
1861 * Write main and/or oob with ECC
1862 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001863static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001864 struct mtd_oob_ops *ops)
1865{
1866 struct onenand_chip *this = mtd->priv;
Kyungmin Park9ce96902008-11-17 17:54:28 +09001867 int written = 0, column, thislen = 0, subpage = 0;
1868 int prev = 0, prevlen = 0, prev_subpage = 0, first = 1;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001869 int oobwritten = 0, oobcolumn, thisooblen, oobsize;
1870 size_t len = ops->len;
1871 size_t ooblen = ops->ooblen;
1872 const u_char *buf = ops->datbuf;
1873 const u_char *oob = ops->oobbuf;
1874 u_char *oobbuf;
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02001875 int ret = 0, cmd;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001876
Brian Norris0a32a102011-07-19 10:06:10 -07001877 pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to,
1878 (int)len);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001879
1880 /* Initialize retlen, in case of early exit */
1881 ops->retlen = 0;
1882 ops->oobretlen = 0;
1883
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001884 /* Reject writes, which are not page aligned */
Roel Kluinb73d7e432008-02-16 18:14:35 +01001885 if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301886 printk(KERN_ERR "%s: Attempt to write not page aligned data\n",
1887 __func__);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001888 return -EINVAL;
1889 }
1890
Kyungmin Park9ce96902008-11-17 17:54:28 +09001891 /* Check zero length */
1892 if (!len)
1893 return 0;
1894
Brian Norris0612b9d2011-08-30 18:45:40 -07001895 if (ops->mode == MTD_OPS_AUTO_OOB)
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001896 oobsize = this->ecclayout->oobavail;
1897 else
1898 oobsize = mtd->oobsize;
1899
1900 oobcolumn = to & (mtd->oobsize - 1);
1901
1902 column = to & (mtd->writesize - 1);
1903
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001904 /* Loop until all data write */
Kyungmin Park9ce96902008-11-17 17:54:28 +09001905 while (1) {
1906 if (written < len) {
1907 u_char *wbuf = (u_char *) buf;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001908
Kyungmin Park9ce96902008-11-17 17:54:28 +09001909 thislen = min_t(int, mtd->writesize - column, len - written);
1910 thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001911
Kyungmin Park9ce96902008-11-17 17:54:28 +09001912 cond_resched();
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001913
Kyungmin Park9ce96902008-11-17 17:54:28 +09001914 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001915
Kyungmin Park9ce96902008-11-17 17:54:28 +09001916 /* Partial page write */
1917 subpage = thislen < mtd->writesize;
1918 if (subpage) {
1919 memset(this->page_buf, 0xff, mtd->writesize);
1920 memcpy(this->page_buf + column, buf, thislen);
1921 wbuf = this->page_buf;
1922 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001923
Kyungmin Park9ce96902008-11-17 17:54:28 +09001924 this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001925
Kyungmin Park9ce96902008-11-17 17:54:28 +09001926 if (oob) {
1927 oobbuf = this->oob_buf;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001928
Kyungmin Park9ce96902008-11-17 17:54:28 +09001929 /* We send data to spare ram with oobsize
1930 * to prevent byte access */
1931 memset(oobbuf, 0xff, mtd->oobsize);
Brian Norris0612b9d2011-08-30 18:45:40 -07001932 if (ops->mode == MTD_OPS_AUTO_OOB)
Kyungmin Park9ce96902008-11-17 17:54:28 +09001933 onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
1934 else
1935 memcpy(oobbuf + oobcolumn, oob, thisooblen);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001936
Kyungmin Park9ce96902008-11-17 17:54:28 +09001937 oobwritten += thisooblen;
1938 oob += thisooblen;
1939 oobcolumn = 0;
1940 } else
1941 oobbuf = (u_char *) ffchars;
1942
1943 this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001944 } else
Kyungmin Park9ce96902008-11-17 17:54:28 +09001945 ONENAND_SET_NEXT_BUFFERRAM(this);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001946
Kyungmin Park9ce96902008-11-17 17:54:28 +09001947 /*
Mika Korhonen492e1502009-06-09 21:52:35 +03001948 * 2 PLANE, MLC, and Flex-OneNAND do not support
1949 * write-while-program feature.
Kyungmin Park9ce96902008-11-17 17:54:28 +09001950 */
Kyungmin Park6a88c472010-04-28 17:46:45 +02001951 if (!ONENAND_IS_2PLANE(this) && !ONENAND_IS_4KB_PAGE(this) && !first) {
Kyungmin Park9ce96902008-11-17 17:54:28 +09001952 ONENAND_SET_PREV_BUFFERRAM(this);
1953
1954 ret = this->wait(mtd, FL_WRITING);
1955
1956 /* In partial page write we don't update bufferram */
1957 onenand_update_bufferram(mtd, prev, !ret && !prev_subpage);
1958 if (ret) {
1959 written -= prevlen;
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301960 printk(KERN_ERR "%s: write failed %d\n",
1961 __func__, ret);
Kyungmin Park9ce96902008-11-17 17:54:28 +09001962 break;
1963 }
1964
1965 if (written == len) {
1966 /* Only check verify write turn on */
1967 ret = onenand_verify(mtd, buf - len, to - len, len);
1968 if (ret)
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301969 printk(KERN_ERR "%s: verify failed %d\n",
1970 __func__, ret);
Kyungmin Park9ce96902008-11-17 17:54:28 +09001971 break;
1972 }
1973
1974 ONENAND_SET_NEXT_BUFFERRAM(this);
1975 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001976
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02001977 this->ongoing = 0;
1978 cmd = ONENAND_CMD_PROG;
1979
1980 /* Exclude 1st OTP and OTP blocks for cache program feature */
1981 if (ONENAND_IS_CACHE_PROGRAM(this) &&
1982 likely(onenand_block(this, to) != 0) &&
1983 ONENAND_IS_4KB_PAGE(this) &&
1984 ((written + thislen) < len)) {
1985 cmd = ONENAND_CMD_2X_CACHE_PROG;
1986 this->ongoing = 1;
1987 }
1988
1989 this->command(mtd, cmd, to, mtd->writesize);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001990
Kyungmin Park9ce96902008-11-17 17:54:28 +09001991 /*
1992 * 2 PLANE, MLC, and Flex-OneNAND wait here
1993 */
Kyungmin Park6a88c472010-04-28 17:46:45 +02001994 if (ONENAND_IS_2PLANE(this) || ONENAND_IS_4KB_PAGE(this)) {
Kyungmin Park9ce96902008-11-17 17:54:28 +09001995 ret = this->wait(mtd, FL_WRITING);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001996
Kyungmin Park9ce96902008-11-17 17:54:28 +09001997 /* In partial page write we don't update bufferram */
1998 onenand_update_bufferram(mtd, to, !ret && !subpage);
1999 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302000 printk(KERN_ERR "%s: write failed %d\n",
2001 __func__, ret);
Kyungmin Park9ce96902008-11-17 17:54:28 +09002002 break;
2003 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002004
Kyungmin Park9ce96902008-11-17 17:54:28 +09002005 /* Only check verify write turn on */
2006 ret = onenand_verify(mtd, buf, to, thislen);
2007 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302008 printk(KERN_ERR "%s: verify failed %d\n",
2009 __func__, ret);
Kyungmin Park9ce96902008-11-17 17:54:28 +09002010 break;
2011 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002012
Kyungmin Park9ce96902008-11-17 17:54:28 +09002013 written += thislen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002014
Kyungmin Park9ce96902008-11-17 17:54:28 +09002015 if (written == len)
2016 break;
2017
2018 } else
2019 written += thislen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002020
2021 column = 0;
Kyungmin Park9ce96902008-11-17 17:54:28 +09002022 prev_subpage = subpage;
2023 prev = to;
2024 prevlen = thislen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002025 to += thislen;
2026 buf += thislen;
Kyungmin Park9ce96902008-11-17 17:54:28 +09002027 first = 0;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002028 }
2029
Kyungmin Park9ce96902008-11-17 17:54:28 +09002030 /* In error case, clear all bufferrams */
2031 if (written != len)
2032 onenand_invalidate_bufferram(mtd, 0, -1);
2033
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002034 ops->retlen = written;
Kyungmin Park9ce96902008-11-17 17:54:28 +09002035 ops->oobretlen = oobwritten;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002036
2037 return ret;
2038}
2039
2040
2041/**
Brian Norris7854d3f2011-06-23 14:12:08 -07002042 * onenand_write_oob_nolock - [INTERN] OneNAND write out-of-band
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002043 * @param mtd MTD device structure
2044 * @param to offset to write to
2045 * @param len number of bytes to write
2046 * @param retlen pointer to variable to store the number of written bytes
2047 * @param buf the data to write
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002048 * @param mode operation mode
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002049 *
2050 * OneNAND write out-of-band
2051 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002052static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
2053 struct mtd_oob_ops *ops)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002054{
2055 struct onenand_chip *this = mtd->priv;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002056 int column, ret = 0, oobsize;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002057 int written = 0, oobcmd;
Kyungmin Park91014e92007-02-12 10:34:39 +09002058 u_char *oobbuf;
Kyungmin Park12f77c92007-08-30 09:36:05 +09002059 size_t len = ops->ooblen;
2060 const u_char *buf = ops->oobbuf;
Brian Norris905c6bc2011-08-30 18:45:39 -07002061 unsigned int mode = ops->mode;
Kyungmin Park12f77c92007-08-30 09:36:05 +09002062
2063 to += ops->ooboffs;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002064
Brian Norris0a32a102011-07-19 10:06:10 -07002065 pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to,
2066 (int)len);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002067
2068 /* Initialize retlen, in case of early exit */
Kyungmin Park12f77c92007-08-30 09:36:05 +09002069 ops->oobretlen = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002070
Brian Norris0612b9d2011-08-30 18:45:40 -07002071 if (mode == MTD_OPS_AUTO_OOB)
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002072 oobsize = this->ecclayout->oobavail;
2073 else
2074 oobsize = mtd->oobsize;
2075
2076 column = to & (mtd->oobsize - 1);
2077
2078 if (unlikely(column >= oobsize)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302079 printk(KERN_ERR "%s: Attempted to start write outside oob\n",
2080 __func__);
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002081 return -EINVAL;
2082 }
2083
Adrian Hunter52e42002007-02-06 09:15:39 +09002084 /* For compatibility with NAND: Do not allow write past end of page */
Kyungmin Park91014e92007-02-12 10:34:39 +09002085 if (unlikely(column + len > oobsize)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302086 printk(KERN_ERR "%s: Attempt to write past end of page\n",
2087 __func__);
Adrian Hunter52e42002007-02-06 09:15:39 +09002088 return -EINVAL;
2089 }
2090
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002091 /* Do not allow reads past end of device */
2092 if (unlikely(to >= mtd->size ||
2093 column + len > ((mtd->size >> this->page_shift) -
2094 (to >> this->page_shift)) * oobsize)) {
David Woodhouse80327472009-10-05 08:30:04 +01002095 printk(KERN_ERR "%s: Attempted to write past end of device\n",
2096 __func__);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002097 return -EINVAL;
2098 }
2099
Kyungmin Park470bc842007-03-09 10:08:11 +09002100 oobbuf = this->oob_buf;
Kyungmin Park91014e92007-02-12 10:34:39 +09002101
Kyungmin Park8a8f6322010-12-02 09:24:16 +09002102 oobcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002103
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002104 /* Loop until all data write */
2105 while (written < len) {
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002106 int thislen = min_t(int, oobsize, len - written);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002107
Artem Bityutskiy61a7e192006-12-26 16:41:24 +09002108 cond_resched();
2109
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002110 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize);
2111
Kyungmin Park34c10602006-05-12 17:02:46 +03002112 /* We send data to spare ram with oobsize
2113 * to prevent byte access */
Kyungmin Park91014e92007-02-12 10:34:39 +09002114 memset(oobbuf, 0xff, mtd->oobsize);
Brian Norris0612b9d2011-08-30 18:45:40 -07002115 if (mode == MTD_OPS_AUTO_OOB)
Kyungmin Park91014e92007-02-12 10:34:39 +09002116 onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen);
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002117 else
Kyungmin Park91014e92007-02-12 10:34:39 +09002118 memcpy(oobbuf + column, buf, thislen);
2119 this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002120
Kyungmin Park8a8f6322010-12-02 09:24:16 +09002121 if (ONENAND_IS_4KB_PAGE(this)) {
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002122 /* Set main area of DataRAM to 0xff*/
2123 memset(this->page_buf, 0xff, mtd->writesize);
2124 this->write_bufferram(mtd, ONENAND_DATARAM,
2125 this->page_buf, 0, mtd->writesize);
2126 }
2127
2128 this->command(mtd, oobcmd, to, mtd->oobsize);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002129
2130 onenand_update_bufferram(mtd, to, 0);
Kyungmin Parkee9745f2007-06-30 13:57:49 +09002131 if (ONENAND_IS_2PLANE(this)) {
2132 ONENAND_SET_BUFFERRAM1(this);
2133 onenand_update_bufferram(mtd, to + this->writesize, 0);
2134 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002135
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002136 ret = this->wait(mtd, FL_WRITING);
2137 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302138 printk(KERN_ERR "%s: write failed %d\n", __func__, ret);
Kyungmin Park5b4246f2007-02-02 09:39:21 +09002139 break;
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002140 }
2141
Kyungmin Park91014e92007-02-12 10:34:39 +09002142 ret = onenand_verify_oob(mtd, oobbuf, to);
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002143 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302144 printk(KERN_ERR "%s: verify failed %d\n",
2145 __func__, ret);
Kyungmin Park5b4246f2007-02-02 09:39:21 +09002146 break;
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002147 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002148
2149 written += thislen;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002150 if (written == len)
2151 break;
2152
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002153 to += mtd->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002154 buf += thislen;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002155 column = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002156 }
2157
Kyungmin Park12f77c92007-08-30 09:36:05 +09002158 ops->oobretlen = written;
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +00002159
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002160 return ret;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002161}
2162
2163/**
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002164 * onenand_write - [MTD Interface] write buffer to FLASH
2165 * @param mtd MTD device structure
2166 * @param to offset to write to
2167 * @param len number of bytes to write
2168 * @param retlen pointer to variable to store the number of written bytes
2169 * @param buf the data to write
2170 *
2171 * Write with ECC
2172 */
2173static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
2174 size_t *retlen, const u_char *buf)
2175{
2176 struct mtd_oob_ops ops = {
2177 .len = len,
2178 .ooblen = 0,
2179 .datbuf = (u_char *) buf,
2180 .oobbuf = NULL,
2181 };
2182 int ret;
2183
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002184 onenand_get_device(mtd, FL_WRITING);
2185 ret = onenand_write_ops_nolock(mtd, to, &ops);
2186 onenand_release_device(mtd);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002187
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002188 *retlen = ops.retlen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002189 return ret;
2190}
2191
2192/**
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02002193 * onenand_write_oob - [MTD Interface] NAND write data and/or out-of-band
Kyungmin Parke3da8062007-02-15 09:36:39 +09002194 * @param mtd: MTD device structure
2195 * @param to: offset to write
2196 * @param ops: oob operation description structure
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02002197 */
2198static int onenand_write_oob(struct mtd_info *mtd, loff_t to,
2199 struct mtd_oob_ops *ops)
2200{
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002201 int ret;
2202
Kyungmin Park4f4fad22007-02-02 09:22:21 +09002203 switch (ops->mode) {
Brian Norris0612b9d2011-08-30 18:45:40 -07002204 case MTD_OPS_PLACE_OOB:
2205 case MTD_OPS_AUTO_OOB:
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002206 break;
Brian Norris0612b9d2011-08-30 18:45:40 -07002207 case MTD_OPS_RAW:
Kyungmin Park4f4fad22007-02-02 09:22:21 +09002208 /* Not implemented yet */
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002209 default:
2210 return -EINVAL;
2211 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002212
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002213 onenand_get_device(mtd, FL_WRITING);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002214 if (ops->datbuf)
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002215 ret = onenand_write_ops_nolock(mtd, to, ops);
2216 else
2217 ret = onenand_write_oob_nolock(mtd, to, ops);
2218 onenand_release_device(mtd);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002219
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002220 return ret;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02002221}
2222
2223/**
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002224 * onenand_block_isbad_nolock - [GENERIC] Check if a block is marked bad
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002225 * @param mtd MTD device structure
2226 * @param ofs offset from device start
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002227 * @param allowbbt 1, if its allowed to access the bbt area
2228 *
2229 * Check, if the block is bad. Either by reading the bad block table or
2230 * calling of the scan function.
2231 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002232static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int allowbbt)
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002233{
2234 struct onenand_chip *this = mtd->priv;
2235 struct bbm_info *bbm = this->bbm;
2236
2237 /* Return info from the table */
2238 return bbm->isbad_bbt(mtd, ofs, allowbbt);
2239}
2240
Mika Korhonen72073022009-10-23 07:50:43 +02002241
2242static int onenand_multiblock_erase_verify(struct mtd_info *mtd,
2243 struct erase_info *instr)
2244{
2245 struct onenand_chip *this = mtd->priv;
2246 loff_t addr = instr->addr;
2247 int len = instr->len;
2248 unsigned int block_size = (1 << this->erase_shift);
2249 int ret = 0;
2250
2251 while (len) {
2252 this->command(mtd, ONENAND_CMD_ERASE_VERIFY, addr, block_size);
2253 ret = this->wait(mtd, FL_VERIFYING_ERASE);
2254 if (ret) {
2255 printk(KERN_ERR "%s: Failed verify, block %d\n",
2256 __func__, onenand_block(this, addr));
2257 instr->state = MTD_ERASE_FAILED;
2258 instr->fail_addr = addr;
2259 return -1;
2260 }
2261 len -= block_size;
2262 addr += block_size;
2263 }
2264 return 0;
2265}
2266
2267/**
Brian Norris7854d3f2011-06-23 14:12:08 -07002268 * onenand_multiblock_erase - [INTERN] erase block(s) using multiblock erase
Mika Korhonen72073022009-10-23 07:50:43 +02002269 * @param mtd MTD device structure
2270 * @param instr erase instruction
2271 * @param region erase region
2272 *
2273 * Erase one or more blocks up to 64 block at a time
2274 */
2275static int onenand_multiblock_erase(struct mtd_info *mtd,
2276 struct erase_info *instr,
2277 unsigned int block_size)
2278{
2279 struct onenand_chip *this = mtd->priv;
2280 loff_t addr = instr->addr;
2281 int len = instr->len;
2282 int eb_count = 0;
2283 int ret = 0;
2284 int bdry_block = 0;
2285
2286 instr->state = MTD_ERASING;
2287
2288 if (ONENAND_IS_DDP(this)) {
2289 loff_t bdry_addr = this->chipsize >> 1;
2290 if (addr < bdry_addr && (addr + len) > bdry_addr)
2291 bdry_block = bdry_addr >> this->erase_shift;
2292 }
2293
2294 /* Pre-check bbs */
2295 while (len) {
2296 /* Check if we have a bad block, we do not erase bad blocks */
2297 if (onenand_block_isbad_nolock(mtd, addr, 0)) {
2298 printk(KERN_WARNING "%s: attempt to erase a bad block "
2299 "at addr 0x%012llx\n",
2300 __func__, (unsigned long long) addr);
2301 instr->state = MTD_ERASE_FAILED;
2302 return -EIO;
2303 }
2304 len -= block_size;
2305 addr += block_size;
2306 }
2307
2308 len = instr->len;
2309 addr = instr->addr;
2310
2311 /* loop over 64 eb batches */
2312 while (len) {
2313 struct erase_info verify_instr = *instr;
2314 int max_eb_count = MB_ERASE_MAX_BLK_COUNT;
2315
2316 verify_instr.addr = addr;
2317 verify_instr.len = 0;
2318
2319 /* do not cross chip boundary */
2320 if (bdry_block) {
2321 int this_block = (addr >> this->erase_shift);
2322
2323 if (this_block < bdry_block) {
2324 max_eb_count = min(max_eb_count,
2325 (bdry_block - this_block));
2326 }
2327 }
2328
2329 eb_count = 0;
2330
2331 while (len > block_size && eb_count < (max_eb_count - 1)) {
2332 this->command(mtd, ONENAND_CMD_MULTIBLOCK_ERASE,
2333 addr, block_size);
2334 onenand_invalidate_bufferram(mtd, addr, block_size);
2335
2336 ret = this->wait(mtd, FL_PREPARING_ERASE);
2337 if (ret) {
2338 printk(KERN_ERR "%s: Failed multiblock erase, "
2339 "block %d\n", __func__,
2340 onenand_block(this, addr));
2341 instr->state = MTD_ERASE_FAILED;
2342 instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
2343 return -EIO;
2344 }
2345
2346 len -= block_size;
2347 addr += block_size;
2348 eb_count++;
2349 }
2350
2351 /* last block of 64-eb series */
2352 cond_resched();
2353 this->command(mtd, ONENAND_CMD_ERASE, addr, block_size);
2354 onenand_invalidate_bufferram(mtd, addr, block_size);
2355
2356 ret = this->wait(mtd, FL_ERASING);
2357 /* Check if it is write protected */
2358 if (ret) {
2359 printk(KERN_ERR "%s: Failed erase, block %d\n",
2360 __func__, onenand_block(this, addr));
2361 instr->state = MTD_ERASE_FAILED;
2362 instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
2363 return -EIO;
2364 }
2365
2366 len -= block_size;
2367 addr += block_size;
2368 eb_count++;
2369
2370 /* verify */
2371 verify_instr.len = eb_count * block_size;
2372 if (onenand_multiblock_erase_verify(mtd, &verify_instr)) {
2373 instr->state = verify_instr.state;
2374 instr->fail_addr = verify_instr.fail_addr;
2375 return -EIO;
2376 }
2377
2378 }
2379 return 0;
2380}
2381
2382
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002383/**
Brian Norris7854d3f2011-06-23 14:12:08 -07002384 * onenand_block_by_block_erase - [INTERN] erase block(s) using regular erase
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002385 * @param mtd MTD device structure
2386 * @param instr erase instruction
Mika Korhonen73885ae2009-10-23 07:50:42 +02002387 * @param region erase region
2388 * @param block_size erase block size
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002389 *
Mika Korhonen73885ae2009-10-23 07:50:42 +02002390 * Erase one or more blocks one block at a time
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002391 */
Mika Korhonen73885ae2009-10-23 07:50:42 +02002392static int onenand_block_by_block_erase(struct mtd_info *mtd,
2393 struct erase_info *instr,
2394 struct mtd_erase_region_info *region,
2395 unsigned int block_size)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002396{
2397 struct onenand_chip *this = mtd->priv;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002398 loff_t addr = instr->addr;
Mika Korhonen73885ae2009-10-23 07:50:42 +02002399 int len = instr->len;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002400 loff_t region_end = 0;
Mika Korhonen73885ae2009-10-23 07:50:42 +02002401 int ret = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002402
Mika Korhonen73885ae2009-10-23 07:50:42 +02002403 if (region) {
2404 /* region is set for Flex-OneNAND */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002405 region_end = region->offset + region->erasesize * region->numblocks;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002406 }
2407
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002408 instr->state = MTD_ERASING;
2409
Mika Korhonen73885ae2009-10-23 07:50:42 +02002410 /* Loop through the blocks */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002411 while (len) {
Artem Bityutskiy61a7e192006-12-26 16:41:24 +09002412 cond_resched();
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002413
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002414 /* Check if we have a bad block, we do not erase bad blocks */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002415 if (onenand_block_isbad_nolock(mtd, addr, 0)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302416 printk(KERN_WARNING "%s: attempt to erase a bad block "
2417 "at addr 0x%012llx\n",
2418 __func__, (unsigned long long) addr);
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002419 instr->state = MTD_ERASE_FAILED;
Mika Korhonen73885ae2009-10-23 07:50:42 +02002420 return -EIO;
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002421 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002422
2423 this->command(mtd, ONENAND_CMD_ERASE, addr, block_size);
2424
Adrian Hunter480b9df2007-02-07 13:55:19 +02002425 onenand_invalidate_bufferram(mtd, addr, block_size);
2426
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002427 ret = this->wait(mtd, FL_ERASING);
2428 /* Check, if it is write protected */
2429 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302430 printk(KERN_ERR "%s: Failed erase, block %d\n",
2431 __func__, onenand_block(this, addr));
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002432 instr->state = MTD_ERASE_FAILED;
2433 instr->fail_addr = addr;
Mika Korhonen73885ae2009-10-23 07:50:42 +02002434 return -EIO;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002435 }
2436
2437 len -= block_size;
2438 addr += block_size;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002439
john.maxin@nokia.comeff3bba2011-05-06 09:17:21 +00002440 if (region && addr == region_end) {
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002441 if (!len)
2442 break;
2443 region++;
2444
2445 block_size = region->erasesize;
2446 region_end = region->offset + region->erasesize * region->numblocks;
2447
2448 if (len & (block_size - 1)) {
2449 /* FIXME: This should be handled at MTD partitioning level. */
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302450 printk(KERN_ERR "%s: Unaligned address\n",
2451 __func__);
Mika Korhonen73885ae2009-10-23 07:50:42 +02002452 return -EIO;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002453 }
2454 }
Mika Korhonen73885ae2009-10-23 07:50:42 +02002455 }
2456 return 0;
2457}
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002458
Mika Korhonen73885ae2009-10-23 07:50:42 +02002459/**
2460 * onenand_erase - [MTD Interface] erase block(s)
2461 * @param mtd MTD device structure
2462 * @param instr erase instruction
2463 *
2464 * Erase one or more blocks
2465 */
2466static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
2467{
2468 struct onenand_chip *this = mtd->priv;
2469 unsigned int block_size;
2470 loff_t addr = instr->addr;
2471 loff_t len = instr->len;
2472 int ret = 0;
2473 struct mtd_erase_region_info *region = NULL;
2474 loff_t region_offset = 0;
2475
Brian Norris289c0522011-07-19 10:06:09 -07002476 pr_debug("%s: start=0x%012llx, len=%llu\n", __func__,
Brian Norris0a32a102011-07-19 10:06:10 -07002477 (unsigned long long)instr->addr,
2478 (unsigned long long)instr->len);
Mika Korhonen73885ae2009-10-23 07:50:42 +02002479
Mika Korhonen73885ae2009-10-23 07:50:42 +02002480 if (FLEXONENAND(this)) {
2481 /* Find the eraseregion of this address */
2482 int i = flexonenand_region(mtd, addr);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002483
Mika Korhonen73885ae2009-10-23 07:50:42 +02002484 region = &mtd->eraseregions[i];
2485 block_size = region->erasesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002486
Mika Korhonen73885ae2009-10-23 07:50:42 +02002487 /* Start address within region must align on block boundary.
2488 * Erase region's start offset is always block start address.
2489 */
2490 region_offset = region->offset;
2491 } else
2492 block_size = 1 << this->erase_shift;
2493
2494 /* Start address must align on block boundary */
2495 if (unlikely((addr - region_offset) & (block_size - 1))) {
2496 printk(KERN_ERR "%s: Unaligned address\n", __func__);
2497 return -EINVAL;
2498 }
2499
2500 /* Length must align on block boundary */
2501 if (unlikely(len & (block_size - 1))) {
2502 printk(KERN_ERR "%s: Length not block aligned\n", __func__);
2503 return -EINVAL;
2504 }
2505
Mika Korhonen73885ae2009-10-23 07:50:42 +02002506 /* Grab the lock and see if the device is available */
2507 onenand_get_device(mtd, FL_ERASING);
2508
Kyungmin Parkd983c542010-12-06 09:05:18 +09002509 if (ONENAND_IS_4KB_PAGE(this) || region ||
2510 instr->len < MB_ERASE_MIN_BLK_COUNT * block_size) {
Mika Korhonen72073022009-10-23 07:50:43 +02002511 /* region is set for Flex-OneNAND (no mb erase) */
2512 ret = onenand_block_by_block_erase(mtd, instr,
2513 region, block_size);
2514 } else {
2515 ret = onenand_multiblock_erase(mtd, instr, block_size);
2516 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002517
2518 /* Deselect and wake up anyone waiting on the device */
2519 onenand_release_device(mtd);
2520
Adrian Hunter3cd3a862007-10-12 10:34:01 +03002521 /* Do call back function */
Mika Korhonen73885ae2009-10-23 07:50:42 +02002522 if (!ret) {
2523 instr->state = MTD_ERASE_DONE;
Adrian Hunter3cd3a862007-10-12 10:34:01 +03002524 mtd_erase_callback(instr);
Mika Korhonen73885ae2009-10-23 07:50:42 +02002525 }
Adrian Hunter3cd3a862007-10-12 10:34:01 +03002526
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002527 return ret;
2528}
2529
2530/**
2531 * onenand_sync - [MTD Interface] sync
2532 * @param mtd MTD device structure
2533 *
2534 * Sync is actually a wait for chip ready function
2535 */
2536static void onenand_sync(struct mtd_info *mtd)
2537{
Brian Norris289c0522011-07-19 10:06:09 -07002538 pr_debug("%s: called\n", __func__);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002539
2540 /* Grab the lock and see if the device is available */
2541 onenand_get_device(mtd, FL_SYNCING);
2542
2543 /* Release it and go back */
2544 onenand_release_device(mtd);
2545}
2546
2547/**
2548 * onenand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad
2549 * @param mtd MTD device structure
2550 * @param ofs offset relative to mtd start
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002551 *
2552 * Check whether the block is bad
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002553 */
2554static int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs)
2555{
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002556 int ret;
2557
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002558 onenand_get_device(mtd, FL_READING);
2559 ret = onenand_block_isbad_nolock(mtd, ofs, 0);
2560 onenand_release_device(mtd);
2561 return ret;
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002562}
2563
2564/**
2565 * onenand_default_block_markbad - [DEFAULT] mark a block bad
2566 * @param mtd MTD device structure
2567 * @param ofs offset from device start
2568 *
2569 * This is the default implementation, which can be overridden by
2570 * a hardware specific driver.
2571 */
2572static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
2573{
2574 struct onenand_chip *this = mtd->priv;
2575 struct bbm_info *bbm = this->bbm;
2576 u_char buf[2] = {0, 0};
Kyungmin Park12f77c92007-08-30 09:36:05 +09002577 struct mtd_oob_ops ops = {
Brian Norris0612b9d2011-08-30 18:45:40 -07002578 .mode = MTD_OPS_PLACE_OOB,
Kyungmin Park12f77c92007-08-30 09:36:05 +09002579 .ooblen = 2,
2580 .oobbuf = buf,
2581 .ooboffs = 0,
2582 };
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002583 int block;
2584
2585 /* Get block number */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002586 block = onenand_block(this, ofs);
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002587 if (bbm->bbt)
2588 bbm->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
2589
Mika Korhonen492e1502009-06-09 21:52:35 +03002590 /* We write two bytes, so we don't have to mess with 16-bit access */
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002591 ofs += mtd->oobsize + (bbm->badblockpos & ~0x01);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002592 /* FIXME : What to do when marking SLC block in partition
2593 * with MLC erasesize? For now, it is not advisable to
2594 * create partitions containing both SLC and MLC regions.
2595 */
2596 return onenand_write_oob_nolock(mtd, ofs, &ops);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002597}
2598
2599/**
2600 * onenand_block_markbad - [MTD Interface] Mark the block at the given offset as bad
2601 * @param mtd MTD device structure
2602 * @param ofs offset relative to mtd start
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002603 *
2604 * Mark the block as bad
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002605 */
2606static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
2607{
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002608 int ret;
2609
2610 ret = onenand_block_isbad(mtd, ofs);
2611 if (ret) {
2612 /* If it was bad already, return success and do nothing */
2613 if (ret > 0)
2614 return 0;
2615 return ret;
2616 }
2617
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002618 onenand_get_device(mtd, FL_WRITING);
Artem Bityutskiy5942ddb2011-12-23 19:37:38 +02002619 ret = mtd_block_markbad(mtd, ofs);
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002620 onenand_release_device(mtd);
2621 return ret;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002622}
2623
2624/**
Kyungmin Park08f782b2006-11-16 11:29:39 +09002625 * onenand_do_lock_cmd - [OneNAND Interface] Lock or unlock block(s)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002626 * @param mtd MTD device structure
2627 * @param ofs offset relative to mtd start
Kyungmin Park08f782b2006-11-16 11:29:39 +09002628 * @param len number of bytes to lock or unlock
Kyungmin Parke3da8062007-02-15 09:36:39 +09002629 * @param cmd lock or unlock command
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002630 *
Kyungmin Park08f782b2006-11-16 11:29:39 +09002631 * Lock or unlock one or more blocks
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002632 */
Kyungmin Park08f782b2006-11-16 11:29:39 +09002633static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int cmd)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002634{
2635 struct onenand_chip *this = mtd->priv;
2636 int start, end, block, value, status;
Kyungmin Park08f782b2006-11-16 11:29:39 +09002637 int wp_status_mask;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002638
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002639 start = onenand_block(this, ofs);
2640 end = onenand_block(this, ofs + len) - 1;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002641
Kyungmin Park08f782b2006-11-16 11:29:39 +09002642 if (cmd == ONENAND_CMD_LOCK)
2643 wp_status_mask = ONENAND_WP_LS;
2644 else
2645 wp_status_mask = ONENAND_WP_US;
2646
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002647 /* Continuous lock scheme */
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002648 if (this->options & ONENAND_HAS_CONT_LOCK) {
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002649 /* Set start block address */
2650 this->write_word(start, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
2651 /* Set end block address */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002652 this->write_word(end, this->base + ONENAND_REG_END_BLOCK_ADDRESS);
Kyungmin Park08f782b2006-11-16 11:29:39 +09002653 /* Write lock command */
2654 this->command(mtd, cmd, 0, 0);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002655
2656 /* There's no return value */
Kyungmin Park08f782b2006-11-16 11:29:39 +09002657 this->wait(mtd, FL_LOCKING);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002658
2659 /* Sanity check */
2660 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
2661 & ONENAND_CTRL_ONGO)
2662 continue;
2663
2664 /* Check lock status */
2665 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
Kyungmin Park08f782b2006-11-16 11:29:39 +09002666 if (!(status & wp_status_mask))
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302667 printk(KERN_ERR "%s: wp status = 0x%x\n",
2668 __func__, status);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002669
2670 return 0;
2671 }
2672
2673 /* Block lock scheme */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002674 for (block = start; block < end + 1; block++) {
Kyungmin Park20ba89a2005-12-16 11:17:29 +09002675 /* Set block address */
2676 value = onenand_block_address(this, block);
2677 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
2678 /* Select DataRAM for DDP */
2679 value = onenand_bufferram_address(this, block);
2680 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002681 /* Set start block address */
2682 this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
Kyungmin Park08f782b2006-11-16 11:29:39 +09002683 /* Write lock command */
2684 this->command(mtd, cmd, 0, 0);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002685
2686 /* There's no return value */
Kyungmin Park08f782b2006-11-16 11:29:39 +09002687 this->wait(mtd, FL_LOCKING);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002688
2689 /* Sanity check */
2690 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
2691 & ONENAND_CTRL_ONGO)
2692 continue;
2693
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002694 /* Check lock status */
2695 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
Kyungmin Park08f782b2006-11-16 11:29:39 +09002696 if (!(status & wp_status_mask))
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302697 printk(KERN_ERR "%s: block = %d, wp status = 0x%x\n",
2698 __func__, block, status);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002699 }
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +00002700
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002701 return 0;
2702}
2703
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002704/**
Kyungmin Park08f782b2006-11-16 11:29:39 +09002705 * onenand_lock - [MTD Interface] Lock block(s)
2706 * @param mtd MTD device structure
2707 * @param ofs offset relative to mtd start
2708 * @param len number of bytes to unlock
2709 *
2710 * Lock one or more blocks
2711 */
Adrian Hunter69423d92008-12-10 13:37:21 +00002712static int onenand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
Kyungmin Park08f782b2006-11-16 11:29:39 +09002713{
Adrian Hunter34627f02007-10-12 10:19:26 +03002714 int ret;
2715
2716 onenand_get_device(mtd, FL_LOCKING);
2717 ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK);
2718 onenand_release_device(mtd);
2719 return ret;
Kyungmin Park08f782b2006-11-16 11:29:39 +09002720}
2721
Kyungmin Park08f782b2006-11-16 11:29:39 +09002722/**
2723 * onenand_unlock - [MTD Interface] Unlock block(s)
2724 * @param mtd MTD device structure
2725 * @param ofs offset relative to mtd start
2726 * @param len number of bytes to unlock
2727 *
2728 * Unlock one or more blocks
2729 */
Adrian Hunter69423d92008-12-10 13:37:21 +00002730static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
Kyungmin Park08f782b2006-11-16 11:29:39 +09002731{
Adrian Hunter34627f02007-10-12 10:19:26 +03002732 int ret;
2733
2734 onenand_get_device(mtd, FL_LOCKING);
2735 ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
2736 onenand_release_device(mtd);
2737 return ret;
Kyungmin Park08f782b2006-11-16 11:29:39 +09002738}
2739
2740/**
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002741 * onenand_check_lock_status - [OneNAND Interface] Check lock status
2742 * @param this onenand chip data structure
2743 *
2744 * Check lock status
2745 */
Kyungmin Park66a10502008-02-13 15:55:38 +09002746static int onenand_check_lock_status(struct onenand_chip *this)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002747{
2748 unsigned int value, block, status;
2749 unsigned int end;
2750
2751 end = this->chipsize >> this->erase_shift;
2752 for (block = 0; block < end; block++) {
2753 /* Set block address */
2754 value = onenand_block_address(this, block);
2755 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
2756 /* Select DataRAM for DDP */
2757 value = onenand_bufferram_address(this, block);
2758 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
2759 /* Set start block address */
2760 this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
2761
2762 /* Check lock status */
2763 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
Kyungmin Park66a10502008-02-13 15:55:38 +09002764 if (!(status & ONENAND_WP_US)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302765 printk(KERN_ERR "%s: block = %d, wp status = 0x%x\n",
2766 __func__, block, status);
Kyungmin Park66a10502008-02-13 15:55:38 +09002767 return 0;
2768 }
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002769 }
Kyungmin Park66a10502008-02-13 15:55:38 +09002770
2771 return 1;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002772}
2773
2774/**
2775 * onenand_unlock_all - [OneNAND Interface] unlock all blocks
2776 * @param mtd MTD device structure
2777 *
2778 * Unlock all blocks
2779 */
Kyungmin Park66a10502008-02-13 15:55:38 +09002780static void onenand_unlock_all(struct mtd_info *mtd)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002781{
2782 struct onenand_chip *this = mtd->priv;
Kyungmin Park66a10502008-02-13 15:55:38 +09002783 loff_t ofs = 0;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002784 loff_t len = mtd->size;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002785
2786 if (this->options & ONENAND_HAS_UNLOCK_ALL) {
Kyungmin Park10b7a2b2007-01-12 05:45:34 +09002787 /* Set start block address */
2788 this->write_word(0, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002789 /* Write unlock command */
2790 this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0);
2791
2792 /* There's no return value */
Kyungmin Park08f782b2006-11-16 11:29:39 +09002793 this->wait(mtd, FL_LOCKING);
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002794
2795 /* Sanity check */
2796 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
2797 & ONENAND_CTRL_ONGO)
2798 continue;
2799
Kyungmin Park31bb9992009-05-12 13:46:57 -07002800 /* Don't check lock status */
2801 if (this->options & ONENAND_SKIP_UNLOCK_CHECK)
2802 return;
2803
Kyungmin Park66a10502008-02-13 15:55:38 +09002804 /* Check lock status */
2805 if (onenand_check_lock_status(this))
2806 return;
2807
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002808 /* Workaround for all block unlock in DDP */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002809 if (ONENAND_IS_DDP(this) && !FLEXONENAND(this)) {
Kyungmin Park66a10502008-02-13 15:55:38 +09002810 /* All blocks on another chip */
2811 ofs = this->chipsize >> 1;
2812 len = this->chipsize >> 1;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002813 }
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002814 }
2815
Kyungmin Park66a10502008-02-13 15:55:38 +09002816 onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002817}
2818
Kyungmin Park493c6462006-05-12 17:03:07 +03002819#ifdef CONFIG_MTD_ONENAND_OTP
2820
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05302821/**
2822 * onenand_otp_command - Send OTP specific command to OneNAND device
2823 * @param mtd MTD device structure
2824 * @param cmd the command to be sent
2825 * @param addr offset to read from or write to
2826 * @param len number of bytes to read or write
2827 */
2828static int onenand_otp_command(struct mtd_info *mtd, int cmd, loff_t addr,
2829 size_t len)
2830{
2831 struct onenand_chip *this = mtd->priv;
2832 int value, block, page;
2833
2834 /* Address translation */
2835 switch (cmd) {
2836 case ONENAND_CMD_OTP_ACCESS:
2837 block = (int) (addr >> this->erase_shift);
2838 page = -1;
2839 break;
2840
2841 default:
2842 block = (int) (addr >> this->erase_shift);
2843 page = (int) (addr >> this->page_shift);
2844
2845 if (ONENAND_IS_2PLANE(this)) {
2846 /* Make the even block number */
2847 block &= ~1;
2848 /* Is it the odd plane? */
2849 if (addr & this->writesize)
2850 block++;
2851 page >>= 1;
2852 }
2853 page &= this->page_mask;
2854 break;
2855 }
2856
2857 if (block != -1) {
2858 /* Write 'DFS, FBA' of Flash */
2859 value = onenand_block_address(this, block);
2860 this->write_word(value, this->base +
2861 ONENAND_REG_START_ADDRESS1);
2862 }
2863
2864 if (page != -1) {
2865 /* Now we use page size operation */
2866 int sectors = 4, count = 4;
2867 int dataram;
2868
2869 switch (cmd) {
2870 default:
2871 if (ONENAND_IS_2PLANE(this) && cmd == ONENAND_CMD_PROG)
2872 cmd = ONENAND_CMD_2X_PROG;
2873 dataram = ONENAND_CURRENT_BUFFERRAM(this);
2874 break;
2875 }
2876
2877 /* Write 'FPA, FSA' of Flash */
2878 value = onenand_page_address(page, sectors);
2879 this->write_word(value, this->base +
2880 ONENAND_REG_START_ADDRESS8);
2881
2882 /* Write 'BSA, BSC' of DataRAM */
2883 value = onenand_buffer_address(dataram, sectors, count);
2884 this->write_word(value, this->base + ONENAND_REG_START_BUFFER);
2885 }
2886
2887 /* Interrupt clear */
2888 this->write_word(ONENAND_INT_CLEAR, this->base + ONENAND_REG_INTERRUPT);
2889
2890 /* Write command */
2891 this->write_word(cmd, this->base + ONENAND_REG_COMMAND);
2892
2893 return 0;
2894}
2895
2896/**
Brian Norris7854d3f2011-06-23 14:12:08 -07002897 * onenand_otp_write_oob_nolock - [INTERN] OneNAND write out-of-band, specific to OTP
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05302898 * @param mtd MTD device structure
2899 * @param to offset to write to
2900 * @param len number of bytes to write
2901 * @param retlen pointer to variable to store the number of written bytes
2902 * @param buf the data to write
2903 *
2904 * OneNAND write out-of-band only for OTP
2905 */
2906static int onenand_otp_write_oob_nolock(struct mtd_info *mtd, loff_t to,
2907 struct mtd_oob_ops *ops)
2908{
2909 struct onenand_chip *this = mtd->priv;
2910 int column, ret = 0, oobsize;
2911 int written = 0;
2912 u_char *oobbuf;
2913 size_t len = ops->ooblen;
2914 const u_char *buf = ops->oobbuf;
2915 int block, value, status;
2916
2917 to += ops->ooboffs;
2918
2919 /* Initialize retlen, in case of early exit */
2920 ops->oobretlen = 0;
2921
2922 oobsize = mtd->oobsize;
2923
2924 column = to & (mtd->oobsize - 1);
2925
2926 oobbuf = this->oob_buf;
2927
2928 /* Loop until all data write */
2929 while (written < len) {
2930 int thislen = min_t(int, oobsize, len - written);
2931
2932 cond_resched();
2933
2934 block = (int) (to >> this->erase_shift);
2935 /*
2936 * Write 'DFS, FBA' of Flash
2937 * Add: F100h DQ=DFS, FBA
2938 */
2939
2940 value = onenand_block_address(this, block);
2941 this->write_word(value, this->base +
2942 ONENAND_REG_START_ADDRESS1);
2943
2944 /*
2945 * Select DataRAM for DDP
2946 * Add: F101h DQ=DBS
2947 */
2948
2949 value = onenand_bufferram_address(this, block);
2950 this->write_word(value, this->base +
2951 ONENAND_REG_START_ADDRESS2);
2952 ONENAND_SET_NEXT_BUFFERRAM(this);
2953
2954 /*
2955 * Enter OTP access mode
2956 */
2957 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
2958 this->wait(mtd, FL_OTPING);
2959
2960 /* We send data to spare ram with oobsize
2961 * to prevent byte access */
2962 memcpy(oobbuf + column, buf, thislen);
2963
2964 /*
2965 * Write Data into DataRAM
2966 * Add: 8th Word
2967 * in sector0/spare/page0
2968 * DQ=XXFCh
2969 */
2970 this->write_bufferram(mtd, ONENAND_SPARERAM,
2971 oobbuf, 0, mtd->oobsize);
2972
2973 onenand_otp_command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize);
2974 onenand_update_bufferram(mtd, to, 0);
2975 if (ONENAND_IS_2PLANE(this)) {
2976 ONENAND_SET_BUFFERRAM1(this);
2977 onenand_update_bufferram(mtd, to + this->writesize, 0);
2978 }
2979
2980 ret = this->wait(mtd, FL_WRITING);
2981 if (ret) {
2982 printk(KERN_ERR "%s: write failed %d\n", __func__, ret);
2983 break;
2984 }
2985
2986 /* Exit OTP access mode */
2987 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
2988 this->wait(mtd, FL_RESETING);
2989
2990 status = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
2991 status &= 0x60;
2992
2993 if (status == 0x60) {
2994 printk(KERN_DEBUG "\nBLOCK\tSTATUS\n");
2995 printk(KERN_DEBUG "1st Block\tLOCKED\n");
2996 printk(KERN_DEBUG "OTP Block\tLOCKED\n");
2997 } else if (status == 0x20) {
2998 printk(KERN_DEBUG "\nBLOCK\tSTATUS\n");
2999 printk(KERN_DEBUG "1st Block\tLOCKED\n");
3000 printk(KERN_DEBUG "OTP Block\tUN-LOCKED\n");
3001 } else if (status == 0x40) {
3002 printk(KERN_DEBUG "\nBLOCK\tSTATUS\n");
3003 printk(KERN_DEBUG "1st Block\tUN-LOCKED\n");
3004 printk(KERN_DEBUG "OTP Block\tLOCKED\n");
3005 } else {
3006 printk(KERN_DEBUG "Reboot to check\n");
3007 }
3008
3009 written += thislen;
3010 if (written == len)
3011 break;
3012
3013 to += mtd->writesize;
3014 buf += thislen;
3015 column = 0;
3016 }
3017
3018 ops->oobretlen = written;
3019
3020 return ret;
3021}
3022
Mika Korhonen492e1502009-06-09 21:52:35 +03003023/* Internal OTP operation */
Kyungmin Park493c6462006-05-12 17:03:07 +03003024typedef int (*otp_op_t)(struct mtd_info *mtd, loff_t form, size_t len,
3025 size_t *retlen, u_char *buf);
3026
3027/**
3028 * do_otp_read - [DEFAULT] Read OTP block area
3029 * @param mtd MTD device structure
3030 * @param from The offset to read
3031 * @param len number of bytes to read
3032 * @param retlen pointer to variable to store the number of readbytes
3033 * @param buf the databuffer to put/get data
3034 *
3035 * Read OTP block area.
3036 */
3037static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len,
3038 size_t *retlen, u_char *buf)
3039{
3040 struct onenand_chip *this = mtd->priv;
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003041 struct mtd_oob_ops ops = {
3042 .len = len,
3043 .ooblen = 0,
3044 .datbuf = buf,
3045 .oobbuf = NULL,
3046 };
Kyungmin Park493c6462006-05-12 17:03:07 +03003047 int ret;
3048
3049 /* Enter OTP access mode */
3050 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
3051 this->wait(mtd, FL_OTPING);
3052
Kyungmin Park8a8f6322010-12-02 09:24:16 +09003053 ret = ONENAND_IS_4KB_PAGE(this) ?
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003054 onenand_mlc_read_ops_nolock(mtd, from, &ops) :
3055 onenand_read_ops_nolock(mtd, from, &ops);
Kyungmin Park493c6462006-05-12 17:03:07 +03003056
3057 /* Exit OTP access mode */
3058 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
3059 this->wait(mtd, FL_RESETING);
3060
3061 return ret;
3062}
3063
3064/**
3065 * do_otp_write - [DEFAULT] Write OTP block area
3066 * @param mtd MTD device structure
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003067 * @param to The offset to write
Kyungmin Park493c6462006-05-12 17:03:07 +03003068 * @param len number of bytes to write
3069 * @param retlen pointer to variable to store the number of write bytes
3070 * @param buf the databuffer to put/get data
3071 *
3072 * Write OTP block area.
3073 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003074static int do_otp_write(struct mtd_info *mtd, loff_t to, size_t len,
Kyungmin Park493c6462006-05-12 17:03:07 +03003075 size_t *retlen, u_char *buf)
3076{
3077 struct onenand_chip *this = mtd->priv;
3078 unsigned char *pbuf = buf;
3079 int ret;
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003080 struct mtd_oob_ops ops;
Kyungmin Park493c6462006-05-12 17:03:07 +03003081
3082 /* Force buffer page aligned */
Joern Engel28318772006-05-22 23:18:05 +02003083 if (len < mtd->writesize) {
Kyungmin Park493c6462006-05-12 17:03:07 +03003084 memcpy(this->page_buf, buf, len);
Joern Engel28318772006-05-22 23:18:05 +02003085 memset(this->page_buf + len, 0xff, mtd->writesize - len);
Kyungmin Park493c6462006-05-12 17:03:07 +03003086 pbuf = this->page_buf;
Joern Engel28318772006-05-22 23:18:05 +02003087 len = mtd->writesize;
Kyungmin Park493c6462006-05-12 17:03:07 +03003088 }
3089
3090 /* Enter OTP access mode */
3091 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
3092 this->wait(mtd, FL_OTPING);
3093
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003094 ops.len = len;
3095 ops.ooblen = 0;
Kyungmin Park14370852007-10-10 13:48:14 +09003096 ops.datbuf = pbuf;
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003097 ops.oobbuf = NULL;
3098 ret = onenand_write_ops_nolock(mtd, to, &ops);
3099 *retlen = ops.retlen;
Kyungmin Park493c6462006-05-12 17:03:07 +03003100
3101 /* Exit OTP access mode */
3102 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
3103 this->wait(mtd, FL_RESETING);
3104
3105 return ret;
3106}
3107
3108/**
3109 * do_otp_lock - [DEFAULT] Lock OTP block area
3110 * @param mtd MTD device structure
3111 * @param from The offset to lock
3112 * @param len number of bytes to lock
3113 * @param retlen pointer to variable to store the number of lock bytes
3114 * @param buf the databuffer to put/get data
3115 *
3116 * Lock OTP block area.
3117 */
3118static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len,
3119 size_t *retlen, u_char *buf)
3120{
3121 struct onenand_chip *this = mtd->priv;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003122 struct mtd_oob_ops ops;
Kyungmin Park493c6462006-05-12 17:03:07 +03003123 int ret;
3124
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003125 if (FLEXONENAND(this)) {
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303126
3127 /* Enter OTP access mode */
3128 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
3129 this->wait(mtd, FL_OTPING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003130 /*
3131 * For Flex-OneNAND, we write lock mark to 1st word of sector 4 of
3132 * main area of page 49.
3133 */
3134 ops.len = mtd->writesize;
3135 ops.ooblen = 0;
3136 ops.datbuf = buf;
3137 ops.oobbuf = NULL;
3138 ret = onenand_write_ops_nolock(mtd, mtd->writesize * 49, &ops);
3139 *retlen = ops.retlen;
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303140
3141 /* Exit OTP access mode */
3142 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
3143 this->wait(mtd, FL_RESETING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003144 } else {
Brian Norris0612b9d2011-08-30 18:45:40 -07003145 ops.mode = MTD_OPS_PLACE_OOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003146 ops.ooblen = len;
3147 ops.oobbuf = buf;
3148 ops.ooboffs = 0;
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303149 ret = onenand_otp_write_oob_nolock(mtd, from, &ops);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003150 *retlen = ops.oobretlen;
3151 }
Kyungmin Park493c6462006-05-12 17:03:07 +03003152
Kyungmin Park493c6462006-05-12 17:03:07 +03003153 return ret;
3154}
3155
3156/**
3157 * onenand_otp_walk - [DEFAULT] Handle OTP operation
3158 * @param mtd MTD device structure
3159 * @param from The offset to read/write
3160 * @param len number of bytes to read/write
3161 * @param retlen pointer to variable to store the number of read bytes
3162 * @param buf the databuffer to put/get data
3163 * @param action do given action
3164 * @param mode specify user and factory
3165 *
3166 * Handle OTP operation.
3167 */
3168static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
3169 size_t *retlen, u_char *buf,
3170 otp_op_t action, int mode)
3171{
3172 struct onenand_chip *this = mtd->priv;
3173 int otp_pages;
3174 int density;
3175 int ret = 0;
3176
3177 *retlen = 0;
3178
Kyungmin Parke71f04f2007-12-11 11:23:45 +09003179 density = onenand_get_density(this->device_id);
Kyungmin Park493c6462006-05-12 17:03:07 +03003180 if (density < ONENAND_DEVICE_DENSITY_512Mb)
3181 otp_pages = 20;
3182 else
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303183 otp_pages = 50;
Kyungmin Park493c6462006-05-12 17:03:07 +03003184
3185 if (mode == MTD_OTP_FACTORY) {
Joern Engel28318772006-05-22 23:18:05 +02003186 from += mtd->writesize * otp_pages;
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303187 otp_pages = ONENAND_PAGES_PER_BLOCK - otp_pages;
Kyungmin Park493c6462006-05-12 17:03:07 +03003188 }
3189
3190 /* Check User/Factory boundary */
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303191 if (mode == MTD_OTP_USER) {
Roel Kluin0a032a42009-12-16 01:37:17 +01003192 if (mtd->writesize * otp_pages < from + len)
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303193 return 0;
3194 } else {
Roel Kluin0a032a42009-12-16 01:37:17 +01003195 if (mtd->writesize * otp_pages < len)
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303196 return 0;
3197 }
Kyungmin Park493c6462006-05-12 17:03:07 +03003198
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003199 onenand_get_device(mtd, FL_OTPING);
Kyungmin Park493c6462006-05-12 17:03:07 +03003200 while (len > 0 && otp_pages > 0) {
3201 if (!action) { /* OTP Info functions */
3202 struct otp_info *otpinfo;
3203
3204 len -= sizeof(struct otp_info);
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003205 if (len <= 0) {
3206 ret = -ENOSPC;
3207 break;
3208 }
Kyungmin Park493c6462006-05-12 17:03:07 +03003209
3210 otpinfo = (struct otp_info *) buf;
3211 otpinfo->start = from;
Joern Engel28318772006-05-22 23:18:05 +02003212 otpinfo->length = mtd->writesize;
Kyungmin Park493c6462006-05-12 17:03:07 +03003213 otpinfo->locked = 0;
3214
Joern Engel28318772006-05-22 23:18:05 +02003215 from += mtd->writesize;
Kyungmin Park493c6462006-05-12 17:03:07 +03003216 buf += sizeof(struct otp_info);
3217 *retlen += sizeof(struct otp_info);
3218 } else {
3219 size_t tmp_retlen;
Kyungmin Park493c6462006-05-12 17:03:07 +03003220
3221 ret = action(mtd, from, len, &tmp_retlen, buf);
3222
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303223 buf += tmp_retlen;
3224 len -= tmp_retlen;
3225 *retlen += tmp_retlen;
Kyungmin Park493c6462006-05-12 17:03:07 +03003226
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003227 if (ret)
3228 break;
Kyungmin Park493c6462006-05-12 17:03:07 +03003229 }
3230 otp_pages--;
3231 }
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003232 onenand_release_device(mtd);
Kyungmin Park493c6462006-05-12 17:03:07 +03003233
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003234 return ret;
Kyungmin Park493c6462006-05-12 17:03:07 +03003235}
3236
3237/**
3238 * onenand_get_fact_prot_info - [MTD Interface] Read factory OTP info
3239 * @param mtd MTD device structure
Kyungmin Park493c6462006-05-12 17:03:07 +03003240 * @param len number of bytes to read
Christian Riesch4b78fc42014-01-28 09:29:44 +01003241 * @param retlen pointer to variable to store the number of read bytes
3242 * @param buf the databuffer to put/get data
Kyungmin Park493c6462006-05-12 17:03:07 +03003243 *
3244 * Read factory OTP info.
3245 */
Christian Riesch4b78fc42014-01-28 09:29:44 +01003246static int onenand_get_fact_prot_info(struct mtd_info *mtd, size_t len,
3247 size_t *retlen, struct otp_info *buf)
Kyungmin Park493c6462006-05-12 17:03:07 +03003248{
Christian Riesch4b78fc42014-01-28 09:29:44 +01003249 return onenand_otp_walk(mtd, 0, len, retlen, (u_char *) buf, NULL,
3250 MTD_OTP_FACTORY);
Kyungmin Park493c6462006-05-12 17:03:07 +03003251}
3252
3253/**
3254 * onenand_read_fact_prot_reg - [MTD Interface] Read factory OTP area
3255 * @param mtd MTD device structure
3256 * @param from The offset to read
3257 * @param len number of bytes to read
3258 * @param retlen pointer to variable to store the number of read bytes
3259 * @param buf the databuffer to put/get data
3260 *
3261 * Read factory OTP area.
3262 */
3263static int onenand_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
3264 size_t len, size_t *retlen, u_char *buf)
3265{
3266 return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_read, MTD_OTP_FACTORY);
3267}
3268
3269/**
3270 * onenand_get_user_prot_info - [MTD Interface] Read user OTP info
3271 * @param mtd MTD device structure
Christian Riesch4b78fc42014-01-28 09:29:44 +01003272 * @param retlen pointer to variable to store the number of read bytes
Kyungmin Park493c6462006-05-12 17:03:07 +03003273 * @param len number of bytes to read
Christian Riesch4b78fc42014-01-28 09:29:44 +01003274 * @param buf the databuffer to put/get data
Kyungmin Park493c6462006-05-12 17:03:07 +03003275 *
3276 * Read user OTP info.
3277 */
Christian Riesch4b78fc42014-01-28 09:29:44 +01003278static int onenand_get_user_prot_info(struct mtd_info *mtd, size_t len,
3279 size_t *retlen, struct otp_info *buf)
Kyungmin Park493c6462006-05-12 17:03:07 +03003280{
Christian Riesch4b78fc42014-01-28 09:29:44 +01003281 return onenand_otp_walk(mtd, 0, len, retlen, (u_char *) buf, NULL,
3282 MTD_OTP_USER);
Kyungmin Park493c6462006-05-12 17:03:07 +03003283}
3284
3285/**
3286 * onenand_read_user_prot_reg - [MTD Interface] Read user OTP area
3287 * @param mtd MTD device structure
3288 * @param from The offset to read
3289 * @param len number of bytes to read
3290 * @param retlen pointer to variable to store the number of read bytes
3291 * @param buf the databuffer to put/get data
3292 *
3293 * Read user OTP area.
3294 */
3295static int onenand_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
3296 size_t len, size_t *retlen, u_char *buf)
3297{
3298 return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_read, MTD_OTP_USER);
3299}
3300
3301/**
3302 * onenand_write_user_prot_reg - [MTD Interface] Write user OTP area
3303 * @param mtd MTD device structure
3304 * @param from The offset to write
3305 * @param len number of bytes to write
3306 * @param retlen pointer to variable to store the number of write bytes
3307 * @param buf the databuffer to put/get data
3308 *
3309 * Write user OTP area.
3310 */
3311static int onenand_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
3312 size_t len, size_t *retlen, u_char *buf)
3313{
3314 return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_write, MTD_OTP_USER);
3315}
3316
3317/**
3318 * onenand_lock_user_prot_reg - [MTD Interface] Lock user OTP area
3319 * @param mtd MTD device structure
3320 * @param from The offset to lock
3321 * @param len number of bytes to unlock
3322 *
3323 * Write lock mark on spare area in page 0 in OTP block
3324 */
3325static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
3326 size_t len)
3327{
Kyungmin Park69d79182007-12-14 14:47:21 +09003328 struct onenand_chip *this = mtd->priv;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003329 u_char *buf = FLEXONENAND(this) ? this->page_buf : this->oob_buf;
Kyungmin Park493c6462006-05-12 17:03:07 +03003330 size_t retlen;
3331 int ret;
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303332 unsigned int otp_lock_offset = ONENAND_OTP_LOCK_OFFSET;
Kyungmin Park493c6462006-05-12 17:03:07 +03003333
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003334 memset(buf, 0xff, FLEXONENAND(this) ? this->writesize
3335 : mtd->oobsize);
Kyungmin Park493c6462006-05-12 17:03:07 +03003336 /*
Kyungmin Park493c6462006-05-12 17:03:07 +03003337 * Write lock mark to 8th word of sector0 of page0 of the spare0.
3338 * We write 16 bytes spare area instead of 2 bytes.
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003339 * For Flex-OneNAND, we write lock mark to 1st word of sector 4 of
3340 * main area of page 49.
Kyungmin Park493c6462006-05-12 17:03:07 +03003341 */
Kyungmin Park493c6462006-05-12 17:03:07 +03003342
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003343 from = 0;
3344 len = FLEXONENAND(this) ? mtd->writesize : 16;
3345
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303346 /*
3347 * Note: OTP lock operation
3348 * OTP block : 0xXXFC XX 1111 1100
3349 * 1st block : 0xXXF3 (If chip support) XX 1111 0011
3350 * Both : 0xXXF0 (If chip support) XX 1111 0000
3351 */
3352 if (FLEXONENAND(this))
3353 otp_lock_offset = FLEXONENAND_OTP_LOCK_OFFSET;
3354
3355 /* ONENAND_OTP_AREA | ONENAND_OTP_BLOCK0 | ONENAND_OTP_AREA_BLOCK0 */
3356 if (otp == 1)
3357 buf[otp_lock_offset] = 0xFC;
3358 else if (otp == 2)
3359 buf[otp_lock_offset] = 0xF3;
3360 else if (otp == 3)
3361 buf[otp_lock_offset] = 0xF0;
3362 else if (otp != 0)
3363 printk(KERN_DEBUG "[OneNAND] Invalid option selected for OTP\n");
3364
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003365 ret = onenand_otp_walk(mtd, from, len, &retlen, buf, do_otp_lock, MTD_OTP_USER);
Kyungmin Park493c6462006-05-12 17:03:07 +03003366
3367 return ret ? : retlen;
3368}
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303369
Kyungmin Park493c6462006-05-12 17:03:07 +03003370#endif /* CONFIG_MTD_ONENAND_OTP */
3371
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003372/**
Kyungmin Park75384b02007-01-18 11:10:57 +09003373 * onenand_check_features - Check and set OneNAND features
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003374 * @param mtd MTD data structure
3375 *
Kyungmin Park75384b02007-01-18 11:10:57 +09003376 * Check and set OneNAND features
3377 * - lock scheme
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003378 * - two plane
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003379 */
Kyungmin Park75384b02007-01-18 11:10:57 +09003380static void onenand_check_features(struct mtd_info *mtd)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003381{
3382 struct onenand_chip *this = mtd->priv;
Roman Tereshonkovedb44b92010-10-11 14:47:32 +03003383 unsigned int density, process, numbufs;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003384
3385 /* Lock scheme depends on density and process */
Kyungmin Parke71f04f2007-12-11 11:23:45 +09003386 density = onenand_get_density(this->device_id);
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003387 process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT;
Roman Tereshonkovedb44b92010-10-11 14:47:32 +03003388 numbufs = this->read_word(this->base + ONENAND_REG_NUM_BUFFERS) >> 8;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003389
3390 /* Lock scheme */
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003391 switch (density) {
3392 case ONENAND_DEVICE_DENSITY_4Gb:
Kyungmin Park6a88c472010-04-28 17:46:45 +02003393 if (ONENAND_IS_DDP(this))
3394 this->options |= ONENAND_HAS_2PLANE;
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02003395 else if (numbufs == 1) {
Kyungmin Park6a88c472010-04-28 17:46:45 +02003396 this->options |= ONENAND_HAS_4KB_PAGE;
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02003397 this->options |= ONENAND_HAS_CACHE_PROGRAM;
Kyungmin Parke1c10242011-06-22 14:16:49 +09003398 /*
3399 * There are two different 4KiB pagesize chips
3400 * and no way to detect it by H/W config values.
3401 *
3402 * To detect the correct NOP for each chips,
3403 * It should check the version ID as workaround.
3404 *
3405 * Now it has as following
3406 * KFM4G16Q4M has NOP 4 with version ID 0x0131
3407 * KFM4G16Q5M has NOP 1 with versoin ID 0x013e
3408 */
3409 if ((this->version_id & 0xf) == 0xe)
3410 this->options |= ONENAND_HAS_NOP_1;
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02003411 }
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003412
3413 case ONENAND_DEVICE_DENSITY_2Gb:
Mika Korhonen492e1502009-06-09 21:52:35 +03003414 /* 2Gb DDP does not have 2 plane */
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003415 if (!ONENAND_IS_DDP(this))
3416 this->options |= ONENAND_HAS_2PLANE;
3417 this->options |= ONENAND_HAS_UNLOCK_ALL;
3418
3419 case ONENAND_DEVICE_DENSITY_1Gb:
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003420 /* A-Die has all block unlock */
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003421 if (process)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003422 this->options |= ONENAND_HAS_UNLOCK_ALL;
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003423 break;
3424
3425 default:
3426 /* Some OneNAND has continuous lock scheme */
3427 if (!process)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003428 this->options |= ONENAND_HAS_CONT_LOCK;
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003429 break;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003430 }
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003431
Kyungmin Park8a8f6322010-12-02 09:24:16 +09003432 /* The MLC has 4KiB pagesize. */
3433 if (ONENAND_IS_MLC(this))
3434 this->options |= ONENAND_HAS_4KB_PAGE;
3435
3436 if (ONENAND_IS_4KB_PAGE(this))
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003437 this->options &= ~ONENAND_HAS_2PLANE;
3438
3439 if (FLEXONENAND(this)) {
3440 this->options &= ~ONENAND_HAS_CONT_LOCK;
3441 this->options |= ONENAND_HAS_UNLOCK_ALL;
3442 }
3443
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003444 if (this->options & ONENAND_HAS_CONT_LOCK)
3445 printk(KERN_DEBUG "Lock scheme is Continuous Lock\n");
3446 if (this->options & ONENAND_HAS_UNLOCK_ALL)
3447 printk(KERN_DEBUG "Chip support all block unlock\n");
3448 if (this->options & ONENAND_HAS_2PLANE)
3449 printk(KERN_DEBUG "Chip has 2 plane\n");
Kyungmin Park6a88c472010-04-28 17:46:45 +02003450 if (this->options & ONENAND_HAS_4KB_PAGE)
3451 printk(KERN_DEBUG "Chip has 4KiB pagesize\n");
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02003452 if (this->options & ONENAND_HAS_CACHE_PROGRAM)
3453 printk(KERN_DEBUG "Chip has cache program feature\n");
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003454}
3455
3456/**
Kyungmin Parke3da8062007-02-15 09:36:39 +09003457 * onenand_print_device_info - Print device & version ID
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003458 * @param device device ID
Kyungmin Parke3da8062007-02-15 09:36:39 +09003459 * @param version version ID
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003460 *
Kyungmin Parke3da8062007-02-15 09:36:39 +09003461 * Print device & version ID
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003462 */
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003463static void onenand_print_device_info(int device, int version)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003464{
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003465 int vcc, demuxed, ddp, density, flexonenand;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003466
3467 vcc = device & ONENAND_DEVICE_VCC_MASK;
3468 demuxed = device & ONENAND_DEVICE_IS_DEMUX;
3469 ddp = device & ONENAND_DEVICE_IS_DDP;
Kyungmin Parke71f04f2007-12-11 11:23:45 +09003470 density = onenand_get_density(device);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003471 flexonenand = device & DEVICE_IS_FLEXONENAND;
3472 printk(KERN_INFO "%s%sOneNAND%s %dMB %sV 16-bit (0x%02x)\n",
3473 demuxed ? "" : "Muxed ",
3474 flexonenand ? "Flex-" : "",
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003475 ddp ? "(DDP)" : "",
3476 (16 << density),
3477 vcc ? "2.65/3.3" : "1.8",
3478 device);
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003479 printk(KERN_INFO "OneNAND version = 0x%04x\n", version);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003480}
3481
3482static const struct onenand_manufacturers onenand_manuf_ids[] = {
3483 {ONENAND_MFR_SAMSUNG, "Samsung"},
Adrian Hunteree8f3762009-05-05 11:04:19 +03003484 {ONENAND_MFR_NUMONYX, "Numonyx"},
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003485};
3486
3487/**
3488 * onenand_check_maf - Check manufacturer ID
3489 * @param manuf manufacturer ID
3490 *
3491 * Check manufacturer ID
3492 */
3493static int onenand_check_maf(int manuf)
3494{
Kyungmin Park37b1cc32005-12-16 11:17:29 +09003495 int size = ARRAY_SIZE(onenand_manuf_ids);
3496 char *name;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003497 int i;
3498
Kyungmin Park37b1cc32005-12-16 11:17:29 +09003499 for (i = 0; i < size; i++)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003500 if (manuf == onenand_manuf_ids[i].id)
3501 break;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003502
Kyungmin Park37b1cc32005-12-16 11:17:29 +09003503 if (i < size)
3504 name = onenand_manuf_ids[i].name;
3505 else
3506 name = "Unknown";
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003507
Kyungmin Park37b1cc32005-12-16 11:17:29 +09003508 printk(KERN_DEBUG "OneNAND Manufacturer: %s (0x%0x)\n", name, manuf);
3509
3510 return (i == size);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003511}
3512
3513/**
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003514* flexonenand_get_boundary - Reads the SLC boundary
3515* @param onenand_info - onenand info structure
3516**/
3517static int flexonenand_get_boundary(struct mtd_info *mtd)
3518{
3519 struct onenand_chip *this = mtd->priv;
3520 unsigned die, bdry;
Brian Norris6b7368c2013-08-27 18:01:19 -07003521 int syscfg, locked;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003522
3523 /* Disable ECC */
3524 syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
3525 this->write_word((syscfg | 0x0100), this->base + ONENAND_REG_SYS_CFG1);
3526
3527 for (die = 0; die < this->dies; die++) {
3528 this->command(mtd, FLEXONENAND_CMD_PI_ACCESS, die, 0);
3529 this->wait(mtd, FL_SYNCING);
3530
3531 this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0);
Brian Norris6b7368c2013-08-27 18:01:19 -07003532 this->wait(mtd, FL_READING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003533
3534 bdry = this->read_word(this->base + ONENAND_DATARAM);
3535 if ((bdry >> FLEXONENAND_PI_UNLOCK_SHIFT) == 3)
3536 locked = 0;
3537 else
3538 locked = 1;
3539 this->boundary[die] = bdry & FLEXONENAND_PI_MASK;
3540
3541 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
Brian Norris6b7368c2013-08-27 18:01:19 -07003542 this->wait(mtd, FL_RESETING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003543
3544 printk(KERN_INFO "Die %d boundary: %d%s\n", die,
3545 this->boundary[die], locked ? "(Locked)" : "(Unlocked)");
3546 }
3547
3548 /* Enable ECC */
3549 this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
3550 return 0;
3551}
3552
3553/**
3554 * flexonenand_get_size - Fill up fields in onenand_chip and mtd_info
3555 * boundary[], diesize[], mtd->size, mtd->erasesize
3556 * @param mtd - MTD device structure
3557 */
3558static void flexonenand_get_size(struct mtd_info *mtd)
3559{
3560 struct onenand_chip *this = mtd->priv;
3561 int die, i, eraseshift, density;
3562 int blksperdie, maxbdry;
3563 loff_t ofs;
3564
3565 density = onenand_get_density(this->device_id);
3566 blksperdie = ((loff_t)(16 << density) << 20) >> (this->erase_shift);
3567 blksperdie >>= ONENAND_IS_DDP(this) ? 1 : 0;
3568 maxbdry = blksperdie - 1;
3569 eraseshift = this->erase_shift - 1;
3570
3571 mtd->numeraseregions = this->dies << 1;
3572
3573 /* This fills up the device boundary */
3574 flexonenand_get_boundary(mtd);
3575 die = ofs = 0;
3576 i = -1;
3577 for (; die < this->dies; die++) {
3578 if (!die || this->boundary[die-1] != maxbdry) {
3579 i++;
3580 mtd->eraseregions[i].offset = ofs;
3581 mtd->eraseregions[i].erasesize = 1 << eraseshift;
3582 mtd->eraseregions[i].numblocks =
3583 this->boundary[die] + 1;
3584 ofs += mtd->eraseregions[i].numblocks << eraseshift;
3585 eraseshift++;
3586 } else {
3587 mtd->numeraseregions -= 1;
3588 mtd->eraseregions[i].numblocks +=
3589 this->boundary[die] + 1;
3590 ofs += (this->boundary[die] + 1) << (eraseshift - 1);
3591 }
3592 if (this->boundary[die] != maxbdry) {
3593 i++;
3594 mtd->eraseregions[i].offset = ofs;
3595 mtd->eraseregions[i].erasesize = 1 << eraseshift;
3596 mtd->eraseregions[i].numblocks = maxbdry ^
3597 this->boundary[die];
3598 ofs += mtd->eraseregions[i].numblocks << eraseshift;
3599 eraseshift--;
3600 } else
3601 mtd->numeraseregions -= 1;
3602 }
3603
3604 /* Expose MLC erase size except when all blocks are SLC */
3605 mtd->erasesize = 1 << this->erase_shift;
3606 if (mtd->numeraseregions == 1)
3607 mtd->erasesize >>= 1;
3608
3609 printk(KERN_INFO "Device has %d eraseregions\n", mtd->numeraseregions);
3610 for (i = 0; i < mtd->numeraseregions; i++)
3611 printk(KERN_INFO "[offset: 0x%08x, erasesize: 0x%05x,"
3612 " numblocks: %04u]\n",
3613 (unsigned int) mtd->eraseregions[i].offset,
3614 mtd->eraseregions[i].erasesize,
3615 mtd->eraseregions[i].numblocks);
3616
3617 for (die = 0, mtd->size = 0; die < this->dies; die++) {
3618 this->diesize[die] = (loff_t)blksperdie << this->erase_shift;
3619 this->diesize[die] -= (loff_t)(this->boundary[die] + 1)
3620 << (this->erase_shift - 1);
3621 mtd->size += this->diesize[die];
3622 }
3623}
3624
3625/**
3626 * flexonenand_check_blocks_erased - Check if blocks are erased
3627 * @param mtd_info - mtd info structure
3628 * @param start - first erase block to check
3629 * @param end - last erase block to check
3630 *
3631 * Converting an unerased block from MLC to SLC
3632 * causes byte values to change. Since both data and its ECC
3633 * have changed, reads on the block give uncorrectable error.
3634 * This might lead to the block being detected as bad.
3635 *
3636 * Avoid this by ensuring that the block to be converted is
3637 * erased.
3638 */
3639static int flexonenand_check_blocks_erased(struct mtd_info *mtd, int start, int end)
3640{
3641 struct onenand_chip *this = mtd->priv;
3642 int i, ret;
3643 int block;
3644 struct mtd_oob_ops ops = {
Brian Norris0612b9d2011-08-30 18:45:40 -07003645 .mode = MTD_OPS_PLACE_OOB,
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003646 .ooboffs = 0,
3647 .ooblen = mtd->oobsize,
3648 .datbuf = NULL,
3649 .oobbuf = this->oob_buf,
3650 };
3651 loff_t addr;
3652
3653 printk(KERN_DEBUG "Check blocks from %d to %d\n", start, end);
3654
3655 for (block = start; block <= end; block++) {
3656 addr = flexonenand_addr(this, block);
3657 if (onenand_block_isbad_nolock(mtd, addr, 0))
3658 continue;
3659
3660 /*
3661 * Since main area write results in ECC write to spare,
3662 * it is sufficient to check only ECC bytes for change.
3663 */
3664 ret = onenand_read_oob_nolock(mtd, addr, &ops);
3665 if (ret)
3666 return ret;
3667
3668 for (i = 0; i < mtd->oobsize; i++)
3669 if (this->oob_buf[i] != 0xff)
3670 break;
3671
3672 if (i != mtd->oobsize) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303673 printk(KERN_WARNING "%s: Block %d not erased.\n",
3674 __func__, block);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003675 return 1;
3676 }
3677 }
3678
3679 return 0;
3680}
3681
3682/**
3683 * flexonenand_set_boundary - Writes the SLC boundary
3684 * @param mtd - mtd info structure
3685 */
Sachin Kamat01319502012-09-22 11:42:31 +05303686static int flexonenand_set_boundary(struct mtd_info *mtd, int die,
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003687 int boundary, int lock)
3688{
3689 struct onenand_chip *this = mtd->priv;
3690 int ret, density, blksperdie, old, new, thisboundary;
3691 loff_t addr;
3692
3693 /* Change only once for SDP Flex-OneNAND */
3694 if (die && (!ONENAND_IS_DDP(this)))
3695 return 0;
3696
3697 /* boundary value of -1 indicates no required change */
3698 if (boundary < 0 || boundary == this->boundary[die])
3699 return 0;
3700
3701 density = onenand_get_density(this->device_id);
3702 blksperdie = ((16 << density) << 20) >> this->erase_shift;
3703 blksperdie >>= ONENAND_IS_DDP(this) ? 1 : 0;
3704
3705 if (boundary >= blksperdie) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303706 printk(KERN_ERR "%s: Invalid boundary value. "
3707 "Boundary not changed.\n", __func__);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003708 return -EINVAL;
3709 }
3710
3711 /* Check if converting blocks are erased */
3712 old = this->boundary[die] + (die * this->density_mask);
3713 new = boundary + (die * this->density_mask);
3714 ret = flexonenand_check_blocks_erased(mtd, min(old, new) + 1, max(old, new));
3715 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303716 printk(KERN_ERR "%s: Please erase blocks "
3717 "before boundary change\n", __func__);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003718 return ret;
3719 }
3720
3721 this->command(mtd, FLEXONENAND_CMD_PI_ACCESS, die, 0);
3722 this->wait(mtd, FL_SYNCING);
3723
3724 /* Check is boundary is locked */
3725 this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0);
Brian Norris6b7368c2013-08-27 18:01:19 -07003726 this->wait(mtd, FL_READING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003727
3728 thisboundary = this->read_word(this->base + ONENAND_DATARAM);
3729 if ((thisboundary >> FLEXONENAND_PI_UNLOCK_SHIFT) != 3) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303730 printk(KERN_ERR "%s: boundary locked\n", __func__);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003731 ret = 1;
3732 goto out;
3733 }
3734
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303735 printk(KERN_INFO "Changing die %d boundary: %d%s\n",
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003736 die, boundary, lock ? "(Locked)" : "(Unlocked)");
3737
3738 addr = die ? this->diesize[0] : 0;
3739
3740 boundary &= FLEXONENAND_PI_MASK;
3741 boundary |= lock ? 0 : (3 << FLEXONENAND_PI_UNLOCK_SHIFT);
3742
3743 this->command(mtd, ONENAND_CMD_ERASE, addr, 0);
3744 ret = this->wait(mtd, FL_ERASING);
3745 if (ret) {
Mika Korhonenf369c7e2009-10-23 07:50:44 +02003746 printk(KERN_ERR "%s: Failed PI erase for Die %d\n",
3747 __func__, die);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003748 goto out;
3749 }
3750
3751 this->write_word(boundary, this->base + ONENAND_DATARAM);
3752 this->command(mtd, ONENAND_CMD_PROG, addr, 0);
3753 ret = this->wait(mtd, FL_WRITING);
3754 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303755 printk(KERN_ERR "%s: Failed PI write for Die %d\n",
3756 __func__, die);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003757 goto out;
3758 }
3759
3760 this->command(mtd, FLEXONENAND_CMD_PI_UPDATE, die, 0);
3761 ret = this->wait(mtd, FL_WRITING);
3762out:
3763 this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_REG_COMMAND);
3764 this->wait(mtd, FL_RESETING);
3765 if (!ret)
3766 /* Recalculate device size on boundary change*/
3767 flexonenand_get_size(mtd);
3768
3769 return ret;
3770}
3771
3772/**
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003773 * onenand_chip_probe - [OneNAND Interface] The generic chip probe
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003774 * @param mtd MTD device structure
3775 *
3776 * OneNAND detection method:
Michael Opdenacker59c51592007-05-09 08:57:56 +02003777 * Compare the values from command with ones from register
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003778 */
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003779static int onenand_chip_probe(struct mtd_info *mtd)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003780{
3781 struct onenand_chip *this = mtd->priv;
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003782 int bram_maf_id, bram_dev_id, maf_id, dev_id;
Kyungmin Park47e777e2006-09-25 23:53:28 +00003783 int syscfg;
3784
3785 /* Save system configuration 1 */
3786 syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
3787 /* Clear Sync. Burst Read mode to read BootRAM */
Adrian Hunteree8f3762009-05-05 11:04:19 +03003788 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 +01003789
3790 /* Send the command for reading device ID from BootRAM */
3791 this->write_word(ONENAND_CMD_READID, this->base + ONENAND_BOOTRAM);
3792
3793 /* Read manufacturer and device IDs from BootRAM */
3794 bram_maf_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x0);
3795 bram_dev_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x2);
3796
Kyungmin Park47e777e2006-09-25 23:53:28 +00003797 /* Reset OneNAND to read default register values */
3798 this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM);
3799 /* Wait reset */
3800 this->wait(mtd, FL_RESETING);
3801
3802 /* Restore system configuration 1 */
3803 this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
3804
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003805 /* Check manufacturer ID */
3806 if (onenand_check_maf(bram_maf_id))
3807 return -ENXIO;
3808
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003809 /* Read manufacturer and device IDs from Register */
3810 maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);
3811 dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
3812
3813 /* Check OneNAND device */
3814 if (maf_id != bram_maf_id || dev_id != bram_dev_id)
3815 return -ENXIO;
3816
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003817 return 0;
3818}
3819
3820/**
3821 * onenand_probe - [OneNAND Interface] Probe the OneNAND device
3822 * @param mtd MTD device structure
3823 */
3824static int onenand_probe(struct mtd_info *mtd)
3825{
3826 struct onenand_chip *this = mtd->priv;
Brian Norris6b7368c2013-08-27 18:01:19 -07003827 int dev_id, ver_id;
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003828 int density;
3829 int ret;
3830
3831 ret = this->chip_probe(mtd);
3832 if (ret)
3833 return ret;
3834
Brian Norris6b7368c2013-08-27 18:01:19 -07003835 /* Device and version IDs from Register */
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003836 dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
3837 ver_id = this->read_word(this->base + ONENAND_REG_VERSION_ID);
3838 this->technology = this->read_word(this->base + ONENAND_REG_TECHNOLOGY);
3839
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003840 /* Flash device information */
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003841 onenand_print_device_info(dev_id, ver_id);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003842 this->device_id = dev_id;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003843 this->version_id = ver_id;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003844
Kyungmin Parkc37cb562010-04-28 17:46:48 +02003845 /* Check OneNAND features */
3846 onenand_check_features(mtd);
3847
Kyungmin Parke71f04f2007-12-11 11:23:45 +09003848 density = onenand_get_density(dev_id);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003849 if (FLEXONENAND(this)) {
3850 this->dies = ONENAND_IS_DDP(this) ? 2 : 1;
3851 /* Maximum possible erase regions */
3852 mtd->numeraseregions = this->dies << 1;
3853 mtd->eraseregions = kzalloc(sizeof(struct mtd_erase_region_info)
3854 * (this->dies << 1), GFP_KERNEL);
3855 if (!mtd->eraseregions)
3856 return -ENOMEM;
3857 }
3858
3859 /*
3860 * For Flex-OneNAND, chipsize represents maximum possible device size.
3861 * mtd->size represents the actual device size.
3862 */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003863 this->chipsize = (16 << density) << 20;
3864
3865 /* OneNAND page size & block size */
3866 /* The data buffer size is equal to page size */
Joern Engel28318772006-05-22 23:18:05 +02003867 mtd->writesize = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003868 /* We use the full BufferRAM */
Kyungmin Park8a8f6322010-12-02 09:24:16 +09003869 if (ONENAND_IS_4KB_PAGE(this))
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003870 mtd->writesize <<= 1;
3871
Joern Engel28318772006-05-22 23:18:05 +02003872 mtd->oobsize = mtd->writesize >> 5;
Kyungmin Park9bfbc9b2007-01-31 14:25:21 +09003873 /* Pages per a block are always 64 in OneNAND */
Joern Engel28318772006-05-22 23:18:05 +02003874 mtd->erasesize = mtd->writesize << 6;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003875 /*
3876 * Flex-OneNAND SLC area has 64 pages per block.
3877 * Flex-OneNAND MLC area has 128 pages per block.
3878 * Expose MLC erase size to find erase_shift and page_mask.
3879 */
3880 if (FLEXONENAND(this))
3881 mtd->erasesize <<= 1;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003882
3883 this->erase_shift = ffs(mtd->erasesize) - 1;
Joern Engel28318772006-05-22 23:18:05 +02003884 this->page_shift = ffs(mtd->writesize) - 1;
Kyungmin Park9bfbc9b2007-01-31 14:25:21 +09003885 this->page_mask = (1 << (this->erase_shift - this->page_shift)) - 1;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003886 /* Set density mask. it is used for DDP */
3887 if (ONENAND_IS_DDP(this))
3888 this->density_mask = this->chipsize >> (this->erase_shift + 1);
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003889 /* It's real page size */
3890 this->writesize = mtd->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003891
Mika Korhonen492e1502009-06-09 21:52:35 +03003892 /* REVISIT: Multichip handling */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003893
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003894 if (FLEXONENAND(this))
3895 flexonenand_get_size(mtd);
3896 else
3897 mtd->size = this->chipsize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003898
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003899 /*
3900 * We emulate the 4KiB page and 256KiB erase block size
3901 * But oobsize is still 64 bytes.
3902 * It is only valid if you turn on 2X program support,
3903 * Otherwise it will be ignored by compiler.
3904 */
3905 if (ONENAND_IS_2PLANE(this)) {
3906 mtd->writesize <<= 1;
3907 mtd->erasesize <<= 1;
3908 }
3909
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003910 return 0;
3911}
3912
Kyungmin Parka41371e2005-09-29 03:55:31 +01003913/**
3914 * onenand_suspend - [MTD Interface] Suspend the OneNAND flash
3915 * @param mtd MTD device structure
3916 */
3917static int onenand_suspend(struct mtd_info *mtd)
3918{
3919 return onenand_get_device(mtd, FL_PM_SUSPENDED);
3920}
3921
3922/**
3923 * onenand_resume - [MTD Interface] Resume the OneNAND flash
3924 * @param mtd MTD device structure
3925 */
3926static void onenand_resume(struct mtd_info *mtd)
3927{
3928 struct onenand_chip *this = mtd->priv;
3929
3930 if (this->state == FL_PM_SUSPENDED)
3931 onenand_release_device(mtd);
3932 else
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303933 printk(KERN_ERR "%s: resume() called for the chip which is not "
3934 "in suspended state\n", __func__);
Kyungmin Parka41371e2005-09-29 03:55:31 +01003935}
3936
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003937/**
3938 * onenand_scan - [OneNAND Interface] Scan for the OneNAND device
3939 * @param mtd MTD device structure
3940 * @param maxchips Number of chips to scan for
3941 *
3942 * This fills out all the not initialized function pointers
3943 * with the defaults.
3944 * The flash ID is read and the mtd/chip structures are
3945 * filled with the appropriate values.
3946 */
3947int onenand_scan(struct mtd_info *mtd, int maxchips)
3948{
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003949 int i, ret;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003950 struct onenand_chip *this = mtd->priv;
3951
3952 if (!this->read_word)
3953 this->read_word = onenand_readw;
3954 if (!this->write_word)
3955 this->write_word = onenand_writew;
3956
3957 if (!this->command)
3958 this->command = onenand_command;
3959 if (!this->wait)
Kyungmin Park2c221202006-11-16 11:23:48 +09003960 onenand_setup_wait(mtd);
Kyungmin Park31bb9992009-05-12 13:46:57 -07003961 if (!this->bbt_wait)
3962 this->bbt_wait = onenand_bbt_wait;
3963 if (!this->unlock_all)
3964 this->unlock_all = onenand_unlock_all;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003965
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003966 if (!this->chip_probe)
3967 this->chip_probe = onenand_chip_probe;
3968
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003969 if (!this->read_bufferram)
3970 this->read_bufferram = onenand_read_bufferram;
3971 if (!this->write_bufferram)
3972 this->write_bufferram = onenand_write_bufferram;
3973
Kyungmin Parkcdc00132005-09-03 07:15:48 +01003974 if (!this->block_markbad)
3975 this->block_markbad = onenand_default_block_markbad;
3976 if (!this->scan_bbt)
3977 this->scan_bbt = onenand_default_bbt;
3978
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003979 if (onenand_probe(mtd))
3980 return -ENXIO;
3981
Kyungmin Park52b0eea2005-09-03 07:07:19 +01003982 /* Set Sync. Burst Read after probing */
3983 if (this->mmcontrol) {
3984 printk(KERN_INFO "OneNAND Sync. Burst Read support\n");
3985 this->read_bufferram = onenand_sync_read_bufferram;
3986 }
3987
Kyungmin Park532a37c2005-12-16 11:17:29 +09003988 /* Allocate buffers, if necessary */
3989 if (!this->page_buf) {
Kyungmin Park470bc842007-03-09 10:08:11 +09003990 this->page_buf = kzalloc(mtd->writesize, GFP_KERNEL);
Jingoo Hane4eec192014-02-06 15:15:38 +09003991 if (!this->page_buf)
Kyungmin Park532a37c2005-12-16 11:17:29 +09003992 return -ENOMEM;
Kyungmin Park4a8ce0b2010-04-28 17:46:46 +02003993#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
3994 this->verify_buf = kzalloc(mtd->writesize, GFP_KERNEL);
3995 if (!this->verify_buf) {
3996 kfree(this->page_buf);
3997 return -ENOMEM;
3998 }
3999#endif
Kyungmin Park532a37c2005-12-16 11:17:29 +09004000 this->options |= ONENAND_PAGEBUF_ALLOC;
4001 }
Kyungmin Park470bc842007-03-09 10:08:11 +09004002 if (!this->oob_buf) {
4003 this->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
4004 if (!this->oob_buf) {
Kyungmin Park470bc842007-03-09 10:08:11 +09004005 if (this->options & ONENAND_PAGEBUF_ALLOC) {
4006 this->options &= ~ONENAND_PAGEBUF_ALLOC;
4007 kfree(this->page_buf);
4008 }
4009 return -ENOMEM;
4010 }
4011 this->options |= ONENAND_OOBBUF_ALLOC;
4012 }
Kyungmin Park532a37c2005-12-16 11:17:29 +09004013
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004014 this->state = FL_READY;
4015 init_waitqueue_head(&this->wq);
4016 spin_lock_init(&this->chip_lock);
4017
Kyungmin Park60d84f92006-12-22 16:21:54 +09004018 /*
4019 * Allow subpage writes up to oobsize.
4020 */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004021 switch (mtd->oobsize) {
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07004022 case 128:
Roman Tereshonkov99b17c02011-04-11 12:52:01 +03004023 if (FLEXONENAND(this)) {
4024 this->ecclayout = &flexonenand_oob_128;
4025 mtd->subpage_sft = 0;
4026 } else {
4027 this->ecclayout = &onenand_oob_128;
4028 mtd->subpage_sft = 2;
4029 }
Kyungmin Parke1c10242011-06-22 14:16:49 +09004030 if (ONENAND_IS_NOP_1(this))
4031 mtd->subpage_sft = 0;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07004032 break;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004033 case 64:
Thomas Gleixner5bd34c02006-05-27 22:16:10 +02004034 this->ecclayout = &onenand_oob_64;
Kyungmin Park60d84f92006-12-22 16:21:54 +09004035 mtd->subpage_sft = 2;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004036 break;
4037
4038 case 32:
Thomas Gleixner5bd34c02006-05-27 22:16:10 +02004039 this->ecclayout = &onenand_oob_32;
Kyungmin Park60d84f92006-12-22 16:21:54 +09004040 mtd->subpage_sft = 1;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004041 break;
4042
4043 default:
Amul Kumar Saha297758f2009-10-02 16:59:11 +05304044 printk(KERN_WARNING "%s: No OOB scheme defined for oobsize %d\n",
4045 __func__, mtd->oobsize);
Kyungmin Park60d84f92006-12-22 16:21:54 +09004046 mtd->subpage_sft = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004047 /* To prevent kernel oops */
Thomas Gleixner5bd34c02006-05-27 22:16:10 +02004048 this->ecclayout = &onenand_oob_32;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004049 break;
4050 }
4051
Kyungmin Park60d84f92006-12-22 16:21:54 +09004052 this->subpagesize = mtd->writesize >> mtd->subpage_sft;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02004053
4054 /*
4055 * The number of bytes available for a client to place data into
4056 * the out of band area
4057 */
4058 this->ecclayout->oobavail = 0;
Kyungmin Parkad286342007-03-23 10:19:52 +09004059 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES &&
4060 this->ecclayout->oobfree[i].length; i++)
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02004061 this->ecclayout->oobavail +=
4062 this->ecclayout->oobfree[i].length;
Vitaly Wool1f922672007-03-06 16:56:34 +03004063 mtd->oobavail = this->ecclayout->oobavail;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02004064
Thomas Gleixner5bd34c02006-05-27 22:16:10 +02004065 mtd->ecclayout = this->ecclayout;
Mike Dunn6a918ba2012-03-11 14:21:11 -07004066 mtd->ecc_strength = 1;
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +00004067
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004068 /* Fill in remaining MTD driver data */
Rohit Hassan Sathyanarayanc7626802010-09-27 16:02:10 +05304069 mtd->type = ONENAND_IS_MLC(this) ? MTD_MLCNANDFLASH : MTD_NANDFLASH;
Joern Engel5fa43392006-05-22 23:18:29 +02004070 mtd->flags = MTD_CAP_NANDFLASH;
Artem Bityutskiy3c3c10b2012-01-30 14:58:32 +02004071 mtd->_erase = onenand_erase;
4072 mtd->_point = NULL;
4073 mtd->_unpoint = NULL;
4074 mtd->_read = onenand_read;
4075 mtd->_write = onenand_write;
4076 mtd->_read_oob = onenand_read_oob;
4077 mtd->_write_oob = onenand_write_oob;
4078 mtd->_panic_write = onenand_panic_write;
Kyungmin Park493c6462006-05-12 17:03:07 +03004079#ifdef CONFIG_MTD_ONENAND_OTP
Artem Bityutskiy3c3c10b2012-01-30 14:58:32 +02004080 mtd->_get_fact_prot_info = onenand_get_fact_prot_info;
4081 mtd->_read_fact_prot_reg = onenand_read_fact_prot_reg;
4082 mtd->_get_user_prot_info = onenand_get_user_prot_info;
4083 mtd->_read_user_prot_reg = onenand_read_user_prot_reg;
4084 mtd->_write_user_prot_reg = onenand_write_user_prot_reg;
4085 mtd->_lock_user_prot_reg = onenand_lock_user_prot_reg;
Kyungmin Park493c6462006-05-12 17:03:07 +03004086#endif
Artem Bityutskiy3c3c10b2012-01-30 14:58:32 +02004087 mtd->_sync = onenand_sync;
4088 mtd->_lock = onenand_lock;
4089 mtd->_unlock = onenand_unlock;
4090 mtd->_suspend = onenand_suspend;
4091 mtd->_resume = onenand_resume;
4092 mtd->_block_isbad = onenand_block_isbad;
4093 mtd->_block_markbad = onenand_block_markbad;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004094 mtd->owner = THIS_MODULE;
Anatolij Gustschin25dcd292010-12-16 23:42:17 +01004095 mtd->writebufsize = mtd->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004096
4097 /* Unlock whole block */
Roman Tereshonkovb3dcfd352011-02-17 13:44:41 +02004098 if (!(this->options & ONENAND_SKIP_INITIAL_UNLOCKING))
4099 this->unlock_all(mtd);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004100
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07004101 ret = this->scan_bbt(mtd);
4102 if ((!FLEXONENAND(this)) || ret)
4103 return ret;
4104
4105 /* Change Flex-OneNAND boundaries if required */
4106 for (i = 0; i < MAX_DIES; i++)
4107 flexonenand_set_boundary(mtd, i, flex_bdry[2 * i],
4108 flex_bdry[(2 * i) + 1]);
4109
4110 return 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004111}
4112
4113/**
4114 * onenand_release - [OneNAND Interface] Free resources held by the OneNAND device
4115 * @param mtd MTD device structure
4116 */
4117void onenand_release(struct mtd_info *mtd)
4118{
Kyungmin Park532a37c2005-12-16 11:17:29 +09004119 struct onenand_chip *this = mtd->priv;
4120
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004121 /* Deregister partitions */
Jamie Iles711a6322011-05-23 10:22:56 +01004122 mtd_device_unregister(mtd);
Kyungmin Park532a37c2005-12-16 11:17:29 +09004123
4124 /* Free bad block table memory, if allocated */
Adrian Hunterf00b0042007-01-22 17:01:01 +09004125 if (this->bbm) {
4126 struct bbm_info *bbm = this->bbm;
4127 kfree(bbm->bbt);
Kyungmin Park532a37c2005-12-16 11:17:29 +09004128 kfree(this->bbm);
Adrian Hunterf00b0042007-01-22 17:01:01 +09004129 }
Kyungmin Park470bc842007-03-09 10:08:11 +09004130 /* Buffers allocated by onenand_scan */
Kyungmin Park4a8ce0b2010-04-28 17:46:46 +02004131 if (this->options & ONENAND_PAGEBUF_ALLOC) {
Kyungmin Park532a37c2005-12-16 11:17:29 +09004132 kfree(this->page_buf);
Kyungmin Park4a8ce0b2010-04-28 17:46:46 +02004133#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
4134 kfree(this->verify_buf);
4135#endif
4136 }
Kyungmin Park470bc842007-03-09 10:08:11 +09004137 if (this->options & ONENAND_OOBBUF_ALLOC)
4138 kfree(this->oob_buf);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07004139 kfree(mtd->eraseregions);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004140}
4141
4142EXPORT_SYMBOL_GPL(onenand_scan);
4143EXPORT_SYMBOL_GPL(onenand_release);
4144
4145MODULE_LICENSE("GPL");
4146MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");
4147MODULE_DESCRIPTION("Generic OneNAND flash driver code");