blob: af28bb3ae7cfc56ccd68e0b0a9d6d05fc5e6296e [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
Boris BREZILLON29f10582016-03-07 10:46:52 +01001127 oobsize = mtd_oobavail(mtd, ops);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001128 oobcolumn = from & (mtd->oobsize - 1);
1129
1130 /* Do not allow reads past end of device */
1131 if (from + len > mtd->size) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301132 printk(KERN_ERR "%s: Attempt read beyond end of device\n",
1133 __func__);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001134 ops->retlen = 0;
1135 ops->oobretlen = 0;
1136 return -EINVAL;
1137 }
1138
1139 stats = mtd->ecc_stats;
1140
1141 while (read < len) {
1142 cond_resched();
1143
1144 thislen = min_t(int, writesize, len - read);
1145
1146 column = from & (writesize - 1);
1147 if (column + thislen > writesize)
1148 thislen = writesize - column;
1149
1150 if (!onenand_check_bufferram(mtd, from)) {
1151 this->command(mtd, ONENAND_CMD_READ, from, writesize);
1152
1153 ret = this->wait(mtd, FL_READING);
1154 if (unlikely(ret))
1155 ret = onenand_recover_lsb(mtd, from, ret);
1156 onenand_update_bufferram(mtd, from, !ret);
Brian Norrisd57f40542011-09-20 18:34:25 -07001157 if (mtd_is_eccerr(ret))
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001158 ret = 0;
Adrian Hunterb0850582011-02-08 12:02:38 +02001159 if (ret)
1160 break;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001161 }
1162
1163 this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
1164 if (oobbuf) {
1165 thisooblen = oobsize - oobcolumn;
1166 thisooblen = min_t(int, thisooblen, ooblen - oobread);
1167
Brian Norris0612b9d2011-08-30 18:45:40 -07001168 if (ops->mode == MTD_OPS_AUTO_OOB)
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001169 onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);
1170 else
1171 this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen);
1172 oobread += thisooblen;
1173 oobbuf += thisooblen;
1174 oobcolumn = 0;
1175 }
1176
1177 read += thislen;
1178 if (read == len)
1179 break;
1180
1181 from += thislen;
1182 buf += thislen;
1183 }
1184
1185 /*
1186 * Return success, if no ECC failures, else -EBADMSG
1187 * fs driver will take care of that, because
1188 * retlen == desired len and result == -EBADMSG
1189 */
1190 ops->retlen = read;
1191 ops->oobretlen = oobread;
1192
1193 if (ret)
1194 return ret;
1195
1196 if (mtd->ecc_stats.failed - stats.failed)
1197 return -EBADMSG;
1198
Mike Dunnedbc45402012-04-25 12:06:11 -07001199 /* return max bitflips per ecc step; ONENANDs correct 1 bit only */
1200 return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001201}
1202
1203/**
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001204 * onenand_read_ops_nolock - [OneNAND Interface] OneNAND read main and/or out-of-band
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001205 * @param mtd MTD device structure
1206 * @param from offset to read from
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001207 * @param ops: oob operation description structure
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001208 *
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001209 * OneNAND read main and/or out-of-band data
1210 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001211static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001212 struct mtd_oob_ops *ops)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001213{
1214 struct onenand_chip *this = mtd->priv;
Kyungmin Parkf4f91ac2006-11-16 12:03:56 +09001215 struct mtd_ecc_stats stats;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001216 size_t len = ops->len;
1217 size_t ooblen = ops->ooblen;
1218 u_char *buf = ops->datbuf;
1219 u_char *oobbuf = ops->oobbuf;
1220 int read = 0, column, thislen;
1221 int oobread = 0, oobcolumn, thisooblen, oobsize;
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001222 int ret = 0, boundary = 0;
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001223 int writesize = this->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001224
Brian Norris0a32a102011-07-19 10:06:10 -07001225 pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from,
1226 (int)len);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001227
Boris BREZILLON29f10582016-03-07 10:46:52 +01001228 oobsize = mtd_oobavail(mtd, ops);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001229 oobcolumn = from & (mtd->oobsize - 1);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001230
1231 /* Do not allow reads past end of device */
1232 if ((from + len) > mtd->size) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301233 printk(KERN_ERR "%s: Attempt read beyond end of device\n",
1234 __func__);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001235 ops->retlen = 0;
1236 ops->oobretlen = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001237 return -EINVAL;
1238 }
1239
Kyungmin Parkf4f91ac2006-11-16 12:03:56 +09001240 stats = mtd->ecc_stats;
Artem Bityutskiy61a7e192006-12-26 16:41:24 +09001241
Adrian Huntera8de85d2007-01-04 09:51:26 +02001242 /* Read-while-load method */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001243
Adrian Huntera8de85d2007-01-04 09:51:26 +02001244 /* Do first load to bufferRAM */
1245 if (read < len) {
1246 if (!onenand_check_bufferram(mtd, from)) {
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001247 this->command(mtd, ONENAND_CMD_READ, from, writesize);
Adrian Huntera8de85d2007-01-04 09:51:26 +02001248 ret = this->wait(mtd, FL_READING);
1249 onenand_update_bufferram(mtd, from, !ret);
Brian Norrisd57f40542011-09-20 18:34:25 -07001250 if (mtd_is_eccerr(ret))
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001251 ret = 0;
Adrian Huntera8de85d2007-01-04 09:51:26 +02001252 }
1253 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001254
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001255 thislen = min_t(int, writesize, len - read);
1256 column = from & (writesize - 1);
1257 if (column + thislen > writesize)
1258 thislen = writesize - column;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001259
Adrian Huntera8de85d2007-01-04 09:51:26 +02001260 while (!ret) {
1261 /* If there is more to load then start next load */
1262 from += thislen;
1263 if (read + thislen < len) {
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001264 this->command(mtd, ONENAND_CMD_READ, from, writesize);
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001265 /*
1266 * Chip boundary handling in DDP
1267 * Now we issued chip 1 read and pointed chip 1
Mika Korhonen492e1502009-06-09 21:52:35 +03001268 * bufferram so we have to point chip 0 bufferram.
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001269 */
Kyungmin Park738d61f2007-01-15 17:09:14 +09001270 if (ONENAND_IS_DDP(this) &&
1271 unlikely(from == (this->chipsize >> 1))) {
1272 this->write_word(ONENAND_DDP_CHIP0, this->base + ONENAND_REG_START_ADDRESS2);
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001273 boundary = 1;
1274 } else
1275 boundary = 0;
Adrian Huntera8de85d2007-01-04 09:51:26 +02001276 ONENAND_SET_PREV_BUFFERRAM(this);
1277 }
1278 /* While load is going, read from last bufferRAM */
1279 this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001280
1281 /* Read oob area if needed */
1282 if (oobbuf) {
1283 thisooblen = oobsize - oobcolumn;
1284 thisooblen = min_t(int, thisooblen, ooblen - oobread);
1285
Brian Norris0612b9d2011-08-30 18:45:40 -07001286 if (ops->mode == MTD_OPS_AUTO_OOB)
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001287 onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);
1288 else
1289 this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen);
1290 oobread += thisooblen;
1291 oobbuf += thisooblen;
1292 oobcolumn = 0;
1293 }
1294
Adrian Huntera8de85d2007-01-04 09:51:26 +02001295 /* See if we are done */
1296 read += thislen;
1297 if (read == len)
1298 break;
1299 /* Set up for next read from bufferRAM */
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001300 if (unlikely(boundary))
Kyungmin Park738d61f2007-01-15 17:09:14 +09001301 this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);
Adrian Huntera8de85d2007-01-04 09:51:26 +02001302 ONENAND_SET_NEXT_BUFFERRAM(this);
1303 buf += thislen;
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001304 thislen = min_t(int, writesize, len - read);
Adrian Huntera8de85d2007-01-04 09:51:26 +02001305 column = 0;
1306 cond_resched();
1307 /* Now wait for load */
1308 ret = this->wait(mtd, FL_READING);
1309 onenand_update_bufferram(mtd, from, !ret);
Brian Norrisd57f40542011-09-20 18:34:25 -07001310 if (mtd_is_eccerr(ret))
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001311 ret = 0;
Adrian Huntera8de85d2007-01-04 09:51:26 +02001312 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001313
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001314 /*
1315 * Return success, if no ECC failures, else -EBADMSG
1316 * fs driver will take care of that, because
1317 * retlen == desired len and result == -EBADMSG
1318 */
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001319 ops->retlen = read;
1320 ops->oobretlen = oobread;
Kyungmin Parkf4f91ac2006-11-16 12:03:56 +09001321
Adrian Huntera8de85d2007-01-04 09:51:26 +02001322 if (ret)
1323 return ret;
1324
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001325 if (mtd->ecc_stats.failed - stats.failed)
1326 return -EBADMSG;
1327
Mike Dunnedbc45402012-04-25 12:06:11 -07001328 /* return max bitflips per ecc step; ONENANDs correct 1 bit only */
1329 return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001330}
1331
1332/**
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001333 * onenand_read_oob_nolock - [MTD Interface] OneNAND read out-of-band
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001334 * @param mtd MTD device structure
1335 * @param from offset to read from
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001336 * @param ops: oob operation description structure
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001337 *
1338 * OneNAND read out-of-band data from the spare area
1339 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001340static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
Kyungmin Park12f77c92007-08-30 09:36:05 +09001341 struct mtd_oob_ops *ops)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001342{
1343 struct onenand_chip *this = mtd->priv;
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001344 struct mtd_ecc_stats stats;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001345 int read = 0, thislen, column, oobsize;
Kyungmin Park12f77c92007-08-30 09:36:05 +09001346 size_t len = ops->ooblen;
Brian Norris905c6bc2011-08-30 18:45:39 -07001347 unsigned int mode = ops->mode;
Kyungmin Park12f77c92007-08-30 09:36:05 +09001348 u_char *buf = ops->oobbuf;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001349 int ret = 0, readcmd;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001350
Kyungmin Park12f77c92007-08-30 09:36:05 +09001351 from += ops->ooboffs;
1352
Brian Norris0a32a102011-07-19 10:06:10 -07001353 pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from,
1354 (int)len);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001355
1356 /* Initialize return length value */
Kyungmin Park12f77c92007-08-30 09:36:05 +09001357 ops->oobretlen = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001358
Brian Norris0612b9d2011-08-30 18:45:40 -07001359 if (mode == MTD_OPS_AUTO_OOB)
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +01001360 oobsize = mtd->oobavail;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001361 else
1362 oobsize = mtd->oobsize;
1363
1364 column = from & (mtd->oobsize - 1);
1365
1366 if (unlikely(column >= oobsize)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301367 printk(KERN_ERR "%s: Attempted to start read outside oob\n",
1368 __func__);
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001369 return -EINVAL;
1370 }
1371
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001372 /* Do not allow reads past end of device */
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001373 if (unlikely(from >= mtd->size ||
1374 column + len > ((mtd->size >> this->page_shift) -
1375 (from >> this->page_shift)) * oobsize)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301376 printk(KERN_ERR "%s: Attempted to read beyond end of device\n",
1377 __func__);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001378 return -EINVAL;
1379 }
1380
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001381 stats = mtd->ecc_stats;
1382
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001383 readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001384
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001385 while (read < len) {
Artem Bityutskiy61a7e192006-12-26 16:41:24 +09001386 cond_resched();
1387
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001388 thislen = oobsize - column;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001389 thislen = min_t(int, thislen, len);
1390
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001391 this->command(mtd, readcmd, from, mtd->oobsize);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001392
1393 onenand_update_bufferram(mtd, from, 0);
1394
1395 ret = this->wait(mtd, FL_READING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001396 if (unlikely(ret))
1397 ret = onenand_recover_lsb(mtd, from, ret);
1398
Brian Norrisd57f40542011-09-20 18:34:25 -07001399 if (ret && !mtd_is_eccerr(ret)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301400 printk(KERN_ERR "%s: read failed = 0x%x\n",
1401 __func__, ret);
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001402 break;
1403 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001404
Brian Norris0612b9d2011-08-30 18:45:40 -07001405 if (mode == MTD_OPS_AUTO_OOB)
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001406 onenand_transfer_auto_oob(mtd, buf, column, thislen);
1407 else
1408 this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001409
1410 read += thislen;
1411
1412 if (read == len)
1413 break;
1414
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001415 buf += thislen;
1416
1417 /* Read more? */
1418 if (read < len) {
1419 /* Page size */
Joern Engel28318772006-05-22 23:18:05 +02001420 from += mtd->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001421 column = 0;
1422 }
1423 }
1424
Kyungmin Park12f77c92007-08-30 09:36:05 +09001425 ops->oobretlen = read;
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001426
1427 if (ret)
1428 return ret;
1429
1430 if (mtd->ecc_stats.failed - stats.failed)
1431 return -EBADMSG;
1432
1433 return 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001434}
1435
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001436/**
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001437 * onenand_read - [MTD Interface] Read data from flash
1438 * @param mtd MTD device structure
1439 * @param from offset to read from
1440 * @param len number of bytes to read
1441 * @param retlen pointer to variable to store the number of read bytes
1442 * @param buf the databuffer to put data
1443 *
1444 * Read with ecc
1445*/
1446static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
1447 size_t *retlen, u_char *buf)
1448{
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001449 struct onenand_chip *this = mtd->priv;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001450 struct mtd_oob_ops ops = {
1451 .len = len,
1452 .ooblen = 0,
1453 .datbuf = buf,
1454 .oobbuf = NULL,
1455 };
1456 int ret;
1457
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001458 onenand_get_device(mtd, FL_READING);
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001459 ret = ONENAND_IS_4KB_PAGE(this) ?
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001460 onenand_mlc_read_ops_nolock(mtd, from, &ops) :
1461 onenand_read_ops_nolock(mtd, from, &ops);
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001462 onenand_release_device(mtd);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001463
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001464 *retlen = ops.retlen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001465 return ret;
1466}
1467
1468/**
1469 * onenand_read_oob - [MTD Interface] Read main and/or out-of-band
Kyungmin Parke3da8062007-02-15 09:36:39 +09001470 * @param mtd: MTD device structure
1471 * @param from: offset to read from
1472 * @param ops: oob operation description structure
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001473
1474 * Read main and/or out-of-band
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001475 */
1476static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
1477 struct mtd_oob_ops *ops)
1478{
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001479 struct onenand_chip *this = mtd->priv;
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001480 int ret;
1481
Kyungmin Park4f4fad22007-02-02 09:22:21 +09001482 switch (ops->mode) {
Brian Norris0612b9d2011-08-30 18:45:40 -07001483 case MTD_OPS_PLACE_OOB:
1484 case MTD_OPS_AUTO_OOB:
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001485 break;
Brian Norris0612b9d2011-08-30 18:45:40 -07001486 case MTD_OPS_RAW:
Kyungmin Park4f4fad22007-02-02 09:22:21 +09001487 /* Not implemented yet */
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001488 default:
1489 return -EINVAL;
1490 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001491
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001492 onenand_get_device(mtd, FL_READING);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001493 if (ops->datbuf)
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001494 ret = ONENAND_IS_4KB_PAGE(this) ?
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001495 onenand_mlc_read_ops_nolock(mtd, from, ops) :
1496 onenand_read_ops_nolock(mtd, from, ops);
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001497 else
1498 ret = onenand_read_oob_nolock(mtd, from, ops);
1499 onenand_release_device(mtd);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001500
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001501 return ret;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001502}
1503
Kyungmin Park211ac752007-02-07 12:15:01 +09001504/**
1505 * onenand_bbt_wait - [DEFAULT] wait until the command is done
1506 * @param mtd MTD device structure
1507 * @param state state to select the max. timeout value
1508 *
1509 * Wait for command done.
1510 */
1511static int onenand_bbt_wait(struct mtd_info *mtd, int state)
1512{
1513 struct onenand_chip *this = mtd->priv;
1514 unsigned long timeout;
Adrian Huntere0c1a922010-12-10 12:04:20 +02001515 unsigned int interrupt, ctrl, ecc, addr1, addr8;
Kyungmin Park211ac752007-02-07 12:15:01 +09001516
1517 /* The 20 msec is enough */
1518 timeout = jiffies + msecs_to_jiffies(20);
1519 while (time_before(jiffies, timeout)) {
1520 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
1521 if (interrupt & ONENAND_INT_MASTER)
1522 break;
1523 }
1524 /* To get correct interrupt status in timeout case */
1525 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
1526 ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
Adrian Huntere0c1a922010-12-10 12:04:20 +02001527 addr1 = this->read_word(this->base + ONENAND_REG_START_ADDRESS1);
1528 addr8 = this->read_word(this->base + ONENAND_REG_START_ADDRESS8);
Kyungmin Park211ac752007-02-07 12:15:01 +09001529
Kyungmin Park211ac752007-02-07 12:15:01 +09001530 if (interrupt & ONENAND_INT_READ) {
Adrian Huntere0c1a922010-12-10 12:04:20 +02001531 ecc = onenand_read_ecc(this);
Kyungmin Park83973b82008-05-29 14:52:40 +09001532 if (ecc & ONENAND_ECC_2BIT_ALL) {
Adrian Huntere0c1a922010-12-10 12:04:20 +02001533 printk(KERN_DEBUG "%s: ecc 0x%04x ctrl 0x%04x "
1534 "intr 0x%04x addr1 %#x addr8 %#x\n",
1535 __func__, ecc, ctrl, interrupt, addr1, addr8);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001536 return ONENAND_BBT_READ_ECC_ERROR;
Kyungmin Park83973b82008-05-29 14:52:40 +09001537 }
Kyungmin Park211ac752007-02-07 12:15:01 +09001538 } else {
Adrian Huntere0c1a922010-12-10 12:04:20 +02001539 printk(KERN_ERR "%s: read timeout! ctrl 0x%04x "
1540 "intr 0x%04x addr1 %#x addr8 %#x\n",
1541 __func__, ctrl, interrupt, addr1, addr8);
Kyungmin Park211ac752007-02-07 12:15:01 +09001542 return ONENAND_BBT_READ_FATAL_ERROR;
1543 }
1544
Kyungmin Park83973b82008-05-29 14:52:40 +09001545 /* Initial bad block case: 0x2400 or 0x0400 */
1546 if (ctrl & ONENAND_CTRL_ERROR) {
Adrian Huntere0c1a922010-12-10 12:04:20 +02001547 printk(KERN_DEBUG "%s: ctrl 0x%04x intr 0x%04x addr1 %#x "
1548 "addr8 %#x\n", __func__, ctrl, interrupt, addr1, addr8);
Kyungmin Park83973b82008-05-29 14:52:40 +09001549 return ONENAND_BBT_READ_ERROR;
1550 }
1551
Kyungmin Park211ac752007-02-07 12:15:01 +09001552 return 0;
1553}
1554
1555/**
1556 * onenand_bbt_read_oob - [MTD Interface] OneNAND read out-of-band for bbt scan
1557 * @param mtd MTD device structure
1558 * @param from offset to read from
Kyungmin Parke3da8062007-02-15 09:36:39 +09001559 * @param ops oob operation description structure
Kyungmin Park211ac752007-02-07 12:15:01 +09001560 *
1561 * OneNAND read out-of-band data from the spare area for bbt scan
1562 */
1563int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
1564 struct mtd_oob_ops *ops)
1565{
1566 struct onenand_chip *this = mtd->priv;
1567 int read = 0, thislen, column;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001568 int ret = 0, readcmd;
Kyungmin Park211ac752007-02-07 12:15:01 +09001569 size_t len = ops->ooblen;
1570 u_char *buf = ops->oobbuf;
1571
Brian Norris0a32a102011-07-19 10:06:10 -07001572 pr_debug("%s: from = 0x%08x, len = %zi\n", __func__, (unsigned int)from,
1573 len);
Kyungmin Park211ac752007-02-07 12:15:01 +09001574
1575 /* Initialize return value */
1576 ops->oobretlen = 0;
1577
1578 /* Do not allow reads past end of device */
1579 if (unlikely((from + len) > mtd->size)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301580 printk(KERN_ERR "%s: Attempt read beyond end of device\n",
1581 __func__);
Kyungmin Park211ac752007-02-07 12:15:01 +09001582 return ONENAND_BBT_READ_FATAL_ERROR;
1583 }
1584
1585 /* Grab the lock and see if the device is available */
1586 onenand_get_device(mtd, FL_READING);
1587
1588 column = from & (mtd->oobsize - 1);
1589
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001590 readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001591
Kyungmin Park211ac752007-02-07 12:15:01 +09001592 while (read < len) {
1593 cond_resched();
1594
1595 thislen = mtd->oobsize - column;
1596 thislen = min_t(int, thislen, len);
1597
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001598 this->command(mtd, readcmd, from, mtd->oobsize);
Kyungmin Park211ac752007-02-07 12:15:01 +09001599
1600 onenand_update_bufferram(mtd, from, 0);
1601
Kyungmin Park31bb9992009-05-12 13:46:57 -07001602 ret = this->bbt_wait(mtd, FL_READING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001603 if (unlikely(ret))
1604 ret = onenand_recover_lsb(mtd, from, ret);
1605
Kyungmin Park211ac752007-02-07 12:15:01 +09001606 if (ret)
1607 break;
1608
1609 this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
1610 read += thislen;
1611 if (read == len)
1612 break;
1613
1614 buf += thislen;
1615
1616 /* Read more? */
1617 if (read < len) {
1618 /* Update Page size */
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001619 from += this->writesize;
Kyungmin Park211ac752007-02-07 12:15:01 +09001620 column = 0;
1621 }
1622 }
1623
1624 /* Deselect and wake up anyone waiting on the device */
1625 onenand_release_device(mtd);
1626
1627 ops->oobretlen = read;
1628 return ret;
1629}
1630
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001631#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
1632/**
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001633 * onenand_verify_oob - [GENERIC] verify the oob contents after a write
1634 * @param mtd MTD device structure
1635 * @param buf the databuffer to verify
1636 * @param to offset to read from
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001637 */
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001638static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to)
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001639{
1640 struct onenand_chip *this = mtd->priv;
Kyungmin Park69d79182007-12-14 14:47:21 +09001641 u_char *oob_buf = this->oob_buf;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001642 int status, i, readcmd;
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001643
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001644 readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001645
1646 this->command(mtd, readcmd, to, mtd->oobsize);
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001647 onenand_update_bufferram(mtd, to, 0);
1648 status = this->wait(mtd, FL_READING);
1649 if (status)
1650 return status;
1651
Kyungmin Park69d79182007-12-14 14:47:21 +09001652 this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
Kyungmin Park91014e92007-02-12 10:34:39 +09001653 for (i = 0; i < mtd->oobsize; i++)
Kyungmin Park69d79182007-12-14 14:47:21 +09001654 if (buf[i] != 0xFF && buf[i] != oob_buf[i])
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001655 return -EBADMSG;
1656
1657 return 0;
1658}
1659
1660/**
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001661 * onenand_verify - [GENERIC] verify the chip contents after a write
1662 * @param mtd MTD device structure
1663 * @param buf the databuffer to verify
1664 * @param addr offset to read from
1665 * @param len number of bytes to read and compare
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001666 */
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001667static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, size_t len)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001668{
1669 struct onenand_chip *this = mtd->priv;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001670 int ret = 0;
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001671 int thislen, column;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001672
Roman Tereshonkove6da8562011-02-08 12:02:42 +02001673 column = addr & (this->writesize - 1);
1674
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001675 while (len != 0) {
Roman Tereshonkove6da8562011-02-08 12:02:42 +02001676 thislen = min_t(int, this->writesize - column, len);
Kyungmin Park60d84f92006-12-22 16:21:54 +09001677
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001678 this->command(mtd, ONENAND_CMD_READ, addr, this->writesize);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001679
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001680 onenand_update_bufferram(mtd, addr, 0);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001681
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001682 ret = this->wait(mtd, FL_READING);
1683 if (ret)
1684 return ret;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001685
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001686 onenand_update_bufferram(mtd, addr, 1);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001687
Kyungmin Park3328dc32010-04-28 17:46:47 +02001688 this->read_bufferram(mtd, ONENAND_DATARAM, this->verify_buf, 0, mtd->writesize);
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001689
Roman Tereshonkove6da8562011-02-08 12:02:42 +02001690 if (memcmp(buf, this->verify_buf + column, thislen))
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001691 return -EBADMSG;
1692
1693 len -= thislen;
1694 buf += thislen;
1695 addr += thislen;
Roman Tereshonkove6da8562011-02-08 12:02:42 +02001696 column = 0;
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001697 }
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +00001698
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001699 return 0;
1700}
1701#else
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001702#define onenand_verify(...) (0)
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001703#define onenand_verify_oob(...) (0)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001704#endif
1705
Kyungmin Park60d84f92006-12-22 16:21:54 +09001706#define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001707
Richard Purdie6c77fd642008-02-06 10:18:22 +00001708static void onenand_panic_wait(struct mtd_info *mtd)
1709{
1710 struct onenand_chip *this = mtd->priv;
1711 unsigned int interrupt;
1712 int i;
1713
1714 for (i = 0; i < 2000; i++) {
1715 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
1716 if (interrupt & ONENAND_INT_MASTER)
1717 break;
1718 udelay(10);
1719 }
1720}
1721
1722/**
1723 * onenand_panic_write - [MTD Interface] write buffer to FLASH in a panic context
1724 * @param mtd MTD device structure
1725 * @param to offset to write to
1726 * @param len number of bytes to write
1727 * @param retlen pointer to variable to store the number of written bytes
1728 * @param buf the data to write
1729 *
1730 * Write with ECC
1731 */
1732static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
1733 size_t *retlen, const u_char *buf)
1734{
1735 struct onenand_chip *this = mtd->priv;
1736 int column, subpage;
1737 int written = 0;
Richard Purdie6c77fd642008-02-06 10:18:22 +00001738
1739 if (this->state == FL_PM_SUSPENDED)
1740 return -EBUSY;
1741
1742 /* Wait for any existing operation to clear */
1743 onenand_panic_wait(mtd);
1744
Brian Norris0a32a102011-07-19 10:06:10 -07001745 pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to,
1746 (int)len);
Richard Purdie6c77fd642008-02-06 10:18:22 +00001747
Richard Purdie6c77fd642008-02-06 10:18:22 +00001748 /* Reject writes, which are not page aligned */
Roel Kluinb73d7e432008-02-16 18:14:35 +01001749 if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301750 printk(KERN_ERR "%s: Attempt to write not page aligned data\n",
1751 __func__);
Richard Purdie6c77fd642008-02-06 10:18:22 +00001752 return -EINVAL;
1753 }
1754
1755 column = to & (mtd->writesize - 1);
1756
1757 /* Loop until all data write */
1758 while (written < len) {
1759 int thislen = min_t(int, mtd->writesize - column, len - written);
1760 u_char *wbuf = (u_char *) buf;
1761
1762 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
1763
1764 /* Partial page write */
1765 subpage = thislen < mtd->writesize;
1766 if (subpage) {
1767 memset(this->page_buf, 0xff, mtd->writesize);
1768 memcpy(this->page_buf + column, buf, thislen);
1769 wbuf = this->page_buf;
1770 }
1771
1772 this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
1773 this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);
1774
1775 this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
1776
1777 onenand_panic_wait(mtd);
1778
1779 /* In partial page write we don't update bufferram */
Brian Norris7f2a7ce2015-02-28 02:02:25 -08001780 onenand_update_bufferram(mtd, to, !subpage);
Richard Purdie6c77fd642008-02-06 10:18:22 +00001781 if (ONENAND_IS_2PLANE(this)) {
1782 ONENAND_SET_BUFFERRAM1(this);
Brian Norris7f2a7ce2015-02-28 02:02:25 -08001783 onenand_update_bufferram(mtd, to + this->writesize, !subpage);
Richard Purdie6c77fd642008-02-06 10:18:22 +00001784 }
1785
1786 written += thislen;
1787
1788 if (written == len)
1789 break;
1790
1791 column = 0;
1792 to += thislen;
1793 buf += thislen;
1794 }
1795
1796 *retlen = written;
Brian Norris7f2a7ce2015-02-28 02:02:25 -08001797 return 0;
Richard Purdie6c77fd642008-02-06 10:18:22 +00001798}
1799
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001800/**
Brian Norris7854d3f2011-06-23 14:12:08 -07001801 * onenand_fill_auto_oob - [INTERN] oob auto-placement transfer
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001802 * @param mtd MTD device structure
1803 * @param oob_buf oob buffer
1804 * @param buf source address
1805 * @param column oob offset to write to
1806 * @param thislen oob length to write
1807 */
1808static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
1809 const u_char *buf, int column, int thislen)
1810{
1811 struct onenand_chip *this = mtd->priv;
1812 struct nand_oobfree *free;
1813 int writecol = column;
1814 int writeend = column + thislen;
1815 int lastgap = 0;
Kyungmin Parkad286342007-03-23 10:19:52 +09001816 unsigned int i;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001817
Kyungmin Parkad286342007-03-23 10:19:52 +09001818 free = this->ecclayout->oobfree;
1819 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001820 if (writecol >= lastgap)
1821 writecol += free->offset - lastgap;
1822 if (writeend >= lastgap)
1823 writeend += free->offset - lastgap;
1824 lastgap = free->offset + free->length;
1825 }
Kyungmin Parkad286342007-03-23 10:19:52 +09001826 free = this->ecclayout->oobfree;
1827 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001828 int free_end = free->offset + free->length;
1829 if (free->offset < writeend && free_end > writecol) {
1830 int st = max_t(int,free->offset,writecol);
1831 int ed = min_t(int,free_end,writeend);
1832 int n = ed - st;
1833 memcpy(oob_buf + st, buf, n);
1834 buf += n;
Adrian Hunterc36c46d2007-03-23 17:16:22 +09001835 } else if (column == 0)
Kyungmin Park5bc399e2007-03-09 09:41:07 +09001836 break;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001837 }
1838 return 0;
1839}
1840
1841/**
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001842 * onenand_write_ops_nolock - [OneNAND Interface] write main and/or out-of-band
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001843 * @param mtd MTD device structure
1844 * @param to offset to write to
1845 * @param ops oob operation description structure
1846 *
1847 * Write main and/or oob with ECC
1848 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001849static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001850 struct mtd_oob_ops *ops)
1851{
1852 struct onenand_chip *this = mtd->priv;
Kyungmin Park9ce96902008-11-17 17:54:28 +09001853 int written = 0, column, thislen = 0, subpage = 0;
1854 int prev = 0, prevlen = 0, prev_subpage = 0, first = 1;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001855 int oobwritten = 0, oobcolumn, thisooblen, oobsize;
1856 size_t len = ops->len;
1857 size_t ooblen = ops->ooblen;
1858 const u_char *buf = ops->datbuf;
1859 const u_char *oob = ops->oobbuf;
1860 u_char *oobbuf;
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02001861 int ret = 0, cmd;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001862
Brian Norris0a32a102011-07-19 10:06:10 -07001863 pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to,
1864 (int)len);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001865
1866 /* Initialize retlen, in case of early exit */
1867 ops->retlen = 0;
1868 ops->oobretlen = 0;
1869
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001870 /* Reject writes, which are not page aligned */
Roel Kluinb73d7e432008-02-16 18:14:35 +01001871 if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301872 printk(KERN_ERR "%s: Attempt to write not page aligned data\n",
1873 __func__);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001874 return -EINVAL;
1875 }
1876
Kyungmin Park9ce96902008-11-17 17:54:28 +09001877 /* Check zero length */
1878 if (!len)
1879 return 0;
Boris BREZILLON29f10582016-03-07 10:46:52 +01001880 oobsize = mtd_oobavail(mtd, ops);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001881 oobcolumn = to & (mtd->oobsize - 1);
1882
1883 column = to & (mtd->writesize - 1);
1884
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001885 /* Loop until all data write */
Kyungmin Park9ce96902008-11-17 17:54:28 +09001886 while (1) {
1887 if (written < len) {
1888 u_char *wbuf = (u_char *) buf;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001889
Kyungmin Park9ce96902008-11-17 17:54:28 +09001890 thislen = min_t(int, mtd->writesize - column, len - written);
1891 thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001892
Kyungmin Park9ce96902008-11-17 17:54:28 +09001893 cond_resched();
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001894
Kyungmin Park9ce96902008-11-17 17:54:28 +09001895 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001896
Kyungmin Park9ce96902008-11-17 17:54:28 +09001897 /* Partial page write */
1898 subpage = thislen < mtd->writesize;
1899 if (subpage) {
1900 memset(this->page_buf, 0xff, mtd->writesize);
1901 memcpy(this->page_buf + column, buf, thislen);
1902 wbuf = this->page_buf;
1903 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001904
Kyungmin Park9ce96902008-11-17 17:54:28 +09001905 this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001906
Kyungmin Park9ce96902008-11-17 17:54:28 +09001907 if (oob) {
1908 oobbuf = this->oob_buf;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001909
Kyungmin Park9ce96902008-11-17 17:54:28 +09001910 /* We send data to spare ram with oobsize
1911 * to prevent byte access */
1912 memset(oobbuf, 0xff, mtd->oobsize);
Brian Norris0612b9d2011-08-30 18:45:40 -07001913 if (ops->mode == MTD_OPS_AUTO_OOB)
Kyungmin Park9ce96902008-11-17 17:54:28 +09001914 onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
1915 else
1916 memcpy(oobbuf + oobcolumn, oob, thisooblen);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001917
Kyungmin Park9ce96902008-11-17 17:54:28 +09001918 oobwritten += thisooblen;
1919 oob += thisooblen;
1920 oobcolumn = 0;
1921 } else
1922 oobbuf = (u_char *) ffchars;
1923
1924 this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001925 } else
Kyungmin Park9ce96902008-11-17 17:54:28 +09001926 ONENAND_SET_NEXT_BUFFERRAM(this);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001927
Kyungmin Park9ce96902008-11-17 17:54:28 +09001928 /*
Mika Korhonen492e1502009-06-09 21:52:35 +03001929 * 2 PLANE, MLC, and Flex-OneNAND do not support
1930 * write-while-program feature.
Kyungmin Park9ce96902008-11-17 17:54:28 +09001931 */
Kyungmin Park6a88c472010-04-28 17:46:45 +02001932 if (!ONENAND_IS_2PLANE(this) && !ONENAND_IS_4KB_PAGE(this) && !first) {
Kyungmin Park9ce96902008-11-17 17:54:28 +09001933 ONENAND_SET_PREV_BUFFERRAM(this);
1934
1935 ret = this->wait(mtd, FL_WRITING);
1936
1937 /* In partial page write we don't update bufferram */
1938 onenand_update_bufferram(mtd, prev, !ret && !prev_subpage);
1939 if (ret) {
1940 written -= prevlen;
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301941 printk(KERN_ERR "%s: write failed %d\n",
1942 __func__, ret);
Kyungmin Park9ce96902008-11-17 17:54:28 +09001943 break;
1944 }
1945
1946 if (written == len) {
1947 /* Only check verify write turn on */
1948 ret = onenand_verify(mtd, buf - len, to - len, len);
1949 if (ret)
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301950 printk(KERN_ERR "%s: verify failed %d\n",
1951 __func__, ret);
Kyungmin Park9ce96902008-11-17 17:54:28 +09001952 break;
1953 }
1954
1955 ONENAND_SET_NEXT_BUFFERRAM(this);
1956 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001957
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02001958 this->ongoing = 0;
1959 cmd = ONENAND_CMD_PROG;
1960
1961 /* Exclude 1st OTP and OTP blocks for cache program feature */
1962 if (ONENAND_IS_CACHE_PROGRAM(this) &&
1963 likely(onenand_block(this, to) != 0) &&
1964 ONENAND_IS_4KB_PAGE(this) &&
1965 ((written + thislen) < len)) {
1966 cmd = ONENAND_CMD_2X_CACHE_PROG;
1967 this->ongoing = 1;
1968 }
1969
1970 this->command(mtd, cmd, to, mtd->writesize);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001971
Kyungmin Park9ce96902008-11-17 17:54:28 +09001972 /*
1973 * 2 PLANE, MLC, and Flex-OneNAND wait here
1974 */
Kyungmin Park6a88c472010-04-28 17:46:45 +02001975 if (ONENAND_IS_2PLANE(this) || ONENAND_IS_4KB_PAGE(this)) {
Kyungmin Park9ce96902008-11-17 17:54:28 +09001976 ret = this->wait(mtd, FL_WRITING);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001977
Kyungmin Park9ce96902008-11-17 17:54:28 +09001978 /* In partial page write we don't update bufferram */
1979 onenand_update_bufferram(mtd, to, !ret && !subpage);
1980 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301981 printk(KERN_ERR "%s: write failed %d\n",
1982 __func__, ret);
Kyungmin Park9ce96902008-11-17 17:54:28 +09001983 break;
1984 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001985
Kyungmin Park9ce96902008-11-17 17:54:28 +09001986 /* Only check verify write turn on */
1987 ret = onenand_verify(mtd, buf, to, thislen);
1988 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301989 printk(KERN_ERR "%s: verify failed %d\n",
1990 __func__, ret);
Kyungmin Park9ce96902008-11-17 17:54:28 +09001991 break;
1992 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001993
Kyungmin Park9ce96902008-11-17 17:54:28 +09001994 written += thislen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001995
Kyungmin Park9ce96902008-11-17 17:54:28 +09001996 if (written == len)
1997 break;
1998
1999 } else
2000 written += thislen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002001
2002 column = 0;
Kyungmin Park9ce96902008-11-17 17:54:28 +09002003 prev_subpage = subpage;
2004 prev = to;
2005 prevlen = thislen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002006 to += thislen;
2007 buf += thislen;
Kyungmin Park9ce96902008-11-17 17:54:28 +09002008 first = 0;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002009 }
2010
Kyungmin Park9ce96902008-11-17 17:54:28 +09002011 /* In error case, clear all bufferrams */
2012 if (written != len)
2013 onenand_invalidate_bufferram(mtd, 0, -1);
2014
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002015 ops->retlen = written;
Kyungmin Park9ce96902008-11-17 17:54:28 +09002016 ops->oobretlen = oobwritten;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002017
2018 return ret;
2019}
2020
2021
2022/**
Brian Norris7854d3f2011-06-23 14:12:08 -07002023 * onenand_write_oob_nolock - [INTERN] OneNAND write out-of-band
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002024 * @param mtd MTD device structure
2025 * @param to offset to write to
2026 * @param len number of bytes to write
2027 * @param retlen pointer to variable to store the number of written bytes
2028 * @param buf the data to write
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002029 * @param mode operation mode
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002030 *
2031 * OneNAND write out-of-band
2032 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002033static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
2034 struct mtd_oob_ops *ops)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002035{
2036 struct onenand_chip *this = mtd->priv;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002037 int column, ret = 0, oobsize;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002038 int written = 0, oobcmd;
Kyungmin Park91014e92007-02-12 10:34:39 +09002039 u_char *oobbuf;
Kyungmin Park12f77c92007-08-30 09:36:05 +09002040 size_t len = ops->ooblen;
2041 const u_char *buf = ops->oobbuf;
Brian Norris905c6bc2011-08-30 18:45:39 -07002042 unsigned int mode = ops->mode;
Kyungmin Park12f77c92007-08-30 09:36:05 +09002043
2044 to += ops->ooboffs;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002045
Brian Norris0a32a102011-07-19 10:06:10 -07002046 pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to,
2047 (int)len);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002048
2049 /* Initialize retlen, in case of early exit */
Kyungmin Park12f77c92007-08-30 09:36:05 +09002050 ops->oobretlen = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002051
Brian Norris0612b9d2011-08-30 18:45:40 -07002052 if (mode == MTD_OPS_AUTO_OOB)
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +01002053 oobsize = mtd->oobavail;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002054 else
2055 oobsize = mtd->oobsize;
2056
2057 column = to & (mtd->oobsize - 1);
2058
2059 if (unlikely(column >= oobsize)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302060 printk(KERN_ERR "%s: Attempted to start write outside oob\n",
2061 __func__);
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002062 return -EINVAL;
2063 }
2064
Adrian Hunter52e42002007-02-06 09:15:39 +09002065 /* For compatibility with NAND: Do not allow write past end of page */
Kyungmin Park91014e92007-02-12 10:34:39 +09002066 if (unlikely(column + len > oobsize)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302067 printk(KERN_ERR "%s: Attempt to write past end of page\n",
2068 __func__);
Adrian Hunter52e42002007-02-06 09:15:39 +09002069 return -EINVAL;
2070 }
2071
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002072 /* Do not allow reads past end of device */
2073 if (unlikely(to >= mtd->size ||
2074 column + len > ((mtd->size >> this->page_shift) -
2075 (to >> this->page_shift)) * oobsize)) {
David Woodhouse80327472009-10-05 08:30:04 +01002076 printk(KERN_ERR "%s: Attempted to write past end of device\n",
2077 __func__);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002078 return -EINVAL;
2079 }
2080
Kyungmin Park470bc842007-03-09 10:08:11 +09002081 oobbuf = this->oob_buf;
Kyungmin Park91014e92007-02-12 10:34:39 +09002082
Kyungmin Park8a8f6322010-12-02 09:24:16 +09002083 oobcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002084
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002085 /* Loop until all data write */
2086 while (written < len) {
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002087 int thislen = min_t(int, oobsize, len - written);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002088
Artem Bityutskiy61a7e192006-12-26 16:41:24 +09002089 cond_resched();
2090
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002091 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize);
2092
Kyungmin Park34c10602006-05-12 17:02:46 +03002093 /* We send data to spare ram with oobsize
2094 * to prevent byte access */
Kyungmin Park91014e92007-02-12 10:34:39 +09002095 memset(oobbuf, 0xff, mtd->oobsize);
Brian Norris0612b9d2011-08-30 18:45:40 -07002096 if (mode == MTD_OPS_AUTO_OOB)
Kyungmin Park91014e92007-02-12 10:34:39 +09002097 onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen);
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002098 else
Kyungmin Park91014e92007-02-12 10:34:39 +09002099 memcpy(oobbuf + column, buf, thislen);
2100 this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002101
Kyungmin Park8a8f6322010-12-02 09:24:16 +09002102 if (ONENAND_IS_4KB_PAGE(this)) {
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002103 /* Set main area of DataRAM to 0xff*/
2104 memset(this->page_buf, 0xff, mtd->writesize);
2105 this->write_bufferram(mtd, ONENAND_DATARAM,
2106 this->page_buf, 0, mtd->writesize);
2107 }
2108
2109 this->command(mtd, oobcmd, to, mtd->oobsize);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002110
2111 onenand_update_bufferram(mtd, to, 0);
Kyungmin Parkee9745f2007-06-30 13:57:49 +09002112 if (ONENAND_IS_2PLANE(this)) {
2113 ONENAND_SET_BUFFERRAM1(this);
2114 onenand_update_bufferram(mtd, to + this->writesize, 0);
2115 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002116
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002117 ret = this->wait(mtd, FL_WRITING);
2118 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302119 printk(KERN_ERR "%s: write failed %d\n", __func__, ret);
Kyungmin Park5b4246f2007-02-02 09:39:21 +09002120 break;
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002121 }
2122
Kyungmin Park91014e92007-02-12 10:34:39 +09002123 ret = onenand_verify_oob(mtd, oobbuf, to);
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002124 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302125 printk(KERN_ERR "%s: verify failed %d\n",
2126 __func__, ret);
Kyungmin Park5b4246f2007-02-02 09:39:21 +09002127 break;
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002128 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002129
2130 written += thislen;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002131 if (written == len)
2132 break;
2133
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002134 to += mtd->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002135 buf += thislen;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002136 column = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002137 }
2138
Kyungmin Park12f77c92007-08-30 09:36:05 +09002139 ops->oobretlen = written;
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +00002140
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002141 return ret;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002142}
2143
2144/**
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002145 * onenand_write - [MTD Interface] write buffer to FLASH
2146 * @param mtd MTD device structure
2147 * @param to offset to write to
2148 * @param len number of bytes to write
2149 * @param retlen pointer to variable to store the number of written bytes
2150 * @param buf the data to write
2151 *
2152 * Write with ECC
2153 */
2154static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
2155 size_t *retlen, const u_char *buf)
2156{
2157 struct mtd_oob_ops ops = {
2158 .len = len,
2159 .ooblen = 0,
2160 .datbuf = (u_char *) buf,
2161 .oobbuf = NULL,
2162 };
2163 int ret;
2164
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002165 onenand_get_device(mtd, FL_WRITING);
2166 ret = onenand_write_ops_nolock(mtd, to, &ops);
2167 onenand_release_device(mtd);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002168
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002169 *retlen = ops.retlen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002170 return ret;
2171}
2172
2173/**
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02002174 * onenand_write_oob - [MTD Interface] NAND write data and/or out-of-band
Kyungmin Parke3da8062007-02-15 09:36:39 +09002175 * @param mtd: MTD device structure
2176 * @param to: offset to write
2177 * @param ops: oob operation description structure
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02002178 */
2179static int onenand_write_oob(struct mtd_info *mtd, loff_t to,
2180 struct mtd_oob_ops *ops)
2181{
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002182 int ret;
2183
Kyungmin Park4f4fad22007-02-02 09:22:21 +09002184 switch (ops->mode) {
Brian Norris0612b9d2011-08-30 18:45:40 -07002185 case MTD_OPS_PLACE_OOB:
2186 case MTD_OPS_AUTO_OOB:
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002187 break;
Brian Norris0612b9d2011-08-30 18:45:40 -07002188 case MTD_OPS_RAW:
Kyungmin Park4f4fad22007-02-02 09:22:21 +09002189 /* Not implemented yet */
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002190 default:
2191 return -EINVAL;
2192 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002193
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002194 onenand_get_device(mtd, FL_WRITING);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002195 if (ops->datbuf)
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002196 ret = onenand_write_ops_nolock(mtd, to, ops);
2197 else
2198 ret = onenand_write_oob_nolock(mtd, to, ops);
2199 onenand_release_device(mtd);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002200
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002201 return ret;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02002202}
2203
2204/**
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002205 * onenand_block_isbad_nolock - [GENERIC] Check if a block is marked bad
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002206 * @param mtd MTD device structure
2207 * @param ofs offset from device start
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002208 * @param allowbbt 1, if its allowed to access the bbt area
2209 *
2210 * Check, if the block is bad. Either by reading the bad block table or
2211 * calling of the scan function.
2212 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002213static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int allowbbt)
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002214{
2215 struct onenand_chip *this = mtd->priv;
2216 struct bbm_info *bbm = this->bbm;
2217
2218 /* Return info from the table */
2219 return bbm->isbad_bbt(mtd, ofs, allowbbt);
2220}
2221
Mika Korhonen72073022009-10-23 07:50:43 +02002222
2223static int onenand_multiblock_erase_verify(struct mtd_info *mtd,
2224 struct erase_info *instr)
2225{
2226 struct onenand_chip *this = mtd->priv;
2227 loff_t addr = instr->addr;
2228 int len = instr->len;
2229 unsigned int block_size = (1 << this->erase_shift);
2230 int ret = 0;
2231
2232 while (len) {
2233 this->command(mtd, ONENAND_CMD_ERASE_VERIFY, addr, block_size);
2234 ret = this->wait(mtd, FL_VERIFYING_ERASE);
2235 if (ret) {
2236 printk(KERN_ERR "%s: Failed verify, block %d\n",
2237 __func__, onenand_block(this, addr));
2238 instr->state = MTD_ERASE_FAILED;
2239 instr->fail_addr = addr;
2240 return -1;
2241 }
2242 len -= block_size;
2243 addr += block_size;
2244 }
2245 return 0;
2246}
2247
2248/**
Brian Norris7854d3f2011-06-23 14:12:08 -07002249 * onenand_multiblock_erase - [INTERN] erase block(s) using multiblock erase
Mika Korhonen72073022009-10-23 07:50:43 +02002250 * @param mtd MTD device structure
2251 * @param instr erase instruction
2252 * @param region erase region
2253 *
2254 * Erase one or more blocks up to 64 block at a time
2255 */
2256static int onenand_multiblock_erase(struct mtd_info *mtd,
2257 struct erase_info *instr,
2258 unsigned int block_size)
2259{
2260 struct onenand_chip *this = mtd->priv;
2261 loff_t addr = instr->addr;
2262 int len = instr->len;
2263 int eb_count = 0;
2264 int ret = 0;
2265 int bdry_block = 0;
2266
2267 instr->state = MTD_ERASING;
2268
2269 if (ONENAND_IS_DDP(this)) {
2270 loff_t bdry_addr = this->chipsize >> 1;
2271 if (addr < bdry_addr && (addr + len) > bdry_addr)
2272 bdry_block = bdry_addr >> this->erase_shift;
2273 }
2274
2275 /* Pre-check bbs */
2276 while (len) {
2277 /* Check if we have a bad block, we do not erase bad blocks */
2278 if (onenand_block_isbad_nolock(mtd, addr, 0)) {
2279 printk(KERN_WARNING "%s: attempt to erase a bad block "
2280 "at addr 0x%012llx\n",
2281 __func__, (unsigned long long) addr);
2282 instr->state = MTD_ERASE_FAILED;
2283 return -EIO;
2284 }
2285 len -= block_size;
2286 addr += block_size;
2287 }
2288
2289 len = instr->len;
2290 addr = instr->addr;
2291
2292 /* loop over 64 eb batches */
2293 while (len) {
2294 struct erase_info verify_instr = *instr;
2295 int max_eb_count = MB_ERASE_MAX_BLK_COUNT;
2296
2297 verify_instr.addr = addr;
2298 verify_instr.len = 0;
2299
2300 /* do not cross chip boundary */
2301 if (bdry_block) {
2302 int this_block = (addr >> this->erase_shift);
2303
2304 if (this_block < bdry_block) {
2305 max_eb_count = min(max_eb_count,
2306 (bdry_block - this_block));
2307 }
2308 }
2309
2310 eb_count = 0;
2311
2312 while (len > block_size && eb_count < (max_eb_count - 1)) {
2313 this->command(mtd, ONENAND_CMD_MULTIBLOCK_ERASE,
2314 addr, block_size);
2315 onenand_invalidate_bufferram(mtd, addr, block_size);
2316
2317 ret = this->wait(mtd, FL_PREPARING_ERASE);
2318 if (ret) {
2319 printk(KERN_ERR "%s: Failed multiblock erase, "
2320 "block %d\n", __func__,
2321 onenand_block(this, addr));
2322 instr->state = MTD_ERASE_FAILED;
2323 instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
2324 return -EIO;
2325 }
2326
2327 len -= block_size;
2328 addr += block_size;
2329 eb_count++;
2330 }
2331
2332 /* last block of 64-eb series */
2333 cond_resched();
2334 this->command(mtd, ONENAND_CMD_ERASE, addr, block_size);
2335 onenand_invalidate_bufferram(mtd, addr, block_size);
2336
2337 ret = this->wait(mtd, FL_ERASING);
2338 /* Check if it is write protected */
2339 if (ret) {
2340 printk(KERN_ERR "%s: Failed erase, block %d\n",
2341 __func__, onenand_block(this, addr));
2342 instr->state = MTD_ERASE_FAILED;
2343 instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
2344 return -EIO;
2345 }
2346
2347 len -= block_size;
2348 addr += block_size;
2349 eb_count++;
2350
2351 /* verify */
2352 verify_instr.len = eb_count * block_size;
2353 if (onenand_multiblock_erase_verify(mtd, &verify_instr)) {
2354 instr->state = verify_instr.state;
2355 instr->fail_addr = verify_instr.fail_addr;
2356 return -EIO;
2357 }
2358
2359 }
2360 return 0;
2361}
2362
2363
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002364/**
Brian Norris7854d3f2011-06-23 14:12:08 -07002365 * onenand_block_by_block_erase - [INTERN] erase block(s) using regular erase
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002366 * @param mtd MTD device structure
2367 * @param instr erase instruction
Mika Korhonen73885ae2009-10-23 07:50:42 +02002368 * @param region erase region
2369 * @param block_size erase block size
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002370 *
Mika Korhonen73885ae2009-10-23 07:50:42 +02002371 * Erase one or more blocks one block at a time
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002372 */
Mika Korhonen73885ae2009-10-23 07:50:42 +02002373static int onenand_block_by_block_erase(struct mtd_info *mtd,
2374 struct erase_info *instr,
2375 struct mtd_erase_region_info *region,
2376 unsigned int block_size)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002377{
2378 struct onenand_chip *this = mtd->priv;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002379 loff_t addr = instr->addr;
Mika Korhonen73885ae2009-10-23 07:50:42 +02002380 int len = instr->len;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002381 loff_t region_end = 0;
Mika Korhonen73885ae2009-10-23 07:50:42 +02002382 int ret = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002383
Mika Korhonen73885ae2009-10-23 07:50:42 +02002384 if (region) {
2385 /* region is set for Flex-OneNAND */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002386 region_end = region->offset + region->erasesize * region->numblocks;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002387 }
2388
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002389 instr->state = MTD_ERASING;
2390
Mika Korhonen73885ae2009-10-23 07:50:42 +02002391 /* Loop through the blocks */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002392 while (len) {
Artem Bityutskiy61a7e192006-12-26 16:41:24 +09002393 cond_resched();
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002394
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002395 /* Check if we have a bad block, we do not erase bad blocks */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002396 if (onenand_block_isbad_nolock(mtd, addr, 0)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302397 printk(KERN_WARNING "%s: attempt to erase a bad block "
2398 "at addr 0x%012llx\n",
2399 __func__, (unsigned long long) addr);
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002400 instr->state = MTD_ERASE_FAILED;
Mika Korhonen73885ae2009-10-23 07:50:42 +02002401 return -EIO;
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002402 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002403
2404 this->command(mtd, ONENAND_CMD_ERASE, addr, block_size);
2405
Adrian Hunter480b9df2007-02-07 13:55:19 +02002406 onenand_invalidate_bufferram(mtd, addr, block_size);
2407
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002408 ret = this->wait(mtd, FL_ERASING);
2409 /* Check, if it is write protected */
2410 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302411 printk(KERN_ERR "%s: Failed erase, block %d\n",
2412 __func__, onenand_block(this, addr));
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002413 instr->state = MTD_ERASE_FAILED;
2414 instr->fail_addr = addr;
Mika Korhonen73885ae2009-10-23 07:50:42 +02002415 return -EIO;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002416 }
2417
2418 len -= block_size;
2419 addr += block_size;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002420
john.maxin@nokia.comeff3bba2011-05-06 09:17:21 +00002421 if (region && addr == region_end) {
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002422 if (!len)
2423 break;
2424 region++;
2425
2426 block_size = region->erasesize;
2427 region_end = region->offset + region->erasesize * region->numblocks;
2428
2429 if (len & (block_size - 1)) {
2430 /* FIXME: This should be handled at MTD partitioning level. */
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302431 printk(KERN_ERR "%s: Unaligned address\n",
2432 __func__);
Mika Korhonen73885ae2009-10-23 07:50:42 +02002433 return -EIO;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002434 }
2435 }
Mika Korhonen73885ae2009-10-23 07:50:42 +02002436 }
2437 return 0;
2438}
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002439
Mika Korhonen73885ae2009-10-23 07:50:42 +02002440/**
2441 * onenand_erase - [MTD Interface] erase block(s)
2442 * @param mtd MTD device structure
2443 * @param instr erase instruction
2444 *
2445 * Erase one or more blocks
2446 */
2447static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
2448{
2449 struct onenand_chip *this = mtd->priv;
2450 unsigned int block_size;
2451 loff_t addr = instr->addr;
2452 loff_t len = instr->len;
2453 int ret = 0;
2454 struct mtd_erase_region_info *region = NULL;
2455 loff_t region_offset = 0;
2456
Brian Norris289c0522011-07-19 10:06:09 -07002457 pr_debug("%s: start=0x%012llx, len=%llu\n", __func__,
Brian Norris0a32a102011-07-19 10:06:10 -07002458 (unsigned long long)instr->addr,
2459 (unsigned long long)instr->len);
Mika Korhonen73885ae2009-10-23 07:50:42 +02002460
Mika Korhonen73885ae2009-10-23 07:50:42 +02002461 if (FLEXONENAND(this)) {
2462 /* Find the eraseregion of this address */
2463 int i = flexonenand_region(mtd, addr);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002464
Mika Korhonen73885ae2009-10-23 07:50:42 +02002465 region = &mtd->eraseregions[i];
2466 block_size = region->erasesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002467
Mika Korhonen73885ae2009-10-23 07:50:42 +02002468 /* Start address within region must align on block boundary.
2469 * Erase region's start offset is always block start address.
2470 */
2471 region_offset = region->offset;
2472 } else
2473 block_size = 1 << this->erase_shift;
2474
2475 /* Start address must align on block boundary */
2476 if (unlikely((addr - region_offset) & (block_size - 1))) {
2477 printk(KERN_ERR "%s: Unaligned address\n", __func__);
2478 return -EINVAL;
2479 }
2480
2481 /* Length must align on block boundary */
2482 if (unlikely(len & (block_size - 1))) {
2483 printk(KERN_ERR "%s: Length not block aligned\n", __func__);
2484 return -EINVAL;
2485 }
2486
Mika Korhonen73885ae2009-10-23 07:50:42 +02002487 /* Grab the lock and see if the device is available */
2488 onenand_get_device(mtd, FL_ERASING);
2489
Kyungmin Parkd983c542010-12-06 09:05:18 +09002490 if (ONENAND_IS_4KB_PAGE(this) || region ||
2491 instr->len < MB_ERASE_MIN_BLK_COUNT * block_size) {
Mika Korhonen72073022009-10-23 07:50:43 +02002492 /* region is set for Flex-OneNAND (no mb erase) */
2493 ret = onenand_block_by_block_erase(mtd, instr,
2494 region, block_size);
2495 } else {
2496 ret = onenand_multiblock_erase(mtd, instr, block_size);
2497 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002498
2499 /* Deselect and wake up anyone waiting on the device */
2500 onenand_release_device(mtd);
2501
Adrian Hunter3cd3a862007-10-12 10:34:01 +03002502 /* Do call back function */
Mika Korhonen73885ae2009-10-23 07:50:42 +02002503 if (!ret) {
2504 instr->state = MTD_ERASE_DONE;
Adrian Hunter3cd3a862007-10-12 10:34:01 +03002505 mtd_erase_callback(instr);
Mika Korhonen73885ae2009-10-23 07:50:42 +02002506 }
Adrian Hunter3cd3a862007-10-12 10:34:01 +03002507
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002508 return ret;
2509}
2510
2511/**
2512 * onenand_sync - [MTD Interface] sync
2513 * @param mtd MTD device structure
2514 *
2515 * Sync is actually a wait for chip ready function
2516 */
2517static void onenand_sync(struct mtd_info *mtd)
2518{
Brian Norris289c0522011-07-19 10:06:09 -07002519 pr_debug("%s: called\n", __func__);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002520
2521 /* Grab the lock and see if the device is available */
2522 onenand_get_device(mtd, FL_SYNCING);
2523
2524 /* Release it and go back */
2525 onenand_release_device(mtd);
2526}
2527
2528/**
2529 * onenand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad
2530 * @param mtd MTD device structure
2531 * @param ofs offset relative to mtd start
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002532 *
2533 * Check whether the block is bad
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002534 */
2535static int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs)
2536{
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002537 int ret;
2538
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002539 onenand_get_device(mtd, FL_READING);
2540 ret = onenand_block_isbad_nolock(mtd, ofs, 0);
2541 onenand_release_device(mtd);
2542 return ret;
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002543}
2544
2545/**
2546 * onenand_default_block_markbad - [DEFAULT] mark a block bad
2547 * @param mtd MTD device structure
2548 * @param ofs offset from device start
2549 *
2550 * This is the default implementation, which can be overridden by
2551 * a hardware specific driver.
2552 */
2553static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
2554{
2555 struct onenand_chip *this = mtd->priv;
2556 struct bbm_info *bbm = this->bbm;
2557 u_char buf[2] = {0, 0};
Kyungmin Park12f77c92007-08-30 09:36:05 +09002558 struct mtd_oob_ops ops = {
Brian Norris0612b9d2011-08-30 18:45:40 -07002559 .mode = MTD_OPS_PLACE_OOB,
Kyungmin Park12f77c92007-08-30 09:36:05 +09002560 .ooblen = 2,
2561 .oobbuf = buf,
2562 .ooboffs = 0,
2563 };
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002564 int block;
2565
2566 /* Get block number */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002567 block = onenand_block(this, ofs);
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002568 if (bbm->bbt)
2569 bbm->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
2570
Mika Korhonen492e1502009-06-09 21:52:35 +03002571 /* We write two bytes, so we don't have to mess with 16-bit access */
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002572 ofs += mtd->oobsize + (bbm->badblockpos & ~0x01);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002573 /* FIXME : What to do when marking SLC block in partition
2574 * with MLC erasesize? For now, it is not advisable to
2575 * create partitions containing both SLC and MLC regions.
2576 */
2577 return onenand_write_oob_nolock(mtd, ofs, &ops);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002578}
2579
2580/**
2581 * onenand_block_markbad - [MTD Interface] Mark the block at the given offset as bad
2582 * @param mtd MTD device structure
2583 * @param ofs offset relative to mtd start
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002584 *
2585 * Mark the block as bad
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002586 */
2587static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
2588{
Aaro Koskinen5e64c292016-02-20 22:27:48 +02002589 struct onenand_chip *this = mtd->priv;
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002590 int ret;
2591
2592 ret = onenand_block_isbad(mtd, ofs);
2593 if (ret) {
2594 /* If it was bad already, return success and do nothing */
2595 if (ret > 0)
2596 return 0;
2597 return ret;
2598 }
2599
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002600 onenand_get_device(mtd, FL_WRITING);
Aaro Koskinen5e64c292016-02-20 22:27:48 +02002601 ret = this->block_markbad(mtd, ofs);
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002602 onenand_release_device(mtd);
2603 return ret;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002604}
2605
2606/**
Kyungmin Park08f782b2006-11-16 11:29:39 +09002607 * onenand_do_lock_cmd - [OneNAND Interface] Lock or unlock block(s)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002608 * @param mtd MTD device structure
2609 * @param ofs offset relative to mtd start
Kyungmin Park08f782b2006-11-16 11:29:39 +09002610 * @param len number of bytes to lock or unlock
Kyungmin Parke3da8062007-02-15 09:36:39 +09002611 * @param cmd lock or unlock command
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002612 *
Kyungmin Park08f782b2006-11-16 11:29:39 +09002613 * Lock or unlock one or more blocks
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002614 */
Kyungmin Park08f782b2006-11-16 11:29:39 +09002615static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int cmd)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002616{
2617 struct onenand_chip *this = mtd->priv;
2618 int start, end, block, value, status;
Kyungmin Park08f782b2006-11-16 11:29:39 +09002619 int wp_status_mask;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002620
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002621 start = onenand_block(this, ofs);
2622 end = onenand_block(this, ofs + len) - 1;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002623
Kyungmin Park08f782b2006-11-16 11:29:39 +09002624 if (cmd == ONENAND_CMD_LOCK)
2625 wp_status_mask = ONENAND_WP_LS;
2626 else
2627 wp_status_mask = ONENAND_WP_US;
2628
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002629 /* Continuous lock scheme */
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002630 if (this->options & ONENAND_HAS_CONT_LOCK) {
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002631 /* Set start block address */
2632 this->write_word(start, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
2633 /* Set end block address */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002634 this->write_word(end, this->base + ONENAND_REG_END_BLOCK_ADDRESS);
Kyungmin Park08f782b2006-11-16 11:29:39 +09002635 /* Write lock command */
2636 this->command(mtd, cmd, 0, 0);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002637
2638 /* There's no return value */
Kyungmin Park08f782b2006-11-16 11:29:39 +09002639 this->wait(mtd, FL_LOCKING);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002640
2641 /* Sanity check */
2642 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
2643 & ONENAND_CTRL_ONGO)
2644 continue;
2645
2646 /* Check lock status */
2647 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
Kyungmin Park08f782b2006-11-16 11:29:39 +09002648 if (!(status & wp_status_mask))
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302649 printk(KERN_ERR "%s: wp status = 0x%x\n",
2650 __func__, status);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002651
2652 return 0;
2653 }
2654
2655 /* Block lock scheme */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002656 for (block = start; block < end + 1; block++) {
Kyungmin Park20ba89a2005-12-16 11:17:29 +09002657 /* Set block address */
2658 value = onenand_block_address(this, block);
2659 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
2660 /* Select DataRAM for DDP */
2661 value = onenand_bufferram_address(this, block);
2662 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002663 /* Set start block address */
2664 this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
Kyungmin Park08f782b2006-11-16 11:29:39 +09002665 /* Write lock command */
2666 this->command(mtd, cmd, 0, 0);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002667
2668 /* There's no return value */
Kyungmin Park08f782b2006-11-16 11:29:39 +09002669 this->wait(mtd, FL_LOCKING);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002670
2671 /* Sanity check */
2672 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
2673 & ONENAND_CTRL_ONGO)
2674 continue;
2675
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002676 /* Check lock status */
2677 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
Kyungmin Park08f782b2006-11-16 11:29:39 +09002678 if (!(status & wp_status_mask))
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302679 printk(KERN_ERR "%s: block = %d, wp status = 0x%x\n",
2680 __func__, block, status);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002681 }
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +00002682
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002683 return 0;
2684}
2685
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002686/**
Kyungmin Park08f782b2006-11-16 11:29:39 +09002687 * onenand_lock - [MTD Interface] Lock block(s)
2688 * @param mtd MTD device structure
2689 * @param ofs offset relative to mtd start
2690 * @param len number of bytes to unlock
2691 *
2692 * Lock one or more blocks
2693 */
Adrian Hunter69423d92008-12-10 13:37:21 +00002694static int onenand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
Kyungmin Park08f782b2006-11-16 11:29:39 +09002695{
Adrian Hunter34627f02007-10-12 10:19:26 +03002696 int ret;
2697
2698 onenand_get_device(mtd, FL_LOCKING);
2699 ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK);
2700 onenand_release_device(mtd);
2701 return ret;
Kyungmin Park08f782b2006-11-16 11:29:39 +09002702}
2703
Kyungmin Park08f782b2006-11-16 11:29:39 +09002704/**
2705 * onenand_unlock - [MTD Interface] Unlock 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 * Unlock one or more blocks
2711 */
Adrian Hunter69423d92008-12-10 13:37:21 +00002712static int onenand_unlock(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_UNLOCK);
2718 onenand_release_device(mtd);
2719 return ret;
Kyungmin Park08f782b2006-11-16 11:29:39 +09002720}
2721
2722/**
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002723 * onenand_check_lock_status - [OneNAND Interface] Check lock status
2724 * @param this onenand chip data structure
2725 *
2726 * Check lock status
2727 */
Kyungmin Park66a10502008-02-13 15:55:38 +09002728static int onenand_check_lock_status(struct onenand_chip *this)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002729{
2730 unsigned int value, block, status;
2731 unsigned int end;
2732
2733 end = this->chipsize >> this->erase_shift;
2734 for (block = 0; block < end; block++) {
2735 /* Set block address */
2736 value = onenand_block_address(this, block);
2737 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
2738 /* Select DataRAM for DDP */
2739 value = onenand_bufferram_address(this, block);
2740 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
2741 /* Set start block address */
2742 this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
2743
2744 /* Check lock status */
2745 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
Kyungmin Park66a10502008-02-13 15:55:38 +09002746 if (!(status & ONENAND_WP_US)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302747 printk(KERN_ERR "%s: block = %d, wp status = 0x%x\n",
2748 __func__, block, status);
Kyungmin Park66a10502008-02-13 15:55:38 +09002749 return 0;
2750 }
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002751 }
Kyungmin Park66a10502008-02-13 15:55:38 +09002752
2753 return 1;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002754}
2755
2756/**
2757 * onenand_unlock_all - [OneNAND Interface] unlock all blocks
2758 * @param mtd MTD device structure
2759 *
2760 * Unlock all blocks
2761 */
Kyungmin Park66a10502008-02-13 15:55:38 +09002762static void onenand_unlock_all(struct mtd_info *mtd)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002763{
2764 struct onenand_chip *this = mtd->priv;
Kyungmin Park66a10502008-02-13 15:55:38 +09002765 loff_t ofs = 0;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002766 loff_t len = mtd->size;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002767
2768 if (this->options & ONENAND_HAS_UNLOCK_ALL) {
Kyungmin Park10b7a2b2007-01-12 05:45:34 +09002769 /* Set start block address */
2770 this->write_word(0, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002771 /* Write unlock command */
2772 this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0);
2773
2774 /* There's no return value */
Kyungmin Park08f782b2006-11-16 11:29:39 +09002775 this->wait(mtd, FL_LOCKING);
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002776
2777 /* Sanity check */
2778 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
2779 & ONENAND_CTRL_ONGO)
2780 continue;
2781
Kyungmin Park31bb9992009-05-12 13:46:57 -07002782 /* Don't check lock status */
2783 if (this->options & ONENAND_SKIP_UNLOCK_CHECK)
2784 return;
2785
Kyungmin Park66a10502008-02-13 15:55:38 +09002786 /* Check lock status */
2787 if (onenand_check_lock_status(this))
2788 return;
2789
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002790 /* Workaround for all block unlock in DDP */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002791 if (ONENAND_IS_DDP(this) && !FLEXONENAND(this)) {
Kyungmin Park66a10502008-02-13 15:55:38 +09002792 /* All blocks on another chip */
2793 ofs = this->chipsize >> 1;
2794 len = this->chipsize >> 1;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002795 }
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002796 }
2797
Kyungmin Park66a10502008-02-13 15:55:38 +09002798 onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002799}
2800
Kyungmin Park493c6462006-05-12 17:03:07 +03002801#ifdef CONFIG_MTD_ONENAND_OTP
2802
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05302803/**
2804 * onenand_otp_command - Send OTP specific command to OneNAND device
2805 * @param mtd MTD device structure
2806 * @param cmd the command to be sent
2807 * @param addr offset to read from or write to
2808 * @param len number of bytes to read or write
2809 */
2810static int onenand_otp_command(struct mtd_info *mtd, int cmd, loff_t addr,
2811 size_t len)
2812{
2813 struct onenand_chip *this = mtd->priv;
2814 int value, block, page;
2815
2816 /* Address translation */
2817 switch (cmd) {
2818 case ONENAND_CMD_OTP_ACCESS:
2819 block = (int) (addr >> this->erase_shift);
2820 page = -1;
2821 break;
2822
2823 default:
2824 block = (int) (addr >> this->erase_shift);
2825 page = (int) (addr >> this->page_shift);
2826
2827 if (ONENAND_IS_2PLANE(this)) {
2828 /* Make the even block number */
2829 block &= ~1;
2830 /* Is it the odd plane? */
2831 if (addr & this->writesize)
2832 block++;
2833 page >>= 1;
2834 }
2835 page &= this->page_mask;
2836 break;
2837 }
2838
2839 if (block != -1) {
2840 /* Write 'DFS, FBA' of Flash */
2841 value = onenand_block_address(this, block);
2842 this->write_word(value, this->base +
2843 ONENAND_REG_START_ADDRESS1);
2844 }
2845
2846 if (page != -1) {
2847 /* Now we use page size operation */
2848 int sectors = 4, count = 4;
2849 int dataram;
2850
2851 switch (cmd) {
2852 default:
2853 if (ONENAND_IS_2PLANE(this) && cmd == ONENAND_CMD_PROG)
2854 cmd = ONENAND_CMD_2X_PROG;
2855 dataram = ONENAND_CURRENT_BUFFERRAM(this);
2856 break;
2857 }
2858
2859 /* Write 'FPA, FSA' of Flash */
2860 value = onenand_page_address(page, sectors);
2861 this->write_word(value, this->base +
2862 ONENAND_REG_START_ADDRESS8);
2863
2864 /* Write 'BSA, BSC' of DataRAM */
2865 value = onenand_buffer_address(dataram, sectors, count);
2866 this->write_word(value, this->base + ONENAND_REG_START_BUFFER);
2867 }
2868
2869 /* Interrupt clear */
2870 this->write_word(ONENAND_INT_CLEAR, this->base + ONENAND_REG_INTERRUPT);
2871
2872 /* Write command */
2873 this->write_word(cmd, this->base + ONENAND_REG_COMMAND);
2874
2875 return 0;
2876}
2877
2878/**
Brian Norris7854d3f2011-06-23 14:12:08 -07002879 * onenand_otp_write_oob_nolock - [INTERN] OneNAND write out-of-band, specific to OTP
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05302880 * @param mtd MTD device structure
2881 * @param to offset to write to
2882 * @param len number of bytes to write
2883 * @param retlen pointer to variable to store the number of written bytes
2884 * @param buf the data to write
2885 *
2886 * OneNAND write out-of-band only for OTP
2887 */
2888static int onenand_otp_write_oob_nolock(struct mtd_info *mtd, loff_t to,
2889 struct mtd_oob_ops *ops)
2890{
2891 struct onenand_chip *this = mtd->priv;
2892 int column, ret = 0, oobsize;
2893 int written = 0;
2894 u_char *oobbuf;
2895 size_t len = ops->ooblen;
2896 const u_char *buf = ops->oobbuf;
2897 int block, value, status;
2898
2899 to += ops->ooboffs;
2900
2901 /* Initialize retlen, in case of early exit */
2902 ops->oobretlen = 0;
2903
2904 oobsize = mtd->oobsize;
2905
2906 column = to & (mtd->oobsize - 1);
2907
2908 oobbuf = this->oob_buf;
2909
2910 /* Loop until all data write */
2911 while (written < len) {
2912 int thislen = min_t(int, oobsize, len - written);
2913
2914 cond_resched();
2915
2916 block = (int) (to >> this->erase_shift);
2917 /*
2918 * Write 'DFS, FBA' of Flash
2919 * Add: F100h DQ=DFS, FBA
2920 */
2921
2922 value = onenand_block_address(this, block);
2923 this->write_word(value, this->base +
2924 ONENAND_REG_START_ADDRESS1);
2925
2926 /*
2927 * Select DataRAM for DDP
2928 * Add: F101h DQ=DBS
2929 */
2930
2931 value = onenand_bufferram_address(this, block);
2932 this->write_word(value, this->base +
2933 ONENAND_REG_START_ADDRESS2);
2934 ONENAND_SET_NEXT_BUFFERRAM(this);
2935
2936 /*
2937 * Enter OTP access mode
2938 */
2939 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
2940 this->wait(mtd, FL_OTPING);
2941
2942 /* We send data to spare ram with oobsize
2943 * to prevent byte access */
2944 memcpy(oobbuf + column, buf, thislen);
2945
2946 /*
2947 * Write Data into DataRAM
2948 * Add: 8th Word
2949 * in sector0/spare/page0
2950 * DQ=XXFCh
2951 */
2952 this->write_bufferram(mtd, ONENAND_SPARERAM,
2953 oobbuf, 0, mtd->oobsize);
2954
2955 onenand_otp_command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize);
2956 onenand_update_bufferram(mtd, to, 0);
2957 if (ONENAND_IS_2PLANE(this)) {
2958 ONENAND_SET_BUFFERRAM1(this);
2959 onenand_update_bufferram(mtd, to + this->writesize, 0);
2960 }
2961
2962 ret = this->wait(mtd, FL_WRITING);
2963 if (ret) {
2964 printk(KERN_ERR "%s: write failed %d\n", __func__, ret);
2965 break;
2966 }
2967
2968 /* Exit OTP access mode */
2969 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
2970 this->wait(mtd, FL_RESETING);
2971
2972 status = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
2973 status &= 0x60;
2974
2975 if (status == 0x60) {
2976 printk(KERN_DEBUG "\nBLOCK\tSTATUS\n");
2977 printk(KERN_DEBUG "1st Block\tLOCKED\n");
2978 printk(KERN_DEBUG "OTP Block\tLOCKED\n");
2979 } else if (status == 0x20) {
2980 printk(KERN_DEBUG "\nBLOCK\tSTATUS\n");
2981 printk(KERN_DEBUG "1st Block\tLOCKED\n");
2982 printk(KERN_DEBUG "OTP Block\tUN-LOCKED\n");
2983 } else if (status == 0x40) {
2984 printk(KERN_DEBUG "\nBLOCK\tSTATUS\n");
2985 printk(KERN_DEBUG "1st Block\tUN-LOCKED\n");
2986 printk(KERN_DEBUG "OTP Block\tLOCKED\n");
2987 } else {
2988 printk(KERN_DEBUG "Reboot to check\n");
2989 }
2990
2991 written += thislen;
2992 if (written == len)
2993 break;
2994
2995 to += mtd->writesize;
2996 buf += thislen;
2997 column = 0;
2998 }
2999
3000 ops->oobretlen = written;
3001
3002 return ret;
3003}
3004
Mika Korhonen492e1502009-06-09 21:52:35 +03003005/* Internal OTP operation */
Kyungmin Park493c6462006-05-12 17:03:07 +03003006typedef int (*otp_op_t)(struct mtd_info *mtd, loff_t form, size_t len,
3007 size_t *retlen, u_char *buf);
3008
3009/**
3010 * do_otp_read - [DEFAULT] Read OTP block area
3011 * @param mtd MTD device structure
3012 * @param from The offset to read
3013 * @param len number of bytes to read
3014 * @param retlen pointer to variable to store the number of readbytes
3015 * @param buf the databuffer to put/get data
3016 *
3017 * Read OTP block area.
3018 */
3019static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len,
3020 size_t *retlen, u_char *buf)
3021{
3022 struct onenand_chip *this = mtd->priv;
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003023 struct mtd_oob_ops ops = {
3024 .len = len,
3025 .ooblen = 0,
3026 .datbuf = buf,
3027 .oobbuf = NULL,
3028 };
Kyungmin Park493c6462006-05-12 17:03:07 +03003029 int ret;
3030
3031 /* Enter OTP access mode */
3032 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
3033 this->wait(mtd, FL_OTPING);
3034
Kyungmin Park8a8f6322010-12-02 09:24:16 +09003035 ret = ONENAND_IS_4KB_PAGE(this) ?
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003036 onenand_mlc_read_ops_nolock(mtd, from, &ops) :
3037 onenand_read_ops_nolock(mtd, from, &ops);
Kyungmin Park493c6462006-05-12 17:03:07 +03003038
3039 /* Exit OTP access mode */
3040 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
3041 this->wait(mtd, FL_RESETING);
3042
3043 return ret;
3044}
3045
3046/**
3047 * do_otp_write - [DEFAULT] Write OTP block area
3048 * @param mtd MTD device structure
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003049 * @param to The offset to write
Kyungmin Park493c6462006-05-12 17:03:07 +03003050 * @param len number of bytes to write
3051 * @param retlen pointer to variable to store the number of write bytes
3052 * @param buf the databuffer to put/get data
3053 *
3054 * Write OTP block area.
3055 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003056static int do_otp_write(struct mtd_info *mtd, loff_t to, size_t len,
Kyungmin Park493c6462006-05-12 17:03:07 +03003057 size_t *retlen, u_char *buf)
3058{
3059 struct onenand_chip *this = mtd->priv;
3060 unsigned char *pbuf = buf;
3061 int ret;
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003062 struct mtd_oob_ops ops;
Kyungmin Park493c6462006-05-12 17:03:07 +03003063
3064 /* Force buffer page aligned */
Joern Engel28318772006-05-22 23:18:05 +02003065 if (len < mtd->writesize) {
Kyungmin Park493c6462006-05-12 17:03:07 +03003066 memcpy(this->page_buf, buf, len);
Joern Engel28318772006-05-22 23:18:05 +02003067 memset(this->page_buf + len, 0xff, mtd->writesize - len);
Kyungmin Park493c6462006-05-12 17:03:07 +03003068 pbuf = this->page_buf;
Joern Engel28318772006-05-22 23:18:05 +02003069 len = mtd->writesize;
Kyungmin Park493c6462006-05-12 17:03:07 +03003070 }
3071
3072 /* Enter OTP access mode */
3073 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
3074 this->wait(mtd, FL_OTPING);
3075
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003076 ops.len = len;
3077 ops.ooblen = 0;
Kyungmin Park14370852007-10-10 13:48:14 +09003078 ops.datbuf = pbuf;
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003079 ops.oobbuf = NULL;
3080 ret = onenand_write_ops_nolock(mtd, to, &ops);
3081 *retlen = ops.retlen;
Kyungmin Park493c6462006-05-12 17:03:07 +03003082
3083 /* Exit OTP access mode */
3084 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
3085 this->wait(mtd, FL_RESETING);
3086
3087 return ret;
3088}
3089
3090/**
3091 * do_otp_lock - [DEFAULT] Lock OTP block area
3092 * @param mtd MTD device structure
3093 * @param from The offset to lock
3094 * @param len number of bytes to lock
3095 * @param retlen pointer to variable to store the number of lock bytes
3096 * @param buf the databuffer to put/get data
3097 *
3098 * Lock OTP block area.
3099 */
3100static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len,
3101 size_t *retlen, u_char *buf)
3102{
3103 struct onenand_chip *this = mtd->priv;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003104 struct mtd_oob_ops ops;
Kyungmin Park493c6462006-05-12 17:03:07 +03003105 int ret;
3106
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003107 if (FLEXONENAND(this)) {
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303108
3109 /* Enter OTP access mode */
3110 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
3111 this->wait(mtd, FL_OTPING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003112 /*
3113 * For Flex-OneNAND, we write lock mark to 1st word of sector 4 of
3114 * main area of page 49.
3115 */
3116 ops.len = mtd->writesize;
3117 ops.ooblen = 0;
3118 ops.datbuf = buf;
3119 ops.oobbuf = NULL;
3120 ret = onenand_write_ops_nolock(mtd, mtd->writesize * 49, &ops);
3121 *retlen = ops.retlen;
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303122
3123 /* Exit OTP access mode */
3124 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
3125 this->wait(mtd, FL_RESETING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003126 } else {
Brian Norris0612b9d2011-08-30 18:45:40 -07003127 ops.mode = MTD_OPS_PLACE_OOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003128 ops.ooblen = len;
3129 ops.oobbuf = buf;
3130 ops.ooboffs = 0;
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303131 ret = onenand_otp_write_oob_nolock(mtd, from, &ops);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003132 *retlen = ops.oobretlen;
3133 }
Kyungmin Park493c6462006-05-12 17:03:07 +03003134
Kyungmin Park493c6462006-05-12 17:03:07 +03003135 return ret;
3136}
3137
3138/**
3139 * onenand_otp_walk - [DEFAULT] Handle OTP operation
3140 * @param mtd MTD device structure
3141 * @param from The offset to read/write
3142 * @param len number of bytes to read/write
3143 * @param retlen pointer to variable to store the number of read bytes
3144 * @param buf the databuffer to put/get data
3145 * @param action do given action
3146 * @param mode specify user and factory
3147 *
3148 * Handle OTP operation.
3149 */
3150static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
3151 size_t *retlen, u_char *buf,
3152 otp_op_t action, int mode)
3153{
3154 struct onenand_chip *this = mtd->priv;
3155 int otp_pages;
3156 int density;
3157 int ret = 0;
3158
3159 *retlen = 0;
3160
Kyungmin Parke71f04f2007-12-11 11:23:45 +09003161 density = onenand_get_density(this->device_id);
Kyungmin Park493c6462006-05-12 17:03:07 +03003162 if (density < ONENAND_DEVICE_DENSITY_512Mb)
3163 otp_pages = 20;
3164 else
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303165 otp_pages = 50;
Kyungmin Park493c6462006-05-12 17:03:07 +03003166
3167 if (mode == MTD_OTP_FACTORY) {
Joern Engel28318772006-05-22 23:18:05 +02003168 from += mtd->writesize * otp_pages;
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303169 otp_pages = ONENAND_PAGES_PER_BLOCK - otp_pages;
Kyungmin Park493c6462006-05-12 17:03:07 +03003170 }
3171
3172 /* Check User/Factory boundary */
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303173 if (mode == MTD_OTP_USER) {
Roel Kluin0a032a42009-12-16 01:37:17 +01003174 if (mtd->writesize * otp_pages < from + len)
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303175 return 0;
3176 } else {
Roel Kluin0a032a42009-12-16 01:37:17 +01003177 if (mtd->writesize * otp_pages < len)
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303178 return 0;
3179 }
Kyungmin Park493c6462006-05-12 17:03:07 +03003180
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003181 onenand_get_device(mtd, FL_OTPING);
Kyungmin Park493c6462006-05-12 17:03:07 +03003182 while (len > 0 && otp_pages > 0) {
3183 if (!action) { /* OTP Info functions */
3184 struct otp_info *otpinfo;
3185
3186 len -= sizeof(struct otp_info);
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003187 if (len <= 0) {
3188 ret = -ENOSPC;
3189 break;
3190 }
Kyungmin Park493c6462006-05-12 17:03:07 +03003191
3192 otpinfo = (struct otp_info *) buf;
3193 otpinfo->start = from;
Joern Engel28318772006-05-22 23:18:05 +02003194 otpinfo->length = mtd->writesize;
Kyungmin Park493c6462006-05-12 17:03:07 +03003195 otpinfo->locked = 0;
3196
Joern Engel28318772006-05-22 23:18:05 +02003197 from += mtd->writesize;
Kyungmin Park493c6462006-05-12 17:03:07 +03003198 buf += sizeof(struct otp_info);
3199 *retlen += sizeof(struct otp_info);
3200 } else {
3201 size_t tmp_retlen;
Kyungmin Park493c6462006-05-12 17:03:07 +03003202
3203 ret = action(mtd, from, len, &tmp_retlen, buf);
3204
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303205 buf += tmp_retlen;
3206 len -= tmp_retlen;
3207 *retlen += tmp_retlen;
Kyungmin Park493c6462006-05-12 17:03:07 +03003208
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003209 if (ret)
3210 break;
Kyungmin Park493c6462006-05-12 17:03:07 +03003211 }
3212 otp_pages--;
3213 }
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003214 onenand_release_device(mtd);
Kyungmin Park493c6462006-05-12 17:03:07 +03003215
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003216 return ret;
Kyungmin Park493c6462006-05-12 17:03:07 +03003217}
3218
3219/**
3220 * onenand_get_fact_prot_info - [MTD Interface] Read factory OTP info
3221 * @param mtd MTD device structure
Kyungmin Park493c6462006-05-12 17:03:07 +03003222 * @param len number of bytes to read
Christian Riesch4b78fc42014-01-28 09:29:44 +01003223 * @param retlen pointer to variable to store the number of read bytes
3224 * @param buf the databuffer to put/get data
Kyungmin Park493c6462006-05-12 17:03:07 +03003225 *
3226 * Read factory OTP info.
3227 */
Christian Riesch4b78fc42014-01-28 09:29:44 +01003228static int onenand_get_fact_prot_info(struct mtd_info *mtd, size_t len,
3229 size_t *retlen, struct otp_info *buf)
Kyungmin Park493c6462006-05-12 17:03:07 +03003230{
Christian Riesch4b78fc42014-01-28 09:29:44 +01003231 return onenand_otp_walk(mtd, 0, len, retlen, (u_char *) buf, NULL,
3232 MTD_OTP_FACTORY);
Kyungmin Park493c6462006-05-12 17:03:07 +03003233}
3234
3235/**
3236 * onenand_read_fact_prot_reg - [MTD Interface] Read factory OTP area
3237 * @param mtd MTD device structure
3238 * @param from The offset to read
3239 * @param len number of bytes to read
3240 * @param retlen pointer to variable to store the number of read bytes
3241 * @param buf the databuffer to put/get data
3242 *
3243 * Read factory OTP area.
3244 */
3245static int onenand_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
3246 size_t len, size_t *retlen, u_char *buf)
3247{
3248 return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_read, MTD_OTP_FACTORY);
3249}
3250
3251/**
3252 * onenand_get_user_prot_info - [MTD Interface] Read user OTP info
3253 * @param mtd MTD device structure
Christian Riesch4b78fc42014-01-28 09:29:44 +01003254 * @param retlen pointer to variable to store the number of read bytes
Kyungmin Park493c6462006-05-12 17:03:07 +03003255 * @param len number of bytes to read
Christian Riesch4b78fc42014-01-28 09:29:44 +01003256 * @param buf the databuffer to put/get data
Kyungmin Park493c6462006-05-12 17:03:07 +03003257 *
3258 * Read user OTP info.
3259 */
Christian Riesch4b78fc42014-01-28 09:29:44 +01003260static int onenand_get_user_prot_info(struct mtd_info *mtd, size_t len,
3261 size_t *retlen, struct otp_info *buf)
Kyungmin Park493c6462006-05-12 17:03:07 +03003262{
Christian Riesch4b78fc42014-01-28 09:29:44 +01003263 return onenand_otp_walk(mtd, 0, len, retlen, (u_char *) buf, NULL,
3264 MTD_OTP_USER);
Kyungmin Park493c6462006-05-12 17:03:07 +03003265}
3266
3267/**
3268 * onenand_read_user_prot_reg - [MTD Interface] Read user OTP area
3269 * @param mtd MTD device structure
3270 * @param from The offset to read
3271 * @param len number of bytes to read
3272 * @param retlen pointer to variable to store the number of read bytes
3273 * @param buf the databuffer to put/get data
3274 *
3275 * Read user OTP area.
3276 */
3277static int onenand_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
3278 size_t len, size_t *retlen, u_char *buf)
3279{
3280 return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_read, MTD_OTP_USER);
3281}
3282
3283/**
3284 * onenand_write_user_prot_reg - [MTD Interface] Write user OTP area
3285 * @param mtd MTD device structure
3286 * @param from The offset to write
3287 * @param len number of bytes to write
3288 * @param retlen pointer to variable to store the number of write bytes
3289 * @param buf the databuffer to put/get data
3290 *
3291 * Write user OTP area.
3292 */
3293static int onenand_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
3294 size_t len, size_t *retlen, u_char *buf)
3295{
3296 return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_write, MTD_OTP_USER);
3297}
3298
3299/**
3300 * onenand_lock_user_prot_reg - [MTD Interface] Lock user OTP area
3301 * @param mtd MTD device structure
3302 * @param from The offset to lock
3303 * @param len number of bytes to unlock
3304 *
3305 * Write lock mark on spare area in page 0 in OTP block
3306 */
3307static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
3308 size_t len)
3309{
Kyungmin Park69d79182007-12-14 14:47:21 +09003310 struct onenand_chip *this = mtd->priv;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003311 u_char *buf = FLEXONENAND(this) ? this->page_buf : this->oob_buf;
Kyungmin Park493c6462006-05-12 17:03:07 +03003312 size_t retlen;
3313 int ret;
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303314 unsigned int otp_lock_offset = ONENAND_OTP_LOCK_OFFSET;
Kyungmin Park493c6462006-05-12 17:03:07 +03003315
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003316 memset(buf, 0xff, FLEXONENAND(this) ? this->writesize
3317 : mtd->oobsize);
Kyungmin Park493c6462006-05-12 17:03:07 +03003318 /*
Kyungmin Park493c6462006-05-12 17:03:07 +03003319 * Write lock mark to 8th word of sector0 of page0 of the spare0.
3320 * We write 16 bytes spare area instead of 2 bytes.
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003321 * For Flex-OneNAND, we write lock mark to 1st word of sector 4 of
3322 * main area of page 49.
Kyungmin Park493c6462006-05-12 17:03:07 +03003323 */
Kyungmin Park493c6462006-05-12 17:03:07 +03003324
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003325 from = 0;
3326 len = FLEXONENAND(this) ? mtd->writesize : 16;
3327
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303328 /*
3329 * Note: OTP lock operation
3330 * OTP block : 0xXXFC XX 1111 1100
3331 * 1st block : 0xXXF3 (If chip support) XX 1111 0011
3332 * Both : 0xXXF0 (If chip support) XX 1111 0000
3333 */
3334 if (FLEXONENAND(this))
3335 otp_lock_offset = FLEXONENAND_OTP_LOCK_OFFSET;
3336
3337 /* ONENAND_OTP_AREA | ONENAND_OTP_BLOCK0 | ONENAND_OTP_AREA_BLOCK0 */
3338 if (otp == 1)
3339 buf[otp_lock_offset] = 0xFC;
3340 else if (otp == 2)
3341 buf[otp_lock_offset] = 0xF3;
3342 else if (otp == 3)
3343 buf[otp_lock_offset] = 0xF0;
3344 else if (otp != 0)
3345 printk(KERN_DEBUG "[OneNAND] Invalid option selected for OTP\n");
3346
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003347 ret = onenand_otp_walk(mtd, from, len, &retlen, buf, do_otp_lock, MTD_OTP_USER);
Kyungmin Park493c6462006-05-12 17:03:07 +03003348
3349 return ret ? : retlen;
3350}
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303351
Kyungmin Park493c6462006-05-12 17:03:07 +03003352#endif /* CONFIG_MTD_ONENAND_OTP */
3353
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003354/**
Kyungmin Park75384b02007-01-18 11:10:57 +09003355 * onenand_check_features - Check and set OneNAND features
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003356 * @param mtd MTD data structure
3357 *
Kyungmin Park75384b02007-01-18 11:10:57 +09003358 * Check and set OneNAND features
3359 * - lock scheme
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003360 * - two plane
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003361 */
Kyungmin Park75384b02007-01-18 11:10:57 +09003362static void onenand_check_features(struct mtd_info *mtd)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003363{
3364 struct onenand_chip *this = mtd->priv;
Roman Tereshonkovedb44b92010-10-11 14:47:32 +03003365 unsigned int density, process, numbufs;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003366
3367 /* Lock scheme depends on density and process */
Kyungmin Parke71f04f2007-12-11 11:23:45 +09003368 density = onenand_get_density(this->device_id);
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003369 process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT;
Roman Tereshonkovedb44b92010-10-11 14:47:32 +03003370 numbufs = this->read_word(this->base + ONENAND_REG_NUM_BUFFERS) >> 8;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003371
3372 /* Lock scheme */
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003373 switch (density) {
3374 case ONENAND_DEVICE_DENSITY_4Gb:
Kyungmin Park6a88c472010-04-28 17:46:45 +02003375 if (ONENAND_IS_DDP(this))
3376 this->options |= ONENAND_HAS_2PLANE;
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02003377 else if (numbufs == 1) {
Kyungmin Park6a88c472010-04-28 17:46:45 +02003378 this->options |= ONENAND_HAS_4KB_PAGE;
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02003379 this->options |= ONENAND_HAS_CACHE_PROGRAM;
Kyungmin Parke1c10242011-06-22 14:16:49 +09003380 /*
3381 * There are two different 4KiB pagesize chips
3382 * and no way to detect it by H/W config values.
3383 *
3384 * To detect the correct NOP for each chips,
3385 * It should check the version ID as workaround.
3386 *
3387 * Now it has as following
3388 * KFM4G16Q4M has NOP 4 with version ID 0x0131
3389 * KFM4G16Q5M has NOP 1 with versoin ID 0x013e
3390 */
3391 if ((this->version_id & 0xf) == 0xe)
3392 this->options |= ONENAND_HAS_NOP_1;
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02003393 }
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003394
3395 case ONENAND_DEVICE_DENSITY_2Gb:
Mika Korhonen492e1502009-06-09 21:52:35 +03003396 /* 2Gb DDP does not have 2 plane */
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003397 if (!ONENAND_IS_DDP(this))
3398 this->options |= ONENAND_HAS_2PLANE;
3399 this->options |= ONENAND_HAS_UNLOCK_ALL;
3400
3401 case ONENAND_DEVICE_DENSITY_1Gb:
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003402 /* A-Die has all block unlock */
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003403 if (process)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003404 this->options |= ONENAND_HAS_UNLOCK_ALL;
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003405 break;
3406
3407 default:
3408 /* Some OneNAND has continuous lock scheme */
3409 if (!process)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003410 this->options |= ONENAND_HAS_CONT_LOCK;
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003411 break;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003412 }
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003413
Kyungmin Park8a8f6322010-12-02 09:24:16 +09003414 /* The MLC has 4KiB pagesize. */
3415 if (ONENAND_IS_MLC(this))
3416 this->options |= ONENAND_HAS_4KB_PAGE;
3417
3418 if (ONENAND_IS_4KB_PAGE(this))
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003419 this->options &= ~ONENAND_HAS_2PLANE;
3420
3421 if (FLEXONENAND(this)) {
3422 this->options &= ~ONENAND_HAS_CONT_LOCK;
3423 this->options |= ONENAND_HAS_UNLOCK_ALL;
3424 }
3425
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003426 if (this->options & ONENAND_HAS_CONT_LOCK)
3427 printk(KERN_DEBUG "Lock scheme is Continuous Lock\n");
3428 if (this->options & ONENAND_HAS_UNLOCK_ALL)
3429 printk(KERN_DEBUG "Chip support all block unlock\n");
3430 if (this->options & ONENAND_HAS_2PLANE)
3431 printk(KERN_DEBUG "Chip has 2 plane\n");
Kyungmin Park6a88c472010-04-28 17:46:45 +02003432 if (this->options & ONENAND_HAS_4KB_PAGE)
3433 printk(KERN_DEBUG "Chip has 4KiB pagesize\n");
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02003434 if (this->options & ONENAND_HAS_CACHE_PROGRAM)
3435 printk(KERN_DEBUG "Chip has cache program feature\n");
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003436}
3437
3438/**
Kyungmin Parke3da8062007-02-15 09:36:39 +09003439 * onenand_print_device_info - Print device & version ID
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003440 * @param device device ID
Kyungmin Parke3da8062007-02-15 09:36:39 +09003441 * @param version version ID
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003442 *
Kyungmin Parke3da8062007-02-15 09:36:39 +09003443 * Print device & version ID
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003444 */
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003445static void onenand_print_device_info(int device, int version)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003446{
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003447 int vcc, demuxed, ddp, density, flexonenand;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003448
3449 vcc = device & ONENAND_DEVICE_VCC_MASK;
3450 demuxed = device & ONENAND_DEVICE_IS_DEMUX;
3451 ddp = device & ONENAND_DEVICE_IS_DDP;
Kyungmin Parke71f04f2007-12-11 11:23:45 +09003452 density = onenand_get_density(device);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003453 flexonenand = device & DEVICE_IS_FLEXONENAND;
3454 printk(KERN_INFO "%s%sOneNAND%s %dMB %sV 16-bit (0x%02x)\n",
3455 demuxed ? "" : "Muxed ",
3456 flexonenand ? "Flex-" : "",
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003457 ddp ? "(DDP)" : "",
3458 (16 << density),
3459 vcc ? "2.65/3.3" : "1.8",
3460 device);
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003461 printk(KERN_INFO "OneNAND version = 0x%04x\n", version);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003462}
3463
3464static const struct onenand_manufacturers onenand_manuf_ids[] = {
3465 {ONENAND_MFR_SAMSUNG, "Samsung"},
Adrian Hunteree8f3762009-05-05 11:04:19 +03003466 {ONENAND_MFR_NUMONYX, "Numonyx"},
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003467};
3468
3469/**
3470 * onenand_check_maf - Check manufacturer ID
3471 * @param manuf manufacturer ID
3472 *
3473 * Check manufacturer ID
3474 */
3475static int onenand_check_maf(int manuf)
3476{
Kyungmin Park37b1cc32005-12-16 11:17:29 +09003477 int size = ARRAY_SIZE(onenand_manuf_ids);
3478 char *name;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003479 int i;
3480
Kyungmin Park37b1cc32005-12-16 11:17:29 +09003481 for (i = 0; i < size; i++)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003482 if (manuf == onenand_manuf_ids[i].id)
3483 break;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003484
Kyungmin Park37b1cc32005-12-16 11:17:29 +09003485 if (i < size)
3486 name = onenand_manuf_ids[i].name;
3487 else
3488 name = "Unknown";
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003489
Kyungmin Park37b1cc32005-12-16 11:17:29 +09003490 printk(KERN_DEBUG "OneNAND Manufacturer: %s (0x%0x)\n", name, manuf);
3491
3492 return (i == size);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003493}
3494
3495/**
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003496* flexonenand_get_boundary - Reads the SLC boundary
3497* @param onenand_info - onenand info structure
3498**/
3499static int flexonenand_get_boundary(struct mtd_info *mtd)
3500{
3501 struct onenand_chip *this = mtd->priv;
3502 unsigned die, bdry;
Brian Norris6b7368c2013-08-27 18:01:19 -07003503 int syscfg, locked;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003504
3505 /* Disable ECC */
3506 syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
3507 this->write_word((syscfg | 0x0100), this->base + ONENAND_REG_SYS_CFG1);
3508
3509 for (die = 0; die < this->dies; die++) {
3510 this->command(mtd, FLEXONENAND_CMD_PI_ACCESS, die, 0);
3511 this->wait(mtd, FL_SYNCING);
3512
3513 this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0);
Brian Norris6b7368c2013-08-27 18:01:19 -07003514 this->wait(mtd, FL_READING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003515
3516 bdry = this->read_word(this->base + ONENAND_DATARAM);
3517 if ((bdry >> FLEXONENAND_PI_UNLOCK_SHIFT) == 3)
3518 locked = 0;
3519 else
3520 locked = 1;
3521 this->boundary[die] = bdry & FLEXONENAND_PI_MASK;
3522
3523 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
Brian Norris6b7368c2013-08-27 18:01:19 -07003524 this->wait(mtd, FL_RESETING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003525
3526 printk(KERN_INFO "Die %d boundary: %d%s\n", die,
3527 this->boundary[die], locked ? "(Locked)" : "(Unlocked)");
3528 }
3529
3530 /* Enable ECC */
3531 this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
3532 return 0;
3533}
3534
3535/**
3536 * flexonenand_get_size - Fill up fields in onenand_chip and mtd_info
3537 * boundary[], diesize[], mtd->size, mtd->erasesize
3538 * @param mtd - MTD device structure
3539 */
3540static void flexonenand_get_size(struct mtd_info *mtd)
3541{
3542 struct onenand_chip *this = mtd->priv;
3543 int die, i, eraseshift, density;
3544 int blksperdie, maxbdry;
3545 loff_t ofs;
3546
3547 density = onenand_get_density(this->device_id);
3548 blksperdie = ((loff_t)(16 << density) << 20) >> (this->erase_shift);
3549 blksperdie >>= ONENAND_IS_DDP(this) ? 1 : 0;
3550 maxbdry = blksperdie - 1;
3551 eraseshift = this->erase_shift - 1;
3552
3553 mtd->numeraseregions = this->dies << 1;
3554
3555 /* This fills up the device boundary */
3556 flexonenand_get_boundary(mtd);
3557 die = ofs = 0;
3558 i = -1;
3559 for (; die < this->dies; die++) {
3560 if (!die || this->boundary[die-1] != maxbdry) {
3561 i++;
3562 mtd->eraseregions[i].offset = ofs;
3563 mtd->eraseregions[i].erasesize = 1 << eraseshift;
3564 mtd->eraseregions[i].numblocks =
3565 this->boundary[die] + 1;
3566 ofs += mtd->eraseregions[i].numblocks << eraseshift;
3567 eraseshift++;
3568 } else {
3569 mtd->numeraseregions -= 1;
3570 mtd->eraseregions[i].numblocks +=
3571 this->boundary[die] + 1;
3572 ofs += (this->boundary[die] + 1) << (eraseshift - 1);
3573 }
3574 if (this->boundary[die] != maxbdry) {
3575 i++;
3576 mtd->eraseregions[i].offset = ofs;
3577 mtd->eraseregions[i].erasesize = 1 << eraseshift;
3578 mtd->eraseregions[i].numblocks = maxbdry ^
3579 this->boundary[die];
3580 ofs += mtd->eraseregions[i].numblocks << eraseshift;
3581 eraseshift--;
3582 } else
3583 mtd->numeraseregions -= 1;
3584 }
3585
3586 /* Expose MLC erase size except when all blocks are SLC */
3587 mtd->erasesize = 1 << this->erase_shift;
3588 if (mtd->numeraseregions == 1)
3589 mtd->erasesize >>= 1;
3590
3591 printk(KERN_INFO "Device has %d eraseregions\n", mtd->numeraseregions);
3592 for (i = 0; i < mtd->numeraseregions; i++)
3593 printk(KERN_INFO "[offset: 0x%08x, erasesize: 0x%05x,"
3594 " numblocks: %04u]\n",
3595 (unsigned int) mtd->eraseregions[i].offset,
3596 mtd->eraseregions[i].erasesize,
3597 mtd->eraseregions[i].numblocks);
3598
3599 for (die = 0, mtd->size = 0; die < this->dies; die++) {
3600 this->diesize[die] = (loff_t)blksperdie << this->erase_shift;
3601 this->diesize[die] -= (loff_t)(this->boundary[die] + 1)
3602 << (this->erase_shift - 1);
3603 mtd->size += this->diesize[die];
3604 }
3605}
3606
3607/**
3608 * flexonenand_check_blocks_erased - Check if blocks are erased
3609 * @param mtd_info - mtd info structure
3610 * @param start - first erase block to check
3611 * @param end - last erase block to check
3612 *
3613 * Converting an unerased block from MLC to SLC
3614 * causes byte values to change. Since both data and its ECC
3615 * have changed, reads on the block give uncorrectable error.
3616 * This might lead to the block being detected as bad.
3617 *
3618 * Avoid this by ensuring that the block to be converted is
3619 * erased.
3620 */
3621static int flexonenand_check_blocks_erased(struct mtd_info *mtd, int start, int end)
3622{
3623 struct onenand_chip *this = mtd->priv;
3624 int i, ret;
3625 int block;
3626 struct mtd_oob_ops ops = {
Brian Norris0612b9d2011-08-30 18:45:40 -07003627 .mode = MTD_OPS_PLACE_OOB,
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003628 .ooboffs = 0,
3629 .ooblen = mtd->oobsize,
3630 .datbuf = NULL,
3631 .oobbuf = this->oob_buf,
3632 };
3633 loff_t addr;
3634
3635 printk(KERN_DEBUG "Check blocks from %d to %d\n", start, end);
3636
3637 for (block = start; block <= end; block++) {
3638 addr = flexonenand_addr(this, block);
3639 if (onenand_block_isbad_nolock(mtd, addr, 0))
3640 continue;
3641
3642 /*
3643 * Since main area write results in ECC write to spare,
3644 * it is sufficient to check only ECC bytes for change.
3645 */
3646 ret = onenand_read_oob_nolock(mtd, addr, &ops);
3647 if (ret)
3648 return ret;
3649
3650 for (i = 0; i < mtd->oobsize; i++)
3651 if (this->oob_buf[i] != 0xff)
3652 break;
3653
3654 if (i != mtd->oobsize) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303655 printk(KERN_WARNING "%s: Block %d not erased.\n",
3656 __func__, block);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003657 return 1;
3658 }
3659 }
3660
3661 return 0;
3662}
3663
3664/**
3665 * flexonenand_set_boundary - Writes the SLC boundary
3666 * @param mtd - mtd info structure
3667 */
Sachin Kamat01319502012-09-22 11:42:31 +05303668static int flexonenand_set_boundary(struct mtd_info *mtd, int die,
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003669 int boundary, int lock)
3670{
3671 struct onenand_chip *this = mtd->priv;
3672 int ret, density, blksperdie, old, new, thisboundary;
3673 loff_t addr;
3674
3675 /* Change only once for SDP Flex-OneNAND */
3676 if (die && (!ONENAND_IS_DDP(this)))
3677 return 0;
3678
3679 /* boundary value of -1 indicates no required change */
3680 if (boundary < 0 || boundary == this->boundary[die])
3681 return 0;
3682
3683 density = onenand_get_density(this->device_id);
3684 blksperdie = ((16 << density) << 20) >> this->erase_shift;
3685 blksperdie >>= ONENAND_IS_DDP(this) ? 1 : 0;
3686
3687 if (boundary >= blksperdie) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303688 printk(KERN_ERR "%s: Invalid boundary value. "
3689 "Boundary not changed.\n", __func__);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003690 return -EINVAL;
3691 }
3692
3693 /* Check if converting blocks are erased */
3694 old = this->boundary[die] + (die * this->density_mask);
3695 new = boundary + (die * this->density_mask);
3696 ret = flexonenand_check_blocks_erased(mtd, min(old, new) + 1, max(old, new));
3697 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303698 printk(KERN_ERR "%s: Please erase blocks "
3699 "before boundary change\n", __func__);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003700 return ret;
3701 }
3702
3703 this->command(mtd, FLEXONENAND_CMD_PI_ACCESS, die, 0);
3704 this->wait(mtd, FL_SYNCING);
3705
3706 /* Check is boundary is locked */
3707 this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0);
Brian Norris6b7368c2013-08-27 18:01:19 -07003708 this->wait(mtd, FL_READING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003709
3710 thisboundary = this->read_word(this->base + ONENAND_DATARAM);
3711 if ((thisboundary >> FLEXONENAND_PI_UNLOCK_SHIFT) != 3) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303712 printk(KERN_ERR "%s: boundary locked\n", __func__);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003713 ret = 1;
3714 goto out;
3715 }
3716
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303717 printk(KERN_INFO "Changing die %d boundary: %d%s\n",
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003718 die, boundary, lock ? "(Locked)" : "(Unlocked)");
3719
3720 addr = die ? this->diesize[0] : 0;
3721
3722 boundary &= FLEXONENAND_PI_MASK;
3723 boundary |= lock ? 0 : (3 << FLEXONENAND_PI_UNLOCK_SHIFT);
3724
3725 this->command(mtd, ONENAND_CMD_ERASE, addr, 0);
3726 ret = this->wait(mtd, FL_ERASING);
3727 if (ret) {
Mika Korhonenf369c7e2009-10-23 07:50:44 +02003728 printk(KERN_ERR "%s: Failed PI erase for Die %d\n",
3729 __func__, die);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003730 goto out;
3731 }
3732
3733 this->write_word(boundary, this->base + ONENAND_DATARAM);
3734 this->command(mtd, ONENAND_CMD_PROG, addr, 0);
3735 ret = this->wait(mtd, FL_WRITING);
3736 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303737 printk(KERN_ERR "%s: Failed PI write for Die %d\n",
3738 __func__, die);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003739 goto out;
3740 }
3741
3742 this->command(mtd, FLEXONENAND_CMD_PI_UPDATE, die, 0);
3743 ret = this->wait(mtd, FL_WRITING);
3744out:
3745 this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_REG_COMMAND);
3746 this->wait(mtd, FL_RESETING);
3747 if (!ret)
3748 /* Recalculate device size on boundary change*/
3749 flexonenand_get_size(mtd);
3750
3751 return ret;
3752}
3753
3754/**
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003755 * onenand_chip_probe - [OneNAND Interface] The generic chip probe
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003756 * @param mtd MTD device structure
3757 *
3758 * OneNAND detection method:
Michael Opdenacker59c51592007-05-09 08:57:56 +02003759 * Compare the values from command with ones from register
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003760 */
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003761static int onenand_chip_probe(struct mtd_info *mtd)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003762{
3763 struct onenand_chip *this = mtd->priv;
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003764 int bram_maf_id, bram_dev_id, maf_id, dev_id;
Kyungmin Park47e777e2006-09-25 23:53:28 +00003765 int syscfg;
3766
3767 /* Save system configuration 1 */
3768 syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
3769 /* Clear Sync. Burst Read mode to read BootRAM */
Adrian Hunteree8f3762009-05-05 11:04:19 +03003770 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 +01003771
3772 /* Send the command for reading device ID from BootRAM */
3773 this->write_word(ONENAND_CMD_READID, this->base + ONENAND_BOOTRAM);
3774
3775 /* Read manufacturer and device IDs from BootRAM */
3776 bram_maf_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x0);
3777 bram_dev_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x2);
3778
Kyungmin Park47e777e2006-09-25 23:53:28 +00003779 /* Reset OneNAND to read default register values */
3780 this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM);
3781 /* Wait reset */
3782 this->wait(mtd, FL_RESETING);
3783
3784 /* Restore system configuration 1 */
3785 this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
3786
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003787 /* Check manufacturer ID */
3788 if (onenand_check_maf(bram_maf_id))
3789 return -ENXIO;
3790
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003791 /* Read manufacturer and device IDs from Register */
3792 maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);
3793 dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
3794
3795 /* Check OneNAND device */
3796 if (maf_id != bram_maf_id || dev_id != bram_dev_id)
3797 return -ENXIO;
3798
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003799 return 0;
3800}
3801
3802/**
3803 * onenand_probe - [OneNAND Interface] Probe the OneNAND device
3804 * @param mtd MTD device structure
3805 */
3806static int onenand_probe(struct mtd_info *mtd)
3807{
3808 struct onenand_chip *this = mtd->priv;
Brian Norris6b7368c2013-08-27 18:01:19 -07003809 int dev_id, ver_id;
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003810 int density;
3811 int ret;
3812
3813 ret = this->chip_probe(mtd);
3814 if (ret)
3815 return ret;
3816
Brian Norris6b7368c2013-08-27 18:01:19 -07003817 /* Device and version IDs from Register */
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003818 dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
3819 ver_id = this->read_word(this->base + ONENAND_REG_VERSION_ID);
3820 this->technology = this->read_word(this->base + ONENAND_REG_TECHNOLOGY);
3821
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003822 /* Flash device information */
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003823 onenand_print_device_info(dev_id, ver_id);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003824 this->device_id = dev_id;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003825 this->version_id = ver_id;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003826
Kyungmin Parkc37cb562010-04-28 17:46:48 +02003827 /* Check OneNAND features */
3828 onenand_check_features(mtd);
3829
Kyungmin Parke71f04f2007-12-11 11:23:45 +09003830 density = onenand_get_density(dev_id);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003831 if (FLEXONENAND(this)) {
3832 this->dies = ONENAND_IS_DDP(this) ? 2 : 1;
3833 /* Maximum possible erase regions */
3834 mtd->numeraseregions = this->dies << 1;
3835 mtd->eraseregions = kzalloc(sizeof(struct mtd_erase_region_info)
3836 * (this->dies << 1), GFP_KERNEL);
3837 if (!mtd->eraseregions)
3838 return -ENOMEM;
3839 }
3840
3841 /*
3842 * For Flex-OneNAND, chipsize represents maximum possible device size.
3843 * mtd->size represents the actual device size.
3844 */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003845 this->chipsize = (16 << density) << 20;
3846
3847 /* OneNAND page size & block size */
3848 /* The data buffer size is equal to page size */
Joern Engel28318772006-05-22 23:18:05 +02003849 mtd->writesize = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003850 /* We use the full BufferRAM */
Kyungmin Park8a8f6322010-12-02 09:24:16 +09003851 if (ONENAND_IS_4KB_PAGE(this))
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003852 mtd->writesize <<= 1;
3853
Joern Engel28318772006-05-22 23:18:05 +02003854 mtd->oobsize = mtd->writesize >> 5;
Kyungmin Park9bfbc9b2007-01-31 14:25:21 +09003855 /* Pages per a block are always 64 in OneNAND */
Joern Engel28318772006-05-22 23:18:05 +02003856 mtd->erasesize = mtd->writesize << 6;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003857 /*
3858 * Flex-OneNAND SLC area has 64 pages per block.
3859 * Flex-OneNAND MLC area has 128 pages per block.
3860 * Expose MLC erase size to find erase_shift and page_mask.
3861 */
3862 if (FLEXONENAND(this))
3863 mtd->erasesize <<= 1;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003864
3865 this->erase_shift = ffs(mtd->erasesize) - 1;
Joern Engel28318772006-05-22 23:18:05 +02003866 this->page_shift = ffs(mtd->writesize) - 1;
Kyungmin Park9bfbc9b2007-01-31 14:25:21 +09003867 this->page_mask = (1 << (this->erase_shift - this->page_shift)) - 1;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003868 /* Set density mask. it is used for DDP */
3869 if (ONENAND_IS_DDP(this))
3870 this->density_mask = this->chipsize >> (this->erase_shift + 1);
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003871 /* It's real page size */
3872 this->writesize = mtd->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003873
Mika Korhonen492e1502009-06-09 21:52:35 +03003874 /* REVISIT: Multichip handling */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003875
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003876 if (FLEXONENAND(this))
3877 flexonenand_get_size(mtd);
3878 else
3879 mtd->size = this->chipsize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003880
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003881 /*
3882 * We emulate the 4KiB page and 256KiB erase block size
3883 * But oobsize is still 64 bytes.
3884 * It is only valid if you turn on 2X program support,
3885 * Otherwise it will be ignored by compiler.
3886 */
3887 if (ONENAND_IS_2PLANE(this)) {
3888 mtd->writesize <<= 1;
3889 mtd->erasesize <<= 1;
3890 }
3891
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003892 return 0;
3893}
3894
Kyungmin Parka41371e2005-09-29 03:55:31 +01003895/**
3896 * onenand_suspend - [MTD Interface] Suspend the OneNAND flash
3897 * @param mtd MTD device structure
3898 */
3899static int onenand_suspend(struct mtd_info *mtd)
3900{
3901 return onenand_get_device(mtd, FL_PM_SUSPENDED);
3902}
3903
3904/**
3905 * onenand_resume - [MTD Interface] Resume the OneNAND flash
3906 * @param mtd MTD device structure
3907 */
3908static void onenand_resume(struct mtd_info *mtd)
3909{
3910 struct onenand_chip *this = mtd->priv;
3911
3912 if (this->state == FL_PM_SUSPENDED)
3913 onenand_release_device(mtd);
3914 else
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303915 printk(KERN_ERR "%s: resume() called for the chip which is not "
3916 "in suspended state\n", __func__);
Kyungmin Parka41371e2005-09-29 03:55:31 +01003917}
3918
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003919/**
3920 * onenand_scan - [OneNAND Interface] Scan for the OneNAND device
3921 * @param mtd MTD device structure
3922 * @param maxchips Number of chips to scan for
3923 *
3924 * This fills out all the not initialized function pointers
3925 * with the defaults.
3926 * The flash ID is read and the mtd/chip structures are
3927 * filled with the appropriate values.
3928 */
3929int onenand_scan(struct mtd_info *mtd, int maxchips)
3930{
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003931 int i, ret;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003932 struct onenand_chip *this = mtd->priv;
3933
3934 if (!this->read_word)
3935 this->read_word = onenand_readw;
3936 if (!this->write_word)
3937 this->write_word = onenand_writew;
3938
3939 if (!this->command)
3940 this->command = onenand_command;
3941 if (!this->wait)
Kyungmin Park2c221202006-11-16 11:23:48 +09003942 onenand_setup_wait(mtd);
Kyungmin Park31bb9992009-05-12 13:46:57 -07003943 if (!this->bbt_wait)
3944 this->bbt_wait = onenand_bbt_wait;
3945 if (!this->unlock_all)
3946 this->unlock_all = onenand_unlock_all;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003947
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003948 if (!this->chip_probe)
3949 this->chip_probe = onenand_chip_probe;
3950
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003951 if (!this->read_bufferram)
3952 this->read_bufferram = onenand_read_bufferram;
3953 if (!this->write_bufferram)
3954 this->write_bufferram = onenand_write_bufferram;
3955
Kyungmin Parkcdc00132005-09-03 07:15:48 +01003956 if (!this->block_markbad)
3957 this->block_markbad = onenand_default_block_markbad;
3958 if (!this->scan_bbt)
3959 this->scan_bbt = onenand_default_bbt;
3960
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003961 if (onenand_probe(mtd))
3962 return -ENXIO;
3963
Kyungmin Park52b0eea2005-09-03 07:07:19 +01003964 /* Set Sync. Burst Read after probing */
3965 if (this->mmcontrol) {
3966 printk(KERN_INFO "OneNAND Sync. Burst Read support\n");
3967 this->read_bufferram = onenand_sync_read_bufferram;
3968 }
3969
Kyungmin Park532a37c2005-12-16 11:17:29 +09003970 /* Allocate buffers, if necessary */
3971 if (!this->page_buf) {
Kyungmin Park470bc842007-03-09 10:08:11 +09003972 this->page_buf = kzalloc(mtd->writesize, GFP_KERNEL);
Jingoo Hane4eec192014-02-06 15:15:38 +09003973 if (!this->page_buf)
Kyungmin Park532a37c2005-12-16 11:17:29 +09003974 return -ENOMEM;
Kyungmin Park4a8ce0b2010-04-28 17:46:46 +02003975#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
3976 this->verify_buf = kzalloc(mtd->writesize, GFP_KERNEL);
3977 if (!this->verify_buf) {
3978 kfree(this->page_buf);
3979 return -ENOMEM;
3980 }
3981#endif
Kyungmin Park532a37c2005-12-16 11:17:29 +09003982 this->options |= ONENAND_PAGEBUF_ALLOC;
3983 }
Kyungmin Park470bc842007-03-09 10:08:11 +09003984 if (!this->oob_buf) {
3985 this->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
3986 if (!this->oob_buf) {
Kyungmin Park470bc842007-03-09 10:08:11 +09003987 if (this->options & ONENAND_PAGEBUF_ALLOC) {
3988 this->options &= ~ONENAND_PAGEBUF_ALLOC;
3989 kfree(this->page_buf);
3990 }
3991 return -ENOMEM;
3992 }
3993 this->options |= ONENAND_OOBBUF_ALLOC;
3994 }
Kyungmin Park532a37c2005-12-16 11:17:29 +09003995
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003996 this->state = FL_READY;
3997 init_waitqueue_head(&this->wq);
3998 spin_lock_init(&this->chip_lock);
3999
Kyungmin Park60d84f92006-12-22 16:21:54 +09004000 /*
4001 * Allow subpage writes up to oobsize.
4002 */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004003 switch (mtd->oobsize) {
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07004004 case 128:
Roman Tereshonkov99b17c02011-04-11 12:52:01 +03004005 if (FLEXONENAND(this)) {
4006 this->ecclayout = &flexonenand_oob_128;
4007 mtd->subpage_sft = 0;
4008 } else {
4009 this->ecclayout = &onenand_oob_128;
4010 mtd->subpage_sft = 2;
4011 }
Kyungmin Parke1c10242011-06-22 14:16:49 +09004012 if (ONENAND_IS_NOP_1(this))
4013 mtd->subpage_sft = 0;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07004014 break;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004015 case 64:
Thomas Gleixner5bd34c02006-05-27 22:16:10 +02004016 this->ecclayout = &onenand_oob_64;
Kyungmin Park60d84f92006-12-22 16:21:54 +09004017 mtd->subpage_sft = 2;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004018 break;
4019
4020 case 32:
Thomas Gleixner5bd34c02006-05-27 22:16:10 +02004021 this->ecclayout = &onenand_oob_32;
Kyungmin Park60d84f92006-12-22 16:21:54 +09004022 mtd->subpage_sft = 1;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004023 break;
4024
4025 default:
Amul Kumar Saha297758f2009-10-02 16:59:11 +05304026 printk(KERN_WARNING "%s: No OOB scheme defined for oobsize %d\n",
4027 __func__, mtd->oobsize);
Kyungmin Park60d84f92006-12-22 16:21:54 +09004028 mtd->subpage_sft = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004029 /* To prevent kernel oops */
Thomas Gleixner5bd34c02006-05-27 22:16:10 +02004030 this->ecclayout = &onenand_oob_32;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004031 break;
4032 }
4033
Kyungmin Park60d84f92006-12-22 16:21:54 +09004034 this->subpagesize = mtd->writesize >> mtd->subpage_sft;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02004035
4036 /*
4037 * The number of bytes available for a client to place data into
4038 * the out of band area
4039 */
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +01004040 mtd->oobavail = 0;
Kyungmin Parkad286342007-03-23 10:19:52 +09004041 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES &&
4042 this->ecclayout->oobfree[i].length; i++)
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +01004043 mtd->oobavail += this->ecclayout->oobfree[i].length;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02004044
Thomas Gleixner5bd34c02006-05-27 22:16:10 +02004045 mtd->ecclayout = this->ecclayout;
Mike Dunn6a918ba2012-03-11 14:21:11 -07004046 mtd->ecc_strength = 1;
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +00004047
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004048 /* Fill in remaining MTD driver data */
Rohit Hassan Sathyanarayanc7626802010-09-27 16:02:10 +05304049 mtd->type = ONENAND_IS_MLC(this) ? MTD_MLCNANDFLASH : MTD_NANDFLASH;
Joern Engel5fa43392006-05-22 23:18:29 +02004050 mtd->flags = MTD_CAP_NANDFLASH;
Artem Bityutskiy3c3c10b2012-01-30 14:58:32 +02004051 mtd->_erase = onenand_erase;
4052 mtd->_point = NULL;
4053 mtd->_unpoint = NULL;
4054 mtd->_read = onenand_read;
4055 mtd->_write = onenand_write;
4056 mtd->_read_oob = onenand_read_oob;
4057 mtd->_write_oob = onenand_write_oob;
4058 mtd->_panic_write = onenand_panic_write;
Kyungmin Park493c6462006-05-12 17:03:07 +03004059#ifdef CONFIG_MTD_ONENAND_OTP
Artem Bityutskiy3c3c10b2012-01-30 14:58:32 +02004060 mtd->_get_fact_prot_info = onenand_get_fact_prot_info;
4061 mtd->_read_fact_prot_reg = onenand_read_fact_prot_reg;
4062 mtd->_get_user_prot_info = onenand_get_user_prot_info;
4063 mtd->_read_user_prot_reg = onenand_read_user_prot_reg;
4064 mtd->_write_user_prot_reg = onenand_write_user_prot_reg;
4065 mtd->_lock_user_prot_reg = onenand_lock_user_prot_reg;
Kyungmin Park493c6462006-05-12 17:03:07 +03004066#endif
Artem Bityutskiy3c3c10b2012-01-30 14:58:32 +02004067 mtd->_sync = onenand_sync;
4068 mtd->_lock = onenand_lock;
4069 mtd->_unlock = onenand_unlock;
4070 mtd->_suspend = onenand_suspend;
4071 mtd->_resume = onenand_resume;
4072 mtd->_block_isbad = onenand_block_isbad;
4073 mtd->_block_markbad = onenand_block_markbad;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004074 mtd->owner = THIS_MODULE;
Anatolij Gustschin25dcd292010-12-16 23:42:17 +01004075 mtd->writebufsize = mtd->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004076
4077 /* Unlock whole block */
Roman Tereshonkovb3dcfd352011-02-17 13:44:41 +02004078 if (!(this->options & ONENAND_SKIP_INITIAL_UNLOCKING))
4079 this->unlock_all(mtd);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004080
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07004081 ret = this->scan_bbt(mtd);
4082 if ((!FLEXONENAND(this)) || ret)
4083 return ret;
4084
4085 /* Change Flex-OneNAND boundaries if required */
4086 for (i = 0; i < MAX_DIES; i++)
4087 flexonenand_set_boundary(mtd, i, flex_bdry[2 * i],
4088 flex_bdry[(2 * i) + 1]);
4089
4090 return 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004091}
4092
4093/**
4094 * onenand_release - [OneNAND Interface] Free resources held by the OneNAND device
4095 * @param mtd MTD device structure
4096 */
4097void onenand_release(struct mtd_info *mtd)
4098{
Kyungmin Park532a37c2005-12-16 11:17:29 +09004099 struct onenand_chip *this = mtd->priv;
4100
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004101 /* Deregister partitions */
Jamie Iles711a6322011-05-23 10:22:56 +01004102 mtd_device_unregister(mtd);
Kyungmin Park532a37c2005-12-16 11:17:29 +09004103
4104 /* Free bad block table memory, if allocated */
Adrian Hunterf00b0042007-01-22 17:01:01 +09004105 if (this->bbm) {
4106 struct bbm_info *bbm = this->bbm;
4107 kfree(bbm->bbt);
Kyungmin Park532a37c2005-12-16 11:17:29 +09004108 kfree(this->bbm);
Adrian Hunterf00b0042007-01-22 17:01:01 +09004109 }
Kyungmin Park470bc842007-03-09 10:08:11 +09004110 /* Buffers allocated by onenand_scan */
Kyungmin Park4a8ce0b2010-04-28 17:46:46 +02004111 if (this->options & ONENAND_PAGEBUF_ALLOC) {
Kyungmin Park532a37c2005-12-16 11:17:29 +09004112 kfree(this->page_buf);
Kyungmin Park4a8ce0b2010-04-28 17:46:46 +02004113#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
4114 kfree(this->verify_buf);
4115#endif
4116 }
Kyungmin Park470bc842007-03-09 10:08:11 +09004117 if (this->options & ONENAND_OOBBUF_ALLOC)
4118 kfree(this->oob_buf);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07004119 kfree(mtd->eraseregions);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004120}
4121
4122EXPORT_SYMBOL_GPL(onenand_scan);
4123EXPORT_SYMBOL_GPL(onenand_release);
4124
4125MODULE_LICENSE("GPL");
4126MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");
4127MODULE_DESCRIPTION("Generic OneNAND flash driver code");